diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de144ee6104c5..96c0955e871b8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,8 @@ # This file defines our primary CI workflow that runs on pull requests # and also on pushes to special branches (auto, try). # -# The actual definition of the executed jobs is calculated by a Python -# script located at src/ci/github-actions/ci.py, which +# The actual definition of the executed jobs is calculated by the +# `src/ci/citool` crate, which # uses job definition data from src/ci/github-actions/jobs.yml. # You should primarily modify the `jobs.yml` file if you want to modify # what jobs are executed in CI. @@ -56,7 +56,10 @@ jobs: - name: Calculate the CI job matrix env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - run: python3 src/ci/github-actions/ci.py calculate-job-matrix >> $GITHUB_OUTPUT + run: | + cd src/ci/citool + CARGO_INCREMENTAL=0 cargo test + CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT id: jobs job: name: ${{ matrix.full_name }} @@ -65,6 +68,7 @@ jobs: timeout-minutes: 360 env: CI_JOB_NAME: ${{ matrix.name }} + CI_JOB_DOC_URL: ${{ matrix.doc_url }} CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse # commit of PR sha or commit sha. `GITHUB_SHA` is not accurate for PRs. HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} @@ -179,9 +183,28 @@ jobs: - name: show the current environment run: src/ci/scripts/dump-environment.sh + # Pre-build citool before the following step uninstalls rustup + # Build it into the build directory, to avoid modifying sources + - name: build citool + run: | + cd src/ci/citool + CARGO_INCREMENTAL=0 CARGO_TARGET_DIR=../../../build/citool cargo build + - name: run the build - # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. - run: src/ci/scripts/run-build-from-ci.sh 2>&1 + run: | + set +e + # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. + src/ci/scripts/run-build-from-ci.sh 2>&1 + STATUS=$? + set -e + + if [[ "$STATUS" -ne 0 && -n "$CI_JOB_DOC_URL" ]]; then + echo "****************************************************************************" + echo "To find more information about this job, visit the following URL:" + echo "$CI_JOB_DOC_URL" + echo "****************************************************************************" + fi + exit ${STATUS} env: AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} @@ -215,16 +238,22 @@ jobs: # erroring about invalid credentials instead. if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1' + - name: postprocess metrics into the summary + run: | + if [ -f build/metrics.json ]; then + ./build/citool/debug/citool postprocess-metrics build/metrics.json ${GITHUB_STEP_SUMMARY} + elif [ -f obj/build/metrics.json ]; then + ./build/citool/debug/citool postprocess-metrics obj/build/metrics.json ${GITHUB_STEP_SUMMARY} + else + echo "No metrics.json found" + fi + - name: upload job metrics to DataDog if: needs.calculate_matrix.outputs.run_type != 'pr' env: - DATADOG_SITE: datadoghq.com DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }} DD_GITHUB_JOB_NAME: ${{ matrix.full_name }} - run: | - cd src/ci - npm ci - python3 scripts/upload-build-metrics.py ../../build/cpu-usage.csv + run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv # This job isused to tell bors the final status of the build, as there is no practical way to detect # when a workflow is successful listening to webhooks only in our current bors implementation (homu). diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml new file mode 100644 index 0000000000000..de31c28cc90e0 --- /dev/null +++ b/.github/workflows/post-merge.yml @@ -0,0 +1,47 @@ +# Workflow that runs after a merge to master, analyses changes in test executions +# and posts the result to the merged PR. + +name: Post merge analysis + +on: + push: + branches: + - master + +jobs: + analysis: + runs-on: ubuntu-24.04 + if: github.repository == 'rust-lang/rust' + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v4 + with: + # Make sure that we have enough commits to find the parent merge commit. + # Since all merges should be through merge commits, fetching two commits + # should be enough to get the parent bors merge commit. + fetch-depth: 2 + - name: Perform analysis and send PR + env: + GH_TOKEN: ${{ github.token }} + run: | + # Get closest bors merge commit + PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` + echo "Parent: ${PARENT_COMMIT}" + + # Find PR for the current commit + HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` + echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" + + cd src/ci/citool + + printf "*This is an experimental post-merge analysis report. You can ignore it.*\n\n" > output.log + printf "
\nPost-merge report\n\n" >> output.log + + cargo run --release post-merge-report ${PARENT_COMMIT} ${{ github.sha }} >> output.log + + printf "
\n" >> output.log + + cat output.log + + gh pr comment ${HEAD_PR} -F output.log diff --git a/.gitignore b/.gitignore index 2184e04f16b27..b8cb31e81908d 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ no_llvm_build /target /library/target /src/bootstrap/target +/src/ci/citool/target /src/tools/x/target # Created by `x vendor` /vendor diff --git a/.mailmap b/.mailmap index eb6a9fcabca99..a791daa681d47 100644 --- a/.mailmap +++ b/.mailmap @@ -292,6 +292,9 @@ James Hinshelwood James Miller James Perry James Sanderson +Jana Dönszelmann +Jana Dönszelmann +Jana Dönszelmann Jan-Erik Rediger Jaro Fietz Jason Fager diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a5ddff595f5d6..e155e253784aa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ For submodules, changes need to be made against the repository corresponding the submodule, and not the main `rust-lang/rust` repository. For subtrees, prefer sending a PR against the subtree's repository if it does -not need to be made against the main `rust-lang/rust` repostory (e.g. a +not need to be made against the main `rust-lang/rust` repository (e.g. a rustc-dev-guide change that does not accompany a compiler change). ## About the [rustc-dev-guide] diff --git a/Cargo.lock b/Cargo.lock index 6bc88fb7a6dc8..85f588f8e8ac5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,7 +358,7 @@ dependencies = [ "cargo_metadata 0.18.1", "directories", "rustc-build-sysroot", - "rustc_tools_util", + "rustc_tools_util 0.4.0", "rustc_version", "serde", "serde_json", @@ -407,9 +407,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.2.13" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "shlex", ] @@ -522,7 +522,7 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "clippy" -version = "0.1.86" +version = "0.1.87" dependencies = [ "anstream", "cargo_metadata 0.18.1", @@ -539,7 +539,7 @@ dependencies = [ "quote", "regex", "rinja", - "rustc_tools_util", + "rustc_tools_util 0.4.2", "serde", "serde_json", "syn 2.0.96", @@ -553,7 +553,7 @@ dependencies = [ [[package]] name = "clippy_config" -version = "0.1.86" +version = "0.1.87" dependencies = [ "clippy_utils", "itertools", @@ -578,7 +578,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.86" +version = "0.1.87" dependencies = [ "arrayvec", "cargo_metadata 0.18.1", @@ -601,7 +601,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.86" +version = "0.1.87" dependencies = [ "arrayvec", "itertools", @@ -1491,6 +1491,7 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ + "allocator-api2", "foldhash", "serde", ] @@ -1547,16 +1548,14 @@ dependencies = [ [[package]] name = "html5ever" -version = "0.27.0" +version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +checksum = "9b958f80f0fde8601dc6c08685adc743eecaa046181cebd5a57551468dfc2ddc" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn 2.0.96", + "match_token", ] [[package]] @@ -2022,7 +2021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -2133,9 +2132,9 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "markup5ever" -version = "0.12.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +checksum = "03a7b81dfb91586d0677086d40a6d755070e0799b71bb897485bac408dfd5c69" dependencies = [ "log", "phf", @@ -2145,6 +2144,17 @@ dependencies = [ "tendril", ] +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + [[package]] name = "matchers" version = "0.1.0" @@ -2526,6 +2536,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "overload" version = "0.1.1" @@ -2617,7 +2637,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_shared 0.11.3", + "phf_shared", ] [[package]] @@ -2626,18 +2646,8 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", + "phf_generator", + "phf_shared", ] [[package]] @@ -2646,26 +2656,17 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared 0.11.3", + "phf_shared", "rand 0.8.5", ] -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - [[package]] name = "phf_shared" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ - "siphasher 1.0.1", + "siphasher", ] [[package]] @@ -2871,11 +2872,11 @@ dependencies = [ [[package]] name = "rand_xoshiro" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" dependencies = [ - "rand_core 0.6.4", + "rand_core 0.9.0", ] [[package]] @@ -3034,13 +3035,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rls" -version = "2.0.0" -dependencies = [ - "serde_json", -] - [[package]] name = "run_make_support" version = "0.2.0" @@ -3050,6 +3044,7 @@ dependencies = [ "gimli 0.31.1", "libc", "object 0.36.7", + "os_pipe", "regex", "serde_json", "similar", @@ -3144,7 +3139,7 @@ name = "rustc_abi" version = "0.0.0" dependencies = [ "bitflags", - "rand 0.8.5", + "rand 0.9.0", "rand_xoshiro", "rustc_data_structures", "rustc_hashes", @@ -3207,6 +3202,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -3215,6 +3211,7 @@ dependencies = [ "rustc_index", "rustc_macros", "rustc_middle", + "rustc_parse", "rustc_session", "rustc_span", "rustc_target", @@ -3263,14 +3260,10 @@ dependencies = [ "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", - "rustc_errors", - "rustc_feature", - "rustc_fluent_macro", - "rustc_lexer", "rustc_macros", "rustc_serialize", - "rustc_session", "rustc_span", + "thin-vec", ] [[package]] @@ -3285,11 +3278,14 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fluent_macro", + "rustc_hir", "rustc_lexer", "rustc_macros", + "rustc_middle", "rustc_serialize", "rustc_session", "rustc_span", + "thin-vec", ] [[package]] @@ -3342,6 +3338,7 @@ dependencies = [ "rustc_expand", "rustc_feature", "rustc_fluent_macro", + "rustc_hir", "rustc_index", "rustc_lexer", "rustc_lint_defs", @@ -3433,7 +3430,6 @@ dependencies = [ "rustc_symbol_mangling", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "serde_json", "smallvec", "tempfile", @@ -3466,7 +3462,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "tracing", ] @@ -3479,6 +3474,7 @@ dependencies = [ "either", "elsa", "ena", + "hashbrown 0.15.2", "indexmap", "jobserver", "libc", @@ -3598,6 +3594,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_error_codes", "rustc_error_messages", @@ -3632,6 +3629,7 @@ dependencies = [ "rustc_errors", "rustc_feature", "rustc_fluent_macro", + "rustc_hir", "rustc_lexer", "rustc_lint_defs", "rustc_macros", @@ -3690,6 +3688,7 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_hashes", "rustc_index", @@ -3725,7 +3724,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "smallvec", "tracing", ] @@ -3737,6 +3735,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", + "rustc_attr_data_structures", "rustc_hir", "rustc_span", ] @@ -3763,7 +3762,6 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_trait_selection", - "rustc_type_ir", "smallvec", "tracing", ] @@ -3772,13 +3770,14 @@ dependencies = [ name = "rustc_incremental" version = "0.0.0" dependencies = [ - "rand 0.8.5", + "rand 0.9.0", "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", "rustc_fs_util", "rustc_graphviz", + "rustc_hashes", "rustc_hir", "rustc_macros", "rustc_middle", @@ -3909,7 +3908,7 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", + "smallvec", "tracing", "unicode-security", ] @@ -3984,7 +3983,6 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "rustc_type_ir", "tempfile", "tracing", ] @@ -4002,7 +4000,8 @@ dependencies = [ "rustc_apfloat", "rustc_arena", "rustc_ast", - "rustc_attr_parsing", + "rustc_ast_ir", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_error_messages", "rustc_errors", @@ -4099,7 +4098,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "smallvec", "tracing", ] @@ -4243,6 +4241,7 @@ name = "rustc_query_impl" version = "0.0.0" dependencies = [ "measureme", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_hashes", @@ -4265,6 +4264,7 @@ dependencies = [ "rustc-rayon-core", "rustc_abi", "rustc_ast", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -4315,6 +4315,7 @@ version = "0.0.0" dependencies = [ "bitflags", "rustc_abi", + "rustc_ast", "rustc_data_structures", "rustc_hir", "rustc_middle", @@ -4411,6 +4412,7 @@ dependencies = [ "punycode", "rustc-demangle", "rustc_abi", + "rustc_ast", "rustc_data_structures", "rustc_errors", "rustc_hashes", @@ -4443,6 +4445,10 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3316159ab19e19d1065ecc49278e87f767a9dae9fae80348d2b4d4fa4ae02d4d" +[[package]] +name = "rustc_tools_util" +version = "0.4.2" + [[package]] name = "rustc_trait_selection" version = "0.0.0" @@ -4490,8 +4496,6 @@ dependencies = [ "rustc_abi", "rustc_data_structures", "rustc_hir", - "rustc_infer", - "rustc_macros", "rustc_middle", "rustc_span", "tracing", @@ -4503,6 +4507,7 @@ version = "0.0.0" dependencies = [ "itertools", "rustc_abi", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4516,7 +4521,6 @@ dependencies = [ "rustc_span", "rustc_target", "rustc_trait_selection", - "rustc_type_ir", "tracing", ] @@ -4570,6 +4574,7 @@ dependencies = [ "itertools", "minifier", "pulldown-cmark 0.9.6", + "pulldown-cmark-escape", "regex", "rinja", "rustdoc-json-types", @@ -4846,12 +4851,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - [[package]] name = "siphasher" version = "1.0.1" @@ -4966,26 +4965,25 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "string_cache" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe" dependencies = [ "new_debug_unreachable", - "once_cell", "parking_lot", - "phf_shared 0.10.0", + "phf_shared", "precomputed-hash", "serde", ] [[package]] name = "string_cache_codegen" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", + "phf_generator", + "phf_shared", "proc-macro2", "quote", ] @@ -5149,8 +5147,8 @@ version = "0.1.0" dependencies = [ "indicatif", "num", - "rand 0.8.5", - "rand_chacha 0.3.1", + "rand 0.9.0", + "rand_chacha 0.9.0", "rayon", ] @@ -5246,6 +5244,7 @@ dependencies = [ "serde", "similar", "termcolor", + "toml 0.7.8", "walkdir", ] @@ -6414,6 +6413,10 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "x" +version = "0.1.1" + [[package]] name = "xattr" version = "1.4.0" diff --git a/Cargo.toml b/Cargo.toml index 20a43aaaeeb37..16ff0f61593ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,51 +1,53 @@ [workspace] resolver = "2" members = [ +# tidy-alphabetical-start "compiler/rustc", "src/build_helper", "src/etc/test-float-parse", - "src/rustc-std-workspace/rustc-std-workspace-core", "src/rustc-std-workspace/rustc-std-workspace-alloc", + "src/rustc-std-workspace/rustc-std-workspace-core", "src/rustc-std-workspace/rustc-std-workspace-std", "src/rustdoc-json-types", + "src/tools/build-manifest", + "src/tools/bump-stage0", "src/tools/cargotest", "src/tools/clippy", "src/tools/clippy/clippy_dev", + "src/tools/collect-license-metadata", "src/tools/compiletest", - "src/tools/run-make-support", + "src/tools/coverage-dump", + "src/tools/features-status-dump", + "src/tools/generate-copyright", + "src/tools/generate-windows-sys", + "src/tools/html-checker", + "src/tools/jsondocck", + "src/tools/jsondoclint", "src/tools/linkchecker", "src/tools/lint-docs", + "src/tools/lld-wrapper", + "src/tools/llvm-bitcode-linker", + "src/tools/miri", + "src/tools/miri/cargo-miri", "src/tools/miropt-test-tools", - "src/tools/unstable-book-gen", - "src/tools/tidy", - "src/tools/tier-check", - "src/tools/build-manifest", + "src/tools/opt-dist", "src/tools/remote-test-client", "src/tools/remote-test-server", + "src/tools/replace-version-placeholder", + "src/tools/run-make-support", "src/tools/rust-installer", "src/tools/rustdoc", - "src/tools/rls", - "src/tools/rustfmt", - "src/tools/miri", - "src/tools/miri/cargo-miri", + "src/tools/rustdoc-gui-test", "src/tools/rustdoc-themes", - "src/tools/unicode-table-generator", - "src/tools/jsondocck", - "src/tools/jsondoclint", - "src/tools/llvm-bitcode-linker", - "src/tools/html-checker", - "src/tools/bump-stage0", - "src/tools/replace-version-placeholder", - "src/tools/lld-wrapper", - "src/tools/collect-license-metadata", - "src/tools/generate-copyright", + "src/tools/rustfmt", "src/tools/suggest-tests", - "src/tools/generate-windows-sys", - "src/tools/rustdoc-gui-test", - "src/tools/opt-dist", - "src/tools/coverage-dump", + "src/tools/tidy", + "src/tools/tier-check", + "src/tools/unicode-table-generator", + "src/tools/unstable-book-gen", "src/tools/wasm-component-ld", - "src/tools/features-status-dump", + "src/tools/x", +# tidy-alphabetical-end ] exclude = [ @@ -56,11 +58,6 @@ exclude = [ "tests/rustdoc-gui", # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`. "obj", - # The `x` binary is a thin wrapper that calls `x.py`, which initializes - # submodules, before which workspace members cannot be invoked because - # not all `Cargo.toml` files are available, so we exclude the `x` binary, - # so it can be invoked before the current checkout is set up. - "src/tools/x", ] [profile.release.package.rustc-rayon-core] diff --git a/INSTALL.md b/INSTALL.md index 74fcc58348b43..a46d3d70093f1 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -210,9 +210,13 @@ itself back on after some time). ### MSVC -MSVC builds of Rust additionally require an installation of Visual Studio 2017 -(or later) so `rustc` can use its linker. The simplest way is to get -[Visual Studio], check the "C++ build tools" and "Windows 10 SDK" workload. +MSVC builds of Rust additionally requires an installation of: + +- Visual Studio 2022 (or later) build tools so `rustc` can use its linker. Older + Visual Studio versions such as 2019 *may* work but aren't actively tested. +- A recent Windows 10 or 11 SDK. + +The simplest way is to get [Visual Studio], check the "C++ build tools". [Visual Studio]: https://visualstudio.microsoft.com/downloads/ diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml index d24b630516a7c..f4caa3ef769d5 100644 --- a/compiler/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc-main" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc/src/main.rs b/compiler/rustc/src/main.rs index a55a63a7bf179..ca1bb59e59d60 100644 --- a/compiler/rustc/src/main.rs +++ b/compiler/rustc/src/main.rs @@ -65,7 +65,7 @@ fn main() { // linking, so we need to explicitly depend on the function. #[cfg(target_os = "macos")] { - extern "C" { + unsafe extern "C" { fn _rjem_je_zone_register(); } diff --git a/compiler/rustc_abi/Cargo.toml b/compiler/rustc_abi/Cargo.toml index 3d6f4a6a10923..5f9afc46a1ace 100644 --- a/compiler/rustc_abi/Cargo.toml +++ b/compiler/rustc_abi/Cargo.toml @@ -1,18 +1,18 @@ [package] name = "rustc_abi" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rand = { version = "0.8.4", default-features = false, optional = true } -rand_xoshiro = { version = "0.6.0", optional = true } -rustc_data_structures = { path = "../rustc_data_structures", optional = true } +rand = { version = "0.9.0", default-features = false, optional = true } +rand_xoshiro = { version = "0.7.0", optional = true } +rustc_data_structures = { path = "../rustc_data_structures", optional = true } rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index", default-features = false } rustc_macros = { path = "../rustc_macros", optional = true } -rustc_serialize = { path = "../rustc_serialize", optional = true } +rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index 4529ab8058e9a..a21e1aee9b08a 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -74,7 +74,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size })) } - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { assert!(!self.is_zst()); Ok(HomogeneousAggregate::Homogeneous(Reg { kind: RegKind::Vector, diff --git a/compiler/rustc_abi/src/callconv/reg.rs b/compiler/rustc_abi/src/callconv/reg.rs index 66f47c52c15d1..8cf140dbaad4e 100644 --- a/compiler/rustc_abi/src/callconv/reg.rs +++ b/compiler/rustc_abi/src/callconv/reg.rs @@ -57,7 +57,7 @@ impl Reg { 128 => dl.f128_align.abi, _ => panic!("unsupported float: {self:?}"), }, - RegKind::Vector => dl.vector_align(self.size).abi, + RegKind::Vector => dl.llvmlike_vector_align(self.size).abi, } } } diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 543c2f8ab12cf..4d70afd4e0bca 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -191,6 +191,17 @@ impl StableOrd for ExternAbi { } impl ExternAbi { + /// An ABI "like Rust" + /// + /// These ABIs are fully controlled by the Rust compiler, which means they + /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"` + /// - often diverge from the C ABI + /// - are subject to change between compiler versions + pub fn is_rustic_abi(self) -> bool { + use ExternAbi::*; + matches!(self, Rust | RustCall | RustIntrinsic | RustCold) + } + pub fn supports_varargs(self) -> bool { // * C and Cdecl obviously support varargs. // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs. diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 53243266f992b..7bffeaf4cc9e2 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -4,6 +4,7 @@ use std::{cmp, iter}; use rustc_hashes::Hash64; use rustc_index::Idx; +use rustc_index::bit_set::BitMatrix; use tracing::debug; use crate::{ @@ -12,6 +13,9 @@ use crate::{ Variants, WrappingRange, }; +mod coroutine; +mod simple; + #[cfg(feature = "nightly")] mod ty; @@ -60,17 +64,28 @@ pub enum LayoutCalculatorError { /// The fields or variants have irreconcilable reprs ReprConflict, + + /// The length of an SIMD type is zero + ZeroLengthSimdType, + + /// The length of an SIMD type exceeds the maximum number of lanes + OversizedSimdType { max_lanes: u64 }, + + /// An element type of an SIMD type isn't a primitive + NonPrimitiveSimdType(F), } impl LayoutCalculatorError { pub fn without_payload(&self) -> LayoutCalculatorError<()> { - match self { - LayoutCalculatorError::UnexpectedUnsized(_) => { - LayoutCalculatorError::UnexpectedUnsized(()) - } - LayoutCalculatorError::SizeOverflow => LayoutCalculatorError::SizeOverflow, - LayoutCalculatorError::EmptyUnion => LayoutCalculatorError::EmptyUnion, - LayoutCalculatorError::ReprConflict => LayoutCalculatorError::ReprConflict, + use LayoutCalculatorError::*; + match *self { + UnexpectedUnsized(_) => UnexpectedUnsized(()), + SizeOverflow => SizeOverflow, + EmptyUnion => EmptyUnion, + ReprConflict => ReprConflict, + ZeroLengthSimdType => ZeroLengthSimdType, + OversizedSimdType { max_lanes } => OversizedSimdType { max_lanes }, + NonPrimitiveSimdType(_) => NonPrimitiveSimdType(()), } } @@ -78,13 +93,15 @@ impl LayoutCalculatorError { /// /// Intended for use by rust-analyzer, as neither it nor `rustc_abi` depend on fluent infra. pub fn fallback_fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use LayoutCalculatorError::*; f.write_str(match self { - LayoutCalculatorError::UnexpectedUnsized(_) => { - "an unsized type was found where a sized type was expected" + UnexpectedUnsized(_) => "an unsized type was found where a sized type was expected", + SizeOverflow => "size overflow", + EmptyUnion => "type is a union with no fields", + ReprConflict => "type has an invalid repr", + ZeroLengthSimdType | OversizedSimdType { .. } | NonPrimitiveSimdType(_) => { + "invalid simd type definition" } - LayoutCalculatorError::SizeOverflow => "size overflow", - LayoutCalculatorError::EmptyUnion => "type is a union with no fields", - LayoutCalculatorError::ReprConflict => "type has an invalid repr", }) } } @@ -102,41 +119,115 @@ impl LayoutCalculator { Self { cx } } - pub fn scalar_pair( + pub fn array_like( &self, - a: Scalar, - b: Scalar, - ) -> LayoutData { - let dl = self.cx.data_layout(); - let b_align = b.align(dl); - let align = a.align(dl).max(b_align).max(dl.aggregate_align); - let b_offset = a.size(dl).align_to(b_align.abi); - let size = (b_offset + b.size(dl)).align_to(align.abi); + element: &LayoutData, + count_if_sized: Option, // None for slices + ) -> LayoutCalculatorResult { + let count = count_if_sized.unwrap_or(0); + let size = + element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?; - // HACK(nox): We iter on `b` and then `a` because `max_by_key` - // returns the last maximum. - let largest_niche = Niche::from_scalar(dl, b_offset, b) - .into_iter() - .chain(Niche::from_scalar(dl, Size::ZERO, a)) - .max_by_key(|niche| niche.available(dl)); + Ok(LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Array { stride: element.size, count }, + backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() }, + largest_niche: element.largest_niche.filter(|_| count != 0), + uninhabited: element.uninhabited && count != 0, + align: element.align, + size, + max_repr_align: None, + unadjusted_abi_align: element.align.abi, + randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)), + }) + } - let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes()); + pub fn simd_type< + FieldIdx: Idx, + VariantIdx: Idx, + F: AsRef> + fmt::Debug, + >( + &self, + element: F, + count: u64, + repr_packed: bool, + ) -> LayoutCalculatorResult { + let elt = element.as_ref(); + if count == 0 { + return Err(LayoutCalculatorError::ZeroLengthSimdType); + } else if count > crate::MAX_SIMD_LANES { + return Err(LayoutCalculatorError::OversizedSimdType { + max_lanes: crate::MAX_SIMD_LANES, + }); + } - LayoutData { + let BackendRepr::Scalar(e_repr) = elt.backend_repr else { + return Err(LayoutCalculatorError::NonPrimitiveSimdType(element)); + }; + + // Compute the size and alignment of the vector + let dl = self.cx.data_layout(); + let size = + elt.size.checked_mul(count, dl).ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; + let (repr, align) = if repr_packed && !count.is_power_of_two() { + // Non-power-of-two vectors have padding up to the next power-of-two. + // If we're a packed repr, remove the padding while keeping the alignment as close + // to a vector as possible. + ( + BackendRepr::Memory { sized: true }, + AbiAndPrefAlign { + abi: Align::max_aligned_factor(size), + pref: dl.llvmlike_vector_align(size).pref, + }, + ) + } else { + (BackendRepr::SimdVector { element: e_repr, count }, dl.llvmlike_vector_align(size)) + }; + let size = size.align_to(align.abi); + + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { - offsets: [Size::ZERO, b_offset].into(), - memory_index: [0, 1].into(), + offsets: [Size::ZERO].into(), + memory_index: [0].into(), }, - backend_repr: BackendRepr::ScalarPair(a, b), - largest_niche, + backend_repr: repr, + largest_niche: elt.largest_niche, uninhabited: false, - align, size, + align, max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: Hash64::new(combined_seed), - } + unadjusted_abi_align: elt.align.abi, + randomization_seed: elt.randomization_seed.wrapping_add(Hash64::new(count)), + }) + } + + /// Compute the layout for a coroutine. + /// + /// This uses dedicated code instead of [`Self::layout_of_struct_or_enum`], as coroutine + /// fields may be shared between multiple variants (see the [`coroutine`] module for details). + pub fn coroutine< + 'a, + F: Deref> + fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, + >( + &self, + local_layouts: &IndexSlice, + prefix_layouts: IndexVec, + variant_fields: &IndexSlice>, + storage_conflicts: &BitMatrix, + tag_to_layout: impl Fn(Scalar) -> F, + ) -> LayoutCalculatorResult { + coroutine::layout( + self, + local_layouts, + prefix_layouts, + variant_fields, + storage_conflicts, + tag_to_layout, + ) } pub fn univariant< @@ -214,25 +305,6 @@ impl LayoutCalculator { layout } - pub fn layout_of_never_type( - &self, - ) -> LayoutData { - let dl = self.cx.data_layout(); - // This is also used for uninhabited enums, so we use `Variants::Empty`. - LayoutData { - variants: Variants::Empty, - fields: FieldsShape::Primitive, - backend_repr: BackendRepr::Memory { sized: true }, - largest_niche: None, - uninhabited: true, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - randomization_seed: Hash64::ZERO, - } - } - pub fn layout_of_struct_or_enum< 'a, FieldIdx: Idx, @@ -260,7 +332,7 @@ impl LayoutCalculator { Some(present_first) => present_first, // Uninhabited because it has no variants, or only absent ones. None if is_enum => { - return Ok(self.layout_of_never_type()); + return Ok(LayoutData::never_type(&self.cx)); } // If it's a struct, still compute a layout so that we can still compute the // field offsets. @@ -310,10 +382,10 @@ impl LayoutCalculator { let mut align = if repr.pack.is_some() { dl.i8_align } else { dl.aggregate_align }; let mut max_repr_align = repr.align; - // If all the non-ZST fields have the same ABI and union ABI optimizations aren't - // disabled, we can use that common ABI for the union as a whole. + // If all the non-ZST fields have the same repr and union repr optimizations aren't + // disabled, we can use that common repr for the union as a whole. struct AbiMismatch; - let mut common_non_zst_abi_and_align = if repr.inhibits_union_abi_opt() { + let mut common_non_zst_repr_and_align = if repr.inhibits_union_abi_opt() { // Can't optimize Err(AbiMismatch) } else { @@ -337,14 +409,14 @@ impl LayoutCalculator { continue; } - if let Ok(common) = common_non_zst_abi_and_align { + if let Ok(common) = common_non_zst_repr_and_align { // Discard valid range information and allow undef let field_abi = field.backend_repr.to_union(); if let Some((common_abi, common_align)) = common { if common_abi != field_abi { // Different fields have different ABI: disable opt - common_non_zst_abi_and_align = Err(AbiMismatch); + common_non_zst_repr_and_align = Err(AbiMismatch); } else { // Fields with the same non-Aggregate ABI should also // have the same alignment @@ -357,7 +429,7 @@ impl LayoutCalculator { } } else { // First non-ZST field: record its ABI and alignment - common_non_zst_abi_and_align = Ok(Some((field_abi, field.align.abi))); + common_non_zst_repr_and_align = Ok(Some((field_abi, field.align.abi))); } } } @@ -376,16 +448,27 @@ impl LayoutCalculator { // If all non-ZST fields have the same ABI, we may forward that ABI // for the union as a whole, unless otherwise inhibited. - let abi = match common_non_zst_abi_and_align { + let backend_repr = match common_non_zst_repr_and_align { Err(AbiMismatch) | Ok(None) => BackendRepr::Memory { sized: true }, - Ok(Some((abi, _))) => { - if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) { - // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt + Ok(Some((repr, _))) => match repr { + // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt + BackendRepr::Scalar(_) | BackendRepr::ScalarPair(_, _) + if repr.scalar_align(dl).unwrap() != align.abi => + { BackendRepr::Memory { sized: true } - } else { - abi } - } + // Vectors require at least element alignment, else disable the opt + BackendRepr::SimdVector { element, count: _ } + if element.align(dl).abi > align.abi => + { + BackendRepr::Memory { sized: true } + } + // the alignment tests passed and we can use this + BackendRepr::Scalar(..) + | BackendRepr::ScalarPair(..) + | BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } => repr, + }, }; let Some(union_field_count) = NonZeroUsize::new(only_variant.len()) else { @@ -400,7 +483,7 @@ impl LayoutCalculator { Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), - backend_repr: abi, + backend_repr, largest_niche: None, uninhabited: false, align, @@ -455,7 +538,7 @@ impl LayoutCalculator { hide_niches(a); hide_niches(b); } - BackendRepr::Vector { element, count: _ } => hide_niches(element), + BackendRepr::SimdVector { element, count: _ } => hide_niches(element), BackendRepr::Memory { sized: _ } => {} } st.largest_niche = None; @@ -938,7 +1021,8 @@ impl LayoutCalculator { // Common prim might be uninit. Scalar::Union { value: prim } }; - let pair = self.scalar_pair::(tag, prim_scalar); + let pair = + LayoutData::::scalar_pair(&self.cx, tag, prim_scalar); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index.raw, [0, 1]); @@ -1305,7 +1389,9 @@ impl LayoutCalculator { match field.backend_repr { // For plain scalars, or vectors of them, we can't unpack // newtypes for `#[repr(C)]`, as that affects C ABIs. - BackendRepr::Scalar(_) | BackendRepr::Vector { .. } if optimize_abi => { + BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } + if optimize_abi => + { abi = field.backend_repr; } // But scalar pairs are Rust-specific and get @@ -1328,7 +1414,8 @@ impl LayoutCalculator { } else { ((j, b), (i, a)) }; - let pair = self.scalar_pair::(a, b); + let pair = + LayoutData::::scalar_pair(&self.cx, a, b); let pair_offsets = match pair.fields { FieldsShape::Arbitrary { ref offsets, ref memory_index } => { assert_eq!(memory_index.raw, [0, 1]); diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs new file mode 100644 index 0000000000000..27e704d538c83 --- /dev/null +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -0,0 +1,320 @@ +//! Coroutine layout logic. +//! +//! When laying out coroutines, we divide our saved local fields into two +//! categories: overlap-eligible and overlap-ineligible. +//! +//! Those fields which are ineligible for overlap go in a "prefix" at the +//! beginning of the layout, and always have space reserved for them. +//! +//! Overlap-eligible fields are only assigned to one variant, so we lay +//! those fields out for each variant and put them right after the +//! prefix. +//! +//! Finally, in the layout details, we point to the fields from the +//! variants they are assigned to. It is possible for some fields to be +//! included in multiple variants. No field ever "moves around" in the +//! layout; its offset is always the same. +//! +//! Also included in the layout are the upvars and the discriminant. +//! These are included as fields on the "outer" layout; they are not part +//! of any variant. + +use std::iter; + +use rustc_index::bit_set::{BitMatrix, DenseBitSet}; +use rustc_index::{Idx, IndexSlice, IndexVec}; +use tracing::{debug, trace}; + +use crate::{ + BackendRepr, FieldsShape, HasDataLayout, Integer, LayoutData, Primitive, ReprOptions, Scalar, + StructKind, TagEncoding, Variants, WrappingRange, +}; + +/// Overlap eligibility and variant assignment for each CoroutineSavedLocal. +#[derive(Clone, Debug, PartialEq)] +enum SavedLocalEligibility { + Unassigned, + Assigned(VariantIdx), + Ineligible(Option), +} + +/// Compute the eligibility and assignment of each local. +fn coroutine_saved_local_eligibility( + nb_locals: usize, + variant_fields: &IndexSlice>, + storage_conflicts: &BitMatrix, +) -> (DenseBitSet, IndexVec>) { + use SavedLocalEligibility::*; + + let mut assignments: IndexVec = IndexVec::from_elem_n(Unassigned, nb_locals); + + // The saved locals not eligible for overlap. These will get + // "promoted" to the prefix of our coroutine. + let mut ineligible_locals = DenseBitSet::new_empty(nb_locals); + + // Figure out which of our saved locals are fields in only + // one variant. The rest are deemed ineligible for overlap. + for (variant_index, fields) in variant_fields.iter_enumerated() { + for local in fields { + match assignments[*local] { + Unassigned => { + assignments[*local] = Assigned(variant_index); + } + Assigned(idx) => { + // We've already seen this local at another suspension + // point, so it is no longer a candidate. + trace!( + "removing local {:?} in >1 variant ({:?}, {:?})", + local, variant_index, idx + ); + ineligible_locals.insert(*local); + assignments[*local] = Ineligible(None); + } + Ineligible(_) => {} + } + } + } + + // Next, check every pair of eligible locals to see if they + // conflict. + for local_a in storage_conflicts.rows() { + let conflicts_a = storage_conflicts.count(local_a); + if ineligible_locals.contains(local_a) { + continue; + } + + for local_b in storage_conflicts.iter(local_a) { + // local_a and local_b are storage live at the same time, therefore they + // cannot overlap in the coroutine layout. The only way to guarantee + // this is if they are in the same variant, or one is ineligible + // (which means it is stored in every variant). + if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] { + continue; + } + + // If they conflict, we will choose one to make ineligible. + // This is not always optimal; it's just a greedy heuristic that + // seems to produce good results most of the time. + let conflicts_b = storage_conflicts.count(local_b); + let (remove, other) = + if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) }; + ineligible_locals.insert(remove); + assignments[remove] = Ineligible(None); + trace!("removing local {:?} due to conflict with {:?}", remove, other); + } + } + + // Count the number of variants in use. If only one of them, then it is + // impossible to overlap any locals in our layout. In this case it's + // always better to make the remaining locals ineligible, so we can + // lay them out with the other locals in the prefix and eliminate + // unnecessary padding bytes. + { + let mut used_variants = DenseBitSet::new_empty(variant_fields.len()); + for assignment in &assignments { + if let Assigned(idx) = assignment { + used_variants.insert(*idx); + } + } + if used_variants.count() < 2 { + for assignment in assignments.iter_mut() { + *assignment = Ineligible(None); + } + ineligible_locals.insert_all(); + } + } + + // Write down the order of our locals that will be promoted to the prefix. + { + for (idx, local) in ineligible_locals.iter().enumerate() { + assignments[local] = Ineligible(Some(FieldIdx::new(idx))); + } + } + debug!("coroutine saved local assignments: {:?}", assignments); + + (ineligible_locals, assignments) +} + +/// Compute the full coroutine layout. +pub(super) fn layout< + 'a, + F: core::ops::Deref> + core::fmt::Debug + Copy, + VariantIdx: Idx, + FieldIdx: Idx, + LocalIdx: Idx, +>( + calc: &super::LayoutCalculator, + local_layouts: &IndexSlice, + mut prefix_layouts: IndexVec, + variant_fields: &IndexSlice>, + storage_conflicts: &BitMatrix, + tag_to_layout: impl Fn(Scalar) -> F, +) -> super::LayoutCalculatorResult { + use SavedLocalEligibility::*; + + let (ineligible_locals, assignments) = + coroutine_saved_local_eligibility(local_layouts.len(), variant_fields, storage_conflicts); + + // Build a prefix layout, including "promoting" all ineligible + // locals as part of the prefix. We compute the layout of all of + // these fields at once to get optimal packing. + let tag_index = prefix_layouts.len(); + + // `variant_fields` already accounts for the reserved variants, so no need to add them. + let max_discr = (variant_fields.len() - 1) as u128; + let discr_int = Integer::fit_unsigned(max_discr); + let tag = Scalar::Initialized { + value: Primitive::Int(discr_int, /* signed = */ false), + valid_range: WrappingRange { start: 0, end: max_discr }, + }; + + let promoted_layouts = ineligible_locals.iter().map(|local| local_layouts[local]); + prefix_layouts.push(tag_to_layout(tag)); + prefix_layouts.extend(promoted_layouts); + let prefix = + calc.univariant(&prefix_layouts, &ReprOptions::default(), StructKind::AlwaysSized)?; + + let (prefix_size, prefix_align) = (prefix.size, prefix.align); + + // Split the prefix layout into the "outer" fields (upvars and + // discriminant) and the "promoted" fields. Promoted fields will + // get included in each variant that requested them in + // CoroutineLayout. + debug!("prefix = {:#?}", prefix); + let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { + FieldsShape::Arbitrary { mut offsets, memory_index } => { + let mut inverse_memory_index = memory_index.invert_bijective_mapping(); + + // "a" (`0..b_start`) and "b" (`b_start..`) correspond to + // "outer" and "promoted" fields respectively. + let b_start = FieldIdx::new(tag_index + 1); + let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.index())); + let offsets_a = offsets; + + // Disentangle the "a" and "b" components of `inverse_memory_index` + // by preserving the order but keeping only one disjoint "half" each. + // FIXME(eddyb) build a better abstraction for permutations, if possible. + let inverse_memory_index_b: IndexVec = inverse_memory_index + .iter() + .filter_map(|&i| i.index().checked_sub(b_start.index()).map(FieldIdx::new)) + .collect(); + inverse_memory_index.raw.retain(|&i| i.index() < b_start.index()); + let inverse_memory_index_a = inverse_memory_index; + + // Since `inverse_memory_index_{a,b}` each only refer to their + // respective fields, they can be safely inverted + let memory_index_a = inverse_memory_index_a.invert_bijective_mapping(); + let memory_index_b = inverse_memory_index_b.invert_bijective_mapping(); + + let outer_fields = + FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; + (outer_fields, offsets_b, memory_index_b) + } + _ => unreachable!(), + }; + + let mut size = prefix.size; + let mut align = prefix.align; + let variants = variant_fields + .iter_enumerated() + .map(|(index, variant_fields)| { + // Only include overlap-eligible fields when we compute our variant layout. + let variant_only_tys = variant_fields + .iter() + .filter(|local| match assignments[**local] { + Unassigned => unreachable!(), + Assigned(v) if v == index => true, + Assigned(_) => unreachable!("assignment does not match variant"), + Ineligible(_) => false, + }) + .map(|local| local_layouts[*local]); + + let mut variant = calc.univariant( + &variant_only_tys.collect::>(), + &ReprOptions::default(), + StructKind::Prefixed(prefix_size, prefix_align.abi), + )?; + variant.variants = Variants::Single { index }; + + let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { + unreachable!(); + }; + + // Now, stitch the promoted and variant-only fields back together in + // the order they are mentioned by our CoroutineLayout. + // Because we only use some subset (that can differ between variants) + // of the promoted fields, we can't just pick those elements of the + // `promoted_memory_index` (as we'd end up with gaps). + // So instead, we build an "inverse memory_index", as if all of the + // promoted fields were being used, but leave the elements not in the + // subset as `invalid_field_idx`, which we can filter out later to + // obtain a valid (bijective) mapping. + let invalid_field_idx = promoted_memory_index.len() + memory_index.len(); + let mut combined_inverse_memory_index = + IndexVec::from_elem_n(FieldIdx::new(invalid_field_idx), invalid_field_idx); + + let mut offsets_and_memory_index = iter::zip(offsets, memory_index); + let combined_offsets = variant_fields + .iter_enumerated() + .map(|(i, local)| { + let (offset, memory_index) = match assignments[*local] { + Unassigned => unreachable!(), + Assigned(_) => { + let (offset, memory_index) = offsets_and_memory_index.next().unwrap(); + (offset, promoted_memory_index.len() as u32 + memory_index) + } + Ineligible(field_idx) => { + let field_idx = field_idx.unwrap(); + (promoted_offsets[field_idx], promoted_memory_index[field_idx]) + } + }; + combined_inverse_memory_index[memory_index] = i; + offset + }) + .collect(); + + // Remove the unused slots and invert the mapping to obtain the + // combined `memory_index` (also see previous comment). + combined_inverse_memory_index.raw.retain(|&i| i.index() != invalid_field_idx); + let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping(); + + variant.fields = FieldsShape::Arbitrary { + offsets: combined_offsets, + memory_index: combined_memory_index, + }; + + size = size.max(variant.size); + align = align.max(variant.align); + Ok(variant) + }) + .collect::, _>>()?; + + size = size.align_to(align.abi); + + let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited()); + let abi = BackendRepr::Memory { sized: true }; + + Ok(LayoutData { + variants: Variants::Multiple { + tag, + tag_encoding: TagEncoding::Direct, + tag_field: tag_index, + variants, + }, + fields: outer_fields, + backend_repr: abi, + // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to + // self-referentiality), getting the discriminant can cause aliasing violations. + // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that + // would do the same for us here. + // See , . + // FIXME: Remove when is implemented and aliased coroutine fields are wrapped in `UnsafePinned`. + largest_niche: None, + uninhabited, + size, + align, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Default::default(), + }) +} diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs new file mode 100644 index 0000000000000..0d0706defc2e5 --- /dev/null +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -0,0 +1,148 @@ +use std::num::NonZero; + +use rustc_hashes::Hash64; +use rustc_index::{Idx, IndexVec}; + +use crate::{ + BackendRepr, FieldsShape, HasDataLayout, LayoutData, Niche, Primitive, Scalar, Size, Variants, +}; + +/// "Simple" layout constructors that cannot fail. +impl LayoutData { + pub fn unit(cx: &C, sized: bool) -> Self { + let dl = cx.data_layout(); + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { + offsets: IndexVec::new(), + memory_index: IndexVec::new(), + }, + backend_repr: BackendRepr::Memory { sized }, + largest_niche: None, + uninhabited: false, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::new(0), + } + } + + pub fn never_type(cx: &C) -> Self { + let dl = cx.data_layout(); + // This is also used for uninhabited enums, so we use `Variants::Empty`. + LayoutData { + variants: Variants::Empty, + fields: FieldsShape::Primitive, + backend_repr: BackendRepr::Memory { sized: true }, + largest_niche: None, + uninhabited: true, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::ZERO, + } + } + + pub fn scalar(cx: &C, scalar: Scalar) -> Self { + let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); + let size = scalar.size(cx); + let align = scalar.align(cx); + + let range = scalar.valid_range(cx); + + // All primitive types for which we don't have subtype coercions should get a distinct seed, + // so that types wrapping them can use randomization to arrive at distinct layouts. + // + // Some type information is already lost at this point, so as an approximation we derive + // the seed from what remains. For example on 64-bit targets usize and u64 can no longer + // be distinguished. + let randomization_seed = size + .bytes() + .wrapping_add( + match scalar.primitive() { + Primitive::Int(_, true) => 1, + Primitive::Int(_, false) => 2, + Primitive::Float(_) => 3, + Primitive::Pointer(_) => 4, + } << 32, + ) + // distinguishes references from pointers + .wrapping_add((range.start as u64).rotate_right(16)) + // distinguishes char from u32 and bool from u8 + .wrapping_add((range.end as u64).rotate_right(16)); + + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Primitive, + backend_repr: BackendRepr::Scalar(scalar), + largest_niche, + uninhabited: false, + size, + align, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Hash64::new(randomization_seed), + } + } + + pub fn scalar_pair(cx: &C, a: Scalar, b: Scalar) -> Self { + let dl = cx.data_layout(); + let b_align = b.align(dl); + let align = a.align(dl).max(b_align).max(dl.aggregate_align); + let b_offset = a.size(dl).align_to(b_align.abi); + let size = (b_offset + b.size(dl)).align_to(align.abi); + + // HACK(nox): We iter on `b` and then `a` because `max_by_key` + // returns the last maximum. + let largest_niche = Niche::from_scalar(dl, b_offset, b) + .into_iter() + .chain(Niche::from_scalar(dl, Size::ZERO, a)) + .max_by_key(|niche| niche.available(dl)); + + let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes()); + + LayoutData { + variants: Variants::Single { index: VariantIdx::new(0) }, + fields: FieldsShape::Arbitrary { + offsets: [Size::ZERO, b_offset].into(), + memory_index: [0, 1].into(), + }, + backend_repr: BackendRepr::ScalarPair(a, b), + largest_niche, + uninhabited: false, + align, + size, + max_repr_align: None, + unadjusted_abi_align: align.abi, + randomization_seed: Hash64::new(combined_seed), + } + } + + /// Returns a dummy layout for an uninhabited variant. + /// + /// Uninhabited variants get pruned as part of the layout calculation, + /// so this can be used after the fact to reconstitute a layout. + pub fn uninhabited_variant(cx: &C, index: VariantIdx, fields: usize) -> Self { + let dl = cx.data_layout(); + LayoutData { + variants: Variants::Single { index }, + fields: match NonZero::new(fields) { + Some(fields) => FieldsShape::Union(fields), + None => FieldsShape::Arbitrary { + offsets: IndexVec::new(), + memory_index: IndexVec::new(), + }, + }, + backend_repr: BackendRepr::Memory { sized: true }, + largest_niche: None, + uninhabited: true, + align: dl.i8_align, + size: Size::ZERO, + max_repr_align: None, + unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: Hash64::ZERO, + } + } +} diff --git a/compiler/rustc_abi/src/layout/ty.rs b/compiler/rustc_abi/src/layout/ty.rs index 221e990ae863b..4f43c0e6f8e96 100644 --- a/compiler/rustc_abi/src/layout/ty.rs +++ b/compiler/rustc_abi/src/layout/ty.rs @@ -150,6 +150,12 @@ impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { } } +impl<'a, Ty> AsRef> for TyAndLayout<'a, Ty> { + fn as_ref(&self) -> &LayoutData { + &*self.layout.0.0 + } +} + /// Trait that needs to be implemented by the higher-level type representation /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality. pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug { @@ -219,7 +225,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { C: HasDataLayout, { match self.backend_repr { - BackendRepr::Vector { .. } => self.size == expected_size, + BackendRepr::SimdVector { .. } => self.size == expected_size, BackendRepr::Memory { .. } => { if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { self.field(cx, 0).is_single_vector_element(cx, expected_size) diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 098638b6bcfa7..3f28dc7a1efae 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -5,7 +5,6 @@ #![cfg_attr(feature = "nightly", feature(rustc_attrs))] #![cfg_attr(feature = "nightly", feature(rustdoc_internals))] #![cfg_attr(feature = "nightly", feature(step_trait))] -#![warn(unreachable_pub)] // tidy-alphabetical-end /*! ABI handling for rustc @@ -53,7 +52,7 @@ use rustc_data_structures::stable_hasher::StableOrd; use rustc_hashes::Hash64; use rustc_index::{Idx, IndexSlice, IndexVec}; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable_Generic, Encodable_Generic, HashStable_Generic}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic}; mod callconv; mod layout; @@ -75,7 +74,10 @@ pub use layout::{LayoutCalculator, LayoutCalculatorError}; pub trait HashStableContext {} #[derive(Clone, Copy, PartialEq, Eq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct ReprFlags(u8); bitflags! { @@ -107,7 +109,10 @@ impl std::fmt::Debug for ReprFlags { } #[derive(Copy, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub enum IntegerType { /// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g. /// `Pointer(true)` means `isize`. @@ -128,7 +133,10 @@ impl IntegerType { /// Represents the repr options provided by the user. #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct ReprOptions { pub int: Option, pub align: Option, @@ -205,6 +213,13 @@ impl ReprOptions { } } +/// The maximum supported number of lanes in a SIMD vector. +/// +/// This value is selected based on backend support: +/// * LLVM does not appear to have a vector width limit. +/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. +pub const MAX_SIMD_LANES: u64 = 1 << 0xF; + /// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout) /// for a target, which contains everything needed to compute layouts. #[derive(Debug, PartialEq, Eq)] @@ -329,19 +344,19 @@ impl TargetDataLayout { [p] if p.starts_with('P') => { dl.instruction_address_space = parse_address_space(&p[1..], "P")? } - ["a", ref a @ ..] => dl.aggregate_align = parse_align(a, "a")?, - ["f16", ref a @ ..] => dl.f16_align = parse_align(a, "f16")?, - ["f32", ref a @ ..] => dl.f32_align = parse_align(a, "f32")?, - ["f64", ref a @ ..] => dl.f64_align = parse_align(a, "f64")?, - ["f128", ref a @ ..] => dl.f128_align = parse_align(a, "f128")?, + ["a", a @ ..] => dl.aggregate_align = parse_align(a, "a")?, + ["f16", a @ ..] => dl.f16_align = parse_align(a, "f16")?, + ["f32", a @ ..] => dl.f32_align = parse_align(a, "f32")?, + ["f64", a @ ..] => dl.f64_align = parse_align(a, "f64")?, + ["f128", a @ ..] => dl.f128_align = parse_align(a, "f128")?, // FIXME(erikdesjardins): we should be parsing nonzero address spaces // this will require replacing TargetDataLayout::{pointer_size,pointer_align} // with e.g. `fn pointer_size_in(AddressSpace)` - [p @ "p", s, ref a @ ..] | [p @ "p0", s, ref a @ ..] => { + [p @ "p", s, a @ ..] | [p @ "p0", s, a @ ..] => { dl.pointer_size = parse_size(s, p)?; dl.pointer_align = parse_align(a, p)?; } - [s, ref a @ ..] if s.starts_with('i') => { + [s, a @ ..] if s.starts_with('i') => { let Ok(bits) = s[1..].parse::() else { parse_size(&s[1..], "i")?; // For the user error. continue; @@ -362,7 +377,7 @@ impl TargetDataLayout { dl.i128_align = a; } } - [s, ref a @ ..] if s.starts_with('v') => { + [s, a @ ..] if s.starts_with('v') => { let v_size = parse_size(&s[1..], "v")?; let a = parse_align(a, s)?; if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) { @@ -408,16 +423,21 @@ impl TargetDataLayout { } } + /// psABI-mandated alignment for a vector type, if any #[inline] - pub fn vector_align(&self, vec_size: Size) -> AbiAndPrefAlign { - for &(size, align) in &self.vector_align { - if size == vec_size { - return align; - } - } - // Default to natural alignment, which is what LLVM does. - // That is, use the size, rounded up to a power of 2. - AbiAndPrefAlign::new(Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap()) + fn cabi_vector_align(&self, vec_size: Size) -> Option { + self.vector_align + .iter() + .find(|(size, _align)| *size == vec_size) + .map(|(_size, align)| *align) + } + + /// an alignment resembling the one LLVM would pick for a vector + #[inline] + pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAndPrefAlign { + self.cabi_vector_align(vec_size).unwrap_or(AbiAndPrefAlign::new( + Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(), + )) } } @@ -476,7 +496,10 @@ impl FromStr for Endian { /// Size of a type in bytes. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct Size { raw: u64, } @@ -702,7 +725,10 @@ impl Step for Size { /// Alignment of a type in bytes (always a power of two). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub struct Align { pow2: u8, } @@ -791,7 +817,7 @@ impl Align { } #[inline] - pub fn bytes(self) -> u64 { + pub const fn bytes(self) -> u64 { 1 << self.pow2 } @@ -801,7 +827,7 @@ impl Align { } #[inline] - pub fn bits(self) -> u64 { + pub const fn bits(self) -> u64 { self.bytes() * 8 } @@ -810,20 +836,19 @@ impl Align { self.bits().try_into().unwrap() } - /// Computes the best alignment possible for the given offset - /// (the largest power of two that the offset is a multiple of). + /// Obtain the greatest factor of `size` that is an alignment + /// (the largest power of two the Size is a multiple of). /// - /// N.B., for an offset of `0`, this happens to return `2^64`. + /// Note that all numbers are factors of 0 #[inline] - pub fn max_for_offset(offset: Size) -> Align { - Align { pow2: offset.bytes().trailing_zeros() as u8 } + pub fn max_aligned_factor(size: Size) -> Align { + Align { pow2: size.bytes().trailing_zeros() as u8 } } - /// Lower the alignment, if necessary, such that the given offset - /// is aligned to it (the offset is a multiple of the alignment). + /// Reduces Align to an aligned factor of `size`. #[inline] - pub fn restrict_for_offset(self, offset: Size) -> Align { - self.min(Align::max_for_offset(offset)) + pub fn restrict_for_offset(self, size: Size) -> Align { + self.min(Align::max_aligned_factor(size)) } } @@ -862,7 +887,10 @@ impl AbiAndPrefAlign { /// Integers, also used for enum discriminants. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(Encodable_Generic, Decodable_Generic, HashStable_Generic))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic) +)] pub enum Integer { I8, I16, @@ -1345,7 +1373,7 @@ impl FieldsShape { /// Gets source indices of the fields by increasing offsets. #[inline] - pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator + '_ { + pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator { let mut inverse_small = [0u8; 64]; let mut inverse_big = IndexVec::new(); let use_small = self.count() <= inverse_small.len(); @@ -1406,7 +1434,7 @@ impl AddressSpace { pub enum BackendRepr { Scalar(Scalar), ScalarPair(Scalar, Scalar), - Vector { + SimdVector { element: Scalar, count: u64, }, @@ -1422,9 +1450,9 @@ impl BackendRepr { #[inline] pub fn is_unsized(&self) -> bool { match *self { - BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. } => { - false - } + BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) + | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => !sized, } } @@ -1455,37 +1483,38 @@ impl BackendRepr { matches!(*self, BackendRepr::Scalar(s) if s.is_bool()) } - /// Returns the fixed alignment of this ABI, if any is mandated. - pub fn inherent_align(&self, cx: &C) -> Option { - Some(match *self { - BackendRepr::Scalar(s) => s.align(cx), - BackendRepr::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)), - BackendRepr::Vector { element, count } => { - cx.data_layout().vector_align(element.size(cx) * count) - } - BackendRepr::Memory { .. } => return None, - }) + /// The psABI alignment for a `Scalar` or `ScalarPair` + /// + /// `None` for other variants. + pub fn scalar_align(&self, cx: &C) -> Option { + match *self { + BackendRepr::Scalar(s) => Some(s.align(cx).abi), + BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi), + // The align of a Vector can vary in surprising ways + BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + } } - /// Returns the fixed size of this ABI, if any is mandated. - pub fn inherent_size(&self, cx: &C) -> Option { - Some(match *self { - BackendRepr::Scalar(s) => { - // No padding in scalars. - s.size(cx) - } + /// The psABI size for a `Scalar` or `ScalarPair` + /// + /// `None` for other variants + pub fn scalar_size(&self, cx: &C) -> Option { + match *self { + // No padding in scalars. + BackendRepr::Scalar(s) => Some(s.size(cx)), + // May have some padding between the pair. BackendRepr::ScalarPair(s1, s2) => { - // May have some padding between the pair. let field2_offset = s1.size(cx).align_to(s2.align(cx).abi); - (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi) + let size = (field2_offset + s2.size(cx)).align_to( + self.scalar_align(cx) + // We absolutely must have an answer here or everything is FUBAR. + .unwrap(), + ); + Some(size) } - BackendRepr::Vector { element, count } => { - // No padding in vectors, except possibly for trailing padding - // to make the size a multiple of align (e.g. for vectors of size 3). - (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi) - } - BackendRepr::Memory { .. } => return None, - }) + // The size of a Vector can vary in surprising ways + BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None, + } } /// Discard validity range information and allow undef. @@ -1495,8 +1524,8 @@ impl BackendRepr { BackendRepr::ScalarPair(s1, s2) => { BackendRepr::ScalarPair(s1.to_union(), s2.to_union()) } - BackendRepr::Vector { element, count } => { - BackendRepr::Vector { element: element.to_union(), count } + BackendRepr::SimdVector { element, count } => { + BackendRepr::SimdVector { element: element.to_union(), count } } BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true }, } @@ -1508,8 +1537,8 @@ impl BackendRepr { // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x). (BackendRepr::Scalar(l), BackendRepr::Scalar(r)) => l.primitive() == r.primitive(), ( - BackendRepr::Vector { element: element_l, count: count_l }, - BackendRepr::Vector { element: element_r, count: count_r }, + BackendRepr::SimdVector { element: element_l, count: count_l }, + BackendRepr::SimdVector { element: element_r, count: count_r }, ) => element_l.primitive() == element_r.primitive() && count_l == count_r, (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => { l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive() @@ -1730,7 +1759,7 @@ impl LayoutData { /// Returns `true` if this is an aggregate type (including a ScalarPair!) pub fn is_aggregate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => false, + BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true, } } @@ -1739,48 +1768,6 @@ impl LayoutData { pub fn is_uninhabited(&self) -> bool { self.uninhabited } - - pub fn scalar(cx: &C, scalar: Scalar) -> Self { - let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); - let size = scalar.size(cx); - let align = scalar.align(cx); - - let range = scalar.valid_range(cx); - - // All primitive types for which we don't have subtype coercions should get a distinct seed, - // so that types wrapping them can use randomization to arrive at distinct layouts. - // - // Some type information is already lost at this point, so as an approximation we derive - // the seed from what remains. For example on 64-bit targets usize and u64 can no longer - // be distinguished. - let randomization_seed = size - .bytes() - .wrapping_add( - match scalar.primitive() { - Primitive::Int(_, true) => 1, - Primitive::Int(_, false) => 2, - Primitive::Float(_) => 3, - Primitive::Pointer(_) => 4, - } << 32, - ) - // distinguishes references from pointers - .wrapping_add((range.start as u64).rotate_right(16)) - // distinguishes char from u32 and bool from u8 - .wrapping_add((range.end as u64).rotate_right(16)); - - LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, - fields: FieldsShape::Primitive, - backend_repr: BackendRepr::Scalar(scalar), - largest_niche, - uninhabited: false, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: Hash64::new(randomization_seed), - } - } } impl fmt::Debug for LayoutData @@ -1802,12 +1789,12 @@ where variants, max_repr_align, unadjusted_abi_align, - ref randomization_seed, + randomization_seed, } = self; f.debug_struct("Layout") .field("size", size) .field("align", align) - .field("abi", backend_repr) + .field("backend_repr", backend_repr) .field("fields", fields) .field("largest_niche", largest_niche) .field("uninhabited", uninhabited) @@ -1872,9 +1859,9 @@ impl LayoutData { /// non-trivial alignment constraints. You probably want to use `is_1zst` instead. pub fn is_zst(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) | BackendRepr::Vector { .. } => { - false - } + BackendRepr::Scalar(_) + | BackendRepr::ScalarPair(..) + | BackendRepr::SimdVector { .. } => false, BackendRepr::Memory { sized } => sized && self.size.bytes() == 0, } } diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index 382ab2b077547..bbcd8ea6d389d 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_arena" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index b21ccba93bb44..6aaac072e4b28 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -23,7 +23,6 @@ #![feature(maybe_uninit_slice)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::alloc::Layout; @@ -93,7 +92,7 @@ impl ArenaChunk { #[inline] fn end(&mut self) -> *mut T { unsafe { - if mem::size_of::() == 0 { + if size_of::() == 0 { // A pointer as large as possible for zero-sized elements. ptr::without_provenance_mut(!0) } else { @@ -151,7 +150,7 @@ impl TypedArena { } unsafe { - if mem::size_of::() == 0 { + if size_of::() == 0 { self.ptr.set(self.ptr.get().wrapping_byte_add(1)); let ptr = ptr::NonNull::::dangling().as_ptr(); // Don't drop the object. This `write` is equivalent to `forget`. @@ -173,13 +172,13 @@ impl TypedArena { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). let available_bytes = self.end.get().addr() - self.ptr.get().addr(); - let additional_bytes = additional.checked_mul(mem::size_of::()).unwrap(); + let additional_bytes = additional.checked_mul(size_of::()).unwrap(); available_bytes >= additional_bytes } #[inline] fn alloc_raw_slice(&self, len: usize) -> *mut T { - assert!(mem::size_of::() != 0); + assert!(size_of::() != 0); assert!(len != 0); // Ensure the current chunk can fit `len` objects. @@ -213,7 +212,7 @@ impl TypedArena { // So we collect all the elements beforehand, which takes care of reentrancy and panic // safety. This function is much less hot than `DroplessArena::alloc_from_iter`, so it // doesn't need to be hyper-optimized. - assert!(mem::size_of::() != 0); + assert!(size_of::() != 0); let mut vec: SmallVec<[_; 8]> = iter.into_iter().collect(); if vec.is_empty() { @@ -236,7 +235,7 @@ impl TypedArena { unsafe { // We need the element size to convert chunk sizes (ranging from // PAGE to HUGE_PAGE bytes) to element counts. - let elem_size = cmp::max(1, mem::size_of::()); + let elem_size = cmp::max(1, size_of::()); let mut chunks = self.chunks.borrow_mut(); let mut new_cap; if let Some(last_chunk) = chunks.last_mut() { @@ -246,7 +245,7 @@ impl TypedArena { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). let used_bytes = self.ptr.get().addr() - last_chunk.start().addr(); - last_chunk.entries = used_bytes / mem::size_of::(); + last_chunk.entries = used_bytes / size_of::(); } // If the previous chunk's len is less than HUGE_PAGE @@ -276,7 +275,7 @@ impl TypedArena { let end = self.ptr.get().addr(); // We then calculate the number of elements to be dropped in the last chunk, // which is the filled area's length. - let diff = if mem::size_of::() == 0 { + let diff = if size_of::() == 0 { // `T` is ZST. It can't have a drop flag, so the value here doesn't matter. We get // the number of zero-sized values in the last and only chunk, just out of caution. // Recall that `end` was incremented for each allocated value. @@ -284,7 +283,7 @@ impl TypedArena { } else { // FIXME: this should *likely* use `offset_from`, but more // investigation is needed (including running tests in miri). - (end - start) / mem::size_of::() + (end - start) / size_of::() }; // Pass that to the `destroy` method. unsafe { @@ -329,7 +328,7 @@ fn align_up(val: usize, align: usize) -> usize { // Pointer alignment is common in compiler types, so keep `DroplessArena` aligned to them // to optimize away alignment code. -const DROPLESS_ALIGNMENT: usize = mem::align_of::(); +const DROPLESS_ALIGNMENT: usize = align_of::(); /// An arena that can hold objects of multiple different types that impl `Copy` /// and/or satisfy `!mem::needs_drop`. @@ -447,7 +446,7 @@ impl DroplessArena { #[inline] pub fn alloc(&self, object: T) -> &mut T { assert!(!mem::needs_drop::()); - assert!(mem::size_of::() != 0); + assert!(size_of::() != 0); let mem = self.alloc_raw(Layout::new::()) as *mut T; @@ -471,7 +470,7 @@ impl DroplessArena { T: Copy, { assert!(!mem::needs_drop::()); - assert!(mem::size_of::() != 0); + assert!(size_of::() != 0); assert!(!slice.is_empty()); let mem = self.alloc_raw(Layout::for_value::<[T]>(slice)) as *mut T; @@ -546,7 +545,7 @@ impl DroplessArena { // Warning: this function is reentrant: `iter` could hold a reference to `&self` and // allocate additional elements while we're iterating. let iter = iter.into_iter(); - assert!(mem::size_of::() != 0); + assert!(size_of::() != 0); assert!(!mem::needs_drop::()); let size_hint = iter.size_hint(); diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml index 34c612dac692b..902287d032802 100644 --- a/compiler/rustc_ast/Cargo.toml +++ b/compiler/rustc_ast/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 29c1d34a125a4..1b831c454e6d5 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -39,7 +39,7 @@ pub use crate::format::*; use crate::ptr::P; use crate::token::{self, CommentKind, Delimiter}; use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream}; -use crate::util::parser::{AssocOp, ExprPrecedence}; +use crate::util::parser::{ExprPrecedence, Fixity}; /// A "Label" is an identifier of some point in sources, /// e.g. in the following code: @@ -124,10 +124,19 @@ impl Path { self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot) } - /// If this path is a single identifier with no arguments, does not ensure - /// that the path resolves to a const param, the caller should check this. - pub fn is_potential_trivial_const_arg(&self) -> bool { - matches!(self.segments[..], [PathSegment { args: None, .. }]) + /// Check if this path is potentially a trivial const arg, i.e., one that can _potentially_ + /// be represented without an anon const in the HIR. + /// + /// If `allow_mgca_arg` is true (as should be the case in most situations when + /// `#![feature(min_generic_const_args)]` is enabled), then this always returns true + /// because all paths are valid. + /// + /// Otherwise, it returns true iff the path has exactly one segment, and it has no generic args + /// (i.e., it is _potentially_ a const parameter). + #[tracing::instrument(level = "debug", ret)] + pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { + allow_mgca_arg + || self.segments.len() == 1 && self.segments.iter().all(|seg| seg.args.is_none()) } } @@ -417,9 +426,11 @@ impl WhereClause { /// A single predicate in a where-clause. #[derive(Clone, Encodable, Decodable, Debug)] pub struct WherePredicate { + pub attrs: AttrVec, pub kind: WherePredicateKind, pub id: NodeId, pub span: Span, + pub is_placeholder: bool, } /// Predicate kind in where-clause. @@ -937,8 +948,37 @@ impl BinOpKind { matches!(self, BinOpKind::And | BinOpKind::Or) } + pub fn precedence(&self) -> ExprPrecedence { + use BinOpKind::*; + match *self { + Mul | Div | Rem => ExprPrecedence::Product, + Add | Sub => ExprPrecedence::Sum, + Shl | Shr => ExprPrecedence::Shift, + BitAnd => ExprPrecedence::BitAnd, + BitXor => ExprPrecedence::BitXor, + BitOr => ExprPrecedence::BitOr, + Lt | Gt | Le | Ge | Eq | Ne => ExprPrecedence::Compare, + And => ExprPrecedence::LAnd, + Or => ExprPrecedence::LOr, + } + } + + pub fn fixity(&self) -> Fixity { + use BinOpKind::*; + match self { + Eq | Ne | Lt | Le | Gt | Ge => Fixity::None, + Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => { + Fixity::Left + } + } + } + pub fn is_comparison(self) -> bool { - crate::util::parser::AssocOp::from_ast_binop(self).is_comparison() + use BinOpKind::*; + match self { + Eq | Ne | Lt | Le | Gt | Ge => true, + Add | Sub | Mul | Div | Rem | And | Or | BitXor | BitAnd | BitOr | Shl | Shr => false, + } } /// Returns `true` if the binary operator takes its arguments by value. @@ -1177,22 +1217,31 @@ pub struct Expr { } impl Expr { - /// Could this expr be either `N`, or `{ N }`, where `N` is a const parameter. + /// Check if this expression is potentially a trivial const arg, i.e., one that can _potentially_ + /// be represented without an anon const in the HIR. + /// + /// This will unwrap at most one block level (curly braces). After that, if the expression + /// is a path, it mostly dispatches to [`Path::is_potential_trivial_const_arg`]. + /// See there for more info about `allow_mgca_arg`. /// - /// If this is not the case, name resolution does not resolve `N` when using - /// `min_const_generics` as more complex expressions are not supported. + /// The only additional thing to note is that when `allow_mgca_arg` is false, this function + /// will only allow paths with no qself, before dispatching to the `Path` function of + /// the same name. /// - /// Does not ensure that the path resolves to a const param, the caller should check this. + /// Does not ensure that the path resolves to a const param/item, the caller should check this. /// This also does not consider macros, so it's only correct after macro-expansion. - pub fn is_potential_trivial_const_arg(&self) -> bool { + pub fn is_potential_trivial_const_arg(&self, allow_mgca_arg: bool) -> bool { let this = self.maybe_unwrap_block(); - - if let ExprKind::Path(None, path) = &this.kind - && path.is_potential_trivial_const_arg() - { - true + if allow_mgca_arg { + matches!(this.kind, ExprKind::Path(..)) } else { - false + if let ExprKind::Path(None, path) = &this.kind + && path.is_potential_trivial_const_arg(allow_mgca_arg) + { + true + } else { + false + } } } @@ -1332,7 +1381,7 @@ impl Expr { ExprKind::Range(..) => ExprPrecedence::Range, // Binop-like expr kinds, handled by `AssocOp`. - ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(), + ExprKind::Binary(op, ..) => op.node.precedence(), ExprKind::Cast(..) => ExprPrecedence::Cast, ExprKind::Assign(..) | @@ -1350,6 +1399,7 @@ impl Expr { // Never need parens ExprKind::Array(_) | ExprKind::Await(..) + | ExprKind::Use(..) | ExprKind::Block(..) | ExprKind::Call(..) | ExprKind::ConstBlock(_) @@ -1424,6 +1474,15 @@ pub enum RangeLimits { Closed, } +impl RangeLimits { + pub fn as_str(&self) -> &'static str { + match self { + RangeLimits::HalfOpen => "..", + RangeLimits::Closed => "..=", + } + } +} + /// A method call (e.g. `x.foo::(a, b, c)`). #[derive(Clone, Encodable, Decodable, Debug)] pub struct MethodCall { @@ -1530,6 +1589,8 @@ pub enum ExprKind { Gen(CaptureBy, P, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(P, Span), + /// A use expression (`x.use`). Span is of use keyword. + Use(P, Span), /// A try block (`try { ... }`). TryBlock(P), @@ -1699,8 +1760,17 @@ pub enum CaptureBy { /// The span of the `move` keyword. move_kw: Span, }, - /// `move` keyword was not specified. + /// `move` or `use` keywords were not specified. Ref, + /// `use |x| y + x`. + /// + /// Note that if you have a regular closure like `|| x.use`, this will *not* result + /// in a `Use` capture. Instead, the `ExprUseVisitor` will look at the type + /// of `x` and treat `x.use` as either a copy/clone/move as appropriate. + Use { + /// The span of the `use` keyword. + use_kw: Span, + }, } /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`. @@ -2583,6 +2653,8 @@ pub enum SelfKind { Value(Mutability), /// `&'lt self`, `&'lt mut self` Region(Option, Mutability), + /// `&'lt pin const self`, `&'lt pin mut self` + Pinned(Option, Mutability), /// `self: TYPE`, `mut self: TYPE` Explicit(P, Mutability), } @@ -2592,6 +2664,8 @@ impl SelfKind { match self { SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(), SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()), + SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()), + SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()), SelfKind::Value(_) | SelfKind::Explicit(_, _) => { unreachable!("if we had an explicit self, we wouldn't be here") } @@ -2608,11 +2682,13 @@ impl Param { if ident.name == kw::SelfLower { return match self.ty.kind { TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))), - TyKind::Ref(lt, MutTy { ref ty, mutbl }) - | TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }) + TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { + Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) + } + TyKind::PinnedRef(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => { - Some(respan(self.pat.span, SelfKind::Region(lt, mutbl))) + Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl))) } _ => Some(respan( self.pat.span.to(self.ty.span), @@ -2654,6 +2730,15 @@ impl Param { tokens: None, }), ), + SelfKind::Pinned(lt, mutbl) => ( + mutbl, + P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }), + span, + tokens: None, + }), + ), }; Param { attrs, @@ -3381,6 +3466,7 @@ pub struct Fn { pub generics: Generics, pub sig: FnSig, pub contract: Option>, + pub define_opaque: Option>, pub body: Option>, } @@ -3678,7 +3764,7 @@ mod size_asserts { static_assert_size!(Block, 32); static_assert_size!(Expr, 72); static_assert_size!(ExprKind, 40); - static_assert_size!(Fn, 168); + static_assert_size!(Fn, 176); static_assert_size!(ForeignItem, 88); static_assert_size!(ForeignItemKind, 16); static_assert_size!(GenericArg, 24); diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs index 346edc87c86bc..849cc650e9d6a 100644 --- a/compiler/rustc_ast/src/ast_traits.rs +++ b/compiler/rustc_ast/src/ast_traits.rs @@ -11,7 +11,7 @@ use crate::tokenstream::LazyAttrTokenStream; use crate::{ Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField, FieldDef, ForeignItem, GenericParam, Item, NodeId, Param, Pat, PatField, Path, Stmt, StmtKind, - Ty, Variant, Visibility, + Ty, Variant, Visibility, WherePredicate, }; /// A utility trait to reduce boilerplate. @@ -79,6 +79,7 @@ impl_has_node_id!( Stmt, Ty, Variant, + WherePredicate, ); impl> HasNodeId for T { @@ -127,7 +128,16 @@ macro_rules! impl_has_tokens_none { } impl_has_tokens!(AssocItem, AttrItem, Block, Expr, ForeignItem, Item, Pat, Path, Ty, Visibility); -impl_has_tokens_none!(Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant); +impl_has_tokens_none!( + Arm, + ExprField, + FieldDef, + GenericParam, + Param, + PatField, + Variant, + WherePredicate +); impl> HasTokens for T { fn tokens(&self) -> Option<&LazyAttrTokenStream> { @@ -199,23 +209,13 @@ impl HasTokens for Attribute { impl HasTokens for Nonterminal { fn tokens(&self) -> Option<&LazyAttrTokenStream> { match self { - Nonterminal::NtItem(item) => item.tokens(), - Nonterminal::NtStmt(stmt) => stmt.tokens(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), - Nonterminal::NtPat(pat) => pat.tokens(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens(), - Nonterminal::NtPath(path) => path.tokens(), Nonterminal::NtBlock(block) => block.tokens(), } } fn tokens_mut(&mut self) -> Option<&mut Option> { match self { - Nonterminal::NtItem(item) => item.tokens_mut(), - Nonterminal::NtStmt(stmt) => stmt.tokens_mut(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), - Nonterminal::NtPat(pat) => pat.tokens_mut(), - Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(), - Nonterminal::NtPath(path) => path.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(), } } @@ -285,6 +285,7 @@ impl_has_attrs!( Param, PatField, Variant, + WherePredicate, ); impl_has_attrs_none!(Attribute, AttrItem, Block, Pat, Path, Ty, Visibility); diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index df2f4b8871249..4d613085d793e 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -14,7 +14,7 @@ use crate::ast::{ PathSegment, Safety, }; use crate::ptr::P; -use crate::token::{self, CommentKind, Delimiter, Token}; +use crate::token::{self, CommentKind, Delimiter, InvisibleOrigin, MetaVarKind, Token}; use crate::tokenstream::{ DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenStreamIter, TokenTree, }; @@ -405,11 +405,17 @@ impl MetaItem { let span = span.with_hi(segments.last().unwrap().ident.span.hi()); Path { span, segments, tokens: None } } - Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt { - token::Nonterminal::NtMeta(item) => return item.meta(item.path.span), - token::Nonterminal::NtPath(path) => (**path).clone(), - _ => return None, - }, + Some(TokenTree::Delimited( + _span, + _spacing, + Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Meta { .. } | MetaVarKind::Path, + )), + _stream, + )) => { + // This path is currently unreachable in the test suite. + unreachable!() + } Some(TokenTree::Token( Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _, diff --git a/compiler/rustc_ast/src/format.rs b/compiler/rustc_ast/src/format.rs index b93846c1fe6f3..b611ddea1d9f1 100644 --- a/compiler/rustc_ast/src/format.rs +++ b/compiler/rustc_ast/src/format.rs @@ -266,7 +266,7 @@ pub enum FormatAlignment { #[derive(Clone, Encodable, Decodable, Debug, PartialEq, Eq)] pub enum FormatCount { /// `{:5}` or `{:.5}` - Literal(usize), + Literal(u16), /// `{:.*}`, `{:.5$}`, or `{:a$}`, etc. Argument(FormatArgPosition), } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 6372c66050e7c..da510e4967dba 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(deny(warnings))) @@ -19,7 +20,6 @@ #![feature(never_type)] #![feature(rustdoc_internals)] #![feature(stmt_expr_attributes)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod util { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 40b29fdba2506..4a1636e6aec0e 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -338,8 +338,11 @@ pub trait MutVisitor: Sized { walk_where_clause(self, where_clause); } - fn visit_where_predicate(&mut self, where_predicate: &mut WherePredicate) { - walk_where_predicate(self, where_predicate) + fn flat_map_where_predicate( + &mut self, + where_predicate: WherePredicate, + ) -> SmallVec<[WherePredicate; 1]> { + walk_flat_map_where_predicate(self, where_predicate) } fn visit_where_predicate_kind(&mut self, kind: &mut WherePredicateKind) { @@ -892,29 +895,9 @@ pub fn visit_token(vis: &mut T, t: &mut Token) { // multiple items there.... fn visit_nonterminal(vis: &mut T, nt: &mut token::Nonterminal) { match nt { - token::NtItem(item) => visit_clobber(item, |item| { - // This is probably okay, because the only visitors likely to - // peek inside interpolated nodes will be renamings/markings, - // which map single items to single items. - vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item") - }), token::NtBlock(block) => vis.visit_block(block), - token::NtStmt(stmt) => visit_clobber(stmt, |stmt| { - // See reasoning above. - stmt.map(|stmt| { - vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item") - }) - }), - token::NtPat(pat) => vis.visit_pat(pat), token::NtExpr(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr), - token::NtMeta(item) => { - let AttrItem { unsafety: _, path, args, tokens } = item.deref_mut(); - vis.visit_path(path); - visit_attr_args(vis, args); - visit_lazy_tts(vis, tokens); - } - token::NtPath(path) => vis.visit_path(path), } } @@ -978,7 +961,14 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { _ctxt, _ident, _vis, - Fn { defaultness, generics, contract, body, sig: FnSig { header, decl, span } }, + Fn { + defaultness, + generics, + contract, + body, + sig: FnSig { header, decl, span }, + define_opaque, + }, ) => { // Identifier and visibility are visited as a part of the item. visit_defaultness(vis, defaultness); @@ -992,6 +982,11 @@ fn walk_fn(vis: &mut T, kind: FnKind<'_>) { vis.visit_block(body); } vis.visit_span(span); + + for (id, path) in define_opaque.iter_mut().flatten() { + vis.visit_id(id); + vis.visit_path(path) + } } FnKind::Closure(binder, coroutine_kind, decl, body) => { vis.visit_closure_binder(binder); @@ -1105,15 +1100,20 @@ fn walk_ty_alias_where_clauses(vis: &mut T, tawcs: &mut TyAliasWh fn walk_where_clause(vis: &mut T, wc: &mut WhereClause) { let WhereClause { has_where_token: _, predicates, span } = wc; - visit_thin_vec(predicates, |predicate| vis.visit_where_predicate(predicate)); + predicates.flat_map_in_place(|predicate| vis.flat_map_where_predicate(predicate)); vis.visit_span(span); } -pub fn walk_where_predicate(vis: &mut T, pred: &mut WherePredicate) { - let WherePredicate { kind, id, span } = pred; +pub fn walk_flat_map_where_predicate( + vis: &mut T, + mut pred: WherePredicate, +) -> SmallVec<[WherePredicate; 1]> { + let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = &mut pred; vis.visit_id(id); + visit_attrs(vis, attrs); vis.visit_where_predicate_kind(kind); vis.visit_span(span); + smallvec![pred] } pub fn walk_where_predicate_kind(vis: &mut T, kind: &mut WherePredicateKind) { @@ -1745,6 +1745,10 @@ pub fn walk_expr(vis: &mut T, Expr { kind, id, span, attrs, token vis.visit_expr(expr); vis.visit_span(await_kw_span); } + ExprKind::Use(expr, use_kw_span) => { + vis.visit_expr(expr); + vis.visit_span(use_kw_span); + } ExprKind::Assign(el, er, span) => { vis.visit_expr(el); vis.visit_expr(er); @@ -1895,6 +1899,9 @@ fn walk_capture_by(vis: &mut T, capture_by: &mut CaptureBy) { CaptureBy::Value { move_kw } => { vis.visit_span(move_kw); } + CaptureBy::Use { use_kw } => { + vis.visit_span(use_kw); + } } } @@ -1929,7 +1936,7 @@ impl DummyAstNode for Item { span: Default::default(), tokens: Default::default(), }, - ident: Ident::empty(), + ident: Ident::dummy(), kind: ItemKind::ExternCrate(None), tokens: Default::default(), } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 97d121909f8dd..f7cd63aaaf823 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -2,7 +2,6 @@ use std::borrow::Cow; use std::fmt; use std::sync::Arc; -pub use BinOpToken::*; pub use LitKind::*; pub use Nonterminal::*; pub use NtExprKind::*; @@ -26,21 +25,6 @@ pub enum CommentKind { Block, } -#[derive(Clone, PartialEq, Encodable, Decodable, Hash, Debug, Copy)] -#[derive(HashStable_Generic)] -pub enum BinOpToken { - Plus, - Minus, - Star, - Slash, - Percent, - Caret, - And, - Or, - Shl, - Shr, -} - // This type must not implement `Hash` due to the unusual `PartialEq` impl below. #[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)] pub enum InvisibleOrigin { @@ -90,7 +74,10 @@ pub enum MetaVarKind { Ident, Lifetime, Literal, - Meta, + Meta { + /// Will `AttrItem::meta` succeed on this, if reparsed? + has_meta_form: bool, + }, Path, Vis, TT, @@ -110,7 +97,7 @@ impl fmt::Display for MetaVarKind { MetaVarKind::Ident => sym::ident, MetaVarKind::Lifetime => sym::lifetime, MetaVarKind::Literal => sym::literal, - MetaVarKind::Meta => sym::meta, + MetaVarKind::Meta { .. } => sym::meta, MetaVarKind::Path => sym::path, MetaVarKind::Vis => sym::vis, MetaVarKind::TT => sym::tt, @@ -373,11 +360,49 @@ pub enum TokenKind { /// `||` OrOr, /// `!` - Not, + Bang, /// `~` Tilde, - BinOp(BinOpToken), - BinOpEq(BinOpToken), + // `+` + Plus, + // `-` + Minus, + // `*` + Star, + // `/` + Slash, + // `%` + Percent, + // `^` + Caret, + // `&` + And, + // `|` + Or, + // `<<` + Shl, + // `>>` + Shr, + // `+=` + PlusEq, + // `-=` + MinusEq, + // `*=` + StarEq, + // `/=` + SlashEq, + // `%=` + PercentEq, + // `^=` + CaretEq, + // `&=` + AndEq, + // `|=` + OrEq, + // `<<=` + ShlEq, + // `>>=` + ShrEq, /* Structural symbols */ /// `@` @@ -497,31 +522,31 @@ impl TokenKind { Some(match (self, n) { (Le, 1) => (Lt, Eq), (EqEq, 1) => (Eq, Eq), - (Ne, 1) => (Not, Eq), + (Ne, 1) => (Bang, Eq), (Ge, 1) => (Gt, Eq), - (AndAnd, 1) => (BinOp(And), BinOp(And)), - (OrOr, 1) => (BinOp(Or), BinOp(Or)), - (BinOp(Shl), 1) => (Lt, Lt), - (BinOp(Shr), 1) => (Gt, Gt), - (BinOpEq(Plus), 1) => (BinOp(Plus), Eq), - (BinOpEq(Minus), 1) => (BinOp(Minus), Eq), - (BinOpEq(Star), 1) => (BinOp(Star), Eq), - (BinOpEq(Slash), 1) => (BinOp(Slash), Eq), - (BinOpEq(Percent), 1) => (BinOp(Percent), Eq), - (BinOpEq(Caret), 1) => (BinOp(Caret), Eq), - (BinOpEq(And), 1) => (BinOp(And), Eq), - (BinOpEq(Or), 1) => (BinOp(Or), Eq), - (BinOpEq(Shl), 1) => (Lt, Le), // `<` + `<=` - (BinOpEq(Shl), 2) => (BinOp(Shl), Eq), // `<<` + `=` - (BinOpEq(Shr), 1) => (Gt, Ge), // `>` + `>=` - (BinOpEq(Shr), 2) => (BinOp(Shr), Eq), // `>>` + `=` + (AndAnd, 1) => (And, And), + (OrOr, 1) => (Or, Or), + (Shl, 1) => (Lt, Lt), + (Shr, 1) => (Gt, Gt), + (PlusEq, 1) => (Plus, Eq), + (MinusEq, 1) => (Minus, Eq), + (StarEq, 1) => (Star, Eq), + (SlashEq, 1) => (Slash, Eq), + (PercentEq, 1) => (Percent, Eq), + (CaretEq, 1) => (Caret, Eq), + (AndEq, 1) => (And, Eq), + (OrEq, 1) => (Or, Eq), + (ShlEq, 1) => (Lt, Le), // `<` + `<=` + (ShlEq, 2) => (Shl, Eq), // `<<` + `=` + (ShrEq, 1) => (Gt, Ge), // `>` + `>=` + (ShrEq, 2) => (Shr, Eq), // `>>` + `=` (DotDot, 1) => (Dot, Dot), (DotDotDot, 1) => (Dot, DotDot), // `.` + `..` (DotDotDot, 2) => (DotDot, Dot), // `..` + `.` (DotDotEq, 2) => (DotDot, Eq), (PathSep, 1) => (Colon, Colon), - (RArrow, 1) => (BinOp(Minus), Gt), - (LArrow, 1) => (Lt, BinOp(Minus)), + (RArrow, 1) => (Minus, Gt), + (LArrow, 1) => (Lt, Minus), (FatArrow, 1) => (Eq, Gt), _ => return None, }) @@ -540,7 +565,7 @@ impl TokenKind { } pub fn should_end_const_arg(&self) -> bool { - matches!(self, Gt | Ge | BinOp(Shr) | BinOpEq(Shr)) + matches!(self, Gt | Ge | Shr | ShrEq) } } @@ -579,11 +604,11 @@ impl Token { pub fn is_punct(&self) -> bool { match self.kind { - Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_) - | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon - | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | SingleQuote => { - true - } + Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Bang | Tilde | Plus | Minus + | Star | Slash | Percent | Caret | And | Or | Shl | Shr | PlusEq | MinusEq | StarEq + | SlashEq | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | Dot | DotDot + | DotDotDot | DotDotEq | Comma | Semi | Colon | PathSep | RArrow | LArrow + | FatArrow | Pound | Dollar | Question | SingleQuote => true, OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false, @@ -591,7 +616,7 @@ impl Token { } pub fn is_like_plus(&self) -> bool { - matches!(self.kind, BinOp(Plus) | BinOpEq(Plus)) + matches!(self.kind, Plus | PlusEq) } /// Returns `true` if the token can appear at the start of an expression. @@ -605,15 +630,15 @@ impl Token { ident_can_begin_expr(name, self.span, is_raw), // value name or keyword OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block Literal(..) | // literal - Not | // operator not - BinOp(Minus) | // unary minus - BinOp(Star) | // dereference - BinOp(Or) | OrOr | // closure - BinOp(And) | // reference + Bang | // operator not + Minus | // unary minus + Star | // dereference + Or | OrOr | // closure + And | // reference AndAnd | // double reference // DotDotDot is no longer supported, but we need some way to display the error DotDot | DotDotDot | DotDotEq | // range notation - Lt | BinOp(Shl) | // associated path + Lt | Shl | // associated path PathSep | // global path Lifetime(..) | // labeled loop Pound => true, // expression attributes @@ -621,8 +646,7 @@ impl Token { matches!(&**nt, NtBlock(..) | NtExpr(..) | - NtLiteral(..) | - NtPath(..) + NtLiteral(..) ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Block | @@ -643,29 +667,25 @@ impl Token { Ident(..) | NtIdent(..) | OpenDelim(Delimiter::Parenthesis) | // tuple pattern OpenDelim(Delimiter::Bracket) | // slice pattern - BinOp(And) | // reference - BinOp(Minus) | // negative literal - AndAnd | // double reference - Literal(_) | // literal - DotDot | // range pattern (future compat) - DotDotDot | // range pattern (future compat) - PathSep | // path - Lt | // path (UFCS constant) - BinOp(Shl) => true, // path (double UFCS) - // leading vert `|` or-pattern - BinOp(Or) => matches!(pat_kind, PatWithOr), + And | // reference + Minus | // negative literal + AndAnd | // double reference + Literal(_) | // literal + DotDot | // range pattern (future compat) + DotDotDot | // range pattern (future compat) + PathSep | // path + Lt | // path (UFCS constant) + Shl => true, // path (double UFCS) + Or => matches!(pat_kind, PatWithOr), // leading vert `|` or-pattern Interpolated(nt) => matches!(&**nt, | NtExpr(..) | NtLiteral(..) - | NtMeta(..) - | NtPat(..) - | NtPath(..) ), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Literal | - MetaVarKind::Meta | + MetaVarKind::Meta { .. } | MetaVarKind::Pat(_) | MetaVarKind::Path | MetaVarKind::Ty { .. } @@ -677,19 +697,18 @@ impl Token { /// Returns `true` if the token can appear at the start of a type. pub fn can_begin_type(&self) -> bool { match self.uninterpolate().kind { - Ident(name, is_raw) => + Ident(name, is_raw) => ident_can_begin_type(name, self.span, is_raw), // type name or keyword OpenDelim(Delimiter::Parenthesis) | // tuple OpenDelim(Delimiter::Bracket) | // array - Not | // never - BinOp(Star) | // raw pointer - BinOp(And) | // reference - AndAnd | // double reference - Question | // maybe bound in trait object - Lifetime(..) | // lifetime bound in trait object - Lt | BinOp(Shl) | // associated path - PathSep => true, // global path - Interpolated(ref nt) => matches!(&**nt, NtPath(..)), + Bang | // never + Star | // raw pointer + And | // reference + AndAnd | // double reference + Question | // maybe bound in trait object + Lifetime(..) | // lifetime bound in trait object + Lt | Shl | // associated path + PathSep => true, // global path OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( MetaVarKind::Ty { .. } | MetaVarKind::Path @@ -703,7 +722,7 @@ impl Token { /// Returns `true` if the token can appear at the start of a const param. pub fn can_begin_const_arg(&self) -> bool { match self.kind { - OpenDelim(Delimiter::Brace) | Literal(..) | BinOp(Minus) => true, + OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)), OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( @@ -752,7 +771,7 @@ impl Token { /// Keep this in sync with and `Lit::from_token`, excluding unary negation. pub fn can_begin_literal_maybe_minus(&self) -> bool { match self.uninterpolate().kind { - Literal(..) | BinOp(Minus) => true, + Literal(..) | Minus => true, Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true, Interpolated(ref nt) => match &**nt { NtLiteral(_) => true, @@ -848,27 +867,17 @@ impl Token { self.ident().is_some_and(|(ident, _)| ident.name == name) } - /// Returns `true` if the token is an interpolated path. - fn is_whole_path(&self) -> bool { - if let Interpolated(nt) = &self.kind - && let NtPath(..) = &**nt - { - return true; - } - - false - } - /// Is this a pre-parsed expression dropped into the token stream /// (which happens while parsing the result of macro expansion)? pub fn is_whole_expr(&self) -> bool { + #[allow(irrefutable_let_patterns)] // FIXME: temporary if let Interpolated(nt) = &self.kind - && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt + && let NtExpr(_) | NtLiteral(_) | NtBlock(_) = &**nt { - return true; + true + } else { + matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) } - - false } /// Is the token an interpolated block (`$b:block`)? @@ -888,13 +897,13 @@ impl Token { } pub fn is_qpath_start(&self) -> bool { - self == &Lt || self == &BinOp(Shl) + self == &Lt || self == &Shl } pub fn is_path_start(&self) -> bool { self == &PathSep || self.is_qpath_start() - || self.is_whole_path() + || matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) || self.is_path_segment_keyword() || self.is_ident() && !self.is_reserved_ident() } @@ -980,59 +989,82 @@ impl Token { } pub fn glue(&self, joint: &Token) -> Option { - let kind = match self.kind { - Eq => match joint.kind { - Eq => EqEq, - Gt => FatArrow, - _ => return None, - }, - Lt => match joint.kind { - Eq => Le, - Lt => BinOp(Shl), - Le => BinOpEq(Shl), - BinOp(Minus) => LArrow, - _ => return None, - }, - Gt => match joint.kind { - Eq => Ge, - Gt => BinOp(Shr), - Ge => BinOpEq(Shr), - _ => return None, - }, - Not => match joint.kind { - Eq => Ne, - _ => return None, - }, - BinOp(op) => match joint.kind { - Eq => BinOpEq(op), - BinOp(And) if op == And => AndAnd, - BinOp(Or) if op == Or => OrOr, - Gt if op == Minus => RArrow, - _ => return None, - }, - Dot => match joint.kind { - Dot => DotDot, - DotDot => DotDotDot, - _ => return None, - }, - DotDot => match joint.kind { - Dot => DotDotDot, - Eq => DotDotEq, - _ => return None, - }, - Colon => match joint.kind { - Colon => PathSep, - _ => return None, - }, - SingleQuote => match joint.kind { - Ident(name, is_raw) => Lifetime(Symbol::intern(&format!("'{name}")), is_raw), - _ => return None, - }, + let kind = match (&self.kind, &joint.kind) { + (Eq, Eq) => EqEq, + (Eq, Gt) => FatArrow, + (Eq, _) => return None, + + (Lt, Eq) => Le, + (Lt, Lt) => Shl, + (Lt, Le) => ShlEq, + (Lt, Minus) => LArrow, + (Lt, _) => return None, - Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot - | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar - | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) - | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => { + (Gt, Eq) => Ge, + (Gt, Gt) => Shr, + (Gt, Ge) => ShrEq, + (Gt, _) => return None, + + (Bang, Eq) => Ne, + (Bang, _) => return None, + + (Plus, Eq) => PlusEq, + (Plus, _) => return None, + + (Minus, Eq) => MinusEq, + (Minus, Gt) => RArrow, + (Minus, _) => return None, + + (Star, Eq) => StarEq, + (Star, _) => return None, + + (Slash, Eq) => SlashEq, + (Slash, _) => return None, + + (Percent, Eq) => PercentEq, + (Percent, _) => return None, + + (Caret, Eq) => CaretEq, + (Caret, _) => return None, + + (And, Eq) => AndEq, + (And, And) => AndAnd, + (And, _) => return None, + + (Or, Eq) => OrEq, + (Or, Or) => OrOr, + (Or, _) => return None, + + (Shl, Eq) => ShlEq, + (Shl, _) => return None, + + (Shr, Eq) => ShrEq, + (Shr, _) => return None, + + (Dot, Dot) => DotDot, + (Dot, DotDot) => DotDotDot, + (Dot, _) => return None, + + (DotDot, Dot) => DotDotDot, + (DotDot, Eq) => DotDotEq, + (DotDot, _) => return None, + + (Colon, Colon) => PathSep, + (Colon, _) => return None, + + (SingleQuote, Ident(name, is_raw)) => { + Lifetime(Symbol::intern(&format!("'{name}")), *is_raw) + } + (SingleQuote, _) => return None, + + ( + Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | PlusEq | MinusEq | StarEq | SlashEq + | PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq + | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question + | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..) + | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof, + _, + ) => { return None; } }; @@ -1072,15 +1104,9 @@ pub enum NtExprKind { #[derive(Clone, Encodable, Decodable)] /// For interpolation during macro expansion. pub enum Nonterminal { - NtItem(P), NtBlock(P), - NtStmt(P), - NtPat(P), NtExpr(P), NtLiteral(P), - /// Stuff inside brackets for attributes - NtMeta(P), - NtPath(P), } #[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)] @@ -1169,26 +1195,16 @@ impl fmt::Display for NonterminalKind { impl Nonterminal { pub fn use_span(&self) -> Span { match self { - NtItem(item) => item.span, NtBlock(block) => block.span, - NtStmt(stmt) => stmt.span, - NtPat(pat) => pat.span, NtExpr(expr) | NtLiteral(expr) => expr.span, - NtMeta(attr_item) => attr_item.span(), - NtPath(path) => path.span, } } pub fn descr(&self) -> &'static str { match self { - NtItem(..) => "item", NtBlock(..) => "block", - NtStmt(..) => "statement", - NtPat(..) => "pattern", NtExpr(..) => "expression", NtLiteral(..) => "literal", - NtMeta(..) => "attribute", - NtPath(..) => "path", } } } @@ -1206,14 +1222,9 @@ impl PartialEq for Nonterminal { impl fmt::Debug for Nonterminal { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - NtItem(..) => f.pad("NtItem(..)"), NtBlock(..) => f.pad("NtBlock(..)"), - NtStmt(..) => f.pad("NtStmt(..)"), - NtPat(..) => f.pad("NtPat(..)"), NtExpr(..) => f.pad("NtExpr(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"), - NtMeta(..) => f.pad("NtMeta(..)"), - NtPath(..) => f.pad("NtPath(..)"), } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index 1123ea3a449b6..bdd244be6d1cc 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -23,7 +23,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Encodable}; use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; -use crate::ast::{AttrStyle, StmtKind}; +use crate::ast::AttrStyle; use crate::ast_traits::{HasAttrs, HasTokens}; use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind}; use crate::{AttrVec, Attribute}; @@ -461,16 +461,7 @@ impl TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { match nt { - Nonterminal::NtItem(item) => TokenStream::from_ast(item), Nonterminal::NtBlock(block) => TokenStream::from_ast(block), - Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => { - // FIXME: Properly collect tokens for empty statements. - TokenStream::token_alone(token::Semi, stmt.span) - } - Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt), - Nonterminal::NtPat(pat) => TokenStream::from_ast(pat), - Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr), - Nonterminal::NtPath(path) => TokenStream::from_ast(path), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), } } @@ -654,7 +645,7 @@ impl TokenStream { if attr_style == AttrStyle::Inner { vec![ TokenTree::token_joint(token::Pound, span), - TokenTree::token_joint_hidden(token::Not, span), + TokenTree::token_joint_hidden(token::Bang, span), body, ] } else { diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 64f2a98b8a6fc..e43d78f6e7217 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -108,6 +108,7 @@ pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { Assign(e, _, _) | AssignOp(_, e, _) | Await(e, _) + | Use(e, _) | Binary(_, e, _) | Call(e, _) | Cast(e, _) @@ -224,6 +225,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option> { | Lit(_) | Type(_, _) | Await(_, _) + | Use(_, _) | Field(_, _) | Index(_, _, _) | Underscore diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 8f2b7a23c01c8..98b1fc52ed747 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -1,59 +1,21 @@ use rustc_span::kw; -use crate::ast::{self, BinOpKind}; -use crate::token::{self, BinOpToken, Token}; +use crate::ast::{self, BinOpKind, RangeLimits}; +use crate::token::{self, Token}; -/// Associative operator with precedence. -/// -/// This is the enum which specifies operator precedence and fixity to the parser. +/// Associative operator. #[derive(Copy, Clone, PartialEq, Debug)] pub enum AssocOp { - /// `+` - Add, - /// `-` - Subtract, - /// `*` - Multiply, - /// `/` - Divide, - /// `%` - Modulus, - /// `&&` - LAnd, - /// `||` - LOr, - /// `^` - BitXor, - /// `&` - BitAnd, - /// `|` - BitOr, - /// `<<` - ShiftLeft, - /// `>>` - ShiftRight, - /// `==` - Equal, - /// `<` - Less, - /// `<=` - LessEqual, - /// `!=` - NotEqual, - /// `>` - Greater, - /// `>=` - GreaterEqual, + /// A binary op. + Binary(BinOpKind), + /// `?=` where ? is one of the assignable BinOps + AssignOp(BinOpKind), /// `=` Assign, - /// `?=` where ? is one of the BinOpToken - AssignOp(BinOpToken), /// `as` - As, - /// `..` range - DotDot, - /// `..=` range - DotDotEq, + Cast, + /// `..` or `..=` range + Range(RangeLimits), } #[derive(PartialEq, Debug)] @@ -67,81 +29,56 @@ pub enum Fixity { } impl AssocOp { - /// Creates a new AssocOP from a token + /// Creates a new AssocOp from a token. pub fn from_token(t: &Token) -> Option { use AssocOp::*; match t.kind { - token::BinOpEq(k) => Some(AssignOp(k)), token::Eq => Some(Assign), - token::BinOp(BinOpToken::Star) => Some(Multiply), - token::BinOp(BinOpToken::Slash) => Some(Divide), - token::BinOp(BinOpToken::Percent) => Some(Modulus), - token::BinOp(BinOpToken::Plus) => Some(Add), - token::BinOp(BinOpToken::Minus) => Some(Subtract), - token::BinOp(BinOpToken::Shl) => Some(ShiftLeft), - token::BinOp(BinOpToken::Shr) => Some(ShiftRight), - token::BinOp(BinOpToken::And) => Some(BitAnd), - token::BinOp(BinOpToken::Caret) => Some(BitXor), - token::BinOp(BinOpToken::Or) => Some(BitOr), - token::Lt => Some(Less), - token::Le => Some(LessEqual), - token::Ge => Some(GreaterEqual), - token::Gt => Some(Greater), - token::EqEq => Some(Equal), - token::Ne => Some(NotEqual), - token::AndAnd => Some(LAnd), - token::OrOr => Some(LOr), - token::DotDot => Some(DotDot), - token::DotDotEq => Some(DotDotEq), + token::Plus => Some(Binary(BinOpKind::Add)), + token::Minus => Some(Binary(BinOpKind::Sub)), + token::Star => Some(Binary(BinOpKind::Mul)), + token::Slash => Some(Binary(BinOpKind::Div)), + token::Percent => Some(Binary(BinOpKind::Rem)), + token::Caret => Some(Binary(BinOpKind::BitXor)), + token::And => Some(Binary(BinOpKind::BitAnd)), + token::Or => Some(Binary(BinOpKind::BitOr)), + token::Shl => Some(Binary(BinOpKind::Shl)), + token::Shr => Some(Binary(BinOpKind::Shr)), + token::PlusEq => Some(AssignOp(BinOpKind::Add)), + token::MinusEq => Some(AssignOp(BinOpKind::Sub)), + token::StarEq => Some(AssignOp(BinOpKind::Mul)), + token::SlashEq => Some(AssignOp(BinOpKind::Div)), + token::PercentEq => Some(AssignOp(BinOpKind::Rem)), + token::CaretEq => Some(AssignOp(BinOpKind::BitXor)), + token::AndEq => Some(AssignOp(BinOpKind::BitAnd)), + token::OrEq => Some(AssignOp(BinOpKind::BitOr)), + token::ShlEq => Some(AssignOp(BinOpKind::Shl)), + token::ShrEq => Some(AssignOp(BinOpKind::Shr)), + token::Lt => Some(Binary(BinOpKind::Lt)), + token::Le => Some(Binary(BinOpKind::Le)), + token::Ge => Some(Binary(BinOpKind::Ge)), + token::Gt => Some(Binary(BinOpKind::Gt)), + token::EqEq => Some(Binary(BinOpKind::Eq)), + token::Ne => Some(Binary(BinOpKind::Ne)), + token::AndAnd => Some(Binary(BinOpKind::And)), + token::OrOr => Some(Binary(BinOpKind::Or)), + token::DotDot => Some(Range(RangeLimits::HalfOpen)), // DotDotDot is no longer supported, but we need some way to display the error - token::DotDotDot => Some(DotDotEq), + token::DotDotEq | token::DotDotDot => Some(Range(RangeLimits::Closed)), // `<-` should probably be `< -` - token::LArrow => Some(Less), - _ if t.is_keyword(kw::As) => Some(As), + token::LArrow => Some(Binary(BinOpKind::Lt)), + _ if t.is_keyword(kw::As) => Some(Cast), _ => None, } } - /// Creates a new AssocOp from ast::BinOpKind. - pub fn from_ast_binop(op: BinOpKind) -> Self { - use AssocOp::*; - match op { - BinOpKind::Lt => Less, - BinOpKind::Gt => Greater, - BinOpKind::Le => LessEqual, - BinOpKind::Ge => GreaterEqual, - BinOpKind::Eq => Equal, - BinOpKind::Ne => NotEqual, - BinOpKind::Mul => Multiply, - BinOpKind::Div => Divide, - BinOpKind::Rem => Modulus, - BinOpKind::Add => Add, - BinOpKind::Sub => Subtract, - BinOpKind::Shl => ShiftLeft, - BinOpKind::Shr => ShiftRight, - BinOpKind::BitAnd => BitAnd, - BinOpKind::BitXor => BitXor, - BinOpKind::BitOr => BitOr, - BinOpKind::And => LAnd, - BinOpKind::Or => LOr, - } - } - /// Gets the precedence of this operator pub fn precedence(&self) -> ExprPrecedence { use AssocOp::*; match *self { - As => ExprPrecedence::Cast, - Multiply | Divide | Modulus => ExprPrecedence::Product, - Add | Subtract => ExprPrecedence::Sum, - ShiftLeft | ShiftRight => ExprPrecedence::Shift, - BitAnd => ExprPrecedence::BitAnd, - BitXor => ExprPrecedence::BitXor, - BitOr => ExprPrecedence::BitOr, - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => ExprPrecedence::Compare, - LAnd => ExprPrecedence::LAnd, - LOr => ExprPrecedence::LOr, - DotDot | DotDotEq => ExprPrecedence::Range, + Cast => ExprPrecedence::Cast, + Binary(bin_op) => bin_op.precedence(), + Range(_) => ExprPrecedence::Range, Assign | AssignOp(_) => ExprPrecedence::Assign, } } @@ -152,22 +89,17 @@ impl AssocOp { // NOTE: it is a bug to have an operators that has same precedence but different fixities! match *self { Assign | AssignOp(_) => Fixity::Right, - As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd - | BitXor | BitOr | LAnd | LOr => Fixity::Left, - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | DotDot | DotDotEq => { - Fixity::None - } + Binary(binop) => binop.fixity(), + Cast => Fixity::Left, + Range(_) => Fixity::None, } } pub fn is_comparison(&self) -> bool { use AssocOp::*; match *self { - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true, - Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract - | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq => { - false - } + Binary(binop) => binop.is_comparison(), + Assign | AssignOp(_) | Cast | Range(_) => false, } } @@ -175,34 +107,7 @@ impl AssocOp { use AssocOp::*; match *self { Assign | AssignOp(_) => true, - Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply - | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor - | BitOr | LAnd | LOr | DotDot | DotDotEq => false, - } - } - - pub fn to_ast_binop(&self) -> Option { - use AssocOp::*; - match *self { - Less => Some(BinOpKind::Lt), - Greater => Some(BinOpKind::Gt), - LessEqual => Some(BinOpKind::Le), - GreaterEqual => Some(BinOpKind::Ge), - Equal => Some(BinOpKind::Eq), - NotEqual => Some(BinOpKind::Ne), - Multiply => Some(BinOpKind::Mul), - Divide => Some(BinOpKind::Div), - Modulus => Some(BinOpKind::Rem), - Add => Some(BinOpKind::Add), - Subtract => Some(BinOpKind::Sub), - ShiftLeft => Some(BinOpKind::Shl), - ShiftRight => Some(BinOpKind::Shr), - BitAnd => Some(BinOpKind::BitAnd), - BitXor => Some(BinOpKind::BitXor), - BitOr => Some(BinOpKind::BitOr), - LAnd => Some(BinOpKind::And), - LOr => Some(BinOpKind::Or), - Assign | AssignOp(_) | As | DotDot | DotDotEq => None, + Cast | Binary(_) | Range(_) => false, } } @@ -212,20 +117,23 @@ impl AssocOp { /// parentheses while having a high degree of confidence on the correctness of the suggestion. pub fn can_continue_expr_unambiguously(&self) -> bool { use AssocOp::*; + use BinOpKind::*; matches!( self, - BitXor | // `{ 42 } ^ 3` Assign | // `{ 42 } = { 42 }` - Divide | // `{ 42 } / 42` - Modulus | // `{ 42 } % 2` - ShiftRight | // `{ 42 } >> 2` - LessEqual | // `{ 42 } <= 3` - Greater | // `{ 42 } > 3` - GreaterEqual | // `{ 42 } >= 3` + Binary( + BitXor | // `{ 42 } ^ 3` + Div | // `{ 42 } / 42` + Rem | // `{ 42 } % 2` + Shr | // `{ 42 } >> 2` + Le | // `{ 42 } <= 3` + Gt | // `{ 42 } > 3` + Ge // `{ 42 } >= 3` + ) | AssignOp(_) | // `{ 42 } +=` // Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery. - As // `{ 42 } as usize` + Cast // `{ 42 } as usize` ) } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 3242d4145959d..cfcb0e23cb5e6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -597,7 +597,7 @@ pub fn walk_use_tree<'a, V: Visitor<'a>>( visit_opt!(visitor, visit_ident, rename); } UseTreeKind::Glob => {} - UseTreeKind::Nested { ref items, span: _ } => { + UseTreeKind::Nested { items, span: _ } => { for &(ref nested_tree, nested_id) in items { try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true)); } @@ -833,7 +833,8 @@ pub fn walk_where_predicate<'a, V: Visitor<'a>>( visitor: &mut V, predicate: &'a WherePredicate, ) -> V::Result { - let WherePredicate { kind, id: _, span: _ } = predicate; + let WherePredicate { attrs, kind, id: _, span: _, is_placeholder: _ } = predicate; + walk_list!(visitor, visit_attribute, attrs); visitor.visit_where_predicate_kind(kind) } @@ -891,7 +892,14 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu _ctxt, _ident, _vis, - Fn { defaultness: _, sig: FnSig { header, decl, span: _ }, generics, contract, body }, + Fn { + defaultness: _, + sig: FnSig { header, decl, span: _ }, + generics, + contract, + body, + define_opaque, + }, ) => { // Identifier and visibility are visited as a part of the item. try_visit!(visitor.visit_fn_header(header)); @@ -899,6 +907,9 @@ pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Resu try_visit!(visitor.visit_fn_decl(decl)); visit_opt!(visitor, visit_contract, contract); visit_opt!(visitor, visit_block, body); + for (id, path) in define_opaque.iter().flatten() { + try_visit!(visitor.visit_path(path, *id)) + } } FnKind::Closure(binder, coroutine_kind, decl, body) => { try_visit!(visitor.visit_closure_binder(binder)); @@ -1202,7 +1213,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id - )) + )); } ExprKind::Block(block, opt_label) => { visit_opt!(visitor, visit_label, opt_label); @@ -1210,6 +1221,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)), ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)), + ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)), ExprKind::Assign(lhs, rhs, _span) => { try_visit!(visitor.visit_expr(lhs)); try_visit!(visitor.visit_expr(rhs)); diff --git a/compiler/rustc_ast_ir/Cargo.toml b/compiler/rustc_ast_ir/Cargo.toml index 1905574073f13..f54e9687d8c7f 100644 --- a/compiler/rustc_ast_ir/Cargo.toml +++ b/compiler/rustc_ast_ir/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast_ir" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index 9884e191ea7bd..0898433a74c53 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -9,18 +9,20 @@ #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(never_type))] #![cfg_attr(feature = "nightly", feature(rustc_attrs))] -#![warn(unreachable_pub)] // tidy-alphabetical-end #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable, HashStable_NoContext}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; pub mod visit; /// The movability of a coroutine / closure literal: /// whether a coroutine contains self-references, causing it to be `!Unpin`. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum Movability { /// May contain self-references, `!Unpin`. Static, @@ -29,7 +31,10 @@ pub enum Movability { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum Mutability { // N.B. Order is deliberate, so that Not < Mut Not, @@ -88,7 +93,10 @@ impl Mutability { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum Pinnedness { Not, Pinned, diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml index ce95f4dfa1b82..2ec4f4b055514 100644 --- a/compiler/rustc_ast_lowering/Cargo.toml +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast_lowering" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] doctest = false @@ -11,6 +11,7 @@ doctest = false rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } @@ -19,6 +20,7 @@ rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } +rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 1b91c33742d8b..906fb213ee779 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -37,11 +37,11 @@ ast_lowering_bad_return_type_notation_inputs = .suggestion = remove the input types ast_lowering_bad_return_type_notation_needs_dots = return type notation arguments must be elided with `..` - .suggestion = add `..` + .suggestion = use the correct syntax by adding `..` to the arguments ast_lowering_bad_return_type_notation_output = return type not allowed with return type notation - .suggestion = remove the return type +ast_lowering_bad_return_type_notation_output_suggestion = use the right argument notation and remove the return type ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet @@ -88,7 +88,7 @@ ast_lowering_invalid_abi_clobber_abi = invalid ABI for `clobber_abi` .note = the following ABIs are supported on this target: {$supported_abis} -ast_lowering_invalid_abi_suggestion = did you mean +ast_lowering_invalid_abi_suggestion = there's a similarly named valid ABI `{$suggestion}` ast_lowering_invalid_asm_template_modifier_const = asm template modifiers are not allowed for `const` arguments diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 96c230ec243a2..65784af92c7ca 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -1,13 +1,12 @@ use std::collections::hash_map::Entry; use std::fmt::Write; -use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_session::parse::feature_err; -use rustc_span::{Span, kw, sym}; +use rustc_span::{Span, sym}; use rustc_target::asm; use super::LoweringContext; @@ -39,6 +38,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } if let Some(asm_arch) = asm_arch { // Inline assembly is currently only stable for these architectures. + // (See also compiletest's `has_asm_support`.) let is_stable = matches!( asm_arch, asm::InlineAsmArch::X86 @@ -196,7 +196,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } InlineAsmOperand::Const { anon_const } => hir::InlineAsmOperand::Const { - anon_const: self.lower_anon_const_to_anon_const(anon_const), + anon_const: self.lower_const_block(anon_const), }, InlineAsmOperand::Sym { sym } => { let static_def_id = self @@ -230,20 +230,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { tokens: None, }; - // Wrap the expression in an AnonConst. - let parent_def_id = self.current_hir_id_owner.def_id; - let node_id = self.next_node_id(); - self.create_def( - parent_def_id, - node_id, - kw::Empty, - DefKind::AnonConst, - *op_sp, - ); - let anon_const = AnonConst { id: node_id, value: P(expr) }; - hir::InlineAsmOperand::SymFn { - anon_const: self.lower_anon_const_to_anon_const(&anon_const), - } + hir::InlineAsmOperand::SymFn { expr: self.lower_expr(&expr) } } } InlineAsmOperand::Label { block } => { diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 88ce6f80e10bd..1d9ca6bb9c8cb 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -108,7 +108,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs); + self.lower_attrs(hir_id, &l.attrs, l.span); self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index d8b7cb0c3225b..efc1fa05c5f92 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -60,25 +60,27 @@ pub(crate) struct DelegationResults<'hir> { } impl<'hir> LoweringContext<'_, 'hir> { - pub(crate) fn delegation_has_self(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool { + /// Defines whether the delegatee is an associated function whose first parameter is `self`. + pub(crate) fn delegatee_is_method(&self, item_id: NodeId, path_id: NodeId, span: Span) -> bool { let sig_id = self.get_delegation_sig_id(item_id, path_id, span); let Ok(sig_id) = sig_id else { return false; }; - self.has_self(sig_id, span) + self.is_method(sig_id, span) } - fn has_self(&self, def_id: DefId, span: Span) -> bool { - if let Some(local_sig_id) = def_id.as_local() { - // The value may be missing due to recursive delegation. - // Error will be emitted later during HIR ty lowering. - self.resolver.delegation_fn_sigs.get(&local_sig_id).is_some_and(|sig| sig.has_self) - } else { - match self.tcx.def_kind(def_id) { - DefKind::Fn => false, - DefKind::AssocFn => self.tcx.associated_item(def_id).fn_has_self_parameter, - _ => span_bug!(span, "unexpected DefKind for delegation item"), - } + fn is_method(&self, def_id: DefId, span: Span) -> bool { + match self.tcx.def_kind(def_id) { + DefKind::Fn => false, + DefKind::AssocFn => match def_id.as_local() { + Some(local_def_id) => self + .resolver + .delegation_fn_sigs + .get(&local_def_id) + .is_some_and(|sig| sig.has_self), + None => self.tcx.associated_item(def_id).fn_has_self_parameter, + }, + _ => span_bug!(span, "unexpected DefKind for delegation item"), } } @@ -188,14 +190,19 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FnSig<'hir> { let header = if let Some(local_sig_id) = sig_id.as_local() { match self.resolver.delegation_fn_sigs.get(&local_sig_id) { - Some(sig) => self.lower_fn_header( - sig.header, + Some(sig) => { + let parent = self.tcx.parent(sig_id); // HACK: we override the default safety instead of generating attributes from the ether. // We are not forwarding the attributes, as the delegation fn sigs are collected on the ast, // and here we need the hir attributes. - if sig.target_feature { hir::Safety::Unsafe } else { hir::Safety::Safe }, - &[], - ), + let default_safety = + if sig.target_feature || self.tcx.def_kind(parent) == DefKind::ForeignMod { + hir::Safety::Unsafe + } else { + hir::Safety::Safe + }; + self.lower_fn_header(sig.header, default_safety, &[]) + } None => self.generate_header_error(), } } else { @@ -324,10 +331,11 @@ impl<'hir> LoweringContext<'_, 'hir> { let call = if self .get_resolution_id(delegation.id, span) - .and_then(|def_id| Ok(self.has_self(def_id, span))) + .and_then(|def_id| Ok(self.is_method(def_id, span))) .unwrap_or_default() && delegation.qself.is_none() && !has_generic_args + && !args.is_empty() { let ast_segment = delegation.path.segments.last().unwrap(); let segment = self.lower_path_segment( diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index f31e2db051d81..ceeb5dffbea04 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -46,8 +46,9 @@ pub(crate) struct TupleStructWithDefault { #[derive(Subdiagnostic)] #[suggestion( ast_lowering_invalid_abi_suggestion, - code = "{suggestion}", - applicability = "maybe-incorrect" + code = "\"{suggestion}\"", + applicability = "maybe-incorrect", + style = "verbose" )] pub(crate) struct InvalidAbiSuggestion { #[primary_span] @@ -372,24 +373,39 @@ pub(crate) struct InclusiveRangeWithNoEnd { pub span: Span, } +#[derive(Subdiagnostic)] +#[multipart_suggestion( + ast_lowering_bad_return_type_notation_output_suggestion, + applicability = "machine-applicable", + style = "verbose" +)] +/// Given `T: Tr Ret>` or `T: Tr Ret>`, suggest `T: Tr`. +pub(crate) struct RTNSuggestion { + #[suggestion_part(code = "")] + pub output: Span, + #[suggestion_part(code = "(..)")] + pub input: Span, +} + #[derive(Diagnostic)] pub(crate) enum BadReturnTypeNotation { #[diag(ast_lowering_bad_return_type_notation_inputs)] Inputs { #[primary_span] - #[suggestion(code = "()", applicability = "maybe-incorrect")] + #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")] span: Span, }, #[diag(ast_lowering_bad_return_type_notation_output)] Output { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect")] span: Span, + #[subdiagnostic] + suggestion: RTNSuggestion, }, #[diag(ast_lowering_bad_return_type_notation_needs_dots)] NeedsDots { #[primary_span] - #[suggestion(code = "(..)", applicability = "maybe-incorrect")] + #[suggestion(code = "(..)", applicability = "machine-applicable", style = "verbose")] span: Span, }, #[diag(ast_lowering_bad_return_type_notation_position)] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index af53c7ec21572..5bb6704dde45a 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -13,7 +13,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym}; use thin_vec::{ThinVec, thin_vec}; use visit::{Visitor, walk_expr}; @@ -77,9 +77,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.attrs.insert( ex.hir_id.local_id, &*self.arena.alloc_from_iter( - e.attrs - .iter() - .map(|a| self.lower_attr(a)) + self.lower_attrs_vec(&e.attrs, e.span) + .into_iter() .chain(old_attrs.iter().cloned()), ), ); @@ -98,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs); + self.lower_attrs(expr_hir_id, &e.attrs, e.span); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -208,6 +207,7 @@ impl<'hir> LoweringContext<'_, 'hir> { }, ), ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr), + ExprKind::Use(expr, use_kw_span) => self.lower_expr_use(*use_kw_span, expr), ExprKind::Closure(box Closure { binder, capture_clause, @@ -484,7 +484,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if legacy_args_idx.contains(&idx) { let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, f.span); + self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span); let mut visitor = WillCreateDefIdsVisitor {}; let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { AstP(Expr { @@ -670,12 +670,15 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs); + self.lower_attrs(hir_id, &arm.attrs, arm.span); let is_never_pattern = pat.is_never_pattern(); - let body = if let Some(body) = &arm.body + // We need to lower the body even if it's unneeded for never pattern in match, + // ensure that we can get HirId for DefId if need (issue #137708). + let body = arm.body.as_ref().map(|x| self.lower_expr(x)); + let body = if let Some(body) = body && !is_never_pattern { - self.lower_expr(body) + body } else { // Either `body.is_none()` or `is_never_pattern` here. if !is_never_pattern { @@ -839,6 +842,7 @@ impl<'hir> LoweringContext<'_, 'hir> { style: AttrStyle::Outer, span: unstable_span, }], + span, ); } } @@ -1064,6 +1068,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } + fn lower_expr_use(&mut self, use_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> { + hir::ExprKind::Use(self.lower_expr(expr), use_kw_span) + } + fn lower_expr_closure( &mut self, binder: &ClosureBinder, @@ -1673,7 +1681,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1687,6 +1695,19 @@ impl<'hir> LoweringContext<'_, 'hir> { let yielded = opt_expr.as_ref().map(|x| self.lower_expr(x)).unwrap_or_else(|| self.expr_unit(span)); + if !self.tcx.features().yield_expr() + && !self.tcx.features().coroutines() + && !self.tcx.features().gen_blocks() + { + rustc_session::parse::feature_err( + &self.tcx.sess, + sym::yield_expr, + span, + fluent_generated::ast_lowering_yield, + ) + .emit(); + } + let is_async_gen = match self.coroutine_kind { Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => false, Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true, @@ -1711,28 +1732,8 @@ impl<'hir> LoweringContext<'_, 'hir> { None, ); } - Some(hir::CoroutineKind::Coroutine(_)) => { - if !self.tcx.features().coroutines() { - rustc_session::parse::feature_err( - &self.tcx.sess, - sym::coroutines, - span, - fluent_generated::ast_lowering_yield, - ) - .emit(); - } - false - } + Some(hir::CoroutineKind::Coroutine(_)) => false, None => { - if !self.tcx.features().coroutines() { - rustc_session::parse::feature_err( - &self.tcx.sess, - sym::coroutines, - span, - fluent_generated::ast_lowering_yield, - ) - .emit(); - } let suggestion = self.current_item.map(|s| s.shrink_to_lo()); self.dcx().emit_err(YieldInClosure { span, suggestion }); self.coroutine_kind = Some(hir::CoroutineKind::Coroutine(Movability::Movable)); @@ -1936,7 +1937,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs); + self.lower_attrs(expr.hir_id, &e.attrs, e.span); expr } @@ -1993,7 +1994,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs); + self.lower_attrs(val_expr.hir_id, &attrs, span); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -2024,7 +2025,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs); + self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) @@ -2129,26 +2130,24 @@ impl<'hir> LoweringContext<'_, 'hir> { self.arena.alloc(self.expr(sp, hir::ExprKind::Tup(&[]))) } - pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + fn expr_uint(&mut self, sp: Span, ty: ast::UintTy, value: u128) -> hir::Expr<'hir> { let lit = self.arena.alloc(hir::Lit { span: sp, - node: ast::LitKind::Int( - (value as u128).into(), - ast::LitIntType::Unsigned(ast::UintTy::Usize), - ), + node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ty)), }); self.expr(sp, hir::ExprKind::Lit(lit)) } + pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> { + self.expr_uint(sp, ast::UintTy::Usize, value as u128) + } + pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> { - let lit = self.arena.alloc(hir::Lit { - span: sp, - node: ast::LitKind::Int( - u128::from(value).into(), - ast::LitIntType::Unsigned(ast::UintTy::U32), - ), - }); - self.expr(sp, hir::ExprKind::Lit(lit)) + self.expr_uint(sp, ast::UintTy::U32, value as u128) + } + + pub(super) fn expr_u16(&mut self, sp: Span, value: u16) -> hir::Expr<'hir> { + self.expr_uint(sp, ast::UintTy::U16, value as u128) } pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> { diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs index 07b94dbc2aebd..faa47274f96ce 100644 --- a/compiler/rustc_ast_lowering/src/format.rs +++ b/compiler/rustc_ast_lowering/src/format.rs @@ -292,7 +292,7 @@ fn make_count<'hir>( hir::LangItem::FormatCount, sym::Is, )); - let value = ctx.arena.alloc_from_iter([ctx.expr_usize(sp, *n)]); + let value = ctx.arena.alloc_from_iter([ctx.expr_u16(sp, *n)]); ctx.expr_call_mut(sp, count_is, value) } Some(FormatCount::Argument(arg)) => { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index bc2db41546989..9adc8bdd3616d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -3,15 +3,14 @@ use rustc_ast::ptr::P; use rustc_ast::visit::AssocCtxt; use rustc_ast::*; use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::PredicateOrigin; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId}; +use rustc_hir::{self as hir, HirId, PredicateOrigin}; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::{DesugaringKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; @@ -93,7 +92,8 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs); + // FIXME(jdonszelman): is dummy span ever a problem here? + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); hir::OwnerNode::Crate(module) }) } @@ -157,7 +157,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut ident = i.ident; let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -208,6 +208,7 @@ impl<'hir> LoweringContext<'_, 'hir> { generics, body, contract, + define_opaque, .. }) => { self.with_new_scopes(*fn_sig_span, |this| { @@ -236,6 +237,7 @@ impl<'hir> LoweringContext<'_, 'hir> { header: this.lower_fn_header(*header, hir::Safety::Safe, attrs), span: this.lower_span(*fn_sig_span), }; + this.lower_define_opaque(hir_id, &define_opaque); hir::ItemKind::Fn { sig, generics, body: body_id, has_body: body.is_some() } }) } @@ -251,7 +253,12 @@ impl<'hir> LoweringContext<'_, 'hir> { .arena .alloc_from_iter(fm.items.iter().map(|x| self.lower_foreign_item_ref(x))), }, - ItemKind::GlobalAsm(asm) => hir::ItemKind::GlobalAsm(self.lower_inline_asm(span, asm)), + ItemKind::GlobalAsm(asm) => { + let asm = self.lower_inline_asm(span, asm); + let fake_body = + self.lower_body(|this| (&[], this.expr(span, hir::ExprKind::InlineAsm(asm)))); + hir::ItemKind::GlobalAsm { asm, fake_body } + } ItemKind::TyAlias(box TyAlias { generics, where_clauses, ty, .. }) => { // We lower // @@ -615,7 +622,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - let attrs = self.lower_attrs(hir_id, &i.attrs); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let item = hir::ForeignItem { owner_id, ident: self.lower_ident(i.ident), @@ -673,7 +680,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs); + self.lower_attrs(hir_id, &v.attrs, v.span); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -735,7 +742,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -754,7 +761,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { @@ -773,7 +780,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); (generics, kind, expr.is_some()) } - AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => { + AssocItemKind::Fn(box Fn { sig, generics, body: None, define_opaque, .. }) => { // FIXME(contracts): Deny contract here since it won't apply to // any impl method or callees. let names = self.lower_fn_params_to_names(&sig.decl); @@ -785,9 +792,22 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_kind, attrs, ); + if define_opaque.is_some() { + self.dcx().span_err( + i.span, + "only trait methods with default bodies can define opaque types", + ); + } (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Required(names)), false) } - AssocItemKind::Fn(box Fn { sig, generics, body: Some(body), contract, .. }) => { + AssocItemKind::Fn(box Fn { + sig, + generics, + body: Some(body), + contract, + define_opaque, + .. + }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -806,6 +826,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_kind, attrs, ); + self.lower_define_opaque(hir_id, &define_opaque); (generics, hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)), true) } AssocItemKind::Type(box TyAlias { generics, where_clauses, bounds, ty, .. }) => { @@ -865,7 +886,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { - has_self: self.delegation_has_self(i.id, delegation.id, i.span), + has_self: self.delegatee_is_method(i.id, delegation.id, i.span), }, AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") @@ -890,7 +911,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let (generics, kind) = match &i.kind { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( @@ -905,7 +926,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Const(ty, body) }, ), - AssocItemKind::Fn(box Fn { sig, generics, body, contract, .. }) => { + AssocItemKind::Fn(box Fn { sig, generics, body, contract, define_opaque, .. }) => { let body_id = self.lower_maybe_coroutine_body( sig.span, i.span, @@ -924,6 +945,7 @@ impl<'hir> LoweringContext<'_, 'hir> { sig.header.coroutine_kind, attrs, ); + self.lower_define_opaque(hir_id, &define_opaque); (generics, hir::ImplItemKind::Fn(sig, body_id)) } @@ -994,7 +1016,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::AssocItemKind::Fn { has_self: sig.decl.has_self() } } AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn { - has_self: self.delegation_has_self(i.id, delegation.id, i.span), + has_self: self.delegatee_is_method(i.id, delegation.id, i.span), }, AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => { panic!("macros should have been expanded by now") @@ -1051,7 +1073,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs); + self.lower_attrs(hir_id, ¶m.attrs, param.span); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), @@ -1504,7 +1526,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: abi.span, suggestion: suggested_name.map(|suggested_name| InvalidAbiSuggestion { span: abi.span, - suggestion: format!("\"{suggested_name}\""), + suggestion: suggested_name.to_string(), }), command: "rustc --print=calling-conventions".to_string(), }); @@ -1651,6 +1673,35 @@ impl<'hir> LoweringContext<'_, 'hir> { (lowered_generics, res) } + pub(super) fn lower_define_opaque( + &mut self, + hir_id: HirId, + define_opaque: &Option>, + ) { + assert_eq!(self.define_opaque, None); + assert!(hir_id.is_owner()); + let Some(define_opaque) = define_opaque.as_ref() else { + return; + }; + let define_opaque = define_opaque.iter().filter_map(|(id, path)| { + let res = self.resolver.get_partial_res(*id).unwrap(); + let Some(did) = res.expect_full_res().opt_def_id() else { + self.dcx().span_delayed_bug(path.span, "should have errored in resolve"); + return None; + }; + let Some(did) = did.as_local() else { + self.dcx().span_err( + path.span, + "only opaque types defined in the local crate can be defined", + ); + return None; + }; + Some((self.lower_span(path.span), did)) + }); + let define_opaque = self.arena.alloc_from_iter(define_opaque); + self.define_opaque = Some(define_opaque); + } + pub(super) fn lower_generic_bound_predicate( &mut self, ident: Ident, @@ -1722,6 +1773,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> { let hir_id = self.lower_node_id(pred.id); let span = self.lower_span(pred.span); + self.lower_attrs(hir_id, &pred.attrs, span); let kind = self.arena.alloc(match &pred.kind { WherePredicateKind::BoundPredicate(WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1c777111896dc..df671cf4b8604 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -32,20 +32,21 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(exact_size_is_empty)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::sync::Arc; use rustc_ast::node_id::NodeMap; use rustc_ast::{self as ast, *}; -use rustc_data_structures::captures::Captures; +use rustc_attr_parsing::{AttributeParser, OmitDoc}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -61,7 +62,8 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::ty::{ResolverAstLowering, TyCtxt}; use rustc_session::parse::{add_feature_diagnostics, feature_err}; -use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym}; +use rustc_span::symbol::{Ident, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, DesugaringKind, Span}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -97,6 +99,8 @@ struct LoweringContext<'a, 'hir> { /// Bodies inside the owner being lowered. bodies: Vec<(hir::ItemLocalId, &'hir hir::Body<'hir>)>, + /// `#[define_opaque]` attributes + define_opaque: Option<&'hir [(Span, LocalDefId)]>, /// Attributes inside the owner being lowered. attrs: SortedMap, /// Collect items that were created by lowering the current owner. @@ -135,13 +139,17 @@ struct LoweringContext<'a, 'hir> { allow_try_trait: Arc<[Symbol]>, allow_gen_future: Arc<[Symbol]>, + allow_pattern_type: Arc<[Symbol]>, allow_async_iterator: Arc<[Symbol]>, allow_for_await: Arc<[Symbol]>, allow_async_fn_traits: Arc<[Symbol]>, + + attribute_parser: AttributeParser<'hir>, } impl<'a, 'hir> LoweringContext<'a, 'hir> { fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self { + let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect(); Self { // Pseudo-globals. tcx, @@ -150,6 +158,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // HirId handling. bodies: Vec::new(), + define_opaque: None, attrs: SortedMap::default(), children: Vec::default(), contract_ensures: None, @@ -172,6 +181,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { impl_trait_defs: Vec::new(), impl_trait_bounds: Vec::new(), allow_try_trait: [sym::try_trait_v2, sym::yeet_desugar_details].into(), + allow_pattern_type: [sym::pattern_types, sym::pattern_type_range_trait].into(), allow_gen_future: if tcx.features().async_fn_track_caller() { [sym::gen_future, sym::closure_track_caller].into() } else { @@ -182,6 +192,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller` // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), + + attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), } } @@ -217,7 +229,6 @@ impl ResolverAstLowering { None } - /// Obtains resolution for a `NodeId` with a single resolution. fn get_partial_res(&self, id: NodeId) -> Option { self.partial_res_map.get(&id).copied() } @@ -487,7 +498,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, parent: LocalDefId, node_id: ast::NodeId, - name: Symbol, + name: Option, def_kind: DefKind, span: Span, ) -> LocalDefId { @@ -540,6 +551,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let current_attrs = std::mem::take(&mut self.attrs); let current_bodies = std::mem::take(&mut self.bodies); + let current_define_opaque = std::mem::take(&mut self.define_opaque); let current_ident_and_label_to_local_id = std::mem::take(&mut self.ident_and_label_to_local_id); @@ -573,6 +585,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.attrs = current_attrs; self.bodies = current_bodies; + self.define_opaque = current_define_opaque; self.ident_and_label_to_local_id = current_ident_and_label_to_local_id; #[cfg(debug_assertions)] @@ -592,6 +605,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn make_owner_info(&mut self, node: hir::OwnerNode<'hir>) -> &'hir hir::OwnerInfo<'hir> { let attrs = std::mem::take(&mut self.attrs); let mut bodies = std::mem::take(&mut self.bodies); + let define_opaque = std::mem::take(&mut self.define_opaque); let trait_map = std::mem::take(&mut self.trait_map); #[cfg(debug_assertions)] @@ -611,7 +625,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; - let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash }; + let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque }; self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) } @@ -767,7 +781,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let _def_id = self.create_def( self.current_hir_id_owner.def_id, param, - kw::UnderscoreLifetime, + Some(kw::UnderscoreLifetime), DefKind::LifetimeParam, ident.span, ); @@ -856,45 +870,38 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ret } - fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [hir::Attribute] { + fn lower_attrs( + &mut self, + id: HirId, + attrs: &[Attribute], + target_span: Span, + ) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { + let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); + debug_assert_eq!(id.owner, self.current_hir_id_owner); - let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a))); - debug_assert!(!ret.is_empty()); - self.attrs.insert(id.local_id, ret); - ret + let ret = self.arena.alloc_from_iter(lowered_attrs); + + // this is possible if an item contained syntactical attribute, + // but none of them parse succesfully or all of them were ignored + // for not being built-in attributes at all. They could be remaining + // unexpanded attributes used as markers in proc-macro derives for example. + // This will have emitted some diagnostics for the misparse, but will then + // not emit the attribute making the list empty. + if ret.is_empty() { + &[] + } else { + self.attrs.insert(id.local_id, ret); + ret + } } } - fn lower_attr(&self, attr: &Attribute) -> hir::Attribute { - // Note that we explicitly do not walk the path. Since we don't really - // lower attributes (we use the AST version) there is nowhere to keep - // the `HirId`s. We don't actually need HIR version of attributes anyway. - // Tokens are also not needed after macro expansion and parsing. - let kind = match attr.kind { - AttrKind::Normal(ref normal) => hir::AttrKind::Normal(Box::new(hir::AttrItem { - unsafety: self.lower_safety(normal.item.unsafety, hir::Safety::Safe), - path: hir::AttrPath { - segments: normal - .item - .path - .segments - .iter() - .map(|i| i.ident) - .collect::>() - .into_boxed_slice(), - span: normal.item.path.span, - }, - args: self.lower_attr_args(&normal.item.args), - })), - AttrKind::DocComment(comment_kind, data) => { - hir::AttrKind::DocComment(comment_kind, data) - } - }; - - hir::Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) } + fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec { + self.attribute_parser + .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s)) } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { @@ -906,34 +913,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_attr_args(&self, args: &AttrArgs) -> hir::AttrArgs { - match args { - AttrArgs::Empty => hir::AttrArgs::Empty, - AttrArgs::Delimited(args) => hir::AttrArgs::Delimited(self.lower_delim_args(args)), - // This is an inert key-value attribute - it will never be visible to macros - // after it gets lowered to HIR. Therefore, we can extract literals to handle - // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). - &AttrArgs::Eq { eq_span, ref expr } => { - // In valid code the value always ends up as a single literal. Otherwise, a dummy - // literal suffices because the error is handled elsewhere. - let lit = if let ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span) - { - lit - } else { - let guar = self.dcx().has_errors().unwrap(); - MetaItemLit { - symbol: kw::Empty, - suffix: None, - kind: LitKind::Err(guar), - span: DUMMY_SP, - } - }; - hir::AttrArgs::Eq { eq_span, expr: lit } - } - } - } - fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs { DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() } } @@ -956,19 +935,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if let Some(first_char) = constraint.ident.as_str().chars().next() && first_char.is_ascii_lowercase() { - let mut err = if !data.inputs.is_empty() { - self.dcx().create_err(errors::BadReturnTypeNotation::Inputs { - span: data.inputs_span, - }) - } else if let FnRetTy::Ty(ty) = &data.output { - self.dcx().create_err(errors::BadReturnTypeNotation::Output { - span: data.inputs_span.shrink_to_hi().to(ty.span), - }) - } else { - self.dcx().create_err(errors::BadReturnTypeNotation::NeedsDots { - span: data.inputs_span, - }) + let err = match (&data.inputs[..], &data.output) { + ([_, ..], FnRetTy::Default(_)) => { + errors::BadReturnTypeNotation::Inputs { span: data.inputs_span } + } + ([], FnRetTy::Default(_)) => { + errors::BadReturnTypeNotation::NeedsDots { span: data.inputs_span } + } + // The case `T: Trait Ret>` is handled in the parser. + (_, FnRetTy::Ty(ty)) => { + let span = data.inputs_span.shrink_to_hi().to(ty.span); + errors::BadReturnTypeNotation::Output { + span, + suggestion: errors::RTNSuggestion { + output: span, + input: data.inputs_span, + }, + } + } }; + let mut err = self.dcx().create_err(err); if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { @@ -1116,7 +1102,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .and_then(|partial_res| partial_res.full_res()) { if !res.matches_ns(Namespace::TypeNS) - && path.is_potential_trivial_const_arg() + && path.is_potential_trivial_const_arg(false) { debug!( "lower_generic_arg: Lowering type argument as const argument: {:?}", @@ -1387,7 +1373,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } TyKind::Pat(ty, pat) => { - hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat)) + hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span)) } TyKind::MacCall(_) => { span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") @@ -1530,7 +1516,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_fn_params_to_names(&mut self, decl: &FnDecl) -> &'hir [Ident] { self.arena.alloc_from_iter(decl.inputs.iter().map(|param| match param.pat.kind { PatKind::Ident(_, ident, _) => self.lower_ident(ident), - _ => Ident::new(kw::Empty, self.lower_span(param.pat.span)), + PatKind::Wild => Ident::new(kw::Underscore, self.lower_span(param.pat.span)), + _ => { + self.dcx().span_delayed_bug( + param.pat.span, + "non-ident/wild param pat must trigger an error", + ); + Ident::new(kw::Empty, self.lower_span(param.pat.span)) + } })) } @@ -1821,11 +1814,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.new_named_lifetime_with_res(new_id, ident, res) } - fn lower_generic_params_mut<'s>( - &'s mut self, - params: &'s [GenericParam], + fn lower_generic_params_mut( + &mut self, + params: &[GenericParam], source: hir::GenericParamSource, - ) -> impl Iterator> + Captures<'a> + Captures<'s> { + ) -> impl Iterator> { params.iter().map(move |param| self.lower_generic_param(param, source)) } @@ -1846,7 +1839,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs); + self.lower_attrs(hir_id, ¶m.attrs, param.span()); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), @@ -1986,11 +1979,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc_from_iter(self.lower_param_bounds_mut(bounds, itctx)) } - fn lower_param_bounds_mut<'s>( - &'s mut self, - bounds: &'s [GenericBound], + fn lower_param_bounds_mut( + &mut self, + bounds: &[GenericBound], itctx: ImplTraitContext, - ) -> impl Iterator> + Captures<'s> + Captures<'a> { + ) -> impl Iterator> { bounds.iter().map(move |bound| self.lower_param_bound(bound, itctx)) } @@ -2083,8 +2076,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> &'hir hir::ConstArg<'hir> { let tcx = self.tcx; - // FIXME(min_generic_const_args): we only allow one-segment const paths for now - let ct_kind = if path.is_potential_trivial_const_arg() + let ct_kind = if path + .is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) && (tcx.features().min_generic_const_args() || matches!(res, Res::Def(DefKind::ConstParam, _))) { @@ -2094,7 +2087,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { path, ParamMode::Optional, AllowReturnTypeNotation::No, - // FIXME(min_generic_const_args): update for `fn foo() -> Bar>` support + // FIXME(mgca): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); @@ -2110,8 +2103,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're lowering a const argument that was originally thought to be a type argument, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = - self.create_def(parent_def_id, node_id, kw::Empty, DefKind::AnonConst, span); + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let path_expr = Expr { @@ -2158,19 +2150,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let maybe_res = self.resolver.get_partial_res(expr.id).and_then(|partial_res| partial_res.full_res()); - // FIXME(min_generic_const_args): we only allow one-segment const paths for now - if let ExprKind::Path(None, path) = &expr.kind - && path.is_potential_trivial_const_arg() + if let ExprKind::Path(qself, path) = &expr.kind + && path.is_potential_trivial_const_arg(tcx.features().min_generic_const_args()) && (tcx.features().min_generic_const_args() || matches!(maybe_res, Some(Res::Def(DefKind::ConstParam, _)))) { let qpath = self.lower_qpath( expr.id, - &None, + qself, path, ParamMode::Optional, AllowReturnTypeNotation::No, - // FIXME(min_generic_const_args): update for `fn foo() -> Bar>` support + // FIXME(mgca): update for `fn foo() -> Bar>` support ImplTraitContext::Disallowed(ImplTraitPosition::Path), None, ); diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index e1f3afbcf5908..07cc64a1358ee 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -3,11 +3,11 @@ use std::sync::Arc; use rustc_ast::ptr::P; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir as hir; -use rustc_hir::def::Res; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir, LangItem}; use rustc_middle::span_bug; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{Ident, Span}; +use rustc_span::{DesugaringKind, Ident, Span}; use super::errors::{ ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding, @@ -93,7 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::PatField { hir_id, @@ -430,22 +430,124 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind }) } - pub(crate) fn lower_ty_pat(&mut self, pattern: &TyPat) -> &'hir hir::TyPat<'hir> { - self.arena.alloc(self.lower_ty_pat_mut(pattern)) + pub(crate) fn lower_ty_pat( + &mut self, + pattern: &TyPat, + base_type: Span, + ) -> &'hir hir::TyPat<'hir> { + self.arena.alloc(self.lower_ty_pat_mut(pattern, base_type)) } - fn lower_ty_pat_mut(&mut self, pattern: &TyPat) -> hir::TyPat<'hir> { + fn lower_ty_pat_mut(&mut self, pattern: &TyPat, base_type: Span) -> hir::TyPat<'hir> { // loop here to avoid recursion let pat_hir_id = self.lower_node_id(pattern.id); let node = match &pattern.kind { - TyPatKind::Range(e1, e2, Spanned { node: end, .. }) => hir::TyPatKind::Range( - e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)), - e2.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)), - self.lower_range_end(end, e2.is_some()), + TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range( + e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| { + self.lower_ty_pat_range_end( + hir::LangItem::RangeMin, + span.shrink_to_lo(), + base_type, + ) + }), + e2.as_deref() + .map(|e| match end { + RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e), + RangeEnd::Excluded => self.lower_excluded_range_end(e), + }) + .unwrap_or_else(|| { + self.lower_ty_pat_range_end( + hir::LangItem::RangeMax, + span.shrink_to_hi(), + base_type, + ) + }), ), TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar), }; hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) } } + + /// Lowers the range end of an exclusive range (`2..5`) to an inclusive range 2..=(5 - 1). + /// This way the type system doesn't have to handle the distinction between inclusive/exclusive ranges. + fn lower_excluded_range_end(&mut self, e: &AnonConst) -> &'hir hir::ConstArg<'hir> { + let span = self.lower_span(e.value.span); + let unstable_span = self.mark_span_with_reason( + DesugaringKind::PatTyRange, + span, + Some(Arc::clone(&self.allow_pattern_type)), + ); + let anon_const = self.with_new_scopes(span, |this| { + let def_id = this.local_def_id(e.id); + let hir_id = this.lower_node_id(e.id); + let body = this.lower_body(|this| { + // Need to use a custom function as we can't just subtract `1` from a `char`. + let kind = hir::ExprKind::Path(this.make_lang_item_qpath( + hir::LangItem::RangeSub, + unstable_span, + None, + )); + let fn_def = this.arena.alloc(hir::Expr { hir_id: this.next_id(), kind, span }); + let args = this.arena.alloc([this.lower_expr_mut(&e.value)]); + ( + &[], + hir::Expr { + hir_id: this.next_id(), + kind: hir::ExprKind::Call(fn_def, args), + span, + }, + ) + }); + hir::AnonConst { def_id, hir_id, body, span } + }); + self.arena.alloc(hir::ConstArg { + hir_id: self.next_id(), + kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)), + }) + } + + /// When a range has no end specified (`1..` or `1..=`) or no start specified (`..5` or `..=5`), + /// we instead use a constant of the MAX/MIN of the type. + /// This way the type system does not have to handle the lack of a start/end. + fn lower_ty_pat_range_end( + &mut self, + lang_item: LangItem, + span: Span, + base_type: Span, + ) -> &'hir hir::ConstArg<'hir> { + let parent_def_id = self.current_hir_id_owner.def_id; + let node_id = self.next_node_id(); + + // Add a definition for the in-band const def. + // We're generating a range end that didn't exist in the AST, + // so the def collector didn't create the def ahead of time. That's why we have to do + // it here. + let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); + let hir_id = self.lower_node_id(node_id); + + let unstable_span = self.mark_span_with_reason( + DesugaringKind::PatTyRange, + self.lower_span(span), + Some(Arc::clone(&self.allow_pattern_type)), + ); + let span = self.lower_span(base_type); + + let path_expr = hir::Expr { + hir_id: self.next_id(), + kind: hir::ExprKind::Path(self.make_lang_item_qpath(lang_item, unstable_span, None)), + span, + }; + + let ct = self.with_new_scopes(span, |this| { + self.arena.alloc(hir::AnonConst { + def_id, + hir_id, + body: this.lower_body(|_this| (&[], path_expr)), + span, + }) + }); + let hir_id = self.next_id(); + self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id }) + } } diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index 55d0647731324..d00c797755f3f 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -13,7 +13,7 @@ use tracing::{debug, instrument}; use super::errors::{ AsyncBoundNotOnTrait, AsyncBoundOnlyForFnTraits, BadReturnTypeNotation, - GenericTypeWithParentheses, UseAngleBrackets, + GenericTypeWithParentheses, RTNSuggestion, UseAngleBrackets, }; use super::{ AllowReturnTypeNotation, GenericArgsCtor, GenericArgsMode, ImplTraitContext, ImplTraitPosition, @@ -268,19 +268,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } GenericArgs::Parenthesized(data) => match generic_args_mode { GenericArgsMode::ReturnTypeNotation => { - let mut err = if !data.inputs.is_empty() { - self.dcx().create_err(BadReturnTypeNotation::Inputs { - span: data.inputs_span, - }) - } else if let FnRetTy::Ty(ty) = &data.output { - self.dcx().create_err(BadReturnTypeNotation::Output { - span: data.inputs_span.shrink_to_hi().to(ty.span), - }) - } else { - self.dcx().create_err(BadReturnTypeNotation::NeedsDots { - span: data.inputs_span, - }) + let err = match (&data.inputs[..], &data.output) { + ([_, ..], FnRetTy::Default(_)) => { + BadReturnTypeNotation::Inputs { span: data.inputs_span } + } + ([], FnRetTy::Default(_)) => { + BadReturnTypeNotation::NeedsDots { span: data.inputs_span } + } + // The case `T: Trait Ret>` is handled in the parser. + (_, FnRetTy::Ty(ty)) => { + let span = data.inputs_span.shrink_to_hi().to(ty.span); + BadReturnTypeNotation::Output { + span, + suggestion: RTNSuggestion { + output: span, + input: data.inputs_span, + }, + } + } }; + let mut err = self.dcx().create_err(err); if !self.tcx.features().return_type_notation() && self.tcx.sess.is_nightly_build() { diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index e4c227532085f..c738cb2aa2fd4 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast_passes" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 5a0ec865f9d4d..25944392a52a9 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -207,8 +207,6 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc} -ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library - ast_passes_static_without_body = free static item without body .suggestion = provide a definition for the static diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f9f4035cb22f0..232d60be4eb2a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -917,7 +917,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; // Avoid visiting again. } - ItemKind::Fn(func @ box Fn { defaultness, generics: _, sig, contract: _, body }) => { + ItemKind::Fn( + func + @ box Fn { defaultness, generics: _, sig, contract: _, body, define_opaque: _ }, + ) => { self.check_defaultness(item.span, *defaultness); let is_intrinsic = diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 0eb2043eaa356..8e53e600f7ac6 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -535,7 +535,6 @@ pub(crate) struct WhereClauseBeforeTypeAlias { } #[derive(Subdiagnostic)] - pub(crate) enum WhereClauseBeforeTypeAliasSugg { #[suggestion(ast_passes_remove_suggestion, applicability = "machine-applicable", code = "")] Remove { @@ -732,13 +731,6 @@ pub(crate) struct AssociatedSuggestion2 { pub potential_assoc: Ident, } -#[derive(Diagnostic)] -#[diag(ast_passes_stability_outside_std, code = E0734)] -pub(crate) struct StabilityOutsideStd { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(ast_passes_feature_on_non_nightly, code = E0554)] pub(crate) struct FeatureOnNonNightly { @@ -804,7 +796,14 @@ pub(crate) struct NegativeBoundWithParentheticalNotation { pub(crate) struct MatchArmWithNoBody { #[primary_span] pub span: Span, - #[suggestion(code = " => todo!(),", applicability = "has-placeholders")] + // We include the braces around `todo!()` so that a comma is optional, and we don't have to have + // any logic looking at the arm being replaced if there was a comma already or not for the + // resulting code to be correct. + #[suggestion( + code = " => {{ todo!() }}", + applicability = "has-placeholders", + style = "verbose" + )] pub suggestion: Span, } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e5d8013058f65..31ff102c127a3 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -178,18 +178,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ); } } - - // Emit errors for non-staged-api crates. - if !self.features.staged_api() { - if attr.has_name(sym::unstable) - || attr.has_name(sym::stable) - || attr.has_name(sym::rustc_const_unstable) - || attr.has_name(sym::rustc_const_stable) - || attr.has_name(sym::rustc_default_body_unstable) - { - self.sess.dcx().emit_err(errors::StabilityOutsideStd { span: attr.span }); - } - } } fn visit_item(&mut self, i: &'a ast::Item) { @@ -501,6 +489,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); + gate_all!(ergonomic_clones, "ergonomic clones are experimental"); gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards"); @@ -515,6 +504,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(unsafe_binders, "unsafe binder types are experimental"); gate_all!(contracts, "contracts are incomplete"); gate_all!(contracts_internals, "contract internal machinery is for internal use only"); + gate_all!(where_clause_attrs, "attributes in `where` clause are unstable"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index b4ed70d83e570..093199cf34212 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -10,7 +10,6 @@ #![feature(iter_is_partitioned)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod ast_validation; diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml index f290fedcd8b9a..2634dd1fdf93e 100644 --- a/compiler/rustc_ast_pretty/Cargo.toml +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_ast_pretty" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 602ab69ee5b5d..84d9ce278a21a 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -3,7 +3,6 @@ #![doc(rust_logo)] #![feature(box_patterns)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod helpers; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0bf5de3ef8985..a8eaff7346b7d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -11,9 +11,7 @@ use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; use rustc_ast::ptr::P; -use rustc_ast::token::{ - self, BinOpToken, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind, -}; +use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; @@ -26,7 +24,6 @@ use rustc_span::edition::Edition; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::IdentPrinter; use rustc_span::{BytePos, CharPos, DUMMY_SP, FileName, Ident, Pos, Span, Symbol, kw, sym}; -use thin_vec::ThinVec; use crate::pp::Breaks::{Consistent, Inconsistent}; use crate::pp::{self, Breaks}; @@ -319,7 +316,7 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { (tt1, Tok(Token { kind: Comma | Semi | Dot, .. }, _)) if !is_punct(tt1) => false, // IDENT + `!`: `println!()`, but `if !x { ... }` needs a space after the `if` - (Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Not, .. }, _)) + (Tok(Token { kind: Ident(sym, is_raw), span }, _), Tok(Token { kind: Bang, .. }, _)) if !Ident::new(*sym, *span).is_reserved() || matches!(is_raw, IdentIsRaw::Yes) => { false @@ -344,21 +341,6 @@ fn space_between(tt1: &TokenTree, tt2: &TokenTree) -> bool { } } -fn binop_to_string(op: BinOpToken) -> &'static str { - match op { - token::Plus => "+", - token::Minus => "-", - token::Star => "*", - token::Slash => "/", - token::Percent => "%", - token::Caret => "^", - token::And => "&", - token::Or => "|", - token::Shl => "<<", - token::Shr => ">>", - } -} - pub fn doc_comment_to_string( comment_kind: CommentKind, attr_style: ast::AttrStyle, @@ -424,20 +406,23 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.ann_post(ident) } - fn strsep( + fn strsep<'x, T: 'x, F, I>( &mut self, sep: &'static str, space_before: bool, b: Breaks, - elts: &[T], + elts: I, mut op: F, ) where F: FnMut(&mut Self, &T), + I: IntoIterator, { + let mut it = elts.into_iter(); + self.rbox(0, b); - if let Some((first, rest)) = elts.split_first() { + if let Some(first) = it.next() { op(self, first); - for elt in rest { + for elt in it { if space_before { self.space(); } @@ -448,9 +433,10 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.end(); } - fn commasep(&mut self, b: Breaks, elts: &[T], op: F) + fn commasep<'x, T: 'x, F, I>(&mut self, b: Breaks, elts: I, op: F) where F: FnMut(&mut Self, &T), + I: IntoIterator, { self.strsep(",", false, b, elts, op) } @@ -909,12 +895,30 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere token::Ne => "!=".into(), token::Ge => ">=".into(), token::Gt => ">".into(), - token::Not => "!".into(), + token::Bang => "!".into(), token::Tilde => "~".into(), token::OrOr => "||".into(), token::AndAnd => "&&".into(), - token::BinOp(op) => binop_to_string(op).into(), - token::BinOpEq(op) => format!("{}=", binop_to_string(op)).into(), + token::Plus => "+".into(), + token::Minus => "-".into(), + token::Star => "*".into(), + token::Slash => "/".into(), + token::Percent => "%".into(), + token::Caret => "^".into(), + token::And => "&".into(), + token::Or => "|".into(), + token::Shl => "<<".into(), + token::Shr => ">>".into(), + token::PlusEq => "+=".into(), + token::MinusEq => "-=".into(), + token::StarEq => "*=".into(), + token::SlashEq => "/=".into(), + token::PercentEq => "%=".into(), + token::CaretEq => "^=".into(), + token::AndEq => "&=".into(), + token::OrEq => "|=".into(), + token::ShlEq => "<<=".into(), + token::ShrEq => ">>=".into(), /* Structural symbols */ token::At => "@".into(), @@ -1778,6 +1782,13 @@ impl<'a> State<'a> { self.print_mutability(*m, false); self.word("self") } + SelfKind::Pinned(lt, m) => { + self.word("&"); + self.print_opt_lifetime(lt); + self.word("pin "); + self.print_mutability(*m, true); + self.word("self") + } SelfKind::Explicit(typ, m) => { self.print_mutability(*m, false); self.word("self"); @@ -1966,15 +1977,7 @@ impl<'a> State<'a> { ) { self.ibox(INDENT_UNIT); self.print_formal_generic_params(generic_params); - let generics = ast::Generics { - params: ThinVec::new(), - where_clause: ast::WhereClause { - has_where_token: false, - predicates: ThinVec::new(), - span: DUMMY_SP, - }, - span: DUMMY_SP, - }; + let generics = ast::Generics::default(); let header = ast::FnHeader { safety, ext, ..ast::FnHeader::default() }; self.print_fn(decl, header, name, &generics); self.end(); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 4b1374ceef31e..e3c41f117abb8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -5,7 +5,7 @@ use itertools::{Itertools, Position}; use rustc_ast::ptr::P; use rustc_ast::util::classify; use rustc_ast::util::literal::escape_byte_str_symbol; -use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity}; +use rustc_ast::util::parser::{self, ExprPrecedence, Fixity}; use rustc_ast::{ self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, FormatDebugHex, FormatSign, FormatTrait, token, @@ -279,12 +279,11 @@ impl<'a> State<'a> { rhs: &ast::Expr, fixup: FixupContext, ) { - let assoc_op = AssocOp::from_ast_binop(op.node); - let binop_prec = assoc_op.precedence(); + let binop_prec = op.node.precedence(); let left_prec = lhs.precedence(); let right_prec = rhs.precedence(); - let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() { + let (mut left_needs_paren, right_needs_paren) = match op.node.fixity() { Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec), Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec), Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec), @@ -575,6 +574,14 @@ impl<'a> State<'a> { ); self.word(".await"); } + ast::ExprKind::Use(expr, _) => { + self.print_expr_cond_paren( + expr, + expr.precedence() < ExprPrecedence::Unambiguous, + fixup, + ); + self.word(".use"); + } ast::ExprKind::Assign(lhs, rhs, _) => { self.print_expr_cond_paren( lhs, @@ -886,6 +893,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) { match capture_clause { ast::CaptureBy::Value { .. } => self.word_space("move"), + ast::CaptureBy::Use { .. } => self.word_space("use"), ast::CaptureBy::Ref => {} } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c10b5ad34e102..6236f8ecfb524 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -650,7 +650,16 @@ impl<'a> State<'a> { attrs: &[ast::Attribute], func: &ast::Fn, ) { - let ast::Fn { defaultness, generics, sig, contract, body } = func; + let ast::Fn { defaultness, generics, sig, contract, body, define_opaque } = func; + + if let Some(define_opaque) = define_opaque { + for (_, path) in define_opaque { + self.word("define opaques from "); + self.print_path(path, false, 0); + self.word(","); + } + } + if body.is_some() { self.head(""); } @@ -698,7 +707,7 @@ impl<'a> State<'a> { } self.print_generic_params(&generics.params); self.print_fn_params_and_ret(decl, false); - self.print_where_clause(&generics.where_clause) + self.print_where_clause(&generics.where_clause); } pub(crate) fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) { @@ -735,7 +744,8 @@ impl<'a> State<'a> { } pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) { - let ast::WherePredicate { kind, id: _, span: _ } = predicate; + let ast::WherePredicate { attrs, kind, id: _, span: _, is_placeholder: _ } = predicate; + self.print_outer_attributes(attrs); match kind { ast::WherePredicateKind::BoundPredicate(where_bound_predicate) => { self.print_where_bound_predicate(where_bound_predicate); diff --git a/compiler/rustc_attr_data_structures/Cargo.toml b/compiler/rustc_attr_data_structures/Cargo.toml index 2ee58f24470e9..b18923c337ff8 100644 --- a/compiler/rustc_attr_data_structures/Cargo.toml +++ b/compiler/rustc_attr_data_structures/Cargo.toml @@ -1,20 +1,16 @@ [package] name = "rustc_attr_data_structures" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start -rustc_abi = { path = "../rustc_abi" } -rustc_ast = { path = "../rustc_ast" } -rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_data_structures = { path = "../rustc_data_structures" } -rustc_errors = { path = "../rustc_errors" } -rustc_feature = { path = "../rustc_feature" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } -rustc_lexer = { path = "../rustc_lexer" } -rustc_macros = { path = "../rustc_macros" } -rustc_serialize = { path = "../rustc_serialize" } -rustc_session = { path = "../rustc_session" } -rustc_span = { path = "../rustc_span" } +rustc_abi = {path = "../rustc_abi"} +rustc_ast = {path = "../rustc_ast"} +rustc_ast_pretty = {path = "../rustc_ast_pretty"} +rustc_data_structures = {path = "../rustc_data_structures"} +rustc_macros = {path = "../rustc_macros"} +rustc_serialize = {path = "../rustc_serialize"} +rustc_span = {path = "../rustc_span"} +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index b4027a096c532..d2d1285b0756f 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -1,9 +1,12 @@ use rustc_abi::Align; -use rustc_ast as ast; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_ast::token::CommentKind; +use rustc_ast::{self as ast, AttrStyle}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; +use rustc_span::hygiene::Transparency; use rustc_span::{Span, Symbol}; +use thin_vec::ThinVec; -use crate::RustcVersion; +use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum InlineAttr { @@ -54,7 +57,7 @@ impl OptimizeAttr { } } -#[derive(Clone, Debug, Encodable, Decodable)] +#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)] pub enum DiagnosticAttribute { // tidy-alphabetical-start DoNotRecommend, @@ -62,7 +65,7 @@ pub enum DiagnosticAttribute { // tidy-alphabetical-end } -#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)] +#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)] pub enum ReprAttr { ReprInt(IntType), ReprRust, @@ -71,6 +74,8 @@ pub enum ReprAttr { ReprSimd, ReprTransparent, ReprAlign(Align), + // this one is just so we can emit a lint for it + ReprEmpty, } pub use ReprAttr::*; @@ -80,13 +85,13 @@ pub enum TransparencyError { } #[derive(Eq, PartialEq, Debug, Copy, Clone)] -#[derive(Encodable, Decodable)] +#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)] pub enum IntType { SignedInt(ast::IntTy), UnsignedInt(ast::UintTy), } -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] pub struct Deprecation { pub since: DeprecatedSince, /// The note to issue a reason. @@ -98,7 +103,7 @@ pub struct Deprecation { } /// Release in which an API is deprecated. -#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)] +#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)] pub enum DeprecatedSince { RustcVersion(RustcVersion), /// Deprecated in the future ("to be determined"). @@ -132,3 +137,64 @@ impl Deprecation { matches!(self.since, DeprecatedSince::RustcVersion(_)) } } + +/// Represent parsed, *built in*, inert attributes. +/// +/// That means attributes that are not actually ever expanded. +/// For more information on this, see the module docs on the [`rustc_attr_parsing`] crate. +/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler. +/// These are kept around after the AST, into the HIR and further on. +/// +/// The word "parsed" could be a little misleading here, because the parser already parses +/// attributes early on. However, the result, an [`ast::Attribute`] +/// is only parsed at a high level, still containing a token stream in many cases. That is +/// because the structure of the contents varies from attribute to attribute. +/// With a parsed attribute I mean that each attribute is processed individually into a +/// final structure, which on-site (the place where the attribute is useful for, think the +/// the place where `must_use` is checked) little to no extra parsing or validating needs to +/// happen. +/// +/// For more docs, look in [`rustc_attr_parsing`]. +/// +/// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html +#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] +pub enum AttributeKind { + // tidy-alphabetical-start + AllowConstFnUnstable(ThinVec), + AllowInternalUnstable(ThinVec<(Symbol, Span)>), + BodyStability { + stability: DefaultBodyStability, + /// Span of the `#[rustc_default_body_unstable(...)]` attribute + span: Span, + }, + Confusables { + symbols: ThinVec, + // FIXME(jdonszelmann): remove when target validation code is moved + first_span: Span, + }, + ConstStability { + stability: PartialConstStability, + /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute + span: Span, + }, + ConstStabilityIndirect, + Deprecation { + deprecation: Deprecation, + span: Span, + }, + Diagnostic(DiagnosticAttribute), + DocComment { + style: AttrStyle, + kind: CommentKind, + span: Span, + comment: Symbol, + }, + MacroTransparency(Transparency), + Repr(ThinVec<(ReprAttr, Span)>), + Stability { + stability: Stability, + /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute + span: Span, + }, + // tidy-alphabetical-end +} diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index 4f204aeab640f..bbd3308809c33 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -3,14 +3,200 @@ #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod attributes; mod stability; mod version; +use std::num::NonZero; + pub use attributes::*; -pub(crate) use rustc_session::HashStableContext; +use rustc_abi::Align; +use rustc_ast::token::CommentKind; +use rustc_ast::{AttrStyle, IntTy, UintTy}; +use rustc_ast_pretty::pp::Printer; +use rustc_span::hygiene::Transparency; +use rustc_span::{Span, Symbol}; pub use stability::*; +use thin_vec::ThinVec; pub use version::*; + +/// Requirements for a `StableHashingContext` to be used in this crate. +/// This is a hack to allow using the `HashStable_Generic` derive macro +/// instead of implementing everything in `rustc_middle`. +pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {} + +/// This trait is used to print attributes in `rustc_hir_pretty`. +/// +/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`]. +/// The output will look a lot like a `Debug` implementation, but fields of several types +/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the +/// representation much. +pub trait PrintAttribute { + /// Whether or not this will render as something meaningful, or if it's skipped + /// (which will force the containing struct to also skip printing a comma + /// and the field name). + fn should_render(&self) -> bool; + + fn print_attribute(&self, p: &mut Printer); +} + +impl PrintAttribute for &T { + fn should_render(&self) -> bool { + T::should_render(self) + } + + fn print_attribute(&self, p: &mut Printer) { + T::print_attribute(self, p) + } +} +impl PrintAttribute for Option { + fn should_render(&self) -> bool { + self.as_ref().is_some_and(|x| x.should_render()) + } + + fn print_attribute(&self, p: &mut Printer) { + if let Some(i) = self { + T::print_attribute(i, p) + } + } +} +impl PrintAttribute for ThinVec { + fn should_render(&self) -> bool { + self.is_empty() || self[0].should_render() + } + + fn print_attribute(&self, p: &mut Printer) { + let mut last_printed = false; + p.word("["); + for i in self { + if last_printed { + p.word_space(","); + } + i.print_attribute(p); + last_printed = i.should_render(); + } + p.word("]"); + } +} +macro_rules! print_skip { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn should_render(&self) -> bool { false } + fn print_attribute(&self, _: &mut Printer) { } + })* + }; +} + +macro_rules! print_disp { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn should_render(&self) -> bool { true } + fn print_attribute(&self, p: &mut Printer) { + p.word(format!("{}", self)); + } + } + )*}; +} +macro_rules! print_debug { + ($($t: ty),* $(,)?) => {$( + impl PrintAttribute for $t { + fn should_render(&self) -> bool { true } + fn print_attribute(&self, p: &mut Printer) { + p.word(format!("{:?}", self)); + } + } + )*}; +} + +macro_rules! print_tup { + (num_should_render $($ts: ident)*) => { 0 $(+ $ts.should_render() as usize)* }; + () => {}; + ($t: ident $($ts: ident)*) => { + #[allow(non_snake_case, unused)] + impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) { + fn should_render(&self) -> bool { + let ($t, $($ts),*) = self; + print_tup!(num_should_render $t $($ts)*) != 0 + } + + fn print_attribute(&self, p: &mut Printer) { + let ($t, $($ts),*) = self; + let parens = print_tup!(num_should_render $t $($ts)*) > 1; + if parens { + p.popen(); + } + + let mut printed_anything = $t.should_render(); + + $t.print_attribute(p); + + $( + if $ts.should_render() { + if printed_anything { + p.word_space(","); + } + printed_anything = true; + } + $ts.print_attribute(p); + )* + + if parens { + p.pclose(); + } + } + } + + print_tup!($($ts)*); + }; +} + +print_tup!(A B C D E F G H); +print_skip!(Span, ()); +print_disp!(u16, bool, NonZero); +print_debug!(Symbol, UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); + +/// Finds attributes in sequences of attributes by pattern matching. +/// +/// A little like `matches` but for attributes. +/// +/// ```rust,ignore (illustrative) +/// // finds the repr attribute +/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { +/// +/// } +/// +/// // checks if one has matched +/// if find_attr!(attrs, AttributeKind::Repr(_)) { +/// +/// } +/// ``` +/// +/// Often this requires you to first end up with a list of attributes. +/// A common way to get those is through `tcx.get_all_attrs(did)` +#[macro_export] +macro_rules! find_attr { + ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ + $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() + }}; + + ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ + fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator) {} + check_attribute_iterator(&$attributes_list); + + let find_attribute = |iter| { + for i in $attributes_list { + match i { + rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { + return Some($e); + } + _ => {} + } + } + + None + }; + find_attribute($attributes_list) + }}; +} diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs index c2213fc9ed881..c0ca08a60f8b3 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_attr_data_structures/src/stability.rs @@ -1,9 +1,9 @@ use std::num::NonZero; -use rustc_macros::{Decodable, Encodable, HashStable_Generic}; +use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute}; use rustc_span::{Symbol, sym}; -use crate::RustcVersion; +use crate::{PrintAttribute, RustcVersion}; /// The version placeholder that recently stabilized features contain inside the /// `since` field of the `#[stable]` attribute. @@ -21,7 +21,7 @@ pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N"); /// - `#[stable]` /// - `#[unstable]` #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct Stability { pub level: StabilityLevel, pub feature: Symbol, @@ -43,7 +43,7 @@ impl Stability { /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct ConstStability { pub level: StabilityLevel, pub feature: Symbol, @@ -83,7 +83,7 @@ impl ConstStability { /// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked` /// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct PartialConstStability { pub level: StabilityLevel, pub feature: Symbol, @@ -103,7 +103,7 @@ impl PartialConstStability { /// The available stability levels. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub enum StabilityLevel { /// `#[unstable]` Unstable { @@ -145,7 +145,7 @@ pub enum StabilityLevel { /// Rust release in which a feature is stabilized. #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub enum StableSince { /// also stores the original symbol for printing Version(RustcVersion), @@ -171,7 +171,7 @@ impl StabilityLevel { } #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub enum UnstableReason { None, Default, @@ -180,7 +180,7 @@ pub enum UnstableReason { /// Represents the `#[rustc_default_body_unstable]` attribute. #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct DefaultBodyStability { pub level: StabilityLevel, pub feature: Symbol, diff --git a/compiler/rustc_attr_data_structures/src/version.rs b/compiler/rustc_attr_data_structures/src/version.rs index 6be875ad4be86..69b0e041d819d 100644 --- a/compiler/rustc_attr_data_structures/src/version.rs +++ b/compiler/rustc_attr_data_structures/src/version.rs @@ -1,9 +1,13 @@ use std::fmt::{self, Display}; -use rustc_macros::{Decodable, Encodable, HashStable_Generic, current_rustc_version}; +use rustc_macros::{ + Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version, +}; + +use crate::PrintAttribute; #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[derive(HashStable_Generic)] +#[derive(HashStable_Generic, PrintAttribute)] pub struct RustcVersion { pub major: u16, pub minor: u16, diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index 7ccedf40c3fa9..6b4ce957630ff 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_attr_parsing" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -13,9 +13,12 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } +thin-vec = "0.2.12" # tidy-alphabetical-end diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index faa2865cb9130..45174c9582d33 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -6,6 +6,8 @@ attr_parsing_deprecated_item_suggestion = .help = add `#![feature(deprecated_suggestion)]` to the crate root .note = see #94785 for more details +attr_parsing_empty_confusables = + expected at least one confusable name attr_parsing_expected_one_cfg_pattern = expected 1 cfg-pattern @@ -21,8 +23,8 @@ attr_parsing_expects_feature_list = attr_parsing_expects_features = `{$name}` expects feature names -attr_parsing_incorrect_meta_item = - incorrect meta item +attr_parsing_incorrect_meta_item = expected a quoted string literal +attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes attr_parsing_incorrect_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses @@ -88,18 +90,20 @@ attr_parsing_multiple_stability_levels = attr_parsing_non_ident_feature = 'feature' is not an identifier +attr_parsing_repr_ident = + meta item in `repr` must be an identifier + attr_parsing_rustc_allowed_unstable_pairing = `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute -attr_parsing_rustc_const_stable_indirect_pairing = - `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied - attr_parsing_rustc_promotable_pairing = `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute attr_parsing_soft_no_args = `soft` should not have any arguments +attr_parsing_stability_outside_std = stability attributes may not be used outside of the standard library + attr_parsing_unknown_meta_item = unknown meta item '{$item}' .label = expected one of {$expected} @@ -107,6 +111,10 @@ attr_parsing_unknown_meta_item = attr_parsing_unknown_version_literal = unknown version literal format, assuming it refers to a future version +attr_parsing_unrecognized_repr_hint = + unrecognized representation hint + .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` + attr_parsing_unstable_cfg_target_compact = compact `cfg(target(..))` is experimental and subject to change @@ -122,3 +130,8 @@ attr_parsing_unsupported_literal_generic = unsupported literal attr_parsing_unsupported_literal_suggestion = consider removing the prefix + +attr_parsing_unused_multiple = + multiple `{$name}` attributes + .suggestion = remove this attribute + .note = attribute also specified here diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 471168ed4f56d..d37ede86cfd2a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -1,49 +1,67 @@ -use rustc_ast::attr::{AttributeExt, filter_by_name}; -use rustc_session::Session; -use rustc_span::{Symbol, sym}; +use std::iter; +use rustc_attr_data_structures::AttributeKind; +use rustc_span::{Span, Symbol, sym}; + +use super::{CombineAttributeParser, ConvertFn}; +use crate::context::AcceptContext; +use crate::parser::ArgParser; use crate::session_diagnostics; -pub fn allow_internal_unstable<'a>( - sess: &'a Session, - attrs: &'a [impl AttributeExt], -) -> impl Iterator + 'a { - allow_unstable(sess, attrs, sym::allow_internal_unstable) +pub(crate) struct AllowInternalUnstableParser; +impl CombineAttributeParser for AllowInternalUnstableParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::allow_internal_unstable]; + type Item = (Symbol, Span); + const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; + + fn extend<'a>( + cx: &'a AcceptContext<'a>, + args: &'a ArgParser<'a>, + ) -> impl IntoIterator + 'a { + parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span)) + } } -pub fn rustc_allow_const_fn_unstable<'a>( - sess: &'a Session, - attrs: &'a [impl AttributeExt], -) -> impl Iterator + 'a { - allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable) +pub(crate) struct AllowConstFnUnstableParser; +impl CombineAttributeParser for AllowConstFnUnstableParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable]; + type Item = Symbol; + const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; + + fn extend<'a>( + cx: &'a AcceptContext<'a>, + args: &'a ArgParser<'a>, + ) -> impl IntoIterator + 'a { + parse_unstable(cx, args, Self::PATH[0]) + } } -fn allow_unstable<'a>( - sess: &'a Session, - attrs: &'a [impl AttributeExt], +fn parse_unstable<'a>( + cx: &AcceptContext<'_>, + args: &'a ArgParser<'a>, symbol: Symbol, -) -> impl Iterator + 'a { - let attrs = filter_by_name(attrs, symbol); - let list = attrs - .filter_map(move |attr| { - attr.meta_item_list().or_else(|| { - sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList { - span: attr.span(), - name: symbol.to_ident_string(), - }); - None - }) - }) - .flatten(); - - list.into_iter().filter_map(move |it| { - let name = it.ident().map(|ident| ident.name); - if name.is_none() { - sess.dcx().emit_err(session_diagnostics::ExpectsFeatures { - span: it.span(), +) -> impl IntoIterator { + let mut res = Vec::new(); + + let Some(list) = args.list() else { + cx.emit_err(session_diagnostics::ExpectsFeatureList { + span: cx.attr_span, + name: symbol.to_ident_string(), + }); + return res; + }; + + for param in list.mixed() { + let param_span = param.span(); + if let Some(ident) = param.meta_item().and_then(|i| i.word_without_args()) { + res.push(ident.name); + } else { + cx.emit_err(session_diagnostics::ExpectsFeatures { + span: param_span, name: symbol.to_ident_string(), }); } - name - }) + } + + res } diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index bb9aaaa2fea9e..0d6d521b40c61 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -1,6 +1,4 @@ -//! Parsing and validation of builtin attributes - -use rustc_ast::{self as ast, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; +use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId}; use rustc_ast_pretty::pprust; use rustc_attr_data_structures::RustcVersion; use rustc_feature::{Features, GatedCfg, find_gated_cfg}; @@ -9,10 +7,11 @@ use rustc_session::config::ExpectedValues; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::UNEXPECTED_CFGS; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::symbol::kw; +use rustc_span::{Span, Symbol, sym}; -use crate::util::UnsupportedLiteralReason; -use crate::{fluent_generated, parse_version, session_diagnostics}; +use crate::session_diagnostics::{self, UnsupportedLiteralReason}; +use crate::{fluent_generated, parse_version}; #[derive(Clone, Debug)] pub struct Condition { @@ -25,7 +24,7 @@ pub struct Condition { /// Tests if a cfg-pattern matches the cfg set pub fn cfg_matches( - cfg: &ast::MetaItemInner, + cfg: &MetaItemInner, sess: &Session, lint_node_id: NodeId, features: Option<&Features>, @@ -80,7 +79,7 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Fea /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to /// evaluate individual items. pub fn eval_condition( - cfg: &ast::MetaItemInner, + cfg: &MetaItemInner, sess: &Session, features: Option<&Features>, eval: &mut impl FnMut(Condition) -> bool, @@ -88,8 +87,8 @@ pub fn eval_condition( let dcx = sess.dcx(); let cfg = match cfg { - ast::MetaItemInner::MetaItem(meta_item) => meta_item, - ast::MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { + MetaItemInner::MetaItem(meta_item) => meta_item, + MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => { if let Some(features) = features { // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true` // and `true`, and we want to keep the former working without feature gate @@ -118,7 +117,7 @@ pub fn eval_condition( }; match &cfg.kind { - ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { + MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { @@ -150,7 +149,7 @@ pub fn eval_condition( RustcVersion::CURRENT >= min_version } } - ast::MetaItemKind::List(mis) => { + MetaItemKind::List(mis) => { for mi in mis.iter() { if mi.meta_item_or_bool().is_none() { dcx.emit_err(session_diagnostics::UnsupportedLiteral { @@ -209,12 +208,7 @@ pub fn eval_condition( seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name)); } - res & eval_condition( - &ast::MetaItemInner::MetaItem(mi), - sess, - features, - eval, - ) + res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval) }) } _ => { @@ -226,7 +220,7 @@ pub fn eval_condition( } } } - ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { + MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => { dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); true } @@ -239,7 +233,7 @@ pub fn eval_condition( }); true } - ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => { + MetaItemKind::Word | MetaItemKind::NameValue(..) => { let ident = cfg.ident().expect("multi-segment cfg predicate"); eval(Condition { name: ident.name, diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 2ced759fd8883..6cff952fcf229 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,21 +1,58 @@ -//! Parsing and validation of builtin attributes +use rustc_attr_data_structures::AttributeKind; +use rustc_span::{Span, Symbol, sym}; +use thin_vec::ThinVec; -use rustc_ast::MetaItemInner; -use rustc_ast::attr::AttributeExt; -use rustc_span::Symbol; +use super::{AcceptMapping, AttributeParser}; +use crate::context::FinalizeContext; +use crate::session_diagnostics; -/// Read the content of a `rustc_confusables` attribute, and return the list of candidate names. -pub fn parse_confusables(attr: &impl AttributeExt) -> Option> { - let metas = attr.meta_item_list()?; +#[derive(Default)] +pub(crate) struct ConfusablesParser { + confusables: ThinVec, + first_span: Option, +} + +impl AttributeParser for ConfusablesParser { + const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], |this, cx, args| { + let Some(list) = args.list() else { + // FIXME(jdonszelmann): error when not a list? Bring validation code here. + // NOTE: currently subsequent attributes are silently ignored using + // tcx.get_attr(). + return; + }; + + if list.is_empty() { + cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); + } + + for param in list.mixed() { + let span = param.span(); - let mut candidates = Vec::new(); + let Some(lit) = param.lit() else { + cx.emit_err(session_diagnostics::IncorrectMetaItem { + span, + suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion { + lo: span.shrink_to_lo(), + hi: span.shrink_to_hi(), + }), + }); + continue; + }; - for meta in metas { - let MetaItemInner::Lit(meta_lit) = meta else { + this.confusables.push(lit.symbol); + } + + this.first_span.get_or_insert(cx.attr_span); + })]; + + fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + if self.confusables.is_empty() { return None; - }; - candidates.push(meta_lit.symbol); - } + } - Some(candidates) + Some(AttributeKind::Confusables { + symbols: self.confusables, + first_span: self.first_span.unwrap(), + }) + } } diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index d7415a7198fd6..7d1417446b21d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,121 +1,122 @@ -//! Parsing and validation of builtin attributes - -use rustc_ast::attr::AttributeExt; -use rustc_ast::{MetaItem, MetaItemInner}; -use rustc_ast_pretty::pprust; -use rustc_attr_data_structures::{DeprecatedSince, Deprecation}; -use rustc_feature::Features; -use rustc_session::Session; +use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; +use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol, sym}; -use super::util::UnsupportedLiteralReason; -use crate::{parse_version, session_diagnostics}; +use super::SingleAttributeParser; +use super::util::parse_version; +use crate::context::AcceptContext; +use crate::parser::ArgParser; +use crate::session_diagnostics; +use crate::session_diagnostics::UnsupportedLiteralReason; -/// Finds the deprecation attribute. `None` if none exists. -pub fn find_deprecation( - sess: &Session, - features: &Features, - attrs: &[impl AttributeExt], -) -> Option<(Deprecation, Span)> { - let mut depr: Option<(Deprecation, Span)> = None; - let is_rustc = features.staged_api(); +pub(crate) struct DeprecationParser; - 'outer: for attr in attrs { - if !attr.has_name(sym::deprecated) { - continue; +fn get( + cx: &AcceptContext<'_>, + ident: Ident, + param_span: Span, + arg: &ArgParser<'_>, + item: &Option, +) -> Option { + if item.is_some() { + cx.emit_err(session_diagnostics::MultipleItem { + span: param_span, + item: ident.to_string(), + }); + return None; + } + if let Some(v) = arg.name_value() { + if let Some(value_str) = v.value_as_str() { + Some(value_str) + } else { + let lit = v.value_as_lit(); + cx.emit_err(session_diagnostics::UnsupportedLiteral { + span: v.value_span, + reason: UnsupportedLiteralReason::DeprecatedString, + is_bytestr: lit.kind.is_bytestr(), + start_point_span: cx.sess().source_map().start_point(lit.span), + }); + None } + } else { + // FIXME(jdonszelmann): suggestion? + cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None }); + None + } +} + +impl SingleAttributeParser for DeprecationParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; + + fn on_duplicate(cx: &AcceptContext<'_>, first_span: rustc_span::Span) { + // FIXME(jdonszelmann): merge with errors from check_attrs.rs + cx.emit_err(session_diagnostics::UnusedMultiple { + this: cx.attr_span, + other: first_span, + name: sym::deprecated, + }); + } + + fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + let features = cx.features(); let mut since = None; let mut note = None; let mut suggestion = None; - if attr.is_doc_comment() { - continue; - } else if attr.is_word() { - } else if let Some(value) = attr.value_str() { - note = Some(value) - } else if let Some(list) = attr.meta_item_list() { - let get = |meta: &MetaItem, item: &mut Option| { - if item.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleItem { - span: meta.span, - item: pprust::path_to_string(&meta.path), + let is_rustc = features.staged_api(); + + if let Some(value) = args.name_value() + && let Some(value_str) = value.value_as_str() + { + note = Some(value_str) + } else if let Some(list) = args.list() { + for param in list.mixed() { + let param_span = param.span(); + let Some(param) = param.meta_item() else { + cx.emit_err(session_diagnostics::UnsupportedLiteral { + span: param_span, + reason: UnsupportedLiteralReason::DeprecatedKvPair, + is_bytestr: false, + start_point_span: cx.sess().source_map().start_point(param_span), }); - return false; - } - if let Some(v) = meta.value_str() { - *item = Some(v); - true - } else { - if let Some(lit) = meta.name_value_literal() { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::DeprecatedString, - is_bytestr: lit.kind.is_bytestr(), - start_point_span: sess.source_map().start_point(lit.span), - }); - } else { - sess.dcx() - .emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); - } - false - } - }; + return None; + }; - for meta in &list { - match meta { - MetaItemInner::MetaItem(mi) => match mi.name_or_empty() { - sym::since => { - if !get(mi, &mut since) { - continue 'outer; - } - } - sym::note => { - if !get(mi, &mut note) { - continue 'outer; - } - } - sym::suggestion => { - if !features.deprecated_suggestion() { - sess.dcx().emit_err( - session_diagnostics::DeprecatedItemSuggestion { - span: mi.span, - is_nightly: sess.is_nightly_build(), - details: (), - }, - ); - } + let (ident, arg) = param.word_or_empty(); - if !get(mi, &mut suggestion) { - continue 'outer; - } - } - _ => { - sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { - span: meta.span(), - item: pprust::path_to_string(&mi.path), - expected: if features.deprecated_suggestion() { - &["since", "note", "suggestion"] - } else { - &["since", "note"] - }, + match ident.name { + sym::since => { + since = Some(get(cx, ident, param_span, arg, &since)?); + } + sym::note => { + note = Some(get(cx, ident, param_span, arg, ¬e)?); + } + sym::suggestion => { + if !features.deprecated_suggestion() { + cx.emit_err(session_diagnostics::DeprecatedItemSuggestion { + span: param_span, + is_nightly: cx.sess().is_nightly_build(), + details: (), }); - continue 'outer; } - }, - MetaItemInner::Lit(lit) => { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: lit.span, - reason: UnsupportedLiteralReason::DeprecatedKvPair, - is_bytestr: false, - start_point_span: sess.source_map().start_point(lit.span), + + suggestion = Some(get(cx, ident, param_span, arg, &suggestion)?); + } + _ => { + cx.emit_err(session_diagnostics::UnknownMetaItem { + span: param_span, + item: ident.to_string(), + expected: if features.deprecated_suggestion() { + &["since", "note", "suggestion"] + } else { + &["since", "note"] + }, }); - continue 'outer; + return None; } } } - } else { - continue; } let since = if let Some(since) = since { @@ -126,23 +127,24 @@ pub fn find_deprecation( } else if let Some(version) = parse_version(since) { DeprecatedSince::RustcVersion(version) } else { - sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() }); + cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); DeprecatedSince::Err } } else if is_rustc { - sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() }); + cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span }); DeprecatedSince::Err } else { DeprecatedSince::Unspecified }; if is_rustc && note.is_none() { - sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span() }); - continue; + cx.emit_err(session_diagnostics::MissingNote { span: cx.attr_span }); + return None; } - depr = Some((Deprecation { since, note, suggestion }, attr.span())); + Some(AttributeKind::Deprecation { + deprecation: Deprecation { since, note, suggestion }, + span: cx.attr_span, + }) } - - depr } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index a78e0b54b64aa..6ecd6b4d7dbb7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -1,17 +1,152 @@ -mod allow_unstable; -mod cfg; -mod confusables; -mod deprecation; -mod repr; -mod stability; -mod transparency; - -pub mod util; - -pub use allow_unstable::*; -pub use cfg::*; -pub use confusables::*; -pub use deprecation::*; -pub use repr::*; -pub use stability::*; -pub use transparency::*; +//! This module defines traits for attribute parsers, little state machines that recognize and parse +//! attributes out of a longer list of attributes. The main trait is called [`AttributeParser`]. +//! You can find more docs about [`AttributeParser`]s on the trait itself. +//! However, for many types of attributes, implementing [`AttributeParser`] is not necessary. +//! It allows for a lot of flexibility you might not want. +//! +//! Specifically, you might not care about managing the state of your [`AttributeParser`] +//! state machine yourself. In this case you can choose to implement: +//! +//! - [`SingleAttributeParser`]: makes it easy to implement an attribute which should error if it +//! appears more than once in a list of attributes +//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the +//! contents of attributes, if an attribute appear multiple times in a list +//! +//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed. + +use std::marker::PhantomData; + +use rustc_attr_data_structures::AttributeKind; +use rustc_span::Span; +use thin_vec::ThinVec; + +use crate::context::{AcceptContext, FinalizeContext}; +use crate::parser::ArgParser; + +pub(crate) mod allow_unstable; +pub(crate) mod cfg; +pub(crate) mod confusables; +pub(crate) mod deprecation; +pub(crate) mod repr; +pub(crate) mod stability; +pub(crate) mod transparency; +pub(crate) mod util; + +type AcceptFn = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>); +type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; + +/// An [`AttributeParser`] is a type which searches for syntactic attributes. +/// +/// Parsers are often tiny state machines that gets to see all syntactical attributes on an item. +/// [`Default::default`] creates a fresh instance that sits in some kind of initial state, usually that the +/// attribute it is looking for was not yet seen. +/// +/// Then, it defines what paths this group will accept in [`AttributeParser::ATTRIBUTES`]. +/// These are listed as pairs, of symbols and function pointers. The function pointer will +/// be called when that attribute is found on an item, which can influence the state of the little +/// state machine. +/// +/// Finally, after all attributes on an item have been seen, and possibly been accepted, +/// the [`finalize`](AttributeParser::finalize) functions for all attribute parsers are called. Each can then report +/// whether it has seen the attribute it has been looking for. +/// +/// The state machine is automatically reset to parse attributes on the next item. +pub(crate) trait AttributeParser: Default + 'static { + /// The symbols for the attributes that this parser is interested in. + /// + /// If an attribute has this symbol, the `accept` function will be called on it. + const ATTRIBUTES: AcceptMapping; + + /// The parser has gotten a chance to accept the attributes on an item, + /// here it can produce an attribute. + fn finalize(self, cx: &FinalizeContext<'_>) -> Option; +} + +/// Alternative to [`AttributeParser`] that automatically handles state management. +/// A slightly simpler and more restricted way to convert attributes. +/// Assumes that an attribute can only appear a single time on an item, +/// and errors when it sees more. +/// +/// [`Single where T: SingleAttributeParser`](Single) implements [`AttributeParser`]. +/// +/// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple +/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. +pub(crate) trait SingleAttributeParser: 'static { + const PATH: &'static [rustc_span::Symbol]; + + /// Caled when a duplicate attribute is found. + /// + /// `first_span` is the span of the first occurrence of this attribute. + // FIXME(jdonszelmann): default error + fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span); + + /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] + fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option; +} + +pub(crate) struct Single(PhantomData, Option<(AttributeKind, Span)>); + +impl Default for Single { + fn default() -> Self { + Self(Default::default(), Default::default()) + } +} + +impl AttributeParser for Single { + const ATTRIBUTES: AcceptMapping = &[(T::PATH, |group: &mut Single, cx, args| { + if let Some((_, s)) = group.1 { + T::on_duplicate(cx, s); + return; + } + + if let Some(pa) = T::convert(cx, args) { + group.1 = Some((pa, cx.attr_span)); + } + })]; + + fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + Some(self.1?.0) + } +} + +type ConvertFn = fn(ThinVec) -> AttributeKind; + +/// Alternative to [`AttributeParser`] that automatically handles state management. +/// If multiple attributes appear on an element, combines the values of each into a +/// [`ThinVec`]. +/// [`Combine where T: CombineAttributeParser`](Combine) implements [`AttributeParser`]. +/// +/// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple +/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. +pub(crate) trait CombineAttributeParser: 'static { + const PATH: &'static [rustc_span::Symbol]; + + type Item; + const CONVERT: ConvertFn; + + /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] + fn extend<'a>( + cx: &'a AcceptContext<'a>, + args: &'a ArgParser<'a>, + ) -> impl IntoIterator + 'a; +} + +pub(crate) struct Combine( + PhantomData, + ThinVec<::Item>, +); + +impl Default for Combine { + fn default() -> Self { + Self(Default::default(), Default::default()) + } +} + +impl AttributeParser for Combine { + const ATTRIBUTES: AcceptMapping = + &[(T::PATH, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; + + fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 28c381160b874..26ca637faec68 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,15 +1,13 @@ -//! Parsing and validation of builtin attributes - use rustc_abi::Align; -use rustc_ast::attr::AttributeExt; -use rustc_ast::{self as ast, MetaItemKind}; -use rustc_attr_data_structures::IntType; -use rustc_attr_data_structures::ReprAttr::*; -use rustc_session::Session; -use rustc_span::{Symbol, sym}; +use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; +use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; +use rustc_span::{Span, Symbol, sym}; -use crate::ReprAttr; -use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; +use super::{CombineAttributeParser, ConvertFn}; +use crate::context::AcceptContext; +use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; +use crate::session_diagnostics; +use crate::session_diagnostics::IncorrectReprFormatGenericCause; /// Parse #[repr(...)] forms. /// @@ -18,185 +16,216 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; /// the same discriminant size that the corresponding C enum would or C /// structure layout, `packed` to remove padding, and `transparent` to delegate representation /// concerns to the only non-ZST field. -pub fn find_repr_attrs(sess: &Session, attr: &impl AttributeExt) -> Vec { - if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() } -} +// FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct? +pub(crate) struct ReprParser; -pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec { - assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}"); - let mut acc = Vec::new(); - let dcx = sess.dcx(); - - if let Some(items) = attr.meta_item_list() { - for item in items { - let mut recognised = false; - if item.is_word() { - let hint = match item.name_or_empty() { - sym::Rust => Some(ReprRust), - sym::C => Some(ReprC), - sym::packed => Some(ReprPacked(Align::ONE)), - sym::simd => Some(ReprSimd), - sym::transparent => Some(ReprTransparent), - sym::align => { - sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg { - span: item.span(), - }); - recognised = true; - None - } - name => int_type_of_word(name).map(ReprInt), - }; - - if let Some(h) = hint { - recognised = true; - acc.push(h); - } - } else if let Some((name, value)) = item.singleton_lit_list() { - let mut literal_error = None; - let mut err_span = item.span(); - if name == sym::align { - recognised = true; - match parse_alignment(&value.kind) { - Ok(literal) => acc.push(ReprAlign(literal)), - Err(message) => { - err_span = value.span; - literal_error = Some(message) - } - }; - } else if name == sym::packed { - recognised = true; - match parse_alignment(&value.kind) { - Ok(literal) => acc.push(ReprPacked(literal)), - Err(message) => { - err_span = value.span; - literal_error = Some(message) - } - }; - } else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent) - || int_type_of_word(name).is_some() - { - recognised = true; - sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen { - span: item.span(), - name: name.to_ident_string(), - }); - } - if let Some(literal_error) = literal_error { - sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric { - span: err_span, - repr_arg: name.to_ident_string(), - error_part: literal_error, - }); - } - } else if let Some(meta_item) = item.meta_item() { - match &meta_item.kind { - MetaItemKind::NameValue(value) => { - if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) { - let name = meta_item.name_or_empty().to_ident_string(); - recognised = true; - sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric { - span: item.span(), - repr_arg: &name, - cause: IncorrectReprFormatGenericCause::from_lit_kind( - item.span(), - &value.kind, - &name, - ), - }); - } else if matches!( - meta_item.name_or_empty(), - sym::Rust | sym::C | sym::simd | sym::transparent - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue { - span: meta_item.span, - name: meta_item.name_or_empty().to_ident_string(), - }); - } - } - MetaItemKind::List(nested_items) => { - if meta_item.has_name(sym::align) { - recognised = true; - if let [nested_item] = nested_items.as_slice() { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatExpectInteger { - span: nested_item.span(), - }, - ); - } else { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatAlignOneArg { - span: meta_item.span, - }, - ); - } - } else if meta_item.has_name(sym::packed) { - recognised = true; - if let [nested_item] = nested_items.as_slice() { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatPackedExpectInteger { - span: nested_item.span(), - }, - ); - } else { - sess.dcx().emit_err( - session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { - span: meta_item.span, - }, - ); - } - } else if matches!( - meta_item.name_or_empty(), - sym::Rust | sym::C | sym::simd | sym::transparent - ) || int_type_of_word(meta_item.name_or_empty()).is_some() - { - recognised = true; - sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen { - span: meta_item.span, - name: meta_item.name_or_empty().to_ident_string(), - }); - } - } - _ => (), - } - } - if !recognised { - // Not a word we recognize. This will be caught and reported by - // the `check_mod_attrs` pass, but this pass doesn't always run - // (e.g. if we only pretty-print the source), so we have to gate - // the `span_delayed_bug` call as follows: - if sess.opts.pretty.is_none_or(|pp| pp.needs_analysis()) { - dcx.span_delayed_bug(item.span(), "unrecognized representation hint"); - } +impl CombineAttributeParser for ReprParser { + type Item = (ReprAttr, Span); + const PATH: &'static [rustc_span::Symbol] = &[sym::repr]; + const CONVERT: ConvertFn = AttributeKind::Repr; + + fn extend<'a>( + cx: &'a AcceptContext<'a>, + args: &'a ArgParser<'a>, + ) -> impl IntoIterator + 'a { + let mut reprs = Vec::new(); + + let Some(list) = args.list() else { + return reprs; + }; + + if list.is_empty() { + // this is so validation can emit a lint + reprs.push((ReprAttr::ReprEmpty, cx.attr_span)); + } + + for param in list.mixed() { + if let Some(_) = param.lit() { + cx.emit_err(session_diagnostics::ReprIdent { span: cx.attr_span }); + continue; } + + reprs.extend( + param.meta_item().and_then(|mi| parse_repr(cx, &mi)).map(|r| (r, param.span())), + ); } + + reprs } - acc +} + +macro_rules! int_pat { + () => { + sym::i8 + | sym::u8 + | sym::i16 + | sym::u16 + | sym::i32 + | sym::u32 + | sym::i64 + | sym::u64 + | sym::i128 + | sym::u128 + | sym::isize + | sym::usize + }; } fn int_type_of_word(s: Symbol) -> Option { - use rustc_attr_data_structures::IntType::*; + use IntType::*; match s { - sym::i8 => Some(SignedInt(ast::IntTy::I8)), - sym::u8 => Some(UnsignedInt(ast::UintTy::U8)), - sym::i16 => Some(SignedInt(ast::IntTy::I16)), - sym::u16 => Some(UnsignedInt(ast::UintTy::U16)), - sym::i32 => Some(SignedInt(ast::IntTy::I32)), - sym::u32 => Some(UnsignedInt(ast::UintTy::U32)), - sym::i64 => Some(SignedInt(ast::IntTy::I64)), - sym::u64 => Some(UnsignedInt(ast::UintTy::U64)), - sym::i128 => Some(SignedInt(ast::IntTy::I128)), - sym::u128 => Some(UnsignedInt(ast::UintTy::U128)), - sym::isize => Some(SignedInt(ast::IntTy::Isize)), - sym::usize => Some(UnsignedInt(ast::UintTy::Usize)), + sym::i8 => Some(SignedInt(IntTy::I8)), + sym::u8 => Some(UnsignedInt(UintTy::U8)), + sym::i16 => Some(SignedInt(IntTy::I16)), + sym::u16 => Some(UnsignedInt(UintTy::U16)), + sym::i32 => Some(SignedInt(IntTy::I32)), + sym::u32 => Some(UnsignedInt(UintTy::U32)), + sym::i64 => Some(SignedInt(IntTy::I64)), + sym::u64 => Some(UnsignedInt(UintTy::U64)), + sym::i128 => Some(SignedInt(IntTy::I128)), + sym::u128 => Some(UnsignedInt(UintTy::U128)), + sym::isize => Some(SignedInt(IntTy::Isize)), + sym::usize => Some(UnsignedInt(UintTy::Usize)), _ => None, } } -pub fn parse_alignment(node: &ast::LitKind) -> Result { - if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { +fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option { + use ReprAttr::*; + + // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the + // structure. + let (ident, args) = param.word_or_empty(); + + match (ident.name, args) { + (sym::align, ArgParser::NoArgs) => { + cx.emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident.span }); + None + } + (sym::align, ArgParser::List(l)) => parse_repr_align(cx, l, param.span(), AlignKind::Align), + + (sym::packed, ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)), + (sym::packed, ArgParser::List(l)) => { + parse_repr_align(cx, l, param.span(), AlignKind::Packed) + } + + (sym::align | sym::packed, ArgParser::NameValue(l)) => { + cx.emit_err(session_diagnostics::IncorrectReprFormatGeneric { + span: param.span(), + // FIXME(jdonszelmann) can just be a string in the diag type + repr_arg: &ident.to_string(), + cause: IncorrectReprFormatGenericCause::from_lit_kind( + param.span(), + &l.value_as_lit().kind, + ident.name.as_str(), + ), + }); + None + } + + (sym::Rust, ArgParser::NoArgs) => Some(ReprRust), + (sym::C, ArgParser::NoArgs) => Some(ReprC), + (sym::simd, ArgParser::NoArgs) => Some(ReprSimd), + (sym::transparent, ArgParser::NoArgs) => Some(ReprTransparent), + (i @ int_pat!(), ArgParser::NoArgs) => { + // int_pat!() should make sure it always parses + Some(ReprInt(int_type_of_word(i).unwrap())) + } + + ( + sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), + ArgParser::NameValue(_), + ) => { + cx.emit_err(session_diagnostics::InvalidReprHintNoValue { + span: param.span(), + name: ident.to_string(), + }); + None + } + (sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), ArgParser::List(_)) => { + cx.emit_err(session_diagnostics::InvalidReprHintNoParen { + span: param.span(), + name: ident.to_string(), + }); + None + } + + _ => { + cx.emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() }); + None + } + } +} + +enum AlignKind { + Packed, + Align, +} + +fn parse_repr_align( + cx: &AcceptContext<'_>, + list: &MetaItemListParser<'_>, + param_span: Span, + align_kind: AlignKind, +) -> Option { + use AlignKind::*; + + let Some(align) = list.single() else { + match align_kind { + Packed => { + cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg { + span: param_span, + }); + } + Align => { + cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg { + span: param_span, + }); + } + } + + return None; + }; + + let Some(lit) = align.lit() else { + match align_kind { + Packed => { + cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger { + span: align.span(), + }); + } + Align => { + cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger { + span: align.span(), + }); + } + } + + return None; + }; + + match parse_alignment(&lit.kind) { + Ok(literal) => Some(match align_kind { + AlignKind::Packed => ReprAttr::ReprPacked(literal), + AlignKind::Align => ReprAttr::ReprAlign(literal), + }), + Err(message) => { + cx.emit_err(session_diagnostics::InvalidReprGeneric { + span: lit.span, + repr_arg: match align_kind { + Packed => "packed".to_string(), + Align => "align".to_string(), + }, + error_part: message, + }); + None + } + } +} + +fn parse_alignment(node: &LitKind) -> Result { + if let LitKind::Int(literal, LitIntType::Unsuffixed) = node { // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first if literal.get().is_power_of_two() { // Only possible error is larger than 2^29 diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 454b8b5de82b5..6d76456e83c80 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -1,266 +1,258 @@ -//! Parsing and validation of builtin attributes - use std::num::NonZero; -use rustc_ast::MetaItem; -use rustc_ast::attr::AttributeExt; -use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{ - ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, UnstableReason, - VERSION_PLACEHOLDER, + AttributeKind, DefaultBodyStability, PartialConstStability, Stability, StabilityLevel, + StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; -use rustc_session::Session; use rustc_span::{Span, Symbol, kw, sym}; -use crate::attributes::util::UnsupportedLiteralReason; -use crate::{parse_version, session_diagnostics}; - -/// Collects stability info from `stable`/`unstable`/`rustc_allowed_through_unstable_modules` -/// attributes in `attrs`. Returns `None` if no stability attributes are found. -pub fn find_stability( - sess: &Session, - attrs: &[impl AttributeExt], - item_sp: Span, -) -> Option<(Stability, Span)> { - let mut stab: Option<(Stability, Span)> = None; - let mut allowed_through_unstable_modules = None; - - for attr in attrs { - match attr.name_or_empty() { - sym::rustc_allowed_through_unstable_modules => { - // The value is mandatory, but avoid ICEs in case such code reaches this function. - allowed_through_unstable_modules = Some(attr.value_str().unwrap_or_else(|| { - sess.dcx().span_delayed_bug( - item_sp, - "`#[rustc_allowed_through_unstable_modules]` without deprecation message", - ); - kw::Empty - })) - } - sym::unstable => { - if stab.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { - span: attr.span(), - }); - break; - } +use super::util::parse_version; +use super::{AcceptMapping, AttributeParser, SingleAttributeParser}; +use crate::context::{AcceptContext, FinalizeContext}; +use crate::parser::{ArgParser, MetaItemParser}; +use crate::session_diagnostics::{self, UnsupportedLiteralReason}; + +macro_rules! reject_outside_std { + ($cx: ident) => { + // Emit errors for non-staged-api crates. + if !$cx.features().staged_api() { + $cx.emit_err(session_diagnostics::StabilityOutsideStd { span: $cx.attr_span }); + return; + } + }; +} - if let Some((feature, level)) = parse_unstability(sess, attr) { - stab = Some((Stability { level, feature }, attr.span())); - } - } - sym::stable => { - if stab.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { - span: attr.span(), - }); - break; - } - if let Some((feature, level)) = parse_stability(sess, attr) { - stab = Some((Stability { level, feature }, attr.span())); - } - } - _ => {} +#[derive(Default)] +pub(crate) struct StabilityParser { + allowed_through_unstable_modules: Option, + stability: Option<(Stability, Span)>, +} + +impl StabilityParser { + /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. + fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + if let Some((_, _)) = self.stability { + cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); + true + } else { + false } } +} - if let Some(allowed_through_unstable_modules) = allowed_through_unstable_modules { - match &mut stab { - Some(( +impl AttributeParser for StabilityParser { + const ATTRIBUTES: AcceptMapping = &[ + (&[sym::stable], |this, cx, args| { + reject_outside_std!(cx); + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_stability(cx, args) + { + this.stability = Some((Stability { level, feature }, cx.attr_span)); + } + }), + (&[sym::unstable], |this, cx, args| { + reject_outside_std!(cx); + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_unstability(cx, args) + { + this.stability = Some((Stability { level, feature }, cx.attr_span)); + } + }), + (&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| { + reject_outside_std!(cx); + this.allowed_through_unstable_modules = + Some(match args.name_value().and_then(|i| i.value_as_str()) { + Some(msg) => msg, + None => kw::Empty, + }); + }), + ]; + + fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option { + if let Some(atum) = self.allowed_through_unstable_modules { + if let Some(( Stability { - level: StabilityLevel::Stable { allowed_through_unstable_modules: in_stab, .. }, + level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. }, .. }, _, - )) => *in_stab = Some(allowed_through_unstable_modules), - _ => { - sess.dcx() - .emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp }); + )) = self.stability + { + *allowed_through_unstable_modules = Some(atum); + } else { + cx.dcx().emit_err(session_diagnostics::RustcAllowedUnstablePairing { + span: cx.target_span, + }); } } - } - stab + let (stability, span) = self.stability?; + + Some(AttributeKind::Stability { stability, span }) + } } -/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable` -/// attributes in `attrs`. Returns `None` if no stability attributes are found. -pub fn find_const_stability( - sess: &Session, - attrs: &[impl AttributeExt], - item_sp: Span, -) -> Option<(ConstStability, Span)> { - let mut const_stab: Option<(ConstStability, Span)> = None; - let mut promotable = false; - let mut const_stable_indirect = false; - - for attr in attrs { - match attr.name_or_empty() { - sym::rustc_promotable => promotable = true, - sym::rustc_const_stable_indirect => const_stable_indirect = true, - sym::rustc_const_unstable => { - if const_stab.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { - span: attr.span(), - }); - break; - } +// FIXME(jdonszelmann) change to Single +#[derive(Default)] +pub(crate) struct BodyStabilityParser { + stability: Option<(DefaultBodyStability, Span)>, +} - if let Some((feature, level)) = parse_unstability(sess, attr) { - const_stab = Some(( - ConstStability { - level, - feature, - const_stable_indirect: false, - promotable: false, - }, - attr.span(), - )); - } +impl AttributeParser for BodyStabilityParser { + const ATTRIBUTES: AcceptMapping = + &[(&[sym::rustc_default_body_unstable], |this, cx, args| { + reject_outside_std!(cx); + if this.stability.is_some() { + cx.dcx() + .emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); + } else if let Some((feature, level)) = parse_unstability(cx, args) { + this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span)); } - sym::rustc_const_stable => { - if const_stab.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels { - span: attr.span(), - }); - break; - } - if let Some((feature, level)) = parse_stability(sess, attr) { - const_stab = Some(( - ConstStability { - level, - feature, - const_stable_indirect: false, - promotable: false, - }, - attr.span(), - )); - } - } - _ => {} - } - } + })]; - // Merge promotable and const_stable_indirect into stability info - if promotable { - match &mut const_stab { - Some((stab, _)) => stab.promotable = promotable, - _ => { - _ = sess - .dcx() - .emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }) - } - } + fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + let (stability, span) = self.stability?; + + Some(AttributeKind::BodyStability { stability, span }) } - if const_stable_indirect { - match &mut const_stab { - Some((stab, _)) => { - if stab.is_const_unstable() { - stab.const_stable_indirect = true; - } else { - _ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing { - span: item_sp, - }) - } - } - _ => { - // This function has no const stability attribute, but has `const_stable_indirect`. - // We ignore that; unmarked functions are subject to recursive const stability - // checks by default so we do carry out the user's intent. - } - } +} + +pub(crate) struct ConstStabilityIndirectParser; +// FIXME(jdonszelmann): single word attribute group when we have these +impl SingleAttributeParser for ConstStabilityIndirectParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; + + // ignore + fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {} + + fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option { + Some(AttributeKind::ConstStabilityIndirect) } +} - const_stab +#[derive(Default)] +pub(crate) struct ConstStabilityParser { + promotable: bool, + stability: Option<(PartialConstStability, Span)>, } -/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate -/// without the `staged_api` feature. -pub fn unmarked_crate_const_stab( - _sess: &Session, - attrs: &[impl AttributeExt], - regular_stab: Stability, -) -> ConstStability { - assert!(regular_stab.level.is_unstable()); - // The only attribute that matters here is `rustc_const_stable_indirect`. - // We enforce recursive const stability rules for those functions. - let const_stable_indirect = - attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect); - ConstStability { - feature: regular_stab.feature, - const_stable_indirect, - promotable: false, - level: regular_stab.level, +impl ConstStabilityParser { + /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. + fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + if let Some((_, _)) = self.stability { + cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); + true + } else { + false + } } } -/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`. -/// Returns `None` if no stability attributes are found. -pub fn find_body_stability( - sess: &Session, - attrs: &[impl AttributeExt], -) -> Option<(DefaultBodyStability, Span)> { - let mut body_stab: Option<(DefaultBodyStability, Span)> = None; - - for attr in attrs { - if attr.has_name(sym::rustc_default_body_unstable) { - if body_stab.is_some() { - sess.dcx() - .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span() }); - break; +impl AttributeParser for ConstStabilityParser { + const ATTRIBUTES: AcceptMapping = &[ + (&[sym::rustc_const_stable], |this, cx, args| { + reject_outside_std!(cx); + + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_stability(cx, args) + { + this.stability = Some(( + PartialConstStability { level, feature, promotable: false }, + cx.attr_span, + )); } - - if let Some((feature, level)) = parse_unstability(sess, attr) { - body_stab = Some((DefaultBodyStability { level, feature }, attr.span())); + }), + (&[sym::rustc_const_unstable], |this, cx, args| { + reject_outside_std!(cx); + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_unstability(cx, args) + { + this.stability = Some(( + PartialConstStability { level, feature, promotable: false }, + cx.attr_span, + )); + } + }), + (&[sym::rustc_promotable], |this, cx, _| { + reject_outside_std!(cx); + this.promotable = true; + }), + ]; + + fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option { + if self.promotable { + if let Some((ref mut stab, _)) = self.stability { + stab.promotable = true; + } else { + cx.dcx() + .emit_err(session_diagnostics::RustcPromotablePairing { span: cx.target_span }); } } - } - body_stab + let (stability, span) = self.stability?; + + Some(AttributeKind::ConstStability { stability, span }) + } } -fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option) -> Option<()> { +/// Tries to insert the value of a `key = value` meta item into an option. +/// +/// Emits an error when either the option was already Some, or the arguments weren't of form +/// `name = value` +fn insert_value_into_option_or_error( + cx: &AcceptContext<'_>, + param: &MetaItemParser<'_>, + item: &mut Option, +) -> Option<()> { if item.is_some() { - sess.dcx().emit_err(session_diagnostics::MultipleItem { - span: meta.span, - item: pprust::path_to_string(&meta.path), + cx.emit_err(session_diagnostics::MultipleItem { + span: param.span(), + item: param.path_without_args().to_string(), }); None - } else if let Some(v) = meta.value_str() { - *item = Some(v); + } else if let Some(v) = param.args().name_value() + && let Some(s) = v.value_as_str() + { + *item = Some(s); Some(()) } else { - sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span }); + cx.emit_err(session_diagnostics::IncorrectMetaItem { + span: param.span(), + suggestion: None, + }); None } } /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and /// its stability information. -fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> { - let metas = attr.meta_item_list()?; - +pub(crate) fn parse_stability( + cx: &AcceptContext<'_>, + args: &ArgParser<'_>, +) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut since = None; - for meta in metas { - let Some(mi) = meta.meta_item() else { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: meta.span(), + + for param in args.list()?.mixed() { + let param_span = param.span(); + let Some(param) = param.meta_item() else { + cx.emit_err(session_diagnostics::UnsupportedLiteral { + span: param_span, reason: UnsupportedLiteralReason::Generic, is_bytestr: false, - start_point_span: sess.source_map().start_point(meta.span()), + start_point_span: cx.sess().source_map().start_point(param_span), }); return None; }; - match mi.name_or_empty() { - sym::feature => insert_or_error(sess, mi, &mut feature)?, - sym::since => insert_or_error(sess, mi, &mut since)?, + match param.word_or_empty_without_args().name { + sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, + sym::since => insert_value_into_option_or_error(cx, ¶m, &mut since)?, _ => { - sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { - span: meta.span(), - item: pprust::path_to_string(&mi.path), + cx.emit_err(session_diagnostics::UnknownMetaItem { + span: param_span, + item: param.path_without_args().to_string(), expected: &["feature", "since"], }); return None; @@ -271,9 +263,9 @@ fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, let feature = match feature { Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(_bad_feature) => { - Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() })) + Err(cx.emit_err(session_diagnostics::NonIdentFeature { span: cx.attr_span })) } - None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })), + None => Err(cx.emit_err(session_diagnostics::MissingFeature { span: cx.attr_span })), }; let since = if let Some(since) = since { @@ -282,11 +274,11 @@ fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, } else if let Some(version) = parse_version(since) { StableSince::Version(version) } else { - sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() }); + cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); StableSince::Err } } else { - sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() }); + cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span }); StableSince::Err }; @@ -299,46 +291,48 @@ fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, } } -/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` +// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` /// attribute, and return the feature name and its stability information. -fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> { - let metas = attr.meta_item_list()?; - +pub(crate) fn parse_unstability( + cx: &AcceptContext<'_>, + args: &ArgParser<'_>, +) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; let mut reason = None; let mut issue = None; let mut issue_num = None; let mut is_soft = false; let mut implied_by = None; - for meta in metas { - let Some(mi) = meta.meta_item() else { - sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral { - span: meta.span(), + for param in args.list()?.mixed() { + let Some(param) = param.meta_item() else { + cx.emit_err(session_diagnostics::UnsupportedLiteral { + span: param.span(), reason: UnsupportedLiteralReason::Generic, is_bytestr: false, - start_point_span: sess.source_map().start_point(meta.span()), + start_point_span: cx.sess().source_map().start_point(param.span()), }); return None; }; - match mi.name_or_empty() { - sym::feature => insert_or_error(sess, mi, &mut feature)?, - sym::reason => insert_or_error(sess, mi, &mut reason)?, + let (word, args) = param.word_or_empty(); + match word.name { + sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, + sym::reason => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, sym::issue => { - insert_or_error(sess, mi, &mut issue)?; + insert_value_into_option_or_error(cx, ¶m, &mut issue)?; - // These unwraps are safe because `insert_or_error` ensures the meta item + // These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item // is a name/value pair string literal. issue_num = match issue.unwrap().as_str() { "none" => None, - issue => match issue.parse::>() { + issue_str => match issue_str.parse::>() { Ok(num) => Some(num), Err(err) => { - sess.dcx().emit_err( + cx.emit_err( session_diagnostics::InvalidIssueString { - span: mi.span, + span: param.span(), cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( - mi.name_value_literal_span().unwrap(), + args.name_value().unwrap().value_span, err.kind(), ), }, @@ -349,16 +343,16 @@ fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol }; } sym::soft => { - if !mi.is_word() { - sess.dcx().emit_err(session_diagnostics::SoftNoArgs { span: mi.span }); + if !args.no_args() { + cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() }); } is_soft = true; } - sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?, + sym::implied_by => insert_value_into_option_or_error(cx, ¶m, &mut implied_by)?, _ => { - sess.dcx().emit_err(session_diagnostics::UnknownMetaItem { - span: meta.span(), - item: pprust::path_to_string(&mi.path), + cx.emit_err(session_diagnostics::UnknownMetaItem { + span: param.span(), + item: param.path_without_args().to_string(), expected: &["feature", "reason", "issue", "soft", "implied_by"], }); return None; @@ -369,14 +363,13 @@ fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol let feature = match feature { Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature), Some(_bad_feature) => { - Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() })) + Err(cx.emit_err(session_diagnostics::NonIdentFeature { span: cx.attr_span })) } - None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })), + None => Err(cx.emit_err(session_diagnostics::MissingFeature { span: cx.attr_span })), }; - let issue = issue.ok_or_else(|| { - sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span() }) - }); + let issue = + issue.ok_or_else(|| cx.emit_err(session_diagnostics::MissingIssue { span: cx.attr_span })); match (feature, issue) { (Ok(feature), Ok(_)) => { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index f4065a7704841..ad83a1f7af80c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,36 +1,33 @@ -use rustc_ast::attr::AttributeExt; -use rustc_attr_data_structures::TransparencyError; +use rustc_attr_data_structures::AttributeKind; use rustc_span::hygiene::Transparency; use rustc_span::sym; -pub fn find_transparency( - attrs: &[impl AttributeExt], - macro_rules: bool, -) -> (Transparency, Option) { - let mut transparency = None; - let mut error = None; - for attr in attrs { - if attr.has_name(sym::rustc_macro_transparency) { - if let Some((_, old_span)) = transparency { - error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span())); - break; - } else if let Some(value) = attr.value_str() { - transparency = Some(( - match value { - sym::transparent => Transparency::Transparent, - sym::semitransparent => Transparency::SemiTransparent, - sym::opaque => Transparency::Opaque, - _ => { - error = - Some(TransparencyError::UnknownTransparency(value, attr.span())); - continue; - } - }, - attr.span(), - )); +use super::{AcceptContext, SingleAttributeParser}; +use crate::parser::ArgParser; + +pub(crate) struct TransparencyParser; + +// FIXME(jdonszelmann): make these proper diagnostics +#[allow(rustc::untranslatable_diagnostic)] +#[allow(rustc::diagnostic_outside_of_impl)] +impl SingleAttributeParser for TransparencyParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; + + fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: rustc_span::Span) { + cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes"); + } + + fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + match args.name_value().and_then(|nv| nv.value_as_str()) { + Some(sym::transparent) => Some(Transparency::Transparent), + Some(sym::semitransparent) => Some(Transparency::SemiTransparent), + Some(sym::opaque) => Some(Transparency::Opaque), + Some(other) => { + cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`")); + None } + None => None, } + .map(AttributeKind::MacroTransparency) } - let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }; - (transparency.map_or(fallback, |t| t.0), error) } diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index e36f7dfff5a5f..05a9029c59aa5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -3,22 +3,6 @@ use rustc_attr_data_structures::RustcVersion; use rustc_feature::is_builtin_attr_name; use rustc_span::{Symbol, sym}; -pub(crate) enum UnsupportedLiteralReason { - Generic, - CfgString, - CfgBoolean, - DeprecatedString, - DeprecatedKvPair, -} - -pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { - attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) -} - -pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option { - first_attr_value_str_by_name(attrs, sym::crate_name) -} - /// Parse a rustc version number written inside string literal in an attribute, /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are /// not accepted in this position, unlike when parsing CFG_RELEASE. @@ -34,3 +18,11 @@ pub fn parse_version(s: Symbol) -> Option { let patch = digits.next().unwrap_or("0").parse().ok()?; Some(RustcVersion { major, minor, patch }) } + +pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool { + attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name)) +} + +pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option { + first_attr_value_str_by_name(attrs, sym::crate_name) +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs new file mode 100644 index 0000000000000..35541bb04bd7b --- /dev/null +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -0,0 +1,350 @@ +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::ops::Deref; +use std::sync::LazyLock; + +use rustc_ast::{self as ast, DelimArgs}; +use rustc_attr_data_structures::AttributeKind; +use rustc_errors::{DiagCtxtHandle, Diagnostic}; +use rustc_feature::Features; +use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId}; +use rustc_session::Session; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; + +use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; +use crate::attributes::confusables::ConfusablesParser; +use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::repr::ReprParser; +use crate::attributes::stability::{ + BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, +}; +use crate::attributes::transparency::TransparencyParser; +use crate::attributes::{AttributeParser as _, Combine, Single}; +use crate::parser::{ArgParser, MetaItemParser}; + +macro_rules! attribute_groups { + ( + pub(crate) static $name: ident = [$($names: ty),* $(,)?]; + ) => { + pub(crate) static $name: LazyLock<( + BTreeMap<&'static [Symbol], Vec, &ArgParser<'_>) + Send + Sync>>>, + Vec) -> Option>> + )> = LazyLock::new(|| { + let mut accepts = BTreeMap::<_, Vec, &ArgParser<'_>) + Send + Sync>>>::new(); + let mut finalizes = Vec::) -> Option>>::new(); + $( + { + thread_local! { + static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default()); + }; + + for (k, v) in <$names>::ATTRIBUTES { + accepts.entry(*k).or_default().push(Box::new(|cx, args| { + STATE_OBJECT.with_borrow_mut(|s| { + v(s, cx, args) + }) + })); + } + + finalizes.push(Box::new(|cx| { + let state = STATE_OBJECT.take(); + state.finalize(cx) + })); + } + )* + + (accepts, finalizes) + }); + }; +} + +attribute_groups!( + pub(crate) static ATTRIBUTE_MAPPING = [ + // tidy-alphabetical-start + BodyStabilityParser, + ConfusablesParser, + ConstStabilityParser, + StabilityParser, + // tidy-alphabetical-end + + // tidy-alphabetical-start + Combine, + Combine, + Combine, + // tidy-alphabetical-end + + // tidy-alphabetical-start + Single, + Single, + Single, + // tidy-alphabetical-end + ]; +); + +/// Context given to every attribute parser when accepting +/// +/// Gives [`AttributeParser`]s enough information to create errors, for example. +pub(crate) struct AcceptContext<'a> { + pub(crate) group_cx: &'a FinalizeContext<'a>, + /// The span of the attribute currently being parsed + pub(crate) attr_span: Span, +} + +impl<'a> AcceptContext<'a> { + pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed { + if self.limit_diagnostics { + self.dcx().create_err(diag).delay_as_bug() + } else { + self.dcx().emit_err(diag) + } + } +} + +impl<'a> Deref for AcceptContext<'a> { + type Target = FinalizeContext<'a>; + + fn deref(&self) -> &Self::Target { + &self.group_cx + } +} + +/// Context given to every attribute parser during finalization. +/// +/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create errors, for example. +pub(crate) struct FinalizeContext<'a> { + /// The parse context, gives access to the session and the + /// diagnostics context. + pub(crate) cx: &'a AttributeParser<'a>, + /// The span of the syntactical component this attribute was applied to + pub(crate) target_span: Span, +} + +impl<'a> Deref for FinalizeContext<'a> { + type Target = AttributeParser<'a>; + + fn deref(&self) -> &Self::Target { + &self.cx + } +} + +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum OmitDoc { + Lower, + Skip, +} + +/// Context created once, for example as part of the ast lowering +/// context, through which all attributes can be lowered. +pub struct AttributeParser<'sess> { + #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes + tools: Vec, + sess: &'sess Session, + features: Option<&'sess Features>, + + /// *only* parse attributes with this symbol. + /// + /// Used in cases where we want the lowering infrastructure for + /// parse just a single attribute. + parse_only: Option, + + /// Can be used to instruct parsers to reduce the number of diagnostics it emits. + /// Useful when using `parse_limited` and you know the attr will be reparsed later. + pub(crate) limit_diagnostics: bool, +} + +impl<'sess> AttributeParser<'sess> { + /// This method allows you to parse attributes *before* you have access to features or tools. + /// One example where this is necessary, is to parse `feature` attributes themselves for + /// example. + /// + /// Try to use this as little as possible. Attributes *should* be lowered during `rustc_ast_lowering`. + /// Some attributes require access to features to parse, which would crash if you tried to do so + /// through [`parse_limited`](Self::parse_limited). + /// + /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with + /// that symbol are picked out of the list of instructions and parsed. Those are returned. + pub fn parse_limited( + sess: &'sess Session, + attrs: &[ast::Attribute], + sym: Symbol, + target_span: Span, + limit_diagnostics: bool, + ) -> Option { + let mut parsed = Self { + sess, + features: None, + tools: Vec::new(), + parse_only: Some(sym), + limit_diagnostics, + } + .parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity); + + assert!(parsed.len() <= 1); + + parsed.pop() + } + + pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { + Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false } + } + + pub(crate) fn sess(&self) -> &'sess Session { + self.sess + } + + pub(crate) fn features(&self) -> &'sess Features { + self.features.expect("features not available at this point in the compiler") + } + + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { + self.sess.dcx() + } + + /// Parse a list of attributes. + /// + /// `target_span` is the span of the thing this list of attributes is applied to, + /// and when `omit_doc` is set, doc attributes are filtered out. + pub fn parse_attribute_list<'a>( + &'a self, + attrs: &'a [ast::Attribute], + target_span: Span, + omit_doc: OmitDoc, + + lower_span: impl Copy + Fn(Span) -> Span, + ) -> Vec { + let mut attributes = Vec::new(); + + let group_cx = FinalizeContext { cx: self, target_span }; + + for attr in attrs { + // if we're only looking for a single attribute, + // skip all the ones we don't care about + if let Some(expected) = self.parse_only { + if attr.name_or_empty() != expected { + continue; + } + } + + // sometimes, for example for `#![doc = include_str!("readme.md")]`, + // doc still contains a non-literal. You might say, when we're lowering attributes + // that's expanded right? But no, sometimes, when parsing attributes on macros, + // we already use the lowering logic and these are still there. So, when `omit_doc` + // is set we *also* want to ignore these + if omit_doc == OmitDoc::Skip && attr.name_or_empty() == sym::doc { + continue; + } + + match &attr.kind { + ast::AttrKind::DocComment(comment_kind, symbol) => { + if omit_doc == OmitDoc::Skip { + continue; + } + + attributes.push(Attribute::Parsed(AttributeKind::DocComment { + style: attr.style, + kind: *comment_kind, + span: lower_span(attr.span), + comment: *symbol, + })) + } + // // FIXME: make doc attributes go through a proper attribute parser + // ast::AttrKind::Normal(n) if n.name_or_empty() == sym::doc => { + // let p = GenericMetaItemParser::from_attr(&n, self.dcx()); + // + // attributes.push(Attribute::Parsed(AttributeKind::DocComment { + // style: attr.style, + // kind: CommentKind::Line, + // span: attr.span, + // comment: p.args().name_value(), + // })) + // } + ast::AttrKind::Normal(n) => { + let parser = MetaItemParser::from_attr(n, self.dcx()); + let (path, args) = parser.deconstruct(); + let parts = path.segments().map(|i| i.name).collect::>(); + + if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { + for f in accepts { + let cx = AcceptContext { + group_cx: &group_cx, + attr_span: lower_span(attr.span), + }; + + f(&cx, &args) + } + } else { + // if we're here, we must be compiling a tool attribute... Or someone forgot to + // parse their fancy new attribute. Let's warn them in any case. If you are that + // person, and you really your attribute should remain unparsed, carefully read the + // documentation in this module and if you still think so you can add an exception + // to this assertion. + + // FIXME(jdonszelmann): convert other attributes, and check with this that + // we caught em all + // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg]; + // assert!( + // self.tools.contains(&parts[0]) || true, + // // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]), + // "attribute {path} wasn't parsed and isn't a know tool attribute", + // ); + + attributes.push(Attribute::Unparsed(Box::new(AttrItem { + path: AttrPath::from_ast(&n.item.path), + args: self.lower_attr_args(&n.item.args, lower_span), + id: HashIgnoredAttrId { attr_id: attr.id }, + style: attr.style, + span: lower_span(attr.span), + }))); + } + } + } + } + + let mut parsed_attributes = Vec::new(); + for f in &ATTRIBUTE_MAPPING.1 { + if let Some(attr) = f(&group_cx) { + parsed_attributes.push(Attribute::Parsed(attr)); + } + } + + attributes.extend(parsed_attributes); + + attributes + } + + fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { + match args { + ast::AttrArgs::Empty => AttrArgs::Empty, + ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs { + dspan: args.dspan, + delim: args.delim, + tokens: args.tokens.flattened(), + }), + // This is an inert key-value attribute - it will never be visible to macros + // after it gets lowered to HIR. Therefore, we can extract literals to handle + // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). + ast::AttrArgs::Eq { eq_span, expr } => { + // In valid code the value always ends up as a single literal. Otherwise, a dummy + // literal suffices because the error is handled elsewhere. + let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind + && let Ok(lit) = + ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span)) + { + lit + } else { + let guar = self.dcx().span_delayed_bug( + args.span().unwrap_or(DUMMY_SP), + "expr in place where literal is expected (builtin attr parsing)", + ); + ast::MetaItemLit { + symbol: sym::dummy, + suffix: None, + kind: ast::LitKind::Err(guar), + span: DUMMY_SP, + } + }; + AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit } + } + } + } +} diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index a1264a6875f69..a7465847e18bf 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -1,22 +1,97 @@ -//! Functions and types dealing with attributes and meta items. +//! Centralized logic for parsing and attributes. //! -//! FIXME(Centril): For now being, much of the logic is still in `rustc_ast::attr`. -//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` -//! to this crate. +//! Part of a series of crates: +//! - rustc_attr_data_structures: contains types that the parsers parse into +//! - rustc_attr_parsing: this crate +//! - (in the future): rustc_attr_validation +//! +//! History: Check out [#131229](https://github.com/rust-lang/rust/issues/131229). +//! There used to be only one definition of attributes in the compiler: `ast::Attribute`. +//! These were then parsed or validated or both in places distributed all over the compiler. +//! This was a mess... +//! +//! Attributes are markers on items. +//! Many of them are actually attribute-like proc-macros, and are expanded to some other rust syntax. +//! This could either be a user provided proc macro, or something compiler provided. +//! `derive` is an example of one that the compiler provides. +//! These are built-in, but they have a valid expansion to Rust tokens and are thus called "active". +//! I personally like calling these *active* compiler-provided attributes, built-in *macros*, +//! because they still expand, and this helps to differentiate them from built-in *attributes*. +//! However, I'll be the first to admit that the naming here can be confusing. +//! +//! The alternative to active attributes, are inert attributes. +//! These can occur in user code (proc-macro helper attributes). +//! But what's important is, many built-in attributes are inert like this. +//! There is nothing they expand to during the macro expansion process, +//! sometimes because they literally cannot expand to something that is valid Rust. +//! They are really just markers to guide the compilation process. +//! An example is `#[inline(...)]` which changes how code for functions is generated. +//! +//! ```text +//! Active Inert +//! ┌──────────────────────┬──────────────────────┐ +//! │ (mostly in) │ these are parsed │ +//! │ rustc_builtin_macros │ here! │ +//! │ │ │ +//! │ │ │ +//! │ #[derive(...)] │ #[stable()] │ +//! Built-in │ #[cfg()] │ #[inline()] │ +//! │ #[cfg_attr()] │ #[repr()] │ +//! │ │ │ +//! │ │ │ +//! │ │ │ +//! ├──────────────────────┼──────────────────────┤ +//! │ │ │ +//! │ │ │ +//! │ │ `b` in │ +//! │ │ #[proc_macro_derive( │ +//! User created │ #[proc_macro_attr()] │ a, │ +//! │ │ attributes(b) │ +//! │ │ ] │ +//! │ │ │ +//! │ │ │ +//! │ │ │ +//! └──────────────────────┴──────────────────────┘ +//! ``` +//! +//! In this crate, syntactical attributes (sequences of tokens that look like +//! `#[something(something else)]`) are parsed into more semantic attributes, markers on items. +//! Multiple syntactic attributes might influence a single semantic attribute. For example, +//! `#[stable(...)]` and `#[unstable()]` cannot occur together, and both semantically define +//! a "stability" of an item. So, the stability attribute has an +//! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]` +//! and `#[unstable()]` syntactic attributes, and at the end produce a single [`AttributeKind::Stability`]. +//! +//! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be +//! combined into a single semantic attribute. For example: +//! +//! ``` +//! #[repr(C)] +//! #[repr(packed)] +//! struct Meow {} +//! ``` +//! +//! should result in a single `AttributeKind::Repr` containing a list of repr annotations, in this +//! case `C` and `packed`. This is equivalent to writing `#[repr(C, packed)]` in a single +//! syntactical annotation. // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end +#[macro_use] mod attributes; +mod context; +pub mod parser; mod session_diagnostics; -pub use attributes::*; +pub use attributes::cfg::*; +pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version}; +pub use context::{AttributeParser, OmitDoc}; pub use rustc_attr_data_structures::*; -pub use util::{find_crate_name, is_builtin_attr, parse_version}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs new file mode 100644 index 0000000000000..a8a1460591cf3 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -0,0 +1,616 @@ +//! This is in essence an (improved) duplicate of `rustc_ast/attr/mod.rs`. +//! That module is intended to be deleted in its entirety. +//! +//! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs` + +use std::fmt::{Debug, Display}; +use std::iter::Peekable; + +use rustc_ast::token::{self, Delimiter, Token}; +use rustc_ast::tokenstream::{TokenStreamIter, TokenTree}; +use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; +use rustc_ast_pretty::pprust; +use rustc_errors::DiagCtxtHandle; +use rustc_hir::{self as hir, AttrPath}; +use rustc_span::symbol::{Ident, kw, sym}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; + +pub struct SegmentIterator<'a> { + offset: usize, + path: &'a PathParser<'a>, +} + +impl<'a> Iterator for SegmentIterator<'a> { + type Item = &'a Ident; + + fn next(&mut self) -> Option { + if self.offset >= self.path.len() { + return None; + } + + let res = match self.path { + PathParser::Ast(ast_path) => &ast_path.segments[self.offset].ident, + PathParser::Attr(attr_path) => &attr_path.segments[self.offset], + }; + + self.offset += 1; + Some(res) + } +} + +#[derive(Clone, Debug)] +pub enum PathParser<'a> { + Ast(&'a Path), + Attr(AttrPath), +} + +impl<'a> PathParser<'a> { + pub fn get_attribute_path(&self) -> hir::AttrPath { + AttrPath { + segments: self.segments().copied().collect::>().into_boxed_slice(), + span: self.span(), + } + } + + pub fn segments(&'a self) -> impl Iterator { + SegmentIterator { offset: 0, path: self } + } + + pub fn span(&self) -> Span { + match self { + PathParser::Ast(path) => path.span, + PathParser::Attr(attr_path) => attr_path.span, + } + } + + pub fn len(&self) -> usize { + match self { + PathParser::Ast(path) => path.segments.len(), + PathParser::Attr(attr_path) => attr_path.segments.len(), + } + } + + pub fn segments_is(&self, segments: &[Symbol]) -> bool { + self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b) + } + + pub fn word(&self) -> Option { + (self.len() == 1).then(|| **self.segments().next().as_ref().unwrap()) + } + + pub fn word_or_empty(&self) -> Ident { + self.word().unwrap_or_else(Ident::empty) + } + + /// Asserts that this MetaItem is some specific word. + /// + /// See [`word`](Self::word) for examples of what a word is. + pub fn word_is(&self, sym: Symbol) -> bool { + self.word().map(|i| i.name == sym).unwrap_or(false) + } +} + +impl Display for PathParser<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PathParser::Ast(path) => write!(f, "{}", pprust::path_to_string(path)), + PathParser::Attr(attr_path) => write!(f, "{attr_path}"), + } + } +} + +#[derive(Clone, Debug)] +#[must_use] +pub enum ArgParser<'a> { + NoArgs, + List(MetaItemListParser<'a>), + NameValue(NameValueParser), +} + +impl<'a> ArgParser<'a> { + pub fn span(&self) -> Option { + match self { + Self::NoArgs => None, + Self::List(l) => Some(l.span), + Self::NameValue(n) => Some(n.value_span.with_lo(n.eq_span.lo())), + } + } + + pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self { + match value { + AttrArgs::Empty => Self::NoArgs, + AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { + Self::List(MetaItemListParser::new(args, dcx)) + } + AttrArgs::Delimited(args) => { + Self::List(MetaItemListParser { sub_parsers: vec![], span: args.dspan.entire() }) + } + AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser { + eq_span: *eq_span, + value: expr_to_lit(dcx, &expr, *eq_span), + value_span: expr.span, + }), + } + } + + /// Asserts that this MetaItem is a list + /// + /// Some examples: + /// + /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list + /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list + pub fn list(&self) -> Option<&MetaItemListParser<'a>> { + match self { + Self::List(l) => Some(l), + Self::NameValue(_) | Self::NoArgs => None, + } + } + + /// Asserts that this MetaItem is a name-value pair. + /// + /// Some examples: + /// + /// - `#[clippy::cyclomatic_complexity = "100"]`: `clippy::cyclomatic_complexity = "100"` is a name value pair, + /// where the name is a path (`clippy::cyclomatic_complexity`). You already checked the path + /// to get an `ArgParser`, so this method will effectively only assert that the `= "100"` is + /// there + /// - `#[doc = "hello"]`: `doc = "hello` is also a name value pair + pub fn name_value(&self) -> Option<&NameValueParser> { + match self { + Self::NameValue(n) => Some(n), + Self::List(_) | Self::NoArgs => None, + } + } + + /// Asserts that there are no arguments + pub fn no_args(&self) -> bool { + matches!(self, Self::NoArgs) + } +} + +/// Inside lists, values could be either literals, or more deeply nested meta items. +/// This enum represents that. +/// +/// Choose which one you want using the provided methods. +#[derive(Debug, Clone)] +pub enum MetaItemOrLitParser<'a> { + MetaItemParser(MetaItemParser<'a>), + Lit(MetaItemLit), + Err(Span, ErrorGuaranteed), +} + +impl<'a> MetaItemOrLitParser<'a> { + pub fn span(&self) -> Span { + match self { + MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => { + generic_meta_item_parser.span() + } + MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span, + MetaItemOrLitParser::Err(span, _) => *span, + } + } + + pub fn lit(&self) -> Option<&MetaItemLit> { + match self { + MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit), + _ => None, + } + } + + pub fn meta_item(&self) -> Option<&MetaItemParser<'a>> { + match self { + MetaItemOrLitParser::MetaItemParser(parser) => Some(parser), + _ => None, + } + } +} + +/// Utility that deconstructs a MetaItem into usable parts. +/// +/// MetaItems are syntactically extremely flexible, but specific attributes want to parse +/// them in custom, more restricted ways. This can be done using this struct. +/// +/// MetaItems consist of some path, and some args. The args could be empty. In other words: +/// +/// - `name` -> args are empty +/// - `name(...)` -> args are a [`list`](ArgParser::list), which is the bit between the parentheses +/// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the +/// `= value` part +/// +/// The syntax of MetaItems can be found at +#[derive(Clone)] +pub struct MetaItemParser<'a> { + path: PathParser<'a>, + args: ArgParser<'a>, +} + +impl<'a> Debug for MetaItemParser<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("MetaItemParser") + .field("path", &self.path) + .field("args", &self.args) + .finish() + } +} + +impl<'a> MetaItemParser<'a> { + /// Create a new parser from a [`NormalAttr`], which is stored inside of any + /// [`ast::Attribute`](rustc_ast::Attribute) + pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self { + Self { + path: PathParser::Ast(&attr.item.path), + args: ArgParser::from_attr_args(&attr.item.args, dcx), + } + } +} + +impl<'a> MetaItemParser<'a> { + pub fn span(&self) -> Span { + if let Some(other) = self.args.span() { + self.path.span().with_hi(other.hi()) + } else { + self.path.span() + } + } + + /// Gets just the path, without the args. + pub fn path_without_args(&self) -> PathParser<'a> { + self.path.clone() + } + + /// Gets just the args parser, without caring about the path. + pub fn args(&self) -> &ArgParser<'a> { + &self.args + } + + pub fn deconstruct(&self) -> (PathParser<'a>, &ArgParser<'a>) { + (self.path_without_args(), self.args()) + } + + /// Asserts that this MetaItem starts with a path. Some examples: + /// + /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path + /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path + /// - `#[inline]`: `inline` is a single segment path + pub fn path(&self) -> (PathParser<'a>, &ArgParser<'a>) { + self.deconstruct() + } + + /// Asserts that this MetaItem starts with a word, or single segment path. + /// Doesn't return the args parser. + /// + /// For examples. see [`Self::word`] + pub fn word_without_args(&self) -> Option { + Some(self.word()?.0) + } + + /// Like [`word`](Self::word), but returns an empty symbol instead of None + pub fn word_or_empty_without_args(&self) -> Ident { + self.word_or_empty().0 + } + + /// Asserts that this MetaItem starts with a word, or single segment path. + /// + /// Some examples: + /// - `#[inline]`: `inline` is a word + /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path, + /// and not a word and should instead be parsed using [`path`](Self::path) + pub fn word(&self) -> Option<(Ident, &ArgParser<'a>)> { + let (path, args) = self.deconstruct(); + Some((path.word()?, args)) + } + + /// Like [`word`](Self::word), but returns an empty symbol instead of None + pub fn word_or_empty(&self) -> (Ident, &ArgParser<'a>) { + let (path, args) = self.deconstruct(); + (path.word().unwrap_or(Ident::empty()), args) + } + + /// Asserts that this MetaItem starts with some specific word. + /// + /// See [`word`](Self::word) for examples of what a word is. + pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> { + self.path_without_args().word_is(sym).then(|| self.args()) + } + + /// Asserts that this MetaItem starts with some specific path. + /// + /// See [`word`](Self::path) for examples of what a word is. + pub fn path_is(&self, segments: &[Symbol]) -> Option<&ArgParser<'a>> { + self.path_without_args().segments_is(segments).then(|| self.args()) + } +} + +#[derive(Clone)] +pub struct NameValueParser { + pub eq_span: Span, + value: MetaItemLit, + pub value_span: Span, +} + +impl Debug for NameValueParser { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("NameValueParser") + .field("eq_span", &self.eq_span) + .field("value", &self.value) + .field("value_span", &self.value_span) + .finish() + } +} + +impl NameValueParser { + pub fn value_as_lit(&self) -> &MetaItemLit { + &self.value + } + + pub fn value_as_str(&self) -> Option { + self.value_as_lit().kind.str() + } +} + +fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit { + // In valid code the value always ends up as a single literal. Otherwise, a dummy + // literal suffices because the error is handled elsewhere. + if let ExprKind::Lit(token_lit) = expr.kind + && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span) + { + lit + } else { + let guar = dcx.span_delayed_bug( + span, + "expr in place where literal is expected (builtin attr parsing)", + ); + MetaItemLit { symbol: sym::dummy, suffix: None, kind: LitKind::Err(guar), span } + } +} + +struct MetaItemListParserContext<'a> { + // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside + inside_delimiters: Peekable>, + dcx: DiagCtxtHandle<'a>, +} + +impl<'a> MetaItemListParserContext<'a> { + fn done(&mut self) -> bool { + self.inside_delimiters.peek().is_none() + } + + fn next_path(&mut self) -> Option { + // FIXME: Share code with `parse_path`. + let tt = self.inside_delimiters.next().map(|tt| TokenTree::uninterpolate(tt)); + + match tt.as_deref()? { + &TokenTree::Token( + Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span }, + _, + ) => { + // here we have either an ident or pathsep `::`. + + let mut segments = if let &token::Ident(name, _) = kind { + // when we lookahead another pathsep, more path's coming + if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = + self.inside_delimiters.peek() + { + self.inside_delimiters.next(); + vec![Ident::new(name, span)] + } else { + // else we have a single identifier path, that's all + return Some(AttrPath { + segments: vec![Ident::new(name, span)].into_boxed_slice(), + span, + }); + } + } else { + // if `::` is all we get, we just got a path root + vec![Ident::new(kw::PathRoot, span)] + }; + + // one segment accepted. accept n more + loop { + // another ident? + if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = + self.inside_delimiters + .next() + .map(|tt| TokenTree::uninterpolate(tt)) + .as_deref() + { + segments.push(Ident::new(name, span)); + } else { + return None; + } + // stop unless we see another `::` + if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = + self.inside_delimiters.peek() + { + self.inside_delimiters.next(); + } else { + break; + } + } + let span = span.with_hi(segments.last().unwrap().span.hi()); + Some(AttrPath { segments: segments.into_boxed_slice(), span }) + } + TokenTree::Token(Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _) => { + None + } + _ => { + // malformed attributes can get here. We can't crash, but somewhere else should've + // already warned for this. + None + } + } + } + + fn value(&mut self) -> Option { + match self.inside_delimiters.next() { + Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => { + MetaItemListParserContext { + inside_delimiters: inner_tokens.iter().peekable(), + dcx: self.dcx, + } + .value() + } + Some(TokenTree::Token(token, _)) => MetaItemLit::from_token(token), + _ => None, + } + } + + /// parses one element on the inside of a list attribute like `#[my_attr( )]` + /// + /// parses a path followed be either: + /// 1. nothing (a word attr) + /// 2. a parenthesized list + /// 3. an equals sign and a literal (name-value) + /// + /// Can also parse *just* a literal. This is for cases like as `#[my_attr("literal")]` + /// where no path is given before the literal + /// + /// Some exceptions too for interpolated attributes which are already pre-processed + fn next(&mut self) -> Option> { + // a list element is either a literal + if let Some(TokenTree::Token(token, _)) = self.inside_delimiters.peek() + && let Some(lit) = MetaItemLit::from_token(token) + { + self.inside_delimiters.next(); + return Some(MetaItemOrLitParser::Lit(lit)); + } else if let Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) = + self.inside_delimiters.peek() + { + self.inside_delimiters.next(); + return MetaItemListParserContext { + inside_delimiters: inner_tokens.iter().peekable(), + dcx: self.dcx, + } + .next(); + } + + // or a path. + let path = + if let Some(TokenTree::Token(Token { kind: token::Interpolated(_), span, .. }, _)) = + self.inside_delimiters.peek() + { + self.inside_delimiters.next(); + // We go into this path if an expr ended up in an attribute that + // expansion did not turn into a literal. Say, `#[repr(align(macro!()))]` + // where the macro didn't expand to a literal. An error is already given + // for this at this point, and then we do continue. This makes this path + // reachable... + let e = self.dcx.span_delayed_bug( + *span, + "expr in place where literal is expected (builtin attr parsing)", + ); + + return Some(MetaItemOrLitParser::Err(*span, e)); + } else { + self.next_path()? + }; + + // Paths can be followed by: + // - `(more meta items)` (another list) + // - `= lit` (a name-value) + // - nothing + Some(MetaItemOrLitParser::MetaItemParser(match self.inside_delimiters.peek() { + Some(TokenTree::Delimited(dspan, _, Delimiter::Parenthesis, inner_tokens)) => { + self.inside_delimiters.next(); + + MetaItemParser { + path: PathParser::Attr(path), + args: ArgParser::List(MetaItemListParser::new_tts( + inner_tokens.iter(), + dspan.entire(), + self.dcx, + )), + } + } + Some(TokenTree::Delimited(_, ..)) => { + self.inside_delimiters.next(); + // self.dcx.span_delayed_bug(span.entire(), "wrong delimiters"); + return None; + } + Some(TokenTree::Token(Token { kind: token::Eq, span }, _)) => { + self.inside_delimiters.next(); + let value = self.value()?; + MetaItemParser { + path: PathParser::Attr(path), + args: ArgParser::NameValue(NameValueParser { + eq_span: *span, + value_span: value.span, + value, + }), + } + } + _ => MetaItemParser { path: PathParser::Attr(path), args: ArgParser::NoArgs }, + })) + } + + fn parse(mut self, span: Span) -> MetaItemListParser<'a> { + let mut sub_parsers = Vec::new(); + + while !self.done() { + let Some(n) = self.next() else { + continue; + }; + sub_parsers.push(n); + + match self.inside_delimiters.peek() { + None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => { + self.inside_delimiters.next(); + } + Some(_) => {} + } + } + + MetaItemListParser { sub_parsers, span } + } +} + +#[derive(Debug, Clone)] +pub struct MetaItemListParser<'a> { + sub_parsers: Vec>, + pub span: Span, +} + +impl<'a> MetaItemListParser<'a> { + fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> { + MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx) + } + + fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self { + MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span) + } + + /// Lets you pick and choose as what you want to parse each element in the list + pub fn mixed<'s>(&'s self) -> impl Iterator> + 's { + self.sub_parsers.iter() + } + + pub fn len(&self) -> usize { + self.sub_parsers.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Asserts that every item in the list is another list starting with a word. + /// + /// See [`MetaItemParser::word`] for examples of words. + pub fn all_word_list<'s>(&'s self) -> Option)>> { + self.mixed().map(|i| i.meta_item()?.word()).collect() + } + + /// Asserts that every item in the list is another list starting with a full path. + /// + /// See [`MetaItemParser::path`] for examples of paths. + pub fn all_path_list<'s>(&'s self) -> Option, &'s ArgParser<'a>)>> { + self.mixed().map(|i| Some(i.meta_item()?.path())).collect() + } + + /// Returns Some if the list contains only a single element. + /// + /// Inside the Some is the parser to parse this single element. + pub fn single(&self) -> Option<&MetaItemOrLitParser<'a>> { + let mut iter = self.mixed(); + iter.next().filter(|_| iter.next().is_none()) + } +} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 92bc2a8aeb05e..9d34b807ac2fe 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -6,9 +6,16 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuar use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; -use crate::attributes::util::UnsupportedLiteralReason; use crate::fluent_generated as fluent; +pub(crate) enum UnsupportedLiteralReason { + Generic, + CfgString, + CfgBoolean, + DeprecatedString, + DeprecatedKvPair, +} + #[derive(Diagnostic)] #[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)] pub(crate) struct ExpectedOneCfgPattern { @@ -39,6 +46,21 @@ pub(crate) struct MultipleItem { pub(crate) struct IncorrectMetaItem { #[primary_span] pub span: Span, + + #[subdiagnostic] + pub suggestion: Option, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + attr_parsing_incorrect_meta_item_suggestion, + applicability = "maybe-incorrect" +)] +pub(crate) struct IncorrectMetaItemSuggestion { + #[suggestion_part(code = "\"")] + pub lo: Span, + #[suggestion_part(code = "\"")] + pub hi: Span, } /// Error code: E0541 @@ -337,13 +359,6 @@ pub(crate) struct RustcPromotablePairing { pub span: Span, } -#[derive(Diagnostic)] -#[diag(attr_parsing_rustc_const_stable_indirect_pairing)] -pub(crate) struct RustcConstStableIndirectPairing { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(attr_parsing_rustc_allowed_unstable_pairing, code = E0789)] pub(crate) struct RustcAllowedUnstablePairing { @@ -423,3 +438,44 @@ pub(crate) struct UnknownVersionLiteral { #[primary_span] pub span: Span, } + +// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated. +#[derive(Diagnostic)] +#[diag(attr_parsing_unused_multiple)] +pub(crate) struct UnusedMultiple { + #[primary_span] + #[suggestion(code = "", applicability = "machine-applicable")] + pub this: Span, + #[note] + pub other: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_stability_outside_std, code = E0734)] +pub(crate) struct StabilityOutsideStd { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_empty_confusables)] +pub(crate) struct EmptyConfusables { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_repr_ident, code = E0565)] +pub(crate) struct ReprIdent { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)] +#[help] +pub(crate) struct UnrecognizedReprHint { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_baked_icu_data/Cargo.toml b/compiler/rustc_baked_icu_data/Cargo.toml index c35556dcf5bf2..cb0e145386b83 100644 --- a/compiler/rustc_baked_icu_data/Cargo.toml +++ b/compiler/rustc_baked_icu_data/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_baked_icu_data" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_baked_icu_data/src/lib.rs b/compiler/rustc_baked_icu_data/src/lib.rs index f86a9db61c600..f3f6522f57587 100644 --- a/compiler/rustc_baked_icu_data/src/lib.rs +++ b/compiler/rustc_baked_icu_data/src/lib.rs @@ -23,6 +23,7 @@ // tidy-alphabetical-start #![allow(elided_lifetimes_in_paths)] #![allow(internal_features)] +#![allow(unreachable_pub)] // because this crate is mostly generated code #![doc(rust_logo)] #![feature(rustdoc_internals)] // #![warn(unreachable_pub)] // don't use because this crate is mostly generated code diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 89154bf2c23c4..9e7d55180a233 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_borrowck" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs index 30e94b0bec708..c9be5575da5ce 100644 --- a/compiler/rustc_borrowck/src/borrowck_errors.rs +++ b/compiler/rustc_borrowck/src/borrowck_errors.rs @@ -403,6 +403,7 @@ impl<'infcx, 'tcx> crate::MirBorrowckCtxt<'_, 'infcx, 'tcx> { .expect_closure(); let span = match capture_clause { rustc_hir::CaptureBy::Value { move_kw } => move_kw.shrink_to_lo(), + rustc_hir::CaptureBy::Use { use_kw } => use_kw.shrink_to_lo(), rustc_hir::CaptureBy::Ref => fn_decl_span.shrink_to_lo(), }; diag.span_suggestion_verbose( diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs index 9d500586f084c..1209d8bf5967a 100644 --- a/compiler/rustc_borrowck/src/constraints/graph.rs +++ b/compiler/rustc_borrowck/src/constraints/graph.rs @@ -1,11 +1,8 @@ use rustc_data_structures::graph; use rustc_index::IndexVec; -use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::{RegionVid, VarianceDiagInfo}; -use rustc_span::DUMMY_SP; +use rustc_middle::ty::RegionVid; use crate::constraints::{OutlivesConstraint, OutlivesConstraintIndex, OutlivesConstraintSet}; -use crate::type_check::Locations; /// The construct graph organizes the constraints by their end-points. /// It can be used to view a `R1: R2` constraint as either an edge `R1 @@ -23,8 +20,8 @@ pub(crate) type ReverseConstraintGraph = ConstraintGraph; /// Marker trait that controls whether a `R1: R2` constraint /// represents an edge `R1 -> R2` or `R2 -> R1`. pub(crate) trait ConstraintGraphDirection: Copy + 'static { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid; - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid; + fn start_region(sup: RegionVid, sub: RegionVid) -> RegionVid; + fn end_region(sup: RegionVid, sub: RegionVid) -> RegionVid; fn is_normal() -> bool; } @@ -36,12 +33,12 @@ pub(crate) trait ConstraintGraphDirection: Copy + 'static { pub(crate) struct Normal; impl ConstraintGraphDirection for Normal { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup + fn start_region(sup: RegionVid, _sub: RegionVid) -> RegionVid { + sup } - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub + fn end_region(_sup: RegionVid, sub: RegionVid) -> RegionVid { + sub } fn is_normal() -> bool { @@ -57,12 +54,12 @@ impl ConstraintGraphDirection for Normal { pub(crate) struct Reverse; impl ConstraintGraphDirection for Reverse { - fn start_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sub + fn start_region(_sup: RegionVid, sub: RegionVid) -> RegionVid { + sub } - fn end_region(c: &OutlivesConstraint<'_>) -> RegionVid { - c.sup + fn end_region(sup: RegionVid, _sub: RegionVid) -> RegionVid { + sup } fn is_normal() -> bool { @@ -84,7 +81,7 @@ impl ConstraintGraph { let mut next_constraints = IndexVec::from_elem(None, &set.outlives); for (idx, constraint) in set.outlives.iter_enumerated().rev() { - let head = &mut first_constraints[D::start_region(constraint)]; + let head = &mut first_constraints[D::start_region(constraint.sup, constraint.sub)]; let next = &mut next_constraints[idx]; debug_assert!(next.is_none()); *next = *head; @@ -105,63 +102,57 @@ impl ConstraintGraph { RegionGraph::new(set, self, static_region) } + pub(crate) fn is_normal(&self) -> bool { + D::is_normal() + } + /// Given a region `R`, iterate over all constraints `R: R1`. - pub(crate) fn outgoing_edges<'a, 'tcx>( + pub(crate) fn outgoing_edges_from_graph<'a, 'tcx>( &'a self, region_sup: RegionVid, constraints: &'a OutlivesConstraintSet<'tcx>, - static_region: RegionVid, - ) -> Edges<'a, 'tcx, D> { - //if this is the `'static` region and the graph's direction is normal, - //then setup the Edges iterator to return all regions #53178 - if region_sup == static_region && D::is_normal() { - Edges { - graph: self, - constraints, - pointer: None, - next_static_idx: Some(0), - static_region, - } - } else { - //otherwise, just setup the iterator as normal - let first = self.first_constraints[region_sup]; - Edges { graph: self, constraints, pointer: first, next_static_idx: None, static_region } - } + ) -> EdgesFromGraph<'a, 'tcx, D> { + EdgesFromGraph { graph: self, constraints, pointer: self.first_constraints[region_sup] } + } + + /// Returns all regions (#53178). + pub(crate) fn outgoing_edges_from_static(&self) -> EdgesFromStatic { + EdgesFromStatic { next_static_idx: 0, end_static_idx: self.first_constraints.len() } } } -pub(crate) struct Edges<'a, 'tcx, D: ConstraintGraphDirection> { +pub(crate) struct EdgesFromGraph<'a, 'tcx, D: ConstraintGraphDirection> { graph: &'a ConstraintGraph, constraints: &'a OutlivesConstraintSet<'tcx>, pointer: Option, - next_static_idx: Option, - static_region: RegionVid, } -impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Edges<'a, 'tcx, D> { - type Item = OutlivesConstraint<'tcx>; +impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for EdgesFromGraph<'a, 'tcx, D> { + type Item = &'a OutlivesConstraint<'tcx>; fn next(&mut self) -> Option { if let Some(p) = self.pointer { self.pointer = self.graph.next_constraints[p]; + Some(&self.constraints[p]) + } else { + None + } + } +} + +pub(crate) struct EdgesFromStatic { + next_static_idx: usize, + end_static_idx: usize, +} + +impl Iterator for EdgesFromStatic { + type Item = RegionVid; - Some(self.constraints[p]) - } else if let Some(next_static_idx) = self.next_static_idx { - self.next_static_idx = if next_static_idx == (self.graph.first_constraints.len() - 1) { - None - } else { - Some(next_static_idx + 1) - }; - - Some(OutlivesConstraint { - sup: self.static_region, - sub: next_static_idx.into(), - locations: Locations::All(DUMMY_SP), - span: DUMMY_SP, - category: ConstraintCategory::Internal, - variance_info: VarianceDiagInfo::default(), - from_closure: false, - }) + fn next(&mut self) -> Option { + if self.next_static_idx < self.end_static_idx { + let ret = RegionVid::from_usize(self.next_static_idx); + self.next_static_idx += 1; + Some(ret) } else { None } @@ -193,21 +184,38 @@ impl<'a, 'tcx, D: ConstraintGraphDirection> RegionGraph<'a, 'tcx, D> { /// Given a region `R`, iterate over all regions `R1` such that /// there exists a constraint `R: R1`. pub(crate) fn outgoing_regions(&self, region_sup: RegionVid) -> Successors<'a, 'tcx, D> { - Successors { - edges: self.constraint_graph.outgoing_edges(region_sup, self.set, self.static_region), + // If this is the `'static` region and the graph's direction is normal, + // then setup the Edges iterator to return all regions (#53178). + if region_sup == self.static_region && D::is_normal() { + Successors::FromStatic(self.constraint_graph.outgoing_edges_from_static()) + } else { + // Otherwise, just setup the iterator as normal. + Successors::FromGraph( + self.constraint_graph.outgoing_edges_from_graph(region_sup, self.set), + ) } } } -pub(crate) struct Successors<'a, 'tcx, D: ConstraintGraphDirection> { - edges: Edges<'a, 'tcx, D>, +pub(crate) enum Successors<'a, 'tcx, D: ConstraintGraphDirection> { + FromStatic(EdgesFromStatic), + FromGraph(EdgesFromGraph<'a, 'tcx, D>), } impl<'a, 'tcx, D: ConstraintGraphDirection> Iterator for Successors<'a, 'tcx, D> { type Item = RegionVid; fn next(&mut self) -> Option { - self.edges.next().map(|c| D::end_region(&c)) + match self { + Successors::FromStatic(edges) => { + // No `D::end_region` call needed here: static successors are only possible when + // the direction is `Normal`, so we can directly use what would be the `sub` value. + edges.next() + } + Successors::FromGraph(edges) => { + edges.next().map(|constraint| D::end_region(constraint.sup, constraint.sub)) + } + } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 5a526da0087ed..2694a1eda78d7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -8,7 +8,6 @@ use std::ops::ControlFlow; use either::Either; use hir::{ClosureKind, Path}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, MultiSpan, struct_span_code_err}; @@ -288,7 +287,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { None => "value".to_owned(), }; if needs_note { - let ty = self.infcx.tcx.short_string(ty, err.long_ty_path()); if let Some(local) = place.as_local() { let span = self.body.local_decls[local].source_info.span; err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { @@ -2617,7 +2615,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat && let Some(init) = local.init - && let hir::Expr { + && let &hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { kind: hir::ClosureKind::Closure, @@ -3530,10 +3528,10 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { location: Location, mpi: MovePathIndex, ) -> (Vec, Vec) { - fn predecessor_locations<'a, 'tcx>( - body: &'a mir::Body<'tcx>, + fn predecessor_locations<'tcx>( + body: &mir::Body<'tcx>, location: Location, - ) -> impl Iterator + Captures<'tcx> + 'a { + ) -> impl Iterator { if location.statement_index == 0 { let predecessors = body.basic_blocks.predecessors()[location.block].to_vec(); Either::Left(predecessors.into_iter().map(move |bb| body.terminator_loc(bb))) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index b2b66eabb38b8..f77dda0d386aa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -262,7 +262,7 @@ impl<'tcx> BorrowExplanation<'tcx> { fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { if let hir::ExprKind::If(cond, _conseq, _alt) | hir::ExprKind::Loop( - hir::Block { + &hir::Block { expr: Some(&hir::Expr { kind: hir::ExprKind::If(cond, _conseq, _alt), diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 7da089c5e8c62..208d510db2e1f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -505,7 +505,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let var_id = self.infcx.tcx.closure_captures(def_id)[field.index()].get_root_variable(); - Some(self.infcx.tcx.hir().name(var_id).to_string()) + Some(self.infcx.tcx.hir_name(var_id).to_string()) } _ => { // Might need a revision when the fields in trait RFC is implemented @@ -1124,9 +1124,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { def_id, target_place, places ); let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id); - let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; + let expr = &self.infcx.tcx.hir_expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); - if let hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr { + if let &hir::ExprKind::Closure(&hir::Closure { kind, fn_decl_span, .. }) = expr { for (captured_place, place) in self.infcx.tcx.closure_captures(def_id).iter().zip(places) { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 5e83d2ffa97a1..29cc749877b3e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -596,10 +596,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, place_ty, expr, None); } - let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, - ty, + ty: place_ty, place: &place_desc, span, }); @@ -629,10 +628,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, place_ty, expr, Some(use_spans)); } - let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, - ty, + ty: place_ty, place: &place_desc, span: use_span, }); @@ -833,10 +831,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, bind_to.ty, expr, None); } - let ty = self.infcx.tcx.short_string(bind_to.ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, - ty, + ty: bind_to.ty, place: place_desc, span: binding_span, }); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index be4a7736b1c20..3951b467961a5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -698,7 +698,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if !matches!(k, hir::AssocItemKind::Fn { .. }) { continue; } - if self.infcx.tcx.hir().name(hi) != self.infcx.tcx.hir().name(my_hir) { + if self.infcx.tcx.hir_name(hi) != self.infcx.tcx.hir_name(my_hir) { continue; } f_in_trait_opt = Some(hi); @@ -823,7 +823,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { ) => { capture_reason = format!("mutable borrow of `{upvar}`"); } - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { capture_reason = format!("possible mutation of `{upvar}`"); } _ => bug!("upvar `{upvar}` borrowed, but not mutably"), diff --git a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs index 876b8f214b017..7192a889adcbc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs +++ b/compiler/rustc_borrowck/src/diagnostics/opaque_suggestions.rs @@ -105,7 +105,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { if let Some(opaque_def_id) = opaque_def_id.as_local() && let hir::OpaqueTyOrigin::FnReturn { parent, .. } = - tcx.hir().expect_opaque_ty(opaque_def_id).origin + tcx.hir_expect_opaque_ty(opaque_def_id).origin { if let Some(sugg) = impl_trait_overcapture_suggestion( tcx, diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 55b6367f35ff8..6b11f1a3681ff 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -14,9 +14,8 @@ use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; use rustc_middle::mir::{AnnotationSource, ConstraintCategory, ReturnConstraint}; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::{ - self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, + self, GenericArgs, Region, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitor, fold_regions, }; use rustc_span::{Ident, Span, kw}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 88804560f28e2..412aaf70c3f19 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -194,8 +194,8 @@ impl Display for RegionName { } impl rustc_errors::IntoDiagArg for RegionName { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> rustc_errors::DiagArgValue { + self.to_string().into_diag_arg(path) } } @@ -343,7 +343,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { } }; let hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }) = - tcx.hir().expect_expr(self.mir_hir_id()).kind + tcx.hir_expect_expr(self.mir_hir_id()).kind else { bug!("Closure is not defined by a closure expr"); }; @@ -681,7 +681,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { let mir_hir_id = self.mir_hir_id(); let (return_span, mir_description, hir_ty) = match tcx.hir_node(mir_hir_id) { - hir::Node::Expr(hir::Expr { + hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl, kind, fn_decl_span, .. }), .. }) => { @@ -873,7 +873,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> { .name; let yield_span = match tcx.hir_node(self.mir_hir_id()) { - hir::Node::Expr(hir::Expr { + hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. }) => tcx.sess.source_map().end_point(fn_decl_span), diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 191c0444c742e..693d22abbe6c8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -69,7 +69,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let upvar_hir_id = upvars[upvar_index].get_root_variable(); debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}"); - let upvar_name = tcx.hir().name(upvar_hir_id); + let upvar_name = tcx.hir_name(upvar_hir_id); let upvar_span = tcx.hir().span(upvar_hir_id); debug!( "get_upvar_name_and_span_for_region: upvar_name={upvar_name:?} upvar_span={upvar_span:?}", diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index a98984a4b4c7a..07b3f3477a849 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -2,6 +2,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -13,7 +14,6 @@ #![feature(rustdoc_internals)] #![feature(stmt_expr_attributes)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::borrow::Cow; @@ -35,8 +35,7 @@ use rustc_infer::infer::{ }; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt, TypingMode, fold_regions}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::impls::{ EverInitializedPlaces, MaybeInitializedPlaces, MaybeUninitializedPlaces, @@ -648,7 +647,7 @@ impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt< | StatementKind::StorageLive(..) => {} // This does not affect borrowck StatementKind::BackwardIncompatibleDropHint { place, reason: BackwardIncompatibleDropReason::Edition2024 } => { - self.check_backward_incompatible_drop(location, (**place, span), state); + self.check_backward_incompatible_drop(location, **place, state); } StatementKind::StorageDead(local) => { self.access_place( @@ -1174,7 +1173,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { fn check_backward_incompatible_drop( &mut self, location: Location, - (place, place_span): (Place<'tcx>, Span), + place: Place<'tcx>, state: &BorrowckDomain, ) { let tcx = self.infcx.tcx; @@ -1490,14 +1489,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { let stmt = &bbd.statements[loc.statement_index]; debug!("temporary assigned in: stmt={:?}", stmt); - if let StatementKind::Assign(box (_, Rvalue::Ref(_, _, source))) = stmt.kind - { - propagate_closure_used_mut_place(self, source); - } else { - bug!( - "closures should only capture user variables \ + match stmt.kind { + StatementKind::Assign(box ( + _, + Rvalue::Ref(_, _, source) + | Rvalue::Use(Operand::Copy(source) | Operand::Move(source)), + )) => { + propagate_closure_used_mut_place(self, source); + } + _ => { + bug!( + "closures should only capture user variables \ or references to user variables" - ); + ); + } } } _ => propagate_closure_used_mut_place(self, place), diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs index a0adf471fd31f..bdd0f6fe11e0f 100644 --- a/compiler/rustc_borrowck/src/member_constraints.rs +++ b/compiler/rustc_borrowck/src/member_constraints.rs @@ -1,7 +1,6 @@ use std::hash::Hash; use std::ops::Index; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexMap; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::ty::{self, Ty}; @@ -147,9 +146,7 @@ impl<'tcx, R> MemberConstraintSet<'tcx, R> where R: Copy + Hash + Eq, { - pub(crate) fn all_indices( - &self, - ) -> impl Iterator + Captures<'tcx> + '_ { + pub(crate) fn all_indices(&self) -> impl Iterator { self.constraints.indices() } @@ -159,7 +156,7 @@ where pub(crate) fn indices( &self, member_region_vid: R, - ) -> impl Iterator + Captures<'tcx> + '_ { + ) -> impl Iterator { let mut next = self.first_constraints.get(&member_region_vid).cloned(); std::iter::from_fn(move || -> Option { if let Some(current) = next { diff --git a/compiler/rustc_borrowck/src/polonius/loan_liveness.rs b/compiler/rustc_borrowck/src/polonius/loan_liveness.rs index 768c12a97a64e..5cd265e0db92d 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_liveness.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_liveness.rs @@ -175,7 +175,7 @@ impl LocalizedConstraintGraph { } /// Returns the outgoing edges of a given node, not its transitive closure. - fn outgoing_edges(&self, node: LocalizedNode) -> impl Iterator + use<'_> { + fn outgoing_edges(&self, node: LocalizedNode) -> impl Iterator { // The outgoing edges are: // - the physical edges present at this node, // - the materialized logical edges that exist virtually at all points for this node's diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index e0e3e028c6123..a80d74d9e370a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -18,11 +18,10 @@ use rustc_middle::mir::{ ReturnConstraint, TerminatorKind, }; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex}; +use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, UniverseIndex, fold_regions}; use rustc_mir_dataflow::points::DenseLocationMap; -use rustc_span::Span; use rustc_span::hygiene::DesugaringKind; +use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; use crate::BorrowckInferCtxt; @@ -311,9 +310,11 @@ enum RegionRelationCheckResult { } #[derive(Clone, PartialEq, Eq, Debug)] -enum Trace<'tcx> { +enum Trace<'a, 'tcx> { StartRegion, - FromOutlivesConstraint(OutlivesConstraint<'tcx>), + FromGraph(&'a OutlivesConstraint<'tcx>), + FromStatic(RegionVid), + FromMember(RegionVid, RegionVid, Span), NotVisited, } @@ -576,9 +577,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { } /// Returns an iterator over all the outlives constraints. - pub(crate) fn outlives_constraints( - &self, - ) -> impl Iterator> + '_ { + pub(crate) fn outlives_constraints(&self) -> impl Iterator> { self.constraints.outlives().iter().copied() } @@ -615,10 +614,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { self.scc_values.region_value_str(scc) } - pub(crate) fn placeholders_contained_in<'a>( - &'a self, + pub(crate) fn placeholders_contained_in( + &self, r: RegionVid, - ) -> impl Iterator + 'a { + ) -> impl Iterator { let scc = self.constraint_sccs.scc(r); self.scc_values.placeholders_contained_in(scc) } @@ -1766,6 +1765,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut context = IndexVec::from_elem(Trace::NotVisited, &self.definitions); context[from_region] = Trace::StartRegion; + let fr_static = self.universal_regions().fr_static; + // Use a deque so that we do a breadth-first search. We will // stop at the first match, which ought to be the shortest // path (fewest constraints). @@ -1785,13 +1786,39 @@ impl<'tcx> RegionInferenceContext<'tcx> { if target_test(r) { let mut result = vec![]; let mut p = r; + // This loop is cold and runs at the end, which is why we delay + // `OutlivesConstraint` construction until now. loop { - match context[p].clone() { - Trace::NotVisited => { - bug!("found unvisited region {:?} on path to {:?}", p, r) + match context[p] { + Trace::FromGraph(c) => { + p = c.sup; + result.push(*c); + } + + Trace::FromStatic(sub) => { + let c = OutlivesConstraint { + sup: fr_static, + sub, + locations: Locations::All(DUMMY_SP), + span: DUMMY_SP, + category: ConstraintCategory::Internal, + variance_info: ty::VarianceDiagInfo::default(), + from_closure: false, + }; + p = c.sup; + result.push(c); } - Trace::FromOutlivesConstraint(c) => { + Trace::FromMember(sup, sub, span) => { + let c = OutlivesConstraint { + sup, + sub, + locations: Locations::All(span), + span, + category: ConstraintCategory::OpaqueType, + variance_info: ty::VarianceDiagInfo::default(), + from_closure: false, + }; p = c.sup; result.push(c); } @@ -1800,6 +1827,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { result.reverse(); return Some((result, r)); } + + Trace::NotVisited => { + bug!("found unvisited region {:?} on path to {:?}", p, r) + } } } } @@ -1810,45 +1841,42 @@ impl<'tcx> RegionInferenceContext<'tcx> { // A constraint like `'r: 'x` can come from our constraint // graph. - let fr_static = self.universal_regions().fr_static; - let outgoing_edges_from_graph = - self.constraint_graph.outgoing_edges(r, &self.constraints, fr_static); // Always inline this closure because it can be hot. - let mut handle_constraint = #[inline(always)] - |constraint: OutlivesConstraint<'tcx>| { - debug_assert_eq!(constraint.sup, r); - let sub_region = constraint.sub; - if let Trace::NotVisited = context[sub_region] { - context[sub_region] = Trace::FromOutlivesConstraint(constraint); - deque.push_back(sub_region); + let mut handle_trace = #[inline(always)] + |sub, trace| { + if let Trace::NotVisited = context[sub] { + context[sub] = trace; + deque.push_back(sub); } }; - // This loop can be hot. - for constraint in outgoing_edges_from_graph { - if matches!(constraint.category, ConstraintCategory::IllegalUniverse) { - debug!("Ignoring illegal universe constraint: {constraint:?}"); - continue; + // If this is the `'static` region and the graph's direction is normal, then set up the + // Edges iterator to return all regions (#53178). + if r == fr_static && self.constraint_graph.is_normal() { + for sub in self.constraint_graph.outgoing_edges_from_static() { + handle_trace(sub, Trace::FromStatic(sub)); + } + } else { + let edges = self.constraint_graph.outgoing_edges_from_graph(r, &self.constraints); + // This loop can be hot. + for constraint in edges { + if matches!(constraint.category, ConstraintCategory::IllegalUniverse) { + debug!("Ignoring illegal universe constraint: {constraint:?}"); + continue; + } + debug_assert_eq!(constraint.sup, r); + handle_trace(constraint.sub, Trace::FromGraph(constraint)); } - handle_constraint(constraint); } // Member constraints can also give rise to `'r: 'x` edges that // were not part of the graph initially, so watch out for those. // (But they are extremely rare; this loop is very cold.) for constraint in self.applied_member_constraints(self.constraint_sccs.scc(r)) { + let sub = constraint.min_choice; let p_c = &self.member_constraints[constraint.member_constraint_index]; - let constraint = OutlivesConstraint { - sup: r, - sub: constraint.min_choice, - locations: Locations::All(p_c.definition_span), - span: p_c.definition_span, - category: ConstraintCategory::OpaqueType, - variance_info: ty::VarianceDiagInfo::default(), - from_closure: false, - }; - handle_constraint(constraint); + handle_trace(sub, Trace::FromMember(r, sub, p_c.definition_span)); } } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 54f9e82dbb82d..048394485962f 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -5,11 +5,9 @@ use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, TyCtxtInferExt as _}; use rustc_macros::extension; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, GenericArgKind, GenericArgs, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, - TypingMode, + TypeVisitableExt, TypingMode, fold_regions, }; use rustc_span::Span; use rustc_trait_selection::regions::OutlivesEnvironmentBuildExt; diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index d0cfe572d0876..b2ed8a3582796 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -20,10 +20,7 @@ pub(crate) struct ReverseSccGraph { impl ReverseSccGraph { /// Find all universal regions that are required to outlive the given SCC. - pub(super) fn upper_bounds<'a>( - &'a self, - scc0: ConstraintSccIndex, - ) -> impl Iterator + 'a { + pub(super) fn upper_bounds(&self, scc0: ConstraintSccIndex) -> impl Iterator { let mut duplicates = FxIndexSet::default(); graph::depth_first_search(&self.graph, scc0) .flat_map(move |scc1| { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index f1bcb353dc61c..d9ac5b5cb132a 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -88,7 +88,7 @@ impl LivenessValues { } /// Iterate through each region that has a value in this set. - pub(crate) fn regions(&self) -> impl Iterator + '_ { + pub(crate) fn regions(&self) -> impl Iterator { self.points.as_ref().expect("use with_specific_points").rows() } @@ -96,7 +96,7 @@ impl LivenessValues { // We are passing query instability implications to the caller. #[rustc_lint_query_instability] #[allow(rustc::potential_query_instability)] - pub(crate) fn live_regions_unordered(&self) -> impl Iterator + '_ { + pub(crate) fn live_regions_unordered(&self) -> impl Iterator { self.live_regions.as_ref().unwrap().iter().copied() } @@ -143,7 +143,7 @@ impl LivenessValues { } /// Returns an iterator of all the points where `region` is live. - fn live_points(&self, region: RegionVid) -> impl Iterator + '_ { + fn live_points(&self, region: RegionVid) -> impl Iterator { let Some(points) = &self.points else { unreachable!( "Should be using LivenessValues::with_specific_points to ask whether live at a location" @@ -340,7 +340,7 @@ impl RegionValues { } /// Returns the locations contained within a given region `r`. - pub(crate) fn locations_outlived_by<'a>(&'a self, r: N) -> impl Iterator + 'a { + pub(crate) fn locations_outlived_by(&self, r: N) -> impl Iterator { self.points.row(r).into_iter().flat_map(move |set| { set.iter() .take_while(move |&p| self.location_map.point_in_range(p)) @@ -349,18 +349,15 @@ impl RegionValues { } /// Returns just the universal regions that are contained in a given region's value. - pub(crate) fn universal_regions_outlived_by<'a>( - &'a self, - r: N, - ) -> impl Iterator + 'a { + pub(crate) fn universal_regions_outlived_by(&self, r: N) -> impl Iterator { self.free_regions.row(r).into_iter().flat_map(|set| set.iter()) } /// Returns all the elements contained in a given region's value. - pub(crate) fn placeholders_contained_in<'a>( - &'a self, + pub(crate) fn placeholders_contained_in( + &self, r: N, - ) -> impl Iterator + 'a { + ) -> impl Iterator { self.placeholders .row(r) .into_iter() @@ -369,10 +366,7 @@ impl RegionValues { } /// Returns all the elements contained in a given region's value. - pub(crate) fn elements_contained_in<'a>( - &'a self, - r: N, - ) -> impl Iterator + 'a { + pub(crate) fn elements_contained_in(&self, r: N) -> impl Iterator { let points_iter = self.locations_outlived_by(r).map(RegionElement::Location); let free_regions_iter = diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs index e355d2b415b03..ff92b4168a86c 100644 --- a/compiler/rustc_borrowck/src/renumber.rs +++ b/compiler/rustc_borrowck/src/renumber.rs @@ -2,8 +2,7 @@ use rustc_index::IndexSlice; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::visit::{MutVisitor, TyContext}; use rustc_middle::mir::{Body, ConstOperand, Location, Promoted}; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeFoldable, fold_regions}; use rustc_span::Symbol; use tracing::{debug, instrument}; diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 11b30c145c2c2..4be5d0dbf4284 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -459,17 +459,17 @@ pub(crate) enum OnClosureNote<'a> { } #[derive(Subdiagnostic)] -pub(crate) enum TypeNoCopy<'a> { +pub(crate) enum TypeNoCopy<'a, 'tcx> { #[label(borrowck_ty_no_impl_copy)] Label { is_partial_move: bool, - ty: String, + ty: Ty<'tcx>, place: &'a str, #[primary_span] span: Span, }, #[note(borrowck_ty_no_impl_copy)] - Note { is_partial_move: bool, ty: String, place: &'a str }, + Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str }, } #[derive(Diagnostic)] diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 3b48ca305c45b..6fbe1db6330e2 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -1,4 +1,4 @@ -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate}; @@ -7,8 +7,9 @@ use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_infer::traits::query::type_op::DeeplyNormalize; use rustc_middle::bug; use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory}; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{ + self, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, +}; use rustc_span::Span; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument}; @@ -88,7 +89,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { pub(crate) fn apply_closure_requirements( &mut self, closure_requirements: &ClosureRegionRequirements<'tcx>, - closure_def_id: DefId, + closure_def_id: LocalDefId, closure_args: ty::GenericArgsRef<'tcx>, ) { // Extract the values of the free regions in `closure_args` @@ -98,7 +99,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.tcx, closure_args, closure_requirements.num_external_vids, - closure_def_id.expect_local(), + closure_def_id, ); debug!(?closure_mapping); diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index efbae1e153537..eaac633b512d6 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -172,7 +172,7 @@ impl UniversalRegionRelations<'_> { } /// Returns the _non-transitive_ set of known `outlives` constraints between free regions. - pub(crate) fn known_outlives(&self) -> impl Iterator + '_ { + pub(crate) fn known_outlives(&self) -> impl Iterator { self.outlives.base_edges() } } diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs index f70b17e33624b..c6b29fe36fd9c 100644 --- a/compiler/rustc_borrowck/src/type_check/input_output.rs +++ b/compiler/rustc_borrowck/src/type_check/input_output.rs @@ -24,9 +24,9 @@ use crate::universal_regions::DefiningTy; impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// Check explicit closure signature annotation, /// e.g., `|x: FxIndexMap<_, &'static u32>| ...`. - #[instrument(skip(self, body), level = "debug")] - pub(super) fn check_signature_annotation(&mut self, body: &Body<'tcx>) { - let mir_def_id = body.source.def_id().expect_local(); + #[instrument(skip(self), level = "debug")] + pub(super) fn check_signature_annotation(&mut self) { + let mir_def_id = self.body.source.def_id().expect_local(); if !self.tcx().is_closure_like(mir_def_id.to_def_id()) { return; @@ -38,9 +38,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // (e.g., the `_` in the code above) with fresh variables. // Then replace the bound items in the fn sig with fresh variables, // so that they represent the view from "inside" the closure. - let user_provided_sig = self.instantiate_canonical(body.span, &user_provided_poly_sig); + let user_provided_sig = self.instantiate_canonical(self.body.span, &user_provided_poly_sig); let mut user_provided_sig = self.infcx.instantiate_binder_with_fresh_vars( - body.span, + self.body.span, BoundRegionConversionTime::FnCall, user_provided_sig, ); @@ -66,12 +66,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Ty::new_tup(self.tcx(), user_provided_sig.inputs()), args.tupled_upvars_ty(), args.coroutine_captures_by_ref_ty(), - self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(body.span), || { - RegionCtxt::Unknown - }), + self.infcx + .next_region_var(RegionVariableOrigin::MiscVariable(self.body.span), || { + RegionCtxt::Unknown + }), ); - let next_ty_var = || self.infcx.next_ty_var(body.span); + let next_ty_var = || self.infcx.next_ty_var(self.body.span); let output_ty = Ty::new_coroutine( self.tcx(), self.tcx().coroutine_for_closure(mir_def_id), @@ -107,9 +108,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { for (&user_ty, arg_decl) in user_provided_sig.inputs().iter().zip_eq( // In MIR, closure args begin with an implicit `self`. // Also, coroutines have a resume type which may be implicitly `()`. - body.args_iter() + self.body + .args_iter() .skip(1 + if is_coroutine_with_implicit_resume_ty { 1 } else { 0 }) - .map(|local| &body.local_decls[local]), + .map(|local| &self.body.local_decls[local]), ) { self.ascribe_user_type_skip_wf( arg_decl.ty, @@ -119,7 +121,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // If the user explicitly annotated the output type, enforce it. - let output_decl = &body.local_decls[RETURN_PLACE]; + let output_decl = &self.body.local_decls[RETURN_PLACE]; self.ascribe_user_type_skip_wf( output_decl.ty, ty::UserType::new(ty::UserTypeKind::Ty(user_provided_sig.output())), @@ -127,12 +129,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - #[instrument(skip(self, body), level = "debug")] - pub(super) fn equate_inputs_and_outputs( - &mut self, - body: &Body<'tcx>, - normalized_inputs_and_output: &[Ty<'tcx>], - ) { + #[instrument(skip(self), level = "debug")] + pub(super) fn equate_inputs_and_outputs(&mut self, normalized_inputs_and_output: &[Ty<'tcx>]) { let (&normalized_output_ty, normalized_input_tys) = normalized_inputs_and_output.split_last().unwrap(); @@ -141,18 +139,18 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // Equate expected input tys with those in the MIR. for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() { - if argument_index + 1 >= body.local_decls.len() { + if argument_index + 1 >= self.body.local_decls.len() { self.tcx() .dcx() - .span_bug(body.span, "found more normalized_input_ty than local_decls"); + .span_bug(self.body.span, "found more normalized_input_ty than local_decls"); } // In MIR, argument N is stored in local N+1. let local = Local::from_usize(argument_index + 1); - let mir_input_ty = body.local_decls[local].ty; + let mir_input_ty = self.body.local_decls[local].ty; - let mir_input_span = body.local_decls[local].source_info.span; + let mir_input_span = self.body.local_decls[local].source_info.span; self.equate_normalized_input_or_output( normalized_input_ty, mir_input_ty, @@ -160,8 +158,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - if let Some(mir_yield_ty) = body.yield_ty() { - let yield_span = body.local_decls[RETURN_PLACE].source_info.span; + if let Some(mir_yield_ty) = self.body.yield_ty() { + let yield_span = self.body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( self.universal_regions.yield_ty.unwrap(), mir_yield_ty, @@ -169,8 +167,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } - if let Some(mir_resume_ty) = body.resume_ty() { - let yield_span = body.local_decls[RETURN_PLACE].source_info.span; + if let Some(mir_resume_ty) = self.body.resume_ty() { + let yield_span = self.body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output( self.universal_regions.resume_ty.unwrap(), mir_resume_ty, @@ -179,8 +177,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // Return types are a bit more complex. They may contain opaque `impl Trait` types. - let mir_output_ty = body.local_decls[RETURN_PLACE].ty; - let output_span = body.local_decls[RETURN_PLACE].source_info.span; + let mir_output_ty = self.body.local_decls[RETURN_PLACE].ty; + let output_span = self.body.local_decls[RETURN_PLACE].source_info.span; self.equate_normalized_input_or_output(normalized_output_ty, mir_output_ty, output_span); } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs index 6182b68f6f411..9591da83708b7 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs @@ -54,7 +54,7 @@ rustc_index::newtype_index! { fn appearances_iter( first: Option, appearances: &Appearances, -) -> impl Iterator + '_ { +) -> impl Iterator { AppearancesIter { appearances, current: first } } @@ -107,17 +107,17 @@ impl LocalUseMap { local_use_map } - pub(crate) fn defs(&self, local: Local) -> impl Iterator + '_ { + pub(crate) fn defs(&self, local: Local) -> impl Iterator { appearances_iter(self.first_def_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } - pub(crate) fn uses(&self, local: Local) -> impl Iterator + '_ { + pub(crate) fn uses(&self, local: Local) -> impl Iterator { appearances_iter(self.first_use_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } - pub(crate) fn drops(&self, local: Local) -> impl Iterator + '_ { + pub(crate) fn drops(&self, local: Local) -> impl Iterator { appearances_iter(self.first_drop_at[local], &self.appearances) .map(move |aa| self.appearances[aa].point_index) } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index dcc179030020d..b7a21cf48c8f7 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -4,8 +4,7 @@ use rustc_middle::mir::visit::{TyContext, Visitor}; use rustc_middle::mir::{Body, Local, Location, SourceInfo}; use rustc_middle::span_bug; use rustc_middle::ty::relate::Relate; -use rustc_middle::ty::visit::TypeVisitable; -use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt, TypeVisitable}; use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::MoveData; @@ -31,7 +30,6 @@ mod trace; /// performed before pub(super) fn generate<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, location_map: &DenseLocationMap, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, @@ -51,23 +49,16 @@ pub(super) fn generate<'a, 'tcx>( // We do record these regions in the polonius context, since they're used to differentiate // relevant and boring locals, which is a key distinction used later in diagnostics. if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { - let (_, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body); + let (_, boring_locals) = + compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body); typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals = boring_locals.into_iter().collect(); free_regions = typeck.universal_regions.universal_regions_iter().collect(); } let (relevant_live_locals, boring_locals) = - compute_relevant_live_locals(typeck.tcx(), &free_regions, body); - - trace::trace( - typeck, - body, - location_map, - flow_inits, - move_data, - relevant_live_locals, - boring_locals, - ); + compute_relevant_live_locals(typeck.tcx(), &free_regions, typeck.body); + + trace::trace(typeck, location_map, flow_inits, move_data, relevant_live_locals, boring_locals); // Mark regions that should be live where they appear within rvalues or within a call: like // args, regions, and types. @@ -76,7 +67,7 @@ pub(super) fn generate<'a, 'tcx>( &mut typeck.constraints.liveness_constraints, &typeck.universal_regions, &mut typeck.polonius_liveness, - body, + typeck.body, ); } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 12e8be41614bd..7718644b9a9a8 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -4,7 +4,6 @@ use rustc_index::interval::IntervalSet; use rustc_infer::infer::canonical::QueryRegionConstraints; use rustc_infer::infer::outlives::for_liveness; use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location}; -use rustc_middle::span_bug; use rustc_middle::traits::query::DropckOutlivesResult; use rustc_middle::ty::relate::Relate; use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt}; @@ -12,7 +11,7 @@ use rustc_mir_dataflow::ResultsCursor; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex}; use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::query::dropck_outlives; @@ -40,17 +39,15 @@ use crate::type_check::{NormalizeLocation, TypeChecker}; /// this respects `#[may_dangle]` annotations). pub(super) fn trace<'a, 'tcx>( typeck: &mut TypeChecker<'_, 'tcx>, - body: &Body<'tcx>, location_map: &DenseLocationMap, flow_inits: ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>, move_data: &MoveData<'tcx>, relevant_live_locals: Vec, boring_locals: Vec, ) { - let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, body); + let local_use_map = &LocalUseMap::build(&relevant_live_locals, location_map, typeck.body); let cx = LivenessContext { typeck, - body, flow_inits, location_map, local_use_map, @@ -70,14 +67,13 @@ pub(super) fn trace<'a, 'tcx>( /// Contextual state for the type-liveness coroutine. struct LivenessContext<'a, 'typeck, 'b, 'tcx> { /// Current type-checker, giving us our inference context etc. + /// + /// This also stores the body we're currently analyzing. typeck: &'a mut TypeChecker<'typeck, 'tcx>, /// Defines the `PointIndex` mapping location_map: &'a DenseLocationMap, - /// MIR we are analyzing. - body: &'a Body<'tcx>, - /// Mapping to/from the various indices used for initialization tracking. move_data: &'a MoveData<'tcx>, @@ -140,7 +136,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { self.compute_use_live_points_for(local); self.compute_drop_live_points_for(local); - let local_ty = self.cx.body.local_decls[local].ty; + let local_ty = self.cx.body().local_decls[local].ty; if !self.use_live_at.is_empty() { self.cx.add_use_live_facts_for(local_ty, &self.use_live_at); @@ -165,8 +161,8 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { /// and can therefore safely be dropped. fn dropck_boring_locals(&mut self, boring_locals: Vec) { for local in boring_locals { - let local_ty = self.cx.body.local_decls[local].ty; - let local_span = self.cx.body.local_decls[local].source_info.span; + let local_ty = self.cx.body().local_decls[local].ty; + let local_span = self.cx.body().local_decls[local].source_info.span; let drop_data = self.cx.drop_data.entry(local_ty).or_insert_with({ let typeck = &self.cx.typeck; move || LivenessContext::compute_drop_data(typeck, local_ty, local_span) @@ -174,7 +170,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { drop_data.dropck_result.report_overflows( self.cx.typeck.infcx.tcx, - self.cx.body.local_decls[local].source_info.span, + self.cx.typeck.body.local_decls[local].source_info.span, local_ty, ); } @@ -203,7 +199,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { .var_dropped_at .iter() .filter_map(|&(local, location_index)| { - let local_ty = self.cx.body.local_decls[local].ty; + let local_ty = self.cx.body().local_decls[local].ty; if relevant_live_locals.contains(&local) || !local_ty.has_free_regions() { return None; } @@ -279,9 +275,9 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { let block = self.cx.location_map.to_location(block_start).block; self.stack.extend( - self.cx.body.basic_blocks.predecessors()[block] + self.cx.body().basic_blocks.predecessors()[block] .iter() - .map(|&pred_bb| self.cx.body.terminator_loc(pred_bb)) + .map(|&pred_bb| self.cx.body().terminator_loc(pred_bb)) .map(|pred_loc| self.cx.location_map.point_from_location(pred_loc)), ); } @@ -306,7 +302,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { // Find the drops where `local` is initialized. for drop_point in self.cx.local_use_map.drops(local) { let location = self.cx.location_map.to_location(drop_point); - debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,); + debug_assert_eq!(self.cx.body().terminator_loc(location.block), location,); if self.cx.initialized_at_terminator(location.block, mpi) && self.drop_live_at.insert(drop_point) @@ -352,7 +348,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { // block. One of them may be either a definition or use // live point. let term_location = self.cx.location_map.to_location(term_point); - debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,); + debug_assert_eq!(self.cx.body().terminator_loc(term_location.block), term_location,); let block = term_location.block; let entry_point = self.cx.location_map.entry_point(term_location.block); for p in (entry_point..term_point).rev() { @@ -377,7 +373,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { } } - let body = self.cx.body; + let body = self.cx.typeck.body; for &pred_block in body.basic_blocks.predecessors()[block].iter() { debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); @@ -404,7 +400,7 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { continue; } - let pred_term_loc = self.cx.body.terminator_loc(pred_block); + let pred_term_loc = self.cx.body().terminator_loc(pred_block); let pred_term_point = self.cx.location_map.point_from_location(pred_term_loc); // If the terminator of this predecessor either *assigns* @@ -464,6 +460,9 @@ impl<'a, 'typeck, 'b, 'tcx> LivenessResults<'a, 'typeck, 'b, 'tcx> { } impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { + fn body(&self) -> &Body<'tcx> { + self.typeck.body + } /// Returns `true` if the local variable (or some part of it) is initialized at the current /// cursor position. Callers should call one of the `seek` methods immediately before to point /// the cursor to the desired location. @@ -482,7 +481,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { /// DROP of some local variable will have an effect -- note that /// drops, as they may unwind, are always terminators. fn initialized_at_terminator(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_before_primary_effect(self.body.terminator_loc(block)); + self.flow_inits.seek_before_primary_effect(self.body().terminator_loc(block)); self.initialized_at_curr_loc(mpi) } @@ -492,7 +491,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { /// **Warning:** Does not account for the result of `Call` /// instructions. fn initialized_at_exit(&mut self, block: BasicBlock, mpi: MovePathIndex) -> bool { - self.flow_inits.seek_after_primary_effect(self.body.terminator_loc(block)); + self.flow_inits.seek_after_primary_effect(self.body().terminator_loc(block)); self.initialized_at_curr_loc(mpi) } @@ -527,7 +526,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { values::pretty_print_points(self.location_map, live_at.iter()), ); - let local_span = self.body.local_decls()[dropped_local].source_info.span; + let local_span = self.body().local_decls()[dropped_local].source_info.span; let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ let typeck = &self.typeck; move || Self::compute_drop_data(typeck, dropped_ty, local_span) @@ -545,7 +544,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { drop_data.dropck_result.report_overflows( self.typeck.infcx.tcx, - self.body.source_info(*drop_locations.first().unwrap()).span, + self.typeck.body.source_info(*drop_locations.first().unwrap()).span, dropped_ty, ); @@ -608,10 +607,10 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { Ok(TypeOpOutput { output, constraints, .. }) => { DropData { dropck_result: output, region_constraint_data: constraints } } - Err(_) => { + Err(ErrorGuaranteed { .. }) => { // We don't run dropck on HIR, and dropck looks inside fields of // types, so there's no guarantee that it succeeds. We also - // can't rely on the the `ErrorGuaranteed` from `fully_perform` here + // can't rely on the `ErrorGuaranteed` from `fully_perform` here // because it comes from delay_span_bug. // // Do this inside of a probe because we don't particularly care (or want) @@ -631,10 +630,10 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { } }; + // Could have no errors if a type lowering error, say, caused the query + // to fail. if !errors.is_empty() { typeck.infcx.err_ctxt().report_fulfillment_errors(errors); - } else { - span_bug!(span, "Rerunning drop data query produced no error."); } }); DropData { dropck_result: Default::default(), region_constraint_data: None } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index bd0d98028ae88..0fda3e31690d1 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -24,12 +24,10 @@ use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt, - Dynamic, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, UserArgs, - UserTypeAnnotationIndex, + Dynamic, GenericArgsRef, OpaqueHiddenType, OpaqueTypeKey, RegionVid, Ty, TyCtxt, + TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::ResultsCursor; @@ -38,7 +36,7 @@ use rustc_mir_dataflow::move_paths::MoveData; use rustc_mir_dataflow::points::DenseLocationMap; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span, sym}; +use rustc_span::{Span, sym}; use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints; use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput}; use tracing::{debug, instrument, trace}; @@ -51,7 +49,6 @@ use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable}; use crate::polonius::{PoloniusContext, PoloniusLivenessContext}; use crate::region_infer::TypeTest; use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; -use crate::renumber::RegionCtxt; use crate::session_diagnostics::{MoveUnsized, SimdIntrinsicArgConst}; use crate::type_check::free_region_relations::{CreateResult, UniversalRegionRelations}; use crate::universal_regions::{DefiningTy, UniversalRegions}; @@ -157,6 +154,7 @@ pub(crate) fn type_check<'a, 'tcx>( infcx, last_span: body.span, body, + promoted, user_type_annotations: &body.user_type_annotations, region_bound_pairs, known_type_outlives_obligations, @@ -171,15 +169,11 @@ pub(crate) fn type_check<'a, 'tcx>( }; typeck.check_user_type_annotations(); + typeck.visit_body(body); + typeck.equate_inputs_and_outputs(&normalized_inputs_and_output); + typeck.check_signature_annotation(); - let mut verifier = TypeVerifier { typeck: &mut typeck, promoted, last_span: body.span }; - verifier.visit_body(body); - - typeck.typeck_mir(body); - typeck.equate_inputs_and_outputs(body, &normalized_inputs_and_output); - typeck.check_signature_annotation(body); - - liveness::generate(&mut typeck, body, &location_map, flow_inits, move_data); + liveness::generate(&mut typeck, &location_map, flow_inits, move_data); let opaque_type_values = opaque_types::take_opaques_and_register_member_constraints(&mut typeck); @@ -213,306 +207,302 @@ enum FieldAccessError { OutOfRange { field_count: usize }, } -/// Verifies that MIR types are sane. -/// -/// FIXME: This should be merged with the actual `TypeChecker`. -struct TypeVerifier<'a, 'b, 'tcx> { - typeck: &'a mut TypeChecker<'b, 'tcx>, - promoted: &'b IndexSlice>, +/// The MIR type checker. Visits the MIR and enforces all the +/// constraints needed for it to be valid and well-typed. Along the +/// way, it accrues region constraints -- these can later be used by +/// NLL region checking. +struct TypeChecker<'a, 'tcx> { + infcx: &'a BorrowckInferCtxt<'tcx>, last_span: Span, + body: &'a Body<'tcx>, + /// The bodies of all promoteds. As promoteds have a completely separate CFG + /// recursing into them may corrupt your data structures if you're not careful. + promoted: &'a IndexSlice>, + /// User type annotations are shared between the main MIR and the MIR of + /// all of the promoted items. + user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, + region_bound_pairs: RegionBoundPairs<'tcx>, + known_type_outlives_obligations: Vec>, + implicit_region_bound: ty::Region<'tcx>, + reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, + universal_regions: &'a UniversalRegions<'tcx>, + location_table: &'a PoloniusLocationTable, + polonius_facts: &'a mut Option, + borrow_set: &'a BorrowSet<'tcx>, + constraints: &'a mut MirTypeckRegionConstraints<'tcx>, + /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints. + polonius_liveness: Option, } -impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { - fn visit_span(&mut self, span: Span) { - if !span.is_dummy() { - self.last_span = span; - } - } +/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions +/// inference computation. +pub(crate) struct MirTypeckResults<'tcx> { + pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, + pub(crate) universal_region_relations: Frozen>, + pub(crate) opaque_type_values: FxIndexMap, OpaqueHiddenType<'tcx>>, + pub(crate) polonius_context: Option, +} - fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { - self.super_place(place, context, location); - let tcx = self.tcx(); - let place_ty = place.ty(self.body(), tcx); - if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), - [place_ty.ty], - ); +/// A collection of region constraints that must be satisfied for the +/// program to be considered well-typed. +pub(crate) struct MirTypeckRegionConstraints<'tcx> { + /// Maps from a `ty::Placeholder` to the corresponding + /// `PlaceholderIndex` bit that we will use for it. + /// + /// To keep everything in sync, do not insert this set + /// directly. Instead, use the `placeholder_region` helper. + pub(crate) placeholder_indices: PlaceholderIndices, - // To have a `Copy` operand, the type `T` of the - // value must be `Copy`. Note that we prove that `T: Copy`, - // rather than using the `is_copy_modulo_regions` - // test. This is important because - // `is_copy_modulo_regions` ignores the resulting region - // obligations and assumes they pass. This can result in - // bounds from `Copy` impls being unsoundly ignored (e.g., - // #29149). Note that we decide to use `Copy` before knowing - // whether the bounds fully apply: in effect, the rule is - // that if a value of some type could implement `Copy`, then - // it must. - self.typeck.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::CopyBound, - ); + /// Each time we add a placeholder to `placeholder_indices`, we + /// also create a corresponding "representative" region vid for + /// that wraps it. This vector tracks those. This way, when we + /// convert the same `ty::RePlaceholder(p)` twice, we can map to + /// the same underlying `RegionVid`. + pub(crate) placeholder_index_to_region: IndexVec>, + + /// In general, the type-checker is not responsible for enforcing + /// liveness constraints; this job falls to the region inferencer, + /// which performs a liveness analysis. However, in some limited + /// cases, the MIR type-checker creates temporary regions that do + /// not otherwise appear in the MIR -- in particular, the + /// late-bound regions that it instantiates at call-sites -- and + /// hence it must report on their liveness constraints. + pub(crate) liveness_constraints: LivenessValues, + + pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>, + + pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, + + pub(crate) universe_causes: FxIndexMap>, + + pub(crate) type_tests: Vec>, +} + +impl<'tcx> MirTypeckRegionConstraints<'tcx> { + /// Creates a `Region` for a given `PlaceholderRegion`, or returns the + /// region that corresponds to a previously created one. + fn placeholder_region( + &mut self, + infcx: &InferCtxt<'tcx>, + placeholder: ty::PlaceholderRegion, + ) -> ty::Region<'tcx> { + let placeholder_index = self.placeholder_indices.insert(placeholder); + match self.placeholder_index_to_region.get(placeholder_index) { + Some(&v) => v, + None => { + let origin = NllRegionVariableOrigin::Placeholder(placeholder); + let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); + self.placeholder_index_to_region.push(region); + region + } } } +} - fn visit_projection_elem( - &mut self, - place: PlaceRef<'tcx>, - elem: PlaceElem<'tcx>, - context: PlaceContext, - location: Location, - ) { - let tcx = self.tcx(); - let base_ty = place.ty(self.body(), tcx); - match elem { - // All these projections don't add any constraints, so there's nothing to - // do here. We check their invariants in the MIR validator after all. - ProjectionElem::Deref - | ProjectionElem::Index(_) - | ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Subslice { .. } - | ProjectionElem::Downcast(..) => {} - ProjectionElem::Field(field, fty) => { - let fty = self.typeck.normalize(fty, location); - let ty = base_ty.field_ty(tcx, field); - let ty = self.typeck.normalize(ty, location); - debug!(?fty, ?ty); +/// The `Locations` type summarizes *where* region constraints are +/// required to hold. Normally, this is at a particular point which +/// created the obligation, but for constraints that the user gave, we +/// want the constraint to hold at all points. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Locations { + /// Indicates that a type constraint should always be true. This + /// is particularly important in the new borrowck analysis for + /// things like the type of the return slot. Consider this + /// example: + /// + /// ```compile_fail,E0515 + /// fn foo<'a>(x: &'a u32) -> &'a u32 { + /// let y = 22; + /// return &y; // error + /// } + /// ``` + /// + /// Here, we wind up with the signature from the return type being + /// something like `&'1 u32` where `'1` is a universal region. But + /// the type of the return slot `_0` is something like `&'2 u32` + /// where `'2` is an existential region variable. The type checker + /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the + /// older NLL analysis, we required this only at the entry point + /// to the function. By the nature of the constraints, this wound + /// up propagating to all points reachable from start (because + /// `'1` -- as a universal region -- is live everywhere). In the + /// newer analysis, though, this doesn't work: `_0` is considered + /// dead at the start (it has no usable value) and hence this type + /// equality is basically a no-op. Then, later on, when we do `_0 + /// = &'3 y`, that region `'3` never winds up related to the + /// universal region `'1` and hence no error occurs. Therefore, we + /// use Locations::All instead, which ensures that the `'1` and + /// `'2` are equal everything. We also use this for other + /// user-given type annotations; e.g., if the user wrote `let mut + /// x: &'static u32 = ...`, we would ensure that all values + /// assigned to `x` are of `'static` lifetime. + /// + /// The span points to the place the constraint arose. For example, + /// it points to the type in a user-given type annotation. If + /// there's no sensible span then it's DUMMY_SP. + All(Span), - if let Err(terr) = self.typeck.relate_types( - ty, - context.ambient_variance(), - fty, - location.to_locations(), - ConstraintCategory::Boring, - ) { - span_mirbug!(self, place, "bad field access ({:?}: {:?}): {:?}", ty, fty, terr); - } - } - ProjectionElem::OpaqueCast(ty) => { - let ty = self.typeck.normalize(ty, location); - self.typeck - .relate_types( - ty, - context.ambient_variance(), - base_ty.ty, - location.to_locations(), - ConstraintCategory::TypeAnnotation(AnnotationSource::OpaqueCast), - ) - .unwrap(); - } - ProjectionElem::UnwrapUnsafeBinder(ty) => { - let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else { - unreachable!(); - }; - let found_ty = self.typeck.infcx.instantiate_binder_with_fresh_vars( - self.body().source_info(location).span, - BoundRegionConversionTime::HigherRankedType, - binder_ty.into(), - ); - self.typeck - .relate_types( - ty, - context.ambient_variance(), - found_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) - .unwrap(); - } - ProjectionElem::Subtype(_) => { - bug!("ProjectionElem::Subtype shouldn't exist in borrowck") - } + /// An outlives constraint that only has to hold at a single location, + /// usually it represents a point where references flow from one spot to + /// another (e.g., `x = y`) + Single(Location), +} + +impl Locations { + pub fn from_location(&self) -> Option { + match self { + Locations::All(_) => None, + Locations::Single(from_location) => Some(*from_location), } } - fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { - debug!(?constant, ?location, "visit_const_operand"); + /// Gets a span representing the location. + pub fn span(&self, body: &Body<'_>) -> Span { + match self { + Locations::All(span) => *span, + Locations::Single(l) => body.source_info(*l).span, + } + } +} - self.super_const_operand(constant, location); - let ty = constant.const_.ty(); +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } - self.typeck.infcx.tcx.for_each_free_region(&ty, |live_region| { - let live_region_vid = self.typeck.universal_regions.to_region_vid(live_region); - self.typeck.constraints.liveness_constraints.add_location(live_region_vid, location); - }); + fn body(&self) -> &Body<'tcx> { + self.body + } - // HACK(compiler-errors): Constants that are gathered into Body.required_consts - // have their locations erased... - let locations = if location != Location::START { - location.to_locations() + fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> RegionVid { + if let ty::RePlaceholder(placeholder) = r.kind() { + self.constraints.placeholder_region(self.infcx, placeholder).as_var() } else { - Locations::All(constant.span) - }; + self.universal_regions.to_region_vid(r) + } + } - if let Some(annotation_index) = constant.user_ty { - if let Err(terr) = self.typeck.relate_type_and_user_type( - constant.const_.ty(), - ty::Invariant, - &UserTypeProjection { base: annotation_index, projs: vec![] }, - locations, - ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg), - ) { - let annotation = &self.typeck.user_type_annotations[annotation_index]; - span_mirbug!( - self, - constant, - "bad constant user type {:?} vs {:?}: {:?}", - annotation, - constant.const_.ty(), - terr, - ); - } - } else { - let tcx = self.tcx(); - let maybe_uneval = match constant.const_ { - Const::Ty(_, ct) => match ct.kind() { - ty::ConstKind::Unevaluated(uv) => { - Some(UnevaluatedConst { def: uv.def, args: uv.args, promoted: None }) - } - _ => None, - }, - Const::Unevaluated(uv, _) => Some(uv), - _ => None, - }; - - if let Some(uv) = maybe_uneval { - if let Some(promoted) = uv.promoted { - let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, - promoted: &Body<'tcx>, - ty, - san_ty| { - if let Err(terr) = verifier.typeck.eq_types( - ty, - san_ty, - locations, - ConstraintCategory::Boring, - ) { - span_mirbug!( - verifier, - promoted, - "bad promoted type ({:?}: {:?}): {:?}", - ty, - san_ty, - terr - ); - }; - }; - - let promoted_body = &self.promoted[promoted]; - self.verify_promoted(promoted_body, location); - - let promoted_ty = promoted_body.return_ty(); - check_err(self, promoted_body, ty, promoted_ty); - } else { - self.typeck.ascribe_user_type( - constant.const_.ty(), - ty::UserType::new(ty::UserTypeKind::TypeOf( - uv.def, - UserArgs { args: uv.args, user_self_ty: None }, - )), - locations.span(self.typeck.body), - ); - } - } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { - let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); - let normalized_ty = self.typeck.normalize(unnormalized_ty, locations); - let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); + fn unsized_feature_enabled(&self) -> bool { + let features = self.tcx().features(); + features.unsized_locals() || features.unsized_fn_params() + } - if let Err(terr) = self.typeck.eq_types( - literal_ty, - normalized_ty, - locations, - ConstraintCategory::Boring, - ) { - span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); - } + /// Equate the inferred type and the annotated type for user type annotations + #[instrument(skip(self), level = "debug")] + fn check_user_type_annotations(&mut self) { + debug!(?self.user_type_annotations); + let tcx = self.tcx(); + for user_annotation in self.user_type_annotations { + let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; + let annotation = self.instantiate_canonical(span, user_ty); + if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind + && let DefKind::InlineConst = tcx.def_kind(def) + { + assert!(annotation.bounds.is_empty()); + self.check_inline_const(inferred_ty, def.expect_local(), args, span); + } else { + self.ascribe_user_type(inferred_ty, annotation, span); } + } + } - if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); - self.typeck.normalize_and_prove_instantiated_predicates( - def_id, - instantiated_predicates, - locations, - ); + #[instrument(skip(self, data), level = "debug")] + fn push_region_constraints( + &mut self, + locations: Locations, + category: ConstraintCategory<'tcx>, + data: &QueryRegionConstraints<'tcx>, + ) { + debug!("constraints generated: {:#?}", data); - assert!(!matches!( - tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)), - Some(DefKind::Impl { of_trait: true }) - )); - self.typeck.prove_predicates( - args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())), - locations, - ConstraintCategory::Boring, - ); - } - } + constraint_conversion::ConstraintConversion::new( + self.infcx, + self.universal_regions, + &self.region_bound_pairs, + self.implicit_region_bound, + self.infcx.param_env, + &self.known_type_outlives_obligations, + locations, + locations.span(self.body), + category, + self.constraints, + ) + .convert_all(data); } - fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { - self.super_local_decl(local, local_decl); + /// Try to relate `sub <: sup` + fn sub_types( + &mut self, + sub: Ty<'tcx>, + sup: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory<'tcx>, + ) -> Result<(), NoSolution> { + // Use this order of parameters because the sup type is usually the + // "expected" type in diagnostics. + self.relate_types(sup, ty::Contravariant, sub, locations, category) + } - for user_ty in - local_decl.user_ty.as_deref().into_iter().flat_map(UserTypeProjections::projections) - { - let span = self.typeck.user_type_annotations[user_ty.base].span; + #[instrument(skip(self, category), level = "debug")] + fn eq_types( + &mut self, + expected: Ty<'tcx>, + found: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory<'tcx>, + ) -> Result<(), NoSolution> { + self.relate_types(expected, ty::Invariant, found, locations, category) + } - let ty = if local_decl.is_nonref_binding() { - local_decl.ty - } else if let &ty::Ref(_, rty, _) = local_decl.ty.kind() { - // If we have a binding of the form `let ref x: T = ..` - // then remove the outermost reference so we can check the - // type annotation for the remaining type. - rty - } else { - bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); - }; + #[instrument(skip(self), level = "debug")] + fn relate_type_and_user_type( + &mut self, + a: Ty<'tcx>, + v: ty::Variance, + user_ty: &UserTypeProjection, + locations: Locations, + category: ConstraintCategory<'tcx>, + ) -> Result<(), NoSolution> { + let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; + trace!(?annotated_type); + let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); - if let Err(terr) = self.typeck.relate_type_and_user_type( - ty, - ty::Invariant, - user_ty, - Locations::All(span), - ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), - ) { - span_mirbug!( - self, - local, - "bad user type on variable {:?}: {:?} != {:?} ({:?})", - local, - local_decl.ty, - local_decl.user_ty, - terr, - ); + let tcx = self.infcx.tcx; + + for proj in &user_ty.projs { + if !self.infcx.next_trait_solver() + && let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() + { + // There is nothing that we can compare here if we go through an opaque type. + // We're always in its defining scope as we can otherwise not project through + // it, so we're constraining it anyways. + return Ok(()); } + let projected_ty = curr_projected_ty.projection_ty_core( + tcx, + proj, + |this, field, ()| { + let ty = this.field_ty(tcx, field); + self.structurally_resolve(ty, locations) + }, + |_, _| unreachable!(), + ); + curr_projected_ty = projected_ty; } - } - - fn visit_body(&mut self, body: &Body<'tcx>) { - // The types of local_decls are checked above which is called in super_body. - self.super_body(body); - } -} + trace!(?curr_projected_ty); -impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { - fn body(&self) -> &Body<'tcx> { - self.typeck.body - } + let ty = curr_projected_ty.ty; + self.relate_types(ty, v.xform(ty::Contravariant), a, locations, category)?; - fn tcx(&self) -> TyCtxt<'tcx> { - self.typeck.infcx.tcx + Ok(()) } - fn verify_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Location) { + fn check_promoted(&mut self, promoted_body: &'a Body<'tcx>, location: Location) { // Determine the constraints from the promoted MIR by running the type // checker on the promoted MIR, then transfer the constraints back to // the main MIR, changing the locations to the provided location. - let parent_body = mem::replace(&mut self.typeck.body, promoted_body); + let parent_body = mem::replace(&mut self.body, promoted_body); // Use new sets of constraints and closure bounds so that we can // modify their locations. @@ -520,24 +510,23 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let mut constraints = Default::default(); let mut liveness_constraints = LivenessValues::without_specific_points(Rc::new(DenseLocationMap::new(promoted_body))); - // Don't try to add borrow_region facts for the promoted MIR + // Don't try to add borrow_region facts for the promoted MIR as they refer + // to the wrong locations. let mut swap_constraints = |this: &mut Self| { - mem::swap(this.typeck.polonius_facts, polonius_facts); - mem::swap(&mut this.typeck.constraints.outlives_constraints, &mut constraints); - mem::swap(&mut this.typeck.constraints.liveness_constraints, &mut liveness_constraints); + mem::swap(this.polonius_facts, polonius_facts); + mem::swap(&mut this.constraints.outlives_constraints, &mut constraints); + mem::swap(&mut this.constraints.liveness_constraints, &mut liveness_constraints); }; swap_constraints(self); self.visit_body(promoted_body); - self.typeck.typeck_mir(promoted_body); + self.body = parent_body; - self.typeck.body = parent_body; // Merge the outlives constraints back in, at the given location. swap_constraints(self); - let locations = location.to_locations(); for constraint in constraints.outlives().iter() { let mut constraint = *constraint; @@ -550,7 +539,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // temporary from the user's point of view. constraint.category = ConstraintCategory::Boring; } - self.typeck.constraints.outlives_constraints.push(constraint) + self.constraints.outlives_constraints.push(constraint) } // If the region is live at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region @@ -560,409 +549,152 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // unordered. #[allow(rustc::potential_query_instability)] for region in liveness_constraints.live_regions_unordered() { - self.typeck.constraints.liveness_constraints.add_location(region, location); + self.constraints.liveness_constraints.add_location(region, location); } } -} -/// The MIR type checker. Visits the MIR and enforces all the -/// constraints needed for it to be valid and well-typed. Along the -/// way, it accrues region constraints -- these can later be used by -/// NLL region checking. -struct TypeChecker<'a, 'tcx> { - infcx: &'a BorrowckInferCtxt<'tcx>, - last_span: Span, - body: &'a Body<'tcx>, - /// User type annotations are shared between the main MIR and the MIR of - /// all of the promoted items. - user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, - region_bound_pairs: RegionBoundPairs<'tcx>, - known_type_outlives_obligations: Vec>, - implicit_region_bound: ty::Region<'tcx>, - reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, - universal_regions: &'a UniversalRegions<'tcx>, - location_table: &'a PoloniusLocationTable, - polonius_facts: &'a mut Option, - borrow_set: &'a BorrowSet<'tcx>, - constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints. - polonius_liveness: Option, + fn check_inline_const( + &mut self, + inferred_ty: Ty<'tcx>, + def_id: LocalDefId, + args: UserArgs<'tcx>, + span: Span, + ) { + assert!(args.user_self_ty.is_none()); + let tcx = self.tcx(); + let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args); + if let Err(terr) = + self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring) + { + span_bug!( + span, + "bad inline const pattern: ({:?} = {:?}) {:?}", + const_ty, + inferred_ty, + terr + ); + } + let args = self.infcx.resolve_vars_if_possible(args.args); + let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); + self.normalize_and_prove_instantiated_predicates( + def_id.to_def_id(), + predicates, + Locations::All(span), + ); + } } -/// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions -/// inference computation. -pub(crate) struct MirTypeckResults<'tcx> { - pub(crate) constraints: MirTypeckRegionConstraints<'tcx>, - pub(crate) universal_region_relations: Frozen>, - pub(crate) opaque_type_values: FxIndexMap, OpaqueHiddenType<'tcx>>, - pub(crate) polonius_context: Option, -} - -/// A collection of region constraints that must be satisfied for the -/// program to be considered well-typed. -pub(crate) struct MirTypeckRegionConstraints<'tcx> { - /// Maps from a `ty::Placeholder` to the corresponding - /// `PlaceholderIndex` bit that we will use for it. - /// - /// To keep everything in sync, do not insert this set - /// directly. Instead, use the `placeholder_region` helper. - pub(crate) placeholder_indices: PlaceholderIndices, - - /// Each time we add a placeholder to `placeholder_indices`, we - /// also create a corresponding "representative" region vid for - /// that wraps it. This vector tracks those. This way, when we - /// convert the same `ty::RePlaceholder(p)` twice, we can map to - /// the same underlying `RegionVid`. - pub(crate) placeholder_index_to_region: IndexVec>, - - /// In general, the type-checker is not responsible for enforcing - /// liveness constraints; this job falls to the region inferencer, - /// which performs a liveness analysis. However, in some limited - /// cases, the MIR type-checker creates temporary regions that do - /// not otherwise appear in the MIR -- in particular, the - /// late-bound regions that it instantiates at call-sites -- and - /// hence it must report on their liveness constraints. - pub(crate) liveness_constraints: LivenessValues, - - pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>, - - pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>, - - pub(crate) universe_causes: FxIndexMap>, - - pub(crate) type_tests: Vec>, -} - -impl<'tcx> MirTypeckRegionConstraints<'tcx> { - /// Creates a `Region` for a given `PlaceholderRegion`, or returns the - /// region that corresponds to a previously created one. - fn placeholder_region( - &mut self, - infcx: &InferCtxt<'tcx>, - placeholder: ty::PlaceholderRegion, - ) -> ty::Region<'tcx> { - let placeholder_index = self.placeholder_indices.insert(placeholder); - match self.placeholder_index_to_region.get(placeholder_index) { - Some(&v) => v, - None => { - let origin = NllRegionVariableOrigin::Placeholder(placeholder); - let region = infcx.next_nll_region_var_in_universe(origin, placeholder.universe); - self.placeholder_index_to_region.push(region); - region - } +impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { + fn visit_span(&mut self, span: Span) { + if !span.is_dummy() { + debug!(?span); + self.last_span = span; } } -} - -/// The `Locations` type summarizes *where* region constraints are -/// required to hold. Normally, this is at a particular point which -/// created the obligation, but for constraints that the user gave, we -/// want the constraint to hold at all points. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -pub enum Locations { - /// Indicates that a type constraint should always be true. This - /// is particularly important in the new borrowck analysis for - /// things like the type of the return slot. Consider this - /// example: - /// - /// ```compile_fail,E0515 - /// fn foo<'a>(x: &'a u32) -> &'a u32 { - /// let y = 22; - /// return &y; // error - /// } - /// ``` - /// - /// Here, we wind up with the signature from the return type being - /// something like `&'1 u32` where `'1` is a universal region. But - /// the type of the return slot `_0` is something like `&'2 u32` - /// where `'2` is an existential region variable. The type checker - /// requires that `&'2 u32 = &'1 u32` -- but at what point? In the - /// older NLL analysis, we required this only at the entry point - /// to the function. By the nature of the constraints, this wound - /// up propagating to all points reachable from start (because - /// `'1` -- as a universal region -- is live everywhere). In the - /// newer analysis, though, this doesn't work: `_0` is considered - /// dead at the start (it has no usable value) and hence this type - /// equality is basically a no-op. Then, later on, when we do `_0 - /// = &'3 y`, that region `'3` never winds up related to the - /// universal region `'1` and hence no error occurs. Therefore, we - /// use Locations::All instead, which ensures that the `'1` and - /// `'2` are equal everything. We also use this for other - /// user-given type annotations; e.g., if the user wrote `let mut - /// x: &'static u32 = ...`, we would ensure that all values - /// assigned to `x` are of `'static` lifetime. - /// - /// The span points to the place the constraint arose. For example, - /// it points to the type in a user-given type annotation. If - /// there's no sensible span then it's DUMMY_SP. - All(Span), - - /// An outlives constraint that only has to hold at a single location, - /// usually it represents a point where references flow from one spot to - /// another (e.g., `x = y`) - Single(Location), -} -impl Locations { - pub fn from_location(&self) -> Option { - match self { - Locations::All(_) => None, - Locations::Single(from_location) => Some(*from_location), - } - } + #[instrument(skip(self, body), level = "debug")] + fn visit_body(&mut self, body: &Body<'tcx>) { + debug_assert!(std::ptr::eq(self.body, body)); - /// Gets a span representing the location. - pub fn span(&self, body: &Body<'_>) -> Span { - match self { - Locations::All(span) => *span, - Locations::Single(l) => body.source_info(*l).span, + for (local, local_decl) in body.local_decls.iter_enumerated() { + self.visit_local_decl(local, local_decl); } - } -} -impl<'a, 'tcx> TypeChecker<'a, 'tcx> { - fn body(&self) -> &Body<'tcx> { - self.body - } + for (block, block_data) in body.basic_blocks.iter_enumerated() { + let mut location = Location { block, statement_index: 0 }; + for stmt in &block_data.statements { + self.visit_statement(stmt, location); + location.statement_index += 1; + } - fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> RegionVid { - if let ty::RePlaceholder(placeholder) = r.kind() { - self.constraints.placeholder_region(self.infcx, placeholder).as_var() - } else { - self.universal_regions.to_region_vid(r) + self.visit_terminator(block_data.terminator(), location); + self.check_iscleanup(block_data); } } - fn unsized_feature_enabled(&self) -> bool { - let features = self.tcx().features(); - features.unsized_locals() || features.unsized_fn_params() - } - - /// Equate the inferred type and the annotated type for user type annotations #[instrument(skip(self), level = "debug")] - fn check_user_type_annotations(&mut self) { - debug!(?self.user_type_annotations); + fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) { + self.super_statement(stmt, location); let tcx = self.tcx(); - for user_annotation in self.user_type_annotations { - let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation; - let annotation = self.instantiate_canonical(span, user_ty); - if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind - && let DefKind::InlineConst = tcx.def_kind(def) - { - assert!(annotation.bounds.is_empty()); - self.check_inline_const(inferred_ty, def.expect_local(), args, span); - } else { - self.ascribe_user_type(inferred_ty, annotation, span); - } - } - } + match &stmt.kind { + StatementKind::Assign(box (place, rv)) => { + // Assignments to temporaries are not "interesting"; + // they are not caused by the user, but rather artifacts + // of lowering. Assignments to other sorts of places *are* interesting + // though. + let category = match place.as_local() { + Some(RETURN_PLACE) => { + let defining_ty = &self.universal_regions.defining_ty; + if defining_ty.is_const() { + if tcx.is_static(defining_ty.def_id()) { + ConstraintCategory::UseAsStatic + } else { + ConstraintCategory::UseAsConst + } + } else { + ConstraintCategory::Return(ReturnConstraint::Normal) + } + } + Some(l) + if matches!( + self.body.local_decls[l].local_info(), + LocalInfo::AggregateTemp + ) => + { + ConstraintCategory::Usage + } + Some(l) if !self.body.local_decls[l].is_user_variable() => { + ConstraintCategory::Boring + } + _ => ConstraintCategory::Assignment, + }; + debug!( + "assignment category: {:?} {:?}", + category, + place.as_local().map(|l| &self.body.local_decls[l]) + ); - #[instrument(skip(self, data), level = "debug")] - fn push_region_constraints( - &mut self, - locations: Locations, - category: ConstraintCategory<'tcx>, - data: &QueryRegionConstraints<'tcx>, - ) { - debug!("constraints generated: {:#?}", data); + let place_ty = place.ty(self.body, tcx).ty; + debug!(?place_ty); + let place_ty = self.normalize(place_ty, location); + debug!("place_ty normalized: {:?}", place_ty); + let rv_ty = rv.ty(self.body, tcx); + debug!(?rv_ty); + let rv_ty = self.normalize(rv_ty, location); + debug!("normalized rv_ty: {:?}", rv_ty); + if let Err(terr) = + self.sub_types(rv_ty, place_ty, location.to_locations(), category) + { + span_mirbug!( + self, + stmt, + "bad assignment ({:?} = {:?}): {:?}", + place_ty, + rv_ty, + terr + ); + } - constraint_conversion::ConstraintConversion::new( - self.infcx, - self.universal_regions, - &self.region_bound_pairs, - self.implicit_region_bound, - self.infcx.param_env, - &self.known_type_outlives_obligations, - locations, - locations.span(self.body), - category, - self.constraints, - ) - .convert_all(data); - } + if let Some(annotation_index) = self.rvalue_user_ty(rv) { + if let Err(terr) = self.relate_type_and_user_type( + rv_ty, + ty::Invariant, + &UserTypeProjection { base: annotation_index, projs: vec![] }, + location.to_locations(), + ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg), + ) { + let annotation = &self.user_type_annotations[annotation_index]; + span_mirbug!( + self, + stmt, + "bad user type on rvalue ({:?} = {:?}): {:?}", + annotation, + rv_ty, + terr + ); + } + } - /// Try to relate `sub <: sup` - fn sub_types( - &mut self, - sub: Ty<'tcx>, - sup: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - // Use this order of parameters because the sup type is usually the - // "expected" type in diagnostics. - self.relate_types(sup, ty::Contravariant, sub, locations, category) - } - - #[instrument(skip(self, category), level = "debug")] - fn eq_types( - &mut self, - expected: Ty<'tcx>, - found: Ty<'tcx>, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - self.relate_types(expected, ty::Invariant, found, locations, category) - } - - #[instrument(skip(self), level = "debug")] - fn relate_type_and_user_type( - &mut self, - a: Ty<'tcx>, - v: ty::Variance, - user_ty: &UserTypeProjection, - locations: Locations, - category: ConstraintCategory<'tcx>, - ) -> Result<(), NoSolution> { - let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty; - trace!(?annotated_type); - let mut curr_projected_ty = PlaceTy::from_ty(annotated_type); - - let tcx = self.infcx.tcx; - - for proj in &user_ty.projs { - if !self.infcx.next_trait_solver() - && let ty::Alias(ty::Opaque, ..) = curr_projected_ty.ty.kind() - { - // There is nothing that we can compare here if we go through an opaque type. - // We're always in its defining scope as we can otherwise not project through - // it, so we're constraining it anyways. - return Ok(()); - } - let projected_ty = curr_projected_ty.projection_ty_core( - tcx, - proj, - |this, field, ()| { - let ty = this.field_ty(tcx, field); - self.structurally_resolve(ty, locations) - }, - |_, _| unreachable!(), - ); - curr_projected_ty = projected_ty; - } - trace!(?curr_projected_ty); - - let ty = curr_projected_ty.ty; - self.relate_types(ty, v.xform(ty::Contravariant), a, locations, category)?; - - Ok(()) - } - - fn check_inline_const( - &mut self, - inferred_ty: Ty<'tcx>, - def_id: LocalDefId, - args: UserArgs<'tcx>, - span: Span, - ) { - assert!(args.user_self_ty.is_none()); - let tcx = self.tcx(); - let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args); - if let Err(terr) = - self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring) - { - span_bug!( - span, - "bad inline const pattern: ({:?} = {:?}) {:?}", - const_ty, - inferred_ty, - terr - ); - } - let args = self.infcx.resolve_vars_if_possible(args.args); - let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span)); - self.normalize_and_prove_instantiated_predicates( - def_id.to_def_id(), - predicates, - Locations::All(span), - ); - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - #[instrument(skip(self, body), level = "debug")] - fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Location) { - let tcx = self.tcx(); - debug!("stmt kind: {:?}", stmt.kind); - match &stmt.kind { - StatementKind::Assign(box (place, rv)) => { - // Assignments to temporaries are not "interesting"; - // they are not caused by the user, but rather artifacts - // of lowering. Assignments to other sorts of places *are* interesting - // though. - let category = match place.as_local() { - Some(RETURN_PLACE) => { - let defining_ty = &self.universal_regions.defining_ty; - if defining_ty.is_const() { - if tcx.is_static(defining_ty.def_id()) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } - } else { - ConstraintCategory::Return(ReturnConstraint::Normal) - } - } - Some(l) - if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) => - { - ConstraintCategory::Usage - } - Some(l) if !body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - _ => ConstraintCategory::Assignment, - }; - debug!( - "assignment category: {:?} {:?}", - category, - place.as_local().map(|l| &body.local_decls[l]) - ); - - let place_ty = place.ty(body, tcx).ty; - debug!(?place_ty); - let place_ty = self.normalize(place_ty, location); - debug!("place_ty normalized: {:?}", place_ty); - let rv_ty = rv.ty(body, tcx); - debug!(?rv_ty); - let rv_ty = self.normalize(rv_ty, location); - debug!("normalized rv_ty: {:?}", rv_ty); - if let Err(terr) = - self.sub_types(rv_ty, place_ty, location.to_locations(), category) - { - span_mirbug!( - self, - stmt, - "bad assignment ({:?} = {:?}): {:?}", - place_ty, - rv_ty, - terr - ); - } - - if let Some(annotation_index) = self.rvalue_user_ty(rv) { - if let Err(terr) = self.relate_type_and_user_type( - rv_ty, - ty::Invariant, - &UserTypeProjection { base: annotation_index, projs: vec![] }, - location.to_locations(), - ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg), - ) { - let annotation = &self.user_type_annotations[annotation_index]; - span_mirbug!( - self, - stmt, - "bad user type on rvalue ({:?} = {:?}): {:?}", - annotation, - rv_ty, - terr - ); - } - } - - self.check_rvalue(body, rv, location); if !self.unsized_feature_enabled() { let trait_ref = ty::TraitRef::new( tcx, @@ -977,7 +709,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } StatementKind::AscribeUserType(box (place, projection), variance) => { - let place_ty = place.ty(body, tcx).ty; + let place_ty = place.ty(self.body, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, *variance, @@ -997,14 +729,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ); } } - StatementKind::Intrinsic(box kind) => match kind { - NonDivergingIntrinsic::Assume(op) => self.check_operand(op, location), - NonDivergingIntrinsic::CopyNonOverlapping(..) => span_bug!( - stmt.source_info.span, - "Unexpected NonDivergingIntrinsic::CopyNonOverlapping, should only appear after lowering_intrinsics", - ), - }, - StatementKind::FakeRead(..) + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(..)) + | StatementKind::FakeRead(..) | StatementKind::StorageLive(..) | StatementKind::StorageDead(..) | StatementKind::Retag { .. } @@ -1013,19 +739,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | StatementKind::PlaceMention(..) | StatementKind::BackwardIncompatibleDropHint { .. } | StatementKind::Nop => {} - StatementKind::Deinit(..) | StatementKind::SetDiscriminant { .. } => { + StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(..)) + | StatementKind::Deinit(..) + | StatementKind::SetDiscriminant { .. } => { bug!("Statement not allowed in this MIR phase") } } } - #[instrument(skip(self, body, term_location), level = "debug")] - fn check_terminator( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - term_location: Location, - ) { + #[instrument(skip(self), level = "debug")] + fn visit_terminator(&mut self, term: &Terminator<'tcx>, term_location: Location) { + self.super_terminator(term, term_location); let tcx = self.tcx(); debug!("terminator kind: {:?}", term.kind); match &term.kind { @@ -1043,9 +767,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } TerminatorKind::SwitchInt { discr, .. } => { - self.check_operand(discr, term_location); - - let switch_ty = discr.ty(body, tcx); + let switch_ty = discr.ty(self.body, tcx); if !switch_ty.is_integral() && !switch_ty.is_char() && !switch_ty.is_bool() { span_mirbug!(self, term, "bad SwitchInt discr ty {:?}", switch_ty); } @@ -1059,12 +781,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { _ => unreachable!(), }; - self.check_operand(func, term_location); - for arg in args { - self.check_operand(&arg.node, term_location); - } - - let func_ty = func.ty(body, tcx); + let func_ty = func.ty(self.body, tcx); debug!("func_ty.kind: {:?}", func_ty.kind()); let sig = match func_ty.kind() { @@ -1132,7 +849,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } if let TerminatorKind::Call { destination, target, .. } = term.kind { - self.check_call_dest(body, term, &sig, destination, target, term_location); + self.check_call_dest(term, &sig, destination, target, term_location); } // The ordinary liveness rules will ensure that all @@ -1147,32 +864,28 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.constraints.liveness_constraints.add_location(region_vid, term_location); } - self.check_call_inputs(body, term, func, &sig, args, term_location, call_source); + self.check_call_inputs(term, func, &sig, args, term_location, call_source); } TerminatorKind::Assert { cond, msg, .. } => { - self.check_operand(cond, term_location); - - let cond_ty = cond.ty(body, tcx); + let cond_ty = cond.ty(self.body, tcx); if cond_ty != tcx.types.bool { span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty); } if let AssertKind::BoundsCheck { len, index } = &**msg { - if len.ty(body, tcx) != tcx.types.usize { + if len.ty(self.body, tcx) != tcx.types.usize { span_mirbug!(self, len, "bounds-check length non-usize {:?}", len) } - if index.ty(body, tcx) != tcx.types.usize { + if index.ty(self.body, tcx) != tcx.types.usize { span_mirbug!(self, index, "bounds-check index non-usize {:?}", index) } } } TerminatorKind::Yield { value, resume_arg, .. } => { - self.check_operand(value, term_location); - - match body.yield_ty() { + match self.body.yield_ty() { None => span_mirbug!(self, term, "yield in non-coroutine"), Some(ty) => { - let value_ty = value.ty(body, tcx); + let value_ty = value.ty(self.body, tcx); if let Err(terr) = self.sub_types( value_ty, ty, @@ -1191,10 +904,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - match body.resume_ty() { + match self.body.resume_ty() { None => span_mirbug!(self, term, "yield in non-coroutine"), Some(ty) => { - let resume_ty = resume_arg.ty(body, tcx); + let resume_ty = resume_arg.ty(self.body, tcx); if let Err(terr) = self.sub_types( ty, resume_ty.ty, @@ -1216,469 +929,146 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } - fn check_call_dest( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - sig: &ty::FnSig<'tcx>, - destination: Place<'tcx>, - target: Option, - term_location: Location, - ) { - let tcx = self.tcx(); - match target { - Some(_) => { - let dest_ty = destination.ty(body, tcx).ty; - let dest_ty = self.normalize(dest_ty, term_location); - let category = match destination.as_local() { - Some(RETURN_PLACE) => { - if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) = - self.universal_regions.defining_ty - { - if tcx.is_static(def_id) { - ConstraintCategory::UseAsStatic - } else { - ConstraintCategory::UseAsConst - } - } else { - ConstraintCategory::Return(ReturnConstraint::Normal) - } - } - Some(l) if !body.local_decls[l].is_user_variable() => { - ConstraintCategory::Boring - } - // The return type of a call is interesting for diagnostics. - _ => ConstraintCategory::Assignment, - }; + fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { + self.super_local_decl(local, local_decl); - let locations = term_location.to_locations(); + for user_ty in + local_decl.user_ty.as_deref().into_iter().flat_map(UserTypeProjections::projections) + { + let span = self.user_type_annotations[user_ty.base].span; - if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { - span_mirbug!( - self, - term, - "call dest mismatch ({:?} <- {:?}): {:?}", - dest_ty, - sig.output(), - terr - ); - } + let ty = if local_decl.is_nonref_binding() { + local_decl.ty + } else if let &ty::Ref(_, rty, _) = local_decl.ty.kind() { + // If we have a binding of the form `let ref x: T = ..` + // then remove the outermost reference so we can check the + // type annotation for the remaining type. + rty + } else { + bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); + }; - // When `unsized_fn_params` and `unsized_locals` are both not enabled, - // this check is done at `check_local`. - if self.unsized_feature_enabled() { - let span = term.source_info.span; - self.ensure_place_sized(dest_ty, span); - } + if let Err(terr) = self.relate_type_and_user_type( + ty, + ty::Invariant, + user_ty, + Locations::All(span), + ConstraintCategory::TypeAnnotation(AnnotationSource::Declaration), + ) { + span_mirbug!( + self, + local, + "bad user type on variable {:?}: {:?} != {:?} ({:?})", + local, + local_decl.ty, + local_decl.user_ty, + terr, + ); } - None => { - // The signature in this call can reference region variables, - // so erase them before calling a query. - let output_ty = self.tcx().erase_regions(sig.output()); - if !output_ty.is_privately_uninhabited( - self.tcx(), - self.infcx.typing_env(self.infcx.param_env), - ) { - span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); - } - } - } - } - - #[instrument(level = "debug", skip(self, body, term, func, term_location, call_source))] - fn check_call_inputs( - &mut self, - body: &Body<'tcx>, - term: &Terminator<'tcx>, - func: &Operand<'tcx>, - sig: &ty::FnSig<'tcx>, - args: &[Spanned>], - term_location: Location, - call_source: CallSource, - ) { - if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { - span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); } - let func_ty = func.ty(body, self.infcx.tcx); - if let ty::FnDef(def_id, _) = *func_ty.kind() { - // Some of the SIMD intrinsics are special: they need a particular argument to be a - // constant. (Eventually this should use const-generics, but those are not up for the - // task yet: https://github.com/rust-lang/rust/issues/85229.) - if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) = - self.tcx().intrinsic(def_id).map(|i| i.name) - { - let idx = match name { - sym::simd_shuffle => 2, - _ => 1, - }; - if !matches!(args[idx], Spanned { node: Operand::Constant(_), .. }) { - self.tcx().dcx().emit_err(SimdIntrinsicArgConst { - span: term.source_info.span, - arg: idx + 1, - intrinsic: name.to_string(), - }); + // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls + // and nullary ops are checked in `check_call_dest`. + if !self.unsized_feature_enabled() { + match self.body.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Arg => { + // return values of normal functions are required to be + // sized by typeck, but return values of ADT constructors are + // not because we don't include a `Self: Sized` bounds on them. + // + // Unbound parts of arguments were never required to be Sized + // - maybe we should make that a warning. + return; + } + LocalKind::Temp => { + let span = local_decl.source_info.span; + let ty = local_decl.ty; + self.ensure_place_sized(ty, span); } } } - debug!(?func_ty); + } - for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { - let op_arg_ty = op_arg.node.ty(body, self.tcx()); + #[instrument(skip(self), level = "debug")] + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + self.super_rvalue(rvalue, location); + let tcx = self.tcx(); + let span = self.body.source_info(location).span; + match rvalue { + Rvalue::Aggregate(ak, ops) => self.check_aggregate_rvalue(rvalue, ak, ops, location), - let op_arg_ty = self.normalize(op_arg_ty, term_location); - let category = if call_source.from_hir_call() { - ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) - } else { - ConstraintCategory::Boring - }; - if let Err(terr) = - self.sub_types(op_arg_ty, *fn_arg, term_location.to_locations(), category) - { - span_mirbug!( - self, - term, - "bad arg #{:?} ({:?} <- {:?}): {:?}", - n, - fn_arg, - op_arg_ty, - terr + Rvalue::Repeat(operand, len) => { + let array_ty = rvalue.ty(self.body.local_decls(), tcx); + self.prove_predicate( + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())), + Locations::Single(location), + ConstraintCategory::Boring, ); - } - } - } - - fn check_iscleanup(&mut self, body: &Body<'tcx>, block_data: &BasicBlockData<'tcx>) { - let is_cleanup = block_data.is_cleanup; - self.last_span = block_data.terminator().source_info.span; - match block_data.terminator().kind { - TerminatorKind::Goto { target } => { - self.assert_iscleanup(body, block_data, target, is_cleanup) - } - TerminatorKind::SwitchInt { ref targets, .. } => { - for target in targets.all_targets() { - self.assert_iscleanup(body, block_data, *target, is_cleanup); - } - } - TerminatorKind::UnwindResume => { - if !is_cleanup { - span_mirbug!(self, block_data, "resume on non-cleanup block!") - } - } - TerminatorKind::UnwindTerminate(_) => { - if !is_cleanup { - span_mirbug!(self, block_data, "terminate on non-cleanup block!") - } - } - TerminatorKind::Return => { - if is_cleanup { - span_mirbug!(self, block_data, "return on cleanup block") - } - } - TerminatorKind::TailCall { .. } => { - if is_cleanup { - span_mirbug!(self, block_data, "tailcall on cleanup block") - } - } - TerminatorKind::CoroutineDrop { .. } => { - if is_cleanup { - span_mirbug!(self, block_data, "coroutine_drop in cleanup block") - } - } - TerminatorKind::Yield { resume, drop, .. } => { - if is_cleanup { - span_mirbug!(self, block_data, "yield in cleanup block") - } - self.assert_iscleanup(body, block_data, resume, is_cleanup); - if let Some(drop) = drop { - self.assert_iscleanup(body, block_data, drop, is_cleanup); - } - } - TerminatorKind::Unreachable => {} - TerminatorKind::Drop { target, unwind, .. } - | TerminatorKind::Assert { target, unwind, .. } => { - self.assert_iscleanup(body, block_data, target, is_cleanup); - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - TerminatorKind::Call { ref target, unwind, .. } => { - if let &Some(target) = target { - self.assert_iscleanup(body, block_data, target, is_cleanup); - } - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - TerminatorKind::FalseEdge { real_target, imaginary_target } => { - self.assert_iscleanup(body, block_data, real_target, is_cleanup); - self.assert_iscleanup(body, block_data, imaginary_target, is_cleanup); - } - TerminatorKind::FalseUnwind { real_target, unwind } => { - self.assert_iscleanup(body, block_data, real_target, is_cleanup); - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - TerminatorKind::InlineAsm { ref targets, unwind, .. } => { - for &target in targets { - self.assert_iscleanup(body, block_data, target, is_cleanup); - } - self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup); - } - } - } - fn assert_iscleanup( - &mut self, - body: &Body<'tcx>, - ctxt: &dyn fmt::Debug, - bb: BasicBlock, - iscleanuppad: bool, - ) { - if body[bb].is_cleanup != iscleanuppad { - span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad); - } - } + // If the length cannot be evaluated we must assume that the length can be larger + // than 1. + // If the length is larger than 1, the repeat expression will need to copy the + // element, so we require the `Copy` trait. + if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) { + match operand { + Operand::Copy(..) | Operand::Constant(..) => { + // These are always okay: direct use of a const, or a value that can + // evidently be copied. + } + Operand::Move(place) => { + // Make sure that repeated elements implement `Copy`. + let ty = place.ty(self.body, tcx).ty; + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Copy, Some(span)), + [ty], + ); - fn assert_iscleanup_unwind( - &mut self, - body: &Body<'tcx>, - ctxt: &dyn fmt::Debug, - unwind: UnwindAction, - is_cleanup: bool, - ) { - match unwind { - UnwindAction::Cleanup(unwind) => { - if is_cleanup { - span_mirbug!(self, ctxt, "unwind on cleanup block") - } - self.assert_iscleanup(body, ctxt, unwind, true); - } - UnwindAction::Continue => { - if is_cleanup { - span_mirbug!(self, ctxt, "unwind on cleanup block") + self.prove_trait_ref( + trait_ref, + Locations::Single(location), + ConstraintCategory::CopyBound, + ); + } + } } } - UnwindAction::Unreachable | UnwindAction::Terminate(_) => (), - } - } - - fn check_local(&mut self, body: &Body<'tcx>, local: Local, local_decl: &LocalDecl<'tcx>) { - match body.local_kind(local) { - LocalKind::ReturnPointer | LocalKind::Arg => { - // return values of normal functions are required to be - // sized by typeck, but return values of ADT constructors are - // not because we don't include a `Self: Sized` bounds on them. - // - // Unbound parts of arguments were never required to be Sized - // - maybe we should make that a warning. - return; - } - LocalKind::Temp => {} - } - - // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls - // and nullary ops are checked in `check_call_dest`. - if !self.unsized_feature_enabled() { - let span = local_decl.source_info.span; - let ty = local_decl.ty; - self.ensure_place_sized(ty, span); - } - } - fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) { - let tcx = self.tcx(); + &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Sized, Some(span)), + [ty], + ); - // Erase the regions from `ty` to get a global type. The - // `Sized` bound in no way depends on precise regions, so this - // shouldn't affect `is_sized`. - let erased_ty = tcx.erase_regions(ty); - // FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here. - if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) { - // in current MIR construction, all non-control-flow rvalue - // expressions evaluate through `as_temp` or `into` a return - // slot or local, so to find all unsized rvalues it is enough - // to check all temps, return slots and locals. - if self.reported_errors.replace((ty, span)).is_none() { - // While this is located in `nll::typeck` this error is not - // an NLL error, it's a required check to prevent creation - // of unsized rvalues in a call expression. - self.tcx().dcx().emit_err(MoveUnsized { ty, span }); + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); } - } - } + &Rvalue::NullaryOp(NullOp::ContractChecks, _) => {} + &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} - fn aggregate_field_ty( - &mut self, - ak: &AggregateKind<'tcx>, - field_index: FieldIdx, - location: Location, - ) -> Result, FieldAccessError> { - let tcx = self.tcx(); + Rvalue::ShallowInitBox(_operand, ty) => { + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Sized, Some(span)), + [*ty], + ); - match *ak { - AggregateKind::Adt(adt_did, variant_index, args, _, active_field_index) => { - let def = tcx.adt_def(adt_did); - let variant = &def.variant(variant_index); - let adj_field_index = active_field_index.unwrap_or(field_index); - if let Some(field) = variant.fields.get(adj_field_index) { - Ok(self.normalize(field.ty(tcx, args), location)) - } else { - Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) - } - } - AggregateKind::Closure(_, args) => { - match args.as_closure().upvar_tys().get(field_index.as_usize()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_closure().upvar_tys().len(), - }), - } - } - AggregateKind::Coroutine(_, args) => { - // It doesn't make sense to look at a field beyond the prefix; - // these require a variant index, and are not initialized in - // aggregate rvalues. - match args.as_coroutine().prefix_tys().get(field_index.as_usize()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_coroutine().prefix_tys().len(), - }), - } - } - AggregateKind::CoroutineClosure(_, args) => { - match args.as_coroutine_closure().upvar_tys().get(field_index.as_usize()) { - Some(ty) => Ok(*ty), - None => Err(FieldAccessError::OutOfRange { - field_count: args.as_coroutine_closure().upvar_tys().len(), - }), - } - } - AggregateKind::Array(ty) => Ok(ty), - AggregateKind::Tuple | AggregateKind::RawPtr(..) => { - unreachable!("This should have been covered in check_rvalues"); - } - } - } - - fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) { - debug!(?op, ?location, "check_operand"); - - if let Operand::Constant(constant) = op { - let maybe_uneval = match constant.const_ { - Const::Val(..) | Const::Ty(_, _) => None, - Const::Unevaluated(uv, _) => Some(uv), - }; - - if let Some(uv) = maybe_uneval { - if uv.promoted.is_none() { - let tcx = self.tcx(); - let def_id = uv.def; - if tcx.def_kind(def_id) == DefKind::InlineConst { - let def_id = def_id.expect_local(); - let predicates = self.prove_closure_bounds( - tcx, - def_id, - uv.args, - location.to_locations(), - ); - self.normalize_and_prove_instantiated_predicates( - def_id.to_def_id(), - predicates, - location.to_locations(), - ); - } - } - } - } - } - - #[instrument(skip(self, body), level = "debug")] - fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - let tcx = self.tcx(); - let span = body.source_info(location).span; - - match rvalue { - Rvalue::Aggregate(ak, ops) => { - for op in ops { - self.check_operand(op, location); - } - self.check_aggregate_rvalue(body, rvalue, ak, ops, location) - } - - Rvalue::Repeat(operand, len) => { - self.check_operand(operand, location); - - let array_ty = rvalue.ty(body.local_decls(), tcx); - self.prove_predicate( - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(array_ty.into())), - Locations::Single(location), - ConstraintCategory::Boring, - ); - - // If the length cannot be evaluated we must assume that the length can be larger - // than 1. - // If the length is larger than 1, the repeat expression will need to copy the - // element, so we require the `Copy` trait. - if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) { - match operand { - Operand::Copy(..) | Operand::Constant(..) => { - // These are always okay: direct use of a const, or a value that can - // evidently be copied. - } - Operand::Move(place) => { - // Make sure that repeated elements implement `Copy`. - let ty = place.ty(body, tcx).ty; - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Copy, Some(span)), - [ty], - ); - - self.prove_trait_ref( - trait_ref, - Locations::Single(location), - ConstraintCategory::CopyBound, - ); - } - } - } - } - - &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [ty], - ); - - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::SizedBound, - ); - } - &Rvalue::NullaryOp(NullOp::ContractChecks, _) => {} - &Rvalue::NullaryOp(NullOp::UbChecks, _) => {} - - Rvalue::ShallowInitBox(operand, ty) => { - self.check_operand(operand, location); - - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Sized, Some(span)), - [*ty], - ); - - self.prove_trait_ref( - trait_ref, - location.to_locations(), - ConstraintCategory::SizedBound, - ); + self.prove_trait_ref( + trait_ref, + location.to_locations(), + ConstraintCategory::SizedBound, + ); } Rvalue::Cast(cast_kind, op, ty) => { - self.check_operand(op, location); - match *cast_kind { CastKind::PointerCoercion(PointerCoercion::ReifyFnPointer, coercion_source) => { let is_implicit_coercion = coercion_source == CoercionSource::Implicit; - let src_ty = op.ty(body, tcx); + let src_ty = op.ty(self.body, tcx); let mut src_sig = src_ty.fn_sig(tcx); if let ty::FnDef(def_id, _) = src_ty.kind() && let ty::FnPtr(_, target_hdr) = *ty.kind() @@ -1687,7 +1077,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { && let Some(safe_sig) = tcx.adjust_target_feature_sig( *def_id, src_sig, - body.source.def_id(), + self.body.source.def_id(), ) { src_sig = safe_sig; @@ -1780,7 +1170,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { PointerCoercion::ClosureFnPointer(safety), coercion_source, ) => { - let sig = match op.ty(body, tcx).kind() { + let sig = match op.ty(self.body, tcx).kind() { ty::Closure(_, args) => args.as_closure().sig(), _ => bug!(), }; @@ -1809,7 +1199,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { PointerCoercion::UnsafeFnPointer, coercion_source, ) => { - let fn_sig = op.ty(body, tcx).fn_sig(tcx); + let fn_sig = op.ty(self.body, tcx).fn_sig(tcx); // The type that we see in the fcx is like // `foo::<'a, 'b>`, where `foo` is the path to a @@ -1843,7 +1233,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let trait_ref = ty::TraitRef::new( tcx, tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), - [op.ty(body, tcx), ty], + [op.ty(self.body, tcx), ty], ); let is_implicit_coercion = coercion_source == CoercionSource::Implicit; @@ -1869,7 +1259,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { _ => panic!("Invalid dyn* cast_ty"), }; - let self_ty = op.ty(body, tcx); + let self_ty = op.ty(self.body, tcx); let is_implicit_coercion = coercion_source == CoercionSource::Implicit; self.prove_predicates( @@ -1896,7 +1286,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { PointerCoercion::MutToConstPointer, coercion_source, ) => { - let ty::RawPtr(ty_from, hir::Mutability::Mut) = op.ty(body, tcx).kind() + let ty::RawPtr(ty_from, hir::Mutability::Mut) = + op.ty(self.body, tcx).kind() else { span_mirbug!(self, rvalue, "unexpected base type for cast {:?}", ty,); return; @@ -1924,7 +1315,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::PointerCoercion(PointerCoercion::ArrayToPointer, coercion_source) => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let opt_ty_elem_mut = match ty_from.kind() { ty::RawPtr(array_ty, array_mut) => match array_ty.kind() { @@ -1987,7 +1378,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::PointerExposeProvenance => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2005,7 +1396,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::PointerWithExposedProvenance => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2022,7 +1413,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } CastKind::IntToInt => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2039,7 +1430,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } CastKind::IntToFloat => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2056,7 +1447,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } CastKind::FloatToInt => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2073,7 +1464,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } CastKind::FloatToFloat => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2090,7 +1481,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } CastKind::FnPtrToPtr => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2107,7 +1498,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } CastKind::PtrToPtr => { - let ty_from = op.ty(body, tcx); + let ty_from = op.ty(self.body, tcx); let cast_ty_from = CastTy::from_ty(ty_from); let cast_ty_to = CastTy::from_ty(*ty); match (cast_ty_from, cast_ty_to) { @@ -2121,168 +1512,704 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // // Note that other checks (such as denying `dyn Send` -> `dyn // Debug`) are in `rustc_hir_typeck`. - if let ty::Dynamic(src_tty, ..) = src_tail.kind() - && let ty::Dynamic(dst_tty, ..) = dst_tail.kind() + if let ty::Dynamic(src_tty, _src_lt, ty::Dyn) = *src_tail.kind() + && let ty::Dynamic(dst_tty, dst_lt, ty::Dyn) = *dst_tail.kind() && src_tty.principal().is_some() && dst_tty.principal().is_some() { // Remove auto traits. // Auto trait checks are handled in `rustc_hir_typeck` as FCW. - let src_obj = tcx.mk_ty_from_kind(ty::Dynamic( + let src_obj = Ty::new_dynamic( + tcx, tcx.mk_poly_existential_predicates( &src_tty.without_auto_traits().collect::>(), ), - tcx.lifetimes.re_static, + // FIXME: Once we disallow casting `*const dyn Trait + 'short` + // to `*const dyn Trait + 'long`, then this can just be `src_lt`. + dst_lt, ty::Dyn, - )); - let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic( + ); + let dst_obj = Ty::new_dynamic( + tcx, tcx.mk_poly_existential_predicates( &dst_tty.without_auto_traits().collect::>(), ), - tcx.lifetimes.re_static, + dst_lt, ty::Dyn, - )); + ); + + debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); + + self.sub_types( + src_obj, + dst_obj, + location.to_locations(), + ConstraintCategory::Cast { + is_implicit_coercion: false, + unsize_to: None, + }, + ) + .unwrap(); + } + } + _ => { + span_mirbug!( + self, + rvalue, + "Invalid PtrToPtr cast {:?} -> {:?}", + ty_from, + ty + ) + } + } + } + CastKind::Transmute => { + span_mirbug!( + self, + rvalue, + "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", + ); + } + } + } + + Rvalue::Ref(region, _borrow_kind, borrowed_place) => { + self.add_reborrow_constraint(location, *region, borrowed_place); + } + + Rvalue::BinaryOp( + BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, + box (left, right), + ) => { + let ty_left = left.ty(self.body, tcx); + match ty_left.kind() { + // Types with regions are comparable if they have a common super-type. + ty::RawPtr(_, _) | ty::FnPtr(..) => { + let ty_right = right.ty(self.body, tcx); + let common_ty = + self.infcx.next_ty_var(self.body.source_info(location).span); + self.sub_types( + ty_left, + common_ty, + location.to_locations(), + ConstraintCategory::CallArgument(None), + ) + .unwrap_or_else(|err| { + bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) + }); + if let Err(terr) = self.sub_types( + ty_right, + common_ty, + location.to_locations(), + ConstraintCategory::CallArgument(None), + ) { + span_mirbug!( + self, + rvalue, + "unexpected comparison types {:?} and {:?} yields {:?}", + ty_left, + ty_right, + terr + ) + } + } + // For types with no regions we can just check that the + // both operands have the same type. + ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) + if ty_left == right.ty(self.body, tcx) => {} + // Other types are compared by trait methods, not by + // `Rvalue::BinaryOp`. + _ => span_mirbug!( + self, + rvalue, + "unexpected comparison types {:?} and {:?}", + ty_left, + right.ty(self.body, tcx) + ), + } + } + + Rvalue::WrapUnsafeBinder(op, ty) => { + let operand_ty = op.ty(self.body, self.tcx()); + let ty::UnsafeBinder(binder_ty) = *ty.kind() else { + unreachable!(); + }; + let expected_ty = self.infcx.instantiate_binder_with_fresh_vars( + self.body().source_info(location).span, + BoundRegionConversionTime::HigherRankedType, + binder_ty.into(), + ); + self.sub_types( + operand_ty, + expected_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) + .unwrap(); + } + + Rvalue::Use(_) + | Rvalue::UnaryOp(_, _) + | Rvalue::CopyForDeref(_) + | Rvalue::BinaryOp(..) + | Rvalue::RawPtr(..) + | Rvalue::ThreadLocalRef(..) + | Rvalue::Len(..) + | Rvalue::Discriminant(..) + | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {} + } + } + + #[instrument(level = "debug", skip(self))] + fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) { + self.super_operand(op, location); + if let Operand::Constant(constant) = op { + let maybe_uneval = match constant.const_ { + Const::Val(..) | Const::Ty(_, _) => None, + Const::Unevaluated(uv, _) => Some(uv), + }; - // Replace trait object lifetimes with fresh vars, to allow - // casts like - // `*mut dyn FnOnce() + 'a` -> `*mut dyn FnOnce() + 'static` - let src_obj = - freshen_single_trait_object_lifetime(self.infcx, src_obj); - let dst_obj = - freshen_single_trait_object_lifetime(self.infcx, dst_obj); + if let Some(uv) = maybe_uneval { + if uv.promoted.is_none() { + let tcx = self.tcx(); + let def_id = uv.def; + if tcx.def_kind(def_id) == DefKind::InlineConst { + let def_id = def_id.expect_local(); + let predicates = self.prove_closure_bounds( + tcx, + def_id, + uv.args, + location.to_locations(), + ); + self.normalize_and_prove_instantiated_predicates( + def_id.to_def_id(), + predicates, + location.to_locations(), + ); + } + } + } + } + } + + #[instrument(level = "debug", skip(self))] + fn visit_const_operand(&mut self, constant: &ConstOperand<'tcx>, location: Location) { + self.super_const_operand(constant, location); + let ty = constant.const_.ty(); + + self.infcx.tcx.for_each_free_region(&ty, |live_region| { + let live_region_vid = self.universal_regions.to_region_vid(live_region); + self.constraints.liveness_constraints.add_location(live_region_vid, location); + }); + + let locations = location.to_locations(); + if let Some(annotation_index) = constant.user_ty { + if let Err(terr) = self.relate_type_and_user_type( + constant.const_.ty(), + ty::Invariant, + &UserTypeProjection { base: annotation_index, projs: vec![] }, + locations, + ConstraintCategory::TypeAnnotation(AnnotationSource::GenericArg), + ) { + let annotation = &self.user_type_annotations[annotation_index]; + span_mirbug!( + self, + constant, + "bad constant user type {:?} vs {:?}: {:?}", + annotation, + constant.const_.ty(), + terr, + ); + } + } else { + let tcx = self.tcx(); + let maybe_uneval = match constant.const_ { + Const::Ty(_, ct) => match ct.kind() { + ty::ConstKind::Unevaluated(uv) => { + Some(UnevaluatedConst { def: uv.def, args: uv.args, promoted: None }) + } + _ => None, + }, + Const::Unevaluated(uv, _) => Some(uv), + _ => None, + }; + + if let Some(uv) = maybe_uneval { + if let Some(promoted) = uv.promoted { + let promoted_body = &self.promoted[promoted]; + self.check_promoted(promoted_body, location); + let promoted_ty = promoted_body.return_ty(); + if let Err(terr) = + self.eq_types(ty, promoted_ty, locations, ConstraintCategory::Boring) + { + span_mirbug!( + self, + promoted, + "bad promoted type ({:?}: {:?}): {:?}", + ty, + promoted_ty, + terr + ); + }; + } else { + self.ascribe_user_type( + constant.const_.ty(), + ty::UserType::new(ty::UserTypeKind::TypeOf( + uv.def, + UserArgs { args: uv.args, user_self_ty: None }, + )), + locations.span(self.body), + ); + } + } else if let Some(static_def_id) = constant.check_static_ptr(tcx) { + let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity(); + let normalized_ty = self.normalize(unnormalized_ty, locations); + let literal_ty = constant.const_.ty().builtin_deref(true).unwrap(); + + if let Err(terr) = + self.eq_types(literal_ty, normalized_ty, locations, ConstraintCategory::Boring) + { + span_mirbug!(self, constant, "bad static type {:?} ({:?})", constant, terr); + } + } else if let Const::Ty(_, ct) = constant.const_ + && let ty::ConstKind::Param(p) = ct.kind() + { + let body_def_id = self.universal_regions.defining_ty.def_id(); + let const_param = tcx.generics_of(body_def_id).const_param(p, tcx); + self.ascribe_user_type( + constant.const_.ty(), + ty::UserType::new(ty::UserTypeKind::TypeOf( + const_param.def_id, + UserArgs { + args: self.universal_regions.defining_ty.args(), + user_self_ty: None, + }, + )), + locations.span(self.body), + ); + } + + if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() { + let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args); + self.normalize_and_prove_instantiated_predicates( + def_id, + instantiated_predicates, + locations, + ); + + assert!(!matches!( + tcx.impl_of_method(def_id).map(|imp| tcx.def_kind(imp)), + Some(DefKind::Impl { of_trait: true }) + )); + self.prove_predicates( + args.types().map(|ty| ty::ClauseKind::WellFormed(ty.into())), + locations, + ConstraintCategory::Boring, + ); + } + } + } + + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) { + self.super_place(place, context, location); + let tcx = self.tcx(); + let place_ty = place.ty(self.body, tcx); + if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context { + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Copy, Some(self.last_span)), + [place_ty.ty], + ); + + // To have a `Copy` operand, the type `T` of the + // value must be `Copy`. Note that we prove that `T: Copy`, + // rather than using the `is_copy_modulo_regions` + // test. This is important because + // `is_copy_modulo_regions` ignores the resulting region + // obligations and assumes they pass. This can result in + // bounds from `Copy` impls being unsoundly ignored (e.g., + // #29149). Note that we decide to use `Copy` before knowing + // whether the bounds fully apply: in effect, the rule is + // that if a value of some type could implement `Copy`, then + // it must. + self.prove_trait_ref(trait_ref, location.to_locations(), ConstraintCategory::CopyBound); + } + } + + fn visit_projection_elem( + &mut self, + place: PlaceRef<'tcx>, + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + let tcx = self.tcx(); + let base_ty = place.ty(self.body(), tcx); + match elem { + // All these projections don't add any constraints, so there's nothing to + // do here. We check their invariants in the MIR validator after all. + ProjectionElem::Deref + | ProjectionElem::Index(_) + | ProjectionElem::ConstantIndex { .. } + | ProjectionElem::Subslice { .. } + | ProjectionElem::Downcast(..) => {} + ProjectionElem::Field(field, fty) => { + let fty = self.normalize(fty, location); + let ty = base_ty.field_ty(tcx, field); + let ty = self.normalize(ty, location); + debug!(?fty, ?ty); + + if let Err(terr) = self.relate_types( + ty, + context.ambient_variance(), + fty, + location.to_locations(), + ConstraintCategory::Boring, + ) { + span_mirbug!(self, place, "bad field access ({:?}: {:?}): {:?}", ty, fty, terr); + } + } + ProjectionElem::OpaqueCast(ty) => { + let ty = self.normalize(ty, location); + self.relate_types( + ty, + context.ambient_variance(), + base_ty.ty, + location.to_locations(), + ConstraintCategory::TypeAnnotation(AnnotationSource::OpaqueCast), + ) + .unwrap(); + } + ProjectionElem::UnwrapUnsafeBinder(ty) => { + let ty::UnsafeBinder(binder_ty) = *base_ty.ty.kind() else { + unreachable!(); + }; + let found_ty = self.infcx.instantiate_binder_with_fresh_vars( + self.body.source_info(location).span, + BoundRegionConversionTime::HigherRankedType, + binder_ty.into(), + ); + self.relate_types( + ty, + context.ambient_variance(), + found_ty, + location.to_locations(), + ConstraintCategory::Boring, + ) + .unwrap(); + } + ProjectionElem::Subtype(_) => { + bug!("ProjectionElem::Subtype shouldn't exist in borrowck") + } + } + } +} + +impl<'a, 'tcx> TypeChecker<'a, 'tcx> { + fn check_call_dest( + &mut self, + term: &Terminator<'tcx>, + sig: &ty::FnSig<'tcx>, + destination: Place<'tcx>, + target: Option, + term_location: Location, + ) { + let tcx = self.tcx(); + match target { + Some(_) => { + let dest_ty = destination.ty(self.body, tcx).ty; + let dest_ty = self.normalize(dest_ty, term_location); + let category = match destination.as_local() { + Some(RETURN_PLACE) => { + if let DefiningTy::Const(def_id, _) | DefiningTy::InlineConst(def_id, _) = + self.universal_regions.defining_ty + { + if tcx.is_static(def_id) { + ConstraintCategory::UseAsStatic + } else { + ConstraintCategory::UseAsConst + } + } else { + ConstraintCategory::Return(ReturnConstraint::Normal) + } + } + Some(l) if !self.body.local_decls[l].is_user_variable() => { + ConstraintCategory::Boring + } + // The return type of a call is interesting for diagnostics. + _ => ConstraintCategory::Assignment, + }; + + let locations = term_location.to_locations(); + + if let Err(terr) = self.sub_types(sig.output(), dest_ty, locations, category) { + span_mirbug!( + self, + term, + "call dest mismatch ({:?} <- {:?}): {:?}", + dest_ty, + sig.output(), + terr + ); + } + + // When `unsized_fn_params` and `unsized_locals` are both not enabled, + // this check is done at `check_local`. + if self.unsized_feature_enabled() { + let span = term.source_info.span; + self.ensure_place_sized(dest_ty, span); + } + } + None => { + // The signature in this call can reference region variables, + // so erase them before calling a query. + let output_ty = self.tcx().erase_regions(sig.output()); + if !output_ty.is_privately_uninhabited( + self.tcx(), + self.infcx.typing_env(self.infcx.param_env), + ) { + span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); + } + } + } + } + + #[instrument(level = "debug", skip(self, term, func, term_location, call_source))] + fn check_call_inputs( + &mut self, + term: &Terminator<'tcx>, + func: &Operand<'tcx>, + sig: &ty::FnSig<'tcx>, + args: &[Spanned>], + term_location: Location, + call_source: CallSource, + ) { + if args.len() < sig.inputs().len() || (args.len() > sig.inputs().len() && !sig.c_variadic) { + span_mirbug!(self, term, "call to {:?} with wrong # of args", sig); + } + + let func_ty = func.ty(self.body, self.infcx.tcx); + if let ty::FnDef(def_id, _) = *func_ty.kind() { + // Some of the SIMD intrinsics are special: they need a particular argument to be a + // constant. (Eventually this should use const-generics, but those are not up for the + // task yet: https://github.com/rust-lang/rust/issues/85229.) + if let Some(name @ (sym::simd_shuffle | sym::simd_insert | sym::simd_extract)) = + self.tcx().intrinsic(def_id).map(|i| i.name) + { + let idx = match name { + sym::simd_shuffle => 2, + _ => 1, + }; + if !matches!(args[idx], Spanned { node: Operand::Constant(_), .. }) { + self.tcx().dcx().emit_err(SimdIntrinsicArgConst { + span: term.source_info.span, + arg: idx + 1, + intrinsic: name.to_string(), + }); + } + } + } + debug!(?func_ty); + + for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() { + let op_arg_ty = op_arg.node.ty(self.body, self.tcx()); + + let op_arg_ty = self.normalize(op_arg_ty, term_location); + let category = if call_source.from_hir_call() { + ConstraintCategory::CallArgument(Some(self.infcx.tcx.erase_regions(func_ty))) + } else { + ConstraintCategory::Boring + }; + if let Err(terr) = + self.sub_types(op_arg_ty, *fn_arg, term_location.to_locations(), category) + { + span_mirbug!( + self, + term, + "bad arg #{:?} ({:?} <- {:?}): {:?}", + n, + fn_arg, + op_arg_ty, + terr + ); + } + } + } + + fn check_iscleanup(&mut self, block_data: &BasicBlockData<'tcx>) { + let is_cleanup = block_data.is_cleanup; + match block_data.terminator().kind { + TerminatorKind::Goto { target } => { + self.assert_iscleanup(block_data, target, is_cleanup) + } + TerminatorKind::SwitchInt { ref targets, .. } => { + for target in targets.all_targets() { + self.assert_iscleanup(block_data, *target, is_cleanup); + } + } + TerminatorKind::UnwindResume => { + if !is_cleanup { + span_mirbug!(self, block_data, "resume on non-cleanup block!") + } + } + TerminatorKind::UnwindTerminate(_) => { + if !is_cleanup { + span_mirbug!(self, block_data, "terminate on non-cleanup block!") + } + } + TerminatorKind::Return => { + if is_cleanup { + span_mirbug!(self, block_data, "return on cleanup block") + } + } + TerminatorKind::TailCall { .. } => { + if is_cleanup { + span_mirbug!(self, block_data, "tailcall on cleanup block") + } + } + TerminatorKind::CoroutineDrop { .. } => { + if is_cleanup { + span_mirbug!(self, block_data, "coroutine_drop in cleanup block") + } + } + TerminatorKind::Yield { resume, drop, .. } => { + if is_cleanup { + span_mirbug!(self, block_data, "yield in cleanup block") + } + self.assert_iscleanup(block_data, resume, is_cleanup); + if let Some(drop) = drop { + self.assert_iscleanup(block_data, drop, is_cleanup); + } + } + TerminatorKind::Unreachable => {} + TerminatorKind::Drop { target, unwind, .. } + | TerminatorKind::Assert { target, unwind, .. } => { + self.assert_iscleanup(block_data, target, is_cleanup); + self.assert_iscleanup_unwind(block_data, unwind, is_cleanup); + } + TerminatorKind::Call { ref target, unwind, .. } => { + if let &Some(target) = target { + self.assert_iscleanup(block_data, target, is_cleanup); + } + self.assert_iscleanup_unwind(block_data, unwind, is_cleanup); + } + TerminatorKind::FalseEdge { real_target, imaginary_target } => { + self.assert_iscleanup(block_data, real_target, is_cleanup); + self.assert_iscleanup(block_data, imaginary_target, is_cleanup); + } + TerminatorKind::FalseUnwind { real_target, unwind } => { + self.assert_iscleanup(block_data, real_target, is_cleanup); + self.assert_iscleanup_unwind(block_data, unwind, is_cleanup); + } + TerminatorKind::InlineAsm { ref targets, unwind, .. } => { + for &target in targets { + self.assert_iscleanup(block_data, target, is_cleanup); + } + self.assert_iscleanup_unwind(block_data, unwind, is_cleanup); + } + } + } - debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); + fn assert_iscleanup(&mut self, ctxt: &dyn fmt::Debug, bb: BasicBlock, iscleanuppad: bool) { + if self.body[bb].is_cleanup != iscleanuppad { + span_mirbug!(self, ctxt, "cleanuppad mismatch: {:?} should be {:?}", bb, iscleanuppad); + } + } - self.sub_types( - src_obj, - dst_obj, - location.to_locations(), - ConstraintCategory::Cast { - is_implicit_coercion: false, - unsize_to: None, - }, - ) - .unwrap(); - } - } - _ => { - span_mirbug!( - self, - rvalue, - "Invalid PtrToPtr cast {:?} -> {:?}", - ty_from, - ty - ) - } - } - } - CastKind::Transmute => { - span_mirbug!( - self, - rvalue, - "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR", - ); - } + fn assert_iscleanup_unwind( + &mut self, + ctxt: &dyn fmt::Debug, + unwind: UnwindAction, + is_cleanup: bool, + ) { + match unwind { + UnwindAction::Cleanup(unwind) => { + if is_cleanup { + span_mirbug!(self, ctxt, "unwind on cleanup block") + } + self.assert_iscleanup(ctxt, unwind, true); + } + UnwindAction::Continue => { + if is_cleanup { + span_mirbug!(self, ctxt, "unwind on cleanup block") } } + UnwindAction::Unreachable | UnwindAction::Terminate(_) => (), + } + } - Rvalue::Ref(region, _borrow_kind, borrowed_place) => { - self.add_reborrow_constraint(body, location, *region, borrowed_place); + fn ensure_place_sized(&mut self, ty: Ty<'tcx>, span: Span) { + let tcx = self.tcx(); + + // Erase the regions from `ty` to get a global type. The + // `Sized` bound in no way depends on precise regions, so this + // shouldn't affect `is_sized`. + let erased_ty = tcx.erase_regions(ty); + // FIXME(#132279): Using `Ty::is_sized` causes us to incorrectly handle opaques here. + if !erased_ty.is_sized(tcx, self.infcx.typing_env(self.infcx.param_env)) { + // in current MIR construction, all non-control-flow rvalue + // expressions evaluate through `as_temp` or `into` a return + // slot or local, so to find all unsized rvalues it is enough + // to check all temps, return slots and locals. + if self.reported_errors.replace((ty, span)).is_none() { + // While this is located in `nll::typeck` this error is not + // an NLL error, it's a required check to prevent creation + // of unsized rvalues in a call expression. + self.tcx().dcx().emit_err(MoveUnsized { ty, span }); } + } + } - Rvalue::BinaryOp( - BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge, - box (left, right), - ) => { - self.check_operand(left, location); - self.check_operand(right, location); + fn aggregate_field_ty( + &mut self, + ak: &AggregateKind<'tcx>, + field_index: FieldIdx, + location: Location, + ) -> Result, FieldAccessError> { + let tcx = self.tcx(); - let ty_left = left.ty(body, tcx); - match ty_left.kind() { - // Types with regions are comparable if they have a common super-type. - ty::RawPtr(_, _) | ty::FnPtr(..) => { - let ty_right = right.ty(body, tcx); - let common_ty = self.infcx.next_ty_var(body.source_info(location).span); - self.sub_types( - ty_left, - common_ty, - location.to_locations(), - ConstraintCategory::CallArgument(None), - ) - .unwrap_or_else(|err| { - bug!("Could not equate type variable with {:?}: {:?}", ty_left, err) - }); - if let Err(terr) = self.sub_types( - ty_right, - common_ty, - location.to_locations(), - ConstraintCategory::CallArgument(None), - ) { - span_mirbug!( - self, - rvalue, - "unexpected comparison types {:?} and {:?} yields {:?}", - ty_left, - ty_right, - terr - ) - } - } - // For types with no regions we can just check that the - // both operands have the same type. - ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) - if ty_left == right.ty(body, tcx) => {} - // Other types are compared by trait methods, not by - // `Rvalue::BinaryOp`. - _ => span_mirbug!( - self, - rvalue, - "unexpected comparison types {:?} and {:?}", - ty_left, - right.ty(body, tcx) - ), + match *ak { + AggregateKind::Adt(adt_did, variant_index, args, _, active_field_index) => { + let def = tcx.adt_def(adt_did); + let variant = &def.variant(variant_index); + let adj_field_index = active_field_index.unwrap_or(field_index); + if let Some(field) = variant.fields.get(adj_field_index) { + Ok(self.normalize(field.ty(tcx, args), location)) + } else { + Err(FieldAccessError::OutOfRange { field_count: variant.fields.len() }) } } - - Rvalue::Use(operand) | Rvalue::UnaryOp(_, operand) => { - self.check_operand(operand, location); + AggregateKind::Closure(_, args) => { + match args.as_closure().upvar_tys().get(field_index.as_usize()) { + Some(ty) => Ok(*ty), + None => Err(FieldAccessError::OutOfRange { + field_count: args.as_closure().upvar_tys().len(), + }), + } } - Rvalue::CopyForDeref(place) => { - let op = &Operand::Copy(*place); - self.check_operand(op, location); + AggregateKind::Coroutine(_, args) => { + // It doesn't make sense to look at a field beyond the prefix; + // these require a variant index, and are not initialized in + // aggregate rvalues. + match args.as_coroutine().prefix_tys().get(field_index.as_usize()) { + Some(ty) => Ok(*ty), + None => Err(FieldAccessError::OutOfRange { + field_count: args.as_coroutine().prefix_tys().len(), + }), + } } - - Rvalue::BinaryOp(_, box (left, right)) => { - self.check_operand(left, location); - self.check_operand(right, location); + AggregateKind::CoroutineClosure(_, args) => { + match args.as_coroutine_closure().upvar_tys().get(field_index.as_usize()) { + Some(ty) => Ok(*ty), + None => Err(FieldAccessError::OutOfRange { + field_count: args.as_coroutine_closure().upvar_tys().len(), + }), + } } - - Rvalue::WrapUnsafeBinder(op, ty) => { - self.check_operand(op, location); - let operand_ty = op.ty(self.body, self.tcx()); - - let ty::UnsafeBinder(binder_ty) = *ty.kind() else { - unreachable!(); - }; - let expected_ty = self.infcx.instantiate_binder_with_fresh_vars( - self.body().source_info(location).span, - BoundRegionConversionTime::HigherRankedType, - binder_ty.into(), - ); - self.sub_types( - operand_ty, - expected_ty, - location.to_locations(), - ConstraintCategory::Boring, - ) - .unwrap(); + AggregateKind::Array(ty) => Ok(ty), + AggregateKind::Tuple | AggregateKind::RawPtr(..) => { + unreachable!("This should have been covered in check_rvalues"); } - - Rvalue::RawPtr(..) - | Rvalue::ThreadLocalRef(..) - | Rvalue::Len(..) - | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {} } } @@ -2320,7 +2247,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { fn check_aggregate_rvalue( &mut self, - body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, aggregate_kind: &AggregateKind<'tcx>, operands: &IndexSlice>, @@ -2353,7 +2279,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { continue; } }; - let operand_ty = operand.ty(body, tcx); + let operand_ty = operand.ty(self.body, tcx); let operand_ty = self.normalize(operand_ty, location); if let Err(terr) = self.sub_types( @@ -2383,7 +2309,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { /// - `borrowed_place`: the place `P` being borrowed fn add_reborrow_constraint( &mut self, - body: &Body<'tcx>, location: Location, borrow_region: ty::Region<'tcx>, borrowed_place: &Place<'tcx>, @@ -2422,7 +2347,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let def = self.body.source.def_id().expect_local(); let upvars = tcx.closure_captures(def); let field = - path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), body); + path_utils::is_upvar_field_projection(tcx, upvars, borrowed_place.as_ref(), self.body); let category = if let Some(field) = field { ConstraintCategory::ClosureUpvar(field) } else { @@ -2434,7 +2359,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { match elem { ProjectionElem::Deref => { - let base_ty = base.ty(body, tcx).ty; + let base_ty = base.ty(self.body, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.kind() { @@ -2443,7 +2368,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { sup: ref_region.as_var(), sub: borrow_region.as_var(), locations: location.to_locations(), - span: location.to_locations().span(body), + span: location.to_locations().span(self.body), category, variance_info: ty::VarianceDiagInfo::default(), from_closure: false, @@ -2587,7 +2512,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring, // same as above. self.constraints, ) - .apply_closure_requirements(closure_requirements, def_id.to_def_id(), args); + .apply_closure_requirements(closure_requirements, def_id, args); } // Now equate closure args to regions inherited from `typeck_root_def_id`. Fixes #98589. @@ -2627,30 +2552,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { tcx.predicates_of(def_id).instantiate(tcx, args) } - - #[instrument(skip(self, body), level = "debug")] - fn typeck_mir(&mut self, body: &Body<'tcx>) { - self.last_span = body.span; - debug!(?body.span); - - for (local, local_decl) in body.local_decls.iter_enumerated() { - self.check_local(body, local, local_decl); - } - - for (block, block_data) in body.basic_blocks.iter_enumerated() { - let mut location = Location { block, statement_index: 0 }; - for stmt in &block_data.statements { - if !stmt.source_info.span.is_dummy() { - self.last_span = stmt.source_info.span; - } - self.check_stmt(body, stmt, location); - location.statement_index += 1; - } - - self.check_terminator(body, block_data.terminator(), location); - self.check_iscleanup(body, block_data); - } - } } trait NormalizeLocation: fmt::Debug + Copy { @@ -2707,16 +2608,3 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> { Ok(output) } } - -fn freshen_single_trait_object_lifetime<'tcx>( - infcx: &BorrowckInferCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Ty<'tcx> { - let &ty::Dynamic(tty, _, dyn_kind @ ty::Dyn) = ty.kind() else { bug!("expected trait object") }; - - let fresh = infcx - .next_region_var(rustc_infer::infer::RegionVariableOrigin::MiscVariable(DUMMY_SP), || { - RegionCtxt::Unknown - }); - infcx.tcx.mk_ty_from_kind(ty::Dynamic(tty, fresh, dyn_kind)) -} diff --git a/compiler/rustc_borrowck/src/type_check/opaque_types.rs b/compiler/rustc_borrowck/src/type_check/opaque_types.rs index 17482cc0cbd22..8bab979a72464 100644 --- a/compiler/rustc_borrowck/src/type_check/opaque_types.rs +++ b/compiler/rustc_borrowck/src/type_check/opaque_types.rs @@ -2,10 +2,9 @@ use std::iter; use rustc_data_structures::fx::FxIndexMap; use rustc_middle::span_bug; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::{ self, GenericArgKind, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + TypeVisitable, TypeVisitableExt, TypeVisitor, fold_regions, }; use tracing::{debug, trace}; @@ -180,6 +179,7 @@ pub(super) fn take_opaques_and_register_member_constraints<'tcx>( /// // Equivalent to: /// # mod dummy { use super::*; /// type FooReturn<'a, T> = impl Foo<'a>; +/// #[define_opaque(FooReturn)] /// fn foo<'a, T>(x: &'a u32, y: T) -> FooReturn<'a, T> { /// (x, y) /// } diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs index 59e2eee41d3fc..02a41469c97f4 100644 --- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs +++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs @@ -10,9 +10,8 @@ use rustc_middle::mir::ConstraintCategory; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::fold::FnMutDelegate; use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, instrument}; diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 9a68eeb3326eb..8f6b405fcef2b 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -27,11 +27,10 @@ use rustc_hir::lang_items::LangItem; use rustc_index::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_macros::extension; -use rustc_middle::ty::fold::{TypeFoldable, fold_regions}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionVid, Ty, - TyCtxt, TypeVisitableExt, + TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, kw, sym}; @@ -126,6 +125,11 @@ pub(crate) enum DefiningTy<'tcx> { /// The MIR represents an inline const. The signature has no inputs and a /// single return value found via `InlineConstArgs::ty`. InlineConst(DefId, GenericArgsRef<'tcx>), + + // Fake body for a global asm. Not particularly useful or interesting, + // but we need it so we can properly store the typeck results of the asm + // operands, which aren't associated with a body otherwise. + GlobalAsm(DefId), } impl<'tcx> DefiningTy<'tcx> { @@ -138,9 +142,10 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(_, args) => args.as_closure().upvar_tys(), DefiningTy::CoroutineClosure(_, args) => args.as_coroutine_closure().upvar_tys(), DefiningTy::Coroutine(_, args) => args.as_coroutine().upvar_tys(), - DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => { - ty::List::empty() - } + DefiningTy::FnDef(..) + | DefiningTy::Const(..) + | DefiningTy::InlineConst(..) + | DefiningTy::GlobalAsm(_) => ty::List::empty(), } } @@ -152,7 +157,10 @@ impl<'tcx> DefiningTy<'tcx> { DefiningTy::Closure(..) | DefiningTy::CoroutineClosure(..) | DefiningTy::Coroutine(..) => 1, - DefiningTy::FnDef(..) | DefiningTy::Const(..) | DefiningTy::InlineConst(..) => 0, + DefiningTy::FnDef(..) + | DefiningTy::Const(..) + | DefiningTy::InlineConst(..) + | DefiningTy::GlobalAsm(_) => 0, } } @@ -171,7 +179,22 @@ impl<'tcx> DefiningTy<'tcx> { | DefiningTy::Coroutine(def_id, ..) | DefiningTy::FnDef(def_id, ..) | DefiningTy::Const(def_id, ..) - | DefiningTy::InlineConst(def_id, ..) => def_id, + | DefiningTy::InlineConst(def_id, ..) + | DefiningTy::GlobalAsm(def_id) => def_id, + } + } + + /// Returns the args of the `DefiningTy`. These are equivalent to the identity + /// substs of the body, but replaced with region vids. + pub(crate) fn args(&self) -> ty::GenericArgsRef<'tcx> { + match *self { + DefiningTy::Closure(_, args) + | DefiningTy::Coroutine(_, args) + | DefiningTy::CoroutineClosure(_, args) + | DefiningTy::FnDef(_, args) + | DefiningTy::Const(_, args) + | DefiningTy::InlineConst(_, args) => args, + DefiningTy::GlobalAsm(_) => ty::List::empty(), } } } @@ -308,7 +331,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// Returns an iterator over all the RegionVids corresponding to /// universally quantified free regions. - pub(crate) fn universal_regions_iter(&self) -> impl Iterator { + pub(crate) fn universal_regions_iter(&self) -> impl Iterator + 'static { (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize) } @@ -332,9 +355,9 @@ impl<'tcx> UniversalRegions<'tcx> { } /// Gets an iterator over all the early-bound regions that have names. - pub(crate) fn named_universal_regions_iter<'s>( - &'s self, - ) -> impl Iterator, ty::RegionVid)> + 's { + pub(crate) fn named_universal_regions_iter( + &self, + ) -> impl Iterator, ty::RegionVid)> { self.indices.indices.iter().map(|(&r, &v)| (r, v)) } @@ -411,6 +434,7 @@ impl<'tcx> UniversalRegions<'tcx> { tcx.def_path_str_with_args(def_id, args), )); } + DefiningTy::GlobalAsm(_) => unreachable!(), } } @@ -633,6 +657,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { DefiningTy::InlineConst(self.mir_def.to_def_id(), args) } } + + BodyOwnerKind::GlobalAsm => DefiningTy::GlobalAsm(self.mir_def.to_def_id()), } } @@ -666,6 +692,8 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { } DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args, + + DefiningTy::GlobalAsm(_) => ty::List::empty(), }; let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); @@ -802,6 +830,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let ty = args.as_inline_const().ty(); ty::Binder::dummy(tcx.mk_type_list(&[ty])) } + + DefiningTy::GlobalAsm(def_id) => { + ty::Binder::dummy(tcx.mk_type_list(&[tcx.type_of(def_id).instantiate_identity()])) + } }; // FIXME(#129952): We probably want a more principled approach here. diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml index b50cb35b8e983..1289d21308b7a 100644 --- a/compiler/rustc_builtin_macros/Cargo.toml +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -1,11 +1,7 @@ [package] name = "rustc_builtin_macros" version = "0.0.0" -edition = "2021" - - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(llvm_enzyme)'] } +edition = "2024" [lib] doctest = false @@ -20,6 +16,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_hir = { path = "../rustc_hir" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 4cac7cb93f581..3f03834f8d781 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -75,9 +75,10 @@ builtin_macros_autodiff_mode = unknown Mode: `{$mode}`. Use `Forward` or `Revers builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode builtin_macros_autodiff_not_build = this rustc version does not support autodiff builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found} +builtin_macros_autodiff_ret_activity = invalid return activity {$act} in {$mode} Mode builtin_macros_autodiff_ty_activity = {$act} can not be used for this type - builtin_macros_autodiff_unknown_activity = did not recognize Activity: `{$act}` + builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s .label = not applicable here .label2 = not a `struct`, `enum` or `union` diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs index 78bf2195975d5..1c1b2c88f76ee 100644 --- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs +++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs @@ -88,6 +88,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span generics: Generics::default(), contract: None, body, + define_opaque: None, })); let attrs = thin_vec![cx.attr_word(sym::rustc_std_internal_symbol, span)]; diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index bb9dc651cec25..a949ab94f3ad7 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -297,6 +297,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::AssignOp(_, _, _) | ExprKind::Gen(_, _, _, _) | ExprKind::Await(_, _) + | ExprKind::Use(_, _) | ExprKind::Block(_, _) | ExprKind::Break(_, _) | ExprKind::Closure(_) diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 8d7ac6de8010b..dcd3c1ce8d917 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -3,13 +3,13 @@ //! configs (autodiff enabled or disabled), so we have to add cfg's to each import. //! FIXME(ZuseZ4): Remove this once we have a smarter linter. -#[cfg(llvm_enzyme)] mod llvm_enzyme { use std::str::FromStr; use std::string::String; use rustc_ast::expand::autodiff_attrs::{ - AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ty_for_activity, + AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, + valid_ty_for_activity, }; use rustc_ast::ptr::P; use rustc_ast::token::{Token, TokenKind}; @@ -130,10 +130,14 @@ mod llvm_enzyme { meta_item: &ast::MetaItem, mut item: Annotatable, ) -> Vec { + if cfg!(not(llvm_enzyme)) { + ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span }); + return vec![item]; + } let dcx = ecx.sess.dcx(); // first get the annotable item: let (sig, is_impl): (FnSig, bool) = match &item { - Annotatable::Item(ref iitem) => { + Annotatable::Item(iitem) => { let sig = match &iitem.kind { ItemKind::Fn(box ast::Fn { sig, .. }) => sig, _ => { @@ -143,7 +147,7 @@ mod llvm_enzyme { }; (sig.clone(), false) } - Annotatable::AssocItem(ref assoc_item, _) => { + Annotatable::AssocItem(assoc_item, _) => { let sig = match &assoc_item.kind { ast::AssocItemKind::Fn(box ast::Fn { sig, .. }) => sig, _ => { @@ -171,8 +175,8 @@ mod llvm_enzyme { let sig_span = ecx.with_call_site_ctxt(sig.span); let (vis, primal) = match &item { - Annotatable::Item(ref iitem) => (iitem.vis.clone(), iitem.ident.clone()), - Annotatable::AssocItem(ref assoc_item, _) => { + Annotatable::Item(iitem) => (iitem.vis.clone(), iitem.ident.clone()), + Annotatable::AssocItem(assoc_item, _) => { (assoc_item.vis.clone(), assoc_item.ident.clone()) } _ => { @@ -244,6 +248,7 @@ mod llvm_enzyme { generics: Generics::default(), contract: None, body: Some(d_body), + define_opaque: None, }); let mut rustc_ad_attr = P(ast::NormalAttr::from_ident(Ident::with_dummy_span(sym::rustc_autodiff))); @@ -283,7 +288,7 @@ mod llvm_enzyme { let orig_annotatable: Annotatable = match item { Annotatable::Item(ref mut iitem) => { if !iitem.attrs.iter().any(|a| a.id == attr.id) { - iitem.attrs.push(attr.clone()); + iitem.attrs.push(attr); } if !iitem.attrs.iter().any(|a| a.id == inline_never.id) { iitem.attrs.push(inline_never.clone()); @@ -292,7 +297,7 @@ mod llvm_enzyme { } Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => { if !assoc_item.attrs.iter().any(|a| a.id == attr.id) { - assoc_item.attrs.push(attr.clone()); + assoc_item.attrs.push(attr); } if !assoc_item.attrs.iter().any(|a| a.id == inline_never.id) { assoc_item.attrs.push(inline_never.clone()); @@ -319,7 +324,7 @@ mod llvm_enzyme { let d_annotatable = if is_impl { let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf); let d_fn = P(ast::AssocItem { - attrs: thin_vec![d_attr.clone(), inline_never], + attrs: thin_vec![d_attr, inline_never], id: ast::DUMMY_NODE_ID, span, vis, @@ -329,12 +334,8 @@ mod llvm_enzyme { }); Annotatable::AssocItem(d_fn, Impl) } else { - let mut d_fn = ecx.item( - span, - d_ident, - thin_vec![d_attr.clone(), inline_never], - ItemKind::Fn(asdf), - ); + let mut d_fn = + ecx.item(span, d_ident, thin_vec![d_attr, inline_never], ItemKind::Fn(asdf)); d_fn.vis = vis; Annotatable::Item(d_fn) }; @@ -443,7 +444,7 @@ mod llvm_enzyme { if primal_ret && n_active == 0 && x.mode.is_rev() { // We only have the primal ret. - body.stmts.push(ecx.stmt_expr(black_box_primal_call.clone())); + body.stmts.push(ecx.stmt_expr(black_box_primal_call)); return body; } @@ -468,7 +469,7 @@ mod llvm_enzyme { if primal_ret { // We have both primal ret and active floats. // primal ret is first, by construction. - exprs.push(primal_call.clone()); + exprs.push(primal_call); } // Now construct default placeholder for each active float. @@ -535,16 +536,11 @@ mod llvm_enzyme { return body; } [arg] => { - ret = ecx.expr_call( - new_decl_span, - blackbox_call_expr.clone(), - thin_vec![arg.clone()], - ); + ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![arg.clone()]); } args => { let ret_tuple: P = ecx.expr_tuple(span, args.into()); - ret = - ecx.expr_call(new_decl_span, blackbox_call_expr.clone(), thin_vec![ret_tuple]); + ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![ret_tuple]); } } assert!(has_ret(&d_sig.decl.output)); @@ -564,7 +560,7 @@ mod llvm_enzyme { let args: ThinVec<_> = idents[1..].iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); let self_expr = ecx.expr_self(span); - ecx.expr_method_call(span, self_expr, primal, args.clone()) + ecx.expr_method_call(span, self_expr, primal, args) } else { let args: ThinVec<_> = idents.iter().map(|arg| ecx.expr_path(ecx.path_ident(span, *arg))).collect(); @@ -582,6 +578,8 @@ mod llvm_enzyme { // // Error handling: If the user provides an invalid configuration (incorrect numbers, types, or // both), we emit an error and return the original signature. This allows us to continue parsing. + // FIXME(Sa4dUs): make individual activities' span available so errors + // can point to only the activity instead of the entire attribute fn gen_enzyme_decl( ecx: &ExtCtxt<'_>, sig: &ast::FnSig, @@ -629,10 +627,22 @@ mod llvm_enzyme { errors = true; } } + + if has_ret && !valid_ret_activity(x.mode, x.ret_activity) { + dcx.emit_err(errors::AutoDiffInvalidRetAct { + span, + mode: x.mode.to_string(), + act: x.ret_activity.to_string(), + }); + // We don't set `errors = true` to avoid annoying type errors relative + // to the expanded macro type signature + } + if errors { // This is not the right signature, but we can continue parsing. return (sig.clone(), new_inputs, idents, true); } + let unsafe_activities = x .input_activity .iter() @@ -801,25 +811,4 @@ mod llvm_enzyme { } } -#[cfg(not(llvm_enzyme))] -mod ad_fallback { - use rustc_ast::ast; - use rustc_expand::base::{Annotatable, ExtCtxt}; - use rustc_span::Span; - - use crate::errors; - pub(crate) fn expand( - ecx: &mut ExtCtxt<'_>, - _expand_span: Span, - meta_item: &ast::MetaItem, - item: Annotatable, - ) -> Vec { - ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span }); - return vec![item]; - } -} - -#[cfg(not(llvm_enzyme))] -pub(crate) use ad_fallback::expand; -#[cfg(llvm_enzyme)] pub(crate) use llvm_enzyme::expand; diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 53c61831b4229..5788966b6e7b1 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -140,8 +140,9 @@ impl CfgEval<'_> { Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap()) } Annotatable::Stmt(_) => { - let stmt = - parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap(); + let stmt = parser + .parse_stmt_without_recovery(false, ForceCollect::Yes, false)? + .unwrap(); Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap())) } Annotatable::Expr(_) => { diff --git a/compiler/rustc_builtin_macros/src/define_opaque.rs b/compiler/rustc_builtin_macros/src/define_opaque.rs new file mode 100644 index 0000000000000..9777e772cf208 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/define_opaque.rs @@ -0,0 +1,54 @@ +use rustc_ast::{DUMMY_NODE_ID, ast}; +use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_span::Span; + +pub(crate) fn expand( + ecx: &mut ExtCtxt<'_>, + _expand_span: Span, + meta_item: &ast::MetaItem, + mut item: Annotatable, +) -> Vec { + let define_opaque = match &mut item { + Annotatable::Item(p) => match &mut p.kind { + ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + _ => None, + }, + Annotatable::AssocItem(i, _assoc_ctxt) => match &mut i.kind { + ast::AssocItemKind::Fn(func) => Some(&mut func.define_opaque), + _ => None, + }, + Annotatable::Stmt(s) => match &mut s.kind { + ast::StmtKind::Item(p) => match &mut p.kind { + ast::ItemKind::Fn(f) => Some(&mut f.define_opaque), + _ => None, + }, + _ => None, + }, + _ => None, + }; + + let Some(list) = meta_item.meta_item_list() else { + ecx.dcx().span_err(meta_item.span, "expected list of type aliases"); + return vec![item]; + }; + + if let Some(define_opaque) = define_opaque { + *define_opaque = Some( + list.iter() + .filter_map(|entry| match entry { + ast::MetaItemInner::MetaItem(meta_item) if meta_item.is_word() => { + Some((DUMMY_NODE_ID, meta_item.path.clone())) + } + _ => { + ecx.dcx().span_err(entry.span(), "expected path to type alias"); + None + } + }) + .collect(), + ); + } else { + ecx.dcx().span_err(meta_item.span, "only functions and methods can define opaque types"); + } + + vec![item] +} diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 5aed9f76f144f..46b79e0978082 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -300,13 +300,16 @@ pub(crate) fn expand_deriving_coerce_pointee( to_ty: &s_ty, rewritten: false, }; - let mut predicate = ast::WherePredicate { - kind: ast::WherePredicateKind::BoundPredicate(bound.clone()), - span: predicate.span, - id: ast::DUMMY_NODE_ID, - }; - substitution.visit_where_predicate(&mut predicate); + let mut kind = ast::WherePredicateKind::BoundPredicate(bound.clone()); + substitution.visit_where_predicate_kind(&mut kind); if substitution.rewritten { + let predicate = ast::WherePredicate { + attrs: predicate.attrs.clone(), + kind, + span: predicate.span, + id: ast::DUMMY_NODE_ID, + is_placeholder: false, + }; impl_generics.where_clause.predicates.push(predicate); } } @@ -388,8 +391,8 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> { } } - fn visit_where_predicate(&mut self, where_predicate: &mut ast::WherePredicate) { - match &mut where_predicate.kind { + fn visit_where_predicate_kind(&mut self, kind: &mut ast::WherePredicateKind) { + match kind { rustc_ast::WherePredicateKind::BoundPredicate(bound) => { bound .bound_generic_params diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 234ec8582165b..03ee59de70e12 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -185,8 +185,9 @@ use rustc_ast::{ self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, Mutability, PatKind, VariantData, }; -use rustc_attr_parsing as attr; +use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprPacked}; use rustc_expand::base::{Annotatable, ExtCtxt}; +use rustc_hir::Attribute; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use thin_vec::{ThinVec, thin_vec}; use ty::{Bounds, Path, Ref, Self_, Ty}; @@ -480,14 +481,10 @@ impl<'a> TraitDef<'a> { ) { match item { Annotatable::Item(item) => { - let is_packed = item.attrs.iter().any(|attr| { - for r in attr::find_repr_attrs(cx.sess, attr) { - if let attr::ReprPacked(_) = r { - return true; - } - } - false - }); + let is_packed = matches!( + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true), + Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) + ); let newitem = match &item.kind { ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def( @@ -690,9 +687,11 @@ impl<'a> TraitDef<'a> { // and similarly for where clauses where_clause.predicates.extend(generics.where_clause.predicates.iter().map(|clause| { ast::WherePredicate { + attrs: clause.attrs.clone(), kind: clause.kind.clone(), id: ast::DUMMY_NODE_ID, span: clause.span.with_ctxt(ctxt), + is_placeholder: false, } })); @@ -747,8 +746,13 @@ impl<'a> TraitDef<'a> { }; let kind = ast::WherePredicateKind::BoundPredicate(predicate); - let predicate = - ast::WherePredicate { kind, id: ast::DUMMY_NODE_ID, span: self.span }; + let predicate = ast::WherePredicate { + attrs: ThinVec::new(), + kind, + id: ast::DUMMY_NODE_ID, + span: self.span, + is_placeholder: false, + }; where_clause.predicates.push(predicate); } } @@ -1036,6 +1040,7 @@ impl<'a> MethodDef<'a> { generics: fn_generics, contract: None, body: Some(body_block), + define_opaque: None, })), tokens: None, }) diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 6213bd802c751..30597944124cb 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -144,10 +144,8 @@ pub(crate) struct AllocMustStatics { pub(crate) span: Span, } -#[cfg(llvm_enzyme)] pub(crate) use autodiff::*; -#[cfg(llvm_enzyme)] mod autodiff { use super::*; #[derive(Diagnostic)] @@ -187,6 +185,15 @@ mod autodiff { pub(crate) act: String, } + #[derive(Diagnostic)] + #[diag(builtin_macros_autodiff_ret_activity)] + pub(crate) struct AutoDiffInvalidRetAct { + #[primary_span] + pub(crate) span: Span, + pub(crate) mode: String, + pub(crate) act: String, + } + #[derive(Diagnostic)] #[diag(builtin_macros_autodiff_mode)] pub(crate) struct AutoDiffInvalidMode { @@ -203,9 +210,7 @@ mod autodiff { } } -#[cfg(not(llvm_enzyme))] pub(crate) use ad_fallback::*; -#[cfg(not(llvm_enzyme))] mod ad_fallback { use super::*; #[derive(Diagnostic)] diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 90447da66807b..12654001a1e28 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -190,7 +190,8 @@ fn make_format_args( && let [stmt] = block.stmts.as_slice() && let StmtKind::Expr(expr) = &stmt.kind && let ExprKind::Path(None, path) = &expr.kind - && path.is_potential_trivial_const_arg() + && path.segments.len() == 1 + && path.segments[0].args.is_none() { err.multipart_suggestion( "quote your inlined format argument to use as string literal", @@ -710,11 +711,9 @@ fn report_missing_placeholders( }; let pos = sub.position(); - let sub = String::from(sub.as_str()); - if explained.contains(&sub) { + if !explained.insert(sub.to_string()) { continue; } - explained.insert(sub); if !found_foreign { found_foreign = true; diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index 866ec72f11646..13d5b42942ac7 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -12,14 +12,16 @@ pub(crate) mod printf { Escape((usize, usize)), } - impl<'a> Substitution<'a> { - pub(crate) fn as_str(&self) -> &str { + impl ToString for Substitution<'_> { + fn to_string(&self) -> String { match self { - Substitution::Format(fmt) => fmt.span, - Substitution::Escape(_) => "%%", + Substitution::Format(fmt) => fmt.span.into(), + Substitution::Escape(_) => "%%".into(), } } + } + impl Substitution<'_> { pub(crate) fn position(&self) -> InnerSpan { match self { Substitution::Format(fmt) => fmt.position, @@ -627,15 +629,17 @@ pub(crate) mod shell { Escape((usize, usize)), } - impl Substitution<'_> { - pub(crate) fn as_str(&self) -> String { + impl ToString for Substitution<'_> { + fn to_string(&self) -> String { match self { Substitution::Ordinal(n, _) => format!("${n}"), Substitution::Name(n, _) => format!("${n}"), Substitution::Escape(_) => "$$".into(), } } + } + impl Substitution<'_> { pub(crate) fn position(&self) -> InnerSpan { let (Self::Ordinal(_, pos) | Self::Name(_, pos) | Self::Escape(pos)) = self; InnerSpan::new(pos.0, pos.1) diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs index 8fdbbf8e704a9..90d79235820f4 100644 --- a/compiler/rustc_builtin_macros/src/global_allocator.rs +++ b/compiler/rustc_builtin_macros/src/global_allocator.rs @@ -83,6 +83,7 @@ impl AllocFnFactory<'_, '_> { generics: Generics::default(), contract: None, body, + define_opaque: None, })); let item = self.cx.item( self.span, diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index ca16583a45de7..dab3053d8b0d7 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -5,6 +5,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -18,7 +19,6 @@ #![feature(rustdoc_internals)] #![feature(string_from_utf8_lossy_owned)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate proc_macro; @@ -39,6 +39,7 @@ mod compile_error; mod concat; mod concat_bytes; mod concat_idents; +mod define_opaque; mod derive; mod deriving; mod edition_panic; @@ -114,6 +115,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { bench: test::expand_bench, cfg_accessible: cfg_accessible::Expander, cfg_eval: cfg_eval::expand, + define_opaque: define_opaque::expand, derive: derive::Expander { is_const: false }, derive_const: derive::Expander { is_const: true }, global_allocator: global_allocator::expand, diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs index 1a3f4d2d44908..ba63b185e0967 100644 --- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs +++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs @@ -19,16 +19,12 @@ pub fn inject( let edition = sess.psess.edition; // the first name in this list is the crate name of the crate with the prelude - let names: &[Symbol] = if attr::contains_name(pre_configured_attrs, sym::no_core) { + let name: Symbol = if attr::contains_name(pre_configured_attrs, sym::no_core) { return 0; } else if attr::contains_name(pre_configured_attrs, sym::no_std) { - if attr::contains_name(pre_configured_attrs, sym::compiler_builtins) { - &[sym::core] - } else { - &[sym::core, sym::compiler_builtins] - } + sym::core } else { - &[sym::std] + sym::std }; let expn_id = resolver.expansion_for_ast_pass( @@ -43,36 +39,16 @@ pub fn inject( let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features); let cx = ExtCtxt::new(sess, ecfg, resolver, None); - // .rev() to preserve ordering above in combination with insert(0, ...) - for &name in names.iter().rev() { - let ident_span = if edition >= Edition2018 { span } else { call_site }; - let item = if name == sym::compiler_builtins { - // compiler_builtins is a private implementation detail. We only - // need to insert it into the crate graph for linking and should not - // expose any of its public API. - // - // FIXME(#113634) We should inject this during post-processing like - // we do for the panic runtime, profiler runtime, etc. - cx.item( - span, - Ident::new(kw::Underscore, ident_span), - thin_vec![], - ast::ItemKind::ExternCrate(Some(name)), - ) - } else { - cx.item( - span, - Ident::new(name, ident_span), - thin_vec![cx.attr_word(sym::macro_use, span)], - ast::ItemKind::ExternCrate(None), - ) - }; - krate.items.insert(0, item); - } + let ident_span = if edition >= Edition2018 { span } else { call_site }; - // The crates have been injected, the assumption is that the first one is - // the one with the prelude. - let name = names[0]; + let item = cx.item( + span, + Ident::new(name, ident_span), + thin_vec![cx.attr_word(sym::macro_use, span)], + ast::ItemKind::ExternCrate(None), + ); + + krate.items.insert(0, item); let root = (edition == Edition2015).then_some(kw::PathRoot); @@ -84,10 +60,12 @@ pub fn inject( Edition2018 => sym::rust_2018, Edition2021 => sym::rust_2021, Edition2024 => sym::rust_2024, + EditionFuture => sym::rust_future, }]) .map(|&symbol| Ident::new(symbol, span)) .collect(); + // Inject the relevant crate's prelude. let use_item = cx.item( span, Ident::empty(), diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 472e16e62d5b0..768b459ec5e30 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -346,6 +346,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { generics: ast::Generics::default(), contract: None, body: Some(main_body), + define_opaque: None, })); // Honor the reexport_test_harness_main attribute diff --git a/compiler/rustc_codegen_cranelift/example/issue-72793.rs b/compiler/rustc_codegen_cranelift/example/issue-72793.rs index 2e08fbca8ef27..95d58b90e7981 100644 --- a/compiler/rustc_codegen_cranelift/example/issue-72793.rs +++ b/compiler/rustc_codegen_cranelift/example/issue-72793.rs @@ -2,23 +2,21 @@ #![feature(type_alias_impl_trait)] -mod helper { - pub trait T { - type Item; - } +pub trait T { + type Item; +} - pub type Alias<'a> = impl T; +pub type Alias<'a> = impl T; - struct S; - impl<'a> T for &'a S { - type Item = &'a (); - } +struct S; +impl<'a> T for &'a S { + type Item = &'a (); +} - pub fn filter_positive<'a>() -> Alias<'a> { - &S - } +#[define_opaque(Alias)] +pub fn filter_positive<'a>() -> Alias<'a> { + &S } -use helper::*; fn with_positive(fun: impl Fn(Alias<'_>)) { fun(filter_positive()); diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 79820232496a5..6e345b2a6fdf0 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -620,70 +620,31 @@ pub union MaybeUninit { pub mod intrinsics { #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn size_of() -> usize { - loop {} - } + pub fn size_of() -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn size_of_val(_val: *const T) -> usize { - loop {} - } + pub unsafe fn size_of_val(val: *const T) -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn min_align_of() -> usize { - loop {} - } + pub fn min_align_of() -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn min_align_of_val(_val: *const T) -> usize { - loop {} - } + pub unsafe fn min_align_of_val(val: *const T) -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize) { - loop {} - } + pub unsafe fn copy(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn transmute(_e: T) -> U { - loop {} - } + pub unsafe fn transmute(e: T) -> U; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn ctlz_nonzero(_x: T) -> u32 { - loop {} - } + pub unsafe fn ctlz_nonzero(x: T) -> u32; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn needs_drop() -> bool { - loop {} - } + pub fn needs_drop() -> bool; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn bitreverse(_x: T) -> T { - loop {} - } + pub fn bitreverse(x: T) -> T; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn bswap(_x: T) -> T { - loop {} - } + pub fn bswap(x: T) -> T; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize) { - loop {} - } + pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn unreachable() -> ! { - loop {} - } + pub unsafe fn unreachable() -> !; } pub mod libc { diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index 3c81b04c0ead2..d7e3b11127c42 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -1,4 +1,4 @@ -From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001 +From 5d7c709608b01301d4628d2159265936d4440b67 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Thu, 18 Feb 2021 18:45:28 +0100 Subject: [PATCH] Disable 128bit atomic operations @@ -7,11 +7,10 @@ Cranelift doesn't support them yet --- library/core/src/panic/unwind_safe.rs | 6 ----- library/core/src/sync/atomic.rs | 38 --------------------------- - library/core/tests/atomic.rs | 4 --- - 4 files changed, 4 insertions(+), 50 deletions(-) + 2 files changed, 44 deletions(-) diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs -index 092b7cf..158cf71 100644 +index a60f0799c0e..af056fbf41f 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -216,9 +216,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicI32 {} @@ -21,7 +20,7 @@ index 092b7cf..158cf71 100644 -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "99069")] -impl RefUnwindSafe for crate::sync::atomic::AtomicI128 {} - + #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] @@ -235,9 +232,6 @@ impl RefUnwindSafe for crate::sync::atomic::AtomicU32 {} @@ -31,14 +30,14 @@ index 092b7cf..158cf71 100644 -#[cfg(target_has_atomic_load_store = "128")] -#[unstable(feature = "integer_atomics", issue = "99069")] -impl RefUnwindSafe for crate::sync::atomic::AtomicU128 {} - + #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs -index d9de37e..8293fce 100644 +index bf2b6d59f88..d5ccce03bbf 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs -@@ -2996,44 +2996,6 @@ atomic_int! { +@@ -3585,44 +3585,6 @@ pub const fn as_ptr(&self) -> *mut $int_type { 8, u64 AtomicU64 } @@ -54,7 +53,7 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), +- rustc_diagnostic_item = "AtomicI128", - "i128", - "#![feature(integer_atomics)]\n\n", - atomic_min, atomic_max, @@ -73,7 +72,7 @@ index d9de37e..8293fce 100644 - unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - rustc_const_unstable(feature = "integer_atomics", issue = "99069"), -- cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), +- rustc_diagnostic_item = "AtomicU128", - "u128", - "#![feature(integer_atomics)]\n\n", - atomic_umin, atomic_umax, @@ -83,7 +82,6 @@ index d9de37e..8293fce 100644 #[cfg(target_has_atomic_load_store = "ptr")] macro_rules! atomic_int_ptr_sized { - ( $($target_pointer_width:literal $align:literal)* ) => { $( --- -2.26.2.7.g19db9cfb68 +-- +2.48.1 diff --git a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch index e3a9512dda9c6..754025ff49db3 100644 --- a/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch +++ b/compiler/rustc_codegen_cranelift/patches/0029-stdlib-Disable-f16-and-f128-in-compiler-builtins.patch @@ -12,15 +12,15 @@ index 7165c3e48af..968552ad435 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -11,7 +11,7 @@ test = { path = "../test" } - edition = "2021" + bench = false [dependencies] - core = { path = "../core" } --compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std', 'no-f16-f128'] } + core = { path = "../core", public = true } +-compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std', 'no-f16-f128'] } - [dev-dependencies] - rand = { version = "0.8.5", default-features = false, features = ["alloc"] } + [features] + compiler-builtins-mem = ['compiler_builtins/mem'] -- 2.34.1 diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index 756a2226753f6..e8076ce77abcf 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -402,9 +402,13 @@ pub(crate) fn codegen_terminator_call<'tcx>( if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) { if target.is_some() { - let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id())); - let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)); - fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); + let caller_def = fx.instance.def_id(); + let e = CompilerBuiltinsCannotCall { + span: fx.tcx.def_span(caller_def), + caller: with_no_trimmed_paths!(fx.tcx.def_path_str(caller_def)), + callee: with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)), + }; + fx.tcx.dcx().emit_err(e); } else { fx.bcx.ins().trap(TrapCode::user(2).unwrap()); return; diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index b28c4c9539cef..06d89bc9ea7d7 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -84,7 +84,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { AbiParam::new(scalar_to_clif_type(tcx, scalar)), attrs )], - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); smallvec![AbiParam::new(vector_ty)] } @@ -135,7 +135,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> { BackendRepr::Scalar(scalar) => { (None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))]) } - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout); (None, vec![AbiParam::new(vector_ty)]) } diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs index 54745b0d8c104..9ea92c300f898 100644 --- a/compiler/rustc_codegen_cranelift/src/global_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs @@ -16,7 +16,7 @@ use crate::prelude::*; pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) { let item = tcx.hir_item(item_id); - if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind { + if let rustc_hir::ItemKind::GlobalAsm { asm, .. } = item.kind { let is_x86 = matches!(tcx.sess.asm_arch.unwrap(), InlineAsmArch::X86 | InlineAsmArch::X86_64); @@ -55,7 +55,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, } } } - InlineAsmOperand::SymFn { anon_const } => { + InlineAsmOperand::SymFn { expr } => { if cfg!(not(feature = "inline_asm_sym")) { tcx.dcx().span_err( item.span, @@ -63,7 +63,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, ); } - let ty = tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + let ty = tcx.typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { &ty::FnDef(def_id, args) => Instance::new(def_id, args), _ => span_bug!(op_sp, "asm sym is not a function"), diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 26f14532b458e..75f3a3c19724f 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -53,7 +53,7 @@ fn report_atomic_type_validation_error<'tcx>( pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Type { let (element, count) = match layout.backend_repr { - BackendRepr::Vector { element, count } => (element, count), + BackendRepr::SimdVector { element, count } => (element, count), _ => unreachable!(), }; @@ -340,14 +340,10 @@ fn codegen_float_intrinsic_call<'tcx>( sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64, types::F64), sym::truncf32 => ("truncf", 1, fx.tcx.types.f32, types::F32), sym::truncf64 => ("trunc", 1, fx.tcx.types.f64, types::F64), - sym::rintf32 => ("rintf", 1, fx.tcx.types.f32, types::F32), - sym::rintf64 => ("rint", 1, fx.tcx.types.f64, types::F64), + sym::round_ties_even_f32 => ("rintf", 1, fx.tcx.types.f32, types::F32), + sym::round_ties_even_f64 => ("rint", 1, fx.tcx.types.f64, types::F64), sym::roundf32 => ("roundf", 1, fx.tcx.types.f32, types::F32), sym::roundf64 => ("round", 1, fx.tcx.types.f64, types::F64), - sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32, types::F32), - sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64, types::F64), - sym::nearbyintf32 => ("nearbyintf", 1, fx.tcx.types.f32, types::F32), - sym::nearbyintf64 => ("nearbyint", 1, fx.tcx.types.f64, types::F64), sym::sinf32 => ("sinf", 1, fx.tcx.types.f32, types::F32), sym::sinf64 => ("sin", 1, fx.tcx.types.f64, types::F64), sym::cosf32 => ("cosf", 1, fx.tcx.types.f32, types::F32), @@ -399,8 +395,8 @@ fn codegen_float_intrinsic_call<'tcx>( | sym::ceilf64 | sym::truncf32 | sym::truncf64 - | sym::nearbyintf32 - | sym::nearbyintf64 + | sym::round_ties_even_f32 + | sym::round_ties_even_f64 | sym::sqrtf32 | sym::sqrtf64 => { let val = match intrinsic { @@ -408,7 +404,9 @@ fn codegen_float_intrinsic_call<'tcx>( sym::floorf32 | sym::floorf64 => fx.bcx.ins().floor(args[0]), sym::ceilf32 | sym::ceilf64 => fx.bcx.ins().ceil(args[0]), sym::truncf32 | sym::truncf64 => fx.bcx.ins().trunc(args[0]), - sym::nearbyintf32 | sym::nearbyintf64 => fx.bcx.ins().nearest(args[0]), + sym::round_ties_even_f32 | sym::round_ties_even_f64 => { + fx.bcx.ins().nearest(args[0]) + } sym::sqrtf32 | sym::sqrtf64 => fx.bcx.ins().sqrt(args[0]), _ => unreachable!(), }; @@ -1033,7 +1031,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1054,7 +1052,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1075,7 +1073,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Int(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); @@ -1096,7 +1094,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let layout = src.layout(); match layout.ty.kind() { - ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {} + ty::Uint(_) => {} _ => { report_atomic_type_validation_error(fx, intrinsic, source_info.span, layout.ty); return Ok(()); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index fcccda62355c7..dd6d8dbb6f5e0 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -116,8 +116,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - // simd_shuffle_generic(x: T, y: T) -> U - sym::simd_shuffle_generic => { + // simd_shuffle_const_generic(x: T, y: T) -> U + sym::simd_shuffle_const_generic => { let [x, y] = args else { bug!("wrong number of args for intrinsic {intrinsic}"); }; @@ -460,64 +460,6 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }); } - sym::simd_fpow => { - intrinsic_args!(fx, args => (a, b); intrinsic); - - if !a.layout().ty.is_simd() { - report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); - return; - } - - simd_pair_for_each_lane(fx, a, b, ret, &|fx, lane_ty, _ret_lane_ty, a_lane, b_lane| { - match lane_ty.kind() { - ty::Float(FloatTy::F32) => fx.lib_call( - "powf", - vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], - vec![AbiParam::new(types::F32)], - &[a_lane, b_lane], - )[0], - ty::Float(FloatTy::F64) => fx.lib_call( - "pow", - vec![AbiParam::new(types::F64), AbiParam::new(types::F64)], - vec![AbiParam::new(types::F64)], - &[a_lane, b_lane], - )[0], - _ => unreachable!("{:?}", lane_ty), - } - }); - } - - sym::simd_fpowi => { - intrinsic_args!(fx, args => (a, exp); intrinsic); - let exp = exp.load_scalar(fx); - - if !a.layout().ty.is_simd() { - report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); - return; - } - - simd_for_each_lane( - fx, - a, - ret, - &|fx, lane_ty, _ret_lane_ty, lane| match lane_ty.kind() { - ty::Float(FloatTy::F32) => fx.lib_call( - "__powisf2", // compiler-builtins - vec![AbiParam::new(types::F32), AbiParam::new(types::I32)], - vec![AbiParam::new(types::F32)], - &[lane, exp], - )[0], - ty::Float(FloatTy::F64) => fx.lib_call( - "__powidf2", // compiler-builtins - vec![AbiParam::new(types::F64), AbiParam::new(types::I32)], - vec![AbiParam::new(types::F64)], - &[lane, exp], - )[0], - _ => unreachable!("{:?}", lane_ty), - }, - ); - } - sym::simd_fsin | sym::simd_fcos | sym::simd_fexp diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index a3f4374487578..06939beb37423 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -176,13 +176,9 @@ impl CodegenBackend for CraneliftCodegenBackend { } } - fn target_features_cfg( - &self, - sess: &Session, - _allow_unstable: bool, - ) -> Vec { + fn target_features_cfg(&self, sess: &Session) -> (Vec, Vec) { // FIXME return the actually used target features. this is necessary for #[cfg(target_feature)] - if sess.target.arch == "x86_64" && sess.target.os != "none" { + let target_features = if sess.target.arch == "x86_64" && sess.target.os != "none" { // x86_64 mandates SSE2 support and rustc requires the x87 feature to be enabled vec![sym::fsxr, sym::sse, sym::sse2, Symbol::intern("x87")] } else if sess.target.arch == "aarch64" { @@ -196,7 +192,10 @@ impl CodegenBackend for CraneliftCodegenBackend { } } else { vec![] - } + }; + // FIXME do `unstable_target_features` properly + let unstable_target_features = target_features.clone(); + (target_features, unstable_target_features) } fn print_version(&self) { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 1b3f86c8405de..cc739fefcd066 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -173,9 +173,11 @@ impl<'tcx> CValue<'tcx> { CValueInner::ByRef(ptr, None) => { let clif_ty = match layout.backend_repr { BackendRepr::Scalar(scalar) => scalar_to_clif_type(fx.tcx, scalar), - BackendRepr::Vector { element, count } => scalar_to_clif_type(fx.tcx, element) - .by(u32::try_from(count).unwrap()) - .unwrap(), + BackendRepr::SimdVector { element, count } => { + scalar_to_clif_type(fx.tcx, element) + .by(u32::try_from(count).unwrap()) + .unwrap() + } _ => unreachable!("{:?}", layout.ty), }; let mut flags = MemFlags::new(); diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index 2ff1d757fd4e0..5544aee9eaf16 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -591,70 +591,31 @@ pub union MaybeUninit { pub mod intrinsics { #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn size_of() -> usize { - loop {} - } + pub fn size_of() -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn size_of_val(_val: *const T) -> usize { - loop {} - } + pub unsafe fn size_of_val(val: *const T) -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn min_align_of() -> usize { - loop {} - } + pub fn min_align_of() -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn min_align_of_val(_val: *const T) -> usize { - loop {} - } + pub unsafe fn min_align_of_val(val: *const T) -> usize; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize) { - loop {} - } + pub unsafe fn copy(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn transmute(_e: T) -> U { - loop {} - } + pub unsafe fn transmute(e: T) -> U; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn ctlz_nonzero(_x: T) -> u32 { - loop {} - } + pub unsafe fn ctlz_nonzero(x: T) -> u32; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn needs_drop() -> bool { - loop {} - } + pub fn needs_drop() -> bool; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn bitreverse(_x: T) -> T { - loop {} - } + pub fn bitreverse(x: T) -> T; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn bswap(_x: T) -> T { - loop {} - } + pub fn bswap(x: T) -> T; #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize) { - loop {} - } + pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub unsafe fn unreachable() -> ! { - loop {} - } + pub unsafe fn unreachable() -> !; } pub mod libc { diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 717baebcd8cd6..9fe6baa3d2573 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -16,7 +16,7 @@ use crate::context::CodegenCx; use crate::intrinsic::ArgAbiExt; use crate::type_of::LayoutGccExt; -impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { +impl AbiBuilderMethods for Builder<'_, '_, '_> { fn get_param(&mut self, index: usize) -> Self::Value { let func = self.current_func(); let param = func.get_param(index as i32); diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index cb4caec8c326c..e5221c7da3197 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -632,17 +632,16 @@ pub unsafe fn optimize_thin_module( Arc::new(SyncContext::new(context)) } }; - let module = ModuleCodegen { - module_llvm: GccContext { + let module = ModuleCodegen::new_regular( + thin_module.name().to_string(), + GccContext { context, should_combine_object_files, // TODO(antoyo): use the correct relocation model here. relocation_model: RelocModel::Pic, temp_dir: None, }, - name: thin_module.name().to_string(), - kind: ModuleKind::Regular, - }; + ); /*{ let target = &*module.module_llvm.tm; let llmod = module.module_llvm.llmod(); diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 962f4b161d788..9b495174a3fab 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -4,10 +4,10 @@ use std::sync::Arc; use std::time::Instant; use gccjit::{CType, Context, FunctionType, GlobalKind}; +use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::DebugInfoCodegenMethods; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_middle::dep_graph; use rustc_middle::mir::mono::Linkage; #[cfg(feature = "master")] @@ -237,16 +237,15 @@ pub fn compile_codegen_unit( } } - ModuleCodegen { - name: cgu_name.to_string(), - module_llvm: GccContext { + ModuleCodegen::new_regular( + cgu_name.to_string(), + GccContext { context: Arc::new(SyncContext::new(context)), relocation_model: tcx.sess.relocation_model(), should_combine_object_files: false, temp_dir: None, }, - kind: ModuleKind::Regular, - } + ) } (module, cost) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index c8b7616e64509..6573b5b165e61 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -2439,9 +2439,5 @@ fn get_maybe_pointer_size(value: RValue<'_>) -> u32 { #[cfg(not(feature = "master"))] fn get_maybe_pointer_size(value: RValue<'_>) -> u32 { let type_ = value.get_type(); - if type_.get_pointee().is_some() { - std::mem::size_of::<*const ()>() as _ - } else { - type_.get_size() - } + if type_.get_pointee().is_some() { size_of::<*const ()>() as _ } else { type_.get_size() } } diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 20a3482aaa27f..a63da6b6e27d8 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -59,16 +59,11 @@ pub fn type_is_pointer(typ: Type<'_>) -> bool { typ.get_pointee().is_some() } -impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> { if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } - fn is_undef(&self, _val: RValue<'gcc>) -> bool { - // FIXME: actually check for undef - false - } - fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined"); if typ.is_struct().is_some() { @@ -146,13 +141,12 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } fn const_str(&self, s: &str) -> (RValue<'gcc>, RValue<'gcc>) { - let str_global = *self - .const_str_cache - .borrow_mut() - .raw_entry_mut() - .from_key(s) - .or_insert_with(|| (s.to_owned(), self.global_string(s))) - .1; + let mut const_str_cache = self.const_str_cache.borrow_mut(); + let str_global = const_str_cache.get(s).copied().unwrap_or_else(|| { + let g = self.global_string(s); + const_str_cache.insert(s.to_owned(), g); + g + }); let len = s.len(); let cs = self.const_ptrcast( str_global.get_address(None), @@ -263,7 +257,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } } - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { const_alloc_to_gcc(self, alloc) } diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index fb0ca31c54334..c514b7a428bc6 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -302,9 +302,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -pub fn const_alloc_to_gcc<'gcc, 'tcx>( - cx: &CodegenCx<'gcc, 'tcx>, - alloc: ConstAllocation<'tcx>, +pub fn const_alloc_to_gcc<'gcc>( + cx: &CodegenCx<'gcc, '_>, + alloc: ConstAllocation<'_>, ) -> RValue<'gcc> { let alloc = alloc.inner(); let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1); diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 4e8c8aaaf5c8a..6eae0c24f48ad 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -48,7 +48,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec( sym::ceilf64 => "ceil", sym::truncf32 => "truncf", sym::truncf64 => "trunc", - sym::rintf32 => "rintf", - sym::rintf64 => "rint", - sym::nearbyintf32 => "nearbyintf", - sym::nearbyintf64 => "nearbyint", + // We match the LLVM backend and lower this to `rint`. + sym::round_ties_even_f32 => "rintf", + sym::round_ties_even_f64 => "rint", sym::roundf32 => "roundf", sym::roundf64 => "round", - sym::roundevenf32 => "roundevenf", - sym::roundevenf64 => "roundeven", sym::abort => "abort", _ => return None, }; @@ -315,7 +312,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc let layout = self.layout_of(tp_ty).layout; let _use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - Vector { .. } => false, + SimdVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index 84cd5b002fbb6..8b454ab2a4241 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -772,8 +772,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( sym::simd_floor => "floor", sym::simd_fma => "fma", sym::simd_relaxed_fma => "fma", // FIXME: this should relax to non-fused multiply-add when necessary - sym::simd_fpowi => "__builtin_powi", - sym::simd_fpow => "pow", sym::simd_fsin => "sin", sym::simd_fsqrt => "sqrt", sym::simd_round => "round", @@ -788,24 +786,16 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( let mut vector_elements = vec![]; for i in 0..in_len { let index = bx.context.new_rvalue_from_long(bx.ulong_type, i as i64); - // we have to treat fpowi specially, since fpowi's second argument is always an i32 let mut arguments = vec![]; - if name == sym::simd_fpowi { - arguments = vec![ - bx.extract_element(args[0].immediate(), index).to_rvalue(), - args[1].immediate(), - ]; - } else { - for arg in args { - let mut element = bx.extract_element(arg.immediate(), index).to_rvalue(); - // FIXME: it would probably be better to not have casts here and use the proper - // instructions. - if let Some(typ) = cast_type { - element = bx.context.new_cast(None, element, typ); - } - arguments.push(element); + for arg in args { + let mut element = bx.extract_element(arg.immediate(), index).to_rvalue(); + // FIXME: it would probably be better to not have casts here and use the proper + // instructions. + if let Some(typ) = cast_type { + element = bx.context.new_cast(None, element, typ); } - }; + arguments.push(element); + } let mut result = bx.context.new_call(None, function, &arguments); if cast_type.is_some() { result = bx.context.new_cast(None, result, elem_ty); @@ -829,8 +819,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( | sym::simd_floor | sym::simd_fma | sym::simd_relaxed_fma - | sym::simd_fpow - | sym::simd_fpowi | sym::simd_fsin | sym::simd_fsqrt | sym::simd_round diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 6455bcec6851b..d478b2af46c28 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -16,7 +16,7 @@ #![allow(internal_features)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![feature(rustc_private, decl_macro, never_type, trusted_len, hash_raw_entry, let_chains)] +#![feature(rustc_private, decl_macro, never_type, trusted_len, let_chains)] #![allow(broken_intra_doc_links)] #![recursion_limit = "256"] #![warn(rust_2018_idioms)] @@ -259,8 +259,8 @@ impl CodegenBackend for GccCodegenBackend { .join(sess) } - fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec { - target_features_cfg(sess, allow_unstable, &self.target_info) + fn target_features_cfg(&self, sess: &Session) -> (Vec, Vec) { + target_features_cfg(sess, &self.target_info) } } @@ -393,7 +393,7 @@ impl WriteBackendMethods for GccCodegenBackend { unsafe fn optimize( _cgcx: &CodegenContext, _dcx: DiagCtxtHandle<'_>, - module: &ModuleCodegen, + module: &mut ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level)); @@ -486,35 +486,41 @@ fn to_gcc_opt_level(optlevel: Option) -> OptimizationLevel { /// Returns the features that should be set in `cfg(target_feature)`. fn target_features_cfg( sess: &Session, - allow_unstable: bool, target_info: &LockedTargetInfo, -) -> Vec { +) -> (Vec, Vec) { // TODO(antoyo): use global_gcc_features. - sess.target - .rust_target_features() - .iter() - .filter_map(|&(feature, gate, _)| { - if allow_unstable - || (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none())) - { - Some(feature) - } else { - None - } - }) - .filter(|feature| { - // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. - if *feature == "neon" { - return false; - } - target_info.cpu_supports(feature) - /* - adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, - avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, - bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, - sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves - */ - }) - .map(Symbol::intern) - .collect() + let f = |allow_unstable| { + sess.target + .rust_target_features() + .iter() + .filter_map(|&(feature, gate, _)| { + if allow_unstable + || (gate.in_cfg() + && (sess.is_nightly_build() || gate.requires_nightly().is_none())) + { + Some(feature) + } else { + None + } + }) + .filter(|feature| { + // TODO: we disable Neon for now since we don't support the LLVM intrinsics for it. + if *feature == "neon" { + return false; + } + target_info.cpu_supports(feature) + /* + adx, aes, avx, avx2, avx512bf16, avx512bitalg, avx512bw, avx512cd, avx512dq, avx512er, avx512f, avx512fp16, avx512ifma, + avx512pf, avx512vbmi, avx512vbmi2, avx512vl, avx512vnni, avx512vp2intersect, avx512vpopcntdq, + bmi1, bmi2, cmpxchg16b, ermsb, f16c, fma, fxsr, gfni, lzcnt, movbe, pclmulqdq, popcnt, rdrand, rdseed, rtm, + sha, sse, sse2, sse3, sse4.1, sse4.2, sse4a, ssse3, tbm, vaes, vpclmulqdq, xsave, xsavec, xsaveopt, xsaves + */ + }) + .map(Symbol::intern) + .collect() + }; + + let target_features = f(false); + let unstable_target_features = f(true); + (target_features, unstable_target_features) } diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index cb08723431a9a..4e0a250b5509a 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -123,7 +123,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } } -impl<'gcc, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { +impl<'gcc, 'tcx> BaseTypeCodegenMethods for CodegenCx<'gcc, 'tcx> { fn type_i8(&self) -> Type<'gcc> { self.i8_type } diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index bac4fc51300a2..ae98b3d0b56e2 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -63,7 +63,7 @@ fn uncached_gcc_type<'gcc, 'tcx>( ) -> Type<'gcc> { match layout.backend_repr { BackendRepr::Scalar(_) => bug!("handled elsewhere"), - BackendRepr::Vector { ref element, count } => { + BackendRepr::SimdVector { ref element, count } => { let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO); let element = // NOTE: gcc doesn't allow pointer types in vectors. @@ -178,7 +178,7 @@ pub trait LayoutGccExt<'tcx> { impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_immediate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, + BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -186,9 +186,9 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { fn is_gcc_scalar_pair(&self) -> bool { match self.backend_repr { BackendRepr::ScalarPair(..) => true, - BackendRepr::Scalar(_) | BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => { - false - } + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs index 385e41a68817f..fe46d9ae41849 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs @@ -36,10 +36,7 @@ mod intrinsics { #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; } /* diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs index 6c66a930e0741..4123f4f4beebc 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs @@ -36,10 +36,7 @@ mod intrinsics { #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; } /* diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs index 4d414c577a657..286155852d50f 100644 --- a/compiler/rustc_codegen_gcc/tests/run/assign.rs +++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs @@ -59,10 +59,7 @@ mod libc { mod intrinsics { #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; } #[lang = "panic"] diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs index 9be64f991ee08..b0215860406e5 100644 --- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs +++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs @@ -61,10 +61,7 @@ mod libc { mod intrinsics { #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; } #[lang = "panic"] diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs index c92d3cc0b8fbf..8ba7a4c5ed8ce 100644 --- a/compiler/rustc_codegen_gcc/tests/run/operations.rs +++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs @@ -67,10 +67,7 @@ mod libc { mod intrinsics { #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; } #[lang = "panic"] diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index 80c8782c4b1a6..c3c8121b1e195 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -49,10 +49,7 @@ mod intrinsics { #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - pub fn abort() -> ! { - loop {} - } + pub fn abort() -> !; } mod libc { diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index a817227054885..d3ce7c5a1130f 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_llvm" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] test = false diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 8c75125e009b9..7105933815138 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -654,7 +654,7 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { } } -impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { +impl AbiBuilderMethods for Builder<'_, '_, '_> { fn get_param(&mut self, index: usize) -> Self::Value { llvm::get_param(self.llfn(), index as c_uint) } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 66723cbf88206..e614115f64b9f 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -3,33 +3,31 @@ use rustc_ast::expand::allocator::{ ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, default_fn_name, global_fn_name, }; +use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DebugInfo, OomStrategy}; -use crate::common::AsCCharPtr; -use crate::llvm::{self, Context, False, Module, True, Type}; -use crate::{ModuleLlvm, attributes, debuginfo}; +use crate::builder::SBuilder; +use crate::declare::declare_simple_fn; +use crate::llvm::{self, False, True, Type}; +use crate::{SimpleCx, attributes, debuginfo}; pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, - module_llvm: &mut ModuleLlvm, + cx: SimpleCx<'_>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) { - let llcx = &*module_llvm.llcx; - let llmod = module_llvm.llmod(); - let usize = unsafe { - match tcx.sess.target.pointer_width { - 16 => llvm::LLVMInt16TypeInContext(llcx), - 32 => llvm::LLVMInt32TypeInContext(llcx), - 64 => llvm::LLVMInt64TypeInContext(llcx), - tws => bug!("Unsupported target word size for int: {}", tws), - } + let usize = match tcx.sess.target.pointer_width { + 16 => cx.type_i16(), + 32 => cx.type_i32(), + 64 => cx.type_i64(), + tws => bug!("Unsupported target word size for int: {}", tws), }; - let i8 = unsafe { llvm::LLVMInt8TypeInContext(llcx) }; - let i8p = unsafe { llvm::LLVMPointerTypeInContext(llcx, 0) }; + let i8 = cx.type_i8(); + let i8p = cx.type_ptr(); if kind == AllocatorKind::Default { for method in ALLOCATOR_METHODS { @@ -58,15 +56,14 @@ pub(crate) unsafe fn codegen( let from_name = global_fn_name(method.name); let to_name = default_fn_name(method.name); - create_wrapper_function(tcx, llcx, llmod, &from_name, &to_name, &args, output, false); + create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false); } } // rust alloc error handler create_wrapper_function( tcx, - llcx, - llmod, + &cx, "__rust_alloc_error_handler", alloc_error_handler_name(alloc_error_handler_kind), &[usize, usize], // size, align @@ -77,21 +74,21 @@ pub(crate) unsafe fn codegen( unsafe { // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + let ll_g = cx.declare_global(name, i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::set_initializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; - let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_c_char_ptr(), name.len(), i8); + let ll_g = cx.declare_global(name, i8); llvm::set_visibility(ll_g, llvm::Visibility::from_generic(tcx.sess.default_visibility())); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::set_initializer(ll_g, llval); } if tcx.sess.opts.debuginfo != DebugInfo::None { - let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod); + let dbg_cx = debuginfo::CodegenUnitDebugContext::new(cx.llmod); debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx); dbg_cx.finalize(tcx.sess); } @@ -99,77 +96,64 @@ pub(crate) unsafe fn codegen( fn create_wrapper_function( tcx: TyCtxt<'_>, - llcx: &Context, - llmod: &Module, + cx: &SimpleCx<'_>, from_name: &str, to_name: &str, args: &[&Type], output: Option<&Type>, no_return: bool, ) { - unsafe { - let ty = llvm::LLVMFunctionType( - output.unwrap_or_else(|| llvm::LLVMVoidTypeInContext(llcx)), - args.as_ptr(), - args.len() as c_uint, - False, - ); - let llfn = llvm::LLVMRustGetOrInsertFunction( - llmod, - from_name.as_c_char_ptr(), - from_name.len(), - ty, - ); - let no_return = if no_return { - // -> ! DIFlagNoReturn - let no_return = llvm::AttributeKind::NoReturn.create_attr(llcx); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); - Some(no_return) - } else { - None - }; - - llvm::set_visibility(llfn, llvm::Visibility::from_generic(tcx.sess.default_visibility())); - - if tcx.sess.must_emit_unwind_tables() { - let uwtable = - attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); - attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); - } + let ty = cx.type_func(args, output.unwrap_or_else(|| cx.type_void())); + let llfn = declare_simple_fn( + &cx, + from_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ty, + ); + let no_return = if no_return { + // -> ! DIFlagNoReturn + let no_return = llvm::AttributeKind::NoReturn.create_attr(cx.llcx); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[no_return]); + Some(no_return) + } else { + None + }; - let callee = - llvm::LLVMRustGetOrInsertFunction(llmod, to_name.as_c_char_ptr(), to_name.len(), ty); - if let Some(no_return) = no_return { - // -> ! DIFlagNoReturn - attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); - } - llvm::set_visibility(callee, llvm::Visibility::Hidden); - - let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, c"entry".as_ptr()); - - let llbuilder = llvm::LLVMCreateBuilderInContext(llcx); - llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb); - let args = args - .iter() - .enumerate() - .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint)) - .collect::>(); - let ret = llvm::LLVMBuildCallWithOperandBundles( - llbuilder, - ty, - callee, - args.as_ptr(), - args.len() as c_uint, - [].as_ptr(), - 0 as c_uint, - c"".as_ptr(), - ); - llvm::LLVMSetTailCall(ret, True); - if output.is_some() { - llvm::LLVMBuildRet(llbuilder, ret); - } else { - llvm::LLVMBuildRetVoid(llbuilder); - } - llvm::LLVMDisposeBuilder(llbuilder); + if tcx.sess.must_emit_unwind_tables() { + let uwtable = + attributes::uwtable_attr(cx.llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); + attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]); + } + + let callee = declare_simple_fn( + &cx, + to_name, + llvm::CallConv::CCallConv, + llvm::UnnamedAddr::Global, + llvm::Visibility::Hidden, + ty, + ); + if let Some(no_return) = no_return { + // -> ! DIFlagNoReturn + attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]); + } + llvm::set_visibility(callee, llvm::Visibility::Hidden); + + let llbb = unsafe { llvm::LLVMAppendBasicBlockInContext(cx.llcx, llfn, c"entry".as_ptr()) }; + + let mut bx = SBuilder::build(&cx, llbb); + let args = args + .iter() + .enumerate() + .map(|(i, _)| llvm::get_param(llfn, i as c_uint)) + .collect::>(); + let ret = bx.call(ty, callee, &args, None); + llvm::LLVMSetTailCall(ret, True); + if output.is_some() { + bx.ret(ret); + } else { + bx.ret_void() } } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index be5673eddf93e..88daa02574048 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -1,6 +1,5 @@ use std::assert_matches::assert_matches; -use libc::{c_char, c_uint}; use rustc_abi::{BackendRepr, Float, Integer, Primitive, Scalar}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_codegen_ssa::mir::operand::OperandValue; @@ -483,12 +482,13 @@ pub(crate) fn inline_asm_call<'ll>( debug!("Asm Output Type: {:?}", output); let fty = bx.cx.type_func(&argtys, output); - unsafe { - // Ask LLVM to verify that the constraints are well-formed. - let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()); - debug!("constraint verification result: {:?}", constraints_ok); - if constraints_ok { - let v = llvm::LLVMRustInlineAsm( + // Ask LLVM to verify that the constraints are well-formed. + let constraints_ok = + unsafe { llvm::LLVMRustInlineAsmVerify(fty, cons.as_c_char_ptr(), cons.len()) }; + debug!("constraint verification result: {:?}", constraints_ok); + if constraints_ok { + let v = unsafe { + llvm::LLVMRustInlineAsm( fty, asm.as_c_char_ptr(), asm.len(), @@ -498,54 +498,50 @@ pub(crate) fn inline_asm_call<'ll>( alignstack, dia, can_throw, - ); - - let call = if !labels.is_empty() { - assert!(catch_funclet.is_none()); - bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) - } else if let Some((catch, funclet)) = catch_funclet { - bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) - } else { - bx.call(fty, None, None, v, inputs, None, None) - }; + ) + }; - // Store mark in a metadata node so we can map LLVM errors - // back to source locations. See #17552. - let key = "srcloc"; - let kind = llvm::LLVMGetMDKindIDInContext( - bx.llcx, - key.as_ptr().cast::(), - key.len() as c_uint, - ); + let call = if !labels.is_empty() { + assert!(catch_funclet.is_none()); + bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None, None) + } else if let Some((catch, funclet)) = catch_funclet { + bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet, None) + } else { + bx.call(fty, None, None, v, inputs, None, None) + }; - // `srcloc` contains one 64-bit integer for each line of assembly code, - // where the lower 32 bits hold the lo byte position and the upper 32 bits - // hold the hi byte position. - let mut srcloc = vec![]; - if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { - // LLVM inserts an extra line to add the ".intel_syntax", so add - // a dummy srcloc entry for it. - // - // Don't do this if we only have 1 line span since that may be - // due to the asm template string coming from a macro. LLVM will - // default to the first srcloc for lines that don't have an - // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); - } - srcloc.extend(line_spans.iter().map(|span| { - llvm::LLVMValueAsMetadata(bx.const_u64( - u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32), - )) - })); - let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()); - let md = llvm::LLVMMetadataAsValue(&bx.llcx, md); - llvm::LLVMSetMetadata(call, kind, md); + // Store mark in a metadata node so we can map LLVM errors + // back to source locations. See #17552. + let key = "srcloc"; + let kind = bx.get_md_kind_id(key); - Some(call) - } else { - // LLVM has detected an issue with our constraints, bail out - None + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. + let mut srcloc = vec![]; + if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { + // LLVM inserts an extra line to add the ".intel_syntax", so add + // a dummy srcloc entry for it. + // + // Don't do this if we only have 1 line span since that may be + // due to the asm template string coming from a macro. LLVM will + // default to the first srcloc for lines that don't have an + // associated srcloc. + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); } + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata( + bx.const_u64(u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32)), + ) + })); + let md = unsafe { llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()) }; + let md = bx.get_metadata_value(md); + llvm::LLVMSetMetadata(call, kind, md); + + Some(call) + } else { + // LLVM has detected an issue with our constraints, bail out + None } } @@ -939,9 +935,10 @@ fn llvm_fixup_input<'ll, 'tcx>( } bx.insert_element(bx.const_undef(vec_ty), value, bx.const_i32(0)) } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) - if layout.size.bytes() == 8 => - { + ( + AArch64(AArch64InlineAsmRegClass::vreg_low16), + BackendRepr::SimdVector { element, count }, + ) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); let vec_ty = bx.cx.type_vector(elem_ty, count); let indices: Vec<_> = (0..count * 2).map(|x| bx.const_i32(x as i32)).collect(); @@ -954,7 +951,7 @@ fn llvm_fixup_input<'ll, 'tcx>( } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - BackendRepr::Vector { .. }, + BackendRepr::SimdVector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, bx.cx.type_vector(bx.cx.type_f64(), 8)), ( X86( @@ -989,7 +986,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - BackendRepr::Vector { element, count: count @ (8 | 16) }, + BackendRepr::SimdVector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } @@ -1026,7 +1023,7 @@ fn llvm_fixup_input<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - BackendRepr::Vector { element, count: count @ (4 | 8) }, + BackendRepr::SimdVector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_i16(), count)) } @@ -1099,9 +1096,10 @@ fn llvm_fixup_output<'ll, 'tcx>( } value } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) - if layout.size.bytes() == 8 => - { + ( + AArch64(AArch64InlineAsmRegClass::vreg_low16), + BackendRepr::SimdVector { element, count }, + ) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(bx.cx, element); let vec_ty = bx.cx.type_vector(elem_ty, count * 2); let indices: Vec<_> = (0..count).map(|x| bx.const_i32(x as i32)).collect(); @@ -1114,7 +1112,7 @@ fn llvm_fixup_output<'ll, 'tcx>( } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - BackendRepr::Vector { .. }, + BackendRepr::SimdVector { .. }, ) if layout.size.bytes() == 64 => bx.bitcast(value, layout.llvm_type(bx.cx)), ( X86( @@ -1145,7 +1143,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - BackendRepr::Vector { element, count: count @ (8 | 16) }, + BackendRepr::SimdVector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } @@ -1182,7 +1180,7 @@ fn llvm_fixup_output<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - BackendRepr::Vector { element, count: count @ (4 | 8) }, + BackendRepr::SimdVector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { bx.bitcast(value, bx.type_vector(bx.type_f16(), count)) } @@ -1243,9 +1241,10 @@ fn llvm_fixup_output_type<'ll, 'tcx>( let count = 16 / layout.size.bytes(); cx.type_vector(elem_ty, count) } - (AArch64(AArch64InlineAsmRegClass::vreg_low16), BackendRepr::Vector { element, count }) - if layout.size.bytes() == 8 => - { + ( + AArch64(AArch64InlineAsmRegClass::vreg_low16), + BackendRepr::SimdVector { element, count }, + ) if layout.size.bytes() == 8 => { let elem_ty = llvm_asm_scalar_type(cx, element); cx.type_vector(elem_ty, count * 2) } @@ -1256,7 +1255,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( } ( X86(X86InlineAsmRegClass::xmm_reg | X86InlineAsmRegClass::zmm_reg), - BackendRepr::Vector { .. }, + BackendRepr::SimdVector { .. }, ) if layout.size.bytes() == 64 => cx.type_vector(cx.type_f64(), 8), ( X86( @@ -1284,7 +1283,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | X86InlineAsmRegClass::ymm_reg | X86InlineAsmRegClass::zmm_reg, ), - BackendRepr::Vector { element, count: count @ (8 | 16) }, + BackendRepr::SimdVector { element, count: count @ (8 | 16) }, ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } @@ -1321,7 +1320,7 @@ fn llvm_fixup_output_type<'ll, 'tcx>( | ArmInlineAsmRegClass::qreg_low4 | ArmInlineAsmRegClass::qreg_low8, ), - BackendRepr::Vector { element, count: count @ (4 | 8) }, + BackendRepr::SimdVector { element, count: count @ (4 | 8) }, ) if element.primitive() == Primitive::Float(Float::F16) => { cx.type_vector(cx.type_i16(), count) } diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 93553f3f3648a..0a161442933ab 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -132,14 +132,33 @@ fn get_llvm_object_symbols( if err.is_null() { return Ok(true); } else { - return Err(unsafe { *Box::from_raw(err as *mut io::Error) }); + let error = unsafe { *Box::from_raw(err as *mut io::Error) }; + // These are the magic constants for LLVM bitcode files: + // https://github.com/llvm/llvm-project/blob/7eadc1960d199676f04add402bb0aa6f65b7b234/llvm/lib/BinaryFormat/Magic.cpp#L90-L97 + if buf.starts_with(&[0xDE, 0xCE, 0x17, 0x0B]) || buf.starts_with(&[b'B', b'C', 0xC0, 0xDE]) + { + // For LLVM bitcode, failure to read the symbols is not fatal. The bitcode may have been + // produced by a newer LLVM version that the one linked to rustc. This is fine provided + // that the linker does use said newer LLVM version. We skip writing the symbols for the + // bitcode to the symbol table of the archive. Traditional linkers don't like this, but + // newer linkers like lld, mold and wild ignore the symbol table anyway, so if they link + // against a new enough LLVM it will work out in the end. + // LLVM's archive writer also has this same behavior of only warning about invalid + // bitcode since https://github.com/llvm/llvm-project/pull/96848 + + // We don't have access to the DiagCtxt here to produce a nice warning in the correct format. + eprintln!("warning: Failed to read symbol table from LLVM bitcode: {}", error); + return Ok(true); + } else { + return Err(error); + } } unsafe extern "C" fn callback(state: *mut c_void, symbol_name: *const c_char) -> *mut c_void { let f = unsafe { &mut *(state as *mut &mut dyn FnMut(&[u8]) -> io::Result<()>) }; match f(unsafe { CStr::from_ptr(symbol_name) }.to_bytes()) { Ok(()) => std::ptr::null_mut(), - Err(err) => Box::into_raw(Box::new(err)) as *mut c_void, + Err(err) => Box::into_raw(Box::new(err) as Box) as *mut c_void, } } @@ -148,7 +167,7 @@ fn get_llvm_object_symbols( Box::into_raw(Box::new(io::Error::new( io::ErrorKind::Other, format!("LLVM error: {}", error.to_string_lossy()), - ))) as *mut c_void + )) as Box) as *mut c_void } } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 99906ea7bce39..668795191a29a 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use std::ffi::{CStr, CString}; use std::fs::File; use std::path::Path; +use std::ptr::NonNull; use std::sync::Arc; use std::{io, iter, slice}; @@ -305,11 +306,8 @@ fn fat_lto( assert!(!serialized_modules.is_empty(), "must have at least one serialized module"); let (buffer, name) = serialized_modules.remove(0); info!("no in-memory regular modules to choose from, parsing {:?}", name); - ModuleCodegen { - module_llvm: ModuleLlvm::parse(cgcx, &name, buffer.data(), dcx)?, - name: name.into_string().unwrap(), - kind: ModuleKind::Regular, - } + let llvm_module = ModuleLlvm::parse(cgcx, &name, buffer.data(), dcx)?; + ModuleCodegen::new_regular(name.into_string().unwrap(), llvm_module) } }; { @@ -655,14 +653,14 @@ pub(crate) fn run_pass_manager( } unsafe { - write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage, stage)?; + write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?; } if cfg!(llvm_enzyme) && enable_ad { let opt_stage = llvm::OptStage::FatLTO; let stage = write::AutodiffStage::PostAD; unsafe { - write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage, stage)?; + write::llvm_optimize(cgcx, dcx, module, None, config, opt_level, opt_stage, stage)?; } // This is the final IR, so people should be able to inspect the optimized autodiff output. @@ -729,6 +727,11 @@ impl ThinBuffer { ThinBuffer(buffer) } } + + pub unsafe fn from_raw_ptr(ptr: *mut llvm::ThinLTOBuffer) -> ThinBuffer { + let mut ptr = NonNull::new(ptr).unwrap(); + ThinBuffer(unsafe { ptr.as_mut() }) + } } impl ThinBufferMethods for ThinBuffer { @@ -772,11 +775,11 @@ pub(crate) unsafe fn optimize_thin_module( // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let module_llvm = ModuleLlvm::parse(cgcx, module_name, thin_module.data(), dcx)?; - let mut module = ModuleCodegen { - module_llvm, - name: thin_module.name().to_string(), - kind: ModuleKind::Regular, - }; + let mut module = ModuleCodegen::new_regular(thin_module.name(), module_llvm); + // Given that the newly created module lacks a thinlto buffer for embedding, we need to re-add it here. + if cgcx.config(ModuleKind::Regular).embed_bitcode() { + module.thin_lto_buffer = Some(thin_module.data().to_vec()); + } { let target = &*module.module_llvm.tm; let llmod = module.module_llvm.llmod(); @@ -793,7 +796,9 @@ pub(crate) unsafe fn optimize_thin_module( { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name()); - unsafe { llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) }; + unsafe { + llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target.raw()) + }; save_temp_bitcode(cgcx, &module, "thin-lto-after-rename"); } @@ -823,7 +828,7 @@ pub(crate) unsafe fn optimize_thin_module( let _timer = cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name()); if unsafe { - !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) + !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target.raw()) } { return Err(write::llvm_err(dcx, LlvmError::PrepareThinLtoModule)); } diff --git a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs index f075f332462fc..dfde45955906c 100644 --- a/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs +++ b/compiler/rustc_codegen_llvm/src/back/owned_target_machine.rs @@ -1,6 +1,5 @@ use std::ffi::{CStr, c_char}; use std::marker::PhantomData; -use std::ops::Deref; use std::ptr::NonNull; use rustc_data_structures::small_c_str::SmallCStr; @@ -80,12 +79,12 @@ impl OwnedTargetMachine { .map(|tm_unique| Self { tm_unique, phantom: PhantomData }) .ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) }) } -} - -impl Deref for OwnedTargetMachine { - type Target = llvm::TargetMachine; - fn deref(&self) -> &Self::Target { + /// Returns inner `llvm::TargetMachine` type. + /// + /// This could be a `Deref` implementation, but `llvm::TargetMachine` is an extern type and + /// `Deref::Target: ?Sized`. + pub fn raw(&self) -> &llvm::TargetMachine { // SAFETY: constructing ensures we have a valid pointer created by // llvm::LLVMRustCreateTargetMachine. unsafe { self.tm_unique.as_ref() } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b67890c046572..bead4c82a8120 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -1,6 +1,7 @@ use std::ffi::{CStr, CString}; use std::io::{self, Write}; use std::path::{Path, PathBuf}; +use std::ptr::null_mut; use std::sync::Arc; use std::{fs, slice, str}; @@ -15,7 +16,7 @@ use rustc_codegen_ssa::back::write::{ TargetMachineFactoryFn, }; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; +use rustc_codegen_ssa::{CompiledModule, ModuleCodegen, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; use rustc_errors::{DiagCtxtHandle, FatalError, Level}; @@ -551,6 +552,7 @@ pub(crate) unsafe fn llvm_optimize( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, module: &ModuleCodegen, + thin_lto_buffer: Option<&mut *mut llvm::ThinLTOBuffer>, config: &ModuleConfig, opt_level: config::OptLevel, opt_stage: llvm::OptStage, @@ -584,7 +586,17 @@ pub(crate) unsafe fn llvm_optimize( vectorize_loop = config.vectorize_loop; } trace!(?unroll_loops, ?vectorize_slp, ?vectorize_loop, ?run_enzyme); - let using_thin_buffers = opt_stage == llvm::OptStage::PreLinkThinLTO || config.bitcode_needed(); + if thin_lto_buffer.is_some() { + assert!( + matches!( + opt_stage, + llvm::OptStage::PreLinkNoLTO + | llvm::OptStage::PreLinkFatLTO + | llvm::OptStage::PreLinkThinLTO + ), + "the bitcode for LTO can only be obtained at the pre-link stage" + ); + } let pgo_gen_path = get_pgo_gen_path(config); let pgo_use_path = get_pgo_use_path(config); let pgo_sample_use_path = get_pgo_sample_use_path(config); @@ -637,14 +649,16 @@ pub(crate) unsafe fn llvm_optimize( let result = unsafe { llvm::LLVMRustOptimize( module.module_llvm.llmod(), - &*module.module_llvm.tm, + &*module.module_llvm.tm.raw(), to_pass_builder_opt_level(opt_level), opt_stage, cgcx.opts.cg.linker_plugin_lto.enabled(), config.no_prepopulate_passes, config.verify_llvm_ir, config.lint_llvm_ir, - using_thin_buffers, + thin_lto_buffer, + config.emit_thin_lto, + config.emit_thin_lto_summary, config.merge_functions, unroll_loops, vectorize_slp, @@ -675,7 +689,7 @@ pub(crate) unsafe fn llvm_optimize( pub(crate) unsafe fn optimize( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, - module: &ModuleCodegen, + module: &mut ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_optimize", &*module.name); @@ -705,9 +719,53 @@ pub(crate) unsafe fn optimize( // Otherwise we pretend AD is already done and run the normal opt pipeline (=PostAD). let consider_ad = cfg!(llvm_enzyme) && config.autodiff.contains(&config::AutoDiff::Enable); let autodiff_stage = if consider_ad { AutodiffStage::PreAD } else { AutodiffStage::PostAD }; - return unsafe { - llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage, autodiff_stage) + // The embedded bitcode is used to run LTO/ThinLTO. + // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO. + // It may have undergone LTO due to ThinLocal, so we need to obtain the embedded bitcode at + // this point. + let mut thin_lto_buffer = if (module.kind == ModuleKind::Regular + && config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full)) + || config.emit_thin_lto_summary + { + Some(null_mut()) + } else { + None }; + unsafe { + llvm_optimize( + cgcx, + dcx, + module, + thin_lto_buffer.as_mut(), + config, + opt_level, + opt_stage, + autodiff_stage, + ) + }?; + if let Some(thin_lto_buffer) = thin_lto_buffer { + let thin_lto_buffer = unsafe { ThinBuffer::from_raw_ptr(thin_lto_buffer) }; + module.thin_lto_buffer = Some(thin_lto_buffer.data().to_vec()); + let bc_summary_out = + cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name); + if config.emit_thin_lto_summary + && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() + { + let summary_data = thin_lto_buffer.thin_link_data(); + cgcx.prof.artifact_size( + "llvm_bitcode_summary", + thin_link_bitcode_filename.to_string_lossy(), + summary_data.len() as u64, + ); + let _timer = cgcx.prof.generic_activity_with_arg( + "LLVM_module_codegen_emit_bitcode_summary", + &*module.name, + ); + if let Err(err) = fs::write(&bc_summary_out, summary_data) { + dcx.emit_err(WriteBytecode { path: &bc_summary_out, err }); + } + } + } } Ok(()) } @@ -760,59 +818,41 @@ pub(crate) unsafe fn codegen( // otherwise requested. let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); - let bc_summary_out = - cgcx.output_filenames.temp_path(OutputType::ThinLinkBitcode, module_name); let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name); if config.bitcode_needed() { - let _timer = cgcx - .prof - .generic_activity_with_arg("LLVM_module_codegen_make_bitcode", &*module.name); - let thin = ThinBuffer::new(llmod, config.emit_thin_lto, config.emit_thin_lto_summary); - let data = thin.data(); - - if let Some(bitcode_filename) = bc_out.file_name() { - cgcx.prof.artifact_size( - "llvm_bitcode", - bitcode_filename.to_string_lossy(), - data.len() as u64, - ); - } - - if config.emit_thin_lto_summary - && let Some(thin_link_bitcode_filename) = bc_summary_out.file_name() - { - let summary_data = thin.thin_link_data(); - cgcx.prof.artifact_size( - "llvm_bitcode_summary", - thin_link_bitcode_filename.to_string_lossy(), - summary_data.len() as u64, - ); - - let _timer = cgcx.prof.generic_activity_with_arg( - "LLVM_module_codegen_emit_bitcode_summary", - &*module.name, - ); - if let Err(err) = fs::write(&bc_summary_out, summary_data) { - dcx.emit_err(WriteBytecode { path: &bc_summary_out, err }); - } - } - if config.emit_bc || config.emit_obj == EmitObj::Bitcode { + let thin = { + let _timer = cgcx.prof.generic_activity_with_arg( + "LLVM_module_codegen_make_bitcode", + &*module.name, + ); + ThinBuffer::new(llmod, config.emit_thin_lto, false) + }; + let data = thin.data(); let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_emit_bitcode", &*module.name); + if let Some(bitcode_filename) = bc_out.file_name() { + cgcx.prof.artifact_size( + "llvm_bitcode", + bitcode_filename.to_string_lossy(), + data.len() as u64, + ); + } if let Err(err) = fs::write(&bc_out, data) { dcx.emit_err(WriteBytecode { path: &bc_out, err }); } } - if config.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) { + if config.embed_bitcode() && module.kind == ModuleKind::Regular { let _timer = cgcx .prof .generic_activity_with_arg("LLVM_module_codegen_embed_bitcode", &*module.name); + let thin_bc = + module.thin_lto_buffer.as_deref().expect("cannot find embedded bitcode"); unsafe { - embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, data); + embed_bitcode(cgcx, llcx, llmod, &config.bc_cmdline, &thin_bc); } } } @@ -875,7 +915,7 @@ pub(crate) unsafe fn codegen( }; write_output_file( dcx, - tm, + tm.raw(), config.no_builtins, llmod, &path, @@ -909,7 +949,7 @@ pub(crate) unsafe fn codegen( write_output_file( dcx, - tm, + tm.raw(), config.no_builtins, llmod, &obj_out, diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index d35c7945baec4..6bd27914dbd16 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -13,10 +13,10 @@ use std::time::Instant; +use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::base::maybe_create_entry_wrapper; use rustc_codegen_ssa::mono_item::MonoItemExt; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::{ModuleCodegen, ModuleKind}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_middle::dep_graph; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; @@ -133,11 +133,7 @@ pub(crate) fn compile_codegen_unit( } } - ModuleCodegen { - name: cgu_name.to_string(), - module_llvm: llvm_module, - kind: ModuleKind::Regular, - } + ModuleCodegen::new_regular(cgu_name.to_string(), llvm_module) } (module, cost) diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index e1609e31c0707..55d34f5f2efe2 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -30,23 +30,25 @@ use tracing::{debug, instrument}; use crate::abi::FnAbiLlvmExt; use crate::common::Funclet; -use crate::context::{CodegenCx, SimpleCx}; -use crate::llvm::{self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, Metadata, True}; +use crate::context::{CodegenCx, FullCx, GenericCx, SCx}; +use crate::llvm::{ + self, AtomicOrdering, AtomicRmwBinOp, BasicBlock, False, GEPNoWrapFlags, Metadata, True, +}; use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use crate::{attributes, llvm_util}; #[must_use] -pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow>> { +pub(crate) struct GenericBuilder<'a, 'll, CX: Borrow>> { pub llbuilder: &'ll mut llvm::Builder<'ll>, - pub cx: &'a CX, + pub cx: &'a GenericCx<'ll, CX>, } -pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SimpleCx<'ll>>; -pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, CodegenCx<'ll, 'tcx>>; +pub(crate) type SBuilder<'a, 'll> = GenericBuilder<'a, 'll, SCx<'ll>>; +pub(crate) type Builder<'a, 'll, 'tcx> = GenericBuilder<'a, 'll, FullCx<'ll, 'tcx>>; -impl<'a, 'll, CX: Borrow>> Drop for GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> Drop for GenericBuilder<'a, 'll, CX> { fn drop(&mut self) { unsafe { llvm::LLVMDisposeBuilder(&mut *(self.llbuilder as *mut _)); @@ -55,7 +57,7 @@ impl<'a, 'll, CX: Borrow>> Drop for GenericBuilder<'a, 'll, CX> { } impl<'a, 'll> SBuilder<'a, 'll> { - fn call( + pub(crate) fn call( &mut self, llty: &'ll Type, llfn: &'ll Value, @@ -85,79 +87,36 @@ impl<'a, 'll> SBuilder<'a, 'll> { }; call } +} - fn with_scx(scx: &'a SimpleCx<'ll>) -> Self { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { + fn with_cx(scx: &'a GenericCx<'ll, CX>) -> Self { // Create a fresh builder from the simple context. - let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.llcx) }; - SBuilder { llbuilder, cx: scx } + let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(scx.deref().borrow().llcx) }; + GenericBuilder { llbuilder, cx: scx } } -} -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { + pub(crate) fn bitcast(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildBitCast(self.llbuilder, val, dest_ty, UNNAMED) } } - fn ret_void(&mut self) { - unsafe { - llvm::LLVMBuildRetVoid(self.llbuilder); - } + pub(crate) fn ret_void(&mut self) { + llvm::LLVMBuildRetVoid(self.llbuilder); } - fn ret(&mut self, v: &'ll Value) { + pub(crate) fn ret(&mut self, v: &'ll Value) { unsafe { llvm::LLVMBuildRet(self.llbuilder, v); } } -} -impl<'a, 'll> SBuilder<'a, 'll> { - fn build(cx: &'a SimpleCx<'ll>, llbb: &'ll BasicBlock) -> SBuilder<'a, 'll> { - let bx = SBuilder::with_scx(cx); + + pub(crate) fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self { + let bx = Self::with_cx(cx); unsafe { llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb); } bx } - - fn check_call<'b>( - &mut self, - typ: &str, - fn_ty: &'ll Type, - llfn: &'ll Value, - args: &'b [&'ll Value], - ) -> Cow<'b, [&'ll Value]> { - assert!( - self.cx.type_kind(fn_ty) == TypeKind::Function, - "builder::{typ} not passed a function, but {fn_ty:?}" - ); - - let param_tys = self.cx.func_params_types(fn_ty); - - let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.cx.val_ty(v))) - .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); - - if all_args_match { - return Cow::Borrowed(args); - } - - let casted_args: Vec<_> = iter::zip(param_tys, args) - .enumerate() - .map(|(i, (expected_ty, &actual_val))| { - let actual_ty = self.cx.val_ty(actual_val); - if expected_ty != actual_ty { - debug!( - "type mismatch in function call of {:?}. \ - Expected {:?} for param {}, got {:?}; injecting bitcast", - llfn, expected_ty, i, actual_ty - ); - self.bitcast(actual_val, expected_ty) - } else { - actual_val - } - }) - .collect(); - - Cow::Owned(casted_args) - } } /// Empty string, to be used where LLVM expects an instruction name, indicating @@ -165,17 +124,17 @@ impl<'a, 'll> SBuilder<'a, 'll> { // FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer. const UNNAMED: *const c_char = c"".as_ptr(); -impl<'ll, 'tcx> BackendTypes for Builder<'_, 'll, 'tcx> { - type Value = as BackendTypes>::Value; - type Metadata = as BackendTypes>::Metadata; - type Function = as BackendTypes>::Function; - type BasicBlock = as BackendTypes>::BasicBlock; - type Type = as BackendTypes>::Type; - type Funclet = as BackendTypes>::Funclet; - - type DIScope = as BackendTypes>::DIScope; - type DILocation = as BackendTypes>::DILocation; - type DIVariable = as BackendTypes>::DIVariable; +impl<'ll, CX: Borrow>> BackendTypes for GenericBuilder<'_, 'll, CX> { + type Value = as BackendTypes>::Value; + type Metadata = as BackendTypes>::Metadata; + type Function = as BackendTypes>::Function; + type BasicBlock = as BackendTypes>::BasicBlock; + type Type = as BackendTypes>::Type; + type Funclet = as BackendTypes>::Funclet; + + type DIScope = as BackendTypes>::DIScope; + type DILocation = as BackendTypes>::DILocation; + type DIVariable = as BackendTypes>::DIVariable; } impl abi::HasDataLayout for Builder<'_, '_, '_> { @@ -291,9 +250,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn ret_void(&mut self) { - unsafe { - llvm::LLVMBuildRetVoid(self.llbuilder); - } + llvm::LLVMBuildRetVoid(self.llbuilder); } fn ret(&mut self, v: &'ll Value) { @@ -354,8 +311,8 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // This function handles switch instructions with more than 2 targets and it needs to // emit branch weights metadata instead of using the intrinsic. // The values 1 and 2000 are the same as the values used by the `llvm.expect` intrinsic. - let cold_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(1)) }; - let hot_weight = unsafe { llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)) }; + let cold_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(1)); + let hot_weight = llvm::LLVMValueAsMetadata(self.cx.const_u32(2000)); let weight = |is_cold: bool| -> &Metadata { if is_cold { cold_weight } else { hot_weight } }; @@ -403,7 +360,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { + if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) { bundles.push(kcfi_bundle); } @@ -910,13 +867,14 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { fn gep(&mut self, ty: &'ll Type, ptr: &'ll Value, indices: &[&'ll Value]) -> &'ll Value { unsafe { - llvm::LLVMBuildGEP2( + llvm::LLVMBuildGEPWithNoWrapFlags( self.llbuilder, ty, ptr, indices.as_ptr(), indices.len() as c_uint, UNNAMED, + GEPNoWrapFlags::default(), ) } } @@ -928,13 +886,33 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { indices: &[&'ll Value], ) -> &'ll Value { unsafe { - llvm::LLVMBuildInBoundsGEP2( + llvm::LLVMBuildGEPWithNoWrapFlags( self.llbuilder, ty, ptr, indices.as_ptr(), indices.len() as c_uint, UNNAMED, + GEPNoWrapFlags::InBounds, + ) + } + } + + fn inbounds_nuw_gep( + &mut self, + ty: &'ll Type, + ptr: &'ll Value, + indices: &[&'ll Value], + ) -> &'ll Value { + unsafe { + llvm::LLVMBuildGEPWithNoWrapFlags( + self.llbuilder, + ty, + ptr, + indices.as_ptr(), + indices.len() as c_uint, + UNNAMED, + GEPNoWrapFlags::InBounds | GEPNoWrapFlags::NUW, ) } } @@ -1410,7 +1388,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { + if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) { bundles.push(kcfi_bundle); } @@ -1453,26 +1431,12 @@ impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { } impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { - fn build(cx: &'a CodegenCx<'ll, 'tcx>, llbb: &'ll BasicBlock) -> Builder<'a, 'll, 'tcx> { - let bx = Builder::with_cx(cx); - unsafe { - llvm::LLVMPositionBuilderAtEnd(bx.llbuilder, llbb); - } - bx - } - - fn with_cx(cx: &'a CodegenCx<'ll, 'tcx>) -> Self { - // Create a fresh builder from the crate context. - let llbuilder = unsafe { llvm::LLVMCreateBuilderInContext(cx.llcx) }; - Builder { llbuilder, cx } - } - pub(crate) fn llfn(&self) -> &'ll Value { unsafe { llvm::LLVMGetBasicBlockParent(self.llbb()) } } } -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { fn position_at_start(&mut self, llbb: &'ll BasicBlock) { unsafe { llvm::LLVMRustPositionBuilderAtStart(self.llbuilder, llbb); @@ -1502,7 +1466,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { } } } -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { pub(crate) fn minnum(&mut self, lhs: &'ll Value, rhs: &'ll Value) -> &'ll Value { unsafe { llvm::LLVMRustBuildMinNum(self.llbuilder, lhs, rhs) } } @@ -1603,9 +1567,7 @@ impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { let ret = unsafe { llvm::LLVMBuildCatchRet(self.llbuilder, funclet.cleanuppad(), unwind) }; ret.expect("LLVM does not have support for catchret") } -} -impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { fn check_call<'b>( &mut self, typ: &str, @@ -1620,7 +1582,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let param_tys = self.cx.func_params_types(fn_ty); - let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.val_ty(v))) + let all_args_match = iter::zip(¶m_tys, args.iter().map(|&v| self.cx.val_ty(v))) .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty); if all_args_match { @@ -1630,7 +1592,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { let casted_args: Vec<_> = iter::zip(param_tys, args) .enumerate() .map(|(i, (expected_ty, &actual_val))| { - let actual_ty = self.val_ty(actual_val); + let actual_ty = self.cx.val_ty(actual_val); if expected_ty != actual_ty { debug!( "type mismatch in function call of {:?}. \ @@ -1646,12 +1608,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { Cow::Owned(casted_args) } -} -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { + pub(crate) fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } } + impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value { let (ty, f) = self.cx.get_intrinsic(intrinsic); @@ -1671,7 +1633,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { self.call_intrinsic(intrinsic, &[self.cx.const_u64(size), ptr]); } } -impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { +impl<'a, 'll, CX: Borrow>> GenericBuilder<'a, 'll, CX> { pub(crate) fn phi( &mut self, ty: &'ll Type, @@ -1759,7 +1721,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // Emit KCFI operand bundle let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, instance, llfn); - if let Some(kcfi_bundle) = kcfi_bundle.as_deref() { + if let Some(kcfi_bundle) = kcfi_bundle.as_ref().map(|b| b.raw()) { bundles.push(kcfi_bundle); } diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs index 2118380cad462..eab43c10ffdcd 100644 --- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs +++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs @@ -2,6 +2,7 @@ use std::ptr; use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, AutoDiffItem, DiffActivity, DiffMode}; use rustc_codegen_ssa::back::write::ModuleConfig; +use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_errors::FatalError; use tracing::{debug, trace}; diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index f17d98fa242b7..457e5452ce946 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,5 +1,7 @@ //! Code that is useful in various codegen modules. +use std::borrow::Borrow; + use libc::{c_char, c_uint}; use rustc_abi as abi; use rustc_abi::Primitive::Pointer; @@ -18,6 +20,7 @@ use tracing::debug; use crate::consts::const_alloc_to_llvm; pub(crate) use crate::context::CodegenCx; +use crate::context::{GenericCx, SCx}; use crate::llvm::{self, BasicBlock, Bool, ConstantInt, False, Metadata, True}; use crate::type_::Type; use crate::value::Value; @@ -77,11 +80,11 @@ impl<'ll> Funclet<'ll> { } pub(crate) fn bundle(&self) -> &llvm::OperandBundle<'ll> { - &self.operand + self.operand.raw() } } -impl<'ll> BackendTypes for CodegenCx<'ll, '_> { +impl<'ll, CX: Borrow>> BackendTypes for GenericCx<'ll, CX> { type Value = &'ll Value; type Metadata = &'ll Metadata; // FIXME(eddyb) replace this with a `Function` "subclass" of `Value`. @@ -118,7 +121,7 @@ impl<'ll> CodegenCx<'ll, '_> { } } -impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { fn const_null(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMConstNull(t) } } @@ -127,10 +130,6 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMGetUndef(t) } } - fn is_undef(&self, v: &'ll Value) -> bool { - unsafe { llvm::LLVMIsUndef(v) == True } - } - fn const_poison(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMGetPoison(t) } } @@ -209,28 +208,24 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn const_str(&self, s: &str) -> (&'ll Value, &'ll Value) { - let str_global = *self - .const_str_cache - .borrow_mut() - .raw_entry_mut() - .from_key(s) - .or_insert_with(|| { - let sc = self.const_bytes(s.as_bytes()); - let sym = self.generate_local_symbol_name("str"); - let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| { - bug!("symbol `{}` is already defined", sym); - }); - llvm::set_initializer(g, sc); - unsafe { - llvm::LLVMSetGlobalConstant(g, True); - llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); - } - llvm::set_linkage(g, llvm::Linkage::InternalLinkage); - // Cast to default address space if globals are in a different addrspace - let g = self.const_pointercast(g, self.type_ptr()); - (s.to_owned(), g) - }) - .1; + let mut const_str_cache = self.const_str_cache.borrow_mut(); + let str_global = const_str_cache.get(s).copied().unwrap_or_else(|| { + let sc = self.const_bytes(s.as_bytes()); + let sym = self.generate_local_symbol_name("str"); + let g = self.define_global(&sym, self.val_ty(sc)).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + llvm::set_initializer(g, sc); + unsafe { + llvm::LLVMSetGlobalConstant(g, True); + llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); + } + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + // Cast to default address space if globals are in a different addrspace + let g = self.const_pointercast(g, self.type_ptr()); + const_str_cache.insert(s.to_owned(), g); + g + }); let len = s.len(); (str_global, self.const_usize(len as u64)) } @@ -350,7 +345,7 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value { + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value { const_alloc_to_llvm(self, alloc, /*static*/ false) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 330e8a8f4069d..a4e5749b3acb9 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -16,7 +16,6 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::Instance; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::{bug, span_bug}; -use rustc_session::config::Lto; use tracing::{debug, instrument, trace}; use crate::common::{AsCCharPtr, CodegenCx}; @@ -344,11 +343,11 @@ impl<'ll> CodegenCx<'ll, '_> { // Local definitions can never be imported, so we must not apply // the DLLImport annotation. && !dso_local - // ThinLTO can't handle this workaround in all cases, so we don't - // emit the attrs. Instead we make them unnecessary by disallowing - // dynamic linking when linker plugin based LTO is enabled. - && !self.tcx.sess.opts.cg.linker_plugin_lto.enabled() - && self.tcx.sess.lto() != Lto::Thin; + // Linker plugin ThinLTO doesn't create the self-dllimport Rust uses for rlibs + // as the code generation happens out of process. Instead we assume static linkage + // and disallow dynamic linking when linker plugin based LTO is enabled. + // Regular in-process ThinLTO doesn't need this workaround. + && !self.tcx.sess.opts.cg.linker_plugin_lto.enabled(); // If this assertion triggers, there's something wrong with commandline // argument validation. @@ -490,7 +489,7 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::LLVMMDStringInContext2(self.llcx, bytes.as_c_char_ptr(), bytes.len()); let data = [section, alloc]; let meta = llvm::LLVMMDNodeInContext2(self.llcx, data.as_ptr(), data.len()); - let val = llvm::LLVMMetadataAsValue(self.llcx, meta); + let val = self.get_metadata_value(meta); llvm::LLVMAddNamedMetadataOperand( self.llmod, c"wasm.custom_sections".as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index e7952bc95e7f9..9f8ec0ea526af 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1,13 +1,13 @@ use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use std::ffi::{CStr, c_char, c_uint}; +use std::marker::PhantomData; use std::ops::Deref; use std::str; -use rustc_abi::{HasDataLayout, TargetDataLayout, VariantIdx}; +use rustc_abi::{HasDataLayout, Size, TargetDataLayout, VariantIdx}; use rustc_codegen_ssa::back::versioned_llvm_target; use rustc_codegen_ssa::base::{wants_msvc_seh, wants_wasm_eh}; -use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::errors as ssa_errors; use rustc_codegen_ssa::traits::*; use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, ToBaseN}; @@ -32,9 +32,9 @@ use smallvec::SmallVec; use crate::back::write::to_llvm_code_model; use crate::callee::get_fn; -use crate::common::{self, AsCCharPtr}; +use crate::common::AsCCharPtr; use crate::debuginfo::metadata::apply_vcall_visibility_metadata; -use crate::llvm::{Metadata, MetadataType}; +use crate::llvm::Metadata; use crate::type_::Type; use crate::value::Value; use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; @@ -43,18 +43,19 @@ use crate::{attributes, coverageinfo, debuginfo, llvm, llvm_util}; /// However, there are various cx related functions which we want to be available to the builder and /// other compiler pieces. Here we define a small subset which has enough information and can be /// moved around more freely. -pub(crate) struct SimpleCx<'ll> { +pub(crate) struct SCx<'ll> { pub llmod: &'ll llvm::Module, pub llcx: &'ll llvm::Context, + pub isize_ty: &'ll Type, } -impl<'ll> Borrow> for CodegenCx<'ll, '_> { - fn borrow(&self) -> &SimpleCx<'ll> { +impl<'ll> Borrow> for FullCx<'ll, '_> { + fn borrow(&self) -> &SCx<'ll> { &self.scx } } -impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> { +impl<'ll, 'tcx> Deref for FullCx<'ll, 'tcx> { type Target = SimpleCx<'ll>; #[inline] @@ -63,10 +64,25 @@ impl<'ll, 'tcx> Deref for CodegenCx<'ll, 'tcx> { } } +pub(crate) struct GenericCx<'ll, T: Borrow>>(T, PhantomData>); + +impl<'ll, T: Borrow>> Deref for GenericCx<'ll, T> { + type Target = T; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +pub(crate) type SimpleCx<'ll> = GenericCx<'ll, SCx<'ll>>; + /// There is one `CodegenCx` per codegen unit. Each one has its own LLVM /// `llvm::Context` so that several codegen units may be processed in parallel. /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. -pub(crate) struct CodegenCx<'ll, 'tcx> { +pub(crate) type CodegenCx<'ll, 'tcx> = GenericCx<'ll, FullCx<'ll, 'tcx>>; + +pub(crate) struct FullCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, pub scx: SimpleCx<'ll>, pub use_dll_storage_attrs: bool, @@ -104,8 +120,6 @@ pub(crate) struct CodegenCx<'ll, 'tcx> { /// Mapping of scalar types to llvm types. pub scalar_lltypes: RefCell, &'ll Type>>, - pub isize_ty: &'ll Type, - /// Extra per-CGU codegen state needed when coverage instrumentation is enabled. pub coverage_cx: Option>, pub dbg_cx: Option>, @@ -205,7 +219,7 @@ pub(crate) unsafe fn create_module<'ll>( { let tm = crate::back::write::create_informational_target_machine(tcx.sess, false); unsafe { - llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); + llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm.raw()); } let llvm_data_layout = unsafe { llvm::LLVMGetDataLayoutStr(llmod) }; @@ -579,33 +593,33 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { None }; - let isize_ty = Type::ix_llcx(llcx, tcx.data_layout.pointer_size.bits()); - - CodegenCx { - tcx, - scx: SimpleCx { llcx, llmod }, - use_dll_storage_attrs, - tls_model, - codegen_unit, - instances: Default::default(), - vtables: Default::default(), - const_str_cache: Default::default(), - const_globals: Default::default(), - statics_to_rauw: RefCell::new(Vec::new()), - used_statics: RefCell::new(Vec::new()), - compiler_used_statics: RefCell::new(Vec::new()), - type_lowering: Default::default(), - scalar_lltypes: Default::default(), - isize_ty, - coverage_cx, - dbg_cx, - eh_personality: Cell::new(None), - eh_catch_typeinfo: Cell::new(None), - rust_try_fn: Cell::new(None), - intrinsics: Default::default(), - local_gen_sym_counter: Cell::new(0), - renamed_statics: Default::default(), - } + GenericCx( + FullCx { + tcx, + scx: SimpleCx::new(llmod, llcx, tcx.data_layout.pointer_size), + use_dll_storage_attrs, + tls_model, + codegen_unit, + instances: Default::default(), + vtables: Default::default(), + const_str_cache: Default::default(), + const_globals: Default::default(), + statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), + compiler_used_statics: RefCell::new(Vec::new()), + type_lowering: Default::default(), + scalar_lltypes: Default::default(), + coverage_cx, + dbg_cx, + eh_personality: Cell::new(None), + eh_catch_typeinfo: Cell::new(None), + rust_try_fn: Cell::new(None), + intrinsics: Default::default(), + local_gen_sym_counter: Cell::new(0), + renamed_statics: Default::default(), + }, + PhantomData, + ) } pub(crate) fn statics_to_rauw(&self) -> &RefCell> { @@ -628,24 +642,32 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { llvm::set_section(g, c"llvm.metadata"); } } + impl<'ll> SimpleCx<'ll> { - pub(crate) fn val_ty(&self, v: &'ll Value) -> &'ll Type { - common::val_ty(v) + pub(crate) fn new( + llmod: &'ll llvm::Module, + llcx: &'ll llvm::Context, + pointer_size: Size, + ) -> Self { + let isize_ty = llvm::Type::ix_llcx(llcx, pointer_size.bits()); + Self(SCx { llmod, llcx, isize_ty }, PhantomData) } +} +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { pub(crate) fn get_metadata_value(&self, metadata: &'ll Metadata) -> &'ll Value { - unsafe { llvm::LLVMMetadataAsValue(self.llcx, metadata) } + llvm::LLVMMetadataAsValue(self.llcx(), metadata) } pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> { let name = SmallCStr::new(name); - unsafe { llvm::LLVMGetNamedFunction(self.llmod, name.as_ptr()) } + unsafe { llvm::LLVMGetNamedFunction((**self).borrow().llmod, name.as_ptr()) } } - pub(crate) fn get_md_kind_id(&self, name: &str) -> u32 { + pub(crate) fn get_md_kind_id(&self, name: &str) -> llvm::MetadataKindId { unsafe { llvm::LLVMGetMDKindIDInContext( - self.llcx, + self.llcx(), name.as_ptr() as *const c_char, name.len() as c_uint, ) @@ -654,13 +676,9 @@ impl<'ll> SimpleCx<'ll> { pub(crate) fn create_metadata(&self, name: String) -> Option<&'ll Metadata> { Some(unsafe { - llvm::LLVMMDStringInContext2(self.llcx, name.as_ptr() as *const c_char, name.len()) + llvm::LLVMMDStringInContext2(self.llcx(), name.as_ptr() as *const c_char, name.len()) }) } - - pub(crate) fn type_kind(&self, ty: &'ll Type) -> TypeKind { - unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } - } } impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { @@ -1203,27 +1221,18 @@ impl CodegenCx<'_, '_> { name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY)); name } - - /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. - pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) { - unsafe { - let node = llvm::LLVMMetadataAsValue(&self.llcx, md); - llvm::LLVMSetMetadata(val, kind_id as c_uint, node); - } - } } -// This is a duplication of the set_metadata function above. However, so far it's the only one -// shared between both contexts, so it doesn't seem worth it to make the Cx generic like we did it -// for the Builder. -impl SimpleCx<'_> { - #[allow(unused)] +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { /// A wrapper for [`llvm::LLVMSetMetadata`], but it takes `Metadata` as a parameter instead of `Value`. - pub(crate) fn set_metadata<'a>(&self, val: &'a Value, kind_id: MetadataType, md: &'a Metadata) { - unsafe { - let node = llvm::LLVMMetadataAsValue(&self.llcx, md); - llvm::LLVMSetMetadata(val, kind_id as c_uint, node); - } + pub(crate) fn set_metadata<'a>( + &self, + val: &'a Value, + kind_id: impl Into, + md: &'ll Metadata, + ) { + let node = self.get_metadata_value(md); + llvm::LLVMSetMetadata(val, kind_id.into(), node); } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs index c53ea6d466610..80e54bf045e24 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -8,7 +8,7 @@ use std::ffi::CString; use rustc_abi::Align; use rustc_codegen_ssa::traits::{ - BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, + BaseTypeCodegenMethods as _, ConstCodegenMethods, StaticCodegenMethods, }; use rustc_middle::mir::coverage::{ BasicCoverageBlock, CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index e79662ebc6472..2419ec1f88854 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -11,6 +11,8 @@ //! * Use define_* family of methods when you might be defining the Value. //! * When in doubt, define. +use std::borrow::Borrow; + use itertools::Itertools; use rustc_codegen_ssa::traits::TypeMembershipCodegenMethods; use rustc_data_structures::fx::FxIndexSet; @@ -22,7 +24,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::common::AsCCharPtr; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, GenericCx, SCx, SimpleCx}; use crate::llvm::AttributePlace::Function; use crate::llvm::Visibility; use crate::type_::Type; @@ -81,16 +83,25 @@ pub(crate) fn declare_raw_fn<'ll, 'tcx>( llfn } -impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { /// Declare a global value. /// /// If there’s a value with the same name already declared, the function will /// return its Value instead. pub(crate) fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); - unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_c_char_ptr(), name.len(), ty) } + unsafe { + llvm::LLVMRustGetOrInsertGlobal( + (**self).borrow().llmod, + name.as_c_char_ptr(), + name.len(), + ty, + ) + } } +} +impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { /// Declare a C ABI function. /// /// Only use this for foreign function ABIs and glue. For Rust functions use diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 4c5a78ca74fe4..55870e386035a 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -90,9 +90,9 @@ impl Diagnostic<'_, G> for ParseTargetMachineConfig<'_> { } } -#[derive(Diagnostic)] -#[diag(codegen_llvm_autodiff_without_lto)] -pub(crate) struct AutoDiffWithoutLTO; +// #[derive(Diagnostic)] +// #[diag(codegen_llvm_autodiff_without_lto)] +// pub(crate) struct AutoDiffWithoutLTO; #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_without_enable)] diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index f68365f6c69bc..660fc7ec4c404 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -127,15 +127,14 @@ fn get_simple_intrinsic<'ll>( sym::truncf64 => "llvm.trunc.f64", sym::truncf128 => "llvm.trunc.f128", - sym::rintf16 => "llvm.rint.f16", - sym::rintf32 => "llvm.rint.f32", - sym::rintf64 => "llvm.rint.f64", - sym::rintf128 => "llvm.rint.f128", - - sym::nearbyintf16 => "llvm.nearbyint.f16", - sym::nearbyintf32 => "llvm.nearbyint.f32", - sym::nearbyintf64 => "llvm.nearbyint.f64", - sym::nearbyintf128 => "llvm.nearbyint.f128", + // We could use any of `rint`, `nearbyint`, or `roundeven` + // for this -- they are all identical in semantics when + // assuming the default FP environment. + // `rint` is what we used for $forever. + sym::round_ties_even_f16 => "llvm.rint.f16", + sym::round_ties_even_f32 => "llvm.rint.f32", + sym::round_ties_even_f64 => "llvm.rint.f64", + sym::round_ties_even_f128 => "llvm.rint.f128", sym::roundf16 => "llvm.round.f16", sym::roundf32 => "llvm.round.f32", @@ -144,11 +143,6 @@ fn get_simple_intrinsic<'ll>( sym::ptr_mask => "llvm.ptrmask", - sym::roundevenf16 => "llvm.roundeven.f16", - sym::roundevenf32 => "llvm.roundeven.f32", - sym::roundevenf64 => "llvm.roundeven.f64", - sym::roundevenf128 => "llvm.roundeven.f128", - _ => return None, }; Some(cx.get_intrinsic(llvm_name)) @@ -476,7 +470,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let layout = self.layout_of(tp_ty).layout; let use_integer_compare = match layout.backend_repr() { Scalar(_) | ScalarPair(_, _) => true, - Vector { .. } => false, + SimdVector { .. } => false, Memory { .. } => { // For rusty ABIs, small aggregates are actually passed // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`), @@ -655,7 +649,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { fn type_test(&mut self, pointer: Self::Value, typeid: Self::Metadata) -> Self::Value { // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time // optimization pass replaces calls to this intrinsic with code to test type membership. - let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; + let typeid = self.get_metadata_value(typeid); self.call_intrinsic("llvm.type.test", &[pointer, typeid]) } @@ -665,7 +659,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { vtable_byte_offset: u64, typeid: &'ll Metadata, ) -> Self::Value { - let typeid = unsafe { llvm::LLVMMetadataAsValue(&self.llcx, typeid) }; + let typeid = self.get_metadata_value(typeid); let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32); let type_checked_load = self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]); @@ -1335,7 +1329,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( )); } - if name == sym::simd_shuffle_generic { + if name == sym::simd_shuffle_const_generic { let idx = fn_args[2].expect_const().to_value().valtree.unwrap_branch(); let n = idx.len() as u64; @@ -1587,8 +1581,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>( sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)), sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), sym::simd_relaxed_fma => ("fmuladd", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)), - sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)), - sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)), sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)), sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)), sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)), @@ -1621,8 +1613,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>( | sym::simd_flog | sym::simd_floor | sym::simd_fma - | sym::simd_fpow - | sym::simd_fpowi | sym::simd_fsin | sym::simd_fsqrt | sym::simd_relaxed_fma diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index ac74e429b10fe..5eda88ed04f16 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -12,7 +12,6 @@ #![feature(exact_size_is_empty)] #![feature(extern_types)] #![feature(file_buffered)] -#![feature(hash_raw_entry)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(iter_intersperse)] @@ -20,7 +19,6 @@ #![feature(rustdoc_internals)] #![feature(slice_as_array)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::any::Any; @@ -29,7 +27,7 @@ use std::mem::ManuallyDrop; use back::owned_target_machine::OwnedTargetMachine; use back::write::{create_informational_target_machine, create_target_machine}; -use errors::{AutoDiffWithoutLTO, ParseTargetMachineConfig}; +use errors::ParseTargetMachineConfig; pub(crate) use llvm_util::target_features_cfg; use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; @@ -46,7 +44,7 @@ use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_middle::util::Providers; use rustc_session::Session; -use rustc_session::config::{Lto, OptLevel, OutputFilenames, PrintKind, PrintRequest}; +use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; use rustc_span::Symbol; mod back { @@ -116,9 +114,11 @@ impl ExtraBackendMethods for LlvmCodegenBackend { kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) -> ModuleLlvm { - let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name); + let module_llvm = ModuleLlvm::new_metadata(tcx, module_name); + let cx = + SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size); unsafe { - allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind); + allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind); } module_llvm } @@ -194,7 +194,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { unsafe fn optimize( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, - module: &ModuleCodegen, + module: &mut ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError> { unsafe { back::write::optimize(cgcx, dcx, module, config) } @@ -360,8 +360,8 @@ impl CodegenBackend for LlvmCodegenBackend { llvm_util::print_version(); } - fn target_features_cfg(&self, sess: &Session, allow_unstable: bool) -> Vec { - target_features_cfg(sess, allow_unstable) + fn target_features_cfg(&self, sess: &Session) -> (Vec, Vec) { + target_features_cfg(sess) } fn codegen_crate<'tcx>( diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index daa6696e9634e..f6b238629075c 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -3,13 +3,14 @@ use libc::{c_char, c_uint}; +use super::MetadataKindId; use super::ffi::{BasicBlock, Metadata, Module, Type, Value}; use crate::llvm::Bool; #[link(name = "llvm-wrapper", kind = "static")] -extern "C" { +unsafe extern "C" { // Enzyme - pub(crate) fn LLVMRustHasMetadata(I: &Value, KindID: c_uint) -> bool; + pub(crate) safe fn LLVMRustHasMetadata(I: &Value, KindID: MetadataKindId) -> bool; pub(crate) fn LLVMRustEraseInstUntilInclusive(BB: &BasicBlock, I: &Value); pub(crate) fn LLVMRustGetLastInstruction<'a>(BB: &BasicBlock) -> Option<&'a Value>; pub(crate) fn LLVMRustDIGetInstMetadata(I: &Value) -> Option<&Metadata>; @@ -18,7 +19,7 @@ extern "C" { pub(crate) fn LLVMRustVerifyFunction(V: &Value, action: LLVMRustVerifierFailureAction) -> Bool; } -extern "C" { +unsafe extern "C" { // Enzyme pub(crate) fn LLVMDumpModule(M: &Module); pub(crate) fn LLVMDumpValue(V: &Value); @@ -42,10 +43,10 @@ pub use self::Enzyme_AD::*; #[cfg(llvm_enzyme)] pub mod Enzyme_AD { use libc::c_void; - extern "C" { + unsafe extern "C" { pub fn EnzymeSetCLBool(arg1: *mut ::std::os::raw::c_void, arg2: u8); } - extern "C" { + unsafe extern "C" { static mut EnzymePrintPerf: c_void; static mut EnzymePrintActivity: c_void; static mut EnzymePrintType: c_void; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 3b0187b9d37b1..39087a4d6f41d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -954,6 +954,17 @@ bitflags! { } } +// These values **must** match with LLVMGEPNoWrapFlags +bitflags! { + #[repr(transparent)] + #[derive(Default)] + pub struct GEPNoWrapFlags : c_uint { + const InBounds = 1 << 0; + const NUSW = 1 << 1; + const NUW = 1 << 2; + } +} + unsafe extern "C" { pub type ModuleBuffer; } @@ -965,6 +976,16 @@ pub type SelfProfileAfterPassCallback = unsafe extern "C" fn(*mut c_void); pub type GetSymbolsCallback = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void; pub type GetSymbolsErrorCallback = unsafe extern "C" fn(*const c_char) -> *mut c_void; +#[derive(Copy, Clone)] +#[repr(transparent)] +pub struct MetadataKindId(c_uint); + +impl From for MetadataKindId { + fn from(value: MetadataType) -> Self { + Self(value as c_uint) + } +} + unsafe extern "C" { // Create and destroy contexts. pub(crate) fn LLVMContextDispose(C: &'static mut Context); @@ -972,7 +993,7 @@ unsafe extern "C" { C: &Context, Name: *const c_char, SLen: c_uint, - ) -> c_uint; + ) -> MetadataKindId; // Create modules. pub(crate) fn LLVMModuleCreateWithNameInContext( @@ -1035,14 +1056,13 @@ unsafe extern "C" { pub(crate) fn LLVMMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values - pub(crate) fn LLVMIsUndef(Val: &Value) -> Bool; pub(crate) fn LLVMTypeOf(Val: &Value) -> &Type; pub(crate) fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char; pub(crate) fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); pub(crate) fn LLVMReplaceAllUsesWith<'a>(OldVal: &'a Value, NewVal: &'a Value); - pub(crate) fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value); + pub(crate) safe fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: MetadataKindId, Node: &'a Value); pub(crate) fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); - pub(crate) fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; + pub(crate) safe fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; // Operations on constants of any type pub(crate) fn LLVMConstNull(Ty: &Type) -> &Value; @@ -1136,7 +1156,7 @@ unsafe extern "C" { pub(crate) fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub(crate) fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; pub(crate) fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); - pub(crate) fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); + pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( @@ -1193,7 +1213,7 @@ unsafe extern "C" { pub(crate) fn LLVMGetCurrentDebugLocation2<'a>(Builder: &Builder<'a>) -> Option<&'a Metadata>; // Terminators - pub(crate) fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; + pub(crate) safe fn LLVMBuildRetVoid<'a>(B: &Builder<'a>) -> &'a Value; pub(crate) fn LLVMBuildRet<'a>(B: &Builder<'a>, V: &'a Value) -> &'a Value; pub(crate) fn LLVMBuildBr<'a>(B: &Builder<'a>, Dest: &'a BasicBlock) -> &'a Value; pub(crate) fn LLVMBuildCondBr<'a>( @@ -1454,21 +1474,14 @@ unsafe extern "C" { pub(crate) fn LLVMBuildStore<'a>(B: &Builder<'a>, Val: &'a Value, Ptr: &'a Value) -> &'a Value; - pub(crate) fn LLVMBuildGEP2<'a>( - B: &Builder<'a>, - Ty: &'a Type, - Pointer: &'a Value, - Indices: *const &'a Value, - NumIndices: c_uint, - Name: *const c_char, - ) -> &'a Value; - pub(crate) fn LLVMBuildInBoundsGEP2<'a>( + pub(crate) fn LLVMBuildGEPWithNoWrapFlags<'a>( B: &Builder<'a>, Ty: &'a Type, Pointer: &'a Value, Indices: *const &'a Value, NumIndices: c_uint, Name: *const c_char, + Flags: GEPNoWrapFlags, ) -> &'a Value; // Casts @@ -1676,7 +1689,7 @@ unsafe extern "C" { Packed: Bool, ); - pub(crate) fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; + pub(crate) safe fn LLVMMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value; pub(crate) fn LLVMSetUnnamedAddress(Global: &Value, UnnamedAddr: UnnamedAddr); @@ -2421,7 +2434,9 @@ unsafe extern "C" { NoPrepopulatePasses: bool, VerifyIR: bool, LintIR: bool, - UseThinLTOBuffers: bool, + ThinLTOBuffer: Option<&mut *mut ThinLTOBuffer>, + EmitThinLTO: bool, + EmitThinLTOSummary: bool, MergeFunctions: bool, UnrollLoops: bool, SLPVectorize: bool, diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 5ec934241314c..a36226b25a249 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -1,7 +1,6 @@ #![allow(non_snake_case)] use std::ffi::{CStr, CString}; -use std::ops::Deref; use std::ptr; use std::str::FromStr; use std::string::FromUtf8Error; @@ -355,6 +354,16 @@ impl<'a> OperandBundleOwned<'a> { }; OperandBundleOwned { raw: ptr::NonNull::new(raw).unwrap() } } + + /// Returns inner `OperandBundle` type. + /// + /// This could be a `Deref` implementation, but `OperandBundle` contains an extern type and + /// `Deref::Target: ?Sized`. + pub(crate) fn raw(&self) -> &OperandBundle<'a> { + // SAFETY: The returned reference is opaque and can only used for FFI. + // It is valid for as long as `&self` is. + unsafe { self.raw.as_ref() } + } } impl Drop for OperandBundleOwned<'_> { @@ -365,16 +374,6 @@ impl Drop for OperandBundleOwned<'_> { } } -impl<'a> Deref for OperandBundleOwned<'a> { - type Target = OperandBundle<'a>; - - fn deref(&self) -> &Self::Target { - // SAFETY: The returned reference is opaque and can only used for FFI. - // It is valid for as long as `&self` is. - unsafe { self.raw.as_ref() } - } -} - pub(crate) fn add_module_flag_u32( module: &Module, merge_behavior: ModuleFlagMergeBehavior, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index b4b5d6a5b1943..4a166b0872dfd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -281,6 +281,8 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, ("riscv32" | "riscv64", "zabha") if get_version().0 < 19 => None, ("riscv32" | "riscv64", "zalrsc") if get_version().0 < 19 => None, + ("riscv32" | "riscv64", "zama16b") if get_version().0 < 19 => None, + ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => { Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))) @@ -304,44 +306,44 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Vec { - let mut features: FxHashSet = Default::default(); - +pub(crate) fn target_features_cfg(sess: &Session) -> (Vec, Vec) { // Add base features for the target. // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below. // The reason is that if LLVM considers a feature implied but we do not, we don't want that to // show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of - // the target CPU, that is still expanded to target features (with all their implied features) by - // LLVM. + // the target CPU, that is still expanded to target features (with all their implied features) + // by LLVM. let target_machine = create_informational_target_machine(sess, true); - // Compute which of the known target features are enabled in the 'base' target machine. - // We only consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. - features.extend( - sess.target - .rust_target_features() - .iter() - .filter(|(feature, _, _)| { - // skip checking special features, as LLVM may not understand them - if RUSTC_SPECIAL_FEATURES.contains(feature) { - return true; - } - // check that all features in a given smallvec are enabled - if let Some(feat) = to_llvm_features(sess, feature) { - for llvm_feature in feat { - let cstr = SmallCStr::new(llvm_feature); - if !unsafe { llvm::LLVMRustHasFeature(&target_machine, cstr.as_ptr()) } { - return false; - } + // Compute which of the known target features are enabled in the 'base' target machine. We only + // consider "supported" features; "forbidden" features are not reflected in `cfg` as of now. + let mut features: FxHashSet = sess + .target + .rust_target_features() + .iter() + .filter(|(feature, _, _)| { + // skip checking special features, as LLVM may not understand them + if RUSTC_SPECIAL_FEATURES.contains(feature) { + return true; + } + if let Some(feat) = to_llvm_features(sess, feature) { + for llvm_feature in feat { + let cstr = SmallCStr::new(llvm_feature); + // `LLVMRustHasFeature` is moderately expensive. On targets with many + // features (e.g. x86) these calls take a non-trivial fraction of runtime + // when compiling very small programs. + if !unsafe { llvm::LLVMRustHasFeature(target_machine.raw(), cstr.as_ptr()) } { + return false; } - true - } else { - false } - }) - .map(|(feature, _, _)| Symbol::intern(feature)), - ); + true + } else { + false + } + }) + .map(|(feature, _, _)| Symbol::intern(feature)) + .collect(); - // Add enabled features + // Add enabled and remove disabled features. for (enabled, feature) in sess.opts.cg.target_feature.split(',').filter_map(|s| match s.chars().next() { Some('+') => Some((true, Symbol::intern(&s[1..]))), @@ -357,7 +359,7 @@ pub(crate) fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec Vec Vec print_target_cpus(sess, &tm, out), - PrintKind::TargetFeatures => print_target_features(sess, &tm, out), + PrintKind::TargetCPUs => print_target_cpus(sess, tm.raw(), out), + PrintKind::TargetFeatures => print_target_features(sess, tm.raw(), out), _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), } } @@ -679,7 +683,7 @@ pub(crate) fn global_llvm_features( for feature in sess.opts.cg.target_feature.split(',') { if let Some(feature) = feature.strip_prefix('+') { all_rust_features.extend( - UnordSet::from(sess.target.implied_target_features(std::iter::once(feature))) + UnordSet::from(sess.target.implied_target_features(feature)) .to_sorted_stable_ord() .iter() .map(|&&s| (true, s)), diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index d61ce41756270..b89ce90d1a1dc 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -1,3 +1,4 @@ +use std::borrow::Borrow; use std::{fmt, ptr}; use libc::{c_char, c_uint}; @@ -11,7 +12,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{CastTarget, FnAbi}; use crate::abi::{FnAbiLlvmExt, LlvmType}; -use crate::context::{CodegenCx, SimpleCx}; +use crate::context::{CodegenCx, GenericCx, SCx}; pub(crate) use crate::llvm::Type; use crate::llvm::{Bool, False, Metadata, True}; use crate::type_of::LayoutLlvmExt; @@ -36,29 +37,29 @@ impl fmt::Debug for Type { } impl<'ll> CodegenCx<'ll, '_> {} -impl<'ll> SimpleCx<'ll> { +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { pub(crate) fn type_named_struct(&self, name: &str) -> &'ll Type { let name = SmallCStr::new(name); - unsafe { llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr()) } + unsafe { llvm::LLVMStructCreateNamed(self.llcx(), name.as_ptr()) } } pub(crate) fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) { unsafe { llvm::LLVMStructSetBody(ty, els.as_ptr(), els.len() as c_uint, packed as Bool) } } pub(crate) fn type_void(&self) -> &'ll Type { - unsafe { llvm::LLVMVoidTypeInContext(self.llcx) } + unsafe { llvm::LLVMVoidTypeInContext(self.llcx()) } } pub(crate) fn type_token(&self) -> &'ll Type { - unsafe { llvm::LLVMTokenTypeInContext(self.llcx) } + unsafe { llvm::LLVMTokenTypeInContext(self.llcx()) } } pub(crate) fn type_metadata(&self) -> &'ll Type { - unsafe { llvm::LLVMMetadataTypeInContext(self.llcx) } + unsafe { llvm::LLVMMetadataTypeInContext(self.llcx()) } } ///x Creates an integer type with the given number of bits, e.g., i24 pub(crate) fn type_ix(&self, num_bits: u64) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) } + unsafe { llvm::LLVMIntTypeInContext(self.llcx(), num_bits as c_uint) } } pub(crate) fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { @@ -121,19 +122,28 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { self.type_array(self.type_from_integer(unit), size / unit_size) } } -impl<'ll> SimpleCx<'ll> { + +impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { + pub(crate) fn llcx(&self) -> &'ll llvm::Context { + (**self).borrow().llcx + } + + pub(crate) fn isize_ty(&self) -> &'ll Type { + (**self).borrow().isize_ty + } + pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } } pub(crate) fn type_i1(&self) -> &'ll Type { - unsafe { llvm::LLVMInt1TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt1TypeInContext(self.llcx()) } } pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { unsafe { llvm::LLVMStructTypeInContext( - self.llcx, + self.llcx(), els.as_ptr(), els.len() as c_uint, packed as Bool, @@ -142,45 +152,45 @@ impl<'ll> SimpleCx<'ll> { } } -impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { +impl<'ll, CX: Borrow>> BaseTypeCodegenMethods for GenericCx<'ll, CX> { fn type_i8(&self) -> &'ll Type { - unsafe { llvm::LLVMInt8TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt8TypeInContext(self.llcx()) } } fn type_i16(&self) -> &'ll Type { - unsafe { llvm::LLVMInt16TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt16TypeInContext(self.llcx()) } } fn type_i32(&self) -> &'ll Type { - unsafe { llvm::LLVMInt32TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt32TypeInContext(self.llcx()) } } fn type_i64(&self) -> &'ll Type { - unsafe { llvm::LLVMInt64TypeInContext(self.llcx) } + unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) } } fn type_i128(&self) -> &'ll Type { - unsafe { llvm::LLVMIntTypeInContext(self.llcx, 128) } + unsafe { llvm::LLVMIntTypeInContext(self.llcx(), 128) } } fn type_isize(&self) -> &'ll Type { - self.isize_ty + self.isize_ty() } fn type_f16(&self) -> &'ll Type { - unsafe { llvm::LLVMHalfTypeInContext(self.llcx) } + unsafe { llvm::LLVMHalfTypeInContext(self.llcx()) } } fn type_f32(&self) -> &'ll Type { - unsafe { llvm::LLVMFloatTypeInContext(self.llcx) } + unsafe { llvm::LLVMFloatTypeInContext(self.llcx()) } } fn type_f64(&self) -> &'ll Type { - unsafe { llvm::LLVMDoubleTypeInContext(self.llcx) } + unsafe { llvm::LLVMDoubleTypeInContext(self.llcx()) } } fn type_f128(&self) -> &'ll Type { - unsafe { llvm::LLVMFP128TypeInContext(self.llcx) } + unsafe { llvm::LLVMFP128TypeInContext(self.llcx()) } } fn type_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { @@ -196,7 +206,7 @@ impl<'ll, 'tcx> BaseTypeCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn type_ptr_ext(&self, address_space: AddressSpace) -> &'ll Type { - unsafe { llvm::LLVMPointerTypeInContext(self.llcx, address_space.0) } + unsafe { llvm::LLVMPointerTypeInContext(self.llcx(), address_space.0) } } fn element_type(&self, ty: &'ll Type) -> &'ll Type { diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index ba01fbff38539..4e7096da502d0 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -19,7 +19,7 @@ fn uncached_llvm_type<'a, 'tcx>( ) -> &'a Type { match layout.backend_repr { BackendRepr::Scalar(_) => bug!("handled elsewhere"), - BackendRepr::Vector { element, count } => { + BackendRepr::SimdVector { element, count } => { let element = layout.scalar_llvm_type_at(cx, element); return cx.type_vector(element, count); } @@ -171,7 +171,7 @@ pub(crate) trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => true, + BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => true, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => false, } } @@ -179,9 +179,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { fn is_llvm_scalar_pair(&self) -> bool { match self.backend_repr { BackendRepr::ScalarPair(..) => true, - BackendRepr::Scalar(_) | BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => { - false - } + BackendRepr::Scalar(_) + | BackendRepr::SimdVector { .. } + | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 963d9258be67d..caa1db8274d97 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_codegen_ssa" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -11,7 +11,7 @@ bitflags = "2.4.1" bstr = "1.11.3" # Pinned so `cargo update` bumps don't cause breakage. Please also update the # `cc` in `rustc_llvm` if you update the `cc` here. -cc = "=1.2.13" +cc = "=1.2.16" either = "1.5.0" itertools = "0.12" pathdiff = "0.2.0" @@ -40,7 +40,6 @@ rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_type_ir = { path = "../rustc_type_ir" } serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tempfile = "3.2" diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 22e262546c3a7..95912b0160072 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -18,6 +18,8 @@ codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing codegen_ssa_autodiff_without_lto = using the autodiff feature requires using fat-lto +codegen_ssa_bare_instruction_set = `#[instruction_set]` requires an argument + codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty codegen_ssa_cgu_not_recorded = @@ -52,6 +54,10 @@ codegen_ssa_error_creating_remark_dir = failed to create remark directory: {$err codegen_ssa_error_writing_def_file = Error writing .DEF file: {$error} +codegen_ssa_expected_name_value_pair = expected name value pair + +codegen_ssa_expected_one_argument = expected one argument + codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)` codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified @@ -88,9 +94,17 @@ codegen_ssa_incorrect_cgu_reuse_type = codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. +codegen_ssa_invalid_argument = invalid argument + .help = valid inline arguments are `always` and `never` + +codegen_ssa_invalid_instruction_set = invalid instruction set specified + codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]` .note = the attribute requires exactly one argument +codegen_ssa_invalid_literal_value = invalid literal value + .label = value must be an integer between `0` and `255` + codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}` codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}` @@ -119,7 +133,8 @@ codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]` -codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_` +codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: found mask element type is `{$ty}`, expected a signed integer type + .note = the mask may be widened, which only has the correct behavior for signed integers codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}` @@ -216,6 +231,8 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions +codegen_ssa_multiple_instruction_set = cannot specify more than one instruction set + codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point @@ -228,6 +245,11 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't +codegen_ssa_null_on_export = `export_name` may not contain null characters + +codegen_ssa_out_of_range_integer = integer value out of range + .label = value must be between `0` and `255` + codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} .note = {$output} @@ -235,6 +257,8 @@ codegen_ssa_read_file = failed to read file: {$message} codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer +codegen_ssa_requires_rust_abi = `#[track_caller]` requires Rust ABI + codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib at `{$path}`: {$error} codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`) @@ -355,6 +379,9 @@ codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error} codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error} +codegen_ssa_unexpected_parameter_name = unexpected parameter name + .label = expected `{$prefix_nops}` or `{$entry_nops}` + codegen_ssa_unknown_archive_kind = Don't know how to build archive of type: {$kind} @@ -366,6 +393,8 @@ codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` +codegen_ssa_unsupported_instruction_set = target does not support `#[instruction_set]` + codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#rustc-link-lib) diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 27331ce4ca66f..3710625ac12d7 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -63,7 +63,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTr }, }; - for attr in tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) { + for attr in tcx.hir_attrs(rustc_hir::CRATE_HIR_ID) { ams.check_attr(attr); } @@ -94,7 +94,7 @@ impl<'tcx> AssertModuleSource<'tcx> { other => { self.tcx .dcx() - .emit_fatal(errors::UnknownReuseKind { span: attr.span, kind: other }); + .emit_fatal(errors::UnknownReuseKind { span: attr.span(), kind: other }); } } } else { @@ -102,7 +102,7 @@ impl<'tcx> AssertModuleSource<'tcx> { }; if !self.tcx.sess.opts.unstable_opts.query_dep_graph { - self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span }); + self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span() }); } if !self.check_config(attr) { @@ -115,7 +115,7 @@ impl<'tcx> AssertModuleSource<'tcx> { if !user_path.starts_with(&crate_name) { self.tcx.dcx().emit_fatal(errors::MalformedCguName { - span: attr.span, + span: attr.span(), user_path, crate_name, }); @@ -145,7 +145,7 @@ impl<'tcx> AssertModuleSource<'tcx> { let cgu_names: Vec<&str> = self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord(); self.tcx.dcx().emit_err(errors::NoModuleNamed { - span: attr.span, + span: attr.span(), user_path, cgu_name, cgu_names: cgu_names.join(", "), @@ -155,7 +155,7 @@ impl<'tcx> AssertModuleSource<'tcx> { self.cgu_reuse_tracker.set_expectation( cgu_name, user_path, - attr.span, + attr.span(), expected_reuse, comp_kind, ); @@ -175,7 +175,7 @@ impl<'tcx> AssertModuleSource<'tcx> { } } - self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span, name }); + self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span(), name }); } /// Scan for a `cfg="foo"` attribute and check whether we have a @@ -211,7 +211,7 @@ impl fmt::Display for CguReuse { } impl IntoDiagArg for CguReuse { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.to_string())) } } diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs index d9c5c3e5af96d..bfa7635a869f8 100644 --- a/compiler/rustc_codegen_ssa/src/back/apple.rs +++ b/compiler/rustc_codegen_ssa/src/back/apple.rs @@ -2,6 +2,7 @@ use std::env; use std::fmt::{Display, from_fn}; use std::num::ParseIntError; +use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::Session; use rustc_target::spec::Target; @@ -26,6 +27,89 @@ pub(super) fn macho_platform(target: &Target) -> u32 { } } +/// Add relocation and section data needed for a symbol to be considered +/// undefined by ld64. +/// +/// The relocation must be valid, and hence must point to a valid piece of +/// machine code, and hence this is unfortunately very architecture-specific. +/// +/// +/// # New architectures +/// +/// The values here are basically the same as emitted by the following program: +/// +/// ```c +/// // clang -c foo.c -target $CLANG_TARGET +/// void foo(void); +/// +/// extern int bar; +/// +/// void* foobar[2] = { +/// (void*)foo, +/// (void*)&bar, +/// // ... +/// }; +/// ``` +/// +/// Can be inspected with: +/// ```console +/// objdump --macho --reloc foo.o +/// objdump --macho --full-contents foo.o +/// ``` +pub(super) fn add_data_and_relocation( + file: &mut object::write::Object<'_>, + section: object::write::SectionId, + symbol: object::write::SymbolId, + target: &Target, + kind: SymbolExportKind, +) -> object::write::Result<()> { + let authenticated_pointer = + kind == SymbolExportKind::Text && target.llvm_target.starts_with("arm64e"); + + let data: &[u8] = match target.pointer_width { + _ if authenticated_pointer => &[0, 0, 0, 0, 0, 0, 0, 0x80], + 32 => &[0; 4], + 64 => &[0; 8], + pointer_width => unimplemented!("unsupported Apple pointer width {pointer_width:?}"), + }; + + if target.arch == "x86_64" { + // Force alignment for the entire section to be 16 on x86_64. + file.section_mut(section).append_data(&[], 16); + } else { + // Elsewhere, the section alignment is the same as the pointer width. + file.section_mut(section).append_data(&[], target.pointer_width as u64); + } + + let offset = file.section_mut(section).append_data(data, data.len() as u64); + + let flags = if authenticated_pointer { + object::write::RelocationFlags::MachO { + r_type: object::macho::ARM64_RELOC_AUTHENTICATED_POINTER, + r_pcrel: false, + r_length: 3, + } + } else if target.arch == "arm" { + // FIXME(madsmtm): Remove once `object` supports 32-bit ARM relocations: + // https://github.com/gimli-rs/object/pull/757 + object::write::RelocationFlags::MachO { + r_type: object::macho::ARM_RELOC_VANILLA, + r_pcrel: false, + r_length: 2, + } + } else { + object::write::RelocationFlags::Generic { + kind: object::RelocationKind::Absolute, + encoding: object::RelocationEncoding::Generic, + size: target.pointer_width as u8, + } + }; + + file.add_relocation(section, object::write::Relocation { offset, addend: 0, symbol, flags })?; + + Ok(()) +} + /// Deployment target or SDK version. /// /// The size of the numbers in here are limited by Mach-O's `LC_BUILD_VERSION`. diff --git a/compiler/rustc_codegen_ssa/src/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs index 63023fdba20fc..05351bd6ca379 100644 --- a/compiler/rustc_codegen_ssa/src/back/command.rs +++ b/compiler/rustc_codegen_ssa/src/back/command.rs @@ -137,17 +137,40 @@ impl Command { /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits, /// or `false` if we should attempt to spawn and see what the OS says. pub(crate) fn very_likely_to_exceed_some_spawn_limit(&self) -> bool { - // We mostly only care about Windows in this method, on Unix the limits - // can be gargantuan anyway so we're pretty unlikely to hit them - if cfg!(unix) { + #[cfg(not(any(windows, unix)))] + { return false; } - // Right now LLD doesn't support the `@` syntax of passing an argument - // through files, so regardless of the platform we try to go to the OS - // on this one. - if let Program::Lld(..) = self.program { - return false; + // On Unix the limits can be gargantuan anyway so we're pretty + // unlikely to hit them, but might still exceed it. + // We consult ARG_MAX here to get an estimate. + #[cfg(unix)] + { + let ptr_size = mem::size_of::(); + // arg + \0 + pointer + let args_size = self.args.iter().fold(0usize, |acc, a| { + let arg = a.as_encoded_bytes().len(); + let nul = 1; + acc.saturating_add(arg).saturating_add(nul).saturating_add(ptr_size) + }); + // key + `=` + value + \0 + pointer + let envs_size = self.env.iter().fold(0usize, |acc, (k, v)| { + let k = k.as_encoded_bytes().len(); + let eq = 1; + let v = v.as_encoded_bytes().len(); + let nul = 1; + acc.saturating_add(k) + .saturating_add(eq) + .saturating_add(v) + .saturating_add(nul) + .saturating_add(ptr_size) + }); + let arg_max = match unsafe { libc::sysconf(libc::_SC_ARG_MAX) } { + -1 => return false, // Go to OS anyway. + max => max as usize, + }; + return args_size.saturating_add(envs_size) > arg_max; } // Ok so on Windows to spawn a process is 32,768 characters in its @@ -172,9 +195,14 @@ impl Command { // // [1]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessa // [2]: https://devblogs.microsoft.com/oldnewthing/?p=41553 - - let estimated_command_line_len = self.args.iter().map(|a| a.len()).sum::(); - estimated_command_line_len > 1024 * 6 + #[cfg(windows)] + { + let estimated_command_line_len = self + .args + .iter() + .fold(0usize, |acc, a| acc.saturating_add(a.as_encoded_bytes().len())); + return estimated_command_line_len > 1024 * 6; + } } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index a8d917f0fdb58..ea961f222db04 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1,3 +1,5 @@ +mod raw_dylib; + use std::collections::BTreeSet; use std::ffi::OsString; use std::fs::{File, OpenOptions, read}; @@ -12,7 +14,7 @@ use itertools::Itertools; use regex::Regex; use rustc_arena::TypedArena; use rustc_ast::CRATE_NODE_ID; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_errors::{DiagCtxtHandle, LintDiagnostic}; @@ -20,7 +22,9 @@ use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_macros::LintDiagnostic; use rustc_metadata::fs::{METADATA_FILENAME, copy_to_stdout, emit_wrapper_file}; -use rustc_metadata::{find_native_static_library, walk_native_lib_search_dirs}; +use rustc_metadata::{ + NativeLibSearchFallback, find_native_static_library, walk_native_lib_search_dirs, +}; use rustc_middle::bug; use rustc_middle::lint::lint_level; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -30,7 +34,6 @@ use rustc_session::config::{ self, CFGuard, CrateType, DebugInfo, LinkerFeaturesCli, OutFileName, OutputFilenames, OutputType, PrintKind, SplitDwarfKind, Strip, }; -use rustc_session::cstore::DllImport; use rustc_session::lint::builtin::LINKER_MESSAGES; use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename}; use rustc_session::search_paths::PathKind; @@ -41,22 +44,21 @@ use rustc_session::{Session, filesearch}; use rustc_span::Symbol; use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ - Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures, - LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, - SplitDebuginfo, + BinaryFormat, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, + LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, + SanitizerSet, SplitDebuginfo, }; use tempfile::Builder as TempFileBuilder; use tracing::{debug, info, warn}; -use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder, ImportLibraryItem}; +use super::archive::{ArchiveBuilder, ArchiveBuilderBuilder}; use super::command::Command; use super::linker::{self, Linker}; use super::metadata::{MetadataPosition, create_wrapper_file}; use super::rpath::{self, RPathConfig}; use super::{apple, versioned_llvm_target}; use crate::{ - CodegenResults, CompiledModule, CrateInfo, NativeLib, common, errors, - looks_like_rust_object_file, + CodegenResults, CompiledModule, CrateInfo, NativeLib, errors, looks_like_rust_object_file, }; pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { @@ -244,22 +246,17 @@ pub fn each_linked_rlib( fmts } else { - for combination in info.dependency_formats.iter().combinations(2) { - let (ty1, list1) = &combination[0]; - let (ty2, list2) = &combination[1]; - if list1 != list2 { - return Err(errors::LinkRlibError::IncompatibleDependencyFormats { - ty1: format!("{ty1:?}"), - ty2: format!("{ty2:?}"), - list1: format!("{list1:?}"), - list2: format!("{list2:?}"), - }); - } - } - if info.dependency_formats.is_empty() { - return Err(errors::LinkRlibError::MissingFormat); + let mut dep_formats = info.dependency_formats.iter(); + let (ty1, list1) = dep_formats.next().ok_or(errors::LinkRlibError::MissingFormat)?; + if let Some((ty2, list2)) = dep_formats.find(|(_, list2)| list1 != *list2) { + return Err(errors::LinkRlibError::IncompatibleDependencyFormats { + ty1: format!("{ty1:?}"), + ty2: format!("{ty2:?}"), + list1: format!("{list1:?}"), + list2: format!("{list2:?}"), + }); } - info.dependency_formats.first().unwrap().1 + list1 }; let used_dep_crates = info.used_crates.iter(); @@ -381,16 +378,22 @@ fn link_rlib<'a>( } } - for output_path in create_dll_import_libs( - sess, - archive_builder_builder, - codegen_results.crate_info.used_libraries.iter(), - tmpdir.as_ref(), - true, - ) { - ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| { - sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error }); - }); + // On Windows, we add the raw-dylib import libraries to the rlibs already. + // But on ELF, this is not possible, as a shared object cannot be a member of a static library. + // Instead, we add all raw-dylibs to the final link on ELF. + if sess.target.is_like_windows { + for output_path in raw_dylib::create_raw_dylib_dll_import_libs( + sess, + archive_builder_builder, + codegen_results.crate_info.used_libraries.iter(), + tmpdir.as_ref(), + true, + ) { + ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| { + sess.dcx() + .emit_fatal(errors::AddNativeLibrary { library_path: output_path, error }); + }); + } } if let Some(trailing_metadata) = trailing_metadata { @@ -431,108 +434,6 @@ fn link_rlib<'a>( ab } -/// Extract all symbols defined in raw-dylib libraries, collated by library name. -/// -/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library, -/// then the CodegenResults value contains one NativeLib instance for each block. However, the -/// linker appears to expect only a single import library for each library used, so we need to -/// collate the symbols together by library name before generating the import libraries. -fn collate_raw_dylibs<'a>( - sess: &Session, - used_libraries: impl IntoIterator, -) -> Vec<(String, Vec)> { - // Use index maps to preserve original order of imports and libraries. - let mut dylib_table = FxIndexMap::>::default(); - - for lib in used_libraries { - if lib.kind == NativeLibKind::RawDylib { - let ext = if lib.verbatim { "" } else { ".dll" }; - let name = format!("{}{}", lib.name, ext); - let imports = dylib_table.entry(name.clone()).or_default(); - for import in &lib.dll_imports { - if let Some(old_import) = imports.insert(import.name, import) { - // FIXME: when we add support for ordinals, figure out if we need to do anything - // if we have two DllImport values with the same name but different ordinals. - if import.calling_convention != old_import.calling_convention { - sess.dcx().emit_err(errors::MultipleExternalFuncDecl { - span: import.span, - function: import.name, - library_name: &name, - }); - } - } - } - } - } - sess.dcx().abort_if_errors(); - dylib_table - .into_iter() - .map(|(name, imports)| { - (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) - }) - .collect() -} - -fn create_dll_import_libs<'a>( - sess: &Session, - archive_builder_builder: &dyn ArchiveBuilderBuilder, - used_libraries: impl IntoIterator, - tmpdir: &Path, - is_direct_dependency: bool, -) -> Vec { - collate_raw_dylibs(sess, used_libraries) - .into_iter() - .map(|(raw_dylib_name, raw_dylib_imports)| { - let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; - let output_path = tmpdir.join(format!("{raw_dylib_name}{name_suffix}.lib")); - - let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target); - - let items: Vec = raw_dylib_imports - .iter() - .map(|import: &DllImport| { - if sess.target.arch == "x86" { - ImportLibraryItem { - name: common::i686_decorated_name( - import, - mingw_gnu_toolchain, - false, - false, - ), - ordinal: import.ordinal(), - symbol_name: import.is_missing_decorations().then(|| { - common::i686_decorated_name( - import, - mingw_gnu_toolchain, - false, - true, - ) - }), - is_data: !import.is_fn, - } - } else { - ImportLibraryItem { - name: import.name.to_string(), - ordinal: import.ordinal(), - symbol_name: None, - is_data: !import.is_fn, - } - } - }) - .collect(); - - archive_builder_builder.create_dll_import_lib( - sess, - &raw_dylib_name, - items, - &output_path, - ); - - output_path - }) - .collect() -} - /// Create a static archive. /// /// This is essentially the same thing as an rlib, but it also involves adding all of the upstream @@ -626,10 +527,9 @@ fn link_staticlib( let mut all_rust_dylibs = vec![]; for &cnum in crates { - match fmts.get(cnum) { - Some(&Linkage::Dynamic) => {} - _ => continue, - } + let Some(Linkage::Dynamic) = fmts.get(cnum) else { + continue; + }; let crate_name = codegen_results.crate_info.crate_name[&cnum]; let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum]; if let Some((path, _)) = &used_crate_source.dylib { @@ -1279,7 +1179,7 @@ mod win { let mut cp: u32 = 0; // We're using the `LOCALE_RETURN_NUMBER` flag to return a u32. // But the API requires us to pass the data as though it's a [u16] string. - let len = std::mem::size_of::() / std::mem::size_of::(); + let len = size_of::() / size_of::(); let data = std::slice::from_raw_parts_mut(&mut cp as *mut u32 as *mut u16, len); let len_written = GetLocaleInfoEx( LOCALE_NAME_SYSTEM_DEFAULT, @@ -1388,8 +1288,7 @@ fn link_sanitizer_runtime( if path.exists() { sess.target_tlib_path.dir.clone() } else { - let default_sysroot = - filesearch::get_or_default_sysroot().expect("Failed finding sysroot"); + let default_sysroot = filesearch::get_or_default_sysroot(); let default_tlib = filesearch::make_target_lib_path(&default_sysroot, sess.opts.target_triple.tuple()); default_tlib @@ -1732,8 +1631,12 @@ fn exec_linker( args.push_str( &Escape { arg: arg.to_str().unwrap(), - // LLD also uses MSVC-like parsing for @-files by default when running on windows hosts - is_like_msvc: sess.target.is_like_msvc || (cfg!(windows) && flavor.uses_lld()), + // Windows-style escaping for @-files is used by + // - all linkers targeting MSVC-like targets, including LLD + // - all LLD flavors running on Windows hosts + // С/С++ compilers use Posix-style escaping (except clang-cl, which we do not use). + is_like_msvc: sess.target.is_like_msvc + || (cfg!(windows) && flavor.uses_lld() && !flavor.uses_cc()), } .to_string(), ); @@ -2064,8 +1967,8 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor /// linker, and since they never participate in the linking, using `KEEP` in the linker scripts /// can't keep them either. This causes #47384. /// -/// To keep them around, we could use `--whole-archive` and equivalents to force rlib to -/// participate in linking like object files, but this proves to be expensive (#93791). Therefore +/// To keep them around, we could use `--whole-archive`, `-force_load` and equivalents to force rlib +/// to participate in linking like object files, but this proves to be expensive (#93791). Therefore /// we instead just introduce an undefined reference to them. This could be done by `-u` command /// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only /// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections` @@ -2107,8 +2010,20 @@ fn add_linked_symbol_object( file.set_mangling(object::write::Mangling::None); } + // ld64 requires a relocation to load undefined symbols, see below. + // Not strictly needed if linking with lld, but might as well do it there too. + let ld64_section_helper = if file.format() == object::BinaryFormat::MachO { + Some(file.add_section( + file.segment_name(object::write::StandardSegment::Data).to_vec(), + "__data".into(), + object::SectionKind::Data, + )) + } else { + None + }; + for (sym, kind) in symbols.iter() { - file.add_symbol(object::write::Symbol { + let symbol = file.add_symbol(object::write::Symbol { name: sym.clone().into(), value: 0, size: 0, @@ -2122,6 +2037,47 @@ fn add_linked_symbol_object( section: object::write::SymbolSection::Undefined, flags: object::SymbolFlags::None, }); + + // The linker shipped with Apple's Xcode, ld64, works a bit differently from other linkers. + // + // Code-wise, the relevant parts of ld64 are roughly: + // 1. Find the `ArchiveLoadMode` based on commandline options, default to `parseObjects`. + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/Options.cpp#L924-L932 + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/Options.h#L55 + // + // 2. Read the archive table of contents (__.SYMDEF file). + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L294-L325 + // + // 3. Begin linking by loading "atoms" from input files. + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/doc/design/linker.html + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/InputFiles.cpp#L1349 + // + // a. Directly specified object files (`.o`) are parsed immediately. + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/macho_relocatable_file.cpp#L4611-L4627 + // + // - Undefined symbols are not atoms (`n_value > 0` denotes a common symbol). + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/macho_relocatable_file.cpp#L2455-L2468 + // https://maskray.me/blog/2022-02-06-all-about-common-symbols + // + // - Relocations/fixups are atoms. + // https://github.com/apple-oss-distributions/ld64/blob/ce6341ae966b3451aa54eeb049f2be865afbd578/src/ld/parsers/macho_relocatable_file.cpp#L2088-L2114 + // + // b. Archives are not parsed yet. + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L467-L577 + // + // 4. When a symbol is needed by an atom, parse the object file that contains the symbol. + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/InputFiles.cpp#L1417-L1491 + // https://github.com/apple-oss-distributions/ld64/blob/ld64-954.16/src/ld/parsers/archive_file.cpp#L579-L597 + // + // All of the steps above are fairly similar to other linkers, except that **it completely + // ignores undefined symbols**. + // + // So to make this trick work on ld64, we need to do something else to load the relevant + // object files. We do this by inserting a relocation (fixup) for each symbol. + if let Some(section) = ld64_section_helper { + apple::add_data_and_relocation(&mut file, section, symbol, &sess.target, *kind) + .expect("failed adding relocation"); + } } let path = tmpdir.join("symbols.o"); @@ -2174,19 +2130,15 @@ fn add_library_search_dirs( return; } - walk_native_lib_search_dirs( - sess, - self_contained_components, - apple_sdk_root, - |dir, is_framework| { - if is_framework { - cmd.framework_path(dir); - } else { - cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); - } - ControlFlow::<()>::Continue(()) - }, - ); + let fallback = Some(NativeLibSearchFallback { self_contained_components, apple_sdk_root }); + walk_native_lib_search_dirs(sess, fallback, |dir, is_framework| { + if is_framework { + cmd.framework_path(dir); + } else { + cmd.include_path(&fix_windows_verbatim_for_gcc(dir)); + } + ControlFlow::<()>::Continue(()) + }); } /// Add options making relocation sections in the produced ELF files read-only @@ -2371,15 +2323,39 @@ fn linker_with_args( link_output_kind, ); + // Raw-dylibs from all crates. + let raw_dylib_dir = tmpdir.join("raw-dylibs"); + if sess.target.binary_format == BinaryFormat::Elf { + // On ELF we can't pass the raw-dylibs stubs to the linker as a path, + // instead we need to pass them via -l. To find the stub, we need to add + // the directory of the stub to the linker search path. + // We make an extra directory for this to avoid polluting the search path. + if let Err(error) = fs::create_dir(&raw_dylib_dir) { + sess.dcx().emit_fatal(errors::CreateTempDir { error }) + } + cmd.include_path(&raw_dylib_dir); + } + // Link with the import library generated for any raw-dylib functions. - for output_path in create_dll_import_libs( - sess, - archive_builder_builder, - codegen_results.crate_info.used_libraries.iter(), - tmpdir, - true, - ) { - cmd.add_object(&output_path); + if sess.target.is_like_windows { + for output_path in raw_dylib::create_raw_dylib_dll_import_libs( + sess, + archive_builder_builder, + codegen_results.crate_info.used_libraries.iter(), + tmpdir, + true, + ) { + cmd.add_object(&output_path); + } + } else { + for link_path in raw_dylib::create_raw_dylib_elf_stub_shared_objects( + sess, + codegen_results.crate_info.used_libraries.iter(), + &raw_dylib_dir, + ) { + // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects. + cmd.link_dylib_by_name(&link_path, true, false); + } } // As with add_upstream_native_libraries, we need to add the upstream raw-dylib symbols in case // they are used within inlined functions or instantiated generic functions. We do this *after* @@ -2398,19 +2374,35 @@ fn linker_with_args( .native_libraries .iter() .filter_map(|(&cnum, libraries)| { - (dependency_linkage[cnum] != Linkage::Static).then_some(libraries) + if sess.target.is_like_windows { + (dependency_linkage[cnum] != Linkage::Static).then_some(libraries) + } else { + Some(libraries) + } }) .flatten() .collect::>(); native_libraries_from_nonstatics.sort_unstable_by(|a, b| a.name.as_str().cmp(b.name.as_str())); - for output_path in create_dll_import_libs( - sess, - archive_builder_builder, - native_libraries_from_nonstatics, - tmpdir, - false, - ) { - cmd.add_object(&output_path); + + if sess.target.is_like_windows { + for output_path in raw_dylib::create_raw_dylib_dll_import_libs( + sess, + archive_builder_builder, + native_libraries_from_nonstatics, + tmpdir, + false, + ) { + cmd.add_object(&output_path); + } + } else { + for link_path in raw_dylib::create_raw_dylib_elf_stub_shared_objects( + sess, + native_libraries_from_nonstatics, + &raw_dylib_dir, + ) { + // Always use verbatim linkage, see comments in create_raw_dylib_elf_stub_shared_objects. + cmd.link_dylib_by_name(&link_path, true, false); + } } // Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make @@ -3387,6 +3379,35 @@ fn add_lld_args( // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { cmd.cc_arg("-fuse-ld=lld"); + + // On ELF platforms like at least x64 linux, GNU ld and LLD have opposite defaults on some + // section garbage-collection features. For example, the somewhat popular `linkme` crate and + // its dependents rely in practice on this difference: when using lld, they need `-z + // nostart-stop-gc` to prevent encapsulation symbols and sections from being + // garbage-collected. + // + // More information about all this can be found in: + // - https://maskray.me/blog/2021-01-31-metadata-sections-comdat-and-shf-link-order + // - https://lld.llvm.org/ELF/start-stop-gc + // + // So when using lld, we restore, for now, the traditional behavior to help migration, but + // will remove it in the future. + // Since this only disables an optimization, it shouldn't create issues, but is in theory + // slightly suboptimal. However, it: + // - doesn't have any visible impact on our benchmarks + // - reduces the need to disable lld for the crates that depend on this + // + // Note that lld can detect some cases where this difference is relied on, and emits a + // dedicated error to add this link arg. We could make use of this error to emit an FCW. As + // of writing this, we don't do it, because lld is already enabled by default on nightly + // without this mitigation: no working project would see the FCW, so we do this to help + // stabilization. + // + // FIXME: emit an FCW if linking fails due its absence, and then remove this link-arg in the + // future. + if sess.target.llvm_target == "x86_64-unknown-linux-gnu" { + cmd.link_arg("-znostart-stop-gc"); + } } if !flavor.is_gnu() { diff --git a/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs new file mode 100644 index 0000000000000..2c24378afe13b --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/back/link/raw_dylib.rs @@ -0,0 +1,373 @@ +use std::fs; +use std::io::{BufWriter, Write}; +use std::path::{Path, PathBuf}; + +use rustc_abi::Endian; +use rustc_data_structures::base_n::{CASE_INSENSITIVE, ToBaseN}; +use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::stable_hasher::StableHasher; +use rustc_hashes::Hash128; +use rustc_session::Session; +use rustc_session::cstore::DllImport; +use rustc_session::utils::NativeLibKind; +use rustc_span::Symbol; + +use crate::back::archive::ImportLibraryItem; +use crate::back::link::ArchiveBuilderBuilder; +use crate::errors::ErrorCreatingImportLibrary; +use crate::{NativeLib, common, errors}; + +/// Extract all symbols defined in raw-dylib libraries, collated by library name. +/// +/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library, +/// then the CodegenResults value contains one NativeLib instance for each block. However, the +/// linker appears to expect only a single import library for each library used, so we need to +/// collate the symbols together by library name before generating the import libraries. +fn collate_raw_dylibs_windows<'a>( + sess: &Session, + used_libraries: impl IntoIterator, +) -> Vec<(String, Vec)> { + // Use index maps to preserve original order of imports and libraries. + let mut dylib_table = FxIndexMap::>::default(); + + for lib in used_libraries { + if lib.kind == NativeLibKind::RawDylib { + let ext = if lib.verbatim { "" } else { ".dll" }; + let name = format!("{}{}", lib.name, ext); + let imports = dylib_table.entry(name.clone()).or_default(); + for import in &lib.dll_imports { + if let Some(old_import) = imports.insert(import.name, import) { + // FIXME: when we add support for ordinals, figure out if we need to do anything + // if we have two DllImport values with the same name but different ordinals. + if import.calling_convention != old_import.calling_convention { + sess.dcx().emit_err(errors::MultipleExternalFuncDecl { + span: import.span, + function: import.name, + library_name: &name, + }); + } + } + } + } + } + sess.dcx().abort_if_errors(); + dylib_table + .into_iter() + .map(|(name, imports)| { + (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) + }) + .collect() +} + +pub(super) fn create_raw_dylib_dll_import_libs<'a>( + sess: &Session, + archive_builder_builder: &dyn ArchiveBuilderBuilder, + used_libraries: impl IntoIterator, + tmpdir: &Path, + is_direct_dependency: bool, +) -> Vec { + collate_raw_dylibs_windows(sess, used_libraries) + .into_iter() + .map(|(raw_dylib_name, raw_dylib_imports)| { + let name_suffix = if is_direct_dependency { "_imports" } else { "_imports_indirect" }; + let output_path = tmpdir.join(format!("{raw_dylib_name}{name_suffix}.lib")); + + let mingw_gnu_toolchain = common::is_mingw_gnu_toolchain(&sess.target); + + let items: Vec = raw_dylib_imports + .iter() + .map(|import: &DllImport| { + if sess.target.arch == "x86" { + ImportLibraryItem { + name: common::i686_decorated_name( + import, + mingw_gnu_toolchain, + false, + false, + ), + ordinal: import.ordinal(), + symbol_name: import.is_missing_decorations().then(|| { + common::i686_decorated_name( + import, + mingw_gnu_toolchain, + false, + true, + ) + }), + is_data: !import.is_fn, + } + } else { + ImportLibraryItem { + name: import.name.to_string(), + ordinal: import.ordinal(), + symbol_name: None, + is_data: !import.is_fn, + } + } + }) + .collect(); + + archive_builder_builder.create_dll_import_lib( + sess, + &raw_dylib_name, + items, + &output_path, + ); + + output_path + }) + .collect() +} + +/// Extract all symbols defined in raw-dylib libraries, collated by library name. +/// +/// If we have multiple extern blocks that specify symbols defined in the same raw-dylib library, +/// then the CodegenResults value contains one NativeLib instance for each block. However, the +/// linker appears to expect only a single import library for each library used, so we need to +/// collate the symbols together by library name before generating the import libraries. +fn collate_raw_dylibs_elf<'a>( + sess: &Session, + used_libraries: impl IntoIterator, +) -> Vec<(String, Vec)> { + // Use index maps to preserve original order of imports and libraries. + let mut dylib_table = FxIndexMap::>::default(); + + for lib in used_libraries { + if lib.kind == NativeLibKind::RawDylib { + let filename = if lib.verbatim { + lib.name.as_str().to_owned() + } else { + let ext = sess.target.dll_suffix.as_ref(); + let prefix = sess.target.dll_prefix.as_ref(); + format!("{prefix}{}{ext}", lib.name) + }; + + let imports = dylib_table.entry(filename.clone()).or_default(); + for import in &lib.dll_imports { + imports.insert(import.name, import); + } + } + } + sess.dcx().abort_if_errors(); + dylib_table + .into_iter() + .map(|(name, imports)| { + (name, imports.into_iter().map(|(_, import)| import.clone()).collect()) + }) + .collect() +} + +pub(super) fn create_raw_dylib_elf_stub_shared_objects<'a>( + sess: &Session, + used_libraries: impl IntoIterator, + raw_dylib_so_dir: &Path, +) -> Vec { + collate_raw_dylibs_elf(sess, used_libraries) + .into_iter() + .map(|(load_filename, raw_dylib_imports)| { + use std::hash::Hash; + + // `load_filename` is the *target/loader* filename that will end up in NEEDED. + // Usually this will be something like `libc.so` or `libc.so.6` but with + // verbatim it might also be an absolute path. + // To be able to support this properly, we always put this load filename + // into the SONAME of the library and link it via a temporary file with a random name. + // This also avoids naming conflicts with non-raw-dylib linkage of the same library. + + let shared_object = create_elf_raw_dylib_stub(sess, &load_filename, &raw_dylib_imports); + + let mut file_name_hasher = StableHasher::new(); + load_filename.hash(&mut file_name_hasher); + for raw_dylib in raw_dylib_imports { + raw_dylib.name.as_str().hash(&mut file_name_hasher); + } + + let library_filename: Hash128 = file_name_hasher.finish(); + let temporary_lib_name = format!( + "{}{}{}", + sess.target.dll_prefix, + library_filename.as_u128().to_base_fixed_len(CASE_INSENSITIVE), + sess.target.dll_suffix + ); + let link_path = raw_dylib_so_dir.join(&temporary_lib_name); + + let file = match fs::File::create_new(&link_path) { + Ok(file) => file, + Err(error) => sess.dcx().emit_fatal(ErrorCreatingImportLibrary { + lib_name: &load_filename, + error: error.to_string(), + }), + }; + if let Err(error) = BufWriter::new(file).write_all(&shared_object) { + sess.dcx().emit_fatal(ErrorCreatingImportLibrary { + lib_name: &load_filename, + error: error.to_string(), + }); + }; + + temporary_lib_name + }) + .collect() +} + +/// Create an ELF .so stub file for raw-dylib. +/// It exports all the provided symbols, but is otherwise empty. +fn create_elf_raw_dylib_stub(sess: &Session, soname: &str, symbols: &[DllImport]) -> Vec { + use object::write::elf as write; + use object::{Architecture, elf}; + + let mut stub_buf = Vec::new(); + + // Build the stub ELF using the object crate. + // The high-level portable API does not allow for the fine-grained control we need, + // so this uses the low-level object::write::elf API. + // The low-level API consists of two stages: reservation and writing. + // We first reserve space for all the things in the binary and then write them. + // It is important that the order of reservation matches the order of writing. + // The object crate contains many debug asserts that fire if you get this wrong. + + let endianness = match sess.target.options.endian { + Endian::Little => object::Endianness::Little, + Endian::Big => object::Endianness::Big, + }; + let mut stub = write::Writer::new(endianness, true, &mut stub_buf); + + // These initial reservations don't reserve any bytes in the binary yet, + // they just allocate in the internal data structures. + + // First, we crate the dynamic symbol table. It starts with a null symbol + // and then all the symbols and their dynamic strings. + stub.reserve_null_dynamic_symbol_index(); + + let dynstrs = symbols + .iter() + .map(|sym| { + stub.reserve_dynamic_symbol_index(); + (sym, stub.add_dynamic_string(sym.name.as_str().as_bytes())) + }) + .collect::>(); + + let soname = stub.add_dynamic_string(soname.as_bytes()); + + // Reserve the sections. + // We have the minimal sections for a dynamic SO and .text where we point our dummy symbols to. + stub.reserve_shstrtab_section_index(); + let text_section_name = stub.add_section_name(".text".as_bytes()); + let text_section = stub.reserve_section_index(); + stub.reserve_dynstr_section_index(); + stub.reserve_dynsym_section_index(); + stub.reserve_dynamic_section_index(); + + // These reservations now determine the actual layout order of the object file. + stub.reserve_file_header(); + stub.reserve_shstrtab(); + stub.reserve_section_headers(); + stub.reserve_dynstr(); + stub.reserve_dynsym(); + stub.reserve_dynamic(2); // DT_SONAME, DT_NULL + + // First write the ELF header with the arch information. + let Some((arch, sub_arch)) = sess.target.object_architecture(&sess.unstable_target_features) + else { + sess.dcx().fatal(format!( + "raw-dylib is not supported for the architecture `{}`", + sess.target.arch + )); + }; + let e_machine = match (arch, sub_arch) { + (Architecture::Aarch64, None) => elf::EM_AARCH64, + (Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64, + (Architecture::Arm, None) => elf::EM_ARM, + (Architecture::Avr, None) => elf::EM_AVR, + (Architecture::Bpf, None) => elf::EM_BPF, + (Architecture::Csky, None) => elf::EM_CSKY, + (Architecture::E2K32, None) => elf::EM_MCST_ELBRUS, + (Architecture::E2K64, None) => elf::EM_MCST_ELBRUS, + (Architecture::I386, None) => elf::EM_386, + (Architecture::X86_64, None) => elf::EM_X86_64, + (Architecture::X86_64_X32, None) => elf::EM_X86_64, + (Architecture::Hexagon, None) => elf::EM_HEXAGON, + (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, + (Architecture::M68k, None) => elf::EM_68K, + (Architecture::Mips, None) => elf::EM_MIPS, + (Architecture::Mips64, None) => elf::EM_MIPS, + (Architecture::Mips64_N32, None) => elf::EM_MIPS, + (Architecture::Msp430, None) => elf::EM_MSP430, + (Architecture::PowerPc, None) => elf::EM_PPC, + (Architecture::PowerPc64, None) => elf::EM_PPC64, + (Architecture::Riscv32, None) => elf::EM_RISCV, + (Architecture::Riscv64, None) => elf::EM_RISCV, + (Architecture::S390x, None) => elf::EM_S390, + (Architecture::Sbf, None) => elf::EM_SBF, + (Architecture::Sharc, None) => elf::EM_SHARC, + (Architecture::Sparc, None) => elf::EM_SPARC, + (Architecture::Sparc32Plus, None) => elf::EM_SPARC32PLUS, + (Architecture::Sparc64, None) => elf::EM_SPARCV9, + (Architecture::Xtensa, None) => elf::EM_XTENSA, + _ => { + sess.dcx().fatal(format!( + "raw-dylib is not supported for the architecture `{}`", + sess.target.arch + )); + } + }; + + stub.write_file_header(&write::FileHeader { + os_abi: crate::back::metadata::elf_os_abi(sess), + abi_version: 0, + e_type: object::elf::ET_DYN, + e_machine, + e_entry: 0, + e_flags: crate::back::metadata::elf_e_flags(arch, sess), + }) + .unwrap(); + + // .shstrtab + stub.write_shstrtab(); + + // Section headers + stub.write_null_section_header(); + stub.write_shstrtab_section_header(); + // Create a dummy .text section for our dummy symbols. + stub.write_section_header(&write::SectionHeader { + name: Some(text_section_name), + sh_type: elf::SHT_PROGBITS, + sh_flags: 0, + sh_addr: 0, + sh_offset: 0, + sh_size: 0, + sh_link: 0, + sh_info: 0, + sh_addralign: 1, + sh_entsize: 0, + }); + stub.write_dynstr_section_header(0); + stub.write_dynsym_section_header(0, 1); + stub.write_dynamic_section_header(0); + + // .dynstr + stub.write_dynstr(); + + // .dynsym + stub.write_null_dynamic_symbol(); + for (_, name) in dynstrs { + stub.write_dynamic_symbol(&write::Sym { + name: Some(name), + st_info: (elf::STB_GLOBAL << 4) | elf::STT_NOTYPE, + st_other: elf::STV_DEFAULT, + section: Some(text_section), + st_shndx: 0, // ignored by object in favor of the `section` field + st_value: 0, + st_size: 0, + }); + } + + // .dynamic + // the DT_SONAME will be used by the linker to populate DT_NEEDED + // which the loader uses to find the library. + // DT_NULL terminates the .dynamic table. + stub.write_dynamic_string(elf::DT_SONAME, soname); + stub.write_dynamic(elf::DT_NULL, 0); + + stub_buf +} diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8900405c1b8f8..a8405a2aec98d 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1655,9 +1655,9 @@ impl<'a> Linker for AixLinker<'a> { } } - fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.link_or_cc_arg(format!("-l{name}")); + self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") }); } fn link_dylib_by_path(&mut self, path: &Path, _as_needed: bool) { @@ -1668,7 +1668,7 @@ impl<'a> Linker for AixLinker<'a> { fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.link_or_cc_arg(format!("-l{name}")); + self.link_or_cc_arg(if verbatim { String::from(name) } else { format!("-l{name}") }); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(find_native_static_library(name, verbatim, self.sess)); @@ -1939,14 +1939,14 @@ impl<'a> Linker for LlbcLinker<'a> { } fn optimize(&mut self) { - match self.sess.opts.optimize { + self.link_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::More => "-O2", OptLevel::Aggressive => "-O3", OptLevel::Size => "-Os", OptLevel::SizeMin => "-Oz", - }; + }); } fn full_relro(&mut self) {} diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d70413b8a4741..68b453ff42425 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -9,8 +9,7 @@ use itertools::Itertools; use object::write::{self, StandardSegment, Symbol, SymbolSection}; use object::{ Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, ObjectSymbol, - SectionFlags, SectionKind, SubArchitecture, SymbolFlags, SymbolKind, SymbolScope, elf, pe, - xcoff, + SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope, elf, pe, xcoff, }; use rustc_abi::Endian; use rustc_data_structures::memmap::Mmap; @@ -206,61 +205,12 @@ pub(crate) fn create_object_file(sess: &Session) -> Option Endianness::Little, Endian::Big => Endianness::Big, }; - let (architecture, sub_architecture) = match &sess.target.arch[..] { - "arm" => (Architecture::Arm, None), - "aarch64" => ( - if sess.target.pointer_width == 32 { - Architecture::Aarch64_Ilp32 - } else { - Architecture::Aarch64 - }, - None, - ), - "x86" => (Architecture::I386, None), - "s390x" => (Architecture::S390x, None), - "mips" | "mips32r6" => (Architecture::Mips, None), - "mips64" | "mips64r6" => (Architecture::Mips64, None), - "x86_64" => ( - if sess.target.pointer_width == 32 { - Architecture::X86_64_X32 - } else { - Architecture::X86_64 - }, - None, - ), - "powerpc" => (Architecture::PowerPc, None), - "powerpc64" => (Architecture::PowerPc64, None), - "riscv32" => (Architecture::Riscv32, None), - "riscv64" => (Architecture::Riscv64, None), - "sparc" => { - if sess.unstable_target_features.contains(&sym::v8plus) { - // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode - (Architecture::Sparc32Plus, None) - } else { - // Target uses V7 or V8, aka EM_SPARC - (Architecture::Sparc, None) - } - } - "sparc64" => (Architecture::Sparc64, None), - "avr" => (Architecture::Avr, None), - "msp430" => (Architecture::Msp430, None), - "hexagon" => (Architecture::Hexagon, None), - "bpf" => (Architecture::Bpf, None), - "loongarch64" => (Architecture::LoongArch64, None), - "csky" => (Architecture::Csky, None), - "arm64ec" => (Architecture::Aarch64, Some(SubArchitecture::Arm64EC)), - // Unsupported architecture. - _ => return None, - }; - let binary_format = if sess.target.is_like_osx { - BinaryFormat::MachO - } else if sess.target.is_like_windows { - BinaryFormat::Coff - } else if sess.target.is_like_aix { - BinaryFormat::Xcoff - } else { - BinaryFormat::Elf + let Some((architecture, sub_architecture)) = + sess.target.object_architecture(&sess.unstable_target_features) + else { + return None; }; + let binary_format = sess.target.binary_format.to_object(); let mut file = write::Object::new(binary_format, architecture, endianness); file.set_sub_architecture(sub_architecture); @@ -300,7 +250,26 @@ pub(crate) fn create_object_file(sess: &Session) -> Option u8 { + match sess.target.options.os.as_ref() { + "hermit" => elf::ELFOSABI_STANDALONE, + "freebsd" => elf::ELFOSABI_FREEBSD, + "solaris" => elf::ELFOSABI_SOLARIS, + _ => elf::ELFOSABI_NONE, + } +} + +pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { + match architecture { Architecture::Mips => { let arch = match sess.target.options.cpu.as_ref() { "mips1" => elf::EF_MIPS_ARCH_1, @@ -381,7 +350,11 @@ pub(crate) fn create_object_file(sess: &Session) -> Option { // Resolve the ISA revision and set // the appropriate EF_AVR_ARCH flag. - ef_avr_arch(&sess.target.options.cpu) + if let Some(ref cpu) = sess.opts.cg.target_cpu { + ef_avr_arch(cpu) + } else { + bug!("AVR CPU not explicitly specified") + } } Architecture::Csky => { let e_flags = match sess.target.options.abi.as_ref() { @@ -391,18 +364,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option 0, - }; - // adapted from LLVM's `MCELFObjectTargetWriter::getOSABI` - let os_abi = match sess.target.options.os.as_ref() { - "hermit" => elf::ELFOSABI_STANDALONE, - "freebsd" => elf::ELFOSABI_FREEBSD, - "solaris" => elf::ELFOSABI_SOLARIS, - _ => elf::ELFOSABI_NONE, - }; - let abi_version = 0; - add_gnu_property_note(&mut file, architecture, binary_format, endianness); - file.flags = FileFlags::Elf { os_abi, abi_version, e_flags }; - Some(file) + } } /// Mach-O files contain information about: diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 12ee872d53141..459f4329d6e92 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -183,11 +183,11 @@ fn exported_symbols_provider_local( }); let mut symbols: Vec<_> = - sorted.iter().map(|(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect(); + sorted.iter().map(|&(&def_id, &info)| (ExportedSymbol::NonGeneric(def_id), info)).collect(); // Export TLS shims if !tcx.sess.target.dll_tls_export { - symbols.extend(sorted.iter().filter_map(|(&def_id, &info)| { + symbols.extend(sorted.iter().filter_map(|&(&def_id, &info)| { tcx.needs_thread_local_shim(def_id).then(|| { ( ExportedSymbol::ThreadLocalShim(def_id), diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 71cc13279ec2b..bb8380bb3d55d 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use std::sync::mpsc::{Receiver, Sender, channel}; use std::{fs, io, mem, str, thread}; +use rustc_abi::Size; use rustc_ast::attr; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; @@ -41,7 +42,7 @@ use tracing::debug; use super::link::{self, ensure_removed}; use super::lto::{self, SerializedModule}; use super::symbol_export::symbol_name_for_instance_in_crate; -use crate::errors::{AutodiffWithoutLto, ErrorCreatingRemarkDir}; +use crate::errors::ErrorCreatingRemarkDir; use crate::traits::*; use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, @@ -278,6 +279,10 @@ impl ModuleConfig { || self.emit_obj == EmitObj::Bitcode || self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) } + + pub fn embed_bitcode(&self) -> bool { + self.emit_obj == EmitObj::ObjectCode(BitcodeSection::Full) + } } /// Configuration passed to the function returned by the `target_machine_factory`. @@ -351,6 +356,7 @@ pub struct CodegenContext { pub target_is_like_aix: bool, pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, + pub pointer_size: Size, /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows @@ -422,7 +428,7 @@ fn generate_lto_work( lto_modules .into_iter() .map(|module| { - let mut module = + let module = unsafe { module.autodiff(cgcx, autodiff.clone(), config).unwrap_or_else(|e| e.raise()) }; let cost = module.cost(); (WorkItem::LTO(module), cost) @@ -472,7 +478,7 @@ pub(crate) fn start_async_codegen( ) -> OngoingCodegen { let (coordinator_send, coordinator_receive) = channel(); - let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); let crate_info = CrateInfo::new(tcx, target_cpu); @@ -576,10 +582,10 @@ fn produce_final_output_artifacts( }; let copy_if_one_unit = |output_type: OutputType, keep_numbered: bool| { - if compiled_modules.modules.len() == 1 { + if let [module] = &compiled_modules.modules[..] { // 1) Only one codegen unit. In this case it's no difficulty // to copy `foo.0.x` to `foo.x`. - let module_name = Some(&compiled_modules.modules[0].name[..]); + let module_name = Some(&module.name[..]); let path = crate_output.temp_path(output_type, module_name); let output = crate_output.path(output_type); if !output_type.is_text_output() && output.is_tty() { @@ -711,8 +717,8 @@ fn produce_final_output_artifacts( } if sess.opts.json_artifact_notifications { - if compiled_modules.modules.len() == 1 { - compiled_modules.modules[0].for_each_output(|_path, ty| { + if let [module] = &compiled_modules.modules[..] { + module.for_each_output(|_path, ty| { if sess.opts.output_types.contains_key(&ty) { let descr = ty.shorthand(); // for single cgu file is renamed to drop cgu specific suffix @@ -868,7 +874,7 @@ pub(crate) fn compute_per_cgu_lto_type( // require LTO so the request for LTO is always unconditionally // passed down to the backend, but we don't actually want to do // anything about it yet until we've got a final product. - let is_rlib = sess_crate_types.len() == 1 && sess_crate_types[0] == CrateType::Rlib; + let is_rlib = matches!(sess_crate_types, [CrateType::Rlib]); match sess_lto { Lto::ThinLocal if !linker_does_lto && !is_allocator => ComputedLtoType::Thin, @@ -880,14 +886,14 @@ pub(crate) fn compute_per_cgu_lto_type( fn execute_optimize_work_item( cgcx: &CodegenContext, - module: ModuleCodegen, + mut module: ModuleCodegen, module_config: &ModuleConfig, ) -> Result, FatalError> { let dcx = cgcx.create_dcx(); let dcx = dcx.handle(); unsafe { - B::optimize(cgcx, dcx, &module, module_config)?; + B::optimize(cgcx, dcx, &mut module, module_config)?; } // After we've done the initial round of optimizations we need to @@ -1215,6 +1221,7 @@ fn start_executing_work( split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel: backend.supports_parallel() && !sess.opts.unstable_opts.no_parallel_backend, + pointer_size: tcx.data_layout.pointer_size, }; // This is the "main loop" of parallel work happening for parallel codegen. @@ -1543,8 +1550,9 @@ fn start_executing_work( // Spin up what work we can, only doing this while we've got available // parallelism slots and work left to spawn. if codegen_state != Aborted { - while !work_items.is_empty() && running_with_own_token < tokens.len() { - let (item, _) = work_items.pop().unwrap(); + while running_with_own_token < tokens.len() + && let Some((item, _)) = work_items.pop() + { spawn_work( &cgcx, &mut llvm_start_time, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 40238f4b4915a..e9c886d28edf6 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -5,7 +5,9 @@ use std::time::{Duration, Instant}; use itertools::Itertools; use rustc_abi::FIRST_VARIANT; +use rustc_ast as ast; use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name}; +use rustc_attr_parsing::OptimizeAttr; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; use rustc_data_structures::sync::par_map; @@ -29,7 +31,6 @@ use rustc_span::{DUMMY_SP, Symbol, sym}; use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; -use {rustc_ast as ast, rustc_attr_parsing as attr}; use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; @@ -686,7 +687,7 @@ pub fn codegen_crate( submit_codegened_module_to_llvm( &backend, &ongoing_codegen.coordinator.sender, - ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator }, + ModuleCodegen::new_allocator(llmod_id, module_llvm), cost, ); } @@ -875,7 +876,7 @@ impl CrateInfo { let linked_symbols = crate_types.iter().map(|&c| (c, crate::back::linker::linked_symbols(tcx, c))).collect(); let local_crate_name = tcx.crate_name(LOCAL_CRATE); - let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); let subsystem = ast::attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem); let windows_subsystem = subsystem.map(|subsystem| { @@ -1061,7 +1062,7 @@ pub(crate) fn provide(providers: &mut Providers) { let any_for_speed = defids.items().any(|id| { let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id); - matches!(optimize, attr::OptimizeAttr::Speed) + matches!(optimize, OptimizeAttr::Speed) }); if any_for_speed { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 3e9dfcea58b8b..998a4ff727e85 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -1,15 +1,11 @@ use std::str::FromStr; use rustc_abi::ExternAbi; -use rustc_ast::attr::list_contains_name; -use rustc_ast::expand::autodiff_attrs::{ - AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity, -}; +use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode}; use rustc_ast::{MetaItem, MetaItemInner, attr}; -use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_parsing::ReprAttr::ReprAlign; +use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::codes::*; -use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; @@ -64,7 +60,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { ); } - let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)); + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)); let mut codegen_fn_attrs = CodegenFnAttrs::new(); if tcx.should_inherit_track_caller(did) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; @@ -79,7 +75,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // When `no_builtins` is applied at the crate level, we should add the // `no-builtins` attribute to each function to ensure it takes effect in LTO. - let crate_attrs = tcx.hir().attrs(rustc_hir::CRATE_HIR_ID); + let crate_attrs = tcx.hir_attrs(rustc_hir::CRATE_HIR_ID); let no_builtins = attr::contains_name(crate_attrs, sym::no_builtins); if no_builtins { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_BUILTINS; @@ -105,12 +101,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let Fn | AssocFn | Variant | Ctor(..) = def_kind { Some(tcx.fn_sig(did)) } else { - tcx.dcx() - .span_delayed_bug(attr.span, "this attribute can only be applied to functions"); + tcx.dcx().span_delayed_bug( + attr.span(), + "this attribute can only be applied to functions", + ); None } }; + if let hir::Attribute::Parsed(p) = attr { + match p { + AttributeKind::Repr(reprs) => { + codegen_fn_attrs.alignment = reprs + .iter() + .find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None }); + } + + _ => {} + } + } + let Some(Ident { name, .. }) = attr.ident() else { continue; }; @@ -131,14 +141,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; mixed_export_name_no_mangle_lint_state.track_no_mangle( - attr.span, + attr.span(), tcx.local_def_id_to_hir_id(did), attr, ); } else { tcx.dcx() .struct_span_err( - attr.span, + attr.span(), format!( "`#[no_mangle]` cannot be used on {} {} as it has no name", tcx.def_descr_article(did.to_def_id()), @@ -159,7 +169,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { feature_err( &tcx.sess, sym::used_with_arg, - attr.span, + attr.span(), "`#[used(linker)]` is currently unstable", ) .emit(); @@ -171,7 +181,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { feature_err( &tcx.sess, sym::used_with_arg, - attr.span, + attr.span(), "`#[used(compiler)]` is currently unstable", ) .emit(); @@ -179,7 +189,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; } Some(_) => { - tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span }); + tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() }); } None => { // Unfortunately, unconditionally using `llvm.used` causes @@ -222,22 +232,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { && let Some(fn_sig) = fn_sig() && fn_sig.skip_binder().abi() != ExternAbi::Rust { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0737, - "`#[track_caller]` requires Rust ABI" - ) - .emit(); + tcx.dcx().emit_err(errors::RequiresRustAbi { span: attr.span() }); } if is_closure && !tcx.features().closure_track_caller() - && !attr.span.allows_unstable(sym::closure_track_caller) + && !attr.span().allows_unstable(sym::closure_track_caller) { feature_err( &tcx.sess, sym::closure_track_caller, - attr.span, + attr.span(), "`#[track_caller]` on closures is currently unstable", ) .emit(); @@ -249,21 +253,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if s.as_str().contains('\0') { // `#[export_name = ...]` will be converted to a null-terminated string, // so it may not contain any null characters. - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0648, - "`export_name` may not contain null characters" - ) - .emit(); + tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() }); } codegen_fn_attrs.export_name = Some(s); - mixed_export_name_no_mangle_lint_state.track_export_name(attr.span); + mixed_export_name_no_mangle_lint_state.track_export_name(attr.span()); } } sym::target_feature => { let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { - tcx.dcx().span_delayed_bug(attr.span, "target_feature applied to non-fn"); + tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn"); continue; }; let safe_target_features = @@ -293,7 +291,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // `main`, `start`, and other functions that are not usually // allowed. } else { - check_target_feature_trait_unsafe(tcx, did, attr.span); + check_target_feature_trait_unsafe(tcx, did, attr.span()); } } from_target_feature_attr( @@ -311,7 +309,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if tcx.is_mutable_static(did.into()) { let mut diag = tcx.dcx().struct_span_err( - attr.span, + attr.span(), "extern mutable statics are not allowed with `#[linkage]`", ); diag.note( @@ -330,7 +328,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let Some(val) = attr.value_str() { if val.as_str().bytes().any(|b| b == 0) { let msg = format!("illegal null byte in link_section value: `{val}`"); - tcx.dcx().span_err(attr.span, msg); + tcx.dcx().span_err(attr.span(), msg); } else { codegen_fn_attrs.link_section = Some(val); } @@ -338,13 +336,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } sym::link_name => codegen_fn_attrs.link_name = attr.value_str(), sym::link_ordinal => { - link_ordinal_span = Some(attr.span); + link_ordinal_span = Some(attr.span()); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { codegen_fn_attrs.link_ordinal = ordinal; } } sym::no_sanitize => { - no_sanitize_span = Some(attr.span); + no_sanitize_span = Some(attr.span()); if let Some(list) = attr.meta_item_list() { for item in list.iter() { match item.name_or_empty() { @@ -377,137 +375,73 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let segments = set.path.segments.iter().map(|x| x.ident.name).collect::>(); match segments.as_slice() { - [sym::arm, sym::a32] | [sym::arm, sym::t32] => { - if !tcx.sess.target.has_thumb_interworking { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0779, - "target does not support `#[instruction_set]`" - ) - .emit(); - None - } else if segments[1] == sym::a32 { - Some(InstructionSetAttr::ArmA32) - } else if segments[1] == sym::t32 { - Some(InstructionSetAttr::ArmT32) - } else { - unreachable!() - } + [sym::arm, sym::a32 | sym::t32] + if !tcx.sess.target.has_thumb_interworking => + { + tcx.dcx().emit_err(errors::UnsuportedInstructionSet { + span: attr.span(), + }); + None } + [sym::arm, sym::a32] => Some(InstructionSetAttr::ArmA32), + [sym::arm, sym::t32] => Some(InstructionSetAttr::ArmT32), _ => { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0779, - "invalid instruction set specified", - ) - .emit(); + tcx.dcx().emit_err(errors::InvalidInstructionSet { + span: attr.span(), + }); None } } } [] => { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0778, - "`#[instruction_set]` requires an argument" - ) - .emit(); + tcx.dcx().emit_err(errors::BareInstructionSet { span: attr.span() }); None } _ => { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0779, - "cannot specify more than one instruction set" - ) - .emit(); + tcx.dcx() + .emit_err(errors::MultipleInstructionSet { span: attr.span() }); None } }) } - sym::repr => { - codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list() - && let [item] = items.as_slice() - && let Some((sym::align, literal)) = item.singleton_lit_list() - { - rustc_attr_parsing::parse_alignment(&literal.kind) - .map_err(|msg| { - struct_span_code_err!( - tcx.dcx(), - literal.span, - E0589, - "invalid `repr(align)` attribute: {}", - msg - ) - .emit(); - }) - .ok() - } else { - None - }; - } sym::patchable_function_entry => { codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| { let mut prefix = None; let mut entry = None; for item in l { let Some(meta_item) = item.meta_item() else { - tcx.dcx().span_err(item.span(), "expected name value pair"); + tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); continue; }; let Some(name_value_lit) = meta_item.name_value_literal() else { - tcx.dcx().span_err(item.span(), "expected name value pair"); + tcx.dcx().emit_err(errors::ExpectedNameValuePair { span: item.span() }); continue; }; - fn emit_error_with_label( - tcx: TyCtxt<'_>, - span: Span, - error: impl Into, - label: impl Into, - ) { - let mut err: rustc_errors::Diag<'_, _> = - tcx.dcx().struct_span_err(span, error); - err.span_label(span, label); - err.emit(); - } - let attrib_to_write = match meta_item.name_or_empty() { sym::prefix_nops => &mut prefix, sym::entry_nops => &mut entry, _ => { - emit_error_with_label( - tcx, - item.span(), - "unexpected parameter name", - format!("expected {} or {}", sym::prefix_nops, sym::entry_nops), - ); + tcx.dcx().emit_err(errors::UnexpectedParameterName { + span: item.span(), + prefix_nops: sym::prefix_nops, + entry_nops: sym::entry_nops, + }); continue; } }; let rustc_ast::LitKind::Int(val, _) = name_value_lit.kind else { - emit_error_with_label( - tcx, - name_value_lit.span, - "invalid literal value", - "value must be an integer between `0` and `255`", - ); + tcx.dcx().emit_err(errors::InvalidLiteralValue { + span: name_value_lit.span, + }); continue; }; let Ok(val) = val.get().try_into() else { - emit_error_with_label( - tcx, - name_value_lit.span, - "integer value out of range", - "value must be between `0` and `255`", - ); + tcx.dcx() + .emit_err(errors::OutOfRangeInteger { span: name_value_lit.span }); continue; }; @@ -515,7 +449,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } if let (None, None) = (prefix, entry) { - tcx.dcx().span_err(attr.span, "must specify at least one parameter"); + tcx.dcx().span_err(attr.span(), "must specify at least one parameter"); } Some(PatchableFunctionEntry::from_prefix_and_entry( @@ -536,25 +470,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } if attr.is_word() { - InlineAttr::Hint - } else if let Some(ref items) = attr.meta_item_list() { - inline_span = Some(attr.span); - if items.len() != 1 { - struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit(); - InlineAttr::None - } else if list_contains_name(items, sym::always) { - InlineAttr::Always - } else if list_contains_name(items, sym::never) { - InlineAttr::Never - } else { - struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .with_help("valid inline arguments are `always` and `never`") - .emit(); + return InlineAttr::Hint; + } + let Some(ref items) = attr.meta_item_list() else { + return ia; + }; + inline_span = Some(attr.span()); - InlineAttr::None - } + let [item] = &items[..] else { + tcx.dcx().emit_err(errors::ExpectedOneArgument { span: attr.span() }); + return InlineAttr::None; + }; + + if item.has_name(sym::always) { + InlineAttr::Always + } else if item.has_name(sym::never) { + InlineAttr::Never } else { - ia + tcx.dcx().emit_err(errors::InvalidArgument { span: items[0].span() }); + + InlineAttr::None } }); codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| { @@ -563,9 +498,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } if attr.is_word() { - InlineAttr::Force { attr_span: attr.span, reason: None } + InlineAttr::Force { attr_span: attr.span(), reason: None } } else if let Some(val) = attr.value_str() { - InlineAttr::Force { attr_span: attr.span, reason: Some(val) } + InlineAttr::Force { attr_span: attr.span(), reason: Some(val) } } else { debug!("`rustc_force_inline` not checked by attribute validation"); ia @@ -583,26 +518,27 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if !attr.has_name(sym::optimize) { return ia; } - let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit(); if attr.is_word() { - err(attr.span, "expected one argument"); - ia - } else if let Some(ref items) = attr.meta_item_list() { - inline_span = Some(attr.span); - if items.len() != 1 { - err(attr.span, "expected one argument"); - OptimizeAttr::Default - } else if list_contains_name(items, sym::size) { - OptimizeAttr::Size - } else if list_contains_name(items, sym::speed) { - OptimizeAttr::Speed - } else if list_contains_name(items, sym::none) { - OptimizeAttr::DoNotOptimize - } else { - err(items[0].span(), "invalid argument"); - OptimizeAttr::Default - } + tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() }); + return ia; + } + let Some(ref items) = attr.meta_item_list() else { + return OptimizeAttr::Default; + }; + + inline_span = Some(attr.span()); + let [item] = &items[..] else { + tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() }); + return OptimizeAttr::Default; + }; + if item.has_name(sym::size) { + OptimizeAttr::Size + } else if item.has_name(sym::speed) { + OptimizeAttr::Speed + } else if item.has_name(sym::none) { + OptimizeAttr::DoNotOptimize } else { + tcx.dcx().emit_err(errors::InvalidArgumentOptimize { span: item.span() }); OptimizeAttr::Default } }); @@ -644,25 +580,20 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // llvm/llvm-project#70563). if !codegen_fn_attrs.target_features.is_empty() && matches!(codegen_fn_attrs.inline, InlineAttr::Always) + && let Some(span) = inline_span { - if let Some(span) = inline_span { - tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`"); - } + tcx.dcx().span_err(span, "cannot use `#[inline(always)]` with `#[target_feature]`"); } - if !codegen_fn_attrs.no_sanitize.is_empty() && codegen_fn_attrs.inline.always() { - if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { - let hir_id = tcx.local_def_id_to_hir_id(did); - tcx.node_span_lint( - lint::builtin::INLINE_NO_SANITIZE, - hir_id, - no_sanitize_span, - |lint| { - lint.primary_message("`no_sanitize` will have no effect after inlining"); - lint.span_note(inline_span, "inlining requested here"); - }, - ) - } + if !codegen_fn_attrs.no_sanitize.is_empty() + && codegen_fn_attrs.inline.always() + && let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) + { + let hir_id = tcx.local_def_id_to_hir_id(did); + tcx.node_span_lint(lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, |lint| { + lint.primary_message("`no_sanitize` will have no effect after inlining"); + lint.span_note(inline_span, "inlining requested here"); + }) } // Weak lang items have the same semantics as "std internal" symbols in the @@ -692,10 +623,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { // Any linkage to LLVM intrinsics for now forcibly marks them all as never // unwinds since LLVM sometimes can't handle codegen which `invoke`s // intrinsic functions. - if let Some(name) = &codegen_fn_attrs.link_name { - if name.as_str().starts_with("llvm.") { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; - } + if let Some(name) = &codegen_fn_attrs.link_name + && name.as_str().starts_with("llvm.") + { + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; } if let Some(features) = check_tied_features( @@ -709,7 +640,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let span = tcx .get_attrs(did, sym::target_feature) .next() - .map_or_else(|| tcx.def_span(did), |a| a.span); + .map_or_else(|| tcx.def_span(did), |a| a.span()); tcx.dcx() .create_err(errors::TargetFeatureDisableOrEnable { features, @@ -756,18 +687,13 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option { use rustc_ast::{LitIntType, LitKind, MetaItemLit}; - let meta_item_list = attr.meta_item_list(); - let meta_item_list = meta_item_list.as_deref(); - let sole_meta_list = match meta_item_list { - Some([item]) => item.lit(), - Some(_) => { - tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span }); - return None; - } - _ => None, + let meta_item_list = attr.meta_item_list()?; + let [sole_meta_list] = &meta_item_list[..] else { + tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span() }); + return None; }; if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = - sole_meta_list + sole_meta_list.lit() { // According to the table at // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the @@ -787,13 +713,13 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option { } else { let msg = format!("ordinal value in `link_ordinal` is too large: `{ordinal}`"); tcx.dcx() - .struct_span_err(attr.span, msg) + .struct_span_err(attr.span(), msg) .with_note("the value may not exceed `u16::MAX`") .emit(); None } } else { - tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span }); + tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span() }); None } } @@ -839,7 +765,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> { export_name: Some(export_name), no_mangle: Some(no_mangle), hir_id: Some(hir_id), - no_mangle_attr: Some(no_mangle_attr), + no_mangle_attr: Some(_), } = self { tcx.emit_node_span_lint( @@ -848,7 +774,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> { no_mangle, errors::MixedExportNameAndNoMangle { no_mangle, - no_mangle_attr: rustc_hir_pretty::attribute_to_string(&tcx, no_mangle_attr), + no_mangle_attr: "#[unsafe(no_mangle)]".to_string(), export_name, removal_span: no_mangle, }, @@ -880,7 +806,7 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { _ => { //FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute //branch above. - span_bug!(attrs[1].span, "cg_ssa: rustc_autodiff should only exist once per source"); + span_bug!(attrs[1].span(), "cg_ssa: rustc_autodiff should only exist once per source"); } }; @@ -892,12 +818,12 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { } let [mode, input_activities @ .., ret_activity] = &list[..] else { - span_bug!(attr.span, "rustc_autodiff attribute must contain mode and activities"); + span_bug!(attr.span(), "rustc_autodiff attribute must contain mode and activities"); }; - let mode = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = mode { + let mode = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = mode { p1.segments.first().unwrap().ident } else { - span_bug!(attr.span, "rustc_autodiff attribute must contain mode"); + span_bug!(attr.span(), "rustc_autodiff attribute must contain mode"); }; // parse mode @@ -910,10 +836,10 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { }; // First read the ret symbol from the attribute - let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p1, .. }) = ret_activity { + let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity { p1.segments.first().unwrap().ident } else { - span_bug!(attr.span, "rustc_autodiff attribute must contain the return activity"); + span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity"); }; // Then parse it into an actual DiffActivity @@ -924,7 +850,7 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { // Now parse all the intermediate (input) activities let mut arg_activities: Vec = vec![]; for arg in input_activities { - let arg_symbol = if let MetaItemInner::MetaItem(MetaItem { path: ref p2, .. }) = arg { + let arg_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p2, .. }) = arg { match p2.segments.first() { Some(x) => x.ident, None => { @@ -946,15 +872,6 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option { } } - for &input in &arg_activities { - if !valid_input_activity(mode, input) { - span_bug!(attr.span, "Invalid input activity {} for {} mode", input, mode); - } - } - if !valid_ret_activity(mode, ret_activity) { - span_bug!(attr.span, "Invalid return activity {} for {} mode", ret_activity, mode); - } - Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities }) } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 3ddbe4aeeec5d..0b7cad0c2fd8a 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -12,10 +12,9 @@ use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutError; +use rustc_middle::ty::{FloatTy, Ty}; use rustc_span::{Span, Symbol}; -use rustc_type_ir::FloatTy; use crate::assert_module_sources::CguReuse; use crate::back::command::Command; @@ -135,6 +134,110 @@ pub(crate) struct NoSavedObjectFile<'a> { pub cgu_name: &'a str, } +#[derive(Diagnostic)] +#[diag(codegen_ssa_requires_rust_abi, code = E0737)] +pub(crate) struct RequiresRustAbi { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_null_on_export, code = E0648)] +pub(crate) struct NullOnExport { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unsupported_instruction_set, code = E0779)] +pub(crate) struct UnsuportedInstructionSet { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_invalid_instruction_set, code = E0779)] +pub(crate) struct InvalidInstructionSet { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_bare_instruction_set, code = E0778)] +pub(crate) struct BareInstructionSet { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_multiple_instruction_set, code = E0779)] +pub(crate) struct MultipleInstructionSet { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_expected_name_value_pair)] +pub(crate) struct ExpectedNameValuePair { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unexpected_parameter_name)] +pub(crate) struct UnexpectedParameterName { + #[primary_span] + #[label] + pub span: Span, + pub prefix_nops: Symbol, + pub entry_nops: Symbol, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_invalid_literal_value)] +pub(crate) struct InvalidLiteralValue { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_out_of_range_integer)] +pub(crate) struct OutOfRangeInteger { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_expected_one_argument, code = E0534)] +pub(crate) struct ExpectedOneArgument { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_expected_one_argument, code = E0722)] +pub(crate) struct ExpectedOneArgumentOptimize { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_invalid_argument, code = E0535)] +#[help] +pub(crate) struct InvalidArgument { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_invalid_argument, code = E0722)] +pub(crate) struct InvalidArgumentOptimize { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(codegen_ssa_copy_path_buf)] pub(crate) struct CopyPathBuf { @@ -161,7 +264,7 @@ impl<'a> CopyPath<'a> { struct DebugArgPath<'a>(pub &'a Path); impl IntoDiagArg for DebugArgPath<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { DiagArgValue::Str(Cow::Owned(format!("{:?}", self.0))) } } @@ -957,6 +1060,7 @@ pub enum InvalidMonomorphization<'tcx> { }, #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = E0511)] + #[note] MaskType { #[primary_span] span: Span, @@ -1087,7 +1191,7 @@ pub enum ExpectedPointerMutability { } impl IntoDiagArg for ExpectedPointerMutability { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { match self { ExpectedPointerMutability::Mut => DiagArgValue::Str(Cow::Borrowed("*mut")), ExpectedPointerMutability::Not => DiagArgValue::Str(Cow::Borrowed("*_")), @@ -1180,6 +1284,8 @@ pub(crate) struct ErrorCreatingRemarkDir { pub struct CompilerBuiltinsCannotCall { pub caller: String, pub callee: String, + #[primary_span] + pub span: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9d2ac219d592c..44b8cc459cf72 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -2,6 +2,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -14,7 +15,6 @@ #![feature(rustdoc_internals)] #![feature(trait_alias)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end //! This crate contains codegen code that is used by all codegen backends (LLVM and others). @@ -75,9 +75,29 @@ pub struct ModuleCodegen { pub name: String, pub module_llvm: M, pub kind: ModuleKind, + /// Saving the ThinLTO buffer for embedding in the object file. + pub thin_lto_buffer: Option>, } impl ModuleCodegen { + pub fn new_regular(name: impl Into, module: M) -> Self { + Self { + name: name.into(), + module_llvm: module, + kind: ModuleKind::Regular, + thin_lto_buffer: None, + } + } + + pub fn new_allocator(name: impl Into, module: M) -> Self { + Self { + name: name.into(), + module_llvm: module, + kind: ModuleKind::Allocator, + thin_lto_buffer: None, + } + } + pub fn into_compiled_module( self, emit_obj: bool, diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index 23baab3124ec6..99f35b7920864 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -205,7 +205,12 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {} PlaceContext::NonMutatingUse( - NonMutatingUseContext::Copy | NonMutatingUseContext::Move, + NonMutatingUseContext::Copy + | NonMutatingUseContext::Move + // Inspect covers things like `PtrMetadata` and `Discriminant` + // which we can treat similar to `Copy` use for the purpose of + // whether we can use SSA variables for things. + | NonMutatingUseContext::Inspect, ) => match &mut self.locals[local] { LocalKind::ZST => {} LocalKind::Memory => {} @@ -229,8 +234,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> Visitor<'tcx> for LocalAnalyzer | MutatingUseContext::Projection, ) | PlaceContext::NonMutatingUse( - NonMutatingUseContext::Inspect - | NonMutatingUseContext::SharedBorrow + NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow | NonMutatingUseContext::RawBorrow | NonMutatingUseContext::Projection, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 49074996174a7..6d1930a402d37 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -3,6 +3,7 @@ use std::cmp; use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, WrappingRange}; use rustc_ast as ast; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_data_structures::packed::Pu128; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::{self, AssertKind, InlineAsmMacro, SwitchTargets, UnwindTerminateReason}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; @@ -165,9 +166,13 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { if let Some(instance) = instance { if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) { if destination.is_some() { - let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id())); - let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())); - tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee }); + let caller_def = fx.instance.def_id(); + let e = CompilerBuiltinsCannotCall { + span: tcx.def_span(caller_def), + caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)), + callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())), + }; + tcx.dcx().emit_err(e); } else { info!( "compiler_builtins call to diverging function {:?} replaced with abort", @@ -402,6 +407,39 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let cmp = bx.icmp(IntPredicate::IntEQ, discr_value, llval); bx.cond_br_with_expect(cmp, lltarget, llotherwise, expect); } + } else if target_iter.len() == 2 + && self.mir[targets.otherwise()].is_empty_unreachable() + && targets.all_values().contains(&Pu128(0)) + && targets.all_values().contains(&Pu128(1)) + { + // This is the really common case for `bool`, `Option`, etc. + // By using `trunc nuw` we communicate that other values are + // impossible without needing `switch` or `assume`s. + let true_bb = targets.target_for_value(1); + let false_bb = targets.target_for_value(0); + let true_ll = helper.llbb_with_cleanup(self, true_bb); + let false_ll = helper.llbb_with_cleanup(self, false_bb); + + let expected_cond_value = if self.cx.sess().opts.optimize == OptLevel::No { + None + } else { + match (self.cold_blocks[true_bb], self.cold_blocks[false_bb]) { + // Same coldness, no expectation + (true, true) | (false, false) => None, + // Different coldness, expect the non-cold one + (true, false) => Some(false), + (false, true) => Some(true), + } + }; + + let bool_ty = bx.tcx().types.bool; + let cond = if switch_ty == bool_ty { + discr_value + } else { + let bool_llty = bx.immediate_backend_type(bx.layout_of(bool_ty)); + bx.unchecked_utrunc(discr_value, bool_llty) + }; + bx.cond_br_with_expect(cond, true_ll, false_ll, expected_cond_value); } else if self.cx.sess().opts.optimize == OptLevel::No && target_iter.len() == 2 && self.mir[targets.otherwise()].is_empty_unreachable() @@ -720,14 +758,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Put together the arguments to the panic entry point. let (lang_item, args) = match msg { - AssertKind::BoundsCheck { ref len, ref index } => { + AssertKind::BoundsCheck { len, index } => { let len = self.codegen_operand(bx, len).immediate(); let index = self.codegen_operand(bx, index).immediate(); // It's `fn panic_bounds_check(index: usize, len: usize)`, // and `#[track_caller]` adds an implicit third argument. (LangItem::PanicBoundsCheck, vec![index, len, location]) } - AssertKind::MisalignedPointerDereference { ref required, ref found } => { + AssertKind::MisalignedPointerDereference { required, found } => { let required = self.codegen_operand(bx, required).immediate(); let found = self.codegen_operand(bx, found).immediate(); // It's `fn panic_misaligned_pointer_dereference(required: usize, found: usize)`, @@ -1003,8 +1041,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let destination = target.map(|target| (return_dest, target)); // Split the rust-call tupled arguments off. - let (first_args, untuple) = if abi == ExternAbi::RustCall && !args.is_empty() { - let (tup, args) = args.split_last().unwrap(); + let (first_args, untuple) = if abi == ExternAbi::RustCall + && let Some((tup, args)) = args.split_last() + { (args, Some(tup)) } else { (args, None) diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index eafc551501c13..68a56044a07c1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Const::Ty(_, c) => match c.kind() { // A constant that came from a const generic but was then used as an argument to // old-style simd_shuffle (passing as argument instead of as a generic param). - rustc_type_ir::ConstKind::Value(cv) => return Ok(Ok(cv.valtree)), + ty::ConstKind::Value(cv) => return Ok(Ok(cv.valtree)), other => span_bug!(constant.span, "{other:#?}"), }, // We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index b34e966ba6ce6..63025a4574fca 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -62,7 +62,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let callee_ty = instance.ty(bx.tcx(), bx.typing_env()); let ty::FnDef(def_id, fn_args) = *callee_ty.kind() else { - bug!("expected fn item type, found {}", callee_ty); + span_bug!(span, "expected fn item type, found {}", callee_ty); }; let sig = callee_ty.fn_sig(bx.tcx()); @@ -325,14 +325,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - sym::discriminant_value => { - if ret_ty.is_integral() { - args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty) - } else { - span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) - } - } - // This requires that atomic intrinsics follow a specific naming pattern: // "atomic_[_]" name if let Some(atomic) = name_str.strip_prefix("atomic_") => { @@ -441,6 +433,40 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // These are all AtomicRMW ops + "max" | "min" => { + let atom_op = if instruction == "max" { + AtomicRmwBinOp::AtomicMax + } else { + AtomicRmwBinOp::AtomicMin + }; + + let ty = fn_args.type_at(0); + if matches!(ty.kind(), ty::Int(_)) { + let ptr = args[0].immediate(); + let val = args[1].immediate(); + bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) + } else { + invalid_monomorphization(ty); + return Ok(()); + } + } + "umax" | "umin" => { + let atom_op = if instruction == "umax" { + AtomicRmwBinOp::AtomicUMax + } else { + AtomicRmwBinOp::AtomicUMin + }; + + let ty = fn_args.type_at(0); + if matches!(ty.kind(), ty::Uint(_)) { + let ptr = args[0].immediate(); + let val = args[1].immediate(); + bx.atomic_rmw(atom_op, ptr, val, parse_ordering(bx, ordering)) + } else { + invalid_monomorphization(ty); + return Ok(()); + } + } op => { let atom_op = match op { "xchg" => AtomicRmwBinOp::AtomicXchg, @@ -450,10 +476,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { "nand" => AtomicRmwBinOp::AtomicNand, "or" => AtomicRmwBinOp::AtomicOr, "xor" => AtomicRmwBinOp::AtomicXor, - "max" => AtomicRmwBinOp::AtomicMax, - "min" => AtomicRmwBinOp::AtomicMin, - "umax" => AtomicRmwBinOp::AtomicUMax, - "umin" => AtomicRmwBinOp::AtomicUMin, _ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOperation), }; diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index ba28720afecdd..0758e5d045673 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -3,7 +3,7 @@ use std::iter; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::{UnwindTerminateReason, traversal}; +use rustc_middle::mir::{Local, UnwindTerminateReason, traversal}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_middle::{bug, mir, span_bug}; @@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let local_values = { let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals); - let mut allocate_local = |local| { + let mut allocate_local = |local: Local| { let decl = &mir.local_decls[local]; let layout = start_bx.layout_of(fx.monomorphize(decl.ty)); assert!(!layout.ty.has_erasable_regions()); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index eb0711dbb32ff..bc9cde1b2a15f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::{Instance, Ty, TyCtxt}; use rustc_middle::{bug, span_bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::WasmCAbi; +use rustc_target::spec::{BinaryFormat, WasmCAbi}; use crate::common; use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; @@ -104,27 +104,6 @@ fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -enum AsmBinaryFormat { - Elf, - Macho, - Coff, - Wasm, -} - -impl AsmBinaryFormat { - fn from_target(target: &rustc_target::spec::Target) -> Self { - if target.is_like_windows { - Self::Coff - } else if target.is_like_osx { - Self::Macho - } else if target.is_like_wasm { - Self::Wasm - } else { - Self::Elf - } - } -} - fn prefix_and_suffix<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, @@ -134,7 +113,7 @@ fn prefix_and_suffix<'tcx>( ) -> (String, String) { use std::fmt::Write; - let asm_binary_format = AsmBinaryFormat::from_target(&tcx.sess.target); + let asm_binary_format = &tcx.sess.target.binary_format; let is_arm = tcx.sess.target.arch == "arm"; let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); @@ -146,7 +125,8 @@ fn prefix_and_suffix<'tcx>( // the alignment from a `#[repr(align())]` is used if it specifies a higher alignment. // if no alignment is specified, an alignment of 4 bytes is used. let min_function_alignment = tcx.sess.opts.unstable_opts.min_function_alignment; - let align = Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4); + let align_bytes = + Ord::max(min_function_alignment, attrs.alignment).map(|a| a.bytes()).unwrap_or(4); // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`. let (arch_prefix, arch_suffix) = if is_arm { @@ -178,10 +158,17 @@ fn prefix_and_suffix<'tcx>( } Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => { match asm_binary_format { - AsmBinaryFormat::Elf | AsmBinaryFormat::Coff | AsmBinaryFormat::Wasm => { + BinaryFormat::Elf | BinaryFormat::Coff | BinaryFormat::Wasm => { writeln!(w, ".weak {asm_name}")?; } - AsmBinaryFormat::Macho => { + BinaryFormat::Xcoff => { + // FIXME: there is currently no way of defining a weak symbol in inline assembly + // for AIX. See https://github.com/llvm/llvm-project/issues/130269 + emit_fatal( + "cannot create weak symbols from inline assembly for this target", + ) + } + BinaryFormat::MachO => { writeln!(w, ".globl {asm_name}")?; writeln!(w, ".weak_definition {asm_name}")?; } @@ -207,7 +194,7 @@ fn prefix_and_suffix<'tcx>( let mut begin = String::new(); let mut end = String::new(); match asm_binary_format { - AsmBinaryFormat::Elf => { + BinaryFormat::Elf => { let section = link_section.unwrap_or(format!(".text.{asm_name}")); let progbits = match is_arm { @@ -221,7 +208,7 @@ fn prefix_and_suffix<'tcx>( }; writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); - writeln!(begin, ".balign {align}").unwrap(); + writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); if let Visibility::Hidden = item_data.visibility { writeln!(begin, ".hidden {asm_name}").unwrap(); @@ -239,10 +226,10 @@ fn prefix_and_suffix<'tcx>( writeln!(end, "{}", arch_suffix).unwrap(); } } - AsmBinaryFormat::Macho => { + BinaryFormat::MachO => { let section = link_section.unwrap_or("__TEXT,__text".to_string()); writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap(); - writeln!(begin, ".balign {align}").unwrap(); + writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); if let Visibility::Hidden = item_data.visibility { writeln!(begin, ".private_extern {asm_name}").unwrap(); @@ -255,15 +242,15 @@ fn prefix_and_suffix<'tcx>( writeln!(end, "{}", arch_suffix).unwrap(); } } - AsmBinaryFormat::Coff => { + BinaryFormat::Coff => { let section = link_section.unwrap_or(format!(".text.{asm_name}")); writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); - writeln!(begin, ".balign {align}").unwrap(); + writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); writeln!(begin, ".def {asm_name}").unwrap(); writeln!(begin, ".scl 2").unwrap(); writeln!(begin, ".type 32").unwrap(); - writeln!(begin, ".endef {asm_name}").unwrap(); + writeln!(begin, ".endef").unwrap(); writeln!(begin, "{asm_name}:").unwrap(); writeln!(end).unwrap(); @@ -272,7 +259,7 @@ fn prefix_and_suffix<'tcx>( writeln!(end, "{}", arch_suffix).unwrap(); } } - AsmBinaryFormat::Wasm => { + BinaryFormat::Wasm => { let section = link_section.unwrap_or(format!(".text.{asm_name}")); writeln!(begin, ".section {section},\"\",@").unwrap(); @@ -297,6 +284,33 @@ fn prefix_and_suffix<'tcx>( // .size is ignored for function symbols, so we can skip it writeln!(end, "end_function").unwrap(); } + BinaryFormat::Xcoff => { + // the LLVM XCOFFAsmParser is extremely incomplete and does not implement many of the + // documented directives. + // + // - https://github.com/llvm/llvm-project/blob/1b25c0c4da968fe78921ce77736e5baef4db75e3/llvm/lib/MC/MCParser/XCOFFAsmParser.cpp + // - https://www.ibm.com/docs/en/ssw_aix_71/assembler/assembler_pdf.pdf + // + // Consequently, we try our best here but cannot do as good a job as for other binary + // formats. + + // FIXME: start a section. `.csect` is not currently implemented in LLVM + + // fun fact: according to the assembler documentation, .align takes an exponent, + // but LLVM only accepts powers of 2 (but does emit the exponent) + // so when we hand `.align 32` to LLVM, the assembly output will contain `.align 5` + writeln!(begin, ".align {}", align_bytes).unwrap(); + + write_linkage(&mut begin).unwrap(); + if let Visibility::Hidden = item_data.visibility { + // FIXME apparently `.globl {asm_name}, hidden` is valid + // but due to limitations with `.weak` (see above) we can't really use that in general yet + } + writeln!(begin, "{asm_name}:").unwrap(); + + writeln!(end).unwrap(); + // FIXME: end the section? + } } (begin, end) @@ -367,7 +381,7 @@ fn wasm_type<'tcx>( PassMode::Direct(_) => { let direct_type = match arg_abi.layout.backend_repr { BackendRepr::Scalar(scalar) => wasm_primitive(scalar.primitive(), ptr_type), - BackendRepr::Vector { .. } => "v128", + BackendRepr::SimdVector { .. } => "v128", BackendRepr::Memory { .. } => { // FIXME: remove this branch once the wasm32-unknown-unknown ABI is fixed let _ = WasmCAbi::Legacy; diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index e7e4dfa05d0c0..7e355b6406aed 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -3,16 +3,17 @@ use std::fmt; use arrayvec::ArrayVec; use either::Either; use rustc_abi as abi; -use rustc_abi::{Align, BackendRepr, Size}; +use rustc_abi::{Align, BackendRepr, FIRST_VARIANT, Primitive, Size, TagEncoding, Variants}; use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range}; use rustc_middle::mir::{self, ConstValue}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, span_bug}; -use tracing::debug; +use tracing::{debug, instrument}; use super::place::{PlaceRef, PlaceValue}; use super::{FunctionCx, LocalRef}; +use crate::common::IntPredicate; use crate::traits::*; use crate::{MemFlags, size_of_val}; @@ -203,30 +204,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let alloc_align = alloc.inner().align; assert!(alloc_align >= layout.align.abi); - // Returns `None` when the value is partially undefined or any byte of it has provenance. - // Otherwise returns the value or (if the entire value is undef) returns an undef. let read_scalar = |start, size, s: abi::Scalar, ty| { - let range = alloc_range(start, size); match alloc.0.read_scalar( bx, - range, + alloc_range(start, size), /*read_provenance*/ matches!(s.primitive(), abi::Primitive::Pointer(_)), ) { - Ok(val) => Some(bx.scalar_to_backend(val, s, ty)), - Err(_) => { - // We may have failed due to partial provenance or unexpected provenance, - // continue down the normal code path if so. - if alloc.0.provenance().range_empty(range, &bx.tcx()) - // Since `read_scalar` failed, but there were no relocations involved, the - // bytes must be partially or fully uninitialized. Thus we can now unwrap the - // information about the range of uninit bytes and check if it's the full range. - && alloc.0.init_mask().is_range_initialized(range).unwrap_err() == range - { - Some(bx.const_undef(ty)) - } else { - None - } - } + Ok(val) => bx.scalar_to_backend(val, s, ty), + Err(_) => bx.const_poison(ty), } }; @@ -237,14 +222,16 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). match layout.backend_repr { - BackendRepr::Scalar(s) => { + BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => { let size = s.size(bx); assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); - if let Some(val) = read_scalar(offset, size, s, bx.immediate_backend_type(layout)) { - return OperandRef { val: OperandValue::Immediate(val), layout }; - } + let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); + OperandRef { val: OperandValue::Immediate(val), layout } } - BackendRepr::ScalarPair(a, b) => { + BackendRepr::ScalarPair( + a @ abi::Scalar::Initialized { .. }, + b @ abi::Scalar::Initialized { .. }, + ) => { let (a_size, b_size) = (a.size(bx), b.size(bx)); let b_offset = (offset + a_size).align_to(b.align(bx).abi); assert!(b_offset.bytes() > 0); @@ -260,21 +247,20 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { b, bx.scalar_pair_element_backend_type(layout, 1, true), ); - if let (Some(a_val), Some(b_val)) = (a_val, b_val) { - return OperandRef { val: OperandValue::Pair(a_val, b_val), layout }; - } + OperandRef { val: OperandValue::Pair(a_val, b_val), layout } + } + _ if layout.is_zst() => OperandRef::zero_sized(layout), + _ => { + // Neither a scalar nor scalar pair. Load from a place + // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the + // same `ConstAllocation`? + let init = bx.const_data_from_alloc(alloc); + let base_addr = bx.static_addr_of(init, alloc_align, None); + + let llval = bx.const_ptr_byte_offset(base_addr, offset); + bx.load_operand(PlaceRef::new_sized(llval, layout)) } - _ if layout.is_zst() => return OperandRef::zero_sized(layout), - _ => {} } - // Neither a scalar nor scalar pair. Load from a place - // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the - // same `ConstAllocation`? - let init = bx.const_data_from_alloc(alloc); - let base_addr = bx.static_addr_of(init, alloc_align, None); - - let llval = bx.const_ptr_byte_offset(base_addr, offset); - bx.load_operand(PlaceRef::new_sized(llval, layout)) } /// Asserts that this operand refers to a scalar and returns @@ -359,7 +345,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let offset = self.layout.fields.offset(i); if !bx.is_backend_ref(self.layout) && bx.is_backend_ref(field) { - if let BackendRepr::Vector { count, .. } = self.layout.backend_repr + if let BackendRepr::SimdVector { count, .. } = self.layout.backend_repr && let BackendRepr::Memory { sized: true } = field.backend_repr && count.is_power_of_two() { @@ -404,7 +390,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } }; OperandValue::Immediate(match field.backend_repr { - BackendRepr::Vector { .. } => imm, + BackendRepr::SimdVector { .. } => imm, BackendRepr::Scalar(out_scalar) => { let Some(in_scalar) = in_scalar else { span_bug!( @@ -430,6 +416,149 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { OperandRef { val, layout: field } } + + /// Obtain the actual discriminant of a value. + #[instrument(level = "trace", skip(fx, bx))] + pub fn codegen_get_discr>( + self, + fx: &mut FunctionCx<'a, 'tcx, Bx>, + bx: &mut Bx, + cast_to: Ty<'tcx>, + ) -> V { + let dl = &bx.tcx().data_layout; + let cast_to_layout = bx.cx().layout_of(cast_to); + let cast_to = bx.cx().immediate_backend_type(cast_to_layout); + + // We check uninhabitedness separately because a type like + // `enum Foo { Bar(i32, !) }` is still reported as `Variants::Single`, + // *not* as `Variants::Empty`. + if self.layout.is_uninhabited() { + return bx.cx().const_poison(cast_to); + } + + let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { + Variants::Empty => unreachable!("we already handled uninhabited types"), + Variants::Single { index } => { + let discr_val = + if let Some(discr) = self.layout.ty.discriminant_for_variant(bx.tcx(), index) { + discr.val + } else { + // This arm is for types which are neither enums nor coroutines, + // and thus for which the only possible "variant" should be the first one. + assert_eq!(index, FIRST_VARIANT); + // There's thus no actual discriminant to return, so we return + // what it would have been if this was a single-variant enum. + 0 + }; + return bx.cx().const_uint_big(cast_to, discr_val); + } + Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { + (tag, tag_encoding, tag_field) + } + }; + + // Read the tag/niche-encoded discriminant from memory. + let tag_op = match self.val { + OperandValue::ZeroSized => bug!(), + OperandValue::Immediate(_) | OperandValue::Pair(_, _) => { + self.extract_field(fx, bx, tag_field) + } + OperandValue::Ref(place) => { + let tag = place.with_type(self.layout).project_field(bx, tag_field); + bx.load_operand(tag) + } + }; + let tag_imm = tag_op.immediate(); + + // Decode the discriminant (specifically if it's niche-encoded). + match *tag_encoding { + TagEncoding::Direct => { + let signed = match tag_scalar.primitive() { + // We use `i1` for bytes that are always `0` or `1`, + // e.g., `#[repr(i8)] enum E { A, B }`, but we can't + // let LLVM interpret the `i1` as signed, because + // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`. + Primitive::Int(_, signed) => !tag_scalar.is_bool() && signed, + _ => false, + }; + bx.intcast(tag_imm, cast_to, signed) + } + TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { + // Cast to an integer so we don't have to treat a pointer as a + // special case. + let (tag, tag_llty) = match tag_scalar.primitive() { + // FIXME(erikdesjardins): handle non-default addrspace ptr sizes + Primitive::Pointer(_) => { + let t = bx.type_from_integer(dl.ptr_sized_integer()); + let tag = bx.ptrtoint(tag_imm, t); + (tag, t) + } + _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), + }; + + let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); + + // We have a subrange `niche_start..=niche_end` inside `range`. + // If the value of the tag is inside this subrange, it's a + // "niche value", an increment of the discriminant. Otherwise it + // indicates the untagged variant. + // A general algorithm to extract the discriminant from the tag + // is: + // relative_tag = tag - niche_start + // is_niche = relative_tag <= (ule) relative_max + // discr = if is_niche { + // cast(relative_tag) + niche_variants.start() + // } else { + // untagged_variant + // } + // However, we will likely be able to emit simpler code. + let (is_niche, tagged_discr, delta) = if relative_max == 0 { + // Best case scenario: only one tagged variant. This will + // likely become just a comparison and a jump. + // The algorithm is: + // is_niche = tag == niche_start + // discr = if is_niche { + // niche_start + // } else { + // untagged_variant + // } + let niche_start = bx.cx().const_uint_big(tag_llty, niche_start); + let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start); + let tagged_discr = + bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); + (is_niche, tagged_discr, 0) + } else { + // The special cases don't apply, so we'll have to go with + // the general algorithm. + let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start)); + let cast_tag = bx.intcast(relative_discr, cast_to, false); + let is_niche = bx.icmp( + IntPredicate::IntULE, + relative_discr, + bx.cx().const_uint(tag_llty, relative_max as u64), + ); + (is_niche, cast_tag, niche_variants.start().as_u32() as u128) + }; + + let tagged_discr = if delta == 0 { + tagged_discr + } else { + bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta)) + }; + + let discr = bx.select( + is_niche, + tagged_discr, + bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64), + ); + + // In principle we could insert assumes on the possible range of `discr`, but + // currently in LLVM this seems to be a pessimization. + + discr + } + } + } } impl<'a, 'tcx, V: CodegenObject> OperandValue { @@ -584,7 +713,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Moves out of scalar and scalar pair fields are trivial. for elem in place_ref.projection.iter() { match elem { - mir::ProjectionElem::Field(ref f, _) => { + mir::ProjectionElem::Field(f, _) => { assert!( !o.layout.ty.is_any_ptr(), "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \ @@ -666,7 +795,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // However, some SIMD types do not actually use the vector ABI // (in particular, packed SIMD types do not). Ensure we exclude those. let layout = bx.layout_of(constant_ty); - if let BackendRepr::Vector { .. } = layout.backend_repr { + if let BackendRepr::SimdVector { .. } = layout.backend_repr { let (llval, ty) = self.immediate_const_vector(bx, constant); return OperandRef { val: OperandValue::Immediate(llval), diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index e32d298869be2..31db7fa9a1888 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -1,8 +1,7 @@ -use rustc_abi::Primitive::{Int, Pointer}; use rustc_abi::{Align, BackendRepr, FieldsShape, Size, TagEncoding, VariantIdx, Variants}; use rustc_middle::mir::PlaceTy; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; use rustc_middle::{bug, mir}; use tracing::{debug, instrument}; @@ -133,7 +132,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { Self::alloca(bx, ptr_layout) } - pub fn len>(&self, cx: &Cx) -> V { + pub fn len>(&self, cx: &Cx) -> V { if let FieldsShape::Array { count, .. } = self.layout.fields { if self.layout.is_unsized() { assert_eq!(count, 0); @@ -168,7 +167,11 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { }; let val = PlaceValue { llval, - llextra: if bx.cx().type_has_metadata(field.ty) { self.val.llextra } else { None }, + llextra: if bx.cx().tcx().type_has_metadata(field.ty, bx.cx().typing_env()) { + self.val.llextra + } else { + None + }, align: effective_field_align, }; val.with_type(field) @@ -229,129 +232,6 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { val.with_type(field) } - /// Obtain the actual discriminant of a value. - #[instrument(level = "trace", skip(bx))] - pub fn codegen_get_discr>( - self, - bx: &mut Bx, - cast_to: Ty<'tcx>, - ) -> V { - let dl = &bx.tcx().data_layout; - let cast_to_layout = bx.cx().layout_of(cast_to); - let cast_to = bx.cx().immediate_backend_type(cast_to_layout); - if self.layout.is_uninhabited() { - return bx.cx().const_poison(cast_to); - } - let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { - Variants::Empty => unreachable!("we already handled uninhabited types"), - Variants::Single { index } => { - let discr_val = self - .layout - .ty - .discriminant_for_variant(bx.cx().tcx(), index) - .map_or(index.as_u32() as u128, |discr| discr.val); - return bx.cx().const_uint_big(cast_to, discr_val); - } - Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { - (tag, tag_encoding, tag_field) - } - }; - - // Read the tag/niche-encoded discriminant from memory. - let tag = self.project_field(bx, tag_field); - let tag_op = bx.load_operand(tag); - let tag_imm = tag_op.immediate(); - - // Decode the discriminant (specifically if it's niche-encoded). - match *tag_encoding { - TagEncoding::Direct => { - let signed = match tag_scalar.primitive() { - // We use `i1` for bytes that are always `0` or `1`, - // e.g., `#[repr(i8)] enum E { A, B }`, but we can't - // let LLVM interpret the `i1` as signed, because - // then `i1 1` (i.e., `E::B`) is effectively `i8 -1`. - Int(_, signed) => !tag_scalar.is_bool() && signed, - _ => false, - }; - bx.intcast(tag_imm, cast_to, signed) - } - TagEncoding::Niche { untagged_variant, ref niche_variants, niche_start } => { - // Cast to an integer so we don't have to treat a pointer as a - // special case. - let (tag, tag_llty) = match tag_scalar.primitive() { - // FIXME(erikdesjardins): handle non-default addrspace ptr sizes - Pointer(_) => { - let t = bx.type_from_integer(dl.ptr_sized_integer()); - let tag = bx.ptrtoint(tag_imm, t); - (tag, t) - } - _ => (tag_imm, bx.cx().immediate_backend_type(tag_op.layout)), - }; - - let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32(); - - // We have a subrange `niche_start..=niche_end` inside `range`. - // If the value of the tag is inside this subrange, it's a - // "niche value", an increment of the discriminant. Otherwise it - // indicates the untagged variant. - // A general algorithm to extract the discriminant from the tag - // is: - // relative_tag = tag - niche_start - // is_niche = relative_tag <= (ule) relative_max - // discr = if is_niche { - // cast(relative_tag) + niche_variants.start() - // } else { - // untagged_variant - // } - // However, we will likely be able to emit simpler code. - let (is_niche, tagged_discr, delta) = if relative_max == 0 { - // Best case scenario: only one tagged variant. This will - // likely become just a comparison and a jump. - // The algorithm is: - // is_niche = tag == niche_start - // discr = if is_niche { - // niche_start - // } else { - // untagged_variant - // } - let niche_start = bx.cx().const_uint_big(tag_llty, niche_start); - let is_niche = bx.icmp(IntPredicate::IntEQ, tag, niche_start); - let tagged_discr = - bx.cx().const_uint(cast_to, niche_variants.start().as_u32() as u64); - (is_niche, tagged_discr, 0) - } else { - // The special cases don't apply, so we'll have to go with - // the general algorithm. - let relative_discr = bx.sub(tag, bx.cx().const_uint_big(tag_llty, niche_start)); - let cast_tag = bx.intcast(relative_discr, cast_to, false); - let is_niche = bx.icmp( - IntPredicate::IntULE, - relative_discr, - bx.cx().const_uint(tag_llty, relative_max as u64), - ); - (is_niche, cast_tag, niche_variants.start().as_u32() as u128) - }; - - let tagged_discr = if delta == 0 { - tagged_discr - } else { - bx.add(tagged_discr, bx.cx().const_uint_big(cast_to, delta)) - }; - - let discr = bx.select( - is_niche, - tagged_discr, - bx.cx().const_uint(cast_to, untagged_variant.as_u32() as u64), - ); - - // In principle we could insert assumes on the possible range of `discr`, but - // currently in LLVM this seems to be a pessimization. - - discr - } - } - } - /// Sets the discriminant for a new value of the given case of the given /// representation. pub fn codegen_set_discr>( @@ -423,7 +303,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { layout.size }; - let llval = bx.inbounds_gep(bx.cx().backend_type(layout), self.val.llval, &[llindex]); + let llval = bx.inbounds_nuw_gep(bx.cx().backend_type(layout), self.val.llval, &[llindex]); let align = self.val.align.restrict_for_offset(offset); PlaceValue::new_sized(llval, align).with_type(layout) } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index daa4fa90ed704..96be44ee09ff1 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -3,12 +3,12 @@ use std::assert_matches::assert_matches; use arrayvec::ArrayVec; use rustc_abi::{self as abi, FIRST_VARIANT, FieldIdx}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, Span}; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument}; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -93,8 +93,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - // If `v` is an integer constant whose value is just a single byte repeated N times, - // emit a `memset` filling the entire `dest` with that byte. let try_init_all_same = |bx: &mut Bx, v| { let start = dest.val.llval; let size = bx.const_usize(dest.layout.size.bytes()); @@ -119,33 +117,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { false }; - trace!(?cg_elem.val); match cg_elem.val { OperandValue::Immediate(v) => { if try_init_all_same(bx, v) { return; } } - OperandValue::Pair(a, b) => { - let a_is_undef = bx.cx().is_undef(a); - match (a_is_undef, bx.cx().is_undef(b)) { - // Can happen for uninit unions - (true, true) => { - // FIXME: can we produce better output here? - } - (false, true) | (true, false) => { - let val = if a_is_undef { b } else { a }; - if try_init_all_same(bx, val) { - return; - } - } - (false, false) => { - // FIXME: if both are the same value, use try_init_all_same - } - } - } - OperandValue::ZeroSized => unreachable!("checked above"), - OperandValue::Ref(..) => {} + _ => (), } let count = self @@ -386,6 +364,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { ) -> Bx::Value { assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx)); + // While optimizations will remove no-op transmutes, they might still be + // there in debug or things that aren't no-op in MIR because they change + // the Rust type but not the underlying layout/niche. + if from_scalar == to_scalar && from_backend_ty == to_backend_ty { + return imm; + } + use abi::Primitive::*; imm = bx.from_immediate(imm); @@ -666,9 +651,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { lhs.layout.ty, ), - (OperandValue::Immediate(lhs_val), OperandValue::Immediate(rhs_val)) => { - self.codegen_scalar_binop(bx, op, lhs_val, rhs_val, lhs.layout.ty) - } + (OperandValue::Immediate(lhs_val), OperandValue::Immediate(rhs_val)) => self + .codegen_scalar_binop( + bx, + op, + lhs_val, + rhs_val, + lhs.layout.ty, + rhs.layout.ty, + ), _ => bug!(), }; @@ -715,7 +706,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Discriminant(ref place) => { let discr_ty = rvalue.ty(self.mir, bx.tcx()); let discr_ty = self.monomorphize(discr_ty); - let discr = self.codegen_place(bx, place.as_ref()).codegen_get_discr(bx, discr_ty); + let operand = self.codegen_consume(bx, place.as_ref()); + let discr = operand.codegen_get_discr(self, bx, discr_ty); OperandRef { val: OperandValue::Immediate(discr), layout: self.cx.layout_of(discr_ty), @@ -872,7 +864,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = cg_place.layout.ty; assert!( - if bx.cx().type_has_metadata(ty) { + if bx.cx().tcx().type_has_metadata(ty, bx.cx().typing_env()) { matches!(val, OperandValue::Pair(..)) } else { matches!(val, OperandValue::Immediate(..)) @@ -889,10 +881,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { op: mir::BinOp, lhs: Bx::Value, rhs: Bx::Value, - input_ty: Ty<'tcx>, + lhs_ty: Ty<'tcx>, + rhs_ty: Ty<'tcx>, ) -> Bx::Value { - let is_float = input_ty.is_floating_point(); - let is_signed = input_ty.is_signed(); + let is_float = lhs_ty.is_floating_point(); + let is_signed = lhs_ty.is_signed(); match op { mir::BinOp::Add => { if is_float { @@ -958,9 +951,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::BinOp::BitAnd => bx.and(lhs, rhs), mir::BinOp::BitXor => bx.xor(lhs, rhs), mir::BinOp::Offset => { - let pointee_type = input_ty + let pointee_type = lhs_ty .builtin_deref(true) - .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty)); + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", lhs_ty)); let pointee_layout = bx.cx().layout_of(pointee_type); if pointee_layout.is_zst() { // `Offset` works in terms of the size of pointee, @@ -968,7 +961,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { lhs } else { let llty = bx.cx().backend_type(pointee_layout); - bx.inbounds_gep(llty, lhs, &[rhs]) + if !rhs_ty.is_signed() { + bx.inbounds_nuw_gep(llty, lhs, &[rhs]) + } else { + bx.inbounds_gep(llty, lhs, &[rhs]) + } } } mir::BinOp::Shl | mir::BinOp::ShlUnchecked => { @@ -1179,7 +1176,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { assert!(!self.cx.is_backend_scalar_pair(layout)); OperandValueKind::Immediate(match layout.backend_repr { abi::BackendRepr::Scalar(s) => s, - abi::BackendRepr::Vector { element, .. } => element, + abi::BackendRepr::SimdVector { element, .. } => element, x => span_bug!(self.mir.span, "Couldn't translate {x:?} as backend immediate"), }) } else if self.cx.is_backend_scalar_pair(layout) { diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 5f95b6615bd30..f6af889fd6ecb 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -36,7 +36,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { } MonoItem::GlobalAsm(item_id) => { let item = cx.tcx().hir_item(item_id); - if let hir::ItemKind::GlobalAsm(asm) = item.kind { + if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind { let operands: Vec<_> = asm .operands .iter() @@ -71,11 +71,8 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { } } } - hir::InlineAsmOperand::SymFn { ref anon_const } => { - let ty = cx - .tcx() - .typeck_body(anon_const.body) - .node_type(anon_const.hir_id); + hir::InlineAsmOperand::SymFn { expr } => { + let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { &ty::FnDef(def_id, args) => Instance::new(def_id, args), _ => span_bug!(*op_sp, "asm sym is not a function"), diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index d8b9bdb55da69..8058cd1b1783a 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -10,7 +10,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; -use rustc_target::target_features; +use rustc_target::target_features::{self, Stability}; use crate::errors; @@ -87,12 +87,17 @@ pub(crate) fn from_target_feature_attr( // But ensure the ABI does not forbid enabling this. // Here we do assume that LLVM doesn't add even more implied features // we don't know about, at least no features that would have ABI effects! - if abi_feature_constraints.incompatible.contains(&name.as_str()) { - tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { - span: item.span(), - feature: name.as_str(), - reason: "this feature is incompatible with the target ABI", - }); + // We skip this logic in rustdoc, where we want to allow all target features of + // all targets, so we can't check their ABI compatibility and anyway we are not + // generating code so "it's fine". + if !tcx.sess.opts.actually_rustdoc { + if abi_feature_constraints.incompatible.contains(&name.as_str()) { + tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { + span: item.span(), + feature: name.as_str(), + reason: "this feature is incompatible with the target ABI", + }); + } } target_features.push(TargetFeature { name, implied: name != feature_sym }) } @@ -142,11 +147,38 @@ pub(crate) fn provide(providers: &mut Providers) { rust_target_features: |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); if tcx.sess.opts.actually_rustdoc { - // rustdoc needs to be able to document functions that use all the features, so - // whitelist them all - rustc_target::target_features::all_rust_features() - .map(|(a, b)| (a.to_string(), b)) - .collect() + // HACK: rustdoc would like to pretend that we have all the target features, so we + // have to merge all the lists into one. To ensure an unstable target never prevents + // a stable one from working, we merge the stability info of all instances of the + // same target feature name, with the "most stable" taking precedence. And then we + // hope that this doesn't cause issues anywhere else in the compiler... + let mut result: UnordMap = Default::default(); + for (name, stability) in rustc_target::target_features::all_rust_features() { + use std::collections::hash_map::Entry; + match result.entry(name.to_owned()) { + Entry::Vacant(vacant_entry) => { + vacant_entry.insert(stability); + } + Entry::Occupied(mut occupied_entry) => { + // Merge the two stabilities, "more stable" taking precedence. + match (occupied_entry.get(), stability) { + (Stability::Stable, _) + | ( + Stability::Unstable { .. }, + Stability::Unstable { .. } | Stability::Forbidden { .. }, + ) + | (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => { + // The stability in the entry is at least as good as the new one, just keep it. + } + _ => { + // Overwrite stabilite. + occupied_entry.insert(stability); + } + } + } + } + } + result } else { tcx.sess .target @@ -158,7 +190,7 @@ pub(crate) fn provide(providers: &mut Providers) { }, implied_target_features: |tcx, feature: Symbol| { let feature = feature.as_str(); - UnordSet::from(tcx.sess.target.implied_target_features(std::iter::once(feature))) + UnordSet::from(tcx.sess.target.implied_target_features(feature)) .into_sorted_stable_ord() .into_iter() .map(|s| Symbol::intern(s)) diff --git a/compiler/rustc_codegen_ssa/src/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs index 60d8f2a9ece48..49c51caa996e4 100644 --- a/compiler/rustc_codegen_ssa/src/traits/abi.rs +++ b/compiler/rustc_codegen_ssa/src/traits/abi.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -pub trait AbiBuilderMethods<'tcx>: BackendTypes { +pub trait AbiBuilderMethods: BackendTypes { fn get_param(&mut self, index: usize) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index ebcf118b90380..65fd843e7a59e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -45,10 +45,13 @@ pub trait CodegenBackend { fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} - /// Returns the features that should be set in `cfg(target_features)`. + /// Returns two feature sets: + /// - The first has the features that should be set in `cfg(target_features)`. + /// - The second is like the first, but also includes unstable features. + /// /// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen. - fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec { - vec![] + fn target_features_cfg(&self, _sess: &Session) -> (Vec, Vec) { + (vec![], vec![]) } fn print_passes(&self) {} diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 2b00ba01946e5..5f91133d5b47e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -40,7 +40,7 @@ pub trait BuilderMethods<'a, 'tcx>: + CoverageInfoBuilderMethods<'tcx> + DebugInfoBuilderMethods + ArgAbiBuilderMethods<'tcx> - + AbiBuilderMethods<'tcx> + + AbiBuilderMethods + IntrinsicCallBuilderMethods<'tcx> + AsmBuilderMethods<'tcx> + StaticBuilderMethods @@ -325,6 +325,14 @@ pub trait BuilderMethods<'a, 'tcx>: ptr: Self::Value, indices: &[Self::Value], ) -> Self::Value; + fn inbounds_nuw_gep( + &mut self, + ty: Self::Type, + ptr: Self::Value, + indices: &[Self::Value], + ) -> Self::Value { + self.inbounds_gep(ty, ptr, indices) + } fn ptradd(&mut self, ptr: Self::Value, offset: Self::Value) -> Self::Value { self.gep(self.cx().type_i8(), ptr, &[offset]) } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 5cfb56ebacee8..d83a04d814be3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -3,13 +3,12 @@ use rustc_middle::mir::interpret::{ConstAllocation, Scalar}; use super::BackendTypes; -pub trait ConstCodegenMethods<'tcx>: BackendTypes { +pub trait ConstCodegenMethods: BackendTypes { // Constant constructors fn const_null(&self, t: Self::Type) -> Self::Value; /// Generate an uninitialized value (matching uninitialized memory in MIR). /// Whether memory is initialized or not is tracked byte-for-byte. fn const_undef(&self, t: Self::Type) -> Self::Value; - fn is_undef(&self, v: Self::Value) -> bool; /// Generate a fake value. Poison always affects the entire value, even if just a single byte is /// poison. This can only be used in codepaths that are already UB, i.e., UB-free Rust code /// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a @@ -38,7 +37,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes { fn const_to_opt_uint(&self, v: Self::Value) -> Option; fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; - fn const_data_from_alloc(&self, alloc: ConstAllocation<'tcx>) -> Self::Value; + fn const_data_from_alloc(&self, alloc: ConstAllocation<'_>) -> Self::Value; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 90fcfbe4da7a1..239857a4298df 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -55,7 +55,7 @@ pub trait CodegenObject = Copy + PartialEq + fmt::Debug; pub trait CodegenMethods<'tcx> = LayoutOf<'tcx, LayoutOfResult = TyAndLayout<'tcx>> + FnAbiOf<'tcx, FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>> + TypeCodegenMethods<'tcx> - + ConstCodegenMethods<'tcx> + + ConstCodegenMethods + StaticCodegenMethods + DebugInfoCodegenMethods<'tcx> + AsmCodegenMethods<'tcx> diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index c178ebc596e1e..32d9f27d32d34 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -1,7 +1,7 @@ use rustc_abi::{AddressSpace, Float, Integer, Reg}; use rustc_middle::bug; +use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout}; -use rustc_middle::ty::{self, Ty}; use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi}; use super::BackendTypes; @@ -9,7 +9,7 @@ use super::misc::MiscCodegenMethods; use crate::common::TypeKind; use crate::mir::place::PlaceRef; -pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { +pub trait BaseTypeCodegenMethods: BackendTypes { fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; @@ -41,7 +41,7 @@ pub trait BaseTypeCodegenMethods<'tcx>: BackendTypes { } pub trait DerivedTypeCodegenMethods<'tcx>: - BaseTypeCodegenMethods<'tcx> + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> + BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { fn type_int(&self) -> Self::Type { match &self.sess().target.c_int_width[..] { @@ -84,26 +84,10 @@ pub trait DerivedTypeCodegenMethods<'tcx>: fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { ty.is_freeze(self.tcx(), self.typing_env()) } - - fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { - if ty.is_sized(self.tcx(), self.typing_env()) { - return false; - } - - let tail = self.tcx().struct_tail_for_codegen(ty, self.typing_env()); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } - } } impl<'tcx, T> DerivedTypeCodegenMethods<'tcx> for T where - Self: BaseTypeCodegenMethods<'tcx> - + MiscCodegenMethods<'tcx> - + HasTyCtxt<'tcx> - + HasTypingEnv<'tcx> + Self: BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { } diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index ac916e90ab990..9fa07f352efc5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -40,7 +40,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { unsafe fn optimize( cgcx: &CodegenContext, dcx: DiagCtxtHandle<'_>, - module: &ModuleCodegen, + module: &mut ModuleCodegen, config: &ModuleConfig, ) -> Result<(), FatalError>; fn optimize_fat( diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml index 7717cd2c69664..02be8762d6f85 100644 --- a/compiler/rustc_const_eval/Cargo.toml +++ b/compiler/rustc_const_eval/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_const_eval" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -23,6 +23,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_type_ir = { path = "../rustc_type_ir" } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index eecc6690f5153..ccf9b240d4088 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -109,6 +109,8 @@ const_eval_frame_note_inner = inside {$where_ -> *[other] {""} } +const_eval_frame_note_last = the failure occurred here + const_eval_in_bounds_test = out-of-bounds pointer use const_eval_incompatible_calling_conventions = calling a function with calling convention {$callee_conv} using calling convention {$caller_conv} @@ -300,8 +302,7 @@ const_eval_overflow_arith = const_eval_overflow_shift = overflowing shift by {$shift_amount} in `{$intrinsic}` -const_eval_panic = - the evaluated program panicked at '{$msg}', {$file}:{$line}:{$col} +const_eval_panic = evaluation panicked: {$msg} const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str` diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs index 52e000858b4c7..06ee7075170ff 100644 --- a/compiler/rustc_const_eval/src/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/check_consts/mod.rs @@ -4,12 +4,13 @@ //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when //! it finds operations that are invalid in a certain context. +use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_errors::DiagCtxtHandle; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::ty::{self, PolyFnSig, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::Symbol; -use {rustc_attr_parsing as attr, rustc_hir as hir}; pub use self::qualifs::Qualif; @@ -80,8 +81,9 @@ pub fn rustc_allow_const_fn_unstable( def_id: LocalDefId, feature_gate: Symbol, ) -> bool { - let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); - attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); + + find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate)) } /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable". @@ -92,6 +94,11 @@ pub fn rustc_allow_const_fn_unstable( /// world into two functions: those that are safe to expose on stable (and hence may not use /// unstable features, not even recursively), and those that are not. pub fn is_fn_or_trait_safe_to_expose_on_stable(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + // A default body in a `#[const_trait]` is const-stable when the trait is const-stable. + if tcx.is_const_default_method(def_id) { + return is_fn_or_trait_safe_to_expose_on_stable(tcx, tcx.parent(def_id)); + } + match tcx.lookup_const_stability(def_id) { None => { // In a `staged_api` crate, we do enforce recursive const stability for all unmarked diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index cc21a18af3a09..ffb32fa41eb53 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -48,11 +48,8 @@ impl MachineStopType for ConstEvalErrKind { | ModifiedGlobal | WriteThroughImmutablePointer => {} AssertFailure(kind) => kind.add_args(adder), - Panic { msg, line, col, file } => { - adder("msg".into(), msg.into_diag_arg()); - adder("file".into(), file.into_diag_arg()); - adder("line".into(), line.into_diag_arg()); - adder("col".into(), col.into_diag_arg()); + Panic { msg, .. } => { + adder("msg".into(), msg.into_diag_arg(&mut None)); } } } @@ -72,7 +69,7 @@ pub fn get_span_and_frames<'tcx>( let mut stacktrace = Frame::generate_stacktrace_from_stack(stack); // Filter out `requires_caller_location` frames. stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*tcx)); - let span = stacktrace.first().map(|f| f.span).unwrap_or(tcx.span); + let span = stacktrace.last().map(|f| f.span).unwrap_or(tcx.span); let mut frames = Vec::new(); @@ -115,6 +112,20 @@ pub fn get_span_and_frames<'tcx>( } } + // In `rustc`, we present const-eval errors from the outer-most place first to the inner-most. + // So we reverse the frames here. The first frame will be the same as the span from the current + // `TyCtxtAt<'_>`, so we remove it as it would be redundant. + frames.reverse(); + if frames.len() > 0 { + frames.remove(0); + } + if let Some(last) = frames.last_mut() + // If the span is not going to be printed, we don't want the span label for `is_last`. + && tcx.sess.source_map().span_to_snippet(last.span.source_callsite()).is_ok() + { + last.has_label = true; + } + (span, frames) } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 82e0a6e6666f3..4db862afd9f6d 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -502,12 +502,10 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { RemainderByZero(op) => RemainderByZero(eval_to_int(op)?), ResumedAfterReturn(coroutine_kind) => ResumedAfterReturn(*coroutine_kind), ResumedAfterPanic(coroutine_kind) => ResumedAfterPanic(*coroutine_kind), - MisalignedPointerDereference { ref required, ref found } => { - MisalignedPointerDereference { - required: eval_to_int(required)?, - found: eval_to_int(found)?, - } - } + MisalignedPointerDereference { required, found } => MisalignedPointerDereference { + required: eval_to_int(required)?, + found: eval_to_int(found)?, + }, NullPointerDereference => NullPointerDereference, }; Err(ConstEvalErrKind::AssertFailure(err)).into() diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index c08495c012f83..b020eeccf717f 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -6,6 +6,7 @@ use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, + MultiSpan, SubdiagMessageOp, Subdiagnostic, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -17,6 +18,7 @@ use rustc_middle::mir::interpret::{ use rustc_middle::ty::{self, Mutability, Ty}; use rustc_span::{Span, Symbol}; +use crate::fluent_generated as fluent; use crate::interpret::InternKind; #[derive(Diagnostic)] @@ -278,14 +280,31 @@ pub(crate) struct NonConstImplNote { pub span: Span, } -#[derive(Subdiagnostic, Clone)] -#[note(const_eval_frame_note)] +#[derive(Clone)] pub struct FrameNote { - #[primary_span] pub span: Span, pub times: i32, pub where_: &'static str, pub instance: String, + pub has_label: bool, +} + +impl Subdiagnostic for FrameNote { + fn add_to_diag_with>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + diag.arg("times", self.times); + diag.arg("where_", self.where_); + diag.arg("instance", self.instance); + let mut span: MultiSpan = self.span.into(); + if self.has_label && !self.span.is_dummy() { + span.push_span_label(self.span, fluent::const_eval_frame_note_last); + } + let msg = f(diag, fluent::const_eval_frame_note.into()); + diag.span_note(span, msg); + } } #[derive(Subdiagnostic)] @@ -967,7 +986,7 @@ impl ReportErrorExt for ResourceExhaustionInfo { } impl rustc_errors::IntoDiagArg for InternKind { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(match self { InternKind::Static(Mutability::Not) => "static", InternKind::Static(Mutability::Mut) => "static_mut", diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 7b706334ed85e..643a5805019ff 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -9,7 +9,6 @@ use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, FloatTy, Ty}; use rustc_middle::{bug, span_bug}; -use rustc_type_ir::TyKind::*; use tracing::trace; use super::util::ensure_monomorphic_enough; @@ -182,9 +181,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { src: &ImmTy<'tcx, M::Provenance>, cast_to: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - use rustc_type_ir::TyKind::*; - - let Float(fty) = src.layout.ty.kind() else { + let ty::Float(fty) = src.layout.ty.kind() else { bug!("FloatToFloat/FloatToInt cast: source type {} is not a float type", src.layout.ty) }; let val = match fty { @@ -277,19 +274,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let signed = src_layout.backend_repr.is_signed(); // Also asserts that abi is `Scalar`. let v = match src_layout.ty.kind() { - Uint(_) | RawPtr(..) | FnPtr(..) => scalar.to_uint(src_layout.size)?, - Int(_) => scalar.to_int(src_layout.size)? as u128, // we will cast back to `i128` below if the sign matters - Bool => scalar.to_bool()?.into(), - Char => scalar.to_char()?.into(), + ty::Uint(_) | ty::RawPtr(..) | ty::FnPtr(..) => scalar.to_uint(src_layout.size)?, + ty::Int(_) => scalar.to_int(src_layout.size)? as u128, // we will cast back to `i128` below if the sign matters + ty::Bool => scalar.to_bool()?.into(), + ty::Char => scalar.to_char()?.into(), _ => span_bug!(self.cur_span(), "invalid int-like cast from {}", src_layout.ty), }; interp_ok(match *cast_ty.kind() { // int -> int - Int(_) | Uint(_) => { + ty::Int(_) | ty::Uint(_) => { let size = match *cast_ty.kind() { - Int(t) => Integer::from_int_ty(self, t).size(), - Uint(t) => Integer::from_uint_ty(self, t).size(), + ty::Int(t) => Integer::from_int_ty(self, t).size(), + ty::Uint(t) => Integer::from_uint_ty(self, t).size(), _ => bug!(), }; let v = size.truncate(v); @@ -297,7 +294,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // signed int -> float - Float(fty) if signed => { + ty::Float(fty) if signed => { let v = v as i128; match fty { FloatTy::F16 => Scalar::from_f16(Half::from_i128(v).value), @@ -307,7 +304,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } // unsigned int -> float - Float(fty) => match fty { + ty::Float(fty) => match fty { FloatTy::F16 => Scalar::from_f16(Half::from_u128(v).value), FloatTy::F32 => Scalar::from_f32(Single::from_u128(v).value), FloatTy::F64 => Scalar::from_f64(Double::from_u128(v).value), @@ -315,7 +312,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }, // u8 -> char - Char => Scalar::from_u32(u8::try_from(v).unwrap().into()), + ty::Char => Scalar::from_u32(u8::try_from(v).unwrap().into()), // Casts to bool are not permitted by rustc, no need to handle them here. _ => span_bug!(self.cur_span(), "invalid int to {} cast", cast_ty), @@ -332,11 +329,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { + FloatConvert + FloatConvert, { - use rustc_type_ir::TyKind::*; - match *dest_ty.kind() { // float -> uint - Uint(t) => { + ty::Uint(t) => { let size = Integer::from_uint_ty(self, t).size(); // `to_u128` is a saturating cast, which is what we need // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). @@ -345,7 +340,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_uint(v, size) } // float -> int - Int(t) => { + ty::Int(t) => { let size = Integer::from_int_ty(self, t).size(); // `to_i128` is a saturating cast, which is what we need // (https://doc.rust-lang.org/nightly/nightly-rustc/rustc_apfloat/trait.Float.html#method.to_i128_r). @@ -353,7 +348,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_int(v, size) } // float -> float - Float(fty) => match fty { + ty::Float(fty) => match fty { FloatTy::F16 => { Scalar::from_f16(self.adjust_nan(f.convert(&mut false).value, &[f])) } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index e14cc1dad3634..e4b2fe5d153e1 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -61,8 +61,8 @@ impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { /// already mutable (as a sanity check). /// /// Returns an iterator over all relocations referred to by this allocation. -fn intern_shallow<'rt, 'tcx, T, M: CompileTimeMachine<'tcx, T>>( - ecx: &'rt mut InterpCx<'tcx, M>, +fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( + ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, ) -> Result + 'tcx, ()> { @@ -104,7 +104,7 @@ fn intern_as_new_static<'tcx>( ) { let feed = tcx.create_def( static_id, - sym::nested, + Some(sym::nested), DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 1a799f5dea5b5..a21bf018d01fa 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -8,7 +8,6 @@ use std::hash::Hash; use rustc_abi::{Align, Size}; use rustc_apfloat::{Float, FloatConvert}; -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::TyAndLayout; @@ -21,7 +20,6 @@ use super::{ AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, interp_ok, throw_unsup, - throw_unsup_format, }; /// Data returned by [`Machine::after_stack_pop`], and consumed by @@ -361,6 +359,19 @@ pub trait Machine<'tcx>: Sized { size: i64, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)>; + /// Return a "root" pointer for the given allocation: the one that is used for direct + /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. + /// + /// Not called on `extern` or thread-local statics (those use the methods above). + /// + /// `kind` is the kind of the allocation the pointer points to; it can be `None` when + /// it's a global and `GLOBAL_KIND` is `None`. + fn adjust_alloc_root_pointer( + ecx: &InterpCx<'tcx, Self>, + ptr: Pointer, + kind: Option>, + ) -> InterpResult<'tcx, Pointer>; + /// Called to adjust global allocations to the Provenance and AllocExtra of this machine. /// /// If `alloc` contains pointers, then they are all pointing to globals. @@ -375,11 +386,12 @@ pub trait Machine<'tcx>: Sized { alloc: &'b Allocation, ) -> InterpResult<'tcx, Cow<'b, Allocation>>; - /// Initialize the extra state of an allocation. + /// Initialize the extra state of an allocation local to this machine. /// - /// This is guaranteed to be called exactly once on all allocations that are accessed by the - /// program. - fn init_alloc_extra( + /// This is guaranteed to be called exactly once on all allocations local to this machine. + /// It will not be called automatically for global allocations; `adjust_global_allocation` + /// has to do that itself if that is desired. + fn init_local_allocation( ecx: &InterpCx<'tcx, Self>, id: AllocId, kind: MemoryKind, @@ -387,34 +399,6 @@ pub trait Machine<'tcx>: Sized { align: Align, ) -> InterpResult<'tcx, Self::AllocExtra>; - /// Return a "root" pointer for the given allocation: the one that is used for direct - /// accesses to this static/const/fn allocation, or the one returned from the heap allocator. - /// - /// Not called on `extern` or thread-local statics (those use the methods above). - /// - /// `kind` is the kind of the allocation the pointer points to; it can be `None` when - /// it's a global and `GLOBAL_KIND` is `None`. - fn adjust_alloc_root_pointer( - ecx: &InterpCx<'tcx, Self>, - ptr: Pointer, - kind: Option>, - ) -> InterpResult<'tcx, Pointer>; - - /// Evaluate the inline assembly. - /// - /// This should take care of jumping to the next block (one of `targets`) when asm goto - /// is triggered, `targets[0]` when the assembly falls through, or diverge in case of - /// naked_asm! or `InlineAsmOptions::NORETURN` being set. - fn eval_inline_asm( - _ecx: &mut InterpCx<'tcx, Self>, - _template: &'tcx [InlineAsmTemplatePiece], - _operands: &[mir::InlineAsmOperand<'tcx>], - _options: InlineAsmOptions, - _targets: &[mir::BasicBlock], - ) -> InterpResult<'tcx> { - throw_unsup_format!("inline assembly is not supported") - } - /// Hook for performing extra checks on a memory read access. /// /// This will *not* be called during validation! @@ -699,7 +683,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { interp_ok(Cow::Borrowed(alloc)) } - fn init_alloc_extra( + fn init_local_allocation( _ecx: &InterpCx<$tcx, Self>, _id: AllocId, _kind: MemoryKind, diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 4f4b6785844dc..75726269a865d 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -263,9 +263,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::GLOBAL_KIND.map(MemoryKind::Machine), "dynamically allocating global memory" ); - // We have set things up so we don't need to call `adjust_from_tcx` here, - // so we avoid copying the entire allocation contents. - let extra = M::init_alloc_extra(self, id, kind, alloc.size(), alloc.align)?; + // This cannot be merged with the `adjust_global_allocation` code path + // since here we have an allocation that already uses `M::Bytes`. + let extra = M::init_local_allocation(self, id, kind, alloc.size(), alloc.align)?; let alloc = alloc.with_extra(extra); self.memory.alloc_map.insert(id, (kind, alloc)); M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind)) @@ -955,18 +955,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Handle the effect an FFI call might have on the state of allocations. /// This overapproximates the modifications which external code might make to memory: - /// We set all reachable allocations as initialized, mark all provenances as exposed + /// We set all reachable allocations as initialized, mark all reachable provenances as exposed /// and overwrite them with `Provenance::WILDCARD`. - pub fn prepare_for_native_call( - &mut self, - id: AllocId, - initial_prov: M::Provenance, - ) -> InterpResult<'tcx> { - // Expose provenance of the root allocation. - M::expose_provenance(self, initial_prov)?; - + /// + /// The allocations in `ids` are assumed to be already exposed. + pub fn prepare_for_native_call(&mut self, ids: Vec) -> InterpResult<'tcx> { let mut done = FxHashSet::default(); - let mut todo = vec![id]; + let mut todo = ids; while let Some(id) = todo.pop() { if !done.insert(id) { // We already saw this allocation before, don't process it again. @@ -987,6 +982,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { todo.push(id); } } + // Also expose the provenance of the interpreter-level allocation, so it can + // be read by FFI. The `black_box` is defensive programming as LLVM likes + // to (incorrectly) optimize away ptr2int casts whose result is unused. + std::hint::black_box(alloc.get_bytes_unchecked_raw().expose_provenance()); // Prepare for possible write from native code if mutable. if info.mutbl.is_mut() { diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 7d0e0492792a9..d7b03776bc481 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -231,13 +231,19 @@ impl<'tcx> FrameInfo<'tcx> { pub fn as_note(&self, tcx: TyCtxt<'tcx>) -> errors::FrameNote { let span = self.span; if tcx.def_key(self.instance.def_id()).disambiguated_data.data == DefPathData::Closure { - errors::FrameNote { where_: "closure", span, instance: String::new(), times: 0 } + errors::FrameNote { + where_: "closure", + span, + instance: String::new(), + times: 0, + has_label: false, + } } else { let instance = format!("{}", self.instance); // Note: this triggers a `must_produce_diag` state, which means that if we ever get // here we must emit a diagnostic. We should never display a `FrameInfo` unless we // actually want to emit a warning or error to the user. - errors::FrameNote { where_: "instance", span, instance, times: 0 } + errors::FrameNote { where_: "instance", span, instance, times: 0, has_label: false } } } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 6a17da61c8b7b..ddf2d65914f6c 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -14,7 +14,7 @@ use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, - Projectable, Scalar, interp_ok, throw_ub, + Projectable, Scalar, interp_ok, throw_ub, throw_unsup_format, }; use crate::util; @@ -590,8 +590,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { terminator.kind ), - InlineAsm { template, ref operands, options, ref targets, .. } => { - M::eval_inline_asm(self, template, operands, options, targets)?; + InlineAsm { .. } => { + throw_unsup_format!("inline assembly is not supported"); } } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 40dec0cb39e7b..eb3f552cd2787 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1296,7 +1296,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, self.visit_scalar(b, b_layout)?; } } - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { // No checks here, we assume layout computation gets this right. // (This is harder to check since Miri does not represent these as `Immediate`. We // also cannot use field projections since this might be a newtype around a vector.) diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index ed5489652fba6..e03849c32f94f 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -16,7 +17,6 @@ #![feature(unqualified_local_imports)] #![feature(yeet_expr)] #![warn(unqualified_local_imports)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod check_consts; diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 6426bca2332d4..d7e97f32bae92 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -117,7 +117,7 @@ fn check_validity_requirement_lax<'tcx>( BackendRepr::ScalarPair(s1, s2) => { scalar_allows_raw_init(s1) && scalar_allows_raw_init(s2) } - BackendRepr::Vector { element: s, count } => count == 0 || scalar_allows_raw_init(s), + BackendRepr::SimdVector { element: s, count } => count == 0 || scalar_allows_raw_init(s), BackendRepr::Memory { .. } => true, // Fields are checked below. }; if !valid { diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 1705af1e210a6..b9a5fc3a1fe9c 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_data_structures" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -29,6 +29,11 @@ thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end +[dependencies.hashbrown] +version = "0.15.2" +default-features = false +features = ["nightly"] # for may_dangle + [dependencies.parking_lot] version = "0.12" diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs index 0e5ecfd9bff6e..a636d09fcae23 100644 --- a/compiler/rustc_data_structures/src/aligned.rs +++ b/compiler/rustc_data_structures/src/aligned.rs @@ -2,10 +2,8 @@ use std::ptr::Alignment; /// Returns the ABI-required minimum alignment of a type in bytes. /// -/// This is equivalent to [`mem::align_of`], but also works for some unsized +/// This is equivalent to [`align_of`], but also works for some unsized /// types (e.g. slices or rustc's `List`s). -/// -/// [`mem::align_of`]: std::mem::align_of pub const fn align_of() -> Alignment { T::ALIGN } @@ -15,10 +13,10 @@ pub const fn align_of() -> Alignment { /// # Safety /// /// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it -/// is [`mem::align_of()`], for unsized types it depends on the type, for +/// is [`align_of::()`], for unsized types it depends on the type, for /// example `[T]` has alignment of `T`. /// -/// [`mem::align_of()`]: std::mem::align_of +/// [`align_of::()`]: align_of pub unsafe trait Aligned { /// Alignment of `Self`. const ALIGN: Alignment; diff --git a/compiler/rustc_data_structures/src/captures.rs b/compiler/rustc_data_structures/src/captures.rs deleted file mode 100644 index 677ccb31454ea..0000000000000 --- a/compiler/rustc_data_structures/src/captures.rs +++ /dev/null @@ -1,8 +0,0 @@ -/// "Signaling" trait used in impl trait to tag lifetimes that you may -/// need to capture but don't really need for other reasons. -/// Basically a workaround; see [this comment] for details. -/// -/// [this comment]: https://github.com/rust-lang/rust/issues/34511#issuecomment-373423999 -pub trait Captures<'a> {} - -impl<'a, T: ?Sized> Captures<'a> for T {} diff --git a/compiler/rustc_data_structures/src/flat_map_in_place.rs b/compiler/rustc_data_structures/src/flat_map_in_place.rs index e66b00b755760..6d718059f9c81 100644 --- a/compiler/rustc_data_structures/src/flat_map_in_place.rs +++ b/compiler/rustc_data_structures/src/flat_map_in_place.rs @@ -1,4 +1,4 @@ -use std::ptr; +use std::{mem, ptr}; use smallvec::{Array, SmallVec}; use thin_vec::ThinVec; @@ -13,39 +13,44 @@ pub trait FlatMapInPlace: Sized { // The implementation of this method is syntactically identical for all the // different vector types. macro_rules! flat_map_in_place { - () => { + ($vec:ident $( where T: $bound:path)?) => { fn flat_map_in_place(&mut self, mut f: F) where F: FnMut(T) -> I, I: IntoIterator, { + struct LeakGuard<'a, T $(: $bound)?>(&'a mut $vec); + + impl<'a, T $(: $bound)?> Drop for LeakGuard<'a, T> { + fn drop(&mut self) { + unsafe { + self.0.set_len(0); // make sure we just leak elements in case of panic + } + } + } + + let this = LeakGuard(self); + let mut read_i = 0; let mut write_i = 0; unsafe { - let mut old_len = self.len(); - self.set_len(0); // make sure we just leak elements in case of panic - - while read_i < old_len { + while read_i < this.0.len() { // move the read_i'th item out of the vector and map it // to an iterator - let e = ptr::read(self.as_ptr().add(read_i)); + let e = ptr::read(this.0.as_ptr().add(read_i)); let iter = f(e).into_iter(); read_i += 1; for e in iter { if write_i < read_i { - ptr::write(self.as_mut_ptr().add(write_i), e); + ptr::write(this.0.as_mut_ptr().add(write_i), e); write_i += 1; } else { // If this is reached we ran out of space // in the middle of the vector. // However, the vector is in a valid state here, // so we just do a somewhat inefficient insert. - self.set_len(old_len); - self.insert(write_i, e); - - old_len = self.len(); - self.set_len(0); + this.0.insert(write_i, e); read_i += 1; write_i += 1; @@ -54,20 +59,23 @@ macro_rules! flat_map_in_place { } // write_i tracks the number of actually written new items. - self.set_len(write_i); + this.0.set_len(write_i); + + // The ThinVec is in a sane state again. Prevent the LeakGuard from leaking the data. + mem::forget(this); } } }; } impl FlatMapInPlace for Vec { - flat_map_in_place!(); + flat_map_in_place!(Vec); } impl> FlatMapInPlace for SmallVec { - flat_map_in_place!(); + flat_map_in_place!(SmallVec where T: Array); } impl FlatMapInPlace for ThinVec { - flat_map_in_place!(); + flat_map_in_place!(ThinVec); } diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 292a33d56469a..d423d8acefd0a 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -4,31 +4,6 @@ //! green/native threading. This is just a bare-bones enough solution for //! librustdoc, it is not production quality at all. -#[cfg(bootstrap)] -cfg_match! { - cfg(target_os = "linux") => { - mod linux; - use linux as imp; - } - cfg(target_os = "redox") => { - mod linux; - use linux as imp; - } - cfg(unix) => { - mod unix; - use unix as imp; - } - cfg(windows) => { - mod windows; - use self::windows as imp; - } - _ => { - mod unsupported; - use unsupported as imp; - } -} - -#[cfg(not(bootstrap))] cfg_match! { target_os = "linux" => { mod linux; diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs index 7724e9347d822..a80365938b96c 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs @@ -193,11 +193,11 @@ impl Graph { AdjacentEdges { graph: self, direction, next: first_edge } } - pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator + '_ { + pub fn successor_nodes(&self, source: NodeIndex) -> impl Iterator { self.outgoing_edges(source).targets() } - pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator + '_ { + pub fn predecessor_nodes(&self, target: NodeIndex) -> impl Iterator { self.incoming_edges(target).sources() } @@ -255,11 +255,11 @@ pub struct AdjacentEdges<'g, N, E> { } impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { - fn targets(self) -> impl Iterator + 'g { + fn targets(self) -> impl Iterator { self.map(|(_, edge)| edge.target) } - fn sources(self) -> impl Iterator + 'g { + fn sources(self) -> impl Iterator { self.map(|(_, edge)| edge.source) } } diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index 93f6192b10b03..e7c4ea3daae45 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -133,7 +133,7 @@ impl Sccs { /// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after. /// This is convenient when the edges represent dependencies: when you visit /// `S1`, the value for `S2` will already have been computed. - pub fn all_sccs(&self) -> impl Iterator { + pub fn all_sccs(&self) -> impl Iterator + 'static { (0..self.scc_data.len()).map(S::new) } diff --git a/compiler/rustc_data_structures/src/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs index b69b9dbc4a8e6..e48b9686c260f 100644 --- a/compiler/rustc_data_structures/src/graph/tests.rs +++ b/compiler/rustc_data_structures/src/graph/tests.rs @@ -3,7 +3,7 @@ use std::cmp::max; use super::*; use crate::fx::FxHashMap; -pub struct TestGraph { +pub(super) struct TestGraph { num_nodes: usize, start_node: usize, successors: FxHashMap>, @@ -11,7 +11,7 @@ pub struct TestGraph { } impl TestGraph { - pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { + pub(super) fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { let mut graph = TestGraph { num_nodes: start_node + 1, start_node, diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 66d3834d85784..865424fd6bbdc 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -24,7 +24,6 @@ #![feature(dropck_eyepatch)] #![feature(extend_one)] #![feature(file_buffered)] -#![feature(hash_raw_entry)] #![feature(macro_metavar_expr)] #![feature(map_try_insert)] #![feature(min_specialization)] @@ -48,7 +47,6 @@ pub use rustc_index::static_assert_size; pub mod aligned; pub mod base_n; pub mod binary_search_util; -pub mod captures; pub mod fingerprint; pub mod flat_map_in_place; pub mod flock; diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index 6ae97222f77fd..64c64bfa3c296 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -1,3 +1,5 @@ +use std::alloc::Allocator; + #[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")] // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` @@ -28,8 +30,8 @@ impls_dyn_send_neg!( [*const T where T: ?Sized] [*mut T where T: ?Sized] [std::ptr::NonNull where T: ?Sized] - [std::rc::Rc where T: ?Sized] - [std::rc::Weak where T: ?Sized] + [std::rc::Rc where T: ?Sized, A: Allocator] + [std::rc::Weak where T: ?Sized, A: Allocator] [std::sync::MutexGuard<'_, T> where T: ?Sized] [std::sync::RwLockReadGuard<'_, T> where T: ?Sized] [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized] @@ -74,6 +76,7 @@ impl_dyn_send!( [crate::sync::RwLock where T: DynSend] [crate::tagged_ptr::TaggedRef<'a, P, T> where 'a, P: Sync, T: Send + crate::tagged_ptr::Tag] [rustc_arena::TypedArena where T: DynSend] + [hashbrown::HashTable where T: DynSend] [indexmap::IndexSet where V: DynSend, S: DynSend] [indexmap::IndexMap where K: DynSend, V: DynSend, S: DynSend] [thin_vec::ThinVec where T: DynSend] @@ -96,8 +99,8 @@ impls_dyn_sync_neg!( [std::cell::RefCell where T: ?Sized] [std::cell::UnsafeCell where T: ?Sized] [std::ptr::NonNull where T: ?Sized] - [std::rc::Rc where T: ?Sized] - [std::rc::Weak where T: ?Sized] + [std::rc::Rc where T: ?Sized, A: Allocator] + [std::rc::Weak where T: ?Sized, A: Allocator] [std::cell::OnceCell where T] [std::sync::mpsc::Receiver where T] [std::sync::mpsc::Sender where T] @@ -151,6 +154,7 @@ impl_dyn_sync!( [crate::tagged_ptr::TaggedRef<'a, P, T> where 'a, P: Sync, T: Sync + crate::tagged_ptr::Tag] [parking_lot::lock_api::Mutex where R: DynSync, T: ?Sized + DynSend] [parking_lot::lock_api::RwLock where R: DynSync, T: ?Sized + DynSend + DynSync] + [hashbrown::HashTable where T: DynSync] [indexmap::IndexSet where V: DynSync, S: DynSync] [indexmap::IndexMap where K: DynSync, V: DynSync, S: DynSync] [smallvec::SmallVec where A: smallvec::Array + DynSync] diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 78d69a66edc8b..f63b201742d9a 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -313,8 +313,9 @@ pub struct Error { mod helper { use super::*; - pub type ObligationTreeIdGenerator = impl Iterator; + pub(super) type ObligationTreeIdGenerator = impl Iterator; impl ObligationForest { + #[cfg_attr(not(bootstrap), define_opaque(ObligationTreeIdGenerator))] pub fn new() -> ObligationForest { ObligationForest { nodes: vec![], diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs index 18e98e6c39fa9..60f007083baf3 100644 --- a/compiler/rustc_data_structures/src/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -860,81 +860,16 @@ fn get_thread_id() -> u32 { } // Memory reporting -#[cfg(bootstrap)] -cfg_match! { - cfg(windows) => { - pub fn get_resident_set_size() -> Option { - use std::mem; - - use windows::{ - Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, - Win32::System::Threading::GetCurrentProcess, - }; - - let mut pmc = PROCESS_MEMORY_COUNTERS::default(); - let pmc_size = mem::size_of_val(&pmc); - unsafe { - K32GetProcessMemoryInfo( - GetCurrentProcess(), - &mut pmc, - pmc_size as u32, - ) - } - .ok() - .ok()?; - - Some(pmc.WorkingSetSize) - } - } - cfg(target_os = "macos") => { - pub fn get_resident_set_size() -> Option { - use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO}; - use std::mem; - const PROC_TASKINFO_SIZE: c_int = mem::size_of::() as c_int; - - unsafe { - let mut info: proc_taskinfo = mem::zeroed(); - let info_ptr = &mut info as *mut proc_taskinfo as *mut c_void; - let pid = getpid() as c_int; - let ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, info_ptr, PROC_TASKINFO_SIZE); - if ret == PROC_TASKINFO_SIZE { - Some(info.pti_resident_size as usize) - } else { - None - } - } - } - } - cfg(unix) => { - pub fn get_resident_set_size() -> Option { - let field = 1; - let contents = fs::read("/proc/self/statm").ok()?; - let contents = String::from_utf8(contents).ok()?; - let s = contents.split_whitespace().nth(field)?; - let npages = s.parse::().ok()?; - Some(npages * 4096) - } - } - _ => { - pub fn get_resident_set_size() -> Option { - None - } - } -} - -#[cfg(not(bootstrap))] cfg_match! { windows => { pub fn get_resident_set_size() -> Option { - use std::mem; - use windows::{ Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS}, Win32::System::Threading::GetCurrentProcess, }; let mut pmc = PROCESS_MEMORY_COUNTERS::default(); - let pmc_size = mem::size_of_val(&pmc); + let pmc_size = size_of_val(&pmc); unsafe { K32GetProcessMemoryInfo( GetCurrentProcess(), @@ -952,7 +887,7 @@ cfg_match! { pub fn get_resident_set_size() -> Option { use libc::{c_int, c_void, getpid, proc_pidinfo, proc_taskinfo, PROC_PIDTASKINFO}; use std::mem; - const PROC_TASKINFO_SIZE: c_int = mem::size_of::() as c_int; + const PROC_TASKINFO_SIZE: c_int = size_of::() as c_int; unsafe { let mut info: proc_taskinfo = mem::zeroed(); diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs index 65488c73d3cdd..49cafcb17a03e 100644 --- a/compiler/rustc_data_structures/src/sharded.rs +++ b/compiler/rustc_data_structures/src/sharded.rs @@ -1,11 +1,11 @@ use std::borrow::Borrow; -use std::collections::hash_map::RawEntryMut; use std::hash::{Hash, Hasher}; use std::{iter, mem}; use either::Either; +use hashbrown::hash_table::{Entry, HashTable}; -use crate::fx::{FxHashMap, FxHasher}; +use crate::fx::FxHasher; use crate::sync::{CacheAligned, Lock, LockGuard, Mode, is_dyn_thread_safe}; // 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700, @@ -43,10 +43,10 @@ impl Sharded { /// The shard is selected by hashing `val` with `FxHasher`. #[inline] - pub fn get_shard_by_value(&self, _val: &K) -> &Lock { + pub fn get_shard_by_value(&self, val: &K) -> &Lock { match self { Self::Single(single) => single, - Self::Shards(..) => self.get_shard_by_hash(make_hash(_val)), + Self::Shards(..) => self.get_shard_by_hash(make_hash(val)), } } @@ -56,12 +56,12 @@ impl Sharded { } #[inline] - pub fn get_shard_by_index(&self, _i: usize) -> &Lock { + pub fn get_shard_by_index(&self, i: usize) -> &Lock { match self { Self::Single(single) => single, Self::Shards(shards) => { // SAFETY: The index gets ANDed with the shard mask, ensuring it is always inbounds. - unsafe { &shards.get_unchecked(_i & (SHARDS - 1)).0 } + unsafe { &shards.get_unchecked(i & (SHARDS - 1)).0 } } } } @@ -69,7 +69,7 @@ impl Sharded { /// The shard is selected by hashing `val` with `FxHasher`. #[inline] #[track_caller] - pub fn lock_shard_by_value(&self, _val: &K) -> LockGuard<'_, T> { + pub fn lock_shard_by_value(&self, val: &K) -> LockGuard<'_, T> { match self { Self::Single(single) => { // Synchronization is disabled so use the `lock_assume_no_sync` method optimized @@ -79,7 +79,7 @@ impl Sharded { // `might_be_dyn_thread_safe` was also false. unsafe { single.lock_assume(Mode::NoSync) } } - Self::Shards(..) => self.lock_shard_by_hash(make_hash(_val)), + Self::Shards(..) => self.lock_shard_by_hash(make_hash(val)), } } @@ -91,7 +91,7 @@ impl Sharded { #[inline] #[track_caller] - pub fn lock_shard_by_index(&self, _i: usize) -> LockGuard<'_, T> { + pub fn lock_shard_by_index(&self, i: usize) -> LockGuard<'_, T> { match self { Self::Single(single) => { // Synchronization is disabled so use the `lock_assume_no_sync` method optimized @@ -109,7 +109,7 @@ impl Sharded { // always inbounds. // SAFETY (lock_assume_sync): We know `is_dyn_thread_safe` was true when creating // the lock thus `might_be_dyn_thread_safe` was also true. - unsafe { shards.get_unchecked(_i & (SHARDS - 1)).0.lock_assume(Mode::Sync) } + unsafe { shards.get_unchecked(i & (SHARDS - 1)).0.lock_assume(Mode::Sync) } } } } @@ -140,14 +140,67 @@ pub fn shards() -> usize { 1 } -pub type ShardedHashMap = Sharded>; +pub type ShardedHashMap = Sharded>; impl ShardedHashMap { + pub fn with_capacity(cap: usize) -> Self { + Self::new(|| HashTable::with_capacity(cap)) + } pub fn len(&self) -> usize { self.lock_shards().map(|shard| shard.len()).sum() } } +impl ShardedHashMap { + #[inline] + pub fn get(&self, key: &Q) -> Option + where + K: Borrow, + Q: Hash + Eq, + V: Clone, + { + let hash = make_hash(key); + let shard = self.lock_shard_by_hash(hash); + let (_, value) = shard.find(hash, |(k, _)| k.borrow() == key)?; + Some(value.clone()) + } + + #[inline] + pub fn get_or_insert_with(&self, key: K, default: impl FnOnce() -> V) -> V + where + V: Copy, + { + let hash = make_hash(&key); + let mut shard = self.lock_shard_by_hash(hash); + + match table_entry(&mut shard, hash, &key) { + Entry::Occupied(e) => e.get().1, + Entry::Vacant(e) => { + let value = default(); + e.insert((key, value)); + value + } + } + } + + #[inline] + pub fn insert(&self, key: K, value: V) -> Option { + let hash = make_hash(&key); + let mut shard = self.lock_shard_by_hash(hash); + + match table_entry(&mut shard, hash, &key) { + Entry::Occupied(e) => { + let previous = mem::replace(&mut e.into_mut().1, value); + Some(previous) + } + Entry::Vacant(e) => { + e.insert((key, value)); + None + } + } + } +} + impl ShardedHashMap { #[inline] pub fn intern_ref(&self, value: &Q, make: impl FnOnce() -> K) -> K @@ -157,13 +210,12 @@ impl ShardedHashMap { { let hash = make_hash(value); let mut shard = self.lock_shard_by_hash(hash); - let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, value); - match entry { - RawEntryMut::Occupied(e) => *e.key(), - RawEntryMut::Vacant(e) => { + match table_entry(&mut shard, hash, value) { + Entry::Occupied(e) => e.get().0, + Entry::Vacant(e) => { let v = make(); - e.insert_hashed_nocheck(hash, v, ()); + e.insert((v, ())); v } } @@ -177,13 +229,12 @@ impl ShardedHashMap { { let hash = make_hash(&value); let mut shard = self.lock_shard_by_hash(hash); - let entry = shard.raw_entry_mut().from_key_hashed_nocheck(hash, &value); - match entry { - RawEntryMut::Occupied(e) => *e.key(), - RawEntryMut::Vacant(e) => { + match table_entry(&mut shard, hash, &value) { + Entry::Occupied(e) => e.get().0, + Entry::Vacant(e) => { let v = make(value); - e.insert_hashed_nocheck(hash, v, ()); + e.insert((v, ())); v } } @@ -200,17 +251,30 @@ impl ShardedHashMap { let hash = make_hash(&value); let shard = self.lock_shard_by_hash(hash); let value = value.into_pointer(); - shard.raw_entry().from_hash(hash, |entry| entry.into_pointer() == value).is_some() + shard.find(hash, |(k, ())| k.into_pointer() == value).is_some() } } #[inline] -pub fn make_hash(val: &K) -> u64 { +fn make_hash(val: &K) -> u64 { let mut state = FxHasher::default(); val.hash(&mut state); state.finish() } +#[inline] +fn table_entry<'a, K, V, Q>( + table: &'a mut HashTable<(K, V)>, + hash: u64, + key: &Q, +) -> Entry<'a, (K, V)> +where + K: Hash + Borrow, + Q: ?Sized + Eq, +{ + table.entry(hash, move |(k, _)| k.borrow() == key, |(k, _)| make_hash(k)) +} + /// Get a shard with a pre-computed hash value. If `get_shard_by_value` is /// ever used in combination with `get_shard_by_hash` on a single `Sharded` /// instance, then `hash` must be computed with `FxHasher`. Otherwise, @@ -218,7 +282,7 @@ pub fn make_hash(val: &K) -> u64 { /// consistently for each `Sharded` instance. #[inline] fn get_shard_hash(hash: u64) -> usize { - let hash_len = mem::size_of::(); + let hash_len = size_of::(); // Ignore the top 7 bits as hashbrown uses these and get the next SHARD_BITS highest bits. // hashbrown also uses the lowest bits, so we can't use those (hash >> (hash_len * 8 - 7 - SHARD_BITS)) as usize diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 066ea03b4ace4..c002d47815b17 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -1,9 +1,10 @@ use std::borrow::Borrow; +use std::cmp::Ordering; use std::fmt::Debug; use std::mem; use std::ops::{Bound, Index, IndexMut, RangeBounds}; -use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; use crate::stable_hasher::{HashStable, StableHasher, StableOrd}; @@ -19,7 +20,7 @@ pub use index_map::SortedIndexMultiMap; /// stores data in a more compact way. It also supports accessing contiguous /// ranges of elements as a slice, and slices of already sorted elements can be /// inserted efficiently. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable_Generic, Decodable_Generic)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable_NoContext, Decodable_NoContext)] pub struct SortedMap { data: Vec<(K, V)>, } @@ -156,6 +157,38 @@ impl SortedMap { &self.data[start..end] } + /// `sm.range_is_empty(r)` == `sm.range(r).is_empty()`, but is faster. + #[inline] + pub fn range_is_empty(&self, range: R) -> bool + where + R: RangeBounds, + { + // `range` must (via `range_slice_indices`) search for the start and + // end separately. But here we can do a single binary search for the + // entire range. If a single `x` matching `range` is found then the + // range is *not* empty. + self.data + .binary_search_by(|(x, _)| { + // Is `x` below `range`? + match range.start_bound() { + Bound::Included(start) if x < start => return Ordering::Less, + Bound::Excluded(start) if x <= start => return Ordering::Less, + _ => {} + }; + + // Is `x` above `range`? + match range.end_bound() { + Bound::Included(end) if x > end => return Ordering::Greater, + Bound::Excluded(end) if x >= end => return Ordering::Greater, + _ => {} + }; + + // `x` must be within `range`. + Ordering::Equal + }) + .is_err() + } + #[inline] pub fn remove_range(&mut self, range: R) where diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs index e9a5fb5197548..b38b09d60ebf0 100644 --- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs @@ -84,7 +84,7 @@ impl SortedIndexMultiMap { /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. #[inline] - pub fn get_by_key(&self, key: K) -> impl Iterator + '_ { + pub fn get_by_key(&self, key: K) -> impl Iterator { self.get_by_key_enumerated(key).map(|(_, v)| v) } @@ -94,7 +94,7 @@ impl SortedIndexMultiMap { /// If there are multiple items that are equivalent to `key`, they will be yielded in /// insertion order. #[inline] - pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator + '_ { + pub fn get_by_key_enumerated(&self, key: K) -> impl Iterator { let lower_bound = self.idx_sorted_by_item_key.partition_point(|&i| self.items[i].0 < key); self.idx_sorted_by_item_key[lower_bound..].iter().map_while(move |&i| { let (k, v) = &self.items[i]; @@ -147,7 +147,7 @@ impl FromIterator<(K, V)> for SortedIndexMultiMap { where J: IntoIterator, { - let items = IndexVec::from_iter(iter); + let items = IndexVec::::from_iter(iter); let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect(); // `sort_by_key` is stable, so insertion order is preserved for duplicate items. diff --git a/compiler/rustc_data_structures/src/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs index def7a7112fb3f..ea4d2f1feacc0 100644 --- a/compiler/rustc_data_structures/src/sorted_map/tests.rs +++ b/compiler/rustc_data_structures/src/sorted_map/tests.rs @@ -24,7 +24,7 @@ fn test_sorted_index_multi_map() { // `get_by_key` returns items in insertion order. let twos: Vec<_> = set.get_by_key_enumerated(2).collect(); let idxs: Vec = twos.iter().map(|(i, _)| *i).collect(); - let values: Vec = twos.iter().map(|(_, &v)| v).collect(); + let values: Vec = twos.iter().map(|&(_, &v)| v).collect(); assert_eq!(idxs, vec![0, 2, 4]); assert_eq!(values, vec![0, 1, 2]); diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs index 3200249a2dc4c..827c82fa46a11 100644 --- a/compiler/rustc_data_structures/src/sso/map.rs +++ b/compiler/rustc_data_structures/src/sso/map.rs @@ -165,7 +165,7 @@ impl SsoHashMap { /// Clears the map, returning all key-value pairs as an iterator. Keeps the /// allocated memory for reuse. - pub fn drain(&mut self) -> impl Iterator + '_ { + pub fn drain(&mut self) -> impl Iterator { match self { SsoHashMap::Array(array) => Either::Left(array.drain(..)), SsoHashMap::Map(map) => Either::Right(map.drain()), diff --git a/compiler/rustc_data_structures/src/sso/set.rs b/compiler/rustc_data_structures/src/sso/set.rs index a4b40138933de..e3fa1cbf4cc57 100644 --- a/compiler/rustc_data_structures/src/sso/set.rs +++ b/compiler/rustc_data_structures/src/sso/set.rs @@ -80,7 +80,7 @@ impl SsoHashSet { /// Clears the set, returning all elements in an iterator. #[inline] - pub fn drain(&mut self) -> impl Iterator + '_ { + pub fn drain(&mut self) -> impl Iterator { self.map.drain().map(entry_to_key) } } diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs index 391a7c9f30dbf..f51fcb8ed22d3 100644 --- a/compiler/rustc_data_structures/src/svh.rs +++ b/compiler/rustc_data_structures/src/svh.rs @@ -7,12 +7,12 @@ use std::fmt; -use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; use crate::fingerprint::Fingerprint; use crate::stable_hasher; -#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_Generic, Decodable_Generic, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable_NoContext, Decodable_NoContext, Hash)] pub struct Svh { hash: Fingerprint, } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 37b54fe38ff74..616a18a72ab7e 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -18,42 +18,54 @@ //! //! | Type | Serial version | Parallel version | //! | ----------------------- | ------------------- | ------------------------------- | -//! | `LRef<'a, T>` [^2] | `&'a mut T` | `&'a T` | -//! | | | | //! | `Lock` | `RefCell` | `RefCell` or | //! | | | `parking_lot::Mutex` | //! | `RwLock` | `RefCell` | `parking_lot::RwLock` | //! | `MTLock` [^1] | `T` | `Lock` | -//! | `MTLockRef<'a, T>` [^2] | `&'a mut MTLock` | `&'a MTLock` | //! | | | | //! | `ParallelIterator` | `Iterator` | `rayon::iter::ParallelIterator` | //! //! [^1]: `MTLock` is similar to `Lock`, but the serial version avoids the cost //! of a `RefCell`. This is appropriate when interior mutability is not //! required. -//! -//! [^2]: `MTRef`, `MTLockRef` are type aliases. use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; -pub use crate::marker::*; +pub use parking_lot::{ + MappedRwLockReadGuard as MappedReadGuard, MappedRwLockWriteGuard as MappedWriteGuard, + RwLockReadGuard as ReadGuard, RwLockWriteGuard as WriteGuard, +}; -mod lock; +pub use self::atomic::AtomicU64; +pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; #[doc(no_inline)] -pub use lock::{Lock, LockGuard, Mode}; - -mod worker_local; -pub use worker_local::{Registry, WorkerLocal}; +pub use self::lock::{Lock, LockGuard, Mode}; +pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; +pub use self::parallel::{ + join, par_for_each_in, par_map, parallel_guard, scope, try_par_for_each_in, +}; +pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec}; +pub use self::worker_local::{Registry, WorkerLocal}; +pub use crate::marker::*; +mod freeze; +mod lock; mod parallel; -pub use parallel::{join, par_for_each_in, par_map, parallel_guard, scope, try_par_for_each_in}; -pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; - mod vec; +mod worker_local; -mod freeze; -pub use freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; +/// Keep the conditional imports together in a submodule, so that import-sorting +/// doesn't split them up. +mod atomic { + // Most hosts can just use a regular AtomicU64. + #[cfg(target_has_atomic = "64")] + pub use std::sync::atomic::AtomicU64; + + // Some 32-bit hosts don't have AtomicU64, so use a fallback. + #[cfg(not(target_has_atomic = "64"))] + pub use portable_atomic::AtomicU64; +} mod mode { use std::sync::atomic::{AtomicU8, Ordering}; @@ -76,7 +88,7 @@ mod mode { // Whether thread safety might be enabled. #[inline] - pub fn might_be_dyn_thread_safe() -> bool { + pub(super) fn might_be_dyn_thread_safe() -> bool { DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE } @@ -97,21 +109,6 @@ mod mode { // FIXME(parallel_compiler): Get rid of these aliases across the compiler. -pub use std::sync::OnceLock; -// Use portable AtomicU64 for targets without native 64-bit atomics -#[cfg(target_has_atomic = "64")] -pub use std::sync::atomic::AtomicU64; - -pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; -pub use parking_lot::{ - MappedRwLockReadGuard as MappedReadGuard, MappedRwLockWriteGuard as MappedWriteGuard, - RwLockReadGuard as ReadGuard, RwLockWriteGuard as WriteGuard, -}; -#[cfg(not(target_has_atomic = "64"))] -pub use portable_atomic::AtomicU64; - -pub type LRef<'a, T> = &'a T; - #[derive(Debug, Default)] pub struct MTLock(Lock); @@ -142,14 +139,10 @@ impl MTLock { } } -use parking_lot::RwLock as InnerRwLock; - /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread const ERROR_CHECKING: bool = false; -pub type MTLockRef<'a, T> = LRef<'a, MTLock>; - #[derive(Default)] #[repr(align(64))] pub struct CacheAligned(pub T); @@ -167,12 +160,12 @@ impl HashMapExt for HashMap } #[derive(Debug, Default)] -pub struct RwLock(InnerRwLock); +pub struct RwLock(parking_lot::RwLock); impl RwLock { #[inline(always)] pub fn new(inner: T) -> Self { - RwLock(InnerRwLock::new(inner)) + RwLock(parking_lot::RwLock::new(inner)) } #[inline(always)] diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 1ba631b862376..8ef8a3f358569 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -46,7 +46,7 @@ pub fn parallel_guard(f: impl FnOnce(&ParallelGuard) -> R) -> R { ret } -pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) +fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) where A: FnOnce() -> RA, B: FnOnce() -> RB, diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs index 21ec5cf6c13bf..afbb0cef9f956 100644 --- a/compiler/rustc_data_structures/src/sync/vec.rs +++ b/compiler/rustc_data_structures/src/sync/vec.rs @@ -45,14 +45,14 @@ impl AppendOnlyVec { self.vec.read().get(i).copied() } - pub fn iter_enumerated(&self) -> impl Iterator + '_ { + pub fn iter_enumerated(&self) -> impl Iterator { (0..) .map(|i| (i, self.get(i))) .take_while(|(_, o)| o.is_some()) .filter_map(|(i, o)| Some((i, o?))) } - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator { (0..).map(|i| self.get(i)).take_while(|o| o.is_some()).flatten() } } diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs index 402ec9827bbaa..d75af00985047 100644 --- a/compiler/rustc_data_structures/src/sync/worker_local.rs +++ b/compiler/rustc_data_structures/src/sync/worker_local.rs @@ -106,6 +106,12 @@ pub struct WorkerLocal { registry: Registry, } +// This is safe because the `deref` call will return a reference to a `T` unique to each thread +// or it will panic for threads without an associated local. So there isn't a need for `T` to do +// it's own synchronization. The `verify` method on `RegistryId` has an issue where the id +// can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse. +unsafe impl Sync for WorkerLocal {} + impl WorkerLocal { /// Creates a new worker local where the `initial` closure computes the /// value this worker local should take for each thread in the registry. @@ -132,11 +138,6 @@ impl Deref for WorkerLocal { fn deref(&self) -> &T { // This is safe because `verify` will only return values less than // `self.registry.thread_limit` which is the size of the `self.locals` array. - - // The `deref` call will return a reference to a `T` unique to each thread - // or it will panic for threads without an associated local. So there isn't a need for `T` to do - // it's own synchronization. The `verify` method on `RegistryId` has an issue where the id - // can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse. unsafe { &self.locals.get_unchecked(self.registry.id().verify()).0 } } } diff --git a/compiler/rustc_data_structures/src/tagged_ptr/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs index 9c1e4cefa6923..85b21a7c8ecdf 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr/tests.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/tests.rs @@ -7,7 +7,7 @@ use crate::stable_hasher::{HashStable, StableHasher}; /// A tag type used in [`TaggedRef`] tests. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Tag2 { +enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs index e81ebb9a4be22..33ac279f3e0ae 100644 --- a/compiler/rustc_data_structures/src/transitive_relation.rs +++ b/compiler/rustc_data_structures/src/transitive_relation.rs @@ -363,7 +363,7 @@ impl TransitiveRelation { /// Lists all the base edges in the graph: the initial _non-transitive_ set of element /// relations, which will be later used as the basis for the transitive closure computation. - pub fn base_edges(&self) -> impl Iterator + '_ { + pub fn base_edges(&self) -> impl Iterator { self.edges .iter() .map(move |edge| (self.elements[edge.source.0], self.elements[edge.target.0])) diff --git a/compiler/rustc_data_structures/src/unord.rs b/compiler/rustc_data_structures/src/unord.rs index 34895d3efe6ca..baa66cd7c8520 100644 --- a/compiler/rustc_data_structures/src/unord.rs +++ b/compiler/rustc_data_structures/src/unord.rs @@ -9,7 +9,7 @@ use std::iter::{Product, Sum}; use std::ops::Index; use rustc_hash::{FxHashMap, FxHashSet}; -use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; use crate::fingerprint::Fingerprint; use crate::stable_hasher::{HashStable, StableCompare, StableHasher, ToStableHashKey}; @@ -224,7 +224,7 @@ trait UnordCollection {} /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] +#[derive(Debug, Eq, PartialEq, Clone, Encodable_NoContext, Decodable_NoContext)] pub struct UnordSet { inner: FxHashSet, } @@ -259,6 +259,12 @@ impl UnordSet { self.inner.is_empty() } + /// If the set has only one element, returns it, otherwise returns `None`. + #[inline] + pub fn get_only(&self) -> Option<&V> { + if self.inner.len() == 1 { self.inner.iter().next() } else { None } + } + #[inline] pub fn insert(&mut self, v: V) -> bool { self.inner.insert(v) @@ -415,7 +421,7 @@ impl> HashStable for UnordSet { /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] +#[derive(Debug, Eq, PartialEq, Clone, Encodable_NoContext, Decodable_NoContext)] pub struct UnordMap { inner: FxHashMap, } @@ -639,7 +645,7 @@ impl, V: HashStable> HashStable fo /// /// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533) /// for more information. -#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable_Generic, Decodable_Generic)] +#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable_NoContext, Decodable_NoContext)] pub struct UnordBag { inner: Vec, } diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml index ae9712ad66d83..e3ee83512952a 100644 --- a/compiler/rustc_driver/Cargo.toml +++ b/compiler/rustc_driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_driver" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] crate-type = ["dylib"] diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index a03834c519d59..381309f83b2c1 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -3,6 +3,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(rust_logo)] #![feature(rustdoc_internals)] // tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 0b45e5786e83d..8593d1faba264 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_driver_impl" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index a2ddff7183e60..ed5662da16dc9 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -7,6 +7,7 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(decl_macro)] @@ -16,7 +17,6 @@ #![feature(result_flattening)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cmp::max; diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 828a14e707c50..16d70af7e05d8 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -268,8 +268,7 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { let tcx = ex.tcx(); let f = |annotation: &dyn pprust_hir::PpAnn| { let sm = sess.source_map(); - let hir_map = tcx.hir(); - let attrs = |id| hir_map.attrs(id); + let attrs = |id| tcx.hir_attrs(id); pprust_hir::print_crate( sm, tcx.hir_root_module(), diff --git a/compiler/rustc_error_codes/Cargo.toml b/compiler/rustc_error_codes/Cargo.toml index de668b81b7e07..55b4e89905126 100644 --- a/compiler/rustc_error_codes/Cargo.toml +++ b/compiler/rustc_error_codes/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_error_codes" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md index efbfa0851a83f..909da368f2b6f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0094.md +++ b/compiler/rustc_error_codes/src/error_codes/E0094.md @@ -7,12 +7,8 @@ Erroneous code example: #![allow(internal_features)] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -fn size_of() -> usize // error: intrinsic has wrong number - // of type parameters -{ - loop {} -} +fn size_of() -> usize; // error: intrinsic has wrong number + // of type parameters ``` Please check that you provided the right number of type parameters @@ -24,9 +20,5 @@ Example: #![allow(internal_features)] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -fn size_of() -> usize // ok! -{ - loop {} -} +fn size_of() -> usize; // ok! ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0133.md b/compiler/rustc_error_codes/src/error_codes/E0133.md index 8ca3f03ce156f..854cca3d10ff2 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0133.md +++ b/compiler/rustc_error_codes/src/error_codes/E0133.md @@ -45,6 +45,7 @@ unsafe fn g() { ``` Linting against this is controlled via the `unsafe_op_in_unsafe_fn` lint, which -is `allow` by default but will be upgraded to `warn` in a future edition. +is `warn` by default in the 2024 edition and `allow` by default in earlier +editions. [unsafe-section]: https://doc.rust-lang.org/book/ch19-01-unsafe-rust.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index d4d26007aa50e..b9db807259728 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -3,7 +3,7 @@ A captured variable in a closure may not live long enough. Erroneous code example: ```compile_fail,E0373 -fn foo() -> Box u32> { +fn foo() -> Box u32> { let x = 0u32; Box::new(|y| x + y) } @@ -42,7 +42,7 @@ This approach moves (or copies, where possible) data into the closure, rather than taking references to it. For example: ``` -fn foo() -> Box u32> { +fn foo() -> Box u32> { let x = 0u32; Box::new(move |y| x + y) } diff --git a/compiler/rustc_error_codes/src/error_codes/E0374.md b/compiler/rustc_error_codes/src/error_codes/E0374.md index 6d7dc88823c99..63c243b54ff2a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0374.md +++ b/compiler/rustc_error_codes/src/error_codes/E0374.md @@ -1,5 +1,5 @@ -`CoerceUnsized` was implemented on a struct which does not contain a field with -an unsized type. +`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which does not +contain a field that is being unsized. Example of erroneous code: @@ -11,47 +11,20 @@ struct Foo { a: i32, } -// error: Struct `Foo` has no unsized fields that need `CoerceUnsized`. +// error: Struct `Foo` has no unsized fields that need to be coerced. impl CoerceUnsized> for Foo where T: CoerceUnsized {} ``` -An [unsized type][1] is any type where the compiler does not know the length or -alignment of at compile time. Any struct containing an unsized type is also -unsized. +`CoerceUnsized` is used to coerce structs that have a field that can be unsized, +like a custom `MyBox` being unsized to `MyBox`. `DispatchFromDyn` +is used to dispatch from `MyBox` to `MyBox` in a dyn-compatible +trait. -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait +If the struct doesn't have any fields of unsized types then there is no +meaningful way to implement `CoerceUnsized` or `DispatchFromDyn`, since +there is no coercion taking place. -`CoerceUnsized` is used to coerce one struct containing an unsized type -into another struct containing a different unsized type. If the struct -doesn't have any fields of unsized types then you don't need explicit -coercion to get the types you want. To fix this you can either -not try to implement `CoerceUnsized` or you can add a field that is -unsized to the struct. - -Example: - -``` -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -// We don't need to impl `CoerceUnsized` here. -struct Foo { - a: i32, -} - -// We add the unsized type field to the struct. -struct Bar { - a: i32, - b: T, -} - -// The struct has an unsized field so we can implement -// `CoerceUnsized` for it. -impl CoerceUnsized> for Bar - where T: CoerceUnsized {} -``` - -Note that `CoerceUnsized` is mainly used by smart pointers like `Box`, `Rc` -and `Arc` to be able to mark that they can coerce unsized types that they -are pointing at. +Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers +like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types +that they are pointing at. diff --git a/compiler/rustc_error_codes/src/error_codes/E0375.md b/compiler/rustc_error_codes/src/error_codes/E0375.md index 71e530571650b..7abb3b6afd02f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0375.md +++ b/compiler/rustc_error_codes/src/error_codes/E0375.md @@ -1,5 +1,5 @@ -`CoerceUnsized` was implemented on a struct which contains more than one field -with an unsized type. +`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which contains +more than one field that is being unsized. Erroneous code example: @@ -17,39 +17,14 @@ struct Foo { impl CoerceUnsized> for Foo {} ``` -A struct with more than one field containing an unsized type cannot implement -`CoerceUnsized`. This only occurs when you are trying to coerce one of the -types in your struct to another type in the struct. In this case we try to -impl `CoerceUnsized` from `T` to `U` which are both types that the struct -takes. An [unsized type][1] is any type that the compiler doesn't know the -length or alignment of at compile time. Any struct containing an unsized type -is also unsized. +`CoerceUnsized` is used to coerce structs that have a field that can be unsized, +like a custom `MyBox` being unsized to `MyBox`. `DispatchFromDyn` +is used to dispatch from `MyBox` to `MyBox` in a dyn-compatible +trait. -`CoerceUnsized` only allows for coercion from a structure with a single -unsized type field to another struct with a single unsized type field. -In fact Rust only allows for a struct to have one unsized type in a struct -and that unsized type must be the last field in the struct. So having two -unsized types in a single struct is not allowed by the compiler. To fix this -use only one field containing an unsized type in the struct and then use -multiple structs to manage each unsized type field you need. +If the struct has multiple fields that must be unsized, then the compiler has no +way to generate a valid implementation of `CoerceUnsized` or `DispatchFromDyn`. -Example: - -``` -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -struct Foo { - a: i32, - b: T, -} - -impl CoerceUnsized> for Foo - where T: CoerceUnsized {} - -fn coerce_foo, U>(t: T) -> Foo { - Foo { a: 12i32, b: t } // we use coercion to get the `Foo` type we need -} -``` - -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait +Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers +like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types +that they are pointing at. diff --git a/compiler/rustc_error_codes/src/error_codes/E0376.md b/compiler/rustc_error_codes/src/error_codes/E0376.md index 50de15bd30f09..5b564ec22fcb8 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0376.md +++ b/compiler/rustc_error_codes/src/error_codes/E0376.md @@ -1,8 +1,11 @@ -`CoerceUnsized` was implemented on something that isn't a struct. +#### Note: this error code is no longer emitted by the compiler. + +`CoerceUnsized` or `DispatchFromDyn` was implemented between two types that +are not structs. Erroneous code example: -```compile_fail,E0376 +```compile_fail,E0377 #![feature(coerce_unsized)] use std::ops::CoerceUnsized; @@ -14,33 +17,4 @@ struct Foo { impl CoerceUnsized for Foo {} ``` -`CoerceUnsized` can only be implemented for a struct. Unsized types are -already able to be coerced without an implementation of `CoerceUnsized` -whereas a struct containing an unsized type needs to know the unsized type -field it's containing is able to be coerced. An [unsized type][1] -is any type that the compiler doesn't know the length or alignment of at -compile time. Any struct containing an unsized type is also unsized. - -[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait - -The `CoerceUnsized` trait takes a struct type. Make sure the type you are -providing to `CoerceUnsized` is a struct with only the last field containing an -unsized type. - -Example: - -``` -#![feature(coerce_unsized)] -use std::ops::CoerceUnsized; - -struct Foo { - a: T, -} - -// The `Foo` is a struct so `CoerceUnsized` can be implemented -impl CoerceUnsized> for Foo where T: CoerceUnsized {} -``` - -Note that in Rust, structs can only contain an unsized type if the field -containing the unsized type is the last and only unsized type field in the -struct. +`CoerceUnsized` or `DispatchFromDyn` can only be implemented between structs. diff --git a/compiler/rustc_error_codes/src/error_codes/E0377.md b/compiler/rustc_error_codes/src/error_codes/E0377.md index b1d36406332bd..cd2b26260a8af 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0377.md +++ b/compiler/rustc_error_codes/src/error_codes/E0377.md @@ -1,5 +1,5 @@ -The trait `CoerceUnsized` may only be implemented for a coercion between -structures with the same definition. +`CoerceUnsized` or `DispatchFromDyn` may only be implemented between structs +of the same type. Example of erroneous code: @@ -20,10 +20,15 @@ pub struct Bar { impl CoerceUnsized> for Foo where T: CoerceUnsized {} ``` -When attempting to implement `CoerceUnsized`, the `impl` signature must look -like: `impl CoerceUnsized> for Type where T: CoerceUnsized`; -the *implementer* and *`CoerceUnsized` type parameter* must be the same -type. In this example, `Bar` and `Foo` (even though structurally identical) -are *not* the same type and are rejected. Learn more about the `CoerceUnsized` -trait and DST coercion in -[the `CoerceUnsized` docs](../std/ops/trait.CoerceUnsized.html). +`CoerceUnsized` is used to coerce structs that have a field that can be unsized, +like a custom `MyBox` being unsized to `MyBox`. `DispatchFromDyn` +is used to dispatch from `MyBox` to `MyBox` in a dyn-compatible +trait. + +The compiler cannot support coercions between structs of different types, so +a valid implementation of `CoerceUnsized` or `DispatchFromDyn` should be +implemented between the same struct with different generic parameters. + +Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers +like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types +that they are pointing at. diff --git a/compiler/rustc_error_codes/src/error_codes/E0792.md b/compiler/rustc_error_codes/src/error_codes/E0792.md index 5e3dcc4aa7277..033e1c65192ba 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0792.md +++ b/compiler/rustc_error_codes/src/error_codes/E0792.md @@ -7,6 +7,7 @@ This means type Foo = impl std::fmt::Debug; +#[define_opaque(Foo)] fn foo() -> Foo { 5u32 } @@ -19,6 +20,7 @@ is not accepted. If it were accepted, one could create unsound situations like type Foo = impl Default; +#[define_opaque(Foo)] fn foo() -> Foo { 5u32 } @@ -36,6 +38,7 @@ Instead you need to make the function generic: type Foo = impl std::fmt::Debug; +#[define_opaque(Foo)] fn foo() -> Foo { 5u32 } @@ -56,6 +59,7 @@ use std::fmt::Debug; type Foo = impl Debug; +#[define_opaque(Foo)] fn foo() -> Foo { Vec::::new() } diff --git a/compiler/rustc_error_codes/src/error_codes/E0804.md b/compiler/rustc_error_codes/src/error_codes/E0804.md new file mode 100644 index 0000000000000..9a6937c0b52e0 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0804.md @@ -0,0 +1,41 @@ +An auto trait cannot be added to the bounds of a `dyn Trait` type via +a pointer cast. + +Erroneous code example: + +```rust,edition2021,compile_fail,E0804 +let ptr: *const dyn core::any::Any = &(); +_ = ptr as *const (dyn core::any::Any + Send); +``` + +Adding an auto trait can make the vtable invalid, potentially causing +UB in safe code afterwards. For example: + +```rust,edition2021,no_run +use core::{mem::transmute, ptr::NonNull}; + +trait Trait { + fn f(&self) + where + Self: Send; +} + +impl Trait for NonNull<()> { + fn f(&self) { + unreachable!() + } +} + +fn main() { + let unsend: &dyn Trait = &NonNull::dangling(); + let bad: &(dyn Trait + Send) = unsafe { transmute(unsend) }; + // This crashes, since the vtable for `NonNull as dyn Trait` does + // not have an entry for `Trait::f`. + bad.f(); +} +``` + +To fix this error, you can use `transmute` rather than pointer casts, +but you must ensure that the vtable is valid for the pointer's type +before calling a method on the trait object or allowing other code to +do so. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 098ca42be2b44..dfeef5a957d69 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -6,7 +6,6 @@ #![deny(rustdoc::invalid_codeblock_attributes)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end // This higher-order macro defines the error codes that are in use. It is used @@ -547,6 +546,7 @@ E0800: 0800, E0801: 0801, E0802: 0802, E0803: 0803, +E0804: 0804, ); ) } diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 6974c12f994b1..578af7fc51d40 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_error_messages" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index ba1c3e185c2d9..39e78ae88416e 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -4,7 +4,6 @@ #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(type_alias_impl_trait)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::borrow::Cow; @@ -107,8 +106,8 @@ impl From> for TranslationBundleError { /// (overriding any conflicting messages). #[instrument(level = "trace")] pub fn fluent_bundle( - mut user_provided_sysroot: Option, - mut sysroot_candidates: Vec, + sysroot: PathBuf, + sysroot_candidates: Vec, requested_locale: Option, additional_ftl_path: Option<&Path>, with_directionality_markers: bool, @@ -142,7 +141,7 @@ pub fn fluent_bundle( // If the user requests the default locale then don't try to load anything. if let Some(requested_locale) = requested_locale { let mut found_resources = false; - for sysroot in user_provided_sysroot.iter_mut().chain(sysroot_candidates.iter_mut()) { + for mut sysroot in Some(sysroot).into_iter().chain(sysroot_candidates.into_iter()) { sysroot.push("share"); sysroot.push("locale"); sysroot.push(requested_locale.to_string()); @@ -209,6 +208,7 @@ pub type LazyFallbackBundle = Arc Fluent /// Return the default `FluentBundle` with standard "en-US" diagnostic messages. #[instrument(level = "trace", skip(resources))] +#[cfg_attr(not(bootstrap), define_opaque(LazyFallbackBundle))] pub fn fallback_fluent_bundle( resources: Vec<&'static str>, with_directionality_markers: bool, diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 434f8c1c76751..b11793c190a14 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_errors" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -10,6 +10,7 @@ derive_setters = "0.1.6" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 29a74ed3f4e48..9f4d2ea5c1ad6 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -148,11 +148,17 @@ where /// converted rather than on `DiagArgValue`, which enables types from other `rustc_*` crates to /// implement this. pub trait IntoDiagArg { - fn into_diag_arg(self) -> DiagArgValue; + /// Convert `Self` into a `DiagArgValue` suitable for rendering in a diagnostic. + /// + /// It takes a `path` where "long values" could be written to, if the `DiagArgValue` is too big + /// for displaying on the terminal. This path comes from the `Diag` itself. When rendering + /// values that come from `TyCtxt`, like `Ty<'_>`, they can use `TyCtxt::short_string`. If a + /// value has no shortening logic that could be used, the argument can be safely ignored. + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue; } impl IntoDiagArg for DiagArgValue { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { self } } @@ -395,7 +401,7 @@ impl DiagInner { } pub(crate) fn arg(&mut self, name: impl Into, arg: impl IntoDiagArg) { - self.args.insert(name.into(), arg.into_diag_arg()); + self.args.insert(name.into(), arg.into_diag_arg(&mut self.long_ty_path)); } /// Fields used for Hash, and PartialEq trait. @@ -484,7 +490,7 @@ pub struct Diag<'a, G: EmissionGuarantee = ErrorGuaranteed> { // would be bad. impl !Clone for Diag<'_, G> {} -rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * std::mem::size_of::()); +rustc_data_structures::static_assert_size!(Diag<'_, ()>, 3 * size_of::()); impl Deref for Diag<'_, G> { type Target = DiagInner; diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index 7f383946c1463..cb2e1769fa1cf 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -8,6 +8,7 @@ use std::process::ExitStatus; use rustc_abi::TargetDataLayoutErrors; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast_pretty::pprust; +use rustc_attr_data_structures::RustcVersion; use rustc_macros::Subdiagnostic; use rustc_span::edition::Edition; use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol}; @@ -24,8 +25,8 @@ use crate::{ pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display); impl IntoDiagArg for DiagArgFromDisplay<'_> { - fn into_diag_arg(self) -> DiagArgValue { - self.0.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.0.to_string().into_diag_arg(path) } } @@ -42,8 +43,8 @@ impl<'a, T: fmt::Display> From<&'a T> for DiagArgFromDisplay<'a> { } impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T { - fn into_diag_arg(self) -> DiagArgValue { - self.clone().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.clone().into_diag_arg(path) } } @@ -52,8 +53,8 @@ macro_rules! into_diag_arg_using_display { ($( $ty:ty ),+ $(,)?) => { $( impl IntoDiagArg for $ty { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.to_string().into_diag_arg(path) } } )+ @@ -64,13 +65,13 @@ macro_rules! into_diag_arg_for_number { ($( $ty:ty ),+ $(,)?) => { $( impl IntoDiagArg for $ty { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { // Convert to a string if it won't fit into `Number`. #[allow(irrefutable_let_patterns)] if let Ok(n) = TryInto::::try_into(self) { DiagArgValue::Number(n) } else { - self.to_string().into_diag_arg() + self.to_string().into_diag_arg(path) } } } @@ -96,27 +97,33 @@ into_diag_arg_using_display!( rustc_abi::ExternAbi, ); +impl IntoDiagArg for RustcVersion { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { + DiagArgValue::Str(Cow::Owned(self.to_string())) + } +} + impl IntoDiagArg for rustc_type_ir::TraitRef { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.to_string().into_diag_arg(path) } } impl IntoDiagArg for rustc_type_ir::ExistentialTraitRef { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.to_string().into_diag_arg(path) } } impl IntoDiagArg for rustc_type_ir::UnevaluatedConst { - fn into_diag_arg(self) -> DiagArgValue { - format!("{self:?}").into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + format!("{self:?}").into_diag_arg(path) } } impl IntoDiagArg for rustc_type_ir::FnSig { - fn into_diag_arg(self) -> DiagArgValue { - format!("{self:?}").into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + format!("{self:?}").into_diag_arg(path) } } @@ -124,15 +131,15 @@ impl IntoDiagArg for rustc_type_ir::Binder where T: IntoDiagArg, { - fn into_diag_arg(self) -> DiagArgValue { - self.skip_binder().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.skip_binder().into_diag_arg(path) } } into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl IntoDiagArg for bool { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { if self { DiagArgValue::Str(Cow::Borrowed("true")) } else { @@ -142,13 +149,13 @@ impl IntoDiagArg for bool { } impl IntoDiagArg for char { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(format!("{self:?}"))) } } impl IntoDiagArg for Vec { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::StrListSepByAnd( self.into_iter().map(|c| Cow::Owned(format!("{c:?}"))).collect(), ) @@ -156,49 +163,49 @@ impl IntoDiagArg for Vec { } impl IntoDiagArg for Symbol { - fn into_diag_arg(self) -> DiagArgValue { - self.to_ident_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.to_ident_string().into_diag_arg(path) } } impl<'a> IntoDiagArg for &'a str { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> DiagArgValue { + self.to_string().into_diag_arg(path) } } impl IntoDiagArg for String { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self)) } } impl<'a> IntoDiagArg for Cow<'a, str> { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.into_owned())) } } impl<'a> IntoDiagArg for &'a Path { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.display().to_string())) } } impl IntoDiagArg for PathBuf { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.display().to_string())) } } impl IntoDiagArg for PanicStrategy { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.desc().to_string())) } } impl IntoDiagArg for hir::ConstContext { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(match self { hir::ConstContext::ConstFn => "const_fn", hir::ConstContext::Static(_) => "static", @@ -208,49 +215,49 @@ impl IntoDiagArg for hir::ConstContext { } impl IntoDiagArg for ast::Expr { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(pprust::expr_to_string(&self))) } } impl IntoDiagArg for ast::Path { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(pprust::path_to_string(&self))) } } impl IntoDiagArg for ast::token::Token { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(pprust::token_to_string(&self)) } } impl IntoDiagArg for ast::token::TokenKind { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(pprust::token_kind_to_string(&self)) } } impl IntoDiagArg for FloatTy { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(self.name_str())) } } impl IntoDiagArg for std::ffi::CString { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned())) } } impl IntoDiagArg for rustc_data_structures::small_c_str::SmallCStr { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(self.to_string_lossy().into_owned())) } } impl IntoDiagArg for ast::Visibility { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { let s = pprust::vis_to_string(&self); let s = s.trim_end().to_string(); DiagArgValue::Str(Cow::Owned(s)) @@ -258,49 +265,49 @@ impl IntoDiagArg for ast::Visibility { } impl IntoDiagArg for rustc_lint_defs::Level { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(self.to_cmd_flag())) } } impl IntoDiagArg for hir::def::Res { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(self.descr())) } } impl IntoDiagArg for DiagLocation { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::from(self.to_string())) } } impl IntoDiagArg for Backtrace { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::from(self.to_string())) } } impl IntoDiagArg for Level { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::from(self.to_string())) } } impl IntoDiagArg for ClosureKind { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(self.as_str().into()) } } impl IntoDiagArg for hir::def::Namespace { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(self.descr())) } } impl IntoDiagArg for ExprPrecedence { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Number(self as i32) } } @@ -321,7 +328,7 @@ impl FromIterator for DiagSymbolList { } impl IntoDiagArg for DiagSymbolList { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::StrListSepByAnd( self.0.into_iter().map(|sym| Cow::Owned(format!("`{sym}`"))).collect(), ) diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index f7f842393084b..fe01e289334cc 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -113,24 +113,11 @@ impl Margin { self.computed_left > 0 } - fn was_cut_right(&self, line_len: usize) -> bool { - let right = - if self.computed_right == self.span_right || self.computed_right == self.label_right { - // FIXME: This comment refers to the only callsite of this method. - // Rephrase it or refactor it, so it can stand on its own. - // Account for the "..." padding given above. Otherwise we end up with code lines - // that do fit but end in "..." as if they were trimmed. - // FIXME: Don't hard-code this offset. Is this meant to represent - // `2 * str_width(self.margin())`? - self.computed_right - 6 - } else { - self.computed_right - }; - right < line_len && self.computed_left + self.column_width < line_len - } - fn compute(&mut self, max_line_len: usize) { // When there's a lot of whitespace (>20), we want to trim it as it is useless. + // FIXME: this doesn't account for '\t', but to do so correctly we need to perform that + // calculation later, right before printing in order to be accurate with both unicode + // handling and trimming of long lines. self.computed_left = if self.whitespace_left > 20 { self.whitespace_left - 16 // We want some padding. } else { @@ -310,7 +297,9 @@ pub trait Emitter: Translate { // are some which do actually involve macros. ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None, - ExpnKind::Macro(macro_kind, name) => Some((macro_kind, name)), + ExpnKind::Macro(macro_kind, name) => { + Some((macro_kind, name, expn_data.hide_backtrace)) + } } }) .collect(); @@ -322,13 +311,17 @@ pub trait Emitter: Translate { self.render_multispans_macro_backtrace(span, children, backtrace); if !backtrace { - if let Some((macro_kind, name)) = has_macro_spans.first() { + // Skip builtin macros, as their expansion isn't relevant to the end user. This includes + // actual intrinsics, like `asm!`. + if let Some((macro_kind, name, _)) = has_macro_spans.first() + && let Some((_, _, false)) = has_macro_spans.last() + { // Mark the actual macro this originates from - let and_then = if let Some((macro_kind, last_name)) = has_macro_spans.last() + let and_then = if let Some((macro_kind, last_name, _)) = has_macro_spans.last() && last_name != name { let descr = macro_kind.descr(); - format!(" which comes from the expansion of the {descr} `{last_name}`",) + format!(" which comes from the expansion of the {descr} `{last_name}`") } else { "".to_string() }; @@ -616,7 +609,6 @@ pub struct HumanEmitter { #[setters(skip)] fallback_bundle: LazyFallbackBundle, short_message: bool, - teach: bool, ui_testing: bool, ignored_directories_in_source_blocks: Vec, diagnostic_width: Option, @@ -642,7 +634,6 @@ impl HumanEmitter { fluent_bundle: None, fallback_bundle, short_message: false, - teach: false, ui_testing: false, ignored_directories_in_source_blocks: Vec::new(), diagnostic_width: None, @@ -670,43 +661,43 @@ impl HumanEmitter { width_offset: usize, code_offset: usize, margin: Margin, - ) { - // Tabs are assumed to have been replaced by spaces in calling code. - debug_assert!(!source_string.contains('\t')); + ) -> usize { let line_len = source_string.len(); // Create the source line we will highlight. let left = margin.left(line_len); let right = margin.right(line_len); // FIXME: The following code looks fishy. See #132860. // On long lines, we strip the source line, accounting for unicode. - let mut taken = 0; let code: String = source_string .chars() - .skip(left) - .take_while(|ch| { - // Make sure that the trimming on the right will fall within the terminal width. - let next = char_width(*ch); - if taken + next > right - left { - return false; - } - taken += next; - true - }) + .enumerate() + .skip_while(|(i, _)| *i < left) + .take_while(|(i, _)| *i < right) + .map(|(_, c)| c) .collect(); + let code = normalize_whitespace(&code); + let was_cut_right = + source_string.chars().enumerate().skip_while(|(i, _)| *i < right).next().is_some(); buffer.puts(line_offset, code_offset, &code, Style::Quotation); let placeholder = self.margin(); if margin.was_cut_left() { // We have stripped some code/whitespace from the beginning, make it clear. buffer.puts(line_offset, code_offset, placeholder, Style::LineNumber); } - if margin.was_cut_right(line_len) { + if was_cut_right { let padding = str_width(placeholder); // We have stripped some code after the rightmost span end, make it clear we did so. - buffer.puts(line_offset, code_offset + taken - padding, placeholder, Style::LineNumber); + buffer.puts( + line_offset, + code_offset + str_width(&code) - padding, + placeholder, + Style::LineNumber, + ); } buffer.puts(line_offset, 0, &self.maybe_anonymized(line_index), Style::LineNumber); self.draw_col_separator_no_space(buffer, line_offset, width_offset - 2); + left } #[instrument(level = "trace", skip(self), ret)] @@ -738,22 +729,16 @@ impl HumanEmitter { return Vec::new(); } - let source_string = match file.get_line(line.line_index - 1) { - Some(s) => normalize_whitespace(&s), - None => return Vec::new(), + let Some(source_string) = file.get_line(line.line_index - 1) else { + return Vec::new(); }; trace!(?source_string); let line_offset = buffer.num_lines(); - // Left trim - let left = margin.left(source_string.len()); - + // Left trim. // FIXME: This looks fishy. See #132860. - // Account for unicode characters of width !=0 that were removed. - let left = source_string.chars().take(left).map(|ch| char_width(ch)).sum(); - - self.draw_line( + let left = self.draw_line( buffer, &source_string, line.line_index, @@ -784,7 +769,7 @@ impl HumanEmitter { let mut short_start = true; for ann in &line.annotations { if let AnnotationType::MultilineStart(depth) = ann.annotation_type { - if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) { + if source_string.chars().take(ann.start_col.file).all(|c| c.is_whitespace()) { let uline = self.underline(ann.is_primary); let chr = uline.multiline_whole_line; annotations.push((depth, uline.style)); @@ -903,11 +888,16 @@ impl HumanEmitter { // | x_span // // + let mut overlap = vec![false; annotations.len()]; let mut annotations_position = vec![]; let mut line_len: usize = 0; let mut p = 0; for (i, annotation) in annotations.iter().enumerate() { for (j, next) in annotations.iter().enumerate() { + if overlaps(next, annotation, 0) && j > i { + overlap[i] = true; + overlap[j] = true; + } if overlaps(next, annotation, 0) // This label overlaps with another one and both && annotation.has_label() // take space (they have text and are not && j > i // multiline lines). @@ -1035,24 +1025,21 @@ impl HumanEmitter { let pos = pos + 1; match annotation.annotation_type { AnnotationType::MultilineStart(depth) | AnnotationType::MultilineEnd(depth) => { + let pre: usize = source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); self.draw_range( buffer, underline.multiline_horizontal, line_offset + pos, width_offset + depth, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset + pre, underline.style, ); } - _ if self.teach => { - buffer.set_style_range( - line_offset, - (code_offset + annotation.start_col.display).saturating_sub(left), - (code_offset + annotation.end_col.display).saturating_sub(left), - underline.style, - annotation.is_primary, - ); - } _ => {} } } @@ -1072,11 +1059,18 @@ impl HumanEmitter { let underline = self.underline(annotation.is_primary); let pos = pos + 1; + let code_offset = code_offset + + source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum::(); if pos > 1 && (annotation.has_label() || annotation.takes_space()) { for p in line_offset + 1..=line_offset + pos { buffer.putc( p, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineLine(_) => underline.multiline_vertical, _ => underline.vertical_text_line, @@ -1087,7 +1081,7 @@ impl HumanEmitter { if let AnnotationType::MultilineStart(_) = annotation.annotation_type { buffer.putc( line_offset + pos, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, underline.bottom_right, underline.style, ); @@ -1097,7 +1091,7 @@ impl HumanEmitter { { buffer.putc( line_offset + pos, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, underline.multiline_bottom_right_with_text, underline.style, ); @@ -1155,13 +1149,30 @@ impl HumanEmitter { let style = if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; let (pos, col) = if pos == 0 { - if annotation.end_col.display == 0 { - (pos + 1, (annotation.end_col.display + 2).saturating_sub(left)) + let pre: usize = source_string + .chars() + .take(annotation.end_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); + if annotation.end_col.file == 0 { + (pos + 1, (pre + 2)) } else { - (pos + 1, (annotation.end_col.display + 1).saturating_sub(left)) + let pad = if annotation.end_col.file - annotation.start_col.file == 0 { + 2 + } else { + 1 + }; + (pos + 1, (pre + pad)) } } else { - (pos + 2, annotation.start_col.display.saturating_sub(left)) + let pre: usize = source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum(); + (pos + 2, pre) }; if let Some(ref label) = annotation.label { buffer.puts(line_offset + pos, code_offset + col, label, style); @@ -1194,14 +1205,35 @@ impl HumanEmitter { // | _^ test for &(pos, annotation) in &annotations_position { let uline = self.underline(annotation.is_primary); - for p in annotation.start_col.display..annotation.end_col.display { + let width = annotation.end_col.file - annotation.start_col.file; + let previous: String = + source_string.chars().take(annotation.start_col.file).skip(left).collect(); + let underlined: String = + source_string.chars().skip(annotation.start_col.file).take(width).collect(); + debug!(?previous, ?underlined); + let code_offset = code_offset + + source_string + .chars() + .take(annotation.start_col.file) + .skip(left) + .map(|c| char_width(c)) + .sum::(); + let ann_width: usize = source_string + .chars() + .skip(annotation.start_col.file) + .take(width) + .map(|c| char_width(c)) + .sum(); + let ann_width = if ann_width == 0 + && matches!(annotation.annotation_type, AnnotationType::Singleline) + { + 1 + } else { + ann_width + }; + for p in 0..ann_width { // The default span label underline. - buffer.putc( - line_offset + 1, - (code_offset + p).saturating_sub(left), - uline.underline, - uline.style, - ); + buffer.putc(line_offset + 1, code_offset + p, uline.underline, uline.style); } if pos == 0 @@ -1213,7 +1245,7 @@ impl HumanEmitter { // The beginning of a multiline span with its leftward moving line on the same line. buffer.putc( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineStart(_) => uline.top_right_flat, AnnotationType::MultilineEnd(_) => uline.multiline_end_same_line, @@ -1231,7 +1263,7 @@ impl HumanEmitter { // so we start going down first. buffer.putc( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), + code_offset, match annotation.annotation_type { AnnotationType::MultilineStart(_) => uline.multiline_start_down, AnnotationType::MultilineEnd(_) => uline.multiline_end_up, @@ -1241,11 +1273,37 @@ impl HumanEmitter { ); } else if pos != 0 && annotation.has_label() { // The beginning of a span label with an actual label, we'll point down. - buffer.putc( + buffer.putc(line_offset + 1, code_offset, uline.label_start, uline.style); + } + } + + // We look for individual *long* spans, and we trim the *middle*, so that we render + // LL | ...= [0, 0, 0, ..., 0, 0]; + // | ^^^^^^^^^^...^^^^^^^ expected `&[u8]`, found `[{integer}; 1680]` + for (i, (_pos, annotation)) in annotations_position.iter().enumerate() { + // Skip cases where multiple spans overlap each other. + if overlap[i] { + continue; + }; + let AnnotationType::Singleline = annotation.annotation_type else { continue }; + let width = annotation.end_col.display - annotation.start_col.display; + if width > margin.column_width * 2 && width > 10 { + // If the terminal is *too* small, we keep at least a tiny bit of the span for + // display. + let pad = max(margin.column_width / 3, 5); + // Code line + buffer.replace( + line_offset, + annotation.start_col.file + pad, + annotation.end_col.file - pad, + self.margin(), + ); + // Underline line + buffer.replace( line_offset + 1, - (code_offset + annotation.start_col.display).saturating_sub(left), - uline.label_start, - uline.style, + annotation.start_col.file + pad, + annotation.end_col.file - pad, + self.margin(), ); } } @@ -1702,17 +1760,11 @@ impl HumanEmitter { // non-rustc_lexer::is_whitespace() chars are reported as an // error (ex. no-break-spaces \u{a0}), and thus can't be considered // for removal during error reporting. + // FIXME: doesn't account for '\t' properly. let leading_whitespace = source_string .chars() .take_while(|c| rustc_lexer::is_whitespace(*c)) - .map(|c| { - match c { - // Tabs are displayed as 4 spaces - '\t' => 4, - _ => 1, - } - }) - .sum(); + .count(); if source_string.chars().any(|c| !rustc_lexer::is_whitespace(c)) { whitespace_margin = min(whitespace_margin, leading_whitespace); } @@ -1726,8 +1778,8 @@ impl HumanEmitter { let mut span_left_margin = usize::MAX; for line in &annotated_file.lines { for ann in &line.annotations { - span_left_margin = min(span_left_margin, ann.start_col.display); - span_left_margin = min(span_left_margin, ann.end_col.display); + span_left_margin = min(span_left_margin, ann.start_col.file); + span_left_margin = min(span_left_margin, ann.end_col.file); } } if span_left_margin == usize::MAX { @@ -1747,12 +1799,12 @@ impl HumanEmitter { .map_or(0, |s| s.len()), ); for ann in &line.annotations { - span_right_margin = max(span_right_margin, ann.start_col.display); - span_right_margin = max(span_right_margin, ann.end_col.display); + span_right_margin = max(span_right_margin, ann.start_col.file); + span_right_margin = max(span_right_margin, ann.end_col.file); // FIXME: account for labels not in the same line let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1); label_right_margin = - max(label_right_margin, ann.end_col.display + label_right); + max(label_right_margin, ann.end_col.file + label_right); } } @@ -1763,15 +1815,7 @@ impl HumanEmitter { width_offset + annotated_file.multiline_depth + 1 }; - let column_width = if let Some(width) = self.diagnostic_width { - width.saturating_sub(code_offset) - } else if self.ui_testing || cfg!(miri) { - DEFAULT_COLUMN_WIDTH - } else { - termize::dimensions() - .map(|(w, _)| w.saturating_sub(code_offset)) - .unwrap_or(DEFAULT_COLUMN_WIDTH) - }; + let column_width = self.column_width(code_offset); let margin = Margin::new( whitespace_margin, @@ -1928,6 +1972,18 @@ impl HumanEmitter { Ok(()) } + fn column_width(&self, code_offset: usize) -> usize { + if let Some(width) = self.diagnostic_width { + width.saturating_sub(code_offset) + } else if self.ui_testing || cfg!(miri) { + DEFAULT_COLUMN_WIDTH + } else { + termize::dimensions() + .map(|(w, _)| w.saturating_sub(code_offset)) + .unwrap_or(DEFAULT_COLUMN_WIDTH) + } + } + fn emit_suggestion_default( &mut self, span: &MultiSpan, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index ceed0cd94fc91..80e43ede4453a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -14,8 +14,8 @@ #![feature(associated_type_defaults)] #![feature(box_into_inner)] #![feature(box_patterns)] +#![feature(default_field_values)] #![feature(error_reporter)] -#![feature(extract_if)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(negative_impls)] @@ -25,7 +25,6 @@ #![feature(trait_alias)] #![feature(try_blocks)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate self as rustc_errors; @@ -627,7 +626,6 @@ pub enum StashKey { MaybeFruTypo, CallAssocMethod, AssociatedTypeSuggestion, - MaybeForgetReturn, /// Query cycle detected, stashing in favor of a better error. Cycle, UndeterminedMacroResolution, diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs index 7a991a2ace71b..f02387d833595 100644 --- a/compiler/rustc_errors/src/markdown/parse.rs +++ b/compiler/rustc_errors/src/markdown/parse.rs @@ -40,11 +40,13 @@ type ParseResult<'a> = Option>; /// Parsing context #[derive(Clone, Copy, Debug, PartialEq)] +// The default values are the most common setting for non top-level parsing: not top block, not at +// line start (yes leading whitespace, not escaped). struct Context { /// If true, we are at a the topmost level (not recursing a nested tt) - top_block: bool, + top_block: bool = false, /// Previous character - prev: Prev, + prev: Prev = Prev::Whitespace, } /// Character class preceding this one @@ -57,14 +59,6 @@ enum Prev { Any, } -impl Default for Context { - /// Most common setting for non top-level parsing: not top block, not at - /// line start (yes leading whitespace, not escaped) - fn default() -> Self { - Self { top_block: false, prev: Prev::Whitespace } - } -} - /// Flags to simple parser function #[derive(Clone, Copy, Debug, PartialEq)] enum ParseOpt { @@ -248,7 +242,7 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> { } let (txt, rest) = parse_to_newline(&buf[1..]); - let ctx = Context { top_block: false, prev: Prev::Whitespace }; + let ctx = Context { .. }; let stream = parse_recursive(txt, ctx); Some((MdTree::Heading(level.try_into().unwrap(), stream), rest)) @@ -257,7 +251,7 @@ fn parse_heading(buf: &[u8]) -> ParseResult<'_> { /// Bulleted list fn parse_unordered_li(buf: &[u8]) -> Parsed<'_> { let (txt, rest) = get_indented_section(&buf[2..]); - let ctx = Context { top_block: false, prev: Prev::Whitespace }; + let ctx = Context { .. }; let stream = parse_recursive(trim_ascii_start(txt), ctx); (MdTree::UnorderedListItem(stream), rest) } @@ -266,7 +260,7 @@ fn parse_unordered_li(buf: &[u8]) -> Parsed<'_> { fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> { let (num, pos) = ord_list_start(buf).unwrap(); // success tested in caller let (txt, rest) = get_indented_section(&buf[pos..]); - let ctx = Context { top_block: false, prev: Prev::Whitespace }; + let ctx = Context { .. }; let stream = parse_recursive(trim_ascii_start(txt), ctx); (MdTree::OrderedListItem(num, stream), rest) } diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs index 5ca9e9b18f341..790efd0286e9d 100644 --- a/compiler/rustc_errors/src/styled_buffer.rs +++ b/compiler/rustc_errors/src/styled_buffer.rs @@ -89,6 +89,19 @@ impl StyledBuffer { } } + pub(crate) fn replace(&mut self, line: usize, start: usize, end: usize, string: &str) { + if start == end { + return; + } + if start > self.lines[line].len() || end > self.lines[line].len() { + return; + } + let _ = self.lines[line].drain(start..(end - string.chars().count())); + for (i, c) in string.chars().enumerate() { + self.lines[line][start + i] = StyledChar::new(c, Style::LineNumber); + } + } + /// For given `line` inserts `string` with `style` before old content of that line, /// adding lines if needed pub(crate) fn prepend(&mut self, line: usize, string: &str, style: Style) { diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml index eb93972387d40..0ba139ea5cc57 100644 --- a/compiler/rustc_expand/Cargo.toml +++ b/compiler/rustc_expand/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_expand" version = "0.0.0" -edition = "2021" +edition = "2024" build = false [lib] @@ -17,6 +17,7 @@ rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } +rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } rustc_macros = { path = "../rustc_macros" } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 819694d1cdc1f..c4b5396258444 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -7,18 +7,19 @@ use std::sync::Arc; use rustc_ast::attr::{AttributeExt, MarkedAttrs}; use rustc_ast::ptr::P; -use rustc_ast::token::Nonterminal; +use rustc_ast::token::MetaVarKind; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; -use rustc_attr_parsing::{self as attr, Deprecation, Stability}; +use rustc_attr_parsing::{AttributeKind, Deprecation, Stability, find_attr}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; +use rustc_hir as hir; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_parse::MACRO_ARGUMENTS; -use rustc_parse::parser::Parser; +use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::parse::ParseSess; use rustc_session::{Limit, Session}; @@ -52,6 +53,7 @@ pub enum Annotatable { Param(ast::Param), FieldDef(ast::FieldDef), Variant(ast::Variant), + WherePredicate(ast::WherePredicate), Crate(ast::Crate), } @@ -70,6 +72,7 @@ impl Annotatable { Annotatable::Param(p) => p.span, Annotatable::FieldDef(sf) => sf.span, Annotatable::Variant(v) => v.span, + Annotatable::WherePredicate(wp) => wp.span, Annotatable::Crate(c) => c.spans.inner_span, } } @@ -88,6 +91,7 @@ impl Annotatable { Annotatable::Param(p) => p.visit_attrs(f), Annotatable::FieldDef(sf) => sf.visit_attrs(f), Annotatable::Variant(v) => v.visit_attrs(f), + Annotatable::WherePredicate(wp) => wp.visit_attrs(f), Annotatable::Crate(c) => c.visit_attrs(f), } } @@ -106,6 +110,7 @@ impl Annotatable { Annotatable::Param(p) => visitor.visit_param(p), Annotatable::FieldDef(sf) => visitor.visit_field_def(sf), Annotatable::Variant(v) => visitor.visit_variant(v), + Annotatable::WherePredicate(wp) => visitor.visit_where_predicate(wp), Annotatable::Crate(c) => visitor.visit_crate(c), } } @@ -127,6 +132,7 @@ impl Annotatable { | Annotatable::Param(..) | Annotatable::FieldDef(..) | Annotatable::Variant(..) + | Annotatable::WherePredicate(..) | Annotatable::Crate(..) => panic!("unexpected annotatable"), } } @@ -222,6 +228,13 @@ impl Annotatable { } } + pub fn expect_where_predicate(self) -> ast::WherePredicate { + match self { + Annotatable::WherePredicate(wp) => wp, + _ => panic!("expected where predicate"), + } + } + pub fn expect_crate(self) -> ast::Crate { match self { Annotatable::Crate(krate) => krate, @@ -445,6 +458,10 @@ pub trait MacResult { None } + fn make_where_predicates(self: Box) -> Option> { + None + } + fn make_crate(self: Box) -> Option { // Fn-like macros cannot produce a crate. unreachable!() @@ -838,19 +855,23 @@ impl SyntaxExtension { /// and other properties converted from attributes. pub fn new( sess: &Session, - features: &Features, kind: SyntaxExtensionKind, span: Span, helper_attrs: Vec, edition: Edition, name: Symbol, - attrs: &[impl AttributeExt], + attrs: &[hir::Attribute], is_local: bool, ) -> SyntaxExtension { let allow_internal_unstable = - rustc_attr_parsing::allow_internal_unstable(sess, attrs).collect::>(); + find_attr!(attrs, AttributeKind::AllowInternalUnstable(i) => i) + .map(|i| i.as_slice()) + .unwrap_or_default(); + // FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style + // let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe); + let allow_internal_unsafe = + ast::attr::find_by_name(attrs, sym::allow_internal_unsafe).is_some(); - let allow_internal_unsafe = ast::attr::contains_name(attrs, sym::allow_internal_unsafe); let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export) .and_then(|macro_export| macro_export.meta_item_list()) .is_some_and(|l| ast::attr::list_contains_name(&l, sym::local_inner_macros)); @@ -867,16 +888,17 @@ impl SyntaxExtension { ) }) .unwrap_or_else(|| (None, helper_attrs)); - let stability = attr::find_stability(sess, attrs, span); - let const_stability = attr::find_const_stability(sess, attrs, span); - let body_stability = attr::find_body_stability(sess, attrs); - if let Some((_, sp)) = const_stability { + + let stability = find_attr!(attrs, AttributeKind::Stability { stability, .. } => *stability); + + // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem + if let Some(sp) = find_attr!(attrs, AttributeKind::ConstStability { span, .. } => *span) { sess.dcx().emit_err(errors::MacroConstStability { span: sp, head_span: sess.source_map().guess_head_span(span), }); } - if let Some((_, sp)) = body_stability { + if let Some(sp) = find_attr!(attrs, AttributeKind::BodyStability{ span, .. } => *span) { sess.dcx().emit_err(errors::MacroBodyStability { span: sp, head_span: sess.source_map().guess_head_span(span), @@ -887,9 +909,13 @@ impl SyntaxExtension { kind, span, allow_internal_unstable: (!allow_internal_unstable.is_empty()) - .then(|| allow_internal_unstable.into()), - stability: stability.map(|(s, _)| s), - deprecation: attr::find_deprecation(sess, features, attrs).map(|(d, _)| d), + // FIXME(jdonszelmann): avoid the into_iter/collect? + .then(|| allow_internal_unstable.iter().map(|i| i.0).collect::>().into()), + stability, + deprecation: find_attr!( + attrs, + AttributeKind::Deprecation { deprecation, .. } => *deprecation + ), helper_attrs, edition, builtin_name, @@ -977,6 +1003,7 @@ impl SyntaxExtension { self.allow_internal_unsafe, self.local_inner_macros, self.collapse_debuginfo, + self.builtin_name.is_some(), ) } } @@ -1382,13 +1409,13 @@ pub fn parse_macro_name_and_helper_attrs( /// If this item looks like a specific enums from `rental`, emit a fatal error. /// See #73345 and #83125 for more details. /// FIXME(#73933): Remove this eventually. -fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { +fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) { let name = item.ident.name; if name == sym::ProceduralMasqueradeDummyType && let ast::ItemKind::Enum(enum_def, _) = &item.kind && let [variant] = &*enum_def.variants && variant.ident.name == sym::Input - && let FileName::Real(real) = sess.source_map().span_to_filename(item.ident.span) + && let FileName::Real(real) = psess.source_map().span_to_filename(item.ident.span) && let Some(c) = real .local_path() .unwrap_or(Path::new("")) @@ -1406,7 +1433,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { }; if crate_matches { - sess.dcx().emit_fatal(errors::ProcMacroBackCompat { + psess.dcx().emit_fatal(errors::ProcMacroBackCompat { crate_name: "rental".to_string(), fixed_version: "0.5.6".to_string(), }); @@ -1414,7 +1441,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { } } -pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) { +pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, psess: &ParseSess) { let item = match ann { Annotatable::Item(item) => item, Annotatable::Stmt(stmt) => match &stmt.kind { @@ -1423,17 +1450,36 @@ pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &S }, _ => return, }; - pretty_printing_compatibility_hack(item, sess) + pretty_printing_compatibility_hack(item, psess) } -pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) { - let item = match nt { - Nonterminal::NtItem(item) => item, - Nonterminal::NtStmt(stmt) => match &stmt.kind { - ast::StmtKind::Item(item) => item, - _ => return, - }, +pub(crate) fn stream_pretty_printing_compatibility_hack( + kind: MetaVarKind, + stream: &TokenStream, + psess: &ParseSess, +) { + let item = match kind { + MetaVarKind::Item => { + let mut parser = Parser::new(psess, stream.clone(), None); + // No need to collect tokens for this simple check. + parser + .parse_item(ForceCollect::No) + .expect("failed to reparse item") + .expect("an actual item") + } + MetaVarKind::Stmt => { + let mut parser = Parser::new(psess, stream.clone(), None); + // No need to collect tokens for this simple check. + let stmt = parser + .parse_stmt(ForceCollect::No) + .expect("failed to reparse") + .expect("an actual stmt"); + match &stmt.kind { + ast::StmtKind::Item(item) => item.clone(), + _ => return, + } + } _ => return, }; - pretty_printing_compatibility_hack(item, sess) + pretty_printing_compatibility_hack(&item, psess) } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 83255b820178f..5570c0c38e831 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -328,7 +328,7 @@ impl<'a> StripUnconfigured<'a> { // For inner attributes, we do the same thing for the `!` in `#![attr]`. let mut trees = if cfg_attr.style == AttrStyle::Inner { - let Some(TokenTree::Token(bang_token @ Token { kind: TokenKind::Not, .. }, _)) = + let Some(TokenTree::Token(bang_token @ Token { kind: TokenKind::Bang, .. }, _)) = orig_trees.next() else { panic!("Bad tokens for attribute {cfg_attr:?}"); diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index e3f31ebeca3f3..87f01be26c25e 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -227,6 +227,12 @@ ast_fragments! { Variants(SmallVec<[ast::Variant; 1]>) { "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; } + WherePredicates(SmallVec<[ast::WherePredicate; 1]>) { + "where predicate"; + many fn flat_map_where_predicate; + fn visit_where_predicate(); + fn make_where_predicates; + } Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; } } @@ -259,7 +265,8 @@ impl AstFragmentKind { | AstFragmentKind::GenericParams | AstFragmentKind::Params | AstFragmentKind::FieldDefs - | AstFragmentKind::Variants => SupportsMacroExpansion::No, + | AstFragmentKind::Variants + | AstFragmentKind::WherePredicates => SupportsMacroExpansion::No, } } @@ -290,6 +297,9 @@ impl AstFragmentKind { AstFragmentKind::Variants => { AstFragment::Variants(items.map(Annotatable::expect_variant).collect()) } + AstFragmentKind::WherePredicates => AstFragment::WherePredicates( + items.map(Annotatable::expect_where_predicate).collect(), + ), AstFragmentKind::Items => { AstFragment::Items(items.map(Annotatable::expect_item).collect()) } @@ -770,8 +780,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } Err(err) => { - let guar = err.emit(); - fragment_kind.dummy(span, guar) + let _guar = err.emit(); + fragment_kind.expect_from_annotatables(iter::once(item)) } } } @@ -865,7 +875,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { | Annotatable::GenericParam(..) | Annotatable::Param(..) | Annotatable::FieldDef(..) - | Annotatable::Variant(..) => panic!("unexpected annotatable"), + | Annotatable::Variant(..) + | Annotatable::WherePredicate(..) => panic!("unexpected annotatable"), }; if self.cx.ecfg.features.proc_macro_hygiene() { return; @@ -1002,7 +1013,8 @@ pub fn parse_ast_fragment<'a>( | AstFragmentKind::GenericParams | AstFragmentKind::Params | AstFragmentKind::FieldDefs - | AstFragmentKind::Variants => panic!("unexpected AST fragment kind"), + | AstFragmentKind::Variants + | AstFragmentKind::WherePredicates => panic!("unexpected AST fragment kind"), }) } @@ -1414,6 +1426,19 @@ impl InvocationCollectorNode for ast::Variant { } } +impl InvocationCollectorNode for ast::WherePredicate { + const KIND: AstFragmentKind = AstFragmentKind::WherePredicates; + fn to_annotatable(self) -> Annotatable { + Annotatable::WherePredicate(self) + } + fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy { + fragment.make_where_predicates() + } + fn walk_flat_map(self, visitor: &mut V) -> Self::OutputTy { + walk_flat_map_where_predicate(visitor, self) + } +} + impl InvocationCollectorNode for ast::FieldDef { const KIND: AstFragmentKind = AstFragmentKind::FieldDefs; fn to_annotatable(self) -> Annotatable { @@ -2116,6 +2141,13 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { self.flat_map_node(node) } + fn flat_map_where_predicate( + &mut self, + node: ast::WherePredicate, + ) -> SmallVec<[ast::WherePredicate; 1]> { + self.flat_map_node(node) + } + fn flat_map_field_def(&mut self, node: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> { self.flat_map_node(node) } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 777044e3f33bf..4222c9fe90616 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -13,7 +13,6 @@ #![feature(rustdoc_internals)] #![feature(try_blocks)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate proc_macro as pm; diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 729dec2bfbdb1..1a2db233b7a64 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -432,7 +432,7 @@ fn check_nested_occurrences( } ( NestedMacroState::MacroRules, - &TokenTree::Token(Token { kind: TokenKind::Not, .. }), + &TokenTree::Token(Token { kind: TokenKind::Bang, .. }), ) => { state = NestedMacroState::MacroRulesNot; } diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index b02a9b93c8af0..5577c8902dae8 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -3,17 +3,17 @@ use std::collections::hash_map::Entry; use std::{mem, slice}; use ast::token::IdentIsRaw; -use rustc_ast::attr::AttributeExt; use rustc_ast::token::NtPatKind::*; use rustc_ast::token::TokenKind::*; use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId}; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{self as attr, TransparencyError}; +use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_errors::{Applicability, ErrorGuaranteed}; use rustc_feature::Features; +use rustc_hir as hir; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -371,7 +371,7 @@ pub fn compile_declarative_macro( features: &Features, macro_def: &ast::MacroDef, ident: Ident, - attrs: &[impl AttributeExt], + attrs: &[hir::Attribute], span: Span, node_id: NodeId, edition: Edition, @@ -379,7 +379,6 @@ pub fn compile_declarative_macro( let mk_syn_ext = |expander| { SyntaxExtension::new( sess, - features, SyntaxExtensionKind::LegacyBang(expander), span, Vec::new(), @@ -391,7 +390,6 @@ pub fn compile_declarative_macro( }; let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); - let dcx = sess.dcx(); let lhs_nm = Ident::new(sym::lhs, span); let rhs_nm = Ident::new(sym::rhs, span); let tt_spec = Some(NonterminalKind::TT); @@ -542,16 +540,8 @@ pub fn compile_declarative_macro( check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses)); - let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules); - match transparency_error { - Some(TransparencyError::UnknownTransparency(value, span)) => { - dcx.span_err(span, format!("unknown macro transparency: `{value}`")); - } - Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => { - dcx.span_err(vec![old_span, new_span], "multiple macro transparency attributes"); - } - None => {} - } + let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) + .unwrap_or(Transparency::fallback(macro_rules)); if let Some(guar) = guar { // To avoid warning noise, only consider the rules of this @@ -700,7 +690,7 @@ fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool { && let TokenKind::Ident(ident, _) = ident.kind && ident == sym::compile_error && let mbe::TokenTree::Token(bang) = bang - && let TokenKind::Not = bang.kind + && let TokenKind::Bang = bang.kind && let mbe::TokenTree::Delimited(.., del) = args && !del.delim.skip() { @@ -1145,7 +1135,7 @@ fn check_matcher_core<'tt>( && matches!(kind, NonterminalKind::Pat(PatParam { inferred: true })) && matches!( next_token, - TokenTree::Token(token) if *token == BinOp(token::BinOpToken::Or) + TokenTree::Token(token) if *token == token::Or ) { // It is suggestion to use pat_param, for example: $x:pat -> $x:pat_param. @@ -1187,7 +1177,7 @@ fn check_matcher_core<'tt>( if kind == NonterminalKind::Pat(PatWithOr) && sess.psess.edition.at_least_rust_2021() - && next_token.is_token(&BinOp(token::BinOpToken::Or)) + && next_token.is_token(&token::Or) { let suggestion = quoted_tt_to_string(&TokenTree::MetaVarDecl( span, @@ -1306,7 +1296,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"]; match tok { TokenTree::Token(token) => match token.kind { - FatArrow | Comma | Eq | BinOp(token::Or) => IsInFollow::Yes, + FatArrow | Comma | Eq | Or => IsInFollow::Yes, Ident(name, IdentIsRaw::No) if name == kw::If || name == kw::In => { IsInFollow::Yes } @@ -1342,9 +1332,9 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { | Colon | Eq | Gt - | BinOp(token::Shr) + | Shr | Semi - | BinOp(token::Or) => IsInFollow::Yes, + | Or => IsInFollow::Yes, Ident(name, IdentIsRaw::No) if name == kw::As || name == kw::Where => { IsInFollow::Yes } diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index b9a0615790790..0ea53627fe786 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -274,7 +274,7 @@ fn parse_tree<'a>( let msg = format!("expected identifier, found `{}`", pprust::token_to_string(token),); sess.dcx().span_err(token.span, msg); - TokenTree::MetaVar(token.span, Ident::empty()) + TokenTree::MetaVar(token.span, Ident::dummy()) } // There are no more tokens. Just return the `$` we already have. @@ -302,8 +302,8 @@ fn parse_tree<'a>( /// `None`. fn kleene_op(token: &Token) -> Option { match token.kind { - token::BinOp(token::Star) => Some(KleeneOp::ZeroOrMore), - token::BinOp(token::Plus) => Some(KleeneOp::OneOrMore), + token::Star => Some(KleeneOp::ZeroOrMore), + token::Plus => Some(KleeneOp::OneOrMore), token::Question => Some(KleeneOp::ZeroOrOne), _ => None, } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 721798b0ce464..cffa4af6ac3d0 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -7,7 +7,7 @@ use rustc_ast::token::{ TokenKind, }; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; -use rustc_ast::{ExprKind, TyKind}; +use rustc_ast::{ExprKind, StmtKind, TyKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize}; use rustc_parse::lexer::nfc_normalize; @@ -258,7 +258,7 @@ pub(super) fn transcribe<'a>( } // Replace the meta-var with the matched token tree from the invocation. - mbe::TokenTree::MetaVar(mut sp, mut original_ident) => { + &mbe::TokenTree::MetaVar(mut sp, mut original_ident) => { // Find the matched nonterminal from the macro invocation, and use it to replace // the meta-var. // @@ -279,9 +279,9 @@ pub(super) fn transcribe<'a>( if let Some(cur_matched) = lookup_cur_matched(ident, interp, &repeats) { // We wrap the tokens in invisible delimiters, unless they are already wrapped // in invisible delimiters with the same `MetaVarKind`. Because some proc - // macros can't multiple layers of invisible delimiters of the same + // macros can't handle multiple layers of invisible delimiters of the same // `MetaVarKind`. This loses some span info, though it hopefully won't matter. - let mut mk_delimited = |mv_kind, mut stream: TokenStream| { + let mut mk_delimited = |mk_span, mv_kind, mut stream: TokenStream| { if stream.len() == 1 { let tree = stream.iter().next().unwrap(); if let TokenTree::Delimited(_, _, delim, inner) = tree @@ -295,6 +295,7 @@ pub(super) fn transcribe<'a>( // Emit as a token stream within `Delimiter::Invisible` to maintain // parsing priorities. marker.visit_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(mk_span, sp)); // Both the open delim and close delim get the same span, which covers the // `$foo` in the decl macro RHS. TokenTree::Delimited( @@ -322,12 +323,44 @@ pub(super) fn transcribe<'a>( let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } + MatchedSingle(ParseNtResult::Item(item)) => { + mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item)) + } + MatchedSingle(ParseNtResult::Stmt(stmt)) => { + let stream = if let StmtKind::Empty = stmt.kind { + // FIXME: Properly collect tokens for empty statements. + TokenStream::token_alone(token::Semi, stmt.span) + } else { + TokenStream::from_ast(stmt) + }; + mk_delimited(stmt.span, MetaVarKind::Stmt, stream) + } + MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => mk_delimited( + pat.span, + MetaVarKind::Pat(*pat_kind), + TokenStream::from_ast(pat), + ), MatchedSingle(ParseNtResult::Ty(ty)) => { let is_path = matches!(&ty.kind, TyKind::Path(None, _path)); - mk_delimited(MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty)) + mk_delimited( + ty.span, + MetaVarKind::Ty { is_path }, + TokenStream::from_ast(ty), + ) + } + MatchedSingle(ParseNtResult::Meta(attr_item)) => { + let has_meta_form = attr_item.meta_kind().is_some(); + mk_delimited( + attr_item.span(), + MetaVarKind::Meta { has_meta_form }, + TokenStream::from_ast(attr_item), + ) + } + MatchedSingle(ParseNtResult::Path(path)) => { + mk_delimited(path.span, MetaVarKind::Path, TokenStream::from_ast(path)) } MatchedSingle(ParseNtResult::Vis(vis)) => { - mk_delimited(MetaVarKind::Vis, TokenStream::from_ast(vis)) + mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis)) } MatchedSingle(ParseNtResult::Nt(nt)) => { // Other variables are emitted into the output stream as groups with @@ -376,7 +409,7 @@ pub(super) fn transcribe<'a>( // We will produce all of the results of the inside of the `Delimited` and then we will // jump back out of the Delimited, pop the result_stack and add the new results back to // the previous results (from outside the Delimited). - mbe::TokenTree::Delimited(mut span, spacing, delimited) => { + &mbe::TokenTree::Delimited(mut span, ref spacing, ref delimited) => { mut_visit::visit_delim_span(&mut marker, &mut span); stack.push(Frame::new_delimited(delimited, span, *spacing)); result_stack.push(mem::take(&mut result)); diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index e969f2d4fb55f..3a470924c7f69 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -188,6 +188,19 @@ pub(crate) fn placeholder( vis, is_placeholder: true, }]), + AstFragmentKind::WherePredicates => { + AstFragment::WherePredicates(smallvec![ast::WherePredicate { + attrs: Default::default(), + id, + span, + kind: ast::WherePredicateKind::BoundPredicate(ast::WhereBoundPredicate { + bound_generic_params: Default::default(), + bounded_ty: ty(), + bounds: Default::default(), + }), + is_placeholder: true, + }]) + } } } @@ -267,6 +280,17 @@ impl MutVisitor for PlaceholderExpander { } } + fn flat_map_where_predicate( + &mut self, + predicate: ast::WherePredicate, + ) -> SmallVec<[ast::WherePredicate; 1]> { + if predicate.is_placeholder { + self.remove(predicate.id).make_where_predicates() + } else { + walk_flat_map_where_predicate(self, predicate) + } + } + fn flat_map_item(&mut self, item: P) -> SmallVec<[P; 1]> { match item.kind { ast::ItemKind::MacCall(_) => self.remove(item.id).make_items(), diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs index dca0516f9f3b3..d5af9849e759f 100644 --- a/compiler/rustc_expand/src/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -31,7 +31,7 @@ impl pm::bridge::server::MessagePipe for MessagePipe { } } -fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy { +fn exec_strategy(ecx: &ExtCtxt<'_>) -> impl pm::bridge::server::ExecutionStrategy + 'static { pm::bridge::server::MaybeCrossThread::>::new( ecx.sess.opts.unstable_opts.proc_macro_execution_strategy == ProcMacroExecutionStrategy::CrossThread, @@ -122,7 +122,7 @@ impl MultiItemModifier for DeriveProcMacro { // We had a lint for a long time, but now we just emit a hard error. // Eventually we might remove the special case hard error check // altogether. See #73345. - crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess); + crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess); let input = item.to_tokens(); let stream = { let _timer = diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 5581a6e65089a..e0269eb690344 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -115,11 +115,43 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { - let delimiter = pm::Delimiter::from_internal(delim); + tokenstream::TokenTree::Delimited(span, _, mut delim, mut stream) => { + // We used to have an alternative behaviour for crates that + // needed it: a hack used to pass AST fragments to + // attribute and derive macros as a single nonterminal + // token instead of a token stream. Such token needs to be + // "unwrapped" and not represented as a delimited group. We + // had a lint for a long time, but now we just emit a hard + // error. Eventually we might remove the special case hard + // error check altogether. See #73345. + if let Delimiter::Invisible(InvisibleOrigin::MetaVar(kind)) = delim { + crate::base::stream_pretty_printing_compatibility_hack( + kind, + &stream, + rustc.psess(), + ); + } + + // In `mk_delimited` we avoid nesting invisible delimited + // of the same `MetaVarKind`. Here we do the same but + // ignore the `MetaVarKind` because it is discarded when we + // convert it to a `Group`. + while let Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) = delim { + if stream.len() == 1 + && let tree = stream.iter().next().unwrap() + && let tokenstream::TokenTree::Delimited(_, _, delim2, stream2) = tree + && let Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) = delim2 + { + delim = *delim2; + stream = stream2.clone(); + } else { + break; + } + } + trees.push(TokenTree::Group(Group { - delimiter, - stream: Some(tts), + delimiter: pm::Delimiter::from_internal(delim), + stream: Some(stream), span: DelimSpan { open: span.open, close: span.close, @@ -180,28 +212,28 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec op(">"), AndAnd => op("&&"), OrOr => op("||"), - Not => op("!"), + Bang => op("!"), Tilde => op("~"), - BinOp(Plus) => op("+"), - BinOp(Minus) => op("-"), - BinOp(Star) => op("*"), - BinOp(Slash) => op("/"), - BinOp(Percent) => op("%"), - BinOp(Caret) => op("^"), - BinOp(And) => op("&"), - BinOp(Or) => op("|"), - BinOp(Shl) => op("<<"), - BinOp(Shr) => op(">>"), - BinOpEq(Plus) => op("+="), - BinOpEq(Minus) => op("-="), - BinOpEq(Star) => op("*="), - BinOpEq(Slash) => op("/="), - BinOpEq(Percent) => op("%="), - BinOpEq(Caret) => op("^="), - BinOpEq(And) => op("&="), - BinOpEq(Or) => op("|="), - BinOpEq(Shl) => op("<<="), - BinOpEq(Shr) => op(">>="), + Plus => op("+"), + Minus => op("-"), + Star => op("*"), + Slash => op("/"), + Percent => op("%"), + Caret => op("^"), + And => op("&"), + Or => op("|"), + Shl => op("<<"), + Shr => op(">>"), + PlusEq => op("+="), + MinusEq => op("-="), + StarEq => op("*="), + SlashEq => op("/="), + PercentEq => op("%="), + CaretEq => op("^="), + AndEq => op("&="), + OrEq => op("|="), + ShlEq => op("<<="), + ShrEq => op(">>="), At => op("@"), Dot => op("."), DotDot => op(".."), @@ -279,15 +311,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec { let stream = TokenStream::from_nonterminal_ast(&nt); - // We used to have an alternative behaviour for crates that - // needed it: a hack used to pass AST fragments to - // attribute and derive macros as a single nonterminal - // token instead of a token stream. Such token needs to be - // "unwrapped" and not represented as a delimited group. We - // had a lint for a long time, but now we just emit a hard - // error. Eventually we might remove the special case hard - // error check altogether. See #73345. - crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess); trees.push(TokenTree::Group(Group { delimiter: pm::Delimiter::None, stream: Some(stream), @@ -322,16 +345,16 @@ impl ToInternal> b'=' => Eq, b'<' => Lt, b'>' => Gt, - b'!' => Not, + b'!' => Bang, b'~' => Tilde, - b'+' => BinOp(Plus), - b'-' => BinOp(Minus), - b'*' => BinOp(Star), - b'/' => BinOp(Slash), - b'%' => BinOp(Percent), - b'^' => BinOp(Caret), - b'&' => BinOp(And), - b'|' => BinOp(Or), + b'+' => Plus, + b'-' => Minus, + b'*' => Star, + b'/' => Slash, + b'%' => Percent, + b'^' => Caret, + b'&' => And, + b'|' => Or, b'@' => At, b'.' => Dot, b',' => Comma, @@ -372,10 +395,9 @@ impl ToInternal> suffix, span, }) if symbol.as_str().starts_with('-') => { - let minus = BinOp(BinOpToken::Minus); let symbol = Symbol::intern(&symbol.as_str()[1..]); let integer = TokenKind::lit(token::Integer, symbol, suffix); - let a = tokenstream::TokenTree::token_joint_hidden(minus, span); + let a = tokenstream::TokenTree::token_joint_hidden(Minus, span); let b = tokenstream::TokenTree::token_alone(integer, span); smallvec![a, b] } @@ -385,10 +407,9 @@ impl ToInternal> suffix, span, }) if symbol.as_str().starts_with('-') => { - let minus = BinOp(BinOpToken::Minus); let symbol = Symbol::intern(&symbol.as_str()[1..]); let float = TokenKind::lit(token::Float, symbol, suffix); - let a = tokenstream::TokenTree::token_joint_hidden(minus, span); + let a = tokenstream::TokenTree::token_joint_hidden(Minus, span); let b = tokenstream::TokenTree::token_alone(float, span); smallvec![a, b] } @@ -599,10 +620,7 @@ impl server::TokenStream for Rustc<'_, '_> { Ok(Self::TokenStream::from_iter([ // FIXME: The span of the `-` token is lost when // parsing, so we cannot faithfully recover it here. - tokenstream::TokenTree::token_joint_hidden( - token::BinOp(token::Minus), - e.span, - ), + tokenstream::TokenTree::token_joint_hidden(token::Minus, e.span), tokenstream::TokenTree::token_alone(token::Literal(*token_lit), e.span), ])) } diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index 77de7fabd4f92..a5ae06473cbe3 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_feature" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 2dfb0c8e04093..d50fe8c6a3e6b 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -387,7 +387,7 @@ declare_features! ( /// Allows `#[target_feature(...)]`. (accepted, target_feature, "1.27.0", None), /// Allows the use of `#[target_feature]` on safe functions. - (accepted, target_feature_11, "CURRENT_RUSTC_VERSION", Some(69098)), + (accepted, target_feature_11, "1.86.0", Some(69098)), /// Allows `fn main()` with return types which implements `Termination` (RFC 1937). (accepted, termination_trait, "1.26.0", Some(43301)), /// Allows `#[test]` functions where the return type implements `Termination` (RFC 1937). @@ -401,7 +401,7 @@ declare_features! ( (accepted, track_caller, "1.46.0", Some(47809)), /// Allows dyn upcasting trait objects via supertraits. /// Dyn upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`. - (accepted, trait_upcasting, "CURRENT_RUSTC_VERSION", Some(65991)), + (accepted, trait_upcasting, "1.86.0", Some(65991)), /// Allows #[repr(transparent)] on univariant enums (RFC 2645). (accepted, transparent_enums, "1.42.0", Some(60405)), /// Allows indexing tuples. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index b2ada8fe61ef0..40857e0066ee5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -576,6 +576,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ EncodeCrossCrate::Yes, experimental!(patchable_function_entry) ), + // Probably temporary component of min_generic_const_args. + // `#[type_const] const ASSOC: usize;` + gated!( + type_const, Normal, template!(Word), ErrorFollowing, + EncodeCrossCrate::Yes, min_generic_const_args, experimental!(type_const), + ), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== @@ -1005,17 +1012,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, "the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items", ), - gated!( - rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, - "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies", - ), rustc_attr!( rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" ), rustc_attr!( rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, - "#![rustc_force_inline] forces a free function to be inlined" + "#[rustc_force_inline] forces a free function to be inlined" ), // ========================================================================== diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 0b034a2ae1075..25764755a8fc9 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -15,7 +15,6 @@ #![allow(internal_features)] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod accepted; diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 60e7788f2c05d..47e4f9a2fe885 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -100,6 +100,15 @@ declare_features! ( Some("renamed to `doc_notable_trait`")), /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (removed, dropck_parametricity, "1.38.0", Some(28498), None), + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1]. + /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and + /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. + /// + /// Renamed from `object_safe_for_dispatch`. + /// + /// [^1]: Formerly known as "object safe". + (removed, dyn_compatible_for_dispatch, "1.83.0", Some(43561), + Some("removed, not used heavily and represented additional complexity in dyn compatibility")), /// Uses generic effect parameters for ~const bounds (removed, effects, "1.84.0", Some(102090), Some("removed, redundant with `#![feature(const_trait_impl)]`")), @@ -235,6 +244,8 @@ declare_features! ( /// Allows unnamed fields of struct and union type (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign")), (removed, unsafe_no_drop_flag, "1.0.0", None, None), + (removed, unsized_tuple_coercion, "CURRENT_RUSTC_VERSION", Some(42877), + Some("The feature restricts possible layouts for tuples, and this restriction is not worth it.")), /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. (removed, untagged_unions, "1.13.0", Some(55149), Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index c7b44cecb9e00..3c61bfd1c93f5 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -1,6 +1,7 @@ //! List of the unstable feature gates. use std::path::PathBuf; +use std::time::{SystemTime, UNIX_EPOCH}; use rustc_data_structures::fx::FxHashSet; use rustc_span::{Span, Symbol, sym}; @@ -203,7 +204,7 @@ declare_features! ( /// Allows using anonymous lifetimes in argument-position impl-trait. (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None), /// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind - (internal, cfg_emscripten_wasm_eh, "CURRENT_RUSTC_VERSION", None), + (internal, cfg_emscripten_wasm_eh, "1.86.0", None), /// Allows identifying the `compiler_builtins` crate. (internal, compiler_builtins, "1.13.0", None), /// Allows writing custom MIR @@ -239,7 +240,7 @@ declare_features! ( /// Added for testing unstable lints; perma-unstable. (internal, test_unstable_lint, "1.60.0", None), /// Helps with formatting for `group_imports = "StdExternalCrate"`. - (unstable, unqualified_local_imports, "1.83.0", None), + (unstable, unqualified_local_imports, "1.83.0", Some(138299)), /// Use for stable + negative coherence and strict coherence depending on trait's /// rustc_strict_coherence value. (unstable, with_negative_coherence, "1.60.0", None), @@ -270,14 +271,6 @@ declare_features! ( (unstable, doc_notable_trait, "1.52.0", Some(45040)), /// Allows using the `may_dangle` attribute (RFC 1327). (unstable, dropck_eyepatch, "1.10.0", Some(34761)), - /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1]. - /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and - /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. - /// - /// Renamed from `object_safe_for_dispatch`. - /// - /// [^1]: Formerly known as "object safe". - (unstable, dyn_compatible_for_dispatch, "1.83.0", Some(43561)), /// Allows using the `#[fundamental]` attribute. (unstable, fundamental, "1.0.0", Some(29635)), /// Allows using `#[link_name="llvm.*"]`. @@ -358,7 +351,7 @@ declare_features! ( /// Allows `extern "C-cmse-nonsecure-call" fn()`. (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)), /// Allows `extern "gpu-kernel" fn()`. - (unstable, abi_gpu_kernel, "CURRENT_RUSTC_VERSION", Some(135467)), + (unstable, abi_gpu_kernel, "1.86.0", Some(135467)), /// Allows `extern "msp430-interrupt" fn()`. (unstable, abi_msp430_interrupt, "1.16.0", Some(38487)), /// Allows `extern "ptx-*" fn()`. @@ -402,7 +395,7 @@ declare_features! ( /// Allows the use of `#[cfg()]`. (unstable, cfg_boolean_literals, "1.83.0", Some(131204)), /// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled. - (unstable, cfg_contract_checks, "CURRENT_RUSTC_VERSION", Some(128044)), + (unstable, cfg_contract_checks, "1.86.0", Some(128044)), /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. (unstable, cfg_overflow_checks, "1.71.0", Some(111466)), /// Provides the relocation model information as cfg entry @@ -446,9 +439,9 @@ declare_features! ( /// Allows the `?` operator in const contexts. (unstable, const_try, "1.56.0", Some(74935)), /// Allows use of contracts attributes. - (incomplete, contracts, "CURRENT_RUSTC_VERSION", Some(128044)), + (incomplete, contracts, "1.86.0", Some(128044)), /// Allows access to internal machinery used to implement contracts. - (internal, contracts_internals, "CURRENT_RUSTC_VERSION", Some(128044)), + (internal, contracts_internals, "1.86.0", Some(128044)), /// Allows coroutines to be cloned. (unstable, coroutine_clone, "1.65.0", Some(95360)), /// Allows defining coroutines. @@ -481,6 +474,8 @@ declare_features! ( (unstable, doc_masked, "1.21.0", Some(44027)), /// Allows `dyn* Trait` objects. (incomplete, dyn_star, "1.65.0", Some(102425)), + /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` + (incomplete, ergonomic_clones, "CURRENT_RUSTC_VERSION", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. @@ -489,7 +484,7 @@ declare_features! ( /// for functions with varargs. (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), /// Allows using `system` as a calling convention with varargs. - (unstable, extern_system_varargs, "CURRENT_RUSTC_VERSION", Some(136946)), + (unstable, extern_system_varargs, "1.86.0", Some(136946)), /// Allows defining `extern type`s. (unstable, extern_types, "1.23.0", Some(43467)), /// Allow using 128-bit (quad precision) floating point numbers. @@ -516,8 +511,10 @@ declare_features! ( (incomplete, generic_const_exprs, "1.56.0", Some(76560)), /// Allows generic parameters and where-clauses on free & associated const items. (incomplete, generic_const_items, "1.73.0", Some(113521)), + /// Allows the type of const generics to depend on generic parameters + (incomplete, generic_const_parameter_types, "CURRENT_RUSTC_VERSION", Some(137626)), /// Allows any generic constants being used as pattern type range ends - (incomplete, generic_pattern_types, "CURRENT_RUSTC_VERSION", Some(136574)), + (incomplete, generic_pattern_types, "1.86.0", Some(136574)), /// Allows registering static items globally, possibly across crates, to iterate over at runtime. (unstable, global_registration, "1.80.0", Some(125119)), /// Allows using guards in patterns. @@ -533,7 +530,7 @@ declare_features! ( /// Allows `impl Trait` as output type in `Fn` traits in return position of functions. (unstable, impl_trait_in_fn_trait_return, "1.64.0", Some(99697)), /// Allows `use` associated functions from traits. - (unstable, import_trait_associated_functions, "CURRENT_RUSTC_VERSION", Some(134691)), + (unstable, import_trait_associated_functions, "1.86.0", Some(134691)), /// Allows associated types in inherent impls. (incomplete, inherent_associated_types, "1.52.0", Some(8995)), /// Allow anonymous constants from an inline `const` block in pattern position @@ -541,7 +538,7 @@ declare_features! ( /// Allows using `pointer` and `reference` in intra-doc links (unstable, intra_doc_pointers, "1.51.0", Some(80896)), // Allows using the `kl` and `widekl` target features and the associated intrinsics - (unstable, keylocker_x86, "CURRENT_RUSTC_VERSION", Some(134813)), + (unstable, keylocker_x86, "1.86.0", Some(134813)), // Allows setting the threshold for the `large_assignments` lint. (unstable, large_assignments, "1.52.0", Some(83518)), /// Allow to have type alias types for inter-crate use. @@ -582,7 +579,7 @@ declare_features! ( /// Allows diverging expressions to fall back to `!` rather than `()`. (unstable, never_type_fallback, "1.41.0", Some(65992)), /// Switch `..` syntax to use the new (`Copy + IntoIterator`) range types. - (unstable, new_range, "CURRENT_RUSTC_VERSION", Some(123741)), + (unstable, new_range, "1.86.0", Some(123741)), /// Allows `#![no_core]`. (unstable, no_core, "1.3.0", Some(29639)), /// Allows the use of `no_sanitize` attribute. @@ -607,6 +604,8 @@ declare_features! ( (unstable, precise_capturing_in_traits, "1.83.0", Some(130044)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), + /// Allows the use of raw-dylibs on ELF platforms + (incomplete, raw_dylib_elf, "CURRENT_RUSTC_VERSION", Some(135694)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant @@ -634,7 +633,7 @@ declare_features! ( /// Allows string patterns to dereference values to match them. (unstable, string_deref_patterns, "1.67.0", Some(87121)), /// Allows subtrait items to shadow supertrait items. - (unstable, supertrait_item_shadowing, "CURRENT_RUSTC_VERSION", Some(89151)), + (unstable, supertrait_item_shadowing, "1.86.0", Some(89151)), /// Allows using `#[thread_local]` on `static` items. (unstable, thread_local, "1.0.0", Some(29594)), /// Allows defining `trait X = A + B;` alias items. @@ -663,16 +662,17 @@ declare_features! ( (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. (incomplete, unsized_locals, "1.30.0", Some(48055)), - /// Allows unsized tuple coercion. - (unstable, unsized_tuple_coercion, "1.20.0", Some(42877)), /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute. (unstable, used_with_arg, "1.60.0", Some(93798)), + /// Allows use of attributes in `where` clauses. + (unstable, where_clause_attrs, "CURRENT_RUSTC_VERSION", Some(115590)), /// Allows use of x86 `AMX` target-feature attributes and intrinsics (unstable, x86_amx_intrinsics, "1.81.0", Some(126622)), /// Allows use of the `xop` target-feature (unstable, xop_target_feature, "1.81.0", Some(127208)), /// Allows `do yeet` expressions (unstable, yeet_expr, "1.62.0", Some(96373)), + (unstable, yield_expr, "CURRENT_RUSTC_VERSION", Some(43122)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! @@ -689,11 +689,13 @@ impl Features { ) -> Result<(), Box> { #[derive(serde::Serialize)] struct LibFeature { + timestamp: u128, symbol: String, } #[derive(serde::Serialize)] struct LangFeature { + timestamp: u128, symbol: String, since: Option, } @@ -707,10 +709,20 @@ impl Features { let metrics_file = std::fs::File::create(metrics_path)?; let metrics_file = std::io::BufWriter::new(metrics_file); + let now = || { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should always be greater than the unix epoch") + .as_nanos() + }; + let lib_features = self .enabled_lib_features .iter() - .map(|EnabledLibFeature { gate_name, .. }| LibFeature { symbol: gate_name.to_string() }) + .map(|EnabledLibFeature { gate_name, .. }| LibFeature { + symbol: gate_name.to_string(), + timestamp: now(), + }) .collect(); let lang_features = self @@ -719,6 +731,7 @@ impl Features { .map(|EnabledLangFeature { gate_name, stable_since, .. }| LangFeature { symbol: gate_name.to_string(), since: stable_since.map(|since| since.to_string()), + timestamp: now(), }) .collect(); diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml index eeceaa4691a2a..ce76b2745eaad 100644 --- a/compiler/rustc_fluent_macro/Cargo.toml +++ b/compiler/rustc_fluent_macro/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_fluent_macro" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] proc-macro = true diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index d4604c27e6da3..b04fd1b48f7ad 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -78,8 +78,8 @@ fn failed(crate_name: &Ident) -> proc_macro::TokenStream { /// See [rustc_fluent_macro::fluent_messages]. pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream { - let crate_name = std::env::var("CARGO_PKG_NAME") - // If `CARGO_PKG_NAME` is missing, then we're probably running in a test, so use + let crate_name = std::env::var("CARGO_CRATE_NAME") + // If `CARGO_CRATE_NAME` is missing, then we're probably running in a test, so use // `no_crate`. .unwrap_or_else(|_| "no_crate".to_string()) .replace("rustc_", ""); diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs index 3ad51fa1e64d0..c6e0484b92106 100644 --- a/compiler/rustc_fluent_macro/src/lib.rs +++ b/compiler/rustc_fluent_macro/src/lib.rs @@ -7,7 +7,6 @@ #![feature(proc_macro_span)] #![feature(rustdoc_internals)] #![feature(track_path)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use proc_macro::TokenStream; diff --git a/compiler/rustc_fs_util/Cargo.toml b/compiler/rustc_fs_util/Cargo.toml index 4b76200c06c53..baca3bc7d49eb 100644 --- a/compiler/rustc_fs_util/Cargo.toml +++ b/compiler/rustc_fs_util/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_fs_util" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_graphviz/Cargo.toml b/compiler/rustc_graphviz/Cargo.toml index 780004ae3fbc8..d84943760baeb 100644 --- a/compiler/rustc_graphviz/Cargo.toml +++ b/compiler/rustc_graphviz/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_graphviz" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index b5774f64b66b2..c8f8fd5be0237 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -277,7 +277,6 @@ )] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::borrow::Cow; diff --git a/compiler/rustc_hashes/Cargo.toml b/compiler/rustc_hashes/Cargo.toml index c2bae2fe8cb06..c7a273cff88c9 100644 --- a/compiler/rustc_hashes/Cargo.toml +++ b/compiler/rustc_hashes/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_hashes" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index b1516e53173ba..7ca8539845a04 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_hir" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -9,6 +9,7 @@ odht = { version = "0.3.1", features = ["nightly"] } rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hashes = { path = "../rustc_hashes" } rustc_index = { path = "../rustc_index" } diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 7e3a8561da08b..5f8941d4754e6 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -253,7 +253,9 @@ impl DefKind { } } - pub fn def_path_data(self, name: Symbol) -> DefPathData { + // Some `DefKind`s require a name, some don't. Panics if one is needed but + // not provided. (`AssocTy` is an exception, see below.) + pub fn def_path_data(self, name: Option) -> DefPathData { match self { DefKind::Mod | DefKind::Struct @@ -264,9 +266,13 @@ impl DefKind { | DefKind::TyAlias | DefKind::ForeignTy | DefKind::TraitAlias - | DefKind::AssocTy | DefKind::TyParam - | DefKind::ExternCrate => DefPathData::TypeNs(name), + | DefKind::ExternCrate => DefPathData::TypeNs(Some(name.unwrap())), + + // An associated type names will be missing for an RPITIT. It will + // later be given a name with `synthetic` in it, if necessary. + DefKind::AssocTy => DefPathData::TypeNs(name), + // It's not exactly an anon const, but wrt DefPathData, there // is no difference. DefKind::Static { nested: true, .. } => DefPathData::AnonConst, @@ -276,9 +282,9 @@ impl DefKind { | DefKind::Static { .. } | DefKind::AssocFn | DefKind::AssocConst - | DefKind::Field => DefPathData::ValueNs(name), - DefKind::Macro(..) => DefPathData::MacroNs(name), - DefKind::LifetimeParam => DefPathData::LifetimeNs(name), + | DefKind::Field => DefPathData::ValueNs(name.unwrap()), + DefKind::Macro(..) => DefPathData::MacroNs(name.unwrap()), + DefKind::LifetimeParam => DefPathData::LifetimeNs(name.unwrap()), DefKind::Ctor(..) => DefPathData::Ctor, DefKind::Use => DefPathData::Use, DefKind::ForeignMod => DefPathData::ForeignMod, @@ -429,7 +435,7 @@ pub enum Res { /// mention any generic parameters to allow the following with `min_const_generics`: /// ``` /// # struct Foo; - /// impl Foo { fn test() -> [u8; std::mem::size_of::()] { todo!() } } + /// impl Foo { fn test() -> [u8; size_of::()] { todo!() } } /// /// struct Bar([u8; baz::()]); /// const fn baz() -> usize { 10 } @@ -439,7 +445,7 @@ pub enum Res { /// compat lint: /// ``` /// fn foo() { - /// let _bar = [1_u8; std::mem::size_of::<*mut T>()]; + /// let _bar = [1_u8; size_of::<*mut T>()]; /// } /// ``` // FIXME(generic_const_exprs): Remove this bodge once that feature is stable. diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 08a0a5225e742..61f5efd9978c3 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -93,7 +93,7 @@ impl DefPathTable { pub fn enumerated_keys_and_path_hashes( &self, - ) -> impl Iterator + ExactSizeIterator + '_ { + ) -> impl Iterator + ExactSizeIterator { self.index_to_key .iter_enumerated() .map(move |(index, key)| (index, key, self.def_path_hash(index))) @@ -271,8 +271,9 @@ pub enum DefPathData { Use, /// A global asm item. GlobalAsm, - /// Something in the type namespace. - TypeNs(Symbol), + /// Something in the type namespace. Will be empty for RPITIT associated + /// types, which are given a synthetic name later, if necessary. + TypeNs(Option), /// Something in the value namespace. ValueNs(Symbol), /// Something in the macro namespace. @@ -410,8 +411,9 @@ impl DefPathData { pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; match *self { - TypeNs(name) if name == kw::Empty => None, - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), + TypeNs(name) => name, + + ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst | OpaqueTy => None, @@ -421,12 +423,14 @@ impl DefPathData { pub fn name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { - TypeNs(name) if name == kw::Empty => { - DefPathDataName::Anon { namespace: sym::synthetic } - } - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { - DefPathDataName::Named(name) + TypeNs(name) => { + if let Some(name) = name { + DefPathDataName::Named(name) + } else { + DefPathDataName::Anon { namespace: sym::synthetic } + } } + ValueNs(name) | MacroNs(name) | LifetimeNs(name) => DefPathDataName::Named(name), // Note that this does not show up in user print-outs. CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, Impl => DefPathDataName::Anon { namespace: kw::Impl }, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index eafc60f9d72f7..5cf231d566828 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,18 +1,20 @@ +// ignore-tidy-filelength use std::fmt; use rustc_abi::ExternAbi; -// ignore-tidy-filelength use rustc_ast::attr::AttributeExt; use rustc_ast::token::CommentKind; -use rustc_ast::util::parser::{AssocOp, ExprPrecedence}; +use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{ - self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, - IntTy, Label, LitIntType, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy, + self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType, + LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind, }; pub use rustc_ast::{ - BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy, - ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind, + AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, + ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, MetaItemInner, MetaItemLit, Movability, + Mutability, UnOp, }; +use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::tagged_ptr::TaggedRef; @@ -241,7 +243,7 @@ impl<'hir> PathSegment<'hir> { } pub fn invalid() -> Self { - Self::new(Ident::empty(), HirId::INVALID, Res::Err) + Self::new(Ident::dummy(), HirId::INVALID, Res::Err) } pub fn args(&self) -> &GenericArgs<'hir> { @@ -1009,174 +1011,248 @@ pub enum AttrArgs { }, } -#[derive(Clone, Debug, Encodable, Decodable)] -pub enum AttrKind { - /// A normal attribute. - Normal(Box), - - /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`). - /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal` - /// variant (which is much less compact and thus more expensive). - DocComment(CommentKind, Symbol), -} - #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct AttrPath { pub segments: Box<[Ident]>, pub span: Span, } +impl AttrPath { + pub fn from_ast(path: &ast::Path) -> Self { + AttrPath { + segments: path.segments.iter().map(|i| i.ident).collect::>().into_boxed_slice(), + span: path.span, + } + } +} + +impl fmt::Display for AttrPath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.segments.iter().map(|i| i.to_string()).collect::>().join("::")) + } +} + #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)] pub struct AttrItem { - pub unsafety: Safety, // Not lowered to hir::Path because we have no NodeId to resolve to. pub path: AttrPath, pub args: AttrArgs, -} - -#[derive(Clone, Debug, Encodable, Decodable)] -pub struct Attribute { - pub kind: AttrKind, - pub id: AttrId, + pub id: HashIgnoredAttrId, /// Denotes if the attribute decorates the following construct (outer) /// or the construct this attribute is contained within (inner). pub style: AttrStyle, + /// Span of the entire attribute pub span: Span, } +/// The derived implementation of [`HashStable_Generic`] on [`Attribute`]s shouldn't hash +/// [`AttrId`]s. By wrapping them in this, we make sure we never do. +#[derive(Copy, Debug, Encodable, Decodable, Clone)] +pub struct HashIgnoredAttrId { + pub attr_id: AttrId, +} + +#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)] +pub enum Attribute { + /// A parsed built-in attribute. + /// + /// Each attribute has a span connected to it. However, you must be somewhat careful using it. + /// That's because sometimes we merge multiple attributes together, like when an item has + /// multiple `repr` attributes. In this case the span might not be very useful. + Parsed(AttributeKind), + + /// An attribute that could not be parsed, out of a token-like representation. + /// This is the case for custom tool attributes. + Unparsed(Box), +} + impl Attribute { pub fn get_normal_item(&self) -> &AttrItem { - match &self.kind { - AttrKind::Normal(normal) => &normal, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), + match &self { + Attribute::Unparsed(normal) => &normal, + _ => panic!("unexpected parsed attribute"), } } pub fn unwrap_normal_item(self) -> AttrItem { - match self.kind { - AttrKind::Normal(normal) => *normal, - AttrKind::DocComment(..) => panic!("unexpected doc comment"), + match self { + Attribute::Unparsed(normal) => *normal, + _ => panic!("unexpected parsed attribute"), } } pub fn value_lit(&self) -> Option<&MetaItemLit> { - match &self.kind { - AttrKind::Normal(box AttrItem { args: AttrArgs::Eq { expr, .. }, .. }) => Some(expr), + match &self { + Attribute::Unparsed(n) => match n.as_ref() { + AttrItem { args: AttrArgs::Eq { eq_span: _, expr }, .. } => Some(expr), + _ => None, + }, _ => None, } } } impl AttributeExt for Attribute { + #[inline] fn id(&self) -> AttrId { - self.id + match &self { + Attribute::Unparsed(u) => u.id.attr_id, + _ => panic!(), + } } + #[inline] fn meta_item_list(&self) -> Option> { - match &self.kind { - AttrKind::Normal(box AttrItem { args: AttrArgs::Delimited(d), .. }) => { - ast::MetaItemKind::list_from_tokens(d.tokens.clone()) - } + match &self { + Attribute::Unparsed(n) => match n.as_ref() { + AttrItem { args: AttrArgs::Delimited(d), .. } => { + ast::MetaItemKind::list_from_tokens(d.tokens.clone()) + } + _ => None, + }, _ => None, } } + #[inline] fn value_str(&self) -> Option { self.value_lit().and_then(|x| x.value_str()) } + #[inline] fn value_span(&self) -> Option { self.value_lit().map(|i| i.span) } /// For a single-segment attribute, returns its name; otherwise, returns `None`. + #[inline] fn ident(&self) -> Option { - match &self.kind { - AttrKind::Normal(box AttrItem { - path: AttrPath { segments: box [ident], .. }, .. - }) => Some(*ident), + match &self { + Attribute::Unparsed(n) => { + if let [ident] = n.path.segments.as_ref() { + Some(*ident) + } else { + None + } + } _ => None, } } + #[inline] fn path_matches(&self, name: &[Symbol]) -> bool { - match &self.kind { - AttrKind::Normal(n) => n.path.segments.iter().map(|segment| &segment.name).eq(name), - AttrKind::DocComment(..) => false, + match &self { + Attribute::Unparsed(n) => { + n.path.segments.len() == name.len() + && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) + } + _ => false, } } + #[inline] fn is_doc_comment(&self) -> bool { - matches!(self.kind, AttrKind::DocComment(..)) + matches!(self, Attribute::Parsed(AttributeKind::DocComment { .. })) } + #[inline] fn span(&self) -> Span { - self.span + match &self { + Attribute::Unparsed(u) => u.span, + // FIXME: should not be needed anymore when all attrs are parsed + Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span, + Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span, + a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"), + } } + #[inline] fn is_word(&self) -> bool { - matches!(self.kind, AttrKind::Normal(box AttrItem { args: AttrArgs::Empty, .. })) + match &self { + Attribute::Unparsed(n) => { + matches!(n.args, AttrArgs::Empty) + } + _ => false, + } } + #[inline] fn ident_path(&self) -> Option> { - match &self.kind { - AttrKind::Normal(n) => Some(n.path.segments.iter().copied().collect()), - AttrKind::DocComment(..) => None, + match &self { + Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()), + _ => None, } } + #[inline] fn doc_str(&self) -> Option { - match &self.kind { - AttrKind::DocComment(.., data) => Some(*data), - AttrKind::Normal(_) if self.has_name(sym::doc) => self.value_str(), + match &self { + Attribute::Parsed(AttributeKind::DocComment { comment, .. }) => Some(*comment), + Attribute::Unparsed(_) if self.has_name(sym::doc) => self.value_str(), _ => None, } } + #[inline] fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { - match &self.kind { - AttrKind::DocComment(kind, data) => Some((*data, *kind)), - AttrKind::Normal(_) if self.name_or_empty() == sym::doc => { + match &self { + Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { + Some((*comment, *kind)) + } + Attribute::Unparsed(_) if self.name_or_empty() == sym::doc => { self.value_str().map(|s| (s, CommentKind::Line)) } _ => None, } } + #[inline] fn style(&self) -> AttrStyle { - self.style + match &self { + Attribute::Unparsed(u) => u.style, + Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style, + _ => panic!(), + } } } // FIXME(fn_delegation): use function delegation instead of manually forwarding impl Attribute { + #[inline] pub fn id(&self) -> AttrId { AttributeExt::id(self) } + #[inline] pub fn name_or_empty(&self) -> Symbol { AttributeExt::name_or_empty(self) } + #[inline] pub fn meta_item_list(&self) -> Option> { AttributeExt::meta_item_list(self) } + #[inline] pub fn value_str(&self) -> Option { AttributeExt::value_str(self) } + #[inline] pub fn value_span(&self) -> Option { AttributeExt::value_span(self) } + #[inline] pub fn ident(&self) -> Option { AttributeExt::ident(self) } + #[inline] pub fn path_matches(&self, name: &[Symbol]) -> bool { AttributeExt::path_matches(self, name) } + #[inline] pub fn is_doc_comment(&self) -> bool { AttributeExt::is_doc_comment(self) } @@ -1186,34 +1262,42 @@ impl Attribute { AttributeExt::has_name(self, name) } + #[inline] pub fn span(&self) -> Span { AttributeExt::span(self) } + #[inline] pub fn is_word(&self) -> bool { AttributeExt::is_word(self) } + #[inline] pub fn path(&self) -> SmallVec<[Symbol; 1]> { AttributeExt::path(self) } + #[inline] pub fn ident_path(&self) -> Option> { AttributeExt::ident_path(self) } + #[inline] pub fn doc_str(&self) -> Option { AttributeExt::doc_str(self) } + #[inline] pub fn is_proc_macro_attr(&self) -> bool { AttributeExt::is_proc_macro_attr(self) } + #[inline] pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> { AttributeExt::doc_str_and_comment_kind(self) } + #[inline] pub fn style(&self) -> AttrStyle { AttributeExt::style(self) } @@ -1223,13 +1307,18 @@ impl Attribute { #[derive(Debug)] pub struct AttributeMap<'tcx> { pub map: SortedMap, + /// Preprocessed `#[define_opaque]` attribute. + pub define_opaque: Option<&'tcx [(Span, LocalDefId)]>, // Only present when the crate hash is needed. pub opt_hash: Option, } impl<'tcx> AttributeMap<'tcx> { - pub const EMPTY: &'static AttributeMap<'static> = - &AttributeMap { map: SortedMap::new(), opt_hash: Some(Fingerprint::ZERO) }; + pub const EMPTY: &'static AttributeMap<'static> = &AttributeMap { + map: SortedMap::new(), + opt_hash: Some(Fingerprint::ZERO), + define_opaque: None, + }; #[inline] pub fn get(&self, id: ItemLocalId) -> &'tcx [Attribute] { @@ -1516,7 +1605,7 @@ pub struct PatField<'hir> { pub span: Span, } -#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic, Hash, Eq, Encodable, Decodable)] pub enum RangeEnd { Included, Excluded, @@ -1584,7 +1673,7 @@ pub enum PatExprKind<'hir> { #[derive(Debug, Clone, Copy, HashStable_Generic)] pub enum TyPatKind<'hir> { /// A range pattern (e.g., `1..=2` or `1..2`). - Range(Option<&'hir ConstArg<'hir>>, Option<&'hir ConstArg<'hir>>, RangeEnd), + Range(&'hir ConstArg<'hir>, &'hir ConstArg<'hir>), /// A placeholder for a pattern that wasn't well formed in some way. Err(ErrorGuaranteed), @@ -1599,6 +1688,12 @@ pub enum PatKind<'hir> { /// The `HirId` is the canonical ID for the variable being bound, /// (e.g., in `Ok(x) | Err(x)`, both `x` use the same canonical ID), /// which is the pattern ID of the first `x`. + /// + /// The `BindingMode` is what's provided by the user, before match + /// ergonomics are applied. For the binding mode actually in use, + /// see [`TypeckResults::extract_binding_mode`]. + /// + /// [`TypeckResults::extract_binding_mode`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.extract_binding_mode Binding(BindingMode, HirId, Ident, Option<&'hir Pat<'hir>>), /// A struct or struct variant pattern (e.g., `Variant {x, y, ..}`). @@ -1913,13 +2008,18 @@ pub enum BodyOwnerKind { /// Initializer of a `static` item. Static(Mutability), + + /// Fake body for a global asm to store its const-like value types. + GlobalAsm, } impl BodyOwnerKind { pub fn is_fn_or_closure(self) -> bool { match self { BodyOwnerKind::Fn | BodyOwnerKind::Closure => true, - BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) => false, + BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(_) | BodyOwnerKind::GlobalAsm => { + false + } } } } @@ -2035,7 +2135,7 @@ impl Expr<'_> { | ExprKind::Become(..) => ExprPrecedence::Jump, // Binop-like expr kinds, handled by `AssocOp`. - ExprKind::Binary(op, ..) => AssocOp::from_ast_binop(op.node).precedence(), + ExprKind::Binary(op, ..) => op.node.precedence(), ExprKind::Cast(..) => ExprPrecedence::Cast, ExprKind::Assign(..) | @@ -2071,6 +2171,7 @@ impl Expr<'_> { | ExprKind::Tup(_) | ExprKind::Type(..) | ExprKind::UnsafeBinderCast(..) + | ExprKind::Use(..) | ExprKind::Err(_) => ExprPrecedence::Unambiguous, ExprKind::DropTemps(expr, ..) => expr.precedence(), @@ -2117,6 +2218,7 @@ impl Expr<'_> { ExprKind::Path(QPath::TypeRelative(..)) | ExprKind::Call(..) | ExprKind::MethodCall(..) + | ExprKind::Use(..) | ExprKind::Struct(..) | ExprKind::Tup(..) | ExprKind::If(..) @@ -2190,7 +2292,9 @@ impl Expr<'_> { pub fn can_have_side_effects(&self) -> bool { match self.peel_drop_temps().kind { - ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false, + ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) | ExprKind::Use(..) => { + false + } ExprKind::Type(base, _) | ExprKind::Unary(_, base) | ExprKind::Field(base, _) @@ -2452,6 +2556,8 @@ pub enum ExprKind<'hir> { /// /// [`type_dependent_def_id`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.type_dependent_def_id MethodCall(&'hir PathSegment<'hir>, &'hir Expr<'hir>, &'hir [Expr<'hir>], Span), + /// An use expression (e.g., `var.use`). + Use(&'hir Expr<'hir>, Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(&'hir [Expr<'hir>]), /// A binary operation (e.g., `a + b`, `a * b`). @@ -3267,13 +3373,16 @@ pub struct OpaqueTy<'hir> { pub span: Span, } -#[derive(Debug, Clone, Copy, HashStable_Generic)] -pub enum PreciseCapturingArg<'hir> { - Lifetime(&'hir Lifetime), +#[derive(Debug, Clone, Copy, HashStable_Generic, Encodable, Decodable)] +pub enum PreciseCapturingArgKind { + Lifetime(T), /// Non-lifetime argument (type or const) - Param(PreciseCapturingNonLifetimeArg), + Param(U), } +pub type PreciseCapturingArg<'hir> = + PreciseCapturingArgKind<&'hir Lifetime, PreciseCapturingNonLifetimeArg>; + impl PreciseCapturingArg<'_> { pub fn hir_id(self) -> HirId { match self { @@ -3417,10 +3526,10 @@ pub enum InlineAsmOperand<'hir> { out_expr: Option<&'hir Expr<'hir>>, }, Const { - anon_const: &'hir AnonConst, + anon_const: ConstBlock, }, SymFn { - anon_const: &'hir AnonConst, + expr: &'hir Expr<'hir>, }, SymStatic { path: QPath<'hir>, @@ -3848,7 +3957,7 @@ impl<'hir> Item<'hir> { expect_foreign_mod, (ExternAbi, &'hir [ForeignItemRef]), ItemKind::ForeignMod { abi, items }, (*abi, items); - expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm(asm), asm; + expect_global_asm, &'hir InlineAsm<'hir>, ItemKind::GlobalAsm { asm, .. }, asm; expect_ty_alias, (&'hir Ty<'hir>, &'hir Generics<'hir>), ItemKind::TyAlias(ty, generics), (ty, generics); @@ -4015,7 +4124,15 @@ pub enum ItemKind<'hir> { /// An external module, e.g. `extern { .. }`. ForeignMod { abi: ExternAbi, items: &'hir [ForeignItemRef] }, /// Module-level inline assembly (from `global_asm!`). - GlobalAsm(&'hir InlineAsm<'hir>), + GlobalAsm { + asm: &'hir InlineAsm<'hir>, + /// A fake body which stores typeck results for the global asm's sym_fn + /// operands, which are represented as path expressions. This body contains + /// a single [`ExprKind::InlineAsm`] which points to the asm in the field + /// above, and which is typechecked like a inline asm expr just for the + /// typeck results. + fake_body: BodyId, + }, /// A type alias, e.g., `type Foo = Bar`. TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), /// An enum definition, e.g., `enum Foo {C, D}`. @@ -4081,7 +4198,7 @@ impl ItemKind<'_> { ItemKind::Macro(..) => "macro", ItemKind::Mod(..) => "module", ItemKind::ForeignMod { .. } => "extern block", - ItemKind::GlobalAsm(..) => "global asm item", + ItemKind::GlobalAsm { .. } => "global asm item", ItemKind::TyAlias(..) => "type alias", ItemKind::Enum(..) => "enum", ItemKind::Struct(..) => "struct", @@ -4218,16 +4335,6 @@ pub enum OwnerNode<'hir> { } impl<'hir> OwnerNode<'hir> { - pub fn ident(&self) -> Option { - match self { - OwnerNode::Item(Item { ident, .. }) - | OwnerNode::ForeignItem(ForeignItem { ident, .. }) - | OwnerNode::ImplItem(ImplItem { ident, .. }) - | OwnerNode::TraitItem(TraitItem { ident, .. }) => Some(*ident), - OwnerNode::Crate(..) | OwnerNode::Synthetic => None, - } - } - pub fn span(&self) -> Span { match self { OwnerNode::Item(Item { span, .. }) @@ -4540,6 +4647,10 @@ impl<'hir> Node<'hir> { .. }) => Some((owner_id.def_id, *body)), + Node::Item(Item { + owner_id, kind: ItemKind::GlobalAsm { asm: _, fake_body }, .. + }) => Some((owner_id.def_id, *fake_body)), + Node::Expr(Expr { kind: ExprKind::Closure(Closure { def_id, body, .. }), .. }) => { Some((*def_id, *body)) } diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs index 300d44355303a..f75b9662132e8 100644 --- a/compiler/rustc_hir/src/hir/tests.rs +++ b/compiler/rustc_hir/src/hir/tests.rs @@ -9,11 +9,11 @@ macro_rules! define_tests { let unambig = $kind::$variant::<'_, ()> { $($init)* }; let unambig_to_ambig = unsafe { std::mem::transmute::<_, $kind<'_, AmbigArg>>(unambig) }; - assert!(matches!(&unambig_to_ambig, $kind::$variant { $($init)* })); + assert!(matches!(&unambig_to_ambig, &$kind::$variant { $($init)* })); let ambig_to_unambig = unsafe { std::mem::transmute::<_, $kind<'_, ()>>(unambig_to_ambig) }; - assert!(matches!(&ambig_to_unambig, $kind::$variant { $($init)* })); + assert!(matches!(&ambig_to_unambig, &$kind::$variant { $($init)* })); } )*}; } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index bd96fe9ee32c7..3ef645a5f6172 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -316,8 +316,8 @@ pub trait Visitor<'v>: Sized { fn visit_ident(&mut self, ident: Ident) -> Self::Result { walk_ident(self, ident) } - fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, n: HirId) -> Self::Result { - walk_mod(self, m, n) + fn visit_mod(&mut self, m: &'v Mod<'v>, _s: Span, _n: HirId) -> Self::Result { + walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v ForeignItem<'v>) -> Self::Result { walk_foreign_item(self, i) @@ -363,7 +363,7 @@ pub trait Visitor<'v>: Sized { /// See the doc comments on [`Ty`] for an explanation of what it means for a type to be /// ambiguous. /// - /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars. + /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_ty(&mut self, t: &'v Ty<'v, AmbigArg>) -> Self::Result { walk_ty(self, t) } @@ -374,7 +374,7 @@ pub trait Visitor<'v>: Sized { /// See the doc comments on [`ConstArg`] for an explanation of what it means for a const to be /// ambiguous. /// - /// The [`Visitor::visit_infer`] method should be overriden in order to handle infer vars. + /// The [`Visitor::visit_infer`] method should be overridden in order to handle infer vars. fn visit_const_arg(&mut self, c: &'v ConstArg<'v, AmbigArg>) -> Self::Result { walk_ambig_const_arg(self, c) } @@ -464,8 +464,8 @@ pub trait Visitor<'v>: Sized { fn visit_field_def(&mut self, s: &'v FieldDef<'v>) -> Self::Result { walk_field_def(self, s) } - fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) -> Self::Result { - walk_enum_def(self, enum_definition, item_id) + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>) -> Self::Result { + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &'v Variant<'v>) -> Self::Result { walk_variant(self, v) @@ -532,28 +532,25 @@ pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) -> } pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::Result { + try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ident(item.ident)); match item.kind { ItemKind::ExternCrate(orig_name) => { - try_visit!(visitor.visit_id(item.hir_id())); visit_opt!(visitor, visit_name, orig_name); } ItemKind::Use(ref path, _) => { try_visit!(visitor.visit_use(path, item.hir_id())); } ItemKind::Static(ref typ, _, body) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_nested_body(body)); } ItemKind::Const(ref typ, ref generics, body) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(typ)); try_visit!(visitor.visit_generics(generics)); try_visit!(visitor.visit_nested_body(body)); } ItemKind::Fn { sig, generics, body: body_id, .. } => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_fn( FnKind::ItemFn(item.ident, generics, sig.header), sig.decl, @@ -562,30 +559,27 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: item.owner_id.def_id, )); } - ItemKind::Macro(..) => { - try_visit!(visitor.visit_id(item.hir_id())); - } + ItemKind::Macro(..) => {} ItemKind::Mod(ref module) => { - // `visit_mod()` takes care of visiting the `Item`'s `HirId`. try_visit!(visitor.visit_mod(module, item.span, item.hir_id())); } ItemKind::ForeignMod { abi: _, items } => { - try_visit!(visitor.visit_id(item.hir_id())); walk_list!(visitor, visit_foreign_item_ref, items); } - ItemKind::GlobalAsm(asm) => { - try_visit!(visitor.visit_id(item.hir_id())); - try_visit!(visitor.visit_inline_asm(asm, item.hir_id())); + ItemKind::GlobalAsm { asm: _, fake_body } => { + // Visit the fake body, which contains the asm statement. + // Therefore we should not visit the asm statement again + // outside of the body, or some visitors won't have their + // typeck results set correctly. + try_visit!(visitor.visit_nested_body(fake_body)); } ItemKind::TyAlias(ref ty, ref generics) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_ty_unambig(ty)); try_visit!(visitor.visit_generics(generics)); } ItemKind::Enum(ref enum_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); - // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. - try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id())); + try_visit!(visitor.visit_enum_def(enum_definition)); } ItemKind::Impl(Impl { constness: _, @@ -593,12 +587,11 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: defaultness: _, polarity: _, defaultness_span: _, - ref generics, - ref of_trait, - ref self_ty, + generics, + of_trait, + self_ty, items, }) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); visit_opt!(visitor, visit_trait_ref, of_trait); try_visit!(visitor.visit_ty_unambig(self_ty)); @@ -607,17 +600,14 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V:: ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_variant_data(struct_definition)); } ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); } ItemKind::TraitAlias(ref generics, bounds) => { - try_visit!(visitor.visit_id(item.hir_id())); try_visit!(visitor.visit_generics(generics)); walk_list!(visitor, visit_param_bound, bounds); } @@ -634,12 +624,7 @@ pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) -> V::Resul visitor.visit_name(ident.name) } -pub fn walk_mod<'v, V: Visitor<'v>>( - visitor: &mut V, - module: &'v Mod<'v>, - mod_hir_id: HirId, -) -> V::Result { - try_visit!(visitor.visit_id(mod_hir_id)); +pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>) -> V::Result { walk_list!(visitor, visit_nested_item, module.item_ids.iter().copied()); V::Result::output() } @@ -704,9 +689,9 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) -> V::Res pub fn walk_ty_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v TyPat<'v>) -> V::Result { try_visit!(visitor.visit_id(pattern.hir_id)); match pattern.kind { - TyPatKind::Range(lower_bound, upper_bound, _) => { - visit_opt!(visitor, visit_const_arg_unambig, lower_bound); - visit_opt!(visitor, visit_const_arg_unambig, upper_bound); + TyPatKind::Range(lower_bound, upper_bound) => { + try_visit!(visitor.visit_const_arg_unambig(lower_bound)); + try_visit!(visitor.visit_const_arg_unambig(upper_bound)); } TyPatKind::Err(_) => (), } @@ -817,6 +802,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) try_visit!(visitor.visit_expr(receiver)); walk_list!(visitor, visit_expr, arguments); } + ExprKind::Use(expr, _) => { + try_visit!(visitor.visit_expr(expr)); + } ExprKind::Binary(_, ref left_expression, ref right_expression) => { try_visit!(visitor.visit_expr(left_expression)); try_visit!(visitor.visit_expr(right_expression)); @@ -1045,7 +1033,7 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>( } GenericParamKind::Const { ref ty, ref default, synthetic: _ } => { try_visit!(visitor.visit_ty_unambig(ty)); - if let Some(ref default) = default { + if let Some(default) = default { try_visit!(visitor.visit_const_param_default(param.hir_id, default)); } } @@ -1141,7 +1129,6 @@ pub fn walk_use<'v, V: Visitor<'v>>( path: &'v UsePath<'v>, hir_id: HirId, ) -> V::Result { - try_visit!(visitor.visit_id(hir_id)); let UsePath { segments, ref res, span } = *path; for &res in res { try_visit!(visitor.visit_path(&Path { segments, res, span }, hir_id)); @@ -1322,9 +1309,7 @@ pub fn walk_field_def<'v, V: Visitor<'v>>( pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, - item_id: HirId, ) -> V::Result { - try_visit!(visitor.visit_id(item_id)); walk_list!(visitor, visit_variant, enum_definition.variants); V::Result::output() } @@ -1401,8 +1386,8 @@ pub fn walk_assoc_item_constraint<'v, V: Visitor<'v>>( try_visit!(visitor.visit_generic_args(constraint.gen_args)); match constraint.kind { AssocItemConstraintKind::Equality { ref term } => match term { - Term::Ty(ref ty) => try_visit!(visitor.visit_ty_unambig(ty)), - Term::Const(ref c) => try_visit!(visitor.visit_const_arg_unambig(c)), + Term::Ty(ty) => try_visit!(visitor.visit_ty_unambig(ty)), + Term::Const(c) => try_visit!(visitor.visit_const_arg_unambig(c)), }, AssocItemConstraintKind::Bound { bounds } => { walk_list!(visitor, visit_param_bound, bounds) @@ -1442,9 +1427,11 @@ pub fn walk_inline_asm<'v, V: Visitor<'v>>( try_visit!(visitor.visit_expr(in_expr)); visit_opt!(visitor, visit_expr, out_expr); } - InlineAsmOperand::Const { anon_const, .. } - | InlineAsmOperand::SymFn { anon_const, .. } => { - try_visit!(visitor.visit_anon_const(anon_const)); + InlineAsmOperand::Const { anon_const, .. } => { + try_visit!(visitor.visit_inline_const(anon_const)); + } + InlineAsmOperand::SymFn { expr, .. } => { + try_visit!(visitor.visit_expr(expr)); } InlineAsmOperand::SymStatic { path, .. } => { try_visit!(visitor.visit_qpath(path, id, *op_sp)); diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 34c0837b25a52..29f4d5b807699 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -60,7 +60,7 @@ impl LanguageItems { self.reverse_items.get(&def_id).copied() } - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator { self.items .iter() .enumerate() @@ -171,6 +171,7 @@ language_item_table! { Copy, sym::copy, copy_trait, Target::Trait, GenericRequirement::Exact(0); Clone, sym::clone, clone_trait, Target::Trait, GenericRequirement::None; CloneFn, sym::clone_fn, clone_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; + UseCloned, sym::use_cloned, use_cloned_trait, Target::Trait, GenericRequirement::None; Sync, sym::sync, sync_trait, Target::Trait, GenericRequirement::Exact(0); DiscriminantKind, sym::discriminant_kind, discriminant_kind_trait, Target::Trait, GenericRequirement::None; /// The associated item of the `DiscriminantKind` trait. @@ -418,6 +419,9 @@ language_item_table! { Range, sym::Range, range_struct, Target::Struct, GenericRequirement::None; RangeToInclusive, sym::RangeToInclusive, range_to_inclusive_struct, Target::Struct, GenericRequirement::None; RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None; + RangeMax, sym::RangeMax, range_max, Target::AssocConst, GenericRequirement::Exact(0); + RangeMin, sym::RangeMin, range_min, Target::AssocConst, GenericRequirement::Exact(0); + RangeSub, sym::RangeSub, range_sub, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::Exact(0); // `new_range` types that are `Copy + IntoIterator` RangeFromCopy, sym::RangeFromCopy, range_from_copy_struct, Target::Struct, GenericRequirement::None; diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 270d4fbec30f8..4a839d4057181 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -4,6 +4,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(closure_track_caller)] @@ -13,7 +14,6 @@ #![feature(never_type)] #![feature(rustc_attrs)] #![feature(variant_count)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate self as rustc_hir; diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index d7c8a3d5c0a5f..91ea88cae4776 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -1,17 +1,21 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_span::def_id::DefPathHash; +use crate::HashIgnoredAttrId; use crate::hir::{ - Attribute, AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, - TraitItemId, + AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, }; use crate::hir_id::{HirId, ItemLocalId}; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro /// instead of implementing everything in `rustc_middle`. -pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext { - fn hash_attr(&mut self, _: &Attribute, hasher: &mut StableHasher); +pub trait HashStableContext: + rustc_attr_data_structures::HashStableContext + + rustc_ast::HashStableContext + + rustc_abi::HashStableContext +{ + fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher); } impl ToStableHashKey for HirId { @@ -102,7 +106,7 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable for AttributeMap fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { // We ignore the `map` since it refers to information included in `opt_hash` which is // hashed in the collector and used for the crate hash. - let AttributeMap { opt_hash, map: _ } = *self; + let AttributeMap { opt_hash, define_opaque: _, map: _ } = *self; opt_hash.unwrap().hash_stable(hcx, hasher); } } @@ -114,8 +118,8 @@ impl HashStable for Crate<'_> { } } -impl HashStable for Attribute { +impl HashStable for HashIgnoredAttrId { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { - hcx.hash_attr(self, hasher) + hcx.hash_attr_id(self, hasher) } } diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs index f3e8f059c9e3c..601898023fc39 100644 --- a/compiler/rustc_hir/src/target.rs +++ b/compiler/rustc_hir/src/target.rs @@ -56,6 +56,7 @@ pub enum Target { Param, PatField, ExprField, + WherePredicate, } impl Display for Target { @@ -96,7 +97,8 @@ impl Target { | Target::MacroDef | Target::Param | Target::PatField - | Target::ExprField => false, + | Target::ExprField + | Target::WherePredicate => false, } } @@ -110,7 +112,7 @@ impl Target { ItemKind::Macro(..) => Target::MacroDef, ItemKind::Mod(..) => Target::Mod, ItemKind::ForeignMod { .. } => Target::ForeignMod, - ItemKind::GlobalAsm(..) => Target::GlobalAsm, + ItemKind::GlobalAsm { .. } => Target::GlobalAsm, ItemKind::TyAlias(..) => Target::TyAlias, ItemKind::Enum(..) => Target::Enum, ItemKind::Struct(..) => Target::Struct, @@ -217,6 +219,7 @@ impl Target { Target::Param => "function param", Target::PatField => "pattern field", Target::ExprField => "struct field", + Target::WherePredicate => "where predicate", } } } diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 196d7d99e933d..e5017794d8f29 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_hir_analysis" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] test = false @@ -28,7 +28,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 47d5976be09ef..194f2cd04e468 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -85,6 +85,10 @@ hir_analysis_cmse_output_stack_spill = .note1 = functions with the `{$abi}` ABI must pass their result via the available return registers .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size +hir_analysis_coerce_multi = implementing `{$trait_name}` does not allow multiple fields to be coerced + .note = the trait `{$trait_name}` may only be implemented when a single field is being coerced + .label = these fields must be coerced for `{$trait_name}` to be valid + hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden @@ -95,12 +99,12 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout +hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}` + .label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized + hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures -hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions - .note = `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced - .coercions_note = currently, {$number} fields need coercions: {$coercions} - .label = requires multiple coercions +hir_analysis_coerce_zero = implementing `{$trait_name}` requires a field to be coerced hir_analysis_coercion_between_struct_same_note = expected coercion between the same definition; expected `{$source_path}`, found `{$target_path}` @@ -139,10 +143,6 @@ hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like ` hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate .label = can't implement cross-crate trait for type in another crate -hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions - .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced - .coercions_note = currently, {$number} fields need coercions: {$coercions} - hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]` hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else @@ -244,9 +244,6 @@ hir_analysis_inherent_ty_outside_relevant = cannot define inherent `impl` for a .help = consider moving this inherent impl into the crate defining the type if possible .span_help = alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items -hir_analysis_invalid_base_type = `{$ty}` is not a valid base type for range patterns - .note = range patterns only support integers - hir_analysis_invalid_generic_receiver_ty = invalid generic `self` parameter type: `{$receiver_ty}` .note = type of `self` must not be a method generic parameter type @@ -278,13 +275,6 @@ hir_analysis_invalid_union_field = hir_analysis_invalid_union_field_sugg = wrap the field type in `ManuallyDrop<...>` -hir_analysis_invalid_unsafe_field = - field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be unsafe - .note = unsafe fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>` - -hir_analysis_invalid_unsafe_field_sugg = - wrap the field type in `ManuallyDrop<...>` - hir_analysis_late_bound_const_in_apit = `impl Trait` can only mention const parameters from an fn or impl .label = const parameter declared here @@ -514,12 +504,9 @@ hir_analysis_supertrait_item_shadowee = item from `{$supertrait}` is shadowed by hir_analysis_supertrait_item_shadowing = trait item `{$item}` from `{$subtrait}` shadows identically named item from supertrait -hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature - .note = this item must mention the opaque type in its signature in order to be able to register hidden types - -hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}`, but has it in its signature - .note = consider moving the opaque type's declaration and defining uses into a separate module - .opaque = this opaque type is in the signature +hir_analysis_tait_forward_compat2 = item does not constrain `{$opaque_type}` + .note = consider removing `#[define_opaque]` or adding an empty `#[define_opaque()]` + .opaque = this opaque type is supposed to be constrained hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]` @@ -605,6 +592,8 @@ hir_analysis_unused_generic_parameter_adt_no_phantom_data_help = hir_analysis_unused_generic_parameter_ty_alias_help = consider removing `{$param_name}` or referring to it in the body of the type alias +hir_analysis_useless_impl_item = this item cannot be used as its where bounds are not satisfied for the `Self` type + hir_analysis_value_of_associated_struct_already_specified = the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified .label = re-bound here @@ -618,6 +607,8 @@ hir_analysis_variances_of = {$variances} hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause .label = `main` cannot have a `where` clause +hir_analysis_within_macro = due to this macro variable + hir_analysis_wrong_number_of_generic_arguments_to_intrinsic = intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected} .label = expected {$expected} {$descr} {$expected -> diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/always_applicable.rs similarity index 61% rename from compiler/rustc_hir_analysis/src/check/dropck.rs rename to compiler/rustc_hir_analysis/src/check/always_applicable.rs index d7dfe482da449..8a841a1155674 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/always_applicable.rs @@ -1,8 +1,15 @@ +//! This module contains methods that assist in checking that impls are general +//! enough, i.e. that they always apply to every valid instantaiton of the ADT +//! they're implemented for. +//! +//! This is necessary for `Drop` and negative impls to be well-formed. + use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_infer::traits::{ObligationCause, ObligationCauseCode}; +use rustc_middle::span_bug; use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -27,11 +34,12 @@ use crate::hir::def_id::{DefId, LocalDefId}; /// 3. Any bounds on the generic parameters must be reflected in the /// struct/enum definition for the nominal type itself (i.e. /// cannot do `struct S; impl Drop for S { ... }`). -/// pub(crate) fn check_drop_impl( tcx: TyCtxt<'_>, drop_impl_did: DefId, ) -> Result<(), ErrorGuaranteed> { + let drop_impl_did = drop_impl_did.expect_local(); + match tcx.impl_polarity(drop_impl_did) { ty::ImplPolarity::Positive => {} ty::ImplPolarity::Negative => { @@ -45,55 +53,110 @@ pub(crate) fn check_drop_impl( })); } } - let dtor_self_type = tcx.type_of(drop_impl_did).instantiate_identity(); - match dtor_self_type.kind() { + + tcx.ensure_ok().orphan_check_impl(drop_impl_did)?; + + let dtor_impl_trait_ref = tcx.impl_trait_ref(drop_impl_did).unwrap().instantiate_identity(); + + match dtor_impl_trait_ref.self_ty().kind() { ty::Adt(adt_def, adt_to_impl_args) => { - ensure_drop_params_and_item_params_correspond( + ensure_impl_params_and_item_params_correspond( tcx, - drop_impl_did.expect_local(), + drop_impl_did, adt_def.did(), adt_to_impl_args, )?; - ensure_drop_predicates_are_implied_by_item_defn( + ensure_impl_predicates_are_implied_by_item_defn( tcx, - drop_impl_did.expect_local(), - adt_def.did().expect_local(), + drop_impl_did, + adt_def.did(), adt_to_impl_args, ) } _ => { - // Destructors only work on nominal types. This was - // already checked by coherence, but compilation may - // not have been terminated. - let span = tcx.def_span(drop_impl_did); - let reported = tcx.dcx().span_delayed_bug( - span, - format!("should have been rejected by coherence check: {dtor_self_type}"), - ); - Err(reported) + span_bug!(tcx.def_span(drop_impl_did), "incoherent impl of Drop"); } } } -fn ensure_drop_params_and_item_params_correspond<'tcx>( +pub(crate) fn check_negative_auto_trait_impl<'tcx>( tcx: TyCtxt<'tcx>, - drop_impl_did: LocalDefId, - self_type_did: DefId, + impl_def_id: LocalDefId, + impl_trait_ref: ty::TraitRef<'tcx>, + polarity: ty::ImplPolarity, +) -> Result<(), ErrorGuaranteed> { + let ty::ImplPolarity::Negative = polarity else { + return Ok(()); + }; + + if !tcx.trait_is_auto(impl_trait_ref.def_id) { + return Ok(()); + } + + if tcx.defaultness(impl_def_id).is_default() { + tcx.dcx().span_delayed_bug(tcx.def_span(impl_def_id), "default impl cannot be negative"); + } + + tcx.ensure_ok().orphan_check_impl(impl_def_id)?; + + match impl_trait_ref.self_ty().kind() { + ty::Adt(adt_def, adt_to_impl_args) => { + ensure_impl_params_and_item_params_correspond( + tcx, + impl_def_id, + adt_def.did(), + adt_to_impl_args, + )?; + + ensure_impl_predicates_are_implied_by_item_defn( + tcx, + impl_def_id, + adt_def.did(), + adt_to_impl_args, + ) + } + _ => { + if tcx.features().auto_traits() { + // NOTE: We ignore the applicability check for negative auto impls + // defined in libcore. In the (almost impossible) future where we + // stabilize auto impls, then the proper applicability check MUST + // be implemented here to handle non-ADT rigid types. + Ok(()) + } else { + Err(tcx.dcx().span_delayed_bug( + tcx.def_span(impl_def_id), + "incoherent impl of negative auto trait", + )) + } + } + } +} + +fn ensure_impl_params_and_item_params_correspond<'tcx>( + tcx: TyCtxt<'tcx>, + impl_def_id: LocalDefId, + adt_def_id: DefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_args, CheckRegions::OnlyParam) else { return Ok(()); }; - let drop_impl_span = tcx.def_span(drop_impl_did); - let item_span = tcx.def_span(self_type_did); - let self_descr = tcx.def_descr(self_type_did); + let impl_span = tcx.def_span(impl_def_id); + let item_span = tcx.def_span(adt_def_id); + let self_descr = tcx.def_descr(adt_def_id); + let polarity = match tcx.impl_polarity(impl_def_id) { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", + ty::ImplPolarity::Negative => "!", + }; + let trait_name = tcx + .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait")); let mut err = struct_span_code_err!( tcx.dcx(), - drop_impl_span, + impl_span, E0366, - "`Drop` impls cannot be specialized" + "`{polarity}{trait_name}` impls cannot be specialized", ); match arg { ty::util::NotUniqueParam::DuplicateParam(arg) => { @@ -116,17 +179,22 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( /// Confirms that all predicates defined on the `Drop` impl (`drop_impl_def_id`) are able to be /// proven from within `adt_def_id`'s environment. I.e. all the predicates on the impl are /// implied by the ADT being well formed. -fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( +fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>( tcx: TyCtxt<'tcx>, - drop_impl_def_id: LocalDefId, - adt_def_id: LocalDefId, + impl_def_id: LocalDefId, + adt_def_id: DefId, adt_to_impl_args: GenericArgsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - let impl_span = tcx.def_span(drop_impl_def_id.to_def_id()); - + let impl_span = tcx.def_span(impl_def_id.to_def_id()); + let trait_name = tcx + .item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait")); + let polarity = match tcx.impl_polarity(impl_def_id) { + ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "", + ty::ImplPolarity::Negative => "!", + }; // Take the param-env of the adt and instantiate the args that show up in // the implementation's self type. This gives us the assumptions that the // self ty of the implementation is allowed to know just from it being a @@ -145,17 +213,21 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let adt_env = ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args); - let fresh_impl_args = infcx.fresh_args_for_item(impl_span, drop_impl_def_id.to_def_id()); + let fresh_impl_args = infcx.fresh_args_for_item(impl_span, impl_def_id.to_def_id()); let fresh_adt_ty = - tcx.impl_trait_ref(drop_impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty(); + tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty(); ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty) - .unwrap(); + .expect("equating fully generic trait ref should never fail"); - for (clause, span) in tcx.predicates_of(drop_impl_def_id).instantiate(tcx, fresh_impl_args) { - let normalize_cause = traits::ObligationCause::misc(span, adt_def_id); + for (clause, span) in tcx.predicates_of(impl_def_id).instantiate(tcx, fresh_impl_args) { + let normalize_cause = traits::ObligationCause::misc(span, impl_def_id); let pred = ocx.normalize(&normalize_cause, adt_env, clause); - let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl); + let cause = traits::ObligationCause::new( + span, + impl_def_id, + ObligationCauseCode::AlwaysApplicableImpl, + ); ocx.register_obligation(traits::Obligation::new(tcx, cause, adt_env, pred)); } @@ -173,13 +245,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( let root_predicate = error.root_obligation.predicate; if root_predicates.insert(root_predicate) { let item_span = tcx.def_span(adt_def_id); - let self_descr = tcx.def_descr(adt_def_id.to_def_id()); + let self_descr = tcx.def_descr(adt_def_id); guar = Some( struct_span_code_err!( tcx.dcx(), error.root_obligation.cause.span, E0367, - "`Drop` impl requires `{root_predicate}` \ + "`{polarity}{trait_name}` impl requires `{root_predicate}` \ but the {self_descr} it is implemented for does not", ) .with_span_note(item_span, "the implementor must specify the same requirement") @@ -190,12 +262,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( return Err(guar.unwrap()); } - let errors = ocx.infcx.resolve_regions(adt_def_id, adt_env, []); + let errors = ocx.infcx.resolve_regions(impl_def_id, adt_env, []); if !errors.is_empty() { let mut guar = None; for error in errors { let item_span = tcx.def_span(adt_def_id); - let self_descr = tcx.def_descr(adt_def_id.to_def_id()); + let self_descr = tcx.def_descr(adt_def_id); let outlives = match error { RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"), RegionResolutionError::GenericBoundFailure(_, generic, r) => { @@ -212,7 +284,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( tcx.dcx(), error.origin().span(), E0367, - "`Drop` impl requires `{outlives}` \ + "`{polarity}{trait_name}` impl requires `{outlives}` \ but the {self_descr} it is implemented for does not", ) .with_span_note(item_span, "the implementor must specify the same requirement") diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index b1b046d71752b..07b5837bd871d 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -2,6 +2,8 @@ use std::cell::LazyCell; use std::ops::ControlFlow; use rustc_abi::FieldIdx; +use rustc_attr_parsing::AttributeKind; +use rustc_attr_parsing::ReprAttr::ReprPacked; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::MultiSpan; use rustc_errors::codes::*; @@ -15,27 +17,24 @@ use rustc_lint_defs::builtin::{ use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ResolvedArg; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::span_bug; use rustc_middle::ty::error::TypeErrorToStringExt; -use rustc_middle::ty::fold::{BottomUpFolder, fold_regions}; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{ - AdtDef, GenericArgKind, RegionKind, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_type_ir::fold::TypeFoldable; use tracing::{debug, instrument}; use ty::TypingMode; use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::compare_impl_item::check_type_bounds; use super::*; -use crate::check::intrinsicck::InlineAsmCtxt; pub fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: ExternAbi) { if !tcx.sess.target.is_abi_supported(abi) { @@ -70,7 +69,6 @@ fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_transparent(tcx, def); check_packed(tcx, span, def); - check_unsafe_fields(tcx, def_id); } fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) { @@ -144,36 +142,6 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b true } -/// Check that the unsafe fields do not need dropping. -fn check_unsafe_fields(tcx: TyCtxt<'_>, item_def_id: LocalDefId) { - let span = tcx.def_span(item_def_id); - let def = tcx.adt_def(item_def_id); - - let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id); - let args = ty::GenericArgs::identity_for_item(tcx, item_def_id); - - for field in def.all_fields() { - if !field.safety.is_unsafe() { - continue; - } - - if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) { - let hir::Node::Field(field) = tcx.hir_node_by_def_id(field.did.expect_local()) else { - unreachable!("field has to correspond to hir field") - }; - let ty_span = field.ty.span; - tcx.dcx().emit_err(errors::InvalidUnsafeField { - field_span: field.span, - sugg: errors::InvalidUnsafeFieldSuggestion { - lo: ty_span.shrink_to_lo(), - hi: ty_span.shrink_to_hi(), - }, - note: (), - }); - } - } -} - /// Check that a `static` is inhabited. fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { // Make sure statics are inhabited. @@ -216,7 +184,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { /// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` /// projections that would result in "inheriting lifetimes". fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) { - let hir::OpaqueTy { origin, .. } = *tcx.hir().expect_opaque_ty(def_id); + let hir::OpaqueTy { origin, .. } = *tcx.hir_expect_opaque_ty(def_id); // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting // `async-std` (and `pub async fn` in general). @@ -423,6 +391,12 @@ fn best_definition_site_of_opaque<'tcx>( return ControlFlow::Continue(()); } + let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id); + // Don't try to check items that cannot possibly constrain the type. + if !opaque_types_defined_by.contains(&self.opaque_def_id) { + return ControlFlow::Continue(()); + } + if let Some(hidden_ty) = self.tcx.mir_borrowck(item_def_id).concrete_opaque_types.get(&self.opaque_def_id) { @@ -482,19 +456,7 @@ fn best_definition_site_of_opaque<'tcx>( None } hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => { - let scope = tcx.hir_get_defining_scope(tcx.local_def_id_to_hir_id(opaque_def_id)); - let found = if scope == hir::CRATE_HIR_ID { - tcx.hir_walk_toplevel_module(&mut locator) - } else { - match tcx.hir_node(scope) { - Node::Item(it) => locator.visit_item(it), - Node::ImplItem(it) => locator.visit_impl_item(it), - Node::TraitItem(it) => locator.visit_trait_item(it), - Node::ForeignItem(it) => locator.visit_foreign_item(it), - other => bug!("{:?} is not a valid scope for an opaque type item", other), - } - }; - found.break_value() + tcx.hir_walk_toplevel_module(&mut locator).break_value() } } } @@ -745,14 +707,10 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { match tcx.def_kind(def_id) { DefKind::Static { .. } => { - tcx.ensure_ok().typeck(def_id); - maybe_check_static_with_link_section(tcx, def_id); check_static_inhabited(tcx, def_id); check_static_linkage(tcx, def_id); } - DefKind::Const => { - tcx.ensure_ok().typeck(def_id); - } + DefKind::Const => {} DefKind::Enum => { check_enum(tcx, def_id); } @@ -766,7 +724,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { ExternAbi::Rust, ) } - // Everything else is checked entirely within check_item_body } DefKind::Impl { of_trait } => { if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) { @@ -827,7 +784,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { check_type_alias_type_params_are_used(tcx, def_id); } DefKind::ForeignMod => { - let it = tcx.hir().expect_item(def_id); + let it = tcx.hir_expect_item(def_id); let hir::ItemKind::ForeignMod { abi, items } = it.kind else { return; }; @@ -895,13 +852,6 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { } } } - DefKind::GlobalAsm => { - let it = tcx.hir().expect_item(def_id); - let hir::ItemKind::GlobalAsm(asm) = it.kind else { - span_bug!(it.span, "DefKind::GlobalAsm but got {:#?}", it) - }; - InlineAsmCtxt::new_global_asm(tcx).check_asm(asm, def_id); - } _ => {} } } @@ -999,6 +949,32 @@ fn check_impl_items_against_trait<'tcx>( let trait_def = tcx.trait_def(trait_ref.def_id); + let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); + + let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id); + let param_env = tcx.param_env(impl_id); + + let self_is_guaranteed_unsized = match tcx + .struct_tail_raw( + trait_ref.self_ty(), + |ty| { + ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| { + Ty::new_error_with_message( + tcx, + tcx.def_span(impl_id), + "struct tail should be computable", + ) + }) + }, + || (), + ) + .kind() + { + ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true, + _ => false, + }; + for &impl_item in impl_item_refs { let ty_impl_item = tcx.associated_item(impl_item); let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id { @@ -1028,6 +1004,15 @@ fn check_impl_items_against_trait<'tcx>( } } + if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) { + tcx.emit_node_span_lint( + rustc_lint_defs::builtin::DEAD_CODE, + tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()), + tcx.def_span(ty_impl_item.def_id), + errors::UselessImplItem, + ) + } + check_specialization_validity( tcx, trait_def, @@ -1051,7 +1036,11 @@ fn check_impl_items_against_trait<'tcx>( .as_ref() .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value()); - if !is_implemented && tcx.defaultness(impl_id).is_final() { + if !is_implemented + && tcx.defaultness(impl_id).is_final() + // unsized types don't need to implement methods that have `Self: Sized` bounds. + && !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id)) + { missing_items.push(tcx.associated_item(trait_item_id)); } @@ -1123,7 +1112,7 @@ fn check_impl_items_against_trait<'tcx>( if let Some(missing_items) = must_implement_one_of { let attr_span = tcx .get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of) - .map(|attr| attr.span); + .map(|attr| attr.span()); missing_items_must_implement_one_of_err( tcx, @@ -1212,11 +1201,13 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) { let repr = def.repr(); if repr.packed() { - for attr in tcx.get_attrs(def.did(), sym::repr) { - for r in attr::parse_repr_attr(tcx.sess, attr) { - if let attr::ReprPacked(pack) = r + if let Some(reprs) = + attr::find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::Repr(r) => r) + { + for (r, _) in reprs { + if let ReprPacked(pack) = r && let Some(repr_pack) = repr.pack - && pack != repr_pack + && pack != &repr_pack { struct_span_code_err!( tcx.dcx(), @@ -1428,16 +1419,19 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { def.destructor(tcx); // force the destructor to be evaluated if def.variants().is_empty() { - if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() { - struct_span_code_err!( - tcx.dcx(), - attr.span, - E0084, - "unsupported representation for zero-variant enum" - ) - .with_span_label(tcx.def_span(def_id), "zero-variant enum") - .emit(); - } + attr::find_attr!( + tcx.get_all_attrs(def_id), + AttributeKind::Repr(rs) => { + struct_span_code_err!( + tcx.dcx(), + rs.first().unwrap().1, + E0084, + "unsupported representation for zero-variant enum" + ) + .with_span_label(tcx.def_span(def_id), "zero-variant enum") + .emit(); + } + ); } let repr_type_ty = def.repr().discr_type().to_ty(tcx); @@ -1480,7 +1474,6 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { detect_discriminant_duplicate(tcx, def); check_transparent(tcx, def); - check_unsafe_fields(tcx, def_id); } /// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal @@ -1721,7 +1714,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, opaque_def_id: LocalDefId) -> ErrorG opaques: Vec, closures: Vec, } - impl<'tcx> ty::visit::TypeVisitor> for OpaqueTypeCollector { + impl<'tcx> ty::TypeVisitor> for OpaqueTypeCollector { fn visit_ty(&mut self, t: Ty<'tcx>) { match *t.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => { diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index c193aad2afd00..ca820deebdfad 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -12,10 +12,9 @@ use rustc_hir::{self as hir, AmbigArg, GenericParamKind, ImplItemKind, intravisi use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::util; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::util::ExplicitSelf; use rustc_middle::ty::{ - self, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder, + self, BottomUpFolder, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypingMode, Upcast, }; use rustc_middle::{bug, span_bug}; @@ -1031,7 +1030,7 @@ fn report_trait_method_mismatch<'tcx>( // When the `impl` receiver is an arbitrary self type, like `self: Box`, the // span points only at the type `Box, but we want to cover the whole // argument pattern and type. - let (sig, body) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); + let (sig, body) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let span = tcx .hir_body_param_names(body) .zip(sig.decl.inputs.iter()) @@ -1051,7 +1050,7 @@ fn report_trait_method_mismatch<'tcx>( // Suggestion to change output type. We do not suggest in `async` functions // to avoid complex logic or incorrect output. if let ImplItemKind::Fn(sig, _) = - &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).kind + &tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).kind && !sig.header.asyncness.is_async() { let msg = "change the output type to match the trait"; @@ -1190,12 +1189,12 @@ fn extract_spans_for_error_reporting<'tcx>( ) -> (Span, Option) { let tcx = infcx.tcx; let mut impl_args = { - let (sig, _) = tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); + let (sig, _) = tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }; let trait_args = trait_m.def_id.as_local().map(|def_id| { - let (sig, _) = tcx.hir().expect_trait_item(def_id).expect_fn(); + let (sig, _) = tcx.hir_expect_trait_item(def_id).expect_fn(); sig.decl.inputs.iter().map(|t| t.span).chain(iter::once(sig.decl.output.span())) }); @@ -1371,7 +1370,7 @@ fn compare_number_of_generics<'tcx>( spans }; let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() { - let trait_item = tcx.hir().expect_trait_item(def_id); + let trait_item = tcx.hir_expect_trait_item(def_id); let arg_spans: Vec = arg_spans(trait_.kind, trait_item.generics); let impl_trait_spans: Vec = trait_item .generics @@ -1388,7 +1387,7 @@ fn compare_number_of_generics<'tcx>( (trait_span.map(|s| vec![s]), vec![]) }; - let impl_item = tcx.hir().expect_impl_item(impl_.def_id.expect_local()); + let impl_item = tcx.hir_expect_impl_item(impl_.def_id.expect_local()); let impl_item_impl_trait_spans: Vec = impl_item .generics .params @@ -1466,7 +1465,7 @@ fn compare_number_of_method_arguments<'tcx>( .def_id .as_local() .and_then(|def_id| { - let (trait_m_sig, _) = &tcx.hir().expect_trait_item(def_id).expect_fn(); + let (trait_m_sig, _) = &tcx.hir_expect_trait_item(def_id).expect_fn(); let pos = trait_number_args.saturating_sub(1); trait_m_sig.decl.inputs.get(pos).map(|arg| { if pos == 0 { @@ -1478,7 +1477,7 @@ fn compare_number_of_method_arguments<'tcx>( }) .or_else(|| tcx.hir().span_if_local(trait_m.def_id)); - let (impl_m_sig, _) = &tcx.hir().expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); + let (impl_m_sig, _) = &tcx.hir_expect_impl_item(impl_m.def_id.expect_local()).expect_fn(); let pos = impl_number_args.saturating_sub(1); let impl_span = impl_m_sig .decl @@ -1580,10 +1579,10 @@ fn compare_synthetic_generics<'tcx>( // as another generic argument let new_name = tcx.opt_item_name(trait_def_id)?; let trait_m = trait_m.def_id.as_local()?; - let trait_m = tcx.hir().expect_trait_item(trait_m); + let trait_m = tcx.hir_expect_trait_item(trait_m); let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().expect_impl_item(impl_m); + let impl_m = tcx.hir_expect_impl_item(impl_m); // in case there are no generics, take the spot between the function name // and the opening paren of the argument list @@ -1613,7 +1612,7 @@ fn compare_synthetic_generics<'tcx>( err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); let _: Option<_> = try { let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().expect_impl_item(impl_m); + let impl_m = tcx.hir_expect_impl_item(impl_m); let (sig, _) = impl_m.expect_fn(); let input_tys = sig.decl.inputs; @@ -1855,7 +1854,7 @@ fn compare_const_predicate_entailment<'tcx>( debug!(?impl_ty, ?trait_ty); // Locate the Span containing just the type of the offending impl - let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const(); + let (ty, _) = tcx.hir_expect_impl_item(impl_ct_def_id).expect_const(); cause.span = ty.span; let mut diag = struct_span_code_err!( @@ -1868,7 +1867,7 @@ fn compare_const_predicate_entailment<'tcx>( let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| { // Add a label to the Span containing just the type of the const - let (ty, _) = tcx.hir().expect_trait_item(trait_ct_def_id).expect_const(); + let (ty, _) = tcx.hir_expect_trait_item(trait_ct_def_id).expect_const(); ty.span }); diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 25c2f8554b7f4..3bad36da99909 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -99,7 +99,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { } for attr in tcx.get_attrs(main_def_id, sym::track_caller) { - tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span }); + tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span }); error = true; } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 08e0e52a4925b..42d785c8dd0fe 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -140,6 +140,10 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::fmul_algebraic | sym::fdiv_algebraic | sym::frem_algebraic + | sym::round_ties_even_f16 + | sym::round_ties_even_f32 + | sym::round_ties_even_f64 + | sym::round_ties_even_f128 | sym::const_eval_select => hir::Safety::Safe, _ => hir::Safety::Unsafe, }; @@ -416,26 +420,16 @@ pub fn check_intrinsic_type( sym::truncf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), sym::truncf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - sym::rintf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::rintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::rintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::rintf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - - sym::nearbyintf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::nearbyintf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::nearbyintf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::nearbyintf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), + sym::round_ties_even_f16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), + sym::round_ties_even_f32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), + sym::round_ties_even_f64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), + sym::round_ties_even_f128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), sym::roundf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), sym::roundf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), sym::roundf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), sym::roundf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - sym::roundevenf16 => (0, 0, vec![tcx.types.f16], tcx.types.f16), - sym::roundevenf32 => (0, 0, vec![tcx.types.f32], tcx.types.f32), - sym::roundevenf64 => (0, 0, vec![tcx.types.f64], tcx.types.f64), - sym::roundevenf128 => (0, 0, vec![tcx.types.f128], tcx.types.f128), - sym::volatile_load | sym::unaligned_volatile_load => { (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], param(0)) } @@ -651,7 +645,6 @@ pub fn check_intrinsic_type( | sym::simd_xor | sym::simd_fmin | sym::simd_fmax - | sym::simd_fpow | sym::simd_saturating_add | sym::simd_saturating_sub => (1, 0, vec![param(0), param(0)], param(0)), sym::simd_arith_offset => (2, 0, vec![param(0), param(1)], param(0)), @@ -674,7 +667,6 @@ pub fn check_intrinsic_type( | sym::simd_floor | sym::simd_round | sym::simd_trunc => (1, 0, vec![param(0)], param(0)), - sym::simd_fpowi => (1, 0, vec![param(0), tcx.types.i32], param(0)), sym::simd_fma | sym::simd_relaxed_fma => { (1, 0, vec![param(0), param(0), param(0)], param(0)) } @@ -705,7 +697,7 @@ pub fn check_intrinsic_type( | sym::simd_reduce_min | sym::simd_reduce_max => (2, 0, vec![param(0)], param(1)), sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)), - sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)), + sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)), other => { tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other }); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 90e93bdbb5075..d63165f0f1698 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -1,12 +1,13 @@ -use std::assert_matches::debug_assert_matches; - use rustc_abi::FieldIdx; use rustc_ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, LangItem}; +use rustc_infer::infer::InferCtxt; use rustc_middle::bug; -use rustc_middle::ty::{self, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy}; +use rustc_middle::ty::{ + self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, TypeckResults, UintTy, +}; use rustc_session::lint; use rustc_span::def_id::LocalDefId; use rustc_span::{Symbol, sym}; @@ -17,44 +18,53 @@ use rustc_target::asm::{ use crate::errors::RegisterTypeUnstable; pub struct InlineAsmCtxt<'a, 'tcx> { - tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - get_operand_ty: Box) -> Ty<'tcx> + 'a>, + target_features: &'tcx FxIndexSet, + infcx: &'a InferCtxt<'tcx>, + typeck_results: &'a TypeckResults<'tcx>, } enum NonAsmTypeReason<'tcx> { UnevaluatedSIMDArrayLength(DefId, ty::Const<'tcx>), Invalid(Ty<'tcx>), InvalidElement(DefId, Ty<'tcx>), + NotSizedPtr(Ty<'tcx>), } impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { - pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { + pub fn new( + def_id: LocalDefId, + infcx: &'a InferCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + typeck_results: &'a TypeckResults<'tcx>, + ) -> Self { InlineAsmCtxt { - tcx, - typing_env: ty::TypingEnv { - typing_mode: ty::TypingMode::non_body_analysis(), - param_env: ty::ParamEnv::empty(), - }, - get_operand_ty: Box::new(|e| bug!("asm operand in global asm: {e:?}")), + typing_env, + target_features: infcx.tcx.asm_target_features(def_id), + infcx, + typeck_results, } } - // FIXME(#132279): This likely causes us to incorrectly handle opaque types in their - // defining scope. - pub fn new_in_fn( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - get_operand_ty: impl Fn(&'tcx hir::Expr<'tcx>) -> Ty<'tcx> + 'a, - ) -> Self { - InlineAsmCtxt { tcx, typing_env, get_operand_ty: Box::new(get_operand_ty) } + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn expr_ty(&self, expr: &hir::Expr<'tcx>) -> Ty<'tcx> { + let ty = self.typeck_results.expr_ty_adjusted(expr); + let ty = self.infcx.resolve_vars_if_possible(ty); + if ty.has_non_region_infer() { + Ty::new_misc_error(self.tcx()) + } else { + self.tcx().erase_regions(ty) + } } // FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()` fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool { // Type still may have region variables, but `Sized` does not depend // on those, so just erase them before querying. - if ty.is_sized(self.tcx, self.typing_env) { + if ty.is_sized(self.tcx(), self.typing_env) { return true; } if let ty::Foreign(..) = ty.kind() { @@ -64,7 +74,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } fn get_asm_ty(&self, ty: Ty<'tcx>) -> Result> { - let asm_ty_isize = match self.tcx.sess.target.pointer_width { + let asm_ty_isize = match self.tcx().sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, 64 => InlineAsmType::I64, @@ -83,16 +93,22 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { ty::Float(FloatTy::F64) => Ok(InlineAsmType::F64), ty::Float(FloatTy::F128) => Ok(InlineAsmType::F128), ty::FnPtr(..) => Ok(asm_ty_isize), - ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Ok(asm_ty_isize), + ty::RawPtr(elem_ty, _) => { + if self.is_thin_ptr_ty(elem_ty) { + Ok(asm_ty_isize) + } else { + Err(NonAsmTypeReason::NotSizedPtr(ty)) + } + } ty::Adt(adt, args) if adt.repr().simd() => { let fields = &adt.non_enum_variant().fields; let field = &fields[FieldIdx::ZERO]; - let elem_ty = field.ty(self.tcx, args); + let elem_ty = field.ty(self.tcx(), args); let (size, ty) = match elem_ty.kind() { ty::Array(ty, len) => { - let len = self.tcx.normalize_erasing_regions(self.typing_env, *len); - if let Some(len) = len.try_to_target_usize(self.tcx) { + let len = self.tcx().normalize_erasing_regions(self.typing_env, *len); + if let Some(len) = len.try_to_target_usize(self.tcx()) { (len, *ty) } else { return Err(NonAsmTypeReason::UnevaluatedSIMDArrayLength( @@ -112,7 +128,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { Ok(InlineAsmType::VecI128(size)) } ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => { - Ok(match self.tcx.sess.target.pointer_width { + Ok(match self.tcx().sess.target.pointer_width { 16 => InlineAsmType::VecI16(size), 32 => InlineAsmType::VecI32(size), 64 => InlineAsmType::VecI64(size), @@ -139,9 +155,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { template: &[InlineAsmTemplatePiece], is_input: bool, tied_input: Option<(&'tcx hir::Expr<'tcx>, Option)>, - target_features: &FxIndexSet, ) -> Option { - let ty = (self.get_operand_ty)(expr); + let ty = self.expr_ty(expr); if ty.has_non_region_infer() { bug!("inference variable in asm operand ty: {:?} {:?}", expr, ty); } @@ -150,9 +165,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // `!` is allowed for input but not for output (issue #87802) ty::Never if is_input => return None, _ if ty.references_error() => return None, - ty::Adt(adt, args) if self.tcx.is_lang_item(adt.did(), LangItem::MaybeUninit) => { + ty::Adt(adt, args) if self.tcx().is_lang_item(adt.did(), LangItem::MaybeUninit) => { let fields = &adt.non_enum_variant().fields; - let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx, args); + let ty = fields[FieldIdx::from_u32(1)].ty(self.tcx(), args); // FIXME: Are we just trying to map to the `T` in `MaybeUninit`? // If so, just get it from the args. let ty::Adt(ty, args) = ty.kind() else { @@ -163,7 +178,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { "expected first field of `MaybeUninit` to be `ManuallyDrop`" ); let fields = &ty.non_enum_variant().fields; - let ty = fields[FieldIdx::ZERO].ty(self.tcx, args); + let ty = fields[FieldIdx::ZERO].ty(self.tcx(), args); self.get_asm_ty(ty) } _ => self.get_asm_ty(ty), @@ -174,9 +189,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { match reason { NonAsmTypeReason::UnevaluatedSIMDArrayLength(did, len) => { let msg = format!("cannot evaluate SIMD vector length `{len}`"); - self.tcx + self.infcx .dcx() - .struct_span_err(self.tcx.def_span(did), msg) + .struct_span_err(self.tcx().def_span(did), msg) .with_span_note( expr.span, "SIMD vector length needs to be known statically for use in `asm!`", @@ -185,17 +200,27 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } NonAsmTypeReason::Invalid(ty) => { let msg = format!("cannot use value of type `{ty}` for inline assembly"); - self.tcx.dcx().struct_span_err(expr.span, msg).with_note( + self.infcx.dcx().struct_span_err(expr.span, msg).with_note( "only integers, floats, SIMD vectors, pointers and function pointers \ can be used as arguments for inline assembly", ).emit(); } + NonAsmTypeReason::NotSizedPtr(ty) => { + let msg = format!( + "cannot use value of unsized pointer type `{ty}` for inline assembly" + ); + self.infcx + .dcx() + .struct_span_err(expr.span, msg) + .with_note("only sized pointers can be used in inline assembly") + .emit(); + } NonAsmTypeReason::InvalidElement(did, ty) => { let msg = format!( "cannot use SIMD vector with element type `{ty}` for inline assembly" ); - self.tcx.dcx() - .struct_span_err(self.tcx.def_span(did), msg).with_span_note( + self.infcx.dcx() + .struct_span_err(self.tcx().def_span(did), msg).with_span_note( expr.span, "only integers, floats, SIMD vectors, pointers and function pointers \ can be used as arguments for inline assembly", @@ -208,9 +233,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check that the type implements Copy. The only case where this can // possibly fail is for SIMD types which don't #[derive(Copy)]. - if !self.tcx.type_is_copy_modulo_regions(self.typing_env, ty) { + if !self.tcx().type_is_copy_modulo_regions(self.typing_env, ty) { let msg = "arguments for inline assembly must be copyable"; - self.tcx + self.infcx .dcx() .struct_span_err(expr.span, msg) .with_note(format!("`{ty}` does not implement the Copy trait")) @@ -229,8 +254,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { if let Some((in_expr, Some(in_asm_ty))) = tied_input { if in_asm_ty != asm_ty { let msg = "incompatible types for asm inout argument"; - let in_expr_ty = (self.get_operand_ty)(in_expr); - self.tcx + let in_expr_ty = self.expr_ty(in_expr); + self.infcx .dcx() .struct_span_err(vec![in_expr.span, expr.span], msg) .with_span_label(in_expr.span, format!("type `{in_expr_ty}`")) @@ -249,21 +274,21 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // Check the type against the list of types supported by the selected // register class. - let asm_arch = self.tcx.sess.asm_arch.unwrap(); - let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); + let asm_arch = self.tcx().sess.asm_arch.unwrap(); + let allow_experimental_reg = self.tcx().features().asm_experimental_reg(); let reg_class = reg.reg_class(); let supported_tys = reg_class.supported_types(asm_arch, allow_experimental_reg); let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else { let mut err = if !allow_experimental_reg && reg_class.supported_types(asm_arch, true).iter().any(|&(t, _)| t == asm_ty) { - self.tcx.sess.create_feature_err( + self.tcx().sess.create_feature_err( RegisterTypeUnstable { span: expr.span, ty }, sym::asm_experimental_reg, ) } else { let msg = format!("type `{ty}` cannot be used with this register class"); - let mut err = self.tcx.dcx().struct_span_err(expr.span, msg); + let mut err = self.infcx.dcx().struct_span_err(expr.span, msg); let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect(); err.note(format!( @@ -291,9 +316,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { // (!). In that case we still need the earlier check to verify that the // register class is usable at all. if let Some(feature) = feature { - if !target_features.contains(feature) { + if !self.target_features.contains(feature) { let msg = format!("`{feature}` target feature is not enabled"); - self.tcx + self.infcx .dcx() .struct_span_err(expr.span, msg) .with_note(format!( @@ -330,7 +355,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { result: default_result, size: default_size, } = reg_class.default_modifier(asm_arch).unwrap(); - self.tcx.node_span_lint( + self.tcx().node_span_lint( lint::builtin::ASM_SUB_REGISTER, expr.hir_id, spans, @@ -351,14 +376,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { Some(asm_ty) } - pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) { - let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id()); - let Some(asm_arch) = self.tcx.sess.asm_arch else { - self.tcx.dcx().delayed_bug("target architecture does not support asm"); + pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>) { + let Some(asm_arch) = self.tcx().sess.asm_arch else { + self.infcx.dcx().delayed_bug("target architecture does not support asm"); return; }; - let allow_experimental_reg = self.tcx.features().asm_experimental_reg(); - for (idx, (op, op_sp)) in asm.operands.iter().enumerate() { + let allow_experimental_reg = self.tcx().features().asm_experimental_reg(); + for (idx, &(op, op_sp)) in asm.operands.iter().enumerate() { // Validate register classes against currently enabled target // features. We check that at least one type is available for // the enabled features. @@ -380,13 +404,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } if let Err(msg) = reg.validate( asm_arch, - self.tcx.sess.relocation_model(), - target_features, - &self.tcx.sess.target, + self.tcx().sess.relocation_model(), + self.target_features, + &self.tcx().sess.target, op.is_clobber(), ) { let msg = format!("cannot use register `{}`: {}", reg.name(), msg); - self.tcx.dcx().span_err(*op_sp, msg); + self.infcx.dcx().span_err(op_sp, msg); continue; } } @@ -401,7 +425,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { { match feature { Some(feature) => { - if target_features.contains(&feature) { + if self.target_features.contains(&feature) { missing_required_features.clear(); break; } else { @@ -426,7 +450,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { reg_class.name(), feature ); - self.tcx.dcx().span_err(*op_sp, msg); + self.infcx.dcx().span_err(op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -440,7 +464,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { .intersperse(", ") .collect::(), ); - self.tcx.dcx().span_err(*op_sp, msg); + self.infcx.dcx().span_err(op_sp, msg); // register isn't enabled, don't do more checks continue; } @@ -448,52 +472,21 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { } } - match *op { + match op { hir::InlineAsmOperand::In { reg, expr } => { - self.check_asm_operand_type( - idx, - reg, - expr, - asm.template, - true, - None, - target_features, - ); + self.check_asm_operand_type(idx, reg, expr, asm.template, true, None); } hir::InlineAsmOperand::Out { reg, late: _, expr } => { if let Some(expr) = expr { - self.check_asm_operand_type( - idx, - reg, - expr, - asm.template, - false, - None, - target_features, - ); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } } hir::InlineAsmOperand::InOut { reg, late: _, expr } => { - self.check_asm_operand_type( - idx, - reg, - expr, - asm.template, - false, - None, - target_features, - ); + self.check_asm_operand_type(idx, reg, expr, asm.template, false, None); } hir::InlineAsmOperand::SplitInOut { reg, late: _, in_expr, out_expr } => { - let in_ty = self.check_asm_operand_type( - idx, - reg, - in_expr, - asm.template, - true, - None, - target_features, - ); + let in_ty = + self.check_asm_operand_type(idx, reg, in_expr, asm.template, true, None); if let Some(out_expr) = out_expr { self.check_asm_operand_type( idx, @@ -502,23 +495,47 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { asm.template, false, Some((in_expr, in_ty)), - target_features, ); } } - // Typeck has checked that Const operands are integers. hir::InlineAsmOperand::Const { anon_const } => { - debug_assert_matches!( - self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(), - ty::Error(_) | ty::Int(_) | ty::Uint(_) - ); + let ty = self.expr_ty(self.tcx().hir_body(anon_const.body).value); + match ty.kind() { + ty::Error(_) => {} + _ if ty.is_integral() => {} + _ => { + self.infcx + .dcx() + .struct_span_err(op_sp, "invalid type for `const` operand") + .with_span_label( + self.tcx().def_span(anon_const.def_id), + format!("is {} `{}`", ty.kind().article(), ty), + ) + .with_help("`const` operands must be of an integer type") + .emit(); + } + } } // Typeck has checked that SymFn refers to a function. - hir::InlineAsmOperand::SymFn { anon_const } => { - debug_assert_matches!( - self.tcx.type_of(anon_const.def_id).instantiate_identity().kind(), - ty::Error(_) | ty::FnDef(..) - ); + hir::InlineAsmOperand::SymFn { expr } => { + let ty = self.expr_ty(expr); + match ty.kind() { + ty::FnDef(..) => {} + ty::Error(_) => {} + _ => { + self.infcx + .dcx() + .struct_span_err(op_sp, "invalid `sym` operand") + .with_span_label( + expr.span, + format!("is {} `{}`", ty.kind().article(), ty), + ) + .with_help( + "`sym` operands must refer to either a function or a static", + ) + .emit(); + } + } } // AST lowering guarantees that SymStatic points to a static. hir::InlineAsmOperand::SymStatic { .. } => {} diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 1c5455710db8a..b4a16b2b8054c 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -62,9 +62,9 @@ a type parameter). */ +pub mod always_applicable; mod check; mod compare_impl_item; -pub mod dropck; mod entry; pub mod intrinsic; pub mod intrinsicck; @@ -84,6 +84,7 @@ use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; +use rustc_middle::ty::print::with_types_for_signature; use rustc_middle::ty::{self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypingMode}; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -113,11 +114,11 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_dtor(def_id.to_def_id(), dropck::check_drop_impl) + tcx.calculate_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) } fn adt_async_destructor(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - tcx.calculate_async_dtor(def_id.to_def_id(), dropck::check_drop_impl) + tcx.calculate_async_dtor(def_id.to_def_id(), always_applicable::check_drop_impl) } /// Given a `DefId` for an opaque type in return position, find its parent item's return @@ -145,7 +146,7 @@ pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: ExternAbi) { } } -fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { +pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { // Only restricted on wasm target for now if !tcx.sess.target.is_like_wasm { return; @@ -240,11 +241,11 @@ fn missing_items_err( (Vec::new(), Vec::new(), Vec::new()); for &trait_item in missing_items { - let snippet = suggestion_signature( + let snippet = with_types_for_signature!(suggestion_signature( tcx, trait_item, tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(), - ); + )); let code = format!("{padding}{snippet}\n{padding}"); if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { missing_trait_item_label diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index e6ea6eddcaaf3..4769153ff4d0d 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -16,10 +16,12 @@ use rustc_lint_defs::builtin::SUPERTRAIT_ITEM_SHADOWING_DEFINITION; use rustc_macros::LintDiagnostic; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::query::Providers; +use rustc_middle::traits::solve::NoSolution; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ - self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast, + self, AdtKind, GenericArgKind, GenericArgs, GenericParamDefKind, Ty, TyCtxt, TypeFlags, + TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + Upcast, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -34,8 +36,6 @@ use rustc_trait_selection::traits::{ self, FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, WellFormedLoc, }; -use rustc_type_ir::TypeFlags; -use rustc_type_ir::solve::NoSolution; use tracing::{debug, instrument}; use {rustc_ast as ast, rustc_hir as hir}; @@ -126,13 +126,14 @@ where let infcx_compat = infcx.fork(); - // We specifically want to call the non-compat version of `implied_bounds_tys`; we do this always. + // We specifically want to *disable* the implied bounds hack, first, + // so we can detect when failures are due to bevy's implied bounds. let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat( &infcx, body_def_id, param_env, assumed_wf_types.iter().copied(), - false, + true, ); lint_redundant_lifetimes(tcx, body_def_id, &outlives_env); @@ -142,53 +143,22 @@ where return Ok(()); } - let is_bevy = assumed_wf_types.visit_with(&mut ContainsBevyParamSet { tcx }).is_break(); - - // If we have set `no_implied_bounds_compat`, then do not attempt compatibility. - // We could also just always enter if `is_bevy`, and call `implied_bounds_tys`, - // but that does result in slightly more work when this option is set and - // just obscures what we mean here anyways. Let's just be explicit. - if is_bevy && !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat { - let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat( - &infcx, - body_def_id, - param_env, - assumed_wf_types, - true, - ); - let errors_compat = infcx_compat.resolve_regions_with_outlives_env(&outlives_env); - if errors_compat.is_empty() { - Ok(()) - } else { - Err(infcx_compat.err_ctxt().report_region_errors(body_def_id, &errors_compat)) - } + let outlives_env = OutlivesEnvironment::new_with_implied_bounds_compat( + &infcx_compat, + body_def_id, + param_env, + assumed_wf_types, + // Don't *disable* the implied bounds hack; though this will only apply + // the implied bounds hack if this contains `bevy_ecs`'s `ParamSet` type. + false, + ); + let errors_compat = infcx_compat.resolve_regions_with_outlives_env(&outlives_env); + if errors_compat.is_empty() { + // FIXME: Once we fix bevy, this would be the place to insert a warning + // to upgrade bevy. + Ok(()) } else { - Err(infcx.err_ctxt().report_region_errors(body_def_id, &errors)) - } -} - -struct ContainsBevyParamSet<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> TypeVisitor> for ContainsBevyParamSet<'tcx> { - type Result = ControlFlow<()>; - - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - // We only care to match `ParamSet` or `&ParamSet`. - match t.kind() { - ty::Adt(def, _) => { - if self.tcx.item_name(def.did()) == sym::ParamSet - && self.tcx.crate_name(def.did().krate) == sym::bevy_ecs - { - return ControlFlow::Break(()); - } - } - ty::Ref(_, ty, _) => ty.visit_with(self)?, - _ => {} - } - - ControlFlow::Continue(()) + Err(infcx_compat.err_ctxt().report_region_errors(body_def_id, &errors_compat)) } } @@ -201,7 +171,7 @@ fn check_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGua hir::Node::ImplItem(item) => check_impl_item(tcx, item), hir::Node::ForeignItem(item) => check_foreign_item(tcx, item), hir::Node::OpaqueTy(_) => Ok(crate::check::check::check_item_type(tcx, def_id)), - _ => unreachable!(), + _ => unreachable!("{node:?}"), }; if let Some(generics) = node.generics() { @@ -543,7 +513,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { continue; } - let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id); + let gat_item_hir = tcx.hir_expect_trait_item(gat_def_id); debug!(?required_bounds); let param_env = tcx.param_env(gat_def_id); @@ -966,7 +936,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), let ty = tcx.type_of(param.def_id).instantiate_identity(); if tcx.features().unsized_const_params() { - enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| { wfcx.register_bound( ObligationCause::new( hir_ty.span, @@ -980,7 +950,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), Ok(()) }) } else if tcx.features().adt_const_params() { - enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { + enter_wf_checking_ctxt(tcx, hir_ty.span, tcx.local_parent(param.def_id), |wfcx| { wfcx.register_bound( ObligationCause::new( hir_ty.span, @@ -1108,7 +1078,13 @@ fn check_associated_item( let ty = tcx.type_of(item.def_id).instantiate_identity(); let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); - check_sized_if_body(wfcx, item.def_id.expect_local(), ty, Some(span)); + check_sized_if_body( + wfcx, + item.def_id.expect_local(), + ty, + Some(span), + ObligationCauseCode::SizedConstOrStatic, + ); Ok(()) } ty::AssocKind::Fn => { @@ -1354,7 +1330,7 @@ fn check_item_type( traits::ObligationCause::new( ty_span, wfcx.body_def_id, - ObligationCauseCode::WellFormed(None), + ObligationCauseCode::SizedConstOrStatic, ), wfcx.param_env, item_ty, @@ -1544,7 +1520,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id struct CountParams { params: FxHashSet, } - impl<'tcx> ty::visit::TypeVisitor> for CountParams { + impl<'tcx> ty::TypeVisitor> for CountParams { type Result = ControlFlow<()>; fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { if let ty::Param(param) = t.kind() { @@ -1698,6 +1674,7 @@ fn check_fn_or_method<'tcx>( hir::FnRetTy::Return(ty) => Some(ty.span), hir::FnRetTy::DefaultReturn(_) => None, }, + ObligationCauseCode::SizedReturnType, ); } @@ -1706,13 +1683,14 @@ fn check_sized_if_body<'tcx>( def_id: LocalDefId, ty: Ty<'tcx>, maybe_span: Option, + code: ObligationCauseCode<'tcx>, ) { let tcx = wfcx.tcx(); if let Some(body) = tcx.hir_maybe_body_owned_by(def_id) { let span = maybe_span.unwrap_or(body.value.span); wfcx.register_bound( - ObligationCause::new(span, def_id, traits::ObligationCauseCode::SizedReturnType), + ObligationCause::new(span, def_id, code), wfcx.param_env, ty, tcx.require_lang_item(LangItem::Sized, Some(span)), diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 750c09887a1e5..464ffa8711a53 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -31,7 +31,7 @@ fn check_unused_traits(tcx: TyCtxt<'_>, (): ()) { if used_trait_imports.contains(&id) { continue; } - let item = tcx.hir().expect_item(id); + let item = tcx.hir_expect_item(id); if item.span.is_dummy() { continue; } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index b46b805f0a9d2..1f3f0b754bb1e 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params, }; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, @@ -82,7 +82,7 @@ fn visit_implementation_of_drop(checker: &Checker<'_>) -> Result<(), ErrorGuaran _ => {} } - let impl_ = tcx.hir().expect_item(impl_did).expect_impl(); + let impl_ = tcx.hir_expect_item(impl_did).expect_impl(); Err(tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span })) } @@ -109,7 +109,7 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) { Ok(()) => Ok(()), Err(CopyImplementationError::InfringingFields(fields)) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(infringing_fields_error( tcx, fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)), @@ -119,15 +119,15 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran )) } Err(CopyImplementationError::NotAnAdt) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span })) } Err(CopyImplementationError::HasDestructor) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span })) } Err(CopyImplementationError::HasUnsafeFields) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(tcx .dcx() .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type))) @@ -157,7 +157,7 @@ fn visit_implementation_of_const_param_ty( match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) { Ok(()) => Ok(()), Err(ConstParamTyImplementationError::InfrigingFields(fields)) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(infringing_fields_error( tcx, fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)), @@ -167,11 +167,11 @@ fn visit_implementation_of_const_param_ty( )) } Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span })) } Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(infringing_fields_error( tcx, infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)), @@ -181,7 +181,7 @@ fn visit_implementation_of_const_param_ty( )) } Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => { - let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span })) } } @@ -195,8 +195,14 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E // Just compute this for the side-effects, in particular reporting // errors; other parts of the code may demand it for the info of // course. - let span = tcx.def_span(impl_did); - tcx.at(span).ensure_ok().coerce_unsized_info(impl_did) + tcx.ensure_ok().coerce_unsized_info(impl_did) +} + +fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool { + span.ctxt() + .outer_expn_data() + .macro_def_id + .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id)) } fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { @@ -206,17 +212,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did); let span = tcx.def_span(impl_did); + let trait_name = "DispatchFromDyn"; let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span)); let source = trait_ref.self_ty(); - assert!(!source.has_escaping_bound_vars()); let target = { assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait); trait_ref.args.type_at(1) }; + // Check `CoercePointee` impl is WF -- if not, then there's no reason to report + // redundant errors for `DispatchFromDyn`. This is best effort, though. + let mut res = Ok(()); + tcx.for_each_relevant_impl( + tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)), + source, + |impl_def_id| { + res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id)); + }, + ); + res?; + debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target); let param_env = tcx.param_env(impl_did); @@ -232,36 +250,38 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() // trait, they *do* satisfy the repr(transparent) rules, and then we assume that everything else // in the compiler (in particular, all the call ABI logic) will treat them as repr(transparent) // even if they do not carry that attribute. - use rustc_type_ir::TyKind::*; match (source.kind(), target.kind()) { - (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if r_a == *r_b && mutbl_a == *mutbl_b => { + (&ty::Ref(r_a, _, mutbl_a), ty::Ref(r_b, _, mutbl_b)) + if r_a == *r_b && mutbl_a == *mutbl_b => + { Ok(()) } - (&RawPtr(_, a_mutbl), &RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()), - (&Adt(def_a, args_a), &Adt(def_b, args_b)) if def_a.is_struct() && def_b.is_struct() => { + (&ty::RawPtr(_, a_mutbl), &ty::RawPtr(_, b_mutbl)) if a_mutbl == b_mutbl => Ok(()), + (&ty::Adt(def_a, args_a), &ty::Adt(def_b, args_b)) + if def_a.is_struct() && def_b.is_struct() => + { if def_a != def_b { let source_path = tcx.def_path_str(def_a.did()); let target_path = tcx.def_path_str(def_b.did()); - - return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion { + return Err(tcx.dcx().emit_err(errors::CoerceSameStruct { span, - trait_name: "DispatchFromDyn", + trait_name, note: true, source_path, target_path, })); } - let mut res = Ok(()); if def_a.repr().c() || def_a.repr().packed() { - res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span })); + return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span })); } let fields = &def_a.non_enum_variant().fields; + let mut res = Ok(()); let coerced_fields = fields - .iter() - .filter(|field| { + .iter_enumerated() + .filter_map(|(i, field)| { // Ignore PhantomData fields let unnormalized_ty = tcx.type_of(field.did).instantiate_identity(); if tcx @@ -272,7 +292,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() .unwrap_or(unnormalized_ty) .is_phantom_data() { - return false; + return None; } let ty_a = field.ty(tcx, args_a); @@ -290,7 +310,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() && !ty_a.has_non_region_param() { // ignore 1-ZST fields - return false; + return None; } res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST { @@ -299,64 +319,57 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<() ty: ty_a, })); - return false; + None + } else { + Some((i, ty_a, ty_b, tcx.def_span(field.did))) } - - true }) .collect::>(); + res?; if coerced_fields.is_empty() { - res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle { + return Err(tcx.dcx().emit_err(errors::CoerceNoField { span, - trait_name: "DispatchFromDyn", + trait_name, note: true, })); - } else if coerced_fields.len() > 1 { - res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti { - span, - coercions_note: true, - number: coerced_fields.len(), - coercions: coerced_fields - .iter() - .map(|field| { - format!( - "`{}` (`{}` to `{}`)", - field.name, - field.ty(tcx, args_a), - field.ty(tcx, args_b), - ) - }) - .collect::>() - .join(", "), - })); - } else { + } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] { let ocx = ObligationCtxt::new_with_diagnostics(&infcx); - for field in coerced_fields { - ocx.register_obligation(Obligation::new( - tcx, - cause.clone(), - param_env, - ty::TraitRef::new( - tcx, - dispatch_from_dyn_trait, - [field.ty(tcx, args_a), field.ty(tcx, args_b)], - ), - )); - } + ocx.register_obligation(Obligation::new( + tcx, + cause.clone(), + param_env, + ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]), + )); let errors = ocx.select_all_or_error(); if !errors.is_empty() { - res = Err(infcx.err_ctxt().report_fulfillment_errors(errors)); + if is_from_coerce_pointee_derive(tcx, span) { + return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity { + span, + trait_name, + ty: trait_ref.self_ty(), + field_span, + field_ty: ty_a, + })); + } else { + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); + } } // Finally, resolve all regions. - res = res.and(ocx.resolve_regions_and_report_errors(impl_did, param_env, [])); + ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?; + + Ok(()) + } else { + return Err(tcx.dcx().emit_err(errors::CoerceMulti { + span, + trait_name, + number: coerced_fields.len(), + fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::>().into(), + })); } - res } - _ => Err(tcx - .dcx() - .emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })), + _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })), } } @@ -366,13 +379,14 @@ pub(crate) fn coerce_unsized_info<'tcx>( ) -> Result { debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did); let span = tcx.def_span(impl_did); + let trait_name = "CoerceUnsized"; let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); let source = tcx.type_of(impl_did).instantiate_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity(); + assert_eq!(trait_ref.def_id, coerce_unsized_trait); let target = trait_ref.args.type_at(1); debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target); @@ -399,9 +413,9 @@ pub(crate) fn coerce_unsized_info<'tcx>( ) .emit(); } - (mt_a.ty, mt_b.ty, unsize_trait, None) + (mt_a.ty, mt_b.ty, unsize_trait, None, span) }; - let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { + let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) { (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; @@ -422,9 +436,9 @@ pub(crate) fn coerce_unsized_info<'tcx>( if def_a != def_b { let source_path = tcx.def_path_str(def_a.did()); let target_path = tcx.def_path_str(def_b.did()); - return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame { + return Err(tcx.dcx().emit_err(errors::CoerceSameStruct { span, - trait_name: "CoerceUnsized", + trait_name, note: true, source_path, target_path, @@ -504,45 +518,39 @@ pub(crate) fn coerce_unsized_info<'tcx>( // Collect up all fields that were significantly changed // i.e., those that contain T in coerce_unsized T -> U - Some((i, a, b)) + Some((i, a, b, tcx.def_span(f.did))) }) .collect::>(); if diff_fields.is_empty() { - return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField { + return Err(tcx.dcx().emit_err(errors::CoerceNoField { span, - trait_name: "CoerceUnsized", + trait_name, note: true, })); } else if diff_fields.len() > 1 { - let item = tcx.hir().expect_item(impl_did); + let item = tcx.hir_expect_item(impl_did); let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind { t.path.span } else { tcx.def_span(impl_did) }; - return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti { + return Err(tcx.dcx().emit_err(errors::CoerceMulti { span, - coercions_note: true, + trait_name, number: diff_fields.len(), - coercions: diff_fields - .iter() - .map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)) - .collect::>() - .join(", "), + fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::>().into(), })); } - let (i, a, b) = diff_fields[0]; + let (i, a, b, field_span) = diff_fields[0]; let kind = ty::adjustment::CustomCoerceUnsized::Struct(i); - (a, b, coerce_unsized_trait, Some(kind)) + (a, b, coerce_unsized_trait, Some(kind), field_span) } _ => { - return Err(tcx - .dcx() - .emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" })); + return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })); } }; @@ -557,12 +565,23 @@ pub(crate) fn coerce_unsized_info<'tcx>( ); ocx.register_obligation(obligation); let errors = ocx.select_all_or_error(); + if !errors.is_empty() { - infcx.err_ctxt().report_fulfillment_errors(errors); + if is_from_coerce_pointee_derive(tcx, span) { + return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity { + span, + trait_name, + ty: trait_ref.self_ty(), + field_span, + field_ty: source, + })); + } else { + return Err(infcx.err_ctxt().report_fulfillment_errors(errors)); + } } // Finally, resolve all regions. - let _ = ocx.resolve_regions_and_report_errors(impl_did, param_env, []); + ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?; Ok(CoerceUnsizedInfo { custom_kind: kind }) } diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 1bc60087ab5ee..15e0a72fdcbd5 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -10,12 +10,12 @@ use rustc_errors::struct_span_code_err; use rustc_hir::LangItem; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt, elaborate}; use rustc_session::parse::feature_err; use rustc_span::{ErrorGuaranteed, sym}; -use rustc_type_ir::elaborate; use tracing::debug; +use crate::check::always_applicable; use crate::errors; mod builtin; @@ -24,11 +24,12 @@ mod inherent_impls_overlap; mod orphan; mod unsafety; -fn check_impl( - tcx: TyCtxt<'_>, +fn check_impl<'tcx>( + tcx: TyCtxt<'tcx>, impl_def_id: LocalDefId, - trait_ref: ty::TraitRef<'_>, - trait_def: &ty::TraitDef, + trait_ref: ty::TraitRef<'tcx>, + trait_def: &'tcx ty::TraitDef, + polarity: ty::ImplPolarity, ) -> Result<(), ErrorGuaranteed> { debug!( "(checking implementation) adding impl for trait '{:?}', item '{}'", @@ -44,6 +45,12 @@ fn check_impl( enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id, trait_def) .and(enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id, trait_def)) + .and(always_applicable::check_negative_auto_trait_impl( + tcx, + impl_def_id, + trait_ref, + polarity, + )) } fn enforce_trait_manually_implementable( @@ -154,16 +161,16 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> let mut res = tcx.ensure_ok().specialization_graph_of(def_id); for &impl_def_id in impls { - let trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); - let trait_ref = trait_header.trait_ref.instantiate_identity(); + let impl_header = tcx.impl_trait_header(impl_def_id).unwrap(); + let trait_ref = impl_header.trait_ref.instantiate_identity(); let trait_def = tcx.trait_def(trait_ref.def_id); res = res - .and(check_impl(tcx, impl_def_id, trait_ref, trait_def)) + .and(check_impl(tcx, impl_def_id, trait_ref, trait_def, impl_header.polarity)) .and(check_object_overlap(tcx, impl_def_id, trait_ref)) - .and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def)) + .and(unsafety::check_item(tcx, impl_def_id, impl_header, trait_def)) .and(tcx.ensure_ok().orphan_check_impl(impl_def_id)) - .and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header)); + .and(builtin::check_trait(tcx, def_id, impl_def_id, impl_header)); } res @@ -199,11 +206,7 @@ fn check_object_overlap<'tcx>( for component_def_id in component_def_ids { if !tcx.is_dyn_compatible(component_def_id) { - // Without the 'dyn_compatible_for_dispatch' feature this is an error - // which will be reported by wfcheck. Ignore it here. - // This is tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`. - // With the feature enabled, the trait is not implemented automatically, - // so this is valid. + // This is a WF error tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`. } else { let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index dbf7a7378f5ab..0b7fc44460ead 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -376,7 +376,7 @@ fn emit_orphan_check_error<'tcx>( ) -> ErrorGuaranteed { match err { traits::OrphanCheckErr::NonLocalInputType(tys) => { - let item = tcx.hir().expect_item(impl_def_id); + let item = tcx.hir_expect_item(impl_def_id); let impl_ = item.expect_impl(); let hir_trait_ref = impl_.of_trait.as_ref().unwrap(); diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 5bb77c096dcf8..54a630f5b005a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -20,7 +20,6 @@ use std::ops::Bound; use rustc_abi::ExternAbi; use rustc_ast::Recovered; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::unord::UnordMap; use rustc_errors::{ @@ -29,14 +28,13 @@ use rustc_errors::{ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt, walk_generics}; -use rustc_hir::{self as hir, GenericParamKind, HirId, Node}; +use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgKind}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; use rustc_middle::query::Providers; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::util::{Discr, IntTypeExt}; -use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode, fold_regions}; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::suggestions::NextTypeParamName; @@ -46,6 +44,7 @@ use tracing::{debug, instrument}; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::errors; +use crate::hir_ty_lowering::errors::assoc_kind_str; use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason}; pub(crate) mod dump; @@ -444,13 +443,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { self.tcx.at(span).type_param_predicates((self.item_def_id, def_id, assoc_name)) } - fn lower_assoc_ty( + fn lower_assoc_shared( &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'tcx>, + item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx> { + kind: ty::AssocKind, + ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { if let Some(trait_ref) = poly_trait_ref.no_bound_vars() { let item_args = self.lowerer().lower_generic_args_of_assoc_item( span, @@ -458,7 +458,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { item_segment, trait_ref.args, ); - Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) + Ok((item_def_id, item_args)) } else { // There are no late-bound regions; we can just ignore the binder. let (mut mpart_sugg, mut inferred_sugg) = (None, None); @@ -468,8 +468,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => { let item = self .tcx - .hir() - .expect_item(self.tcx.hir_get_parent_item(self.hir_id()).def_id); + .hir_expect_item(self.tcx.hir_get_parent_item(self.hir_id()).def_id); match &item.kind { hir::ItemKind::Enum(_, generics) | hir::ItemKind::Struct(_, generics) @@ -519,16 +518,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } _ => {} } - Ty::new_error( - self.tcx(), - self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams { - span, - inferred_sugg, - bound, - mpart_sugg, - what: "type", - }), - ) + + Err(self.tcx().dcx().emit_err(errors::AssociatedItemTraitUninferredGenericParams { + span, + inferred_sugg, + bound, + mpart_sugg, + what: assoc_kind_str(kind), + })) } } @@ -680,7 +677,7 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { | hir::ItemKind::Use(..) | hir::ItemKind::Macro(..) | hir::ItemKind::Mod(_) - | hir::ItemKind::GlobalAsm(_) => {} + | hir::ItemKind::GlobalAsm { .. } => {} hir::ItemKind::ForeignMod { items, .. } => { for item in *items { let item = tcx.hir_foreign_item(item.id); @@ -1075,7 +1072,6 @@ fn lower_variant<'tcx>( def.ctor().map(|(kind, _, def_id)| (kind, def_id.to_def_id())), discr, fields, - adt_kind, parent_did.to_def_id(), recovered, adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive) @@ -1145,7 +1141,7 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { } fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { - let item = tcx.hir().expect_item(def_id); + let item = tcx.hir_expect_item(def_id); let (is_alias, is_auto, safety, items) = match item.kind { hir::ItemKind::Trait(is_auto, safety, .., items) => { @@ -1203,7 +1199,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { // and that they are all identifiers .and_then(|attr| match attr.meta_item_list() { Some(items) if items.len() < 2 => { - tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span }); + tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span() }); None } @@ -1215,7 +1211,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef { tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span }); }) .ok() - .zip(Some(attr.span)), + .zip(Some(attr.span())), // Error is reported by `rustc_attr!` None => None, }) @@ -1344,7 +1340,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, ty::PolyFn ), ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(sig, _, _), .. }) => { - let abi = tcx.hir().get_foreign_abi(hir_id); + let abi = tcx.hir_get_foreign_abi(hir_id); compute_sig_of_foreign_fn_decl(tcx, def_id, sig.decl, abi, sig.header.safety()) } @@ -1599,7 +1595,7 @@ pub fn suggest_impl_trait<'tcx>( fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option> { let icx = ItemCtxt::new(tcx, def_id); - let item = tcx.hir().expect_item(def_id); + let item = tcx.hir_expect_item(def_id); let impl_ = item.expect_impl(); impl_.of_trait.as_ref().map(|ast_trait_ref| { let selfty = tcx.type_of(def_id).instantiate_identity(); @@ -1690,10 +1686,10 @@ fn polarity_of_impl( /// the lifetimes that are declared. For fns or methods, we have to /// screen out those that do not appear in any where-clauses etc using /// `resolve_lifetime::early_bound_lifetimes`. -fn early_bound_lifetimes_from_generics<'a, 'tcx: 'a>( +fn early_bound_lifetimes_from_generics<'a, 'tcx>( tcx: TyCtxt<'tcx>, generics: &'a hir::Generics<'a>, -) -> impl Iterator> + Captures<'tcx> { +) -> impl Iterator> { generics.params.iter().filter(move |param| match param.kind { GenericParamKind::Lifetime { .. } => !tcx.is_late_bound(param.hir_id), _ => false, @@ -1794,7 +1790,7 @@ fn opaque_ty_origin<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> hir::OpaqueT fn rendered_precise_capturing_args<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> Option<&'tcx [Symbol]> { +) -> Option<&'tcx [PreciseCapturingArgKind]> { if let Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) = tcx.opt_rpitit_info(def_id.to_def_id()) { @@ -1803,7 +1799,12 @@ fn rendered_precise_capturing_args<'tcx>( tcx.hir_node_by_def_id(def_id).expect_opaque_ty().bounds.iter().find_map(|bound| match bound { hir::GenericBound::Use(args, ..) => { - Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| arg.name()))) + Some(&*tcx.arena.alloc_from_iter(args.iter().map(|arg| match arg { + PreciseCapturingArgKind::Lifetime(_) => { + PreciseCapturingArgKind::Lifetime(arg.name()) + } + PreciseCapturingArgKind::Param(_) => PreciseCapturingArgKind::Param(arg.name()), + }))) } _ => None, }) @@ -1824,6 +1825,9 @@ fn const_param_default<'tcx>( ), }; let icx = ItemCtxt::new(tcx, def_id); - let ct = icx.lowerer().lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id())); + let identity_args = ty::GenericArgs::identity_for_item(tcx, def_id); + let ct = icx + .lowerer() + .lower_const_arg(default_ct, FeedConstTy::Param(def_id.to_def_id(), identity_args)); ty::EarlyBinder::bind(ct) } diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs index 63c445fa6a3d4..7cbd31de6bab2 100644 --- a/compiler/rustc_hir_analysis/src/collect/dump.rs +++ b/compiler/rustc_hir_analysis/src/collect/dump.rs @@ -13,7 +13,7 @@ pub(crate) fn opaque_hidden_types(tcx: TyCtxt<'_>) { for id in tcx.hir_crate_items(()).opaques() { if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. } | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = - tcx.hir().expect_opaque_ty(id).origin + tcx.hir_expect_opaque_ty(id).origin && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id) && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn() { @@ -111,14 +111,14 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity(); if trait_ref.has_non_region_param() { tcx.dcx().span_err( - attr.span, + attr.span(), "`rustc_dump_vtable` must be applied to non-generic impl", ); continue; } if !tcx.is_dyn_compatible(trait_ref.def_id) { tcx.dcx().span_err( - attr.span, + attr.span(), "`rustc_dump_vtable` must be applied to dyn-compatible trait", ); continue; @@ -127,7 +127,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref) else { tcx.dcx().span_err( - attr.span, + attr.span(), "`rustc_dump_vtable` applied to impl header that cannot be normalized", ); continue; @@ -138,7 +138,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { let ty = tcx.type_of(def_id).instantiate_identity(); if ty.has_non_region_param() { tcx.dcx().span_err( - attr.span, + attr.span(), "`rustc_dump_vtable` must be applied to non-generic type", ); continue; @@ -147,13 +147,14 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty) else { tcx.dcx().span_err( - attr.span, + attr.span(), "`rustc_dump_vtable` applied to type alias that cannot be normalized", ); continue; }; let ty::Dynamic(data, _, _) = *ty.kind() else { - tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type"); + tcx.dcx() + .span_err(attr.span(), "`rustc_dump_vtable` to type alias of dyn type"); continue; }; if let Some(principal) = data.principal() { @@ -166,7 +167,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) { } _ => { tcx.dcx().span_err( - attr.span, + attr.span(), "`rustc_dump_vtable` only applies to impl, or type alias of dyn type", ); continue; diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index a363076b75ac1..a153ce8ea902d 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -186,19 +186,9 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { { Some(parent_did) } - // Exclude `GlobalAsm` here which cannot have generics. - Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - if asm.operands.iter().any(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } => { - anon_const.hir_id == hir_id - } - _ => false, - }) => - { - Some(parent_did) - } Node::TyPat(_) => Some(parent_did), + // Field default values inherit the ADT's generics. + Node::Field(_) => Some(parent_did), _ => None, } } diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 1c1a246cc1519..6e07f0ff53c39 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -1,14 +1,13 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::util; -use rustc_middle::ty::fold::shift_vars; use rustc_middle::ty::{ self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + Upcast, shift_vars, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; use rustc_span::def_id::{DefId, LocalDefId}; -use rustc_type_ir::Upcast; use tracing::{debug, instrument}; use super::ItemCtxt; diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 5b511d270743b..2022127a15b05 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -223,10 +223,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen } hir::GenericParamKind::Const { .. } => { let param_def_id = param.def_id.to_def_id(); - let ct_ty = tcx - .type_of(param_def_id) - .no_bound_vars() - .expect("const parameters cannot be generic"); + let ct_ty = tcx.type_of(param_def_id).instantiate_identity(); let ct = icx.lowerer().lower_const_param(param_def_id, param.hir_id); predicates .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span)); @@ -940,12 +937,6 @@ impl<'tcx> ItemCtxt<'tcx> { } } -/// Compute the conditions that need to hold for a conditionally-const item to be const. -/// That is, compute the set of `~const` where clauses for a given item. -/// -/// This query also computes the `~const` where clauses for associated types, which are -/// not "const", but which have item bounds which may be `~const`. These must hold for -/// the `~const` item bound to hold. pub(super) fn const_conditions<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, @@ -1063,7 +1054,9 @@ pub(super) fn explicit_implied_const_bounds<'tcx>( def_id: LocalDefId, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { if !tcx.is_conditionally_const(def_id) { - bug!("const_conditions invoked for item that is not conditionally const: {def_id:?}"); + bug!( + "explicit_implied_const_bounds invoked for item that is not conditionally const: {def_id:?}" + ); } let bounds = match tcx.opt_rpitit_info(def_id.to_def_id()) { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index fee3c6088ede8..883a1acdb3094 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -160,7 +160,7 @@ enum Scope<'a> { impl<'a> Scope<'a> { // A helper for debugging scopes without printing parent scopes - fn debug_truncated(&'a self) -> impl fmt::Debug + 'a { + fn debug_truncated(&self) -> impl fmt::Debug { fmt::from_fn(move |f| match self { Self::Binder { bound_vars, scope_type, hir_id, where_bound_origin, s: _ } => f .debug_struct("Binder") @@ -623,7 +623,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { | hir::ItemKind::Mod(..) | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Static(..) - | hir::ItemKind::GlobalAsm(..) => { + | hir::ItemKind::GlobalAsm { .. } => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } @@ -1462,7 +1462,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { let mut captures = captures.borrow_mut(); let remapped = *captures.entry(lifetime).or_insert_with(|| { - let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam); + let feed = + self.tcx.create_def(opaque_def_id, Some(ident.name), DefKind::LifetimeParam); feed.def_span(ident.span); feed.def_ident_span(Some(ident.span)); feed.def_id() @@ -2159,10 +2160,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { /// Walk the generics of the item for a trait bound whose self type /// corresponds to the expected res, and return the trait def id. - fn for_each_trait_bound_on_res( - &self, - expected_res: Res, - ) -> impl Iterator + use<'tcx, '_> { + fn for_each_trait_bound_on_res(&self, expected_res: Res) -> impl Iterator { std::iter::from_coroutine( #[coroutine] move || { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 717713d93399d..4e8f5ce398658 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -5,10 +5,9 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::{self as hir, AmbigArg, HirId}; use rustc_middle::query::plumbing::CyclePlaceholder; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::print::with_forced_trimmed_paths; use rustc_middle::ty::util::IntTypeExt; -use rustc_middle::ty::{self, Article, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, fold_regions}; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span}; @@ -35,20 +34,6 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx let parent_node_id = tcx.parent_hir_id(hir_id); let parent_node = tcx.hir_node(parent_node_id); - let find_sym_fn = |&(op, op_sp)| match op { - hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == hir_id => { - Some((anon_const, op_sp)) - } - _ => None, - }; - - let find_const = |&(op, op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == hir_id => { - Some((anon_const, op_sp)) - } - _ => None, - }; - match parent_node { // Anon consts "inside" the type system. Node::ConstArg(&ConstArg { @@ -57,56 +42,7 @@ fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx .. }) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span), - // Anon consts outside the type system. - Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) - if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_sym_fn) => - { - let ty = tcx.typeck(def_id).node_type(hir_id); - - match ty.kind() { - ty::Error(_) => ty, - ty::FnDef(..) => ty, - _ => { - let guar = tcx - .dcx() - .struct_span_err(op_sp, "invalid `sym` operand") - .with_span_label( - tcx.def_span(anon_const.def_id), - format!("is {} `{}`", ty.kind().article(), ty), - ) - .with_help("`sym` operands must refer to either a function or a static") - .emit(); - - Ty::new_error(tcx, guar) - } - } - } - Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. }) - | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. }) - if let Some((anon_const, op_sp)) = asm.operands.iter().find_map(find_const) => - { - let ty = tcx.typeck(def_id).node_type(hir_id); - - match ty.kind() { - ty::Error(_) => ty, - ty::Int(_) | ty::Uint(_) => ty, - _ => { - let guar = tcx - .dcx() - .struct_span_err(op_sp, "invalid type for `const` operand") - .with_span_label( - tcx.def_span(anon_const.def_id), - format!("is {} `{}`", ty.kind().article(), ty), - ) - .with_help("`const` operands must be of an integer type") - .emit(); - - Ty::new_error(tcx, guar) - } - } - } - Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => { + Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => { tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) } // Sort of affects the type system, but only for the purpose of diagnostics @@ -313,12 +249,12 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_ let args = ty::GenericArgs::identity_for_item(tcx, def_id); Ty::new_adt(tcx, def, args) } + ItemKind::GlobalAsm { .. } => tcx.typeck(def_id).node_type(hir_id), ItemKind::Trait(..) | ItemKind::TraitAlias(..) | ItemKind::Macro(..) | ItemKind::Mod(..) | ItemKind::ForeignMod { .. } - | ItemKind::GlobalAsm(..) | ItemKind::ExternCrate(..) | ItemKind::Use(..) => { span_bug!(item.span, "compute_type_of_item: unexpected item type: {:?}", item.kind); @@ -543,5 +479,5 @@ pub(crate) fn type_alias_is_lazy<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> } } } - HasTait.visit_ty_unambig(tcx.hir().expect_item(def_id).expect_ty_alias().0).is_break() + HasTait.visit_ty_unambig(tcx.hir_expect_item(def_id).expect_ty_alias().0).is_break() } diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index 399c4fbe55a9c..142078900f0e8 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -1,14 +1,13 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def}; +use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem, def, intravisit}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::DUMMY_SP; use tracing::{debug, instrument, trace}; -use crate::errors::{TaitForwardCompat, TaitForwardCompat2, UnconstrainedOpaqueType}; +use crate::errors::{TaitForwardCompat2, UnconstrainedOpaqueType}; /// Checks "defining uses" of opaque `impl Trait` in associated types. /// These can only be defined by associated items of the same trait. @@ -82,38 +81,9 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type( /// ``` #[instrument(skip(tcx), level = "debug")] pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { - let hir_id = tcx.local_def_id_to_hir_id(def_id); - let scope = tcx.hir_get_defining_scope(hir_id); let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] }; - debug!(?scope); - - if scope == hir::CRATE_HIR_ID { - tcx.hir_walk_toplevel_module(&mut locator); - } else { - trace!("scope={:#?}", tcx.hir_node(scope)); - match tcx.hir_node(scope) { - // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods - // This allows our visitor to process the defining item itself, causing - // it to pick up any 'sibling' defining uses. - // - // For example, this code: - // ``` - // fn foo() { - // type Blah = impl Debug; - // let my_closure = || -> Blah { true }; - // } - // ``` - // - // requires us to explicitly process `foo()` in order - // to notice the defining usage of `Blah`. - Node::Item(it) => locator.visit_item(it), - Node::ImplItem(it) => locator.visit_impl_item(it), - Node::TraitItem(it) => locator.visit_trait_item(it), - Node::ForeignItem(it) => locator.visit_foreign_item(it), - other => bug!("{:?} is not a valid scope for an opaque type item", other), - } - } + tcx.hir_walk_toplevel_module(&mut locator); if let Some(hidden) = locator.found { // Only check against typeck if we didn't already error @@ -137,12 +107,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType { span: tcx.def_span(def_id), name: tcx.item_ident(parent_def_id.to_def_id()), - what: match tcx.hir_node(scope) { - _ if scope == hir::CRATE_HIR_ID => "module", - Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module", - Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl", - _ => "item", - }, + what: "crate", }); Ty::new_error(tcx, reported) } @@ -176,6 +141,13 @@ impl TaitConstraintLocator<'_> { return; } + let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id); + // Don't try to check items that cannot possibly constrain the type. + if !opaque_types_defined_by.contains(&self.def_id) { + debug!("no constraint: no opaque types defined"); + return; + } + // Function items with `_` in their return type already emit an error, skip any // "non-defining use" errors for them. // Note that we use `Node::fn_sig` instead of `Node::fn_decl` here, because the former @@ -215,8 +187,6 @@ impl TaitConstraintLocator<'_> { return; } - let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id); - let mut constrained = false; for (&opaque_type_key, &hidden_type) in &tables.concrete_opaque_types { if opaque_type_key.def_id != self.def_id { @@ -224,20 +194,6 @@ impl TaitConstraintLocator<'_> { } constrained = true; - if !opaque_types_defined_by.contains(&self.def_id) { - let guar = self.tcx.dcx().emit_err(TaitForwardCompat { - span: hidden_type.span, - item_span: self - .tcx - .def_ident_span(item_def_id) - .unwrap_or_else(|| self.tcx.def_span(item_def_id)), - }); - // Avoid "opaque type not constrained" errors on the opaque itself. - self.found = Some(ty::OpaqueHiddenType { - span: DUMMY_SP, - ty: Ty::new_error(self.tcx, guar), - }); - } let concrete_type = self.tcx.erase_regions(hidden_type.remap_generic_params_to_declaration_params( opaque_type_key, @@ -309,19 +265,13 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> { } fn visit_item(&mut self, it: &'tcx Item<'tcx>) { trace!(?it.owner_id); - // The opaque type itself or its children are not within its reveal scope. - if it.owner_id.def_id != self.def_id { - self.check(it.owner_id.def_id); - intravisit::walk_item(self, it); - } + self.check(it.owner_id.def_id); + intravisit::walk_item(self, it); } fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { trace!(?it.owner_id); - // The opaque type itself or its children are not within its reveal scope. - if it.owner_id.def_id != self.def_id { - self.check(it.owner_id.def_id); - intravisit::walk_impl_item(self, it); - } + self.check(it.owner_id.def_id); + intravisit::walk_impl_item(self, it); } fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) { trace!(?it.owner_id); diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 6a9ae0de1c1ab..53866aa27b166 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -1,9 +1,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; -use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitor}; use rustc_span::Span; -use rustc_type_ir::fold::TypeFoldable; use tracing::debug; #[derive(Clone, PartialEq, Eq, Hash, Debug)] diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 4dbdfa3d85a9b..b907ec090e5d8 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -7,10 +7,10 @@ use std::assert_matches::debug_assert_matches; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, +}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_type_ir::visit::TypeVisitableExt; type RemapTable = FxHashMap; @@ -404,11 +404,16 @@ fn check_constraints<'tcx>( }; if let Some(local_sig_id) = sig_id.as_local() - && tcx.hir().opt_delegation_sig_id(local_sig_id).is_some() + && tcx.hir_opt_delegation_sig_id(local_sig_id).is_some() { emit("recursive delegation is not supported yet"); } + if tcx.fn_sig(sig_id).skip_binder().skip_binder().c_variadic { + // See issue #127443 for explanation. + emit("delegation to C-variadic functions is not allowed"); + } + ret } @@ -416,7 +421,7 @@ pub(crate) fn inherit_sig_for_delegation_item<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> &'tcx [Ty<'tcx>] { - let sig_id = tcx.hir().opt_delegation_sig_id(def_id).unwrap(); + let sig_id = tcx.hir_opt_delegation_sig_id(def_id).unwrap(); let caller_sig = tcx.fn_sig(sig_id); if let Err(err) = check_constraints(tcx, def_id, sig_id) { let sig_len = caller_sig.instantiate_identity().skip_binder().inputs().len() + 1; diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 1a0b0edb25703..f2560f22874bc 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -11,8 +11,6 @@ use rustc_middle::ty::Ty; use rustc_span::{Ident, Span, Symbol}; use crate::fluent_generated as fluent; -mod pattern_types; -pub(crate) use pattern_types::*; pub(crate) mod wrong_number_of_generic_args; mod precise_captures; @@ -84,6 +82,8 @@ pub(crate) struct AssocItemNotFound<'a> { pub label: Option>, #[subdiagnostic] pub sugg: Option>, + #[label(hir_analysis_within_macro)] + pub within_macro_span: Option, } #[derive(Subdiagnostic)] @@ -424,16 +424,6 @@ pub(crate) struct UnconstrainedOpaqueType { pub what: &'static str, } -#[derive(Diagnostic)] -#[diag(hir_analysis_tait_forward_compat)] -#[note] -pub(crate) struct TaitForwardCompat { - #[primary_span] - pub span: Span, - #[note] - pub item_span: Span, -} - #[derive(Diagnostic)] #[diag(hir_analysis_tait_forward_compat2)] #[note] @@ -710,17 +700,6 @@ pub(crate) struct InvalidUnionField { pub note: (), } -#[derive(Diagnostic)] -#[diag(hir_analysis_invalid_unsafe_field, code = E0740)] -pub(crate) struct InvalidUnsafeField { - #[primary_span] - pub field_span: Span, - #[subdiagnostic] - pub sugg: InvalidUnsafeFieldSuggestion, - #[note] - pub note: (), -} - #[derive(Diagnostic)] #[diag(hir_analysis_return_type_notation_on_non_rpitit)] pub(crate) struct ReturnTypeNotationOnNonRpitit<'tcx> { @@ -742,18 +721,6 @@ pub(crate) struct InvalidUnionFieldSuggestion { pub hi: Span, } -#[derive(Subdiagnostic)] -#[multipart_suggestion( - hir_analysis_invalid_unsafe_field_sugg, - applicability = "machine-applicable" -)] -pub(crate) struct InvalidUnsafeFieldSuggestion { - #[suggestion_part(code = "std::mem::ManuallyDrop<")] - pub lo: Span, - #[suggestion_part(code = ">")] - pub hi: Span, -} - #[derive(Diagnostic)] #[diag(hir_analysis_return_type_notation_equality_bound)] pub(crate) struct ReturnTypeNotationEqualityBound { @@ -908,6 +875,10 @@ pub(crate) enum ImplNotMarkedDefault { }, } +#[derive(LintDiagnostic)] +#[diag(hir_analysis_useless_impl_item)] +pub(crate) struct UselessImplItem; + #[derive(Diagnostic)] #[diag(hir_analysis_missing_trait_item, code = E0046)] pub(crate) struct MissingTraitItem { @@ -1164,18 +1135,6 @@ pub(crate) struct InherentTyOutside { pub span: Span, } -#[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = E0378)] -pub(crate) struct DispatchFromDynCoercion<'a> { - #[primary_span] - pub span: Span, - pub trait_name: &'a str, - #[note(hir_analysis_coercion_between_struct_same_note)] - pub note: bool, - pub source_path: String, - pub target_path: String, -} - #[derive(Diagnostic)] #[diag(hir_analysis_dispatch_from_dyn_repr, code = E0378)] pub(crate) struct DispatchFromDynRepr { @@ -1293,41 +1252,40 @@ pub(crate) struct DispatchFromDynZST<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = E0378)] -pub(crate) struct DispatchFromDynSingle<'a> { +#[diag(hir_analysis_coerce_zero, code = E0374)] +pub(crate) struct CoerceNoField { #[primary_span] pub span: Span, - pub trait_name: &'a str, + pub trait_name: &'static str, #[note(hir_analysis_coercion_between_struct_single_note)] pub note: bool, } #[derive(Diagnostic)] -#[diag(hir_analysis_dispatch_from_dyn_multi, code = E0378)] -#[note] -pub(crate) struct DispatchFromDynMulti { +#[diag(hir_analysis_coerce_multi, code = E0375)] +pub(crate) struct CoerceMulti { + pub trait_name: &'static str, #[primary_span] pub span: Span, - #[note(hir_analysis_coercions_note)] - pub coercions_note: bool, pub number: usize, - pub coercions: String, + #[note] + pub fields: MultiSpan, } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = E0376)] -pub(crate) struct DispatchFromDynStruct<'a> { +#[diag(hir_analysis_coerce_unsized_may, code = E0377)] +pub(crate) struct CoerceUnsizedNonStruct { #[primary_span] pub span: Span, - pub trait_name: &'a str, + pub trait_name: &'static str, } #[derive(Diagnostic)] #[diag(hir_analysis_coerce_unsized_may, code = E0377)] -pub(crate) struct DispatchFromDynSame<'a> { +pub(crate) struct CoerceSameStruct { #[primary_span] pub span: Span, - pub trait_name: &'a str, + pub trait_name: &'static str, #[note(hir_analysis_coercion_between_struct_same_note)] pub note: bool, pub source_path: String, @@ -1335,34 +1293,15 @@ pub(crate) struct DispatchFromDynSame<'a> { } #[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = E0374)] -pub(crate) struct CoerceUnsizedOneField<'a> { +#[diag(hir_analysis_coerce_unsized_field_validity)] +pub(crate) struct CoerceFieldValidity<'tcx> { #[primary_span] pub span: Span, - pub trait_name: &'a str, - #[note(hir_analysis_coercion_between_struct_single_note)] - pub note: bool, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_multi, code = E0375)] -#[note] -pub(crate) struct CoerceUnsizedMulti { - #[primary_span] + pub ty: Ty<'tcx>, + pub trait_name: &'static str, #[label] - pub span: Span, - #[note(hir_analysis_coercions_note)] - pub coercions_note: bool, - pub number: usize, - pub coercions: String, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_coerce_unsized_may, code = E0378)] -pub(crate) struct CoerceUnsizedMay<'a> { - #[primary_span] - pub span: Span, - pub trait_name: &'a str, + pub field_span: Span, + pub field_ty: Ty<'tcx>, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs deleted file mode 100644 index ec7b3aaa1c14c..0000000000000 --- a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs +++ /dev/null @@ -1,14 +0,0 @@ -use rustc_macros::Diagnostic; -use rustc_middle::ty::Ty; -use rustc_span::Span; - -#[derive(Diagnostic)] -#[diag(hir_analysis_invalid_base_type)] -pub(crate) struct InvalidBaseType<'tcx> { - pub ty: Ty<'tcx>, - #[primary_span] - pub ty_span: Span, - pub pat: &'static str, - #[note] - pub pat_span: Span, -} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index dd346ed1f97a5..f0dffd780bcc7 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -8,10 +8,12 @@ use rustc_hir::HirId; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::bug; -use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{ + self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + TypeVisitor, Upcast, +}; use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::traits; -use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -468,11 +470,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Good error for `where Trait::method(..): Send`. let Some(self_ty) = opt_self_ty else { - return self.error_missing_qpath_self_ty( + let guar = self.error_missing_qpath_self_ty( trait_def_id, hir_ty.span, item_segment, + ty::AssocKind::Type, ); + return Ty::new_error(tcx, guar); }; let self_ty = self.lower_ty(self_ty); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 3eb4945ebf80e..7e1f35627e337 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -4,15 +4,14 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; -use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ - self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, + self, BottomUpFolder, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; -use rustc_type_ir::elaborate::ClauseWithSupertraitSpan; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index d644a1f224c7e..fa061c806180f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -151,6 +151,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { qself: &qself_str, label: None, sugg: None, + // Try to get the span of the identifier within the path's syntax context + // (if that's different). + within_macro_span: assoc_name.span.within_macro(span, tcx.sess.source_map()), }; if is_dummy { @@ -385,14 +388,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) } - pub(super) fn report_ambiguous_assoc_ty( + pub(super) fn report_ambiguous_assoc( &self, span: Span, types: &[String], traits: &[String], name: Symbol, + kind: ty::AssocKind, ) -> ErrorGuaranteed { - let mut err = struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type"); + let kind_str = assoc_kind_str(kind); + let mut err = + struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}"); if self .tcx() .resolutions(()) @@ -417,7 +423,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, format!( "if there were a type named `Type` that implements a trait named \ - `Trait` with associated type `{name}`, you could use the \ + `Trait` with associated {kind_str} `{name}`, you could use the \ fully-qualified path", ), format!("::{name}"), @@ -440,7 +446,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, format!( "if there were a type named `Example` that implemented one of the \ - traits with associated type `{name}`, you could use the \ + traits with associated {kind_str} `{name}`, you could use the \ fully-qualified path", ), traits.iter().map(|trait_str| format!("::{name}")), @@ -451,7 +457,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_suggestion_verbose( span, format!( - "if there were a trait named `Example` with associated type `{name}` \ + "if there were a trait named `Example` with associated {kind_str} `{name}` \ implemented for `{type_str}`, you could use the fully-qualified path", ), format!("<{type_str} as Example>::{name}"), @@ -462,7 +468,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.span_suggestions( span, format!( - "if there were a trait named `Example` with associated type `{name}` \ + "if there were a trait named `Example` with associated {kind_str} `{name}` \ implemented for one of the types, you could use the fully-qualified \ path", ), @@ -491,7 +497,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { err.emit() } - pub(crate) fn complain_about_ambiguous_inherent_assoc_ty( + pub(crate) fn complain_about_ambiguous_inherent_assoc( &self, name: Ident, candidates: Vec, @@ -552,13 +558,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // FIXME(inherent_associated_types): Find similarly named associated types and suggest them. - pub(crate) fn complain_about_inherent_assoc_ty_not_found( + pub(crate) fn complain_about_inherent_assoc_not_found( &self, name: Ident, self_ty: Ty<'tcx>, candidates: Vec<(DefId, (DefId, DefId))>, fulfillment_errors: Vec>, span: Span, + kind: ty::AssocKind, ) -> ErrorGuaranteed { // FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`. // Either @@ -568,12 +575,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); + let kind_str = assoc_kind_str(kind); let adt_did = self_ty.ty_adt_def().map(|def| def.did()); let add_def_label = |err: &mut Diag<'_>| { if let Some(did) = adt_did { err.span_label( tcx.def_span(did), - format!("associated item `{name}` not found for this {}", tcx.def_descr(did)), + format!( + "associated {kind_str} `{name}` not found for this {}", + tcx.def_descr(did) + ), ); } }; @@ -600,11 +611,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.dcx(), name.span, E0220, - "associated type `{name}` not found for `{self_ty}` in the current scope" + "associated {kind_str} `{name}` not found for `{self_ty}` in the current scope" ); err.span_label(name.span, format!("associated item not found in `{self_ty}`")); err.note(format!( - "the associated type was found for\n{type_candidates}{additional_types}", + "the associated {kind_str} was found for\n{type_candidates}{additional_types}", )); add_def_label(&mut err); return err.emit(); @@ -685,7 +696,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut err = self.dcx().struct_span_err( name.span, - format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") + format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied") ); if !bounds.is_empty() { err.note(format!( @@ -695,7 +706,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } err.span_label( name.span, - format!("associated type cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") + format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds") ); for (span, mut bounds) in bound_spans { @@ -789,7 +800,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(args.constraints.iter().filter_map(|constraint| { let ident = constraint.ident; - let trait_def = path.res.def_id(); + + let Res::Def(DefKind::Trait, trait_def) = path.res else { + return None; + }; + let assoc_item = tcx.associated_items(trait_def).find_by_name_and_kind( tcx, ident, @@ -1505,7 +1520,7 @@ fn generics_args_err_extend<'a>( }) .collect(); if args.len() > 1 - && let Some(span) = args.into_iter().last() + && let Some(span) = args.into_iter().next_back() { err.note( "generic arguments are not allowed on both an enum and its variant's path \ @@ -1610,7 +1625,7 @@ fn generics_args_err_extend<'a>( } } -pub(super) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { +pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str { match kind { ty::AssocKind::Fn => "function", ty::AssocKind::Const => "constant", diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs index 8d58a3bfbd3c5..60a60f6415a22 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs @@ -115,7 +115,7 @@ fn generic_arg_mismatch_err( body.value.kind && let Res::Def(DefKind::Fn { .. }, id) = path.res { - // FIXME(min_generic_const_args): this branch is dead once new const path lowering + // FIXME(mgca): this branch is dead once new const path lowering // (for single-segment paths) is no longer gated err.help(format!("`{}` is a function item, not a type", tcx.item_name(id))); err.help("function item types cannot be named directly"); @@ -273,7 +273,7 @@ pub fn lower_generic_args<'tcx: 'a, 'a>( // We lower to an infer even when the feature gate is not enabled // as it is useful for diagnostics to be able to see a `ConstKind::Infer` - args.push(ctx.provided_kind(param, arg)); + args.push(ctx.provided_kind(&args, param, arg)); args_iter.next(); params.next(); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index f5e075367f336..be726c042dadf 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -78,15 +78,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } if self_ty.span.edition().at_least_rust_2021() { - let msg = "expected a type, found a trait"; - let label = "you can add the `dyn` keyword if you want a trait object"; - let mut diag = - rustc_errors::struct_span_code_err!(self.dcx(), self_ty.span, E0782, "{}", msg); + let mut diag = rustc_errors::struct_span_code_err!( + self.dcx(), + self_ty.span, + E0782, + "{}", + "expected a type, found a trait" + ); if self_ty.span.can_be_used_for_suggestions() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) + && !self.maybe_suggest_dyn_trait(self_ty, sugg, &mut diag) { - // FIXME: Only emit this suggestion if the trait is dyn-compatible. - diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable); + self.maybe_suggest_add_generic_impl_trait(self_ty, &mut diag); } // Check if the impl trait that we are considering is an impl of a local trait. self.maybe_suggest_blanket_trait_impl(self_ty, &mut diag); @@ -123,6 +126,64 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + /// For a struct or enum with an invalid bare trait object field, suggest turning + /// it into a generic type bound. + fn maybe_suggest_add_generic_impl_trait( + &self, + self_ty: &hir::Ty<'_>, + diag: &mut Diag<'_>, + ) -> bool { + let tcx = self.tcx(); + + let parent_hir_id = tcx.parent_hir_id(self_ty.hir_id); + let parent_item = tcx.hir_get_parent_item(self_ty.hir_id).def_id; + + let generics = match tcx.hir_node_by_def_id(parent_item) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Struct(variant, generics), .. + }) => { + if !variant.fields().iter().any(|field| field.hir_id == parent_hir_id) { + return false; + } + generics + } + hir::Node::Item(hir::Item { kind: hir::ItemKind::Enum(def, generics), .. }) => { + if !def + .variants + .iter() + .flat_map(|variant| variant.data.fields().iter()) + .any(|field| field.hir_id == parent_hir_id) + { + return false; + } + generics + } + _ => return false, + }; + + let Ok(rendered_ty) = tcx.sess.source_map().span_to_snippet(self_ty.span) else { + return false; + }; + + let param = "TUV" + .chars() + .map(|c| c.to_string()) + .chain((0..).map(|i| format!("P{i}"))) + .find(|s| !generics.params.iter().any(|param| param.name.ident().as_str() == s)) + .expect("we definitely can find at least one param name to generate"); + let mut sugg = vec![(self_ty.span, param.to_string())]; + if let Some(insertion_span) = generics.span_for_param_suggestion() { + sugg.push((insertion_span, format!(", {param}: {}", rendered_ty))); + } else { + sugg.push((generics.where_clause_span, format!("<{param}: {}>", rendered_ty))); + } + diag.multipart_suggestion_verbose( + "you might be missing a type parameter", + sugg, + Applicability::MachineApplicable, + ); + true + } /// Make sure that we are in the condition to suggest the blanket implementation. fn maybe_suggest_blanket_trait_impl( &self, @@ -171,6 +232,65 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } + /// Try our best to approximate when adding `dyn` would be helpful for a bare + /// trait object. + /// + /// Right now, this is if the type is either directly nested in another ty, + /// or if it's in the tail field within a struct. This approximates what the + /// user would've gotten on edition 2015, except for the case where we have + /// an *obvious* knock-on `Sized` error. + fn maybe_suggest_dyn_trait( + &self, + self_ty: &hir::Ty<'_>, + sugg: Vec<(Span, String)>, + diag: &mut Diag<'_>, + ) -> bool { + let tcx = self.tcx(); + + // Look at the direct HIR parent, since we care about the relationship between + // the type and the thing that directly encloses it. + match tcx.parent_hir_node(self_ty.hir_id) { + // These are all generally ok. Namely, when a trait object is nested + // into another expression or ty, it's either very certain that they + // missed the ty (e.g. `&Trait`) or it's not really possible to tell + // what their intention is, so let's not give confusing suggestions and + // just mention `dyn`. The user can make up their mind what to do here. + hir::Node::Ty(_) + | hir::Node::Expr(_) + | hir::Node::PatExpr(_) + | hir::Node::PathSegment(_) + | hir::Node::AssocItemConstraint(_) + | hir::Node::TraitRef(_) + | hir::Node::Item(_) + | hir::Node::WherePredicate(_) => {} + + hir::Node::Field(field) => { + // Enums can't have unsized fields, fields can only have an unsized tail field. + if let hir::Node::Item(hir::Item { + kind: hir::ItemKind::Struct(variant, _), .. + }) = tcx.parent_hir_node(field.hir_id) + && variant + .fields() + .last() + .is_some_and(|tail_field| tail_field.hir_id == field.hir_id) + { + // Ok + } else { + return false; + } + } + _ => return false, + } + + // FIXME: Only emit this suggestion if the trait is dyn-compatible. + diag.multipart_suggestion_verbose( + "you can add the `dyn` keyword if you want a trait object", + sugg, + Applicability::MachineApplicable, + ); + true + } + fn add_generic_param_suggestion( &self, generics: &hir::Generics<'_>, @@ -291,14 +411,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Applicability::MachineApplicable, ); if !is_dyn_compatible { - diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`")); + diag.note(format!( + "`{trait_name}` is dyn-incompatible, otherwise a trait object could be used" + )); } else { // No ampersand in suggestion if it's borrowed already let (dyn_str, paren_dyn_str) = if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") }; let sugg = if let hir::TyKind::TraitObject([_, _, ..], _) = self_ty.kind { - // There are more than one trait bound, we need surrounding parentheses. + // There is more than one trait bound, we need surrounding parentheses. vec![ (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()), (self_ty.span.shrink_to_hi(), ")".to_string()), diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index fcd0d4d40fd4c..76a880da41855 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -36,26 +36,24 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, - TypeVisitableExt, TypingMode, + TypeVisitableExt, TypingMode, Upcast, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; +use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; -use rustc_type_ir::Upcast; use tracing::{debug, instrument}; +use self::errors::assoc_kind_str; use crate::check::check_abi_fn_ptr; -use crate::errors::{ - AmbiguousLifetimeBound, BadReturnTypeNotation, InvalidBaseType, NoVariantNamed, -}; +use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed}; use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -152,7 +150,7 @@ pub trait HirTyLowerer<'tcx> { assoc_name: Ident, ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]>; - /// Lower an associated type to a projection. + /// Lower an associated type/const (from a trait) to a projection. /// /// This method has to be defined by the concrete lowering context because /// dealing with higher-ranked trait references depends on its capabilities: @@ -164,13 +162,14 @@ pub trait HirTyLowerer<'tcx> { /// /// The canonical example of this is associated type `T::P` where `T` is a type /// param constrained by `T: for<'a> Trait<'a>` and where `Trait` defines `P`. - fn lower_assoc_ty( + fn lower_assoc_shared( &self, span: Span, item_def_id: DefId, item_segment: &hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx>; + kind: ty::AssocKind, + ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>; fn lower_fn_sig( &self, @@ -232,16 +231,55 @@ impl AssocItemQSelf { /// Use this enum with `::lower_const_arg` to instruct it with the /// desired behavior. #[derive(Debug, Clone, Copy)] -pub enum FeedConstTy { +pub enum FeedConstTy<'a, 'tcx> { /// Feed the type. /// /// The `DefId` belongs to the const param that we are supplying /// this (anon) const arg to. - Param(DefId), + /// + /// The list of generic args is used to instantiate the parameters + /// used by the type of the const param specified by `DefId`. + Param(DefId, &'a [ty::GenericArg<'tcx>]), /// Don't feed the type. No, } +#[derive(Debug, Clone, Copy)] +enum LowerAssocMode { + Type { permit_variants: bool }, + Const, +} + +impl LowerAssocMode { + fn kind(self) -> ty::AssocKind { + match self { + LowerAssocMode::Type { .. } => ty::AssocKind::Type, + LowerAssocMode::Const => ty::AssocKind::Const, + } + } + + fn def_kind(self) -> DefKind { + match self { + LowerAssocMode::Type { .. } => DefKind::AssocTy, + LowerAssocMode::Const => DefKind::AssocConst, + } + } + + fn permit_variants(self) -> bool { + match self { + LowerAssocMode::Type { permit_variants } => permit_variants, + // FIXME(mgca): Support paths like `Option::::None` or `Option::::Some` which resolve to const ctors/fn items respectively + LowerAssocMode::Const => false, + } + } +} + +#[derive(Debug, Clone, Copy)] +enum LoweredAssoc<'tcx> { + Term(DefId, GenericArgsRef<'tcx>), + Variant { adt: Ty<'tcx>, variant_did: DefId }, +} + /// New-typed boolean indicating whether explicit late-bound lifetimes /// are present in a set of generic arguments. /// @@ -298,6 +336,7 @@ pub trait GenericArgsLowerer<'a, 'tcx> { fn provided_kind( &mut self, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx>; @@ -329,7 +368,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { #[instrument(level = "debug", skip(self), ret)] pub fn lower_resolved_lifetime(&self, resolved: rbv::ResolvedArg) -> ty::Region<'tcx> { let tcx = self.tcx(); - let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); + let lifetime_name = |def_id| tcx.hir_name(tcx.local_def_id_to_hir_id(def_id)); match resolved { rbv::ResolvedArg::StaticLifetime => tcx.lifetimes.re_static, @@ -481,6 +520,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn provided_kind( &mut self, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { @@ -526,7 +566,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self .lowerer // Ambig portions of `ConstArg` are handled in the match arm below - .lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id)) + .lower_const_arg( + ct.as_unambig_ct(), + FeedConstTy::Param(param.def_id, preceding_args), + ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.lowerer.ct_infer(Some(param), inf.span).into() @@ -582,8 +625,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ty = tcx .at(self.span) .type_of(param.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); + .instantiate(tcx, preceding_args); if let Err(guar) = ty.error_reported() { return ty::Const::new_error(tcx, guar).into(); } @@ -623,7 +665,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { (args, arg_count) } - #[instrument(level = "debug", skip_all)] + #[instrument(level = "debug", skip(self))] pub fn lower_generic_args_of_assoc_item( &self, span: Span, @@ -631,7 +673,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { item_segment: &hir::PathSegment<'tcx>, parent_args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { - debug!(?span, ?item_def_id, ?item_segment); let (args, _) = self.lower_generic_args_of_path(span, item_def_id, parent_args, item_segment, None); if let Some(c) = item_segment.args().constraints.first() { @@ -1111,7 +1152,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // NOTE: When this function starts resolving `Trait::AssocTy` successfully // it should also start reporting the `BARE_TRAIT_OBJECTS` lint. #[instrument(level = "debug", skip_all, ret)] - pub fn lower_assoc_path( + pub fn lower_assoc_path_ty( &self, hir_ref_id: HirId, span: Span, @@ -1120,6 +1161,72 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { assoc_segment: &'tcx hir::PathSegment<'tcx>, permit_variants: bool, ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> { + let tcx = self.tcx(); + match self.lower_assoc_path_shared( + hir_ref_id, + span, + qself_ty, + qself, + assoc_segment, + LowerAssocMode::Type { permit_variants }, + )? { + LoweredAssoc::Term(def_id, args) => { + let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args); + let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty); + Ok((ty, tcx.def_kind(def_id), def_id)) + } + LoweredAssoc::Variant { adt, variant_did } => Ok((adt, DefKind::Variant, variant_did)), + } + } + + #[instrument(level = "debug", skip_all, ret)] + fn lower_assoc_path_const( + &self, + hir_ref_id: HirId, + span: Span, + qself_ty: Ty<'tcx>, + qself: &'tcx hir::Ty<'tcx>, + assoc_segment: &'tcx hir::PathSegment<'tcx>, + ) -> Result, ErrorGuaranteed> { + let tcx = self.tcx(); + let (def_id, args) = match self.lower_assoc_path_shared( + hir_ref_id, + span, + qself_ty, + qself, + assoc_segment, + LowerAssocMode::Const, + )? { + LoweredAssoc::Term(def_id, args) => { + if !tcx.associated_item(def_id).is_type_const_capable(tcx) { + let mut err = tcx.dcx().struct_span_err( + span, + "use of trait associated const without `#[type_const]`", + ); + err.note("the declaration in the trait must be marked with `#[type_const]`"); + return Err(err.emit()); + } + (def_id, args) + } + // FIXME(mgca): implement support for this once ready to support all adt ctor expressions, + // not just const ctors + LoweredAssoc::Variant { .. } => { + span_bug!(span, "unexpected variant res for type associated const path") + } + }; + Ok(Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(def_id, args))) + } + + #[instrument(level = "debug", skip_all, ret)] + fn lower_assoc_path_shared( + &self, + hir_ref_id: HirId, + span: Span, + qself_ty: Ty<'tcx>, + qself: &'tcx hir::Ty<'tcx>, + assoc_segment: &'tcx hir::PathSegment<'tcx>, + mode: LowerAssocMode, + ) -> Result, ErrorGuaranteed> { debug!(%qself_ty, ?assoc_segment.ident); let tcx = self.tcx(); @@ -1134,13 +1241,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did())); if let Some(variant_def) = variant_def { - if permit_variants { + if mode.permit_variants() { tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None); let _ = self.prohibit_generic_args( slice::from_ref(assoc_segment).iter(), GenericsArgsErrExtend::EnumVariant { qself, assoc_segment, adt_def }, ); - return Ok((qself_ty, DefKind::Variant, variant_def.def_id)); + return Ok(LoweredAssoc::Variant { + adt: qself_ty, + variant_did: variant_def.def_id, + }); } else { variant_resolution = Some(variant_def.def_id); } @@ -1148,15 +1258,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // FIXME(inherent_associated_types, #106719): Support self types other than ADTs. - if let Some((ty, did)) = self.probe_inherent_assoc_ty( - assoc_ident, + if let Some((did, args)) = self.probe_inherent_assoc_shared( assoc_segment, adt_def.did(), qself_ty, hir_ref_id, span, + mode.kind(), )? { - return Ok((ty, DefKind::AssocTy, did)); + return Ok(LoweredAssoc::Term(did, args)); } } @@ -1185,7 +1295,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) }, AssocItemQSelf::SelfTyAlias, - ty::AssocKind::Type, + mode.kind(), assoc_ident, span, None, @@ -1197,14 +1307,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ) => self.probe_single_ty_param_bound_for_assoc_item( param_did.expect_local(), qself.span, - ty::AssocKind::Type, + mode.kind(), assoc_ident, span, )?, _ => { + let kind_str = assoc_kind_str(mode.kind()); let reported = if variant_resolution.is_some() { // Variant in type position - let msg = format!("expected type, found variant `{assoc_ident}`"); + let msg = format!("expected {kind_str}, found variant `{assoc_ident}`"); self.dcx().span_err(span, msg) } else if qself_ty.is_enum() { let mut err = self.dcx().create_err(NoVariantNamed { @@ -1226,11 +1337,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { adt_def.variants().iter().find(|s| s.name == variant_name) { let mut suggestion = vec![(assoc_ident.span, variant_name.to_string())]; - if let hir::Node::Stmt(hir::Stmt { - kind: hir::StmtKind::Semi(ref expr), - .. + if let hir::Node::Stmt(&hir::Stmt { + kind: hir::StmtKind::Semi(expr), .. }) - | hir::Node::Expr(ref expr) = tcx.parent_hir_node(hir_ref_id) + | hir::Node::Expr(expr) = tcx.parent_hir_node(hir_ref_id) && let hir::ExprKind::Struct(..) = expr.kind { match variant.ctor { @@ -1304,11 +1414,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self.probe_traits_that_match_assoc_ty(qself_ty, assoc_ident); // Don't print `ty::Error` to the user. - self.report_ambiguous_assoc_ty( + self.report_ambiguous_assoc( span, &[qself_ty.to_string()], &traits, assoc_ident.name, + mode.kind(), ) }; return Err(reported); @@ -1316,10 +1427,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; let trait_did = bound.def_id(); - let assoc_ty = self - .probe_assoc_item(assoc_ident, ty::AssocKind::Type, hir_ref_id, span, trait_did) - .expect("failed to find associated type"); - let ty = self.lower_assoc_ty(span, assoc_ty.def_id, assoc_segment, bound); + let assoc_item = self + .probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did) + .expect("failed to find associated item"); + let (def_id, args) = + self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?; + let result = LoweredAssoc::Term(def_id, args); if let Some(variant_def_id) = variant_resolution { tcx.node_span_lint(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { @@ -1335,7 +1448,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }; could_refer_to(DefKind::Variant, variant_def_id, ""); - could_refer_to(DefKind::AssocTy, assoc_ty.def_id, " also"); + could_refer_to(mode.def_kind(), assoc_item.def_id, " also"); lint.span_suggestion( span, @@ -1345,36 +1458,51 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); }); } - Ok((ty, DefKind::AssocTy, assoc_ty.def_id)) + Ok(result) } - fn probe_inherent_assoc_ty( + fn probe_inherent_assoc_shared( &self, - name: Ident, segment: &hir::PathSegment<'tcx>, adt_did: DefId, self_ty: Ty<'tcx>, block: HirId, span: Span, - ) -> Result, DefId)>, ErrorGuaranteed> { + kind: ty::AssocKind, + ) -> Result)>, ErrorGuaranteed> { let tcx = self.tcx(); - // Don't attempt to look up inherent associated types when the feature is not enabled. - // Theoretically it'd be fine to do so since we feature-gate their definition site. - // However, due to current limitations of the implementation (caused by us performing - // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle - // errors (#108491) which mask the feature-gate error, needlessly confusing users - // who use IATs by accident (#113265). if !tcx.features().inherent_associated_types() { - return Ok(None); + match kind { + // Don't attempt to look up inherent associated types when the feature is not enabled. + // Theoretically it'd be fine to do so since we feature-gate their definition site. + // However, due to current limitations of the implementation (caused by us performing + // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle + // errors (#108491) which mask the feature-gate error, needlessly confusing users + // who use IATs by accident (#113265). + ty::AssocKind::Type => return Ok(None), + ty::AssocKind::Const => { + // We also gate the mgca codepath for type-level uses of inherent consts + // with the inherent_associated_types feature gate since it relies on the + // same machinery and has similar rough edges. + return Err(feature_err( + &tcx.sess, + sym::inherent_associated_types, + span, + "inherent associated types are unstable", + ) + .emit()); + } + ty::AssocKind::Fn => unreachable!(), + } } + let name = segment.ident; let candidates: Vec<_> = tcx .inherent_impls(adt_did) .iter() .filter_map(|&impl_| { - let (item, scope) = - self.probe_assoc_item_unchecked(name, ty::AssocKind::Type, block, impl_)?; + let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?; Some((impl_, (item.def_id, scope))) }) .collect(); @@ -1389,13 +1517,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // In contexts that have no inference context, just make a new one. // We do need a local variable to store it, though. - let infcx_; let infcx = match self.infcx() { Some(infcx) => infcx, None => { assert!(!self_ty.has_infer()); - infcx_ = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); - &infcx_ + &tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()) } }; @@ -1414,8 +1540,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &mut universes, self_ty, |self_ty| { - self.select_inherent_assoc_type_candidates( - infcx, name, span, self_ty, param_env, candidates, + self.select_inherent_assoc_candidates( + infcx, name, span, self_ty, param_env, candidates, kind, ) }, )?; @@ -1432,13 +1558,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .chain(args.into_iter().skip(parent_args.len())), ); - let ty = - Ty::new_alias(tcx, ty::Inherent, ty::AliasTy::new_from_args(tcx, assoc_item, args)); - - Ok(Some((ty, assoc_item))) + Ok(Some((assoc_item, args))) } - fn select_inherent_assoc_type_candidates( + fn select_inherent_assoc_candidates( &self, infcx: &InferCtxt<'tcx>, name: Ident, @@ -1446,6 +1569,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { self_ty: Ty<'tcx>, param_env: ParamEnv<'tcx>, candidates: Vec<(DefId, (DefId, DefId))>, + kind: ty::AssocKind, ) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> { let tcx = self.tcx(); let mut fulfillment_errors = Vec::new(); @@ -1490,17 +1614,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .collect(); match &applicable_candidates[..] { - &[] => Err(self.complain_about_inherent_assoc_ty_not_found( + &[] => Err(self.complain_about_inherent_assoc_not_found( name, self_ty, candidates, fulfillment_errors, span, + kind, )), &[applicable_candidate] => Ok(applicable_candidate), - &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc_ty( + &[_, ..] => Err(self.complain_about_ambiguous_inherent_assoc( name, applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(), span, @@ -1632,7 +1757,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a qualified path to a type. #[instrument(level = "debug", skip_all)] - fn lower_qpath( + fn lower_qpath_ty( &self, span: Span, opt_self_ty: Option>, @@ -1640,13 +1765,64 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_segment: &hir::PathSegment<'tcx>, item_segment: &hir::PathSegment<'tcx>, ) -> Ty<'tcx> { + match self.lower_qpath_shared( + span, + opt_self_ty, + item_def_id, + trait_segment, + item_segment, + ty::AssocKind::Type, + ) { + Ok((item_def_id, item_args)) => { + Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) + } + Err(guar) => Ty::new_error(self.tcx(), guar), + } + } + + /// Lower a qualified path to a const. + #[instrument(level = "debug", skip_all)] + fn lower_qpath_const( + &self, + span: Span, + opt_self_ty: Option>, + item_def_id: DefId, + trait_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'tcx>, + ) -> Const<'tcx> { + match self.lower_qpath_shared( + span, + opt_self_ty, + item_def_id, + trait_segment, + item_segment, + ty::AssocKind::Const, + ) { + Ok((item_def_id, item_args)) => { + let uv = ty::UnevaluatedConst::new(item_def_id, item_args); + Const::new_unevaluated(self.tcx(), uv) + } + Err(guar) => Const::new_error(self.tcx(), guar), + } + } + + #[instrument(level = "debug", skip_all)] + fn lower_qpath_shared( + &self, + span: Span, + opt_self_ty: Option>, + item_def_id: DefId, + trait_segment: &hir::PathSegment<'tcx>, + item_segment: &hir::PathSegment<'tcx>, + kind: ty::AssocKind, + ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { let tcx = self.tcx(); let trait_def_id = tcx.parent(item_def_id); debug!(?trait_def_id); let Some(self_ty) = opt_self_ty else { - return self.error_missing_qpath_self_ty(trait_def_id, span, item_segment); + return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind)); }; debug!(?self_ty); @@ -1657,7 +1833,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let item_args = self.lower_generic_args_of_assoc_item(span, item_def_id, item_segment, trait_ref.args); - Ty::new_projection_from_args(tcx, item_def_id, item_args) + Ok((item_def_id, item_args)) } fn error_missing_qpath_self_ty( @@ -1665,7 +1841,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { trait_def_id: DefId, span: Span, item_segment: &hir::PathSegment<'tcx>, - ) -> Ty<'tcx> { + kind: ty::AssocKind, + ) -> ErrorGuaranteed { let tcx = self.tcx(); let path_str = tcx.def_path_str(trait_def_id); @@ -1701,9 +1878,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that // references the trait. Relevant for the first case in // `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs` - let reported = - self.report_ambiguous_assoc_ty(span, &type_names, &[path_str], item_segment.ident.name); - Ty::new_error(tcx, reported) + self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind) } pub fn prohibit_generic_args<'a>( @@ -2007,7 +2182,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { path.segments[..path.segments.len() - 2].iter(), GenericsArgsErrExtend::None, ); - self.lower_qpath( + self.lower_qpath_ty( span, opt_self_ty, def_id, @@ -2108,14 +2283,59 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn lower_const_arg( &self, const_arg: &hir::ConstArg<'tcx>, - feed: FeedConstTy, + feed: FeedConstTy<'_, 'tcx>, ) -> Const<'tcx> { let tcx = self.tcx(); - if let FeedConstTy::Param(param_def_id) = feed + if let FeedConstTy::Param(param_def_id, args) = feed && let hir::ConstArgKind::Anon(anon) = &const_arg.kind { - tcx.feed_anon_const_type(anon.def_id, tcx.type_of(param_def_id)); + let anon_const_type = tcx.type_of(param_def_id).instantiate(tcx, args); + + // FIXME(generic_const_parameter_types): Ideally we remove these errors below when + // we have the ability to intermix typeck of anon const const args with the parent + // bodies typeck. + + // We also error if the type contains any regions as effectively any region will wind + // up as a region variable in mir borrowck. It would also be somewhat concerning if + // hir typeck was using equality but mir borrowck wound up using subtyping as that could + // result in a non-infer in hir typeck but a region variable in borrowck. + if tcx.features().generic_const_parameter_types() + && (anon_const_type.has_free_regions() || anon_const_type.has_erased_regions()) + { + let e = tcx.dcx().span_err( + const_arg.span(), + "anonymous constants with lifetimes in their type are not yet supported", + ); + tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); + return ty::Const::new_error(tcx, e); + } + // We must error if the instantiated type has any inference variables as we will + // use this type to feed the `type_of` and query results must not contain inference + // variables otherwise we will ICE. + if anon_const_type.has_non_region_infer() { + let e = tcx.dcx().span_err( + const_arg.span(), + "anonymous constants with inferred types are not yet supported", + ); + tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); + return ty::Const::new_error(tcx, e); + } + // We error when the type contains unsubstituted generics since we do not currently + // give the anon const any of the generics from the parent. + if anon_const_type.has_non_region_param() { + let e = tcx.dcx().span_err( + const_arg.span(), + "anonymous constants referencing generics are not yet supported", + ); + tcx.feed_anon_const_type(anon.def_id, ty::EarlyBinder::bind(Ty::new_error(tcx, e))); + return ty::Const::new_error(tcx, e); + } + + tcx.feed_anon_const_type( + anon.def_id, + ty::EarlyBinder::bind(tcx.type_of(param_def_id).instantiate(tcx, args)), + ); } let hir_id = const_arg.hir_id; @@ -2125,11 +2345,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); self.lower_const_path_resolved(opt_self_ty, path, hir_id) } - hir::ConstArgKind::Path(qpath) => ty::Const::new_error_with_message( - tcx, - qpath.span(), - format!("Const::lower_const_arg: invalid qpath {qpath:?}"), - ), + hir::ConstArgKind::Path(hir::QPath::TypeRelative(qself, segment)) => { + debug!(?qself, ?segment); + let ty = self.lower_ty(qself); + self.lower_assoc_path_const(hir_id, const_arg.span(), ty, qself, segment) + .unwrap_or_else(|guar| Const::new_error(tcx, guar)) + } + hir::ConstArgKind::Path(qpath @ hir::QPath::LangItem(..)) => { + ty::Const::new_error_with_message( + tcx, + qpath.span(), + format!("Const::lower_const_arg: invalid qpath {qpath:?}"), + ) + } hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), } @@ -2165,6 +2393,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ); ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } + Res::Def(DefKind::AssocConst, did) => { + debug_assert!(path.segments.len() >= 2); + let _ = self.prohibit_generic_args( + path.segments[..path.segments.len() - 2].iter(), + GenericsArgsErrExtend::None, + ); + self.lower_qpath_const( + span, + opt_self_ty, + did, + &path.segments[path.segments.len() - 2], + path.segments.last().unwrap(), + ) + } Res::Def(DefKind::Static { .. }, _) => { span_bug!(span, "use of bare `static` ConstArgKind::Path's not yet supported") } @@ -2181,7 +2423,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Exhaustive match to be clear about what exactly we're considering to be // an invalid Res for a const path. - Res::Def( + res @ (Res::Def( DefKind::Mod | DefKind::Enum | DefKind::Variant @@ -2195,7 +2437,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | DefKind::Union | DefKind::Trait | DefKind::ForeignTy - | DefKind::AssocConst | DefKind::TyParam | DefKind::Macro(_) | DefKind::LifetimeParam @@ -2218,12 +2459,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { | Res::Local(_) | Res::ToolMod | Res::NonMacroAttr(_) - | Res::Err => Const::new_error_with_message(tcx, span, "invalid Res for const path"), + | Res::Err) => Const::new_error_with_message( + tcx, + span, + format!("invalid Res {res:?} for const path"), + ), } } - /// Literals and const generic parameters are eagerly converted to a constant, everything else - /// becomes `Unevaluated`. + /// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`. #[instrument(skip(self), level = "debug")] fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> { let tcx = self.tcx(); @@ -2231,10 +2475,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let expr = &tcx.hir_body(anon.body).value; debug!(?expr); - let ty = tcx - .type_of(anon.def_id) - .no_bound_vars() - .expect("const parameter types cannot be generic"); + // FIXME(generic_const_parameter_types): We should use the proper generic args + // here. It's only used as a hint for literals so doesn't matter too much to use the right + // generic arguments, just weaker type inference. + let ty = tcx.type_of(anon.def_id).instantiate_identity(); match self.try_lower_anon_const_lit(ty, expr) { Some(v) => v, @@ -2422,7 +2666,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Path(hir::QPath::TypeRelative(qself, segment)) => { debug!(?qself, ?segment); let ty = self.lower_ty(qself); - self.lower_assoc_path(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false) + self.lower_assoc_path_ty(hir_ty.hir_id, hir_ty.span, ty, qself, segment, false) .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } @@ -2453,28 +2697,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let ty_span = ty.span; let ty = self.lower_ty(ty); let pat_ty = match pat.kind { - hir::TyPatKind::Range(start, end, include_end) => { - let ty = match ty.kind() { - ty::Int(_) | ty::Uint(_) | ty::Char => ty, - _ => Ty::new_error( - tcx, - self.dcx().emit_err(InvalidBaseType { - ty, - pat: "range", + hir::TyPatKind::Range(start, end) => { + let (ty, start, end) = match ty.kind() { + // Keep this list of types in sync with the list of types that + // the `RangePattern` trait is implemented for. + ty::Int(_) | ty::Uint(_) | ty::Char => { + let start = self.lower_const_arg(start, FeedConstTy::No); + let end = self.lower_const_arg(end, FeedConstTy::No); + (ty, start, end) + } + _ => { + let guar = self.dcx().span_delayed_bug( ty_span, - pat_span: pat.span, - }), - ), - }; - let start = start.map(|expr| self.lower_const_arg(expr, FeedConstTy::No)); - let end = end.map(|expr| self.lower_const_arg(expr, FeedConstTy::No)); - - let include_end = match include_end { - hir::RangeEnd::Included => true, - hir::RangeEnd::Excluded => false, + "invalid base type for range pattern", + ); + let errc = ty::Const::new_error(tcx, guar); + (Ty::new_error(tcx, guar), errc, errc) + } }; - let pat = tcx.mk_pat(ty::PatternKind::Range { start, end, include_end }); + let pat = tcx.mk_pat(ty::PatternKind::Range { start, end }); Ty::new_pat(tcx, ty, pat) } hir::TyPatKind::Err(e) => Ty::new_error(tcx, e), diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 0b1be8e4f7a99..1f5d69bd1b326 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -4,8 +4,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, TyCtxt, TypingMode, fold_regions}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; use tracing::debug; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index bdfbd540e40a3..e7ecd727a852f 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -59,6 +59,7 @@ This API is completely unstable and subject to change. #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -73,7 +74,6 @@ This API is completely unstable and subject to change. #![feature(slice_partition_dedup)] #![feature(try_blocks)] #![feature(unwrap_infallible)] -#![warn(unreachable_pub)] // tidy-alphabetical-end // These are used by Clippy. @@ -212,7 +212,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.par_hir_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); match def_kind { - DefKind::Static { .. } => tcx.ensure_ok().eval_static_initializer(item_def_id), + DefKind::Static { .. } => { + tcx.ensure_ok().eval_static_initializer(item_def_id); + check::maybe_check_static_with_link_section(tcx, item_def_id); + } DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; @@ -223,12 +226,9 @@ pub fn check_crate(tcx: TyCtxt<'_>) { } }); - // FIXME: Remove this when we implement creating `DefId`s - // for anon constants during their parents' typeck. - // Typeck all body owners in parallel will produce queries - // cycle errors because it may typeck on anon constants directly. tcx.par_hir_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); + // Skip `AnonConst`s because we feed their `type_of`. if !matches!(def_kind, DefKind::AnonConst) { tcx.ensure_ok().typeck(item_def_id); } @@ -252,7 +252,9 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { // def-ID that will be used to determine the traits/predicates in // scope. This is derived from the enclosing item-like thing. let env_def_id = tcx.hir_get_parent_item(hir_ty.hir_id); - collect::ItemCtxt::new(tcx, env_def_id.def_id).lower_ty(hir_ty) + collect::ItemCtxt::new(tcx, env_def_id.def_id) + .lowerer() + .lower_ty_maybe_return_type_notation(hir_ty) } /// This is for rustdoc. @@ -260,7 +262,7 @@ pub fn lower_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { pub fn lower_const_arg_for_rustdoc<'tcx>( tcx: TyCtxt<'tcx>, hir_ct: &hir::ConstArg<'tcx>, - feed: FeedConstTy, + feed: FeedConstTy<'_, 'tcx>, ) -> Const<'tcx> { let env_def_id = tcx.hir_get_parent_item(hir_ct.hir_id); collect::ItemCtxt::new(tcx, env_def_id.def_id).lowerer().lower_const_arg(hir_ct, feed) diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs index 0c9f5ba8b6fa8..d0a2a2230ab77 100644 --- a/compiler/rustc_hir_analysis/src/outlives/utils.rs +++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fx::FxIndexMap; +use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{self, GenericArg, GenericArgKind, Region, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::smallvec; /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index e954d2b9ea48e..8475903c68fde 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -252,13 +252,9 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ty::Pat(typ, pat) => { match *pat { - ty::PatternKind::Range { start, end, include_end: _ } => { - if let Some(start) = start { - self.add_constraints_from_const(current, start, variance); - } - if let Some(end) = end { - self.add_constraints_from_const(current, end, variance); - } + ty::PatternKind::Range { start, end } => { + self.add_constraints_from_const(current, start, variance); + self.add_constraints_from_const(current, end, variance); } } self.add_constraints_from_ty(current, typ, variance); diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index a7760326bb4c3..0800d99e9452e 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -198,6 +198,10 @@ fn variance_of_opaque( ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref: ty::TraitRef { def_id: _, args, .. }, polarity: _, + }) + | ty::ClauseKind::HostEffect(ty::HostEffectPredicate { + trait_ref: ty::TraitRef { def_id: _, args, .. }, + constness: _, }) => { for arg in &args[1..] { arg.visit_with(&mut collector); diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index 9af1fb8279e9f..91da8cb3fc5fb 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "rustc_hir_pretty" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } # tidy-alphabetical-end diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 34124a6aa11a3..1409310339a08 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -3,22 +3,23 @@ // tidy-alphabetical-start #![recursion_limit = "256"] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cell::Cell; use std::vec; use rustc_abi::ExternAbi; -use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity}; -use rustc_ast::{DUMMY_NODE_ID, DelimArgs}; +use rustc_ast::util::parser::{self, ExprPrecedence, Fixity}; +use rustc_ast::{AttrStyle, DUMMY_NODE_ID, DelimArgs}; use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; +use rustc_attr_data_structures::{AttributeKind, PrintAttribute}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, - HirId, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, TyPatKind, + HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, + TyPatKind, }; use rustc_span::source_map::SourceMap; use rustc_span::{FileName, Ident, Span, Symbol, kw}; @@ -79,65 +80,48 @@ impl<'a> State<'a> { (self.attrs)(id) } - fn print_inner_attributes(&mut self, attrs: &[hir::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) + fn print_attrs_as_inner(&mut self, attrs: &[hir::Attribute]) { + self.print_either_attributes(attrs, ast::AttrStyle::Inner) } - fn print_outer_attributes(&mut self, attrs: &[hir::Attribute]) -> bool { - self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true) + fn print_attrs_as_outer(&mut self, attrs: &[hir::Attribute]) { + self.print_either_attributes(attrs, ast::AttrStyle::Outer) } - fn print_either_attributes( - &mut self, - attrs: &[hir::Attribute], - kind: ast::AttrStyle, - is_inline: bool, - trailing_hardbreak: bool, - ) -> bool { - let mut printed = false; - for attr in attrs { - if attr.style == kind { - self.print_attribute_inline(attr, is_inline); - if is_inline { - self.nbsp(); - } - printed = true; - } + fn print_either_attributes(&mut self, attrs: &[hir::Attribute], style: ast::AttrStyle) { + if attrs.is_empty() { + return; } - if printed && trailing_hardbreak && !is_inline { - self.hardbreak_if_not_bol(); + + for attr in attrs { + self.print_attribute_inline(attr, style); } - printed + self.hardbreak_if_not_bol(); } - fn print_attribute_inline(&mut self, attr: &hir::Attribute, is_inline: bool) { - if !is_inline { - self.hardbreak_if_not_bol(); - } - self.maybe_print_comment(attr.span.lo()); - match &attr.kind { - hir::AttrKind::Normal(normal) => { - match attr.style { + fn print_attribute_inline(&mut self, attr: &hir::Attribute, style: AttrStyle) { + match &attr { + hir::Attribute::Unparsed(unparsed) => { + self.maybe_print_comment(unparsed.span.lo()); + match style { ast::AttrStyle::Inner => self.word("#!["), ast::AttrStyle::Outer => self.word("#["), } - if normal.unsafety == hir::Safety::Unsafe { - self.word("unsafe("); - } - self.print_attr_item(&normal, attr.span); - if normal.unsafety == hir::Safety::Unsafe { - self.word(")"); - } + self.print_attr_item(&unparsed, unparsed.span); self.word("]"); } - hir::AttrKind::DocComment(comment_kind, data) => { + hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => { self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string( - *comment_kind, - attr.style, - *data, + *kind, *style, *comment, )); self.hardbreak() } + hir::Attribute::Parsed(pa) => { + self.word("#[attr = "); + pa.print_attribute(self); + self.word("]"); + self.hardbreak() + } } } @@ -161,7 +145,7 @@ impl<'a> State<'a> { false, None, *delim, - tokens, + &tokens, true, span, ), @@ -306,7 +290,7 @@ where } pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String { - to_string(ann, |s| s.print_attribute_inline(attr, false)) + to_string(ann, |s| s.print_attribute_inline(attr, AttrStyle::Outer)) } pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String { @@ -369,7 +353,7 @@ impl<'a> State<'a> { } fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[hir::Attribute]) { - self.print_inner_attributes(attrs); + self.print_attrs_as_inner(attrs); for &item_id in _mod.item_ids { self.ann.nested(self, Nested::Item(item_id)); } @@ -486,7 +470,7 @@ impl<'a> State<'a> { fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); - self.print_outer_attributes(self.attrs(item.hir_id())); + self.print_attrs_as_outer(self.attrs(item.hir_id())); match item.kind { hir::ForeignItemKind::Fn(sig, arg_names, generics) => { self.head(""); @@ -568,29 +552,11 @@ impl<'a> State<'a> { self.word(";") } - fn print_item_type( - &mut self, - item: &hir::Item<'_>, - generics: &hir::Generics<'_>, - inner: impl Fn(&mut Self), - ) { - self.head("type"); - self.print_ident(item.ident); - self.print_generic_params(generics.params); - self.end(); // end the inner ibox - - self.print_where_clause(generics); - self.space(); - inner(self); - self.word(";"); - self.end(); // end the outer ibox - } - fn print_item(&mut self, item: &hir::Item<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); let attrs = self.attrs(item.hir_id()); - self.print_outer_attributes(attrs); + self.print_attrs_as_outer(attrs); self.ann.pre(self, AnnNode::Item(item)); match item.kind { hir::ItemKind::ExternCrate(orig_name) => { @@ -686,22 +652,29 @@ impl<'a> State<'a> { self.head("extern"); self.word_nbsp(abi.to_string()); self.bopen(); - self.print_inner_attributes(self.attrs(item.hir_id())); + self.print_attrs_as_inner(self.attrs(item.hir_id())); for item in items { self.ann.nested(self, Nested::ForeignItem(item.id)); } self.bclose(item.span); } - hir::ItemKind::GlobalAsm(asm) => { + hir::ItemKind::GlobalAsm { asm, .. } => { self.head("global_asm!"); self.print_inline_asm(asm); self.end() } hir::ItemKind::TyAlias(ty, generics) => { - self.print_item_type(item, generics, |state| { - state.word_space("="); - state.print_type(ty); - }); + self.head("type"); + self.print_ident(item.ident); + self.print_generic_params(generics.params); + self.end(); // end the inner ibox + + self.print_where_clause(generics); + self.space(); + self.word_space("="); + self.print_type(ty); + self.word(";"); + self.end(); // end the outer ibox } hir::ItemKind::Enum(ref enum_definition, params) => { self.print_enum_def(enum_definition, params, item.ident.name, item.span); @@ -754,7 +727,7 @@ impl<'a> State<'a> { self.space(); self.bopen(); - self.print_inner_attributes(attrs); + self.print_attrs_as_inner(attrs); for impl_item in items { self.ann.nested(self, Nested::ImplItem(impl_item.id)); } @@ -846,7 +819,7 @@ impl<'a> State<'a> { for v in variants { self.space_if_not_bol(); self.maybe_print_comment(v.span.lo()); - self.print_outer_attributes(self.attrs(v.hir_id)); + self.print_attrs_as_outer(self.attrs(v.hir_id)); self.ibox(INDENT_UNIT); self.print_variant(v); self.word(","); @@ -879,7 +852,7 @@ impl<'a> State<'a> { self.popen(); self.commasep(Inconsistent, struct_def.fields(), |s, field| { s.maybe_print_comment(field.span.lo()); - s.print_outer_attributes(s.attrs(field.hir_id)); + s.print_attrs_as_outer(s.attrs(field.hir_id)); s.print_type(field.ty); }); self.pclose(); @@ -906,7 +879,7 @@ impl<'a> State<'a> { for field in fields { self.hardbreak_if_not_bol(); self.maybe_print_comment(field.span.lo()); - self.print_outer_attributes(self.attrs(field.hir_id)); + self.print_attrs_as_outer(self.attrs(field.hir_id)); self.print_ident(field.ident); self.word_nbsp(":"); self.print_type(field.ty); @@ -942,7 +915,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::SubItem(ti.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ti.span.lo()); - self.print_outer_attributes(self.attrs(ti.hir_id())); + self.print_attrs_as_outer(self.attrs(ti.hir_id())); match ti.kind { hir::TraitItemKind::Const(ty, default) => { self.print_associated_const(ti.ident, ti.generics, ty, default); @@ -970,7 +943,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::SubItem(ii.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ii.span.lo()); - self.print_outer_attributes(self.attrs(ii.hir_id())); + self.print_attrs_as_outer(self.attrs(ii.hir_id())); match ii.kind { hir::ImplItemKind::Const(ty, expr) => { @@ -1073,7 +1046,7 @@ impl<'a> State<'a> { self.ann.pre(self, AnnNode::Block(blk)); self.bopen(); - self.print_inner_attributes(attrs); + self.print_attrs_as_inner(attrs); for st in blk.stmts { self.print_stmt(st); @@ -1263,7 +1236,7 @@ impl<'a> State<'a> { self.space(); } self.cbox(INDENT_UNIT); - self.print_outer_attributes(self.attrs(field.hir_id)); + self.print_attrs_as_outer(self.attrs(field.hir_id)); if !field.is_shorthand { self.print_ident(field.ident); self.word_space(":"); @@ -1311,12 +1284,11 @@ impl<'a> State<'a> { } fn print_expr_binary(&mut self, op: hir::BinOp, lhs: &hir::Expr<'_>, rhs: &hir::Expr<'_>) { - let assoc_op = AssocOp::from_ast_binop(op.node); - let binop_prec = assoc_op.precedence(); + let binop_prec = op.node.precedence(); let left_prec = lhs.precedence(); let right_prec = rhs.precedence(); - let (mut left_needs_paren, right_needs_paren) = match assoc_op.fixity() { + let (mut left_needs_paren, right_needs_paren) = match op.node.fixity() { Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec), Fixity::Right => (left_prec <= binop_prec, right_prec < binop_prec), Fixity::None => (left_prec <= binop_prec, right_prec <= binop_prec), @@ -1429,12 +1401,13 @@ impl<'a> State<'a> { hir::InlineAsmOperand::Const { ref anon_const } => { s.word("const"); s.space(); - s.print_anon_const(anon_const); + // Not using `print_inline_const` to avoid additional `const { ... }` + s.ann.nested(s, Nested::Body(anon_const.body)) } - hir::InlineAsmOperand::SymFn { ref anon_const } => { + hir::InlineAsmOperand::SymFn { ref expr } => { s.word("sym_fn"); s.space(); - s.print_anon_const(anon_const); + s.print_expr(expr); } hir::InlineAsmOperand::SymStatic { ref path, def_id: _ } => { s.word("sym_static"); @@ -1460,7 +1433,7 @@ impl<'a> State<'a> { fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.maybe_print_comment(expr.span.lo()); - self.print_outer_attributes(self.attrs(expr.hir_id)); + self.print_attrs_as_outer(self.attrs(expr.hir_id)); self.ibox(INDENT_UNIT); self.ann.pre(self, AnnNode::Expr(expr)); match expr.kind { @@ -1485,6 +1458,10 @@ impl<'a> State<'a> { hir::ExprKind::MethodCall(segment, receiver, args, _) => { self.print_expr_method_call(segment, receiver, args); } + hir::ExprKind::Use(expr, _) => { + self.print_expr(expr); + self.word(".use"); + } hir::ExprKind::Binary(op, lhs, rhs) => { self.print_expr_binary(op, lhs, rhs); } @@ -1676,8 +1653,8 @@ impl<'a> State<'a> { } hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => { match kind { - hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("), - hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("), + ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("), + ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("), } self.print_expr(expr); if let Some(ty) = ty { @@ -1856,7 +1833,7 @@ impl<'a> State<'a> { self.word_space("="); match term { Term::Ty(ty) => self.print_type(ty), - Term::Const(ref c) => self.print_const_arg(c), + Term::Const(c) => self.print_const_arg(c), } } hir::AssocItemConstraintKind::Bound { bounds } => { @@ -1884,17 +1861,10 @@ impl<'a> State<'a> { // Pat isn't normalized, but the beauty of it // is that it doesn't matter match pat.kind { - TyPatKind::Range(begin, end, end_kind) => { - if let Some(expr) = begin { - self.print_const_arg(expr); - } - match end_kind { - RangeEnd::Included => self.word("..."), - RangeEnd::Excluded => self.word(".."), - } - if let Some(expr) = end { - self.print_const_arg(expr); - } + TyPatKind::Range(begin, end) => { + self.print_const_arg(begin); + self.word("..="); + self.print_const_arg(end); } TyPatKind::Err(_) => { self.popen(); @@ -2072,7 +2042,7 @@ impl<'a> State<'a> { self.space(); } self.cbox(INDENT_UNIT); - self.print_outer_attributes(self.attrs(field.hir_id)); + self.print_attrs_as_outer(self.attrs(field.hir_id)); if !field.is_shorthand { self.print_ident(field.ident); self.word_nbsp(":"); @@ -2082,10 +2052,32 @@ impl<'a> State<'a> { } fn print_param(&mut self, arg: &hir::Param<'_>) { - self.print_outer_attributes(self.attrs(arg.hir_id)); + self.print_attrs_as_outer(self.attrs(arg.hir_id)); self.print_pat(arg.pat); } + fn print_implicit_self(&mut self, implicit_self_kind: &hir::ImplicitSelfKind) { + match implicit_self_kind { + ImplicitSelfKind::Imm => { + self.word("self"); + } + ImplicitSelfKind::Mut => { + self.print_mutability(hir::Mutability::Mut, false); + self.word("self"); + } + ImplicitSelfKind::RefImm => { + self.word("&"); + self.word("self"); + } + ImplicitSelfKind::RefMut => { + self.word("&"); + self.print_mutability(hir::Mutability::Mut, false); + self.word("self"); + } + ImplicitSelfKind::None => unreachable!(), + } + } + fn print_arm(&mut self, arm: &hir::Arm<'_>) { // I have no idea why this check is necessary, but here it // is :( @@ -2095,7 +2087,7 @@ impl<'a> State<'a> { self.cbox(INDENT_UNIT); self.ann.pre(self, AnnNode::Arm(arm)); self.ibox(0); - self.print_outer_attributes(self.attrs(arm.hir_id)); + self.print_attrs_as_outer(self.attrs(arm.hir_id)); self.print_pat(arm.pat); self.space(); if let Some(ref g) = arm.guard { @@ -2151,27 +2143,35 @@ impl<'a> State<'a> { // Make sure we aren't supplied *both* `arg_names` and `body_id`. assert!(arg_names.is_empty() || body_id.is_none()); let mut i = 0; - let mut print_arg = |s: &mut Self| { - if let Some(arg_name) = arg_names.get(i) { - s.word(arg_name.to_string()); - s.word(":"); - s.space(); - } else if let Some(body_id) = body_id { - s.ann.nested(s, Nested::BodyParamPat(body_id, i)); - s.word(":"); - s.space(); + let mut print_arg = |s: &mut Self, ty: Option<&hir::Ty<'_>>| { + if i == 0 && decl.implicit_self.has_implicit_self() { + s.print_implicit_self(&decl.implicit_self); + } else { + if let Some(arg_name) = arg_names.get(i) { + if arg_name.name != kw::Empty { + s.word(arg_name.to_string()); + s.word(":"); + s.space(); + } + } else if let Some(body_id) = body_id { + s.ann.nested(s, Nested::BodyParamPat(body_id, i)); + s.word(":"); + s.space(); + } + if let Some(ty) = ty { + s.print_type(ty); + } } i += 1; }; self.commasep(Inconsistent, decl.inputs, |s, ty| { s.ibox(INDENT_UNIT); - print_arg(s); - s.print_type(ty); + print_arg(s, Some(ty)); s.end(); }); if decl.c_variadic { self.word(", "); - print_arg(self); + print_arg(self, None); self.word("..."); } self.pclose(); @@ -2214,6 +2214,7 @@ impl<'a> State<'a> { fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { match capture_clause { hir::CaptureBy::Value { .. } => self.word_space("move"), + hir::CaptureBy::Use { .. } => self.word_space("use"), hir::CaptureBy::Ref => {} } } @@ -2284,7 +2285,9 @@ impl<'a> State<'a> { GenericBound::Use(args, _) => { self.word("use <"); - self.commasep(Inconsistent, args, |s, arg| s.print_precise_capturing_arg(*arg)); + self.commasep(Inconsistent, *args, |s, arg| { + s.print_precise_capturing_arg(*arg) + }); self.word(">"); } @@ -2300,10 +2303,23 @@ impl<'a> State<'a> { } fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) { - if !generic_params.is_empty() { + let is_lifetime_elided = |generic_param: &GenericParam<'_>| { + matches!( + generic_param.kind, + GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided(_) } + ) + }; + + // We don't want to show elided lifetimes as they are compiler-inserted and not + // expressible in surface level Rust. + if !generic_params.is_empty() && !generic_params.iter().all(is_lifetime_elided) { self.word("<"); - self.commasep(Inconsistent, generic_params, |s, param| s.print_generic_param(param)); + self.commasep( + Inconsistent, + generic_params.iter().filter(|gp| !is_lifetime_elided(gp)), + |s, param| s.print_generic_param(param), + ); self.word(">"); } @@ -2358,6 +2374,7 @@ impl<'a> State<'a> { } fn print_where_predicate(&mut self, predicate: &hir::WherePredicate<'_>) { + self.print_attrs_as_outer(self.attrs(predicate.hir_id)); match *predicate.kind { hir::WherePredicateKind::BoundPredicate(hir::WhereBoundPredicate { bound_generic_params, diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml index 0331a20f95b79..b2b90cb29e36f 100644 --- a/compiler/rustc_hir_typeck/Cargo.toml +++ b/compiler/rustc_hir_typeck/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_hir_typeck" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -23,7 +23,6 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index a994b31aeb437..872861d6289d9 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -10,6 +10,7 @@ hir_typeck_address_of_temporary_taken = cannot take address of a temporary hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new +hir_typeck_as_deref_suggestion = consider using `as_deref` here hir_typeck_base_expression_double_dot = base expression required after `..` hir_typeck_base_expression_double_dot_add_expr = add a base expression here hir_typeck_base_expression_double_dot_enable_default_field_values = @@ -27,6 +28,9 @@ hir_typeck_cannot_cast_to_bool = cannot cast `{$expr_ty}` as `bool` .help = compare with zero instead .label = unsupported cast +hir_typeck_cant_dereference = type `{$ty}` cannot be dereferenced +hir_typeck_cant_dereference_label = can't be dereferenced + hir_typeck_cast_enum_drop = cannot cast enum `{$expr_ty}` into integer `{$cast_ty}` because it implements `Drop` hir_typeck_cast_thin_pointer_to_wide_pointer = cannot cast thin pointer `{$expr_ty}` to wide pointer `{$cast_ty}` @@ -72,6 +76,9 @@ hir_typeck_dependency_on_unit_never_type_fallback = this function depends on nev hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty` +hir_typeck_expected_array_or_slice = expected an array or slice, found `{$ty}` +hir_typeck_expected_array_or_slice_label = pattern cannot match with input type `{$ty}` + hir_typeck_expected_default_return_type = expected `()` because of default return type hir_typeck_expected_return_type = expected `{$expected}` because of return type @@ -112,7 +119,11 @@ hir_typeck_int_to_fat = cannot cast `{$expr_ty}` to a pointer that {$known_wide hir_typeck_int_to_fat_label = creating a `{$cast_ty}` requires both an address and {$metadata} hir_typeck_int_to_fat_label_nightly = consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` -hir_typeck_invalid_callee = expected function, found {$ty} +hir_typeck_invalid_callee = expected function, found {$found} +hir_typeck_invalid_defined = `{$path}` defined here +hir_typeck_invalid_defined_kind = {$kind} `{$path}` defined here +hir_typeck_invalid_fn_defined = `{$func}` defined here returns `{$ty}` +hir_typeck_invalid_local = `{$local_name}` has type `{$ty}` hir_typeck_lossy_provenance_int2ptr = strict provenance disallows casting integer `{$expr_ty}` to pointer `{$cast_ty}` @@ -142,6 +153,12 @@ hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for { *[other] {" "}in the current scope } +hir_typeck_no_field_on_type = no field `{$field}` on type `{$ty}` + +hir_typeck_no_field_on_variant = no field named `{$field}` on enum variant `{$container}::{$ident}` +hir_typeck_no_field_on_variant_enum = this enum variant... +hir_typeck_no_field_on_variant_field = ...does not have this field + hir_typeck_note_caller_chooses_ty_for_ty_param = the caller chooses a type for `{$ty_param_name}` which can be different from `{$found_ty}` hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide @@ -154,10 +171,13 @@ hir_typeck_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` .teach_help = certain types, like `{$ty}`, must be casted before passing them to a variadic function, because of arcane ABI rules dictated by the C standard -hir_typeck_ptr_cast_add_auto_to_object = adding {$traits_len -> - [1] an auto trait {$traits} +hir_typeck_ptr_cast_add_auto_to_object = cannot add {$traits_len -> + [1] auto trait {$traits} *[other] auto traits {$traits} -} to a trait object in a pointer cast may cause UB later on +} to dyn bound via pointer cast + .note = this could allow UB elsewhere + .help = use `transmute` if you're sure this is sound + .label = unsupported cast hir_typeck_remove_semi_for_coerce = you might have meant to return the `match` expression hir_typeck_remove_semi_for_coerce_expr = this could be implicitly returned but it is a statement, not a tail expression @@ -183,6 +203,8 @@ hir_typeck_self_ctor_from_outer_item = can't reference `Self` constructor from o .label = the inner item doesn't inherit generics from this impl, so `Self` is invalid to reference .suggestion = replace `Self` with the actual type +hir_typeck_slicing_suggestion = consider slicing here + hir_typeck_struct_expr_non_exhaustive = cannot create non-exhaustive {$what} using struct expression diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 5de3c05c63c58..2a24d626ac357 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -23,7 +23,7 @@ use tracing::{debug, instrument}; use super::method::MethodCallee; use super::method::probe::ProbeScope; use super::{Expectation, FnCtxt, TupleArgumentsFlag}; -use crate::errors; +use crate::{errors, fluent_generated}; /// Checks that it is legal to call methods of the trait corresponding /// to `trait_id` (this only cares about the trait, not the specific @@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; }; - let fn_decl_span = if let hir::Node::Expr(hir::Expr { + let fn_decl_span = if let hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. }) = self.tcx.parent_hir_node(hir_id) @@ -371,7 +371,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // Actually need to unwrap one more layer of HIR to get to // the _real_ closure... - if let hir::Node::Expr(hir::Expr { + if let hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }), .. }) = self.tcx.parent_hir_node(parent_hir_id) @@ -674,13 +674,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let callee_ty = self.resolve_vars_if_possible(callee_ty); + let mut path = None; let mut err = self.dcx().create_err(errors::InvalidCallee { span: callee_expr.span, - ty: match &unit_variant { + ty: callee_ty, + found: match &unit_variant { Some((_, kind, path)) => format!("{kind} `{path}`"), - None => format!("`{callee_ty}`"), + None => format!("`{}`", self.tcx.short_string(callee_ty, &mut path)), }, }); + *err.long_ty_path() = path; if callee_ty.references_error() { err.downgrade_to_delayed_bug(); } @@ -780,27 +783,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(span) = self.tcx.hir().res_span(def) { let callee_ty = callee_ty.to_string(); let label = match (unit_variant, inner_callee_path) { - (Some((_, kind, path)), _) => Some(format!("{kind} `{path}` defined here")), - (_, Some(hir::QPath::Resolved(_, path))) => self - .tcx - .sess - .source_map() - .span_to_snippet(path.span) - .ok() - .map(|p| format!("`{p}` defined here returns `{callee_ty}`")), + (Some((_, kind, path)), _) => { + err.arg("kind", kind); + err.arg("path", path); + Some(fluent_generated::hir_typeck_invalid_defined_kind) + } + (_, Some(hir::QPath::Resolved(_, path))) => { + self.tcx.sess.source_map().span_to_snippet(path.span).ok().map(|p| { + err.arg("func", p); + fluent_generated::hir_typeck_invalid_fn_defined + }) + } _ => { match def { // Emit a different diagnostic for local variables, as they are not // type definitions themselves, but rather variables *of* that type. - Res::Local(hir_id) => Some(format!( - "`{}` has type `{}`", - self.tcx.hir().name(hir_id), - callee_ty - )), + Res::Local(hir_id) => { + err.arg("local_name", self.tcx.hir_name(hir_id)); + Some(fluent_generated::hir_typeck_invalid_local) + } Res::Def(kind, def_id) if kind.ns() == Some(Namespace::ValueNS) => { - Some(format!("`{}` defined here", self.tcx.def_path_str(def_id),)) + err.arg("path", self.tcx.def_path_str(def_id)); + Some(fluent_generated::hir_typeck_invalid_defined) + } + _ => { + err.arg("path", callee_ty); + Some(fluent_generated::hir_typeck_invalid_defined) } - _ => Some(format!("`{callee_ty}` defined here")), } } }; diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index f5f6ada12c3cc..c85c3b90ce72d 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -32,6 +32,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxHashSet; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; +use rustc_hir::def_id::DefId; use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_macros::{TypeFoldable, TypeVisitable}; @@ -39,13 +40,12 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut, TypeVisitableExt, VariantDef, elaborate}; use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::infer::InferCtxtExt; -use rustc_type_ir::elaborate; use tracing::{debug, instrument}; use super::FnCtxt; @@ -155,7 +155,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -#[derive(Copy, Clone, Debug)] +#[derive(Debug)] enum CastError<'tcx> { ErrorGuaranteed(ErrorGuaranteed), @@ -182,6 +182,7 @@ enum CastError<'tcx> { /// when we're typechecking a type parameter with a ?Sized bound. IntToWideCast(Option<&'static str>), ForeignNonExhaustiveAdt, + PtrPtrAddingAutoTrait(Vec), } impl From for CastError<'_> { @@ -548,17 +549,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.emit(); } CastError::SizedUnsizedCast => { + let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); fcx.dcx().emit_err(errors::CastThinPointerToWidePointer { span: self.span, - expr_ty: self.expr_ty, - cast_ty: fcx.ty_to_string(self.cast_ty), + expr_ty, + cast_ty, teach: fcx.tcx.sess.teach(E0607), }); } CastError::IntToWideCast(known_metadata) => { let expr_if_nightly = fcx.tcx.sess.is_nightly_build().then_some(self.expr_span); let cast_ty = fcx.resolve_vars_if_possible(self.cast_ty); - let expr_ty = fcx.ty_to_string(self.expr_ty); + let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty); let metadata = known_metadata.unwrap_or("type-specific metadata"); let known_wide = known_metadata.is_some(); let span = self.cast_span; @@ -594,6 +597,21 @@ impl<'a, 'tcx> CastCheck<'tcx> { .with_note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") .emit(); } + CastError::PtrPtrAddingAutoTrait(added) => { + fcx.dcx().emit_err(errors::PtrCastAddAutoToObject { + span: self.span, + traits_len: added.len(), + traits: { + let mut traits: Vec<_> = added + .into_iter() + .map(|trait_did| fcx.tcx.def_path_str(trait_did)) + .collect(); + + traits.sort(); + traits.into() + }, + }); + } } } @@ -893,20 +911,22 @@ impl<'a, 'tcx> CastCheck<'tcx> { // e.g. we want to allow `dyn T -> (dyn T,)`, etc. // // We also need to skip auto traits to emit an FCW and not an error. - let src_obj = tcx.mk_ty_from_kind(ty::Dynamic( + let src_obj = Ty::new_dynamic( + tcx, tcx.mk_poly_existential_predicates( &src_tty.without_auto_traits().collect::>(), ), tcx.lifetimes.re_erased, ty::Dyn, - )); - let dst_obj = tcx.mk_ty_from_kind(ty::Dynamic( + ); + let dst_obj = Ty::new_dynamic( + tcx, tcx.mk_poly_existential_predicates( &dst_tty.without_auto_traits().collect::>(), ), tcx.lifetimes.re_erased, ty::Dyn, - )); + ); // `dyn Src = dyn Dst`, this checks for matching traits/generics/projections // This is `fcx.demand_eqtype`, but inlined to give a better error. @@ -936,23 +956,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { .collect::>(); if !added.is_empty() { - tcx.emit_node_span_lint( - lint::builtin::PTR_CAST_ADD_AUTO_TO_OBJECT, - self.expr.hir_id, - self.span, - errors::PtrCastAddAutoToObject { - traits_len: added.len(), - traits: { - let mut traits: Vec<_> = added - .into_iter() - .map(|trait_did| tcx.def_path_str(trait_did)) - .collect(); - - traits.sort(); - traits.into() - }, - }, - ) + return Err(CastError::PtrPtrAddingAutoTrait(added)); } Ok(CastKind::PtrPtrCast) @@ -1164,10 +1168,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { if let Some((deref_ty, _)) = derefed { // Give a note about what the expr derefs to. if deref_ty != self.expr_ty.peel_refs() { - err.subdiagnostic(errors::DerefImplsIsEmpty { - span: self.expr_span, - deref_ty: fcx.ty_to_string(deref_ty), - }); + err.subdiagnostic(errors::DerefImplsIsEmpty { span: self.expr_span, deref_ty }); } // Create a multipart suggestion: add `!` and `.is_empty()` in @@ -1175,7 +1176,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.subdiagnostic(errors::UseIsEmpty { lo: self.expr_span.shrink_to_lo(), hi: self.span.with_lo(self.expr_span.hi()), - expr_ty: fcx.ty_to_string(self.expr_ty), + expr_ty: self.expr_ty, }); } } diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index 71a0664bbdff6..fc1f9a7f2e072 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -12,13 +12,14 @@ use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk, use rustc_infer::traits::{ObligationCauseCode, PredicateObligations}; use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::span_bug; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; +use rustc_middle::ty::{ + self, ClosureKind, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, +}; use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::error_reporting::traits::ArgKind; use rustc_trait_selection::traits; -use rustc_type_ir::ClosureKind; use tracing::{debug, instrument, trace}; use super::{CoroutineTypes, Expectation, FnCtxt, check_fn}; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 625c7f38fbb40..4cbc42b99ea35 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -41,8 +41,8 @@ use rustc_abi::ExternAbi; use rustc_attr_parsing::InlineAttr; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::{self as hir, LangItem}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::infer::relate::RelateResult; use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult}; @@ -51,15 +51,12 @@ use rustc_infer::traits::{ PredicateObligations, }; use rustc_middle::span_bug; -use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt}; -use rustc_session::parse::feature_err; -use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span, sym}; +use rustc_middle::ty::{self, AliasTy, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ @@ -595,6 +592,63 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Create an obligation for `Source: CoerceUnsized`. let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target }); + let root_obligation = Obligation::new( + self.tcx, + cause.clone(), + self.fcx.param_env, + ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]), + ); + + // If the root `Source: CoerceUnsized` obligation can't possibly hold, + // we don't have to assume that this is unsizing coercion (it will always lead to an error) + // + // However, we don't want to bail early all the time, since the unholdable obligations + // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id`), + // so we only bail if there (likely) is another way to convert the types. + if !self.infcx.predicate_may_hold(&root_obligation) { + if let Some(dyn_metadata_adt_def_id) = self.tcx.lang_items().get(LangItem::DynMetadata) + && let Some(metadata_type_def_id) = self.tcx.lang_items().get(LangItem::Metadata) + { + self.probe(|_| { + let ocx = ObligationCtxt::new(&self.infcx); + + // returns `true` if `::Metadata` is `DynMetadata<_>` + let has_dyn_trait_metadata = |ty| { + let metadata_ty: Result<_, _> = ocx.structurally_normalize_ty( + &ObligationCause::dummy(), + self.fcx.param_env, + Ty::new_alias( + self.tcx, + ty::AliasTyKind::Projection, + AliasTy::new(self.tcx, metadata_type_def_id, [ty]), + ), + ); + + metadata_ty.is_ok_and(|metadata_ty| { + metadata_ty + .ty_adt_def() + .is_some_and(|d| d.did() == dyn_metadata_adt_def_id) + }) + }; + + // If both types are raw pointers to a (wrapper over a) trait object, + // this might be a cast like `*const W -> *const dyn Trait`. + // So it's better to bail and try that. (even if the cast is not possible, for + // example due to vtables not matching, cast diagnostic will likely still be better) + // + // N.B. use `target`, not `coerce_target` (the latter is a var) + if let &ty::RawPtr(source_pointee, _) = coerce_source.kind() + && let &ty::RawPtr(target_pointee, _) = target.kind() + && has_dyn_trait_metadata(source_pointee) + && has_dyn_trait_metadata(target_pointee) + { + return Err(TypeError::Mismatch); + } + + Ok(()) + })?; + } + } // Use a FIFO queue for this custom fulfillment procedure. // @@ -603,14 +657,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // and almost never more than 3. By using a SmallVec we avoid an // allocation, at the (very small) cost of (occasionally) having to // shift subsequent elements down when removing the front element. - let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new( - self.tcx, - cause, - self.fcx.param_env, - ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]) - )]; - - let mut has_unsized_tuple_coercion = false; + let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![root_obligation]; // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where @@ -690,31 +737,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // be silent, as it causes a type mismatch later. } - Ok(Some(impl_source)) => { - // Some builtin coercions are still unstable so we detect - // these here and emit a feature error if coercion doesn't fail - // due to another reason. - match impl_source { - traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { - has_unsized_tuple_coercion = true; - } - _ => {} - } - queue.extend(impl_source.nested_obligations()) - } + Ok(Some(impl_source)) => queue.extend(impl_source.nested_obligations()), } } - if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion() { - feature_err( - &self.tcx.sess, - sym::unsized_tuple_coercion, - self.cause.span, - "unsized tuple coercion is not stable enough for use and is subject to change", - ) - .emit(); - } - Ok(coercion) } @@ -1887,7 +1913,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { let parent_id = fcx.tcx.parent_hir_id(block_or_return_id); let parent = fcx.tcx.hir_node(parent_id); if let Some(expr) = expression - && let hir::Node::Expr(hir::Expr { + && let hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure { body, .. }), .. }) = parent diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 38c07e473db3b..3eef32aa7c17c 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -6,9 +6,8 @@ use rustc_infer::infer::DefineOpaqueTypes; use rustc_middle::bug; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, AssocItem, Ty, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, AssocItem, BottomUpFolder, Ty, TypeFoldable, TypeVisitableExt}; use rustc_span::{DUMMY_SP, Ident, Span, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCause; @@ -577,9 +576,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut parent; 'outer: loop { // Climb the HIR tree to see if the current `Expr` is part of a `break;` statement. - let (hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Semi(&ref p), .. }) - | hir::Node::Block(hir::Block { expr: Some(&ref p), .. }) - | hir::Node::Expr(&ref p)) = self.tcx.hir_node(parent_id) + let (hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(p), .. }) + | hir::Node::Block(&hir::Block { expr: Some(p), .. }) + | hir::Node::Expr(p)) = self.tcx.hir_node(parent_id) else { break; }; @@ -593,13 +592,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { loop { // Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to. let parent = match self.tcx.hir_node(parent_id) { - hir::Node::Expr(&ref parent) => { + hir::Node::Expr(parent) => { parent_id = self.tcx.parent_hir_id(parent.hir_id); parent } hir::Node::Stmt(hir::Stmt { hir_id, - kind: hir::StmtKind::Semi(&ref parent) | hir::StmtKind::Expr(&ref parent), + kind: hir::StmtKind::Semi(parent) | hir::StmtKind::Expr(parent), .. }) => { parent_id = self.tcx.parent_hir_id(*hir_id); @@ -1265,7 +1264,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { CallableKind::Function }; - maybe_emit_help(def_id, path.segments[0].ident, args, callable_kind); + maybe_emit_help(def_id, path.segments.last().unwrap().ident, args, callable_kind); } hir::ExprKind::MethodCall(method, _receiver, args, _span) => { let Some(def_id) = diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 1bf8aa4f78d4d..b73cd26927a5c 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -91,7 +91,7 @@ pub(crate) enum ReturnLikeStatementKind { } impl IntoDiagArg for ReturnLikeStatementKind { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { let kind = match self { Self::Return => "return", Self::Become => "become", @@ -373,9 +373,14 @@ pub(crate) struct LossyProvenanceInt2Ptr<'tcx> { pub sugg: LossyProvenanceInt2PtrSuggestion, } -#[derive(LintDiagnostic)] -#[diag(hir_typeck_ptr_cast_add_auto_to_object)] +#[derive(Diagnostic)] +#[diag(hir_typeck_ptr_cast_add_auto_to_object, code = E0804)] +#[note] +#[help] pub(crate) struct PtrCastAddAutoToObject { + #[primary_span] + #[label] + pub span: Span, pub traits_len: usize, pub traits: DiagSymbolList, } @@ -454,12 +459,83 @@ impl HelpUseLatestEdition { } } +#[derive(Diagnostic)] +#[diag(hir_typeck_no_field_on_type, code = E0609)] +pub(crate) struct NoFieldOnType<'tcx> { + #[primary_span] + pub(crate) span: Span, + pub(crate) ty: Ty<'tcx>, + pub(crate) field: Ident, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_no_field_on_variant, code = E0609)] +pub(crate) struct NoFieldOnVariant<'tcx> { + #[primary_span] + pub(crate) span: Span, + pub(crate) container: Ty<'tcx>, + pub(crate) ident: Ident, + pub(crate) field: Ident, + #[label(hir_typeck_no_field_on_variant_enum)] + pub(crate) enum_span: Span, + #[label(hir_typeck_no_field_on_variant_field)] + pub(crate) field_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_cant_dereference, code = E0614)] +pub(crate) struct CantDereference<'tcx> { + #[primary_span] + #[label(hir_typeck_cant_dereference_label)] + pub(crate) span: Span, + pub(crate) ty: Ty<'tcx>, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_expected_array_or_slice, code = E0529)] +pub(crate) struct ExpectedArrayOrSlice<'tcx> { + #[primary_span] + #[label(hir_typeck_expected_array_or_slice_label)] + pub(crate) span: Span, + pub(crate) ty: Ty<'tcx>, + pub(crate) slice_pat_semantics: bool, + #[subdiagnostic] + pub(crate) as_deref: Option, + #[subdiagnostic] + pub(crate) slicing: Option, +} + +#[derive(Subdiagnostic)] +#[suggestion( + hir_typeck_as_deref_suggestion, + code = ".as_deref()", + style = "verbose", + applicability = "maybe-incorrect" +)] +pub(crate) struct AsDerefSuggestion { + #[primary_span] + pub(crate) span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + hir_typeck_slicing_suggestion, + code = "[..]", + style = "verbose", + applicability = "maybe-incorrect" +)] +pub(crate) struct SlicingSuggestion { + #[primary_span] + pub(crate) span: Span, +} + #[derive(Diagnostic)] #[diag(hir_typeck_invalid_callee, code = E0618)] -pub(crate) struct InvalidCallee { +pub(crate) struct InvalidCallee<'tcx> { #[primary_span] pub span: Span, - pub ty: String, + pub ty: Ty<'tcx>, + pub found: String, } #[derive(Diagnostic)] @@ -469,7 +545,7 @@ pub(crate) struct IntToWide<'tcx> { #[label(hir_typeck_int_to_fat_label)] pub span: Span, pub metadata: &'tcx str, - pub expr_ty: String, + pub expr_ty: Ty<'tcx>, pub cast_ty: Ty<'tcx>, #[label(hir_typeck_int_to_fat_label_nightly)] pub expr_if_nightly: Option, @@ -581,12 +657,12 @@ pub(crate) struct UnionPatDotDot { applicability = "maybe-incorrect", style = "verbose" )] -pub(crate) struct UseIsEmpty { +pub(crate) struct UseIsEmpty<'tcx> { #[suggestion_part(code = "!")] pub lo: Span, #[suggestion_part(code = ".is_empty()")] pub hi: Span, - pub expr_ty: String, + pub expr_ty: Ty<'tcx>, } #[derive(Diagnostic)] @@ -745,10 +821,10 @@ pub(crate) struct CtorIsPrivate { #[derive(Subdiagnostic)] #[note(hir_typeck_deref_is_empty)] -pub(crate) struct DerefImplsIsEmpty { +pub(crate) struct DerefImplsIsEmpty<'tcx> { #[primary_span] pub span: Span, - pub deref_ty: String, + pub deref_ty: Ty<'tcx>, } #[derive(Subdiagnostic)] @@ -826,7 +902,7 @@ pub(crate) struct CastThinPointerToWidePointer<'tcx> { #[primary_span] pub span: Span, pub expr_ty: Ty<'tcx>, - pub cast_ty: String, + pub cast_ty: Ty<'tcx>, #[note(hir_typeck_teach_help)] pub(crate) teach: bool, } diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 277396da19c13..7e8e4e3a5610e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -45,9 +45,10 @@ use crate::coercion::{CoerceMany, DynamicCoerceMany}; use crate::errors::{ AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove, - FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, - ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, - TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, + CantDereference, FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, + HelpUseLatestEdition, NoFieldOnType, NoFieldOnVariant, ReturnLikeStatementKind, + ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, + YieldExprOutsideOfCoroutine, }; use crate::{ BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, cast, fatally_break_rust, @@ -297,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Combine the diverging and has_error flags. self.diverges.set(self.diverges.get() | old_diverges); - debug!("type of {} is...", self.tcx.hir().node_to_string(expr.hir_id)); + debug!("type of {} is...", self.tcx.hir_id_to_string(expr.hir_id)); debug!("... {:?}, expected is {:?}", ty, expected); ty @@ -361,6 +362,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Any expression child of these expressions constitute reads. ExprKind::Array(_) | ExprKind::Call(_, _) + | ExprKind::Use(_, _) | ExprKind::MethodCall(_, _, _, _) | ExprKind::Tup(_) | ExprKind::Binary(_, _, _) @@ -551,6 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::Closure(closure) => self.check_expr_closure(closure, expr.span, expected), ExprKind::Block(body, _) => self.check_expr_block(body, expected), ExprKind::Call(callee, args) => self.check_expr_call(expr, callee, args, expected), + ExprKind::Use(used_expr, _) => self.check_expr_use(used_expr, expected), ExprKind::MethodCall(segment, receiver, args, _) => { self.check_expr_method_call(expr, segment, receiver, args, expected) } @@ -607,13 +610,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ty) = self.lookup_derefing(expr, oprnd, oprnd_t) { oprnd_t = ty; } else { - let mut err = type_error_struct!( - self.dcx(), - expr.span, - oprnd_t, - E0614, - "type `{oprnd_t}` cannot be dereferenced", - ); + let mut err = + self.dcx().create_err(CantDereference { span: expr.span, ty: oprnd_t }); let sp = tcx.sess.source_map().start_point(expr.span).with_parent(None); if let Some(sp) = tcx.sess.psess.ambiguous_block_expr_parse.borrow().get(&sp) @@ -1620,6 +1618,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) } + /// Checks use `x.use`. + fn check_expr_use( + &self, + used_expr: &'tcx hir::Expr<'tcx>, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + self.check_expr_with_expectation(used_expr, expected) + } + fn check_expr_cast( &self, e: &'tcx hir::Expr<'tcx>, @@ -1656,13 +1663,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_unsafe_binder_cast( &self, span: Span, - kind: hir::UnsafeBinderCastKind, + kind: ast::UnsafeBinderCastKind, inner_expr: &'tcx hir::Expr<'tcx>, hir_ty: Option<&'tcx hir::Ty<'tcx>>, expected: Expectation<'tcx>, ) -> Ty<'tcx> { match kind { - hir::UnsafeBinderCastKind::Wrap => { + ast::UnsafeBinderCastKind::Wrap => { let ascribed_ty = hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty)); let expected_ty = expected.only_has_type(self); @@ -1706,7 +1713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { binder_ty } - hir::UnsafeBinderCastKind::Unwrap => { + ast::UnsafeBinderCastKind::Unwrap => { let ascribed_ty = hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty)); let hint_ty = ascribed_ty.unwrap_or_else(|| self.next_ty_var(inner_expr.span)); @@ -1810,7 +1817,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { crate::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(body.value, expected); - fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized); + fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::SizedConstOrStatic); fcx.write_ty(block.hir_id, ty); ty } @@ -1857,12 +1864,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ty::new_error(tcx, guar); } + // We defer checking whether the element type is `Copy` as it is possible to have + // an inference variable as a repeat count and it seems unlikely that `Copy` would + // have inference side effects required for type checking to succeed. + if tcx.features().generic_arg_infer() { + self.deferred_repeat_expr_checks.borrow_mut().push((element, element_ty, count)); // If the length is 0, we don't create any elements, so we don't copy any. // If the length is 1, we don't copy that one element, we move it. Only check // for `Copy` if the length is larger, or unevaluated. - // FIXME(min_const_generic_exprs): We could perhaps defer this check so that - // we don't require `::CONST` doesn't unnecessarily require `Copy`. - if count.try_to_target_usize(tcx).is_none_or(|x| x > 1) { + } else if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) { self.enforce_repeat_element_needs_copy_bound(element, element_ty); } @@ -1872,7 +1882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Requires that `element_ty` is `Copy` (unless it's a const expression itself). - fn enforce_repeat_element_needs_copy_bound( + pub(super) fn enforce_repeat_element_needs_copy_bound( &self, element: &hir::Expr<'_>, element_ty: Ty<'tcx>, @@ -2050,7 +2060,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // struct-like enums (yet...), but it's definitely not // a bug to have constructed one. if adt_kind != AdtKind::Enum { - tcx.check_stability(v_field.did, Some(expr.hir_id), field.span, None); + tcx.check_stability(v_field.did, Some(field.hir_id), field.span, None); } self.field_ty(field.span, v_field, args) @@ -2923,7 +2933,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let guar = if field.name == kw::Empty { - self.dcx().span_delayed_bug(field.span, "field name with no name") + self.dcx().span_bug(field.span, "field name with no name") } else if self.method_exists_for_diagnostic( field, base_ty, @@ -3070,7 +3080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, base_ty={:?}", ident, base, expr, base_ty ); - let mut err = self.no_such_field_err(ident, base_ty, base.hir_id); + let mut err = self.no_such_field_err(ident, base_ty, expr); match *base_ty.peel_refs().kind() { ty::Array(_, len) => { @@ -3283,21 +3293,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - fn no_such_field_err(&self, field: Ident, expr_t: Ty<'tcx>, id: HirId) -> Diag<'_> { + fn no_such_field_err( + &self, + field: Ident, + base_ty: Ty<'tcx>, + expr: &hir::Expr<'tcx>, + ) -> Diag<'_> { let span = field.span; - debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t); + debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, base_ty); - let mut err = type_error_struct!( - self.dcx(), - span, - expr_t, - E0609, - "no field `{field}` on type `{expr_t}`", - ); + let mut err = self.dcx().create_err(NoFieldOnType { span, ty: base_ty, field }); + if base_ty.references_error() { + err.downgrade_to_delayed_bug(); + } + + if let Some(within_macro_span) = span.within_macro(expr.span, self.tcx.sess.source_map()) { + err.span_label(within_macro_span, "due to this macro variable"); + } // try to add a suggestion in case the field is a nested field of a field of the Adt - let mod_id = self.tcx.parent_module(id).to_def_id(); - let (ty, unwrap) = if let ty::Adt(def, args) = expr_t.kind() + let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id(); + let (ty, unwrap) = if let ty::Adt(def, args) = base_ty.kind() && (self.tcx.is_diagnostic_item(sym::Result, def.did()) || self.tcx.is_diagnostic_item(sym::Option, def.did())) && let Some(arg) = args.get(0) @@ -3305,10 +3321,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { (ty, "unwrap().") } else { - (expr_t, "") + (base_ty, "") }; for (found_fields, args) in - self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, id) + self.get_field_candidates_considering_privacy_for_diag(span, ty, mod_id, expr.hir_id) { let field_names = found_fields.iter().map(|field| field.name).collect::>(); let mut candidate_fields: Vec<_> = found_fields @@ -3321,7 +3337,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { args, vec![], mod_id, - id, + expr.hir_id, ) }) .map(|mut field_path| { @@ -3332,7 +3348,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_fields.sort(); let len = candidate_fields.len(); - if len > 0 { + // Don't suggest `.field` if the base expr is from a different + // syntax context than the field. + if len > 0 && expr.span.eq_ctxt(field.span) { err.span_suggestions( field.span.shrink_to_lo(), format!( @@ -3763,7 +3781,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut diverge = asm.asm_macro.diverges(asm.options); for (op, _op_sp) in asm.operands { - match op { + match *op { hir::InlineAsmOperand::In { expr, .. } => { self.check_expr_asm_operand(expr, true); } @@ -3778,10 +3796,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_asm_operand(out_expr, false); } } - // `AnonConst`s have their own body and is type-checked separately. - // As they don't flow into the type system we don't need them to - // be well-formed. - hir::InlineAsmOperand::Const { .. } | hir::InlineAsmOperand::SymFn { .. } => {} + hir::InlineAsmOperand::Const { ref anon_const } => { + self.check_expr_const_block(anon_const, Expectation::NoExpectation); + } + hir::InlineAsmOperand::SymFn { expr } => { + self.check_expr(expr); + } hir::InlineAsmOperand::SymStatic { .. } => {} hir::InlineAsmOperand::Label { block } => { let previous_diverges = self.diverges.get(); @@ -3864,16 +3884,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter_enumerated() .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident) else { - type_error_struct!( - self.dcx(), - ident.span, - container, - E0609, - "no field named `{subfield}` on enum variant `{container}::{ident}`", - ) - .with_span_label(field.span, "this enum variant...") - .with_span_label(subident.span, "...does not have this field") - .emit(); + self.dcx() + .create_err(NoFieldOnVariant { + span: ident.span, + container, + ident, + field: subfield, + enum_span: field.span, + field_span: subident.span, + }) + .emit_unless(container.references_error()); break; }; @@ -3965,7 +3985,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => (), }; - self.no_such_field_err(field, container, expr.hir_id).emit(); + self.no_such_field_err(field, container, expr).emit(); break; } diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 9b85b2aeec6e9..35e687f2b0fb8 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -47,6 +47,21 @@ pub trait Delegate<'tcx> { /// the id of the binding in the pattern `pat`. fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId); + /// The value found at `place` is used, depending + /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. + /// + /// Use of a `Copy` type in a ByUse context is considered a use + /// by `ImmBorrow` and `borrow` is called instead. This is because + /// a shared borrow is the "minimum access" that would be needed + /// to perform a copy. + /// + /// + /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for + /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic + /// id will be the id of the expression `expr` but the place itself will have + /// the id of the binding in the pattern `pat`. + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId); + /// The value found at `place` is being borrowed with kind `bk`. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). fn borrow( @@ -91,6 +106,10 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D { (**self).consume(place_with_id, diag_expr_id) } + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + (**self).use_cloned(place_with_id, diag_expr_id) + } + fn borrow( &mut self, place_with_id: &PlaceWithHirId<'tcx>, @@ -143,6 +162,8 @@ pub trait TypeInformationCtxt<'tcx> { fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool; + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool; + fn body_owner_def_id(&self) -> LocalDefId; fn tcx(&self) -> TyCtxt<'tcx>; @@ -184,6 +205,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { self.infcx.type_is_copy_modulo_regions(self.param_env, ty) } + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.infcx.type_is_use_cloned_modulo_regions(self.param_env, ty) + } + fn body_owner_def_id(&self) -> LocalDefId { self.body_id } @@ -230,6 +255,10 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { self.0.type_is_copy_modulo_regions(ty) } + fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.0.type_is_use_cloned_modulo_regions(ty) + } + fn body_owner_def_id(&self) -> LocalDefId { self.1 } @@ -295,6 +324,24 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } + pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id); + + // `x.use` will do one of the following + // * if it implements `Copy`, it will be a copy + // * if it implements `UseCloned`, it will be a call to `clone` + // * otherwise, it is a move + // + // we do a conservative approximation of this, treating it as a move unless we know that it implements copy or `UseCloned` + if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) { + self.delegate.borrow_mut().copy(place_with_id, diag_expr_id); + } else if self.cx.type_is_use_cloned_modulo_regions(place_with_id.place.ty()) { + self.delegate.borrow_mut().use_cloned(place_with_id, diag_expr_id); + } else { + self.delegate.borrow_mut().consume(place_with_id, diag_expr_id); + } + } + fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> { for expr in exprs { self.consume_expr(expr)?; @@ -313,6 +360,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { + debug!("consume_or_clone_expr(expr={:?})", expr); + + let place_with_id = self.cat_expr(expr)?; + self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); + self.walk_expr(expr)?; + Ok(()) + } + fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { let place_with_id = self.cat_expr(expr)?; self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id); @@ -366,6 +422,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.consume_exprs(args)?; } + hir::ExprKind::Use(expr, _) => { + self.consume_or_clone_expr(expr)?; + } + hir::ExprKind::MethodCall(.., receiver, args, _) => { // callee.m(args) self.consume_expr(receiver)?; @@ -895,48 +955,44 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx match pat.kind { PatKind::Binding(_, canonical_id, ..) => { debug!("walk_pat: binding place={:?} pat={:?}", place, pat); - if let Some(bm) = self + let bm = self .cx .typeck_results() - .extract_binding_mode(tcx.sess, pat.hir_id, pat.span) - { - debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); + .extract_binding_mode(tcx.sess, pat.hir_id, pat.span); + debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); - // pat_ty: the type of the binding being produced. - let pat_ty = self.node_ty(pat.hir_id)?; - debug!("walk_pat: pat_ty={:?}", pat_ty); + // pat_ty: the type of the binding being produced. + let pat_ty = self.node_ty(pat.hir_id)?; + debug!("walk_pat: pat_ty={:?}", pat_ty); - let def = Res::Local(canonical_id); - if let Ok(ref binding_place) = - self.cat_res(pat.hir_id, pat.span, pat_ty, def) - { - self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id); - } + let def = Res::Local(canonical_id); + if let Ok(ref binding_place) = self.cat_res(pat.hir_id, pat.span, pat_ty, def) { + self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id); + } - // Subtle: MIR desugaring introduces immutable borrows for each pattern - // binding when lowering pattern guards to ensure that the guard does not - // modify the scrutinee. - if has_guard { - self.delegate.borrow_mut().borrow( - place, - discr_place.hir_id, - BorrowKind::Immutable, - ); - } + // Subtle: MIR desugaring introduces immutable borrows for each pattern + // binding when lowering pattern guards to ensure that the guard does not + // modify the scrutinee. + if has_guard { + self.delegate.borrow_mut().borrow( + place, + discr_place.hir_id, + BorrowKind::Immutable, + ); + } - // It is also a borrow or copy/move of the value being matched. - // In a cases of pattern like `let pat = upvar`, don't use the span - // of the pattern, as this just looks confusing, instead use the span - // of the discriminant. - match bm.0 { - hir::ByRef::Yes(m) => { - let bk = ty::BorrowKind::from_mutbl(m); - self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); - } - hir::ByRef::No => { - debug!("walk_pat binding consuming pat"); - self.consume_or_copy(place, discr_place.hir_id); - } + // It is also a borrow or copy/move of the value being matched. + // In a cases of pattern like `let pat = upvar`, don't use the span + // of the pattern, as this just looks confusing, instead use the span + // of the discriminant. + match bm.0 { + hir::ByRef::Yes(m) => { + let bk = ty::BorrowKind::from_mutbl(m); + self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk); + } + hir::ByRef::No => { + debug!("walk_pat binding consuming pat"); + self.consume_or_copy(place, discr_place.hir_id); } } } @@ -1089,6 +1145,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ty::UpvarCapture::ByValue => { self.consume_or_copy(&place_with_id, place_with_id.hir_id); } + ty::UpvarCapture::ByUse => { + self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); + } ty::UpvarCapture::ByRef(upvar_borrow) => { self.delegate.borrow_mut().borrow( &place_with_id, @@ -1176,7 +1235,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.cx.tainted_by_errors()?; bug!( "no type for node {} in mem_categorization", - self.cx.tcx().hir().node_to_string(id) + self.cx.tcx().hir_id_to_string(id) ); } } @@ -1390,6 +1449,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) + | hir::ExprKind::Use(..) | hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | hir::ExprKind::Closure { .. } @@ -1780,7 +1840,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let ty = self.pat_ty_adjusted(subpat)?; let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability); // A deref pattern generates a temporary. - let place = self.cat_rvalue(pat.hir_id, ty); + let base = self.cat_rvalue(pat.hir_id, ty); + let place = self.cat_deref(pat.hir_id, base)?; self.cat_pattern(place, subpat, op)?; } diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index e051fc7ac6ca7..759b5d9550c05 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -503,7 +503,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { let unit_errors = remaining_errors_if_fallback_to(self.tcx.types.unit); if unit_errors.is_empty() && let mut never_errors = remaining_errors_if_fallback_to(self.tcx.types.never) - && let [ref mut never_error, ..] = never_errors.as_mut_slice() + && let [never_error, ..] = never_errors.as_mut_slice() { self.adjust_fulfillment_error_for_expr_obligation(never_error); let sugg = self.try_to_suggest_annotations(diverging_vids, coercions); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2d7d80e39bc31..64886957ff37f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -21,11 +21,9 @@ use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryRespons use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, GenericArgKind, GenericArgsRef, GenericParamDefKind, - IsIdentity, Ty, TyCtxt, UserArgs, UserSelfTy, + IsIdentity, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, UserSelfTy, }; use rustc_middle::{bug, span_bug}; use rustc_session::lint; @@ -85,25 +83,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) } - /// Resolves type and const variables in `ty` if possible. Unlike the infcx + /// Resolves type and const variables in `t` if possible. Unlike the infcx /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. // FIXME(-Znext-solver): A lot of the calls to this method should // probably be `try_structurally_resolve_type` or `structurally_resolve_type` instead. #[instrument(skip(self), level = "debug", ret)] - pub(crate) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + pub(crate) fn resolve_vars_with_obligations>>( + &self, + mut t: T, + ) -> T { // No Infer()? Nothing needs doing. - if !ty.has_non_region_infer() { + if !t.has_non_region_infer() { debug!("no inference var, nothing needs doing"); - return ty; + return t; } - // If `ty` is a type variable, see whether we already know what it is. - ty = self.resolve_vars_if_possible(ty); - if !ty.has_non_region_infer() { - debug!(?ty); - return ty; + // If `t` is a type variable, see whether we already know what it is. + t = self.resolve_vars_if_possible(t); + if !t.has_non_region_infer() { + debug!(?t); + return t; } // If not, try resolving pending obligations as much as @@ -111,7 +112,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // indirect dependencies that don't seem worth tracking // precisely. self.select_obligations_where_possible(|_| {}); - self.resolve_vars_if_possible(ty) + self.resolve_vars_if_possible(t) } pub(crate) fn record_deferred_call_resolution( @@ -137,7 +138,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn local_ty(&self, span: Span, nid: HirId) -> Ty<'tcx> { self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| { - span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid)) + span_bug!(span, "no type for local variable {}", self.tcx.hir_id_to_string(nid)) }) } @@ -217,6 +218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { debug!("fcx {}", self.tag()); + // Don't write user type annotations for const param types, since we give them + // identity args just so that we can trivially substitute their `EarlyBinder`. + // We enforce that they match their type in MIR later on. + if matches!(self.tcx.def_kind(def_id), DefKind::ConstParam) { + return; + } + if Self::can_contain_user_lifetime_bounds((args, user_self_ty)) { let canonicalized = self.canonicalize_user_type_annotation(ty::UserType::new( ty::UserTypeKind::TypeOf(def_id, UserArgs { args, user_self_ty }), @@ -519,7 +527,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn lower_const_arg( &self, const_arg: &'tcx hir::ConstArg<'tcx>, - feed: FeedConstTy, + feed: FeedConstTy<'_, 'tcx>, ) -> ty::Const<'tcx> { let ct = self.lowerer().lower_const_arg(const_arg, feed); self.register_wf_obligation( @@ -549,11 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(&t) => t, None if let Some(e) = self.tainted_by_errors() => Ty::new_error(self.tcx, e), None => { - bug!( - "no type for node {} in fcx {}", - self.tcx.hir().node_to_string(id), - self.tag() - ); + bug!("no type for node {} in fcx {}", self.tcx.hir_id_to_string(id), self.tag()); } } } @@ -666,12 +670,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !errors.is_empty() { self.adjust_fulfillment_errors_for_expr_obligation(&mut errors); - let errors_causecode = errors - .iter() - .map(|e| (e.obligation.cause.span, e.root_obligation.cause.code().clone())) - .collect::>(); self.err_ctxt().report_fulfillment_errors(errors); - self.collect_unused_stmts_for_coerce_return_ty(errors_causecode); } } @@ -827,15 +826,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let trait_missing_method = matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); - if item_name.name != kw::Empty { - self.report_method_error( - hir_id, - ty.normalized, - error, - Expectation::NoExpectation, - trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 - ); - } + assert_ne!(item_name.name, kw::Empty); + self.report_method_error( + hir_id, + ty.normalized, + error, + Expectation::NoExpectation, + trait_missing_method && span.edition().at_least_rust_2021(), // emits missing method for trait only after edition 2021 + ); result }); @@ -1135,7 +1133,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .last() .is_some_and(|GenericPathSegment(def_id, _)| tcx.generics_of(*def_id).has_self); - let (res, self_ctor_args) = if let Res::SelfCtor(impl_def_id) = res { + let (res, implicit_args) = if let Res::Def(DefKind::ConstParam, def) = res { + // types of const parameters are somewhat special as they are part of + // the same environment as the const parameter itself. this means that + // unlike most paths `type-of(N)` can return a type naming parameters + // introduced by the containing item, rather than provided through `N`. + // + // for example given `` and some + // `let a = N;` expression. The path to `N` would wind up with no args + // (as it has no args), but instantiating the early binder on `typeof(N)` + // requires providing generic arguments for `[T, M, N]`. + (res, Some(ty::GenericArgs::identity_for_item(tcx, tcx.parent(def)))) + } else if let Res::SelfCtor(impl_def_id) = res { let ty = LoweredTy::from_raw( self, span, @@ -1261,6 +1270,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn provided_kind( &mut self, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { @@ -1280,7 +1290,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self .fcx // Ambiguous parts of `ConstArg` are handled in the match arms below - .lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id)) + .lower_const_arg( + ct.as_unambig_ct(), + FeedConstTy::Param(param.def_id, preceding_args), + ) .into(), (&GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.fcx.ct_infer(Some(param), inf.span).into() @@ -1320,7 +1333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let args_raw = self_ctor_args.unwrap_or_else(|| { + let args_raw = implicit_args.unwrap_or_else(|| { lower_generic_args( self, def_id, @@ -1454,7 +1467,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sp: Span, ct: ty::Const<'tcx>, ) -> ty::Const<'tcx> { - // FIXME(min_const_generic_exprs): We could process obligations here if `ct` is a var. + let ct = self.resolve_vars_with_obligations(ct); if self.next_trait_solver() && let ty::ConstKind::Unevaluated(..) = ct.kind() @@ -1510,6 +1523,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub(crate) fn structurally_resolve_const( + &self, + sp: Span, + ct: ty::Const<'tcx>, + ) -> ty::Const<'tcx> { + let ct = self.try_structurally_resolve_const(sp, ct); + + if !ct.is_ct_infer() { + ct + } else { + let e = self.tainted_by_errors().unwrap_or_else(|| { + self.err_ctxt() + .emit_inference_failure_err( + self.body_id, + sp, + ct.into(), + TypeAnnotationNeeded::E0282, + true, + ) + .emit() + }); + // FIXME: Infer `?ct = {const error}`? + ty::Const::new_error(self.tcx, e) + } + } + pub(crate) fn with_breakable_ctxt R, R>( &self, id: HirId, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs index 358bc389bd138..f6298adf2ebb7 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs @@ -22,6 +22,12 @@ impl ExpectedIdx { } } +impl ProvidedIdx { + pub(crate) fn to_expected_idx(self) -> ExpectedIdx { + ExpectedIdx::from_u32(self.as_u32()) + } +} + // An issue that might be found in the compatibility matrix #[derive(Debug)] enum Issue { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index cf61659479b13..90bdb3c4b3739 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -3,9 +3,7 @@ use std::{fmt, iter, mem}; use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; -use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize, -}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, listify, pluralize}; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -17,11 +15,10 @@ use rustc_index::IndexVec; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TypeTrace}; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt}; +use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_session::Session; -use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, kw, sym}; use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext}; @@ -101,21 +98,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); for (asm, hir_id) in deferred_asm_checks.drain(..) { let enclosing_id = self.tcx.hir_enclosing_body_owner(hir_id); - let get_operand_ty = |expr| { - let ty = self.typeck_results.borrow().expr_ty_adjusted(expr); - let ty = self.resolve_vars_if_possible(ty); - if ty.has_non_region_infer() { - Ty::new_misc_error(self.tcx) - } else { - self.tcx.erase_regions(ty) - } - }; - InlineAsmCtxt::new_in_fn( - self.tcx, - self.infcx.typing_env(self.param_env), - get_operand_ty, + InlineAsmCtxt::new( + enclosing_id, + &self.infcx, + self.typing_env(self.param_env), + &*self.typeck_results.borrow(), ) - .check_asm(asm, enclosing_id); + .check_asm(asm); + } + } + + pub(in super::super) fn check_repeat_exprs(&self) { + let mut deferred_repeat_expr_checks = self.deferred_repeat_expr_checks.borrow_mut(); + debug!("FnCtxt::check_repeat_exprs: {} deferred checks", deferred_repeat_expr_checks.len()); + for (element, element_ty, count) in deferred_repeat_expr_checks.drain(..) { + // We want to emit an error if the const is not structurally resolveable as otherwise + // we can find up conservatively proving `Copy` which may infer the repeat expr count + // to something that never required `Copy` in the first place. + let count = + self.structurally_resolve_const(element.span, self.normalize(element.span, count)); + + // Avoid run on "`NotCopy: Copy` is not implemented" errors when the repeat expr count + // is erroneous/unknown. The user might wind up specifying a repeat count of 0/1. + if count.references_error() { + continue; + } + + // If the length is 0, we don't create any elements, so we don't copy any. + // If the length is 1, we don't copy that one element, we move it. Only check + // for `Copy` if the length is larger. + if count.try_to_target_usize(self.tcx).is_none_or(|x| x > 1) { + self.enforce_repeat_element_needs_copy_bound(element, element_ty); + } } } @@ -780,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // First, check if we just need to wrap some arguments in a tuple. if let Some((mismatch_idx, terr)) = - compatibility_diagonal.iter().enumerate().find_map(|(i, c)| { + compatibility_diagonal.iter_enumerated().find_map(|(i, c)| { if let Compatibility::Incompatible(Some(terr)) = c { Some((i, *terr)) } else { @@ -792,24 +806,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Do we have as many extra provided arguments as the tuple's length? // If so, we might have just forgotten to wrap some args in a tuple. if let Some(ty::Tuple(tys)) = - formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind()) + formal_and_expected_inputs.get(mismatch_idx.to_expected_idx()).map(|tys| tys.1.kind()) // If the tuple is unit, we're not actually wrapping any arguments. && !tys.is_empty() && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() { // Wrap up the N provided arguments starting at this position in a tuple. - let provided_as_tuple = Ty::new_tup_from_iter( - tcx, - provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()), - ); + let provided_args_to_tuple = &provided_arg_tys[mismatch_idx..]; + let (provided_args_to_tuple, provided_args_after_tuple) = + provided_args_to_tuple.split_at(tys.len()); + let provided_as_tuple = + Ty::new_tup_from_iter(tcx, provided_args_to_tuple.iter().map(|&(ty, _)| ty)); let mut satisfied = true; // Check if the newly wrapped tuple + rest of the arguments are compatible. for ((_, expected_ty), provided_ty) in std::iter::zip( - formal_and_expected_inputs.iter().skip(mismatch_idx), - [provided_as_tuple].into_iter().chain( - provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()), - ), + formal_and_expected_inputs[mismatch_idx.to_expected_idx()..].iter(), + [provided_as_tuple] + .into_iter() + .chain(provided_args_after_tuple.iter().map(|&(ty, _)| ty)), ) { if !self.may_coerce(provided_ty, *expected_ty) { satisfied = false; @@ -821,10 +836,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Take some care with spans, so we don't suggest wrapping a macro's // innards in parenthesis, for example. if satisfied - && let Some((_, lo)) = - provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx)) - && let Some((_, hi)) = - provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1)) + && let &[(_, hi @ lo)] | &[(_, lo), .., (_, hi)] = provided_args_to_tuple { let mut err; if tys.len() == 1 { @@ -832,9 +844,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so don't do anything special here. err = self.err_ctxt().report_and_explain_type_error( mk_trace( - *lo, - formal_and_expected_inputs[mismatch_idx.into()], - provided_arg_tys[mismatch_idx.into()].0, + lo, + formal_and_expected_inputs[mismatch_idx.to_expected_idx()], + provided_arg_tys[mismatch_idx].0, ), self.param_env, terr, @@ -873,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { callee_ty, call_expr, None, - Some(mismatch_idx), + Some(mismatch_idx.as_usize()), &matched_inputs, &formal_and_expected_inputs, is_method, @@ -1623,7 +1635,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::Char(_) => tcx.types.char, ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => Ty::new_int(tcx, ty::int_ty(t)), ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => Ty::new_uint(tcx, ty::uint_ty(t)), - ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { + ast::LitKind::Int(i, ast::LitIntType::Unsuffixed) => { let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Int(_) | ty::Uint(_) => Some(ty), // These exist to direct casts like `0x61 as char` to use @@ -1632,6 +1644,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Char => Some(tcx.types.u8), ty::RawPtr(..) => Some(tcx.types.usize), ty::FnDef(..) | ty::FnPtr(..) => Some(tcx.types.usize), + &ty::Pat(base, _) if base.is_integral() => { + let layout = tcx + .layout_of(self.typing_env(self.param_env).as_query_input(ty)) + .ok()?; + assert!(!layout.uninhabited); + + match layout.backend_repr { + rustc_abi::BackendRepr::Scalar(scalar) => { + scalar.valid_range(&tcx).contains(u128::from(i.get())).then_some(ty) + } + _ => unreachable!(), + } + } _ => None, }); opt_ty.unwrap_or_else(|| self.next_int_var()) @@ -2148,7 +2173,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let result = self .lowerer() - .lower_assoc_path(hir_id, path_span, ty.raw, qself, segment, true); + .lower_assoc_path_ty(hir_id, path_span, ty.raw, qself, segment, true); let ty = result .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar)); @@ -2167,62 +2192,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - pub(super) fn collect_unused_stmts_for_coerce_return_ty( - &self, - errors_causecode: Vec<(Span, ObligationCauseCode<'tcx>)>, - ) { - for (span, code) in errors_causecode { - self.dcx().try_steal_modify_and_emit_err(span, StashKey::MaybeForgetReturn, |err| { - if let Some(fn_sig) = self.body_fn_sig() - && let ObligationCauseCode::WhereClauseInExpr(_, _, binding_hir_id, ..) = code - && !fn_sig.output().is_unit() - { - let mut block_num = 0; - let mut found_semi = false; - for (hir_id, node) in self.tcx.hir_parent_iter(binding_hir_id) { - // Don't proceed into parent bodies - if hir_id.owner != binding_hir_id.owner { - break; - } - match node { - hir::Node::Stmt(stmt) => { - if let hir::StmtKind::Semi(expr) = stmt.kind { - let expr_ty = self.typeck_results.borrow().expr_ty(expr); - let return_ty = fn_sig.output(); - if !matches!(expr.kind, hir::ExprKind::Ret(..)) - && self.may_coerce(expr_ty, return_ty) - { - found_semi = true; - } - } - } - hir::Node::Block(_block) => { - if found_semi { - block_num += 1; - } - } - hir::Node::Item(item) => { - if let hir::ItemKind::Fn { .. } = item.kind { - break; - } - } - _ => {} - } - } - if block_num > 1 && found_semi { - err.span_suggestion_verbose( - // use the span of the *whole* expr - self.tcx.hir().span(binding_hir_id).shrink_to_lo(), - "you might have meant to return this to infer its type parameters", - "return ", - Applicability::MaybeIncorrect, - ); - } - } - }); - } - } - /// Given a vector of fulfillment errors, try to adjust the spans of the /// errors to more accurately point at the cause of the failure. /// @@ -2620,7 +2589,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let expected_display_type = self - .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1) + .resolve_vars_if_possible(formal_and_expected_inputs[idx].1) .sort_string(self.tcx); let label = if idxs_matched == params_with_generics.len() - 1 { format!( @@ -2709,7 +2678,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { params.get(is_method as usize..params.len() - sig.decl.c_variadic as usize)?; debug_assert_eq!(params.len(), fn_inputs.len()); Some(( - fn_inputs.zip(params.iter().map(|param| FnParam::Name(param))).collect(), + fn_inputs.zip(params.iter().map(|¶m| FnParam::Name(param))).collect(), generics, )) } @@ -2740,23 +2709,14 @@ impl<'tcx> Visitor<'tcx> for FindClosureArg<'tcx> { #[derive(Clone, Copy)] enum FnParam<'hir> { Param(&'hir hir::Param<'hir>), - Name(&'hir Ident), + Name(Ident), } + impl FnParam<'_> { fn span(&self) -> Span { match self { - Self::Param(x) => x.span, - Self::Name(x) => x.span, - } - } - - fn name(&self) -> Option { - match self { - Self::Param(x) if let hir::PatKind::Binding(_, _, ident, _) = x.pat.kind => { - Some(ident.name) - } - Self::Name(x) if x.name != kw::Empty => Some(x.name), - _ => None, + Self::Param(param) => param.span, + Self::Name(ident) => ident.span, } } @@ -2764,8 +2724,23 @@ impl FnParam<'_> { struct D<'a>(FnParam<'a>, usize); impl fmt::Display for D<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(name) = self.0.name() { - write!(f, "`{name}`") + // A "unique" param name is one that (a) exists, and (b) is guaranteed to be unique + // among the parameters, i.e. `_` does not count. + let unique_name = match self.0 { + FnParam::Param(param) + if let hir::PatKind::Binding(_, _, ident, _) = param.pat.kind => + { + Some(ident.name) + } + FnParam::Name(ident) + if ident.name != kw::Empty && ident.name != kw::Underscore => + { + Some(ident.name) + } + _ => None, + }; + if let Some(unique_name) = unique_name { + write!(f, "`{unique_name}`") } else { write!(f, "parameter #{}", self.1 + 1) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index dc10b53fd8390..95b9cb3be627c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -1,13 +1,12 @@ //! A utility module to inspect currently ambiguous obligations in the current context. use rustc_infer::traits::{self, ObligationCause, PredicateObligations}; -use rustc_middle::traits::solve::Goal; +use rustc_middle::traits::solve::{Goal, GoalSource}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::solve::inspect::{ InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor, }; -use rustc_type_ir::solve::GoalSource; use tracing::{debug, instrument, trace}; use crate::FnCtxt; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 42236ac6d8087..e14f1528d2c4c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,7 +17,7 @@ use rustc_infer::infer; use rustc_infer::traits::Obligation; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; -use rustc_span::{self, DUMMY_SP, Ident, Span, sym}; +use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym}; use rustc_trait_selection::error_reporting::TypeErrCtxt; use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; @@ -308,15 +308,17 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { )) } - fn lower_assoc_ty( + fn lower_assoc_shared( &self, span: Span, item_def_id: DefId, - item_segment: &hir::PathSegment<'tcx>, + item_segment: &rustc_hir::PathSegment<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx> { + _kind: ty::AssocKind, + ) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> { let trait_ref = self.instantiate_binder_with_fresh_vars( span, + // FIXME(mgca): this should be assoc const if that is the `kind` infer::BoundRegionConversionTime::AssocTypeProjection(item_def_id), poly_trait_ref, ); @@ -328,7 +330,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { trait_ref.args, ); - Ty::new_projection_from_args(self.tcx(), item_def_id, item_args) + Ok((item_def_id, item_args)) } fn probe_adt(&self, span: Span, ty: Ty<'tcx>) -> Option> { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index f9fc121593637..f19e36206a7f5 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -23,7 +23,7 @@ use rustc_middle::ty::{ }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; -use rustc_span::{Ident, Span, Symbol, sym}; +use rustc_span::{ExpnKind, Ident, MacroKind, Span, Symbol, sym}; use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::DefIdOrName; use rustc_trait_selection::infer::InferCtxtExt; @@ -613,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .take(4) .map(|(var_hir_id, upvar)| { - let var_name = self.tcx.hir().name(*var_hir_id).to_string(); + let var_name = self.tcx.hir_name(*var_hir_id).to_string(); let msg = format!("`{var_name}` captured here"); (upvar.span, msg) }) @@ -1365,6 +1365,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.param_env, ty::TraitRef::new(self.tcx, into_def_id, [expr_ty, expected_ty]), )) + && !expr + .span + .macro_backtrace() + .any(|x| matches!(x.kind, ExpnKind::Macro(MacroKind::Attr | MacroKind::Derive, ..))) { let span = expr.span.find_oldest_ancestor_in_same_ctxt(); @@ -1380,10 +1384,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg.insert(0, (expr.span.shrink_to_lo(), format!("{}: ", name))); } diag.multipart_suggestion( - format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), - sugg, - Applicability::MaybeIncorrect - ); + format!("call `Into::into` on this expression to convert `{expr_ty}` into `{expected_ty}`"), + sugg, + Applicability::MaybeIncorrect + ); return true; } @@ -2979,7 +2983,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } - let Ok(src) = self.tcx.sess.source_map().span_to_snippet(expr.span) else { + let span = if let hir::ExprKind::Lit(lit) = &expr.kind { lit.span } else { expr.span }; + let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; }; @@ -3074,10 +3079,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Remove fractional part from literal, for example `42.0f32` into `42` let src = src.trim_end_matches(&checked_ty.to_string()); let len = src.split('.').next().unwrap().len(); - expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) + span.with_lo(span.lo() + BytePos(len as u32)) } else { let len = src.trim_end_matches(&checked_ty.to_string()).len(); - expr.span.with_lo(expr.span.lo() + BytePos(len as u32)) + span.with_lo(span.lo() + BytePos(len as u32)) }, if expr.precedence() < ExprPrecedence::Unambiguous { // Readd `)` diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 9d5184acb3ca7..4968998fd512b 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -1,6 +1,7 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(box_patterns)] #![feature(if_let_guard)] @@ -8,7 +9,6 @@ #![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod _match; @@ -133,7 +133,12 @@ fn typeck_with_inspect<'tcx>( } let mut fcx = FnCtxt::new(&root_ctxt, param_env, def_id); - if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { + if let hir::Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, .. }) = node { + // Check the fake body of a global ASM. There's not much to do here except + // for visit the asm expr of the body. + let ty = fcx.check_expr(body.value); + fcx.write_ty(id, ty); + } else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() { // In the case that we're recovering `fn() -> W<_>` or some other return // type that has an infer in it, lower the type directly so that it'll @@ -194,6 +199,15 @@ fn typeck_with_inspect<'tcx>( fcx.write_ty(id, expected_type); }; + // Whether to check repeat exprs before/after inference fallback is somewhat arbitrary of a decision + // as neither option is strictly more permissive than the other. However, we opt to check repeat exprs + // first as errors from not having inferred array lengths yet seem less confusing than errors from inference + // fallback arbitrarily inferring something incompatible with `Copy` inference side effects. + // + // This should also be forwards compatible with moving repeat expr checks to a custom goal kind or using + // marker traits in the future. + fcx.check_repeat_exprs(); + fcx.type_inference_fallback(); // Even though coercion casts provide type hints, we check casts after fallback for @@ -277,12 +291,9 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti Some(fcx.next_ty_var(span)) } Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. }) - | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => { + | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm { asm, .. }, span, .. }) => { asm.operands.iter().find_map(|(op, _op_sp)| match op { - hir::InlineAsmOperand::Const { anon_const } - | hir::InlineAsmOperand::SymFn { anon_const } - if anon_const.hir_id == id => - { + hir::InlineAsmOperand::Const { anon_const } if anon_const.hir_id == id => { Some(fcx.next_ty_var(span)) } _ => None, diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 8fb425ff0c94c..a614b4f00ffe4 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -11,13 +11,13 @@ use rustc_hir_analysis::hir_ty_lowering::{ }; use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk}; use rustc_lint::builtin::SUPERTRAIT_ITEM_SHADOWING_USAGE; -use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext}; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion, }; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, UserArgs, + self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, UserArgs, }; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Span}; @@ -136,7 +136,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { "confirm: self_ty={:?} method_sig_rcvr={:?} method_sig={:?} method_predicates={:?}", self_ty, method_sig_rcvr, method_sig, method_predicates ); - self.unify_receivers(self_ty, method_sig_rcvr, pick, all_args); + self.unify_receivers(self_ty, method_sig_rcvr, pick); let (method_sig, method_predicates) = self.normalize(self.span, (method_sig, method_predicates)); @@ -426,6 +426,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { fn provided_kind( &mut self, + preceding_args: &[ty::GenericArg<'tcx>], param: &ty::GenericParamDef, arg: &GenericArg<'tcx>, ) -> ty::GenericArg<'tcx> { @@ -446,7 +447,10 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { (GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => self .cfcx // We handle the ambig portions of `ConstArg` in the match arms below - .lower_const_arg(ct.as_unambig_ct(), FeedConstTy::Param(param.def_id)) + .lower_const_arg( + ct.as_unambig_ct(), + FeedConstTy::Param(param.def_id, preceding_args), + ) .into(), (GenericParamDefKind::Const { .. }, GenericArg::Infer(inf)) => { self.cfcx.ct_infer(Some(param), inf.span).into() @@ -525,20 +529,12 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>, pick: &probe::Pick<'tcx>, - args: GenericArgsRef<'tcx>, ) { debug!( "unify_receivers: self_ty={:?} method_self_ty={:?} span={:?} pick={:?}", self_ty, method_self_ty, self.span, pick ); - let cause = self.cause( - self.self_expr.span, - ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext { - assoc_item: pick.item, - param_env: self.param_env, - args, - })), - ); + let cause = self.cause(self.self_expr.span, ObligationCauseCode::Misc); match self.at(&cause, self.param_env).sup(DefineOpaqueTypes::Yes, method_self_ty, self_ty) { Ok(InferOk { obligations, value: () }) => { self.register_predicates(obligations); diff --git a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs index 69d7a6c97cb36..72f8793d78399 100644 --- a/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs +++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs @@ -363,7 +363,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let import_items: Vec<_> = applicable_trait .import_ids .iter() - .map(|&import_id| self.tcx.hir().expect_item(import_id)) + .map(|&import_id| self.tcx.hir_expect_item(import_id)) .collect(); // Find an identifier with which this trait was imported (note that `_` doesn't count). diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index b3e48fd5bb592..0a01ec89a327d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -14,6 +14,7 @@ use rustc_infer::infer::{self, DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::middle::stability; use rustc_middle::query::Providers; +use rustc_middle::ty::elaborate::supertrait_def_ids; use rustc_middle::ty::fast_reject::{TreatParams, simplify_type}; use rustc_middle::ty::{ self, AssocItem, AssocItemContainer, GenericArgs, GenericArgsRef, GenericParamDefKind, @@ -34,7 +35,6 @@ use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult, }; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCtxt}; -use rustc_type_ir::elaborate::supertrait_def_ids; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -873,7 +873,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { #[instrument(level = "debug", skip(self))] fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) { let principal = match self_ty.kind() { - ty::Dynamic(ref data, ..) => Some(data), + ty::Dynamic(data, ..) => Some(data), _ => None, } .and_then(|data| data.principal()) @@ -2344,7 +2344,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return false; }; let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id); - let attrs = self.fcx.tcx.hir().attrs(hir_id); + let attrs = self.fcx.tcx.hir_attrs(hir_id); for attr in attrs { if sym::doc == attr.name_or_empty() { } else if sym::rustc_confusables == attr.name_or_empty() { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index c757d089478f5..1a1540f505d37 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -9,7 +9,7 @@ use std::path::PathBuf; use hir::Expr; use rustc_ast::ast::Mutability; -use rustc_attr_parsing::parse_confusables; +use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; @@ -158,7 +158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results.borrow_mut().used_trait_imports.insert(import_id); } - let (span, sugg_span, source, item_name, args) = match self.tcx.hir_node(call_id) { + let (span, expr_span, source, item_name, args) = match self.tcx.hir_node(call_id) { hir::Node::Expr(&hir::Expr { kind: hir::ExprKind::MethodCall(segment, rcvr, args, _), span, @@ -194,6 +194,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { node => unreachable!("{node:?}"), }; + // Try to get the span of the identifier within the expression's syntax context + // (if that's different). + let within_macro_span = span.within_macro(expr_span, self.tcx.sess.source_map()); + // Avoid suggestions when we don't know what's going on. if let Err(guar) = rcvr_ty.error_reported() { return guar; @@ -207,10 +211,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { call_id, source, args, - sugg_span, + expr_span, &mut no_match_data, expected, trait_missing_method, + within_macro_span, ), MethodError::Ambiguity(mut sources) => { @@ -221,6 +226,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "multiple applicable items in scope" ); err.span_label(item_name.span, format!("multiple `{item_name}` found")); + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } self.note_candidates_on_method_error( rcvr_ty, @@ -230,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, &mut err, &mut sources, - Some(sugg_span), + Some(expr_span), ); err.emit() } @@ -252,6 +260,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .span_if_local(def_id) .unwrap_or_else(|| self.tcx.def_span(def_id)); err.span_label(sp, format!("private {kind} defined here")); + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } self.suggest_valid_traits(&mut err, item_name, out_of_scope_traits, true); err.emit() } @@ -268,6 +279,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if !needs_mut { err.span_label(bound_span, "this has a `Sized` requirement"); } + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } if !candidates.is_empty() { let help = format!( "{an}other candidate{s} {were} found in the following trait{s}", @@ -581,6 +595,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, trait_missing_method: bool, + within_macro_span: Option, ) -> ErrorGuaranteed { let mode = no_match_data.mode; let tcx = self.tcx; @@ -721,6 +736,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } + if let Some(within_macro_span) = within_macro_span { + err.span_label(within_macro_span, "due to this macro variable"); + } if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { ty_str = short_ty_str; @@ -773,7 +791,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Ok(pick) = self.lookup_probe_for_diagnostic( item_name, Ty::new_ref(tcx, ty::Region::new_error_misc(tcx), ty, ptr_mutbl), - self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)), + self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)), ProbeScope::TraitsInScope, None, ) @@ -816,8 +834,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let SelfSource::MethodCall(rcvr_expr) = source { self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| { - let call_expr = - self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)); + let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id)); let probe = self.lookup_probe_for_diagnostic( item_name, output_ty, @@ -905,11 +922,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else if self.impl_into_iterator_should_be_iterator(rcvr_ty, span, unsatisfied_predicates) { err.span_label(span, format!("`{rcvr_ty}` is not an iterator")); - err.multipart_suggestion_verbose( - "call `.into_iter()` first", - vec![(span.shrink_to_lo(), format!("into_iter()."))], - Applicability::MaybeIncorrect, - ); + if !span.in_external_macro(self.tcx.sess.source_map()) { + err.multipart_suggestion_verbose( + "call `.into_iter()` first", + vec![(span.shrink_to_lo(), format!("into_iter()."))], + Applicability::MaybeIncorrect, + ); + } return err.emit(); } else if !unsatisfied_predicates.is_empty() && matches!(rcvr_ty.kind(), ty::Param(_)) { // We special case the situation where we are looking for `_` in @@ -1586,10 +1605,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let SelfSource::QPath(ty) = source && let hir::Node::Expr(ref path_expr) = self.tcx.parent_hir_node(ty.hir_id) && let hir::ExprKind::Path(_) = path_expr.kind - && let hir::Node::Stmt(hir::Stmt { - kind: hir::StmtKind::Semi(ref parent), .. - }) - | hir::Node::Expr(ref parent) = self.tcx.parent_hir_node(path_expr.hir_id) + && let hir::Node::Stmt(&hir::Stmt { kind: hir::StmtKind::Semi(parent), .. }) + | hir::Node::Expr(parent) = self.tcx.parent_hir_node(path_expr.hir_id) { let replacement_span = if let hir::ExprKind::Call(..) | hir::ExprKind::Struct(..) = parent.kind { @@ -1884,9 +1901,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for inherent_method in self.tcx.associated_items(inherent_impl_did).in_definition_order() { - if let Some(attr) = - self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables) - && let Some(candidates) = parse_confusables(attr) + if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols) && candidates.contains(&item_name.name) && let ty::AssocKind::Fn = inherent_method.kind { @@ -2357,7 +2372,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } else { - let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id)); + let call_expr = tcx.hir_expect_expr(tcx.parent_hir_id(expr.hir_id)); if let Some(span) = call_expr.span.trim_start(item_name.span) { err.span_suggestion( @@ -2664,7 +2679,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mod_id, expr.hir_id, ) { - let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)); + let call_expr = self.tcx.hir_expect_expr(self.tcx.parent_hir_id(expr.hir_id)); let lang_items = self.tcx.lang_items(); let never_mention_traits = [ @@ -2741,7 +2756,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let SelfSource::MethodCall(expr) = source else { return; }; - let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id)); + let call_expr = tcx.hir_expect_expr(tcx.parent_hir_id(expr.hir_id)); let ty::Adt(kind, args) = actual.kind() else { return; @@ -3149,8 +3164,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut derives_grouped = Vec::<(String, Span, String)>::new(); for (self_name, self_span, trait_name) in derives.into_iter() { - if let Some((last_self_name, _, ref mut last_trait_names)) = derives_grouped.last_mut() - { + if let Some((last_self_name, _, last_trait_names)) = derives_grouped.last_mut() { if last_self_name == &self_name { last_trait_names.push_str(format!(", {trait_name}").as_str()); continue; diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index 1750c2af1c7ff..a473e14b24445 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -15,7 +15,6 @@ use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span, sym}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{FulfillmentError, Obligation, ObligationCtxt}; -use rustc_type_ir::TyKind::*; use tracing::debug; use {rustc_ast as ast, rustc_hir as hir}; @@ -519,7 +518,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { suggest_deref_binop(&mut err, lhs_deref_ty); } else if is_assign == IsAssign::No - && let Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind() + && let ty::Ref(region, lhs_deref_ty, mutbl) = lhs_ty.kind() { if self.type_is_copy_modulo_regions(self.param_env, *lhs_deref_ty) { suggest_deref_binop(&mut err, *lhs_deref_ty); @@ -536,7 +535,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, ); - if let Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() { + if let ty::Ref(region, rhs_deref_ty, mutbl) = rhs_ty.kind() { let rhs_inv_mutbl = mutbl.invert(); let rhs_inv_mutbl_ty = Ty::new_ref(self.tcx, *region, *rhs_deref_ty, rhs_inv_mutbl); @@ -726,12 +725,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |ty: Ty<'tcx>| ty.ty_adt_def().is_some_and(|ty_def| Some(ty_def.did()) == string_type); match (lhs_ty.kind(), rhs_ty.kind()) { - (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str - if (*l_ty.kind() == Str || is_std_string(l_ty)) - && (*r_ty.kind() == Str + (&ty::Ref(_, l_ty, _), &ty::Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str + if (*l_ty.kind() == ty::Str || is_std_string(l_ty)) + && (*r_ty.kind() == ty::Str || is_std_string(r_ty) || matches!( - r_ty.kind(), Ref(_, inner_ty, _) if *inner_ty.kind() == Str + r_ty.kind(), ty::Ref(_, inner_ty, _) if *inner_ty.kind() == ty::Str )) => { if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str` @@ -755,8 +754,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } true } - (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` - if (*l_ty.kind() == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => + (&ty::Ref(_, l_ty, _), &ty::Adt(..)) // Handle `&str` & `&String` + `String` + if (*l_ty.kind() == ty::Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => { err.span_label( op.span, @@ -847,7 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } else { match actual.kind() { - Uint(_) if op == hir::UnOp::Neg => { + ty::Uint(_) if op == hir::UnOp::Neg => { err.note("unsigned values cannot be negated"); if let hir::ExprKind::Unary( @@ -881,8 +880,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - Str | Never | Char | Tuple(_) | Array(_, _) => {} - Ref(_, lty, _) if *lty.kind() == Str => {} + ty::Str | ty::Never | ty::Char | ty::Tuple(_) | ty::Array(_, _) => {} + ty::Ref(_, lty, _) if *lty.kind() == ty::Str => {} _ => { self.note_unmet_impls_on_type(&mut err, errors, true); } diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index c56396c38c956..3d1c61a9c344f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -87,10 +87,10 @@ struct TopInfo<'tcx> { } #[derive(Copy, Clone)] -struct PatInfo<'a, 'tcx> { +struct PatInfo<'tcx> { binding_mode: ByRef, max_ref_mutbl: MutblCap, - top_info: &'a TopInfo<'tcx>, + top_info: TopInfo<'tcx>, decl_origin: Option>, /// The depth of current pattern @@ -303,11 +303,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { origin_expr: Option<&'tcx hir::Expr<'tcx>>, decl_origin: Option>, ) { - let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id }; + let top_info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id }; let pat_info = PatInfo { binding_mode: ByRef::No, max_ref_mutbl: MutblCap::Mut, - top_info: &info, + top_info, decl_origin, current_depth: 0, }; @@ -320,11 +320,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Outside of this module, `check_pat_top` should always be used. /// Conversely, inside this module, `check_pat_top` should never be used. #[instrument(level = "debug", skip(self, pat_info))] - fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) { + fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) { let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info; let path_res = match pat.kind { - PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => { + PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => { Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span)) } _ => None, @@ -344,7 +344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PatKind::Wild | PatKind::Err(_) => expected, // We allow any type here; we ensure that the type is uninhabited during match checking. PatKind::Never => expected, - PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => { + PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => { let ty = self.check_pat_path( *hir_id, pat.hir_id, @@ -352,13 +352,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { qpath, path_res.unwrap(), expected, - ti, + &pat_info.top_info, ); self.write_ty(*hir_id, ty); ty } - PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti), - PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti), + PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, &pat_info.top_info), + PatKind::Range(lhs, rhs, _) => { + self.check_pat_range(pat.span, lhs, rhs, expected, &pat_info.top_info) + } PatKind::Binding(ba, var_id, ident, sub) => { self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info) } @@ -818,7 +820,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ident: Ident, sub: Option<&'tcx Pat<'tcx>>, expected: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info; @@ -914,12 +916,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // We have a concrete type for the local, so we do not need to taint it and hide follow up errors *using* the local. - let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti); + let _ = self.demand_eqtype_pat(pat.span, eq_ty, local_ty, &ti); // If there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be. if var_id != pat.hir_id { - self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, ti); + self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, &ti); } if let Some(p) = sub { @@ -1149,7 +1151,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, expected: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { // Resolve the path and check the definition for errors. let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) { @@ -1164,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // Type-check the path. - let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, pat_info.top_info); + let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info); // Type-check subpatterns. match self.check_struct_pat_fields(pat_ty, pat, variant, fields, has_rest_pat, pat_info) { @@ -1353,7 +1355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { subpats: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let on_error = |e| { @@ -1403,7 +1405,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let pat_ty = pat_ty.no_bound_vars().expect("expected fn type"); // Type-check the tuple struct pattern against the expected type. - let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, pat_info.top_info); + let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info); let had_err = diag.map_err(|diag| diag.emit()); // Type-check subpatterns. @@ -1420,7 +1422,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.check_stability( variant.fields[FieldIdx::from_usize(i)].did, - Some(pat.hir_id), + Some(subpat.hir_id), subpat.span, None, ); @@ -1610,7 +1612,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { elements: &'tcx [Pat<'tcx>], ddpos: hir::DotDotPos, expected: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let mut expected_len = elements.len(); @@ -1625,7 +1627,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span)); let element_tys = tcx.mk_type_list_from_iter(element_tys_iter); let pat_ty = Ty::new_tup(tcx, element_tys); - if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, pat_info.top_info) { + if let Err(reported) = self.demand_eqtype_pat(span, expected, pat_ty, &pat_info.top_info) { // Walk subpatterns with an expected type of `err` in this case to silence // further errors being emitted when using the bindings. #50333 let element_tys_iter = (0..max_len).map(|_| Ty::new_error(tcx, reported)); @@ -1648,7 +1650,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { variant: &'tcx ty::VariantDef, fields: &'tcx [hir::PatField<'tcx>], has_rest_pat: bool, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx; @@ -1684,7 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .get(&ident) .map(|(i, f)| { self.write_field_index(field.hir_id, *i); - self.tcx.check_stability(f.did, Some(pat.hir_id), span, None); + self.tcx.check_stability(f.did, Some(field.hir_id), span, None); self.field_ty(span, f, args) }) .unwrap_or_else(|| { @@ -2257,7 +2259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; let (box_ty, inner_ty) = self @@ -2267,7 +2269,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // think any errors can be introduced by using `demand::eqtype`. let inner_ty = self.next_ty_var(inner.span); let box_ty = Ty::new_box(tcx, inner_ty); - self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info)?; + self.demand_eqtype_pat(span, expected, box_ty, &pat_info.top_info)?; Ok((box_ty, inner_ty)) }) .unwrap_or_else(|guar| { @@ -2283,7 +2285,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, inner: &'tcx Pat<'tcx>, expected: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; // Register a `DerefPure` bound, which is required by all `deref!()` pats. @@ -2324,7 +2326,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { inner: &'tcx Pat<'tcx>, pat_mutbl: Mutability, mut expected: Ty<'tcx>, - mut pat_info: PatInfo<'_, 'tcx>, + mut pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -2482,7 +2484,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pat.span, expected, ref_ty, - pat_info.top_info, + &pat_info.top_info, ); // Look for a case like `fn foo(&foo: u32)` and suggest @@ -2605,7 +2607,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { slice: Option<&'tcx Pat<'tcx>>, after: &'tcx [Pat<'tcx>], expected: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> Ty<'tcx> { let expected = self.try_structurally_resolve_type(span, expected); @@ -2767,20 +2769,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, span: Span, expected_ty: Ty<'tcx>, - pat_info: PatInfo<'_, 'tcx>, + pat_info: PatInfo<'tcx>, ) -> ErrorGuaranteed { let PatInfo { top_info: ti, current_depth, .. } = pat_info; - let mut err = struct_span_code_err!( - self.dcx(), - span, - E0529, - "expected an array or slice, found `{expected_ty}`" - ); + let mut slice_pat_semantics = false; + let mut as_deref = None; + let mut slicing = None; if let ty::Ref(_, ty, _) = expected_ty.kind() && let ty::Array(..) | ty::Slice(..) = ty.kind() { - err.help("the semantics of slice patterns changed recently; see issue #62254"); + slice_pat_semantics = true; } else if self .autoderef(span, expected_ty) .silence_errors() @@ -2797,28 +2796,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.tcx.is_diagnostic_item(sym::Result, adt_def.did()) => { // Slicing won't work here, but `.as_deref()` might (issue #91328). - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider using `as_deref` here", - ".as_deref()", - Applicability::MaybeIncorrect, - ); + as_deref = Some(errors::AsDerefSuggestion { span: span.shrink_to_hi() }); } _ => (), } let is_top_level = current_depth <= 1; if is_slice_or_array_or_vector && is_top_level { - err.span_suggestion_verbose( - span.shrink_to_hi(), - "consider slicing here", - "[..]", - Applicability::MachineApplicable, - ); + slicing = Some(errors::SlicingSuggestion { span: span.shrink_to_hi() }); } } - err.span_label(span, format!("pattern cannot match with input type `{expected_ty}`")); - err.emit() + self.dcx().emit_err(errors::ExpectedArrayOrSlice { + span, + ty: expected_ty, + slice_pat_semantics, + as_deref, + slicing, + }) } fn is_slice_or_array_or_vector(&self, ty: Ty<'tcx>) -> (bool, Ty<'tcx>) { diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index 903be7e732afa..88f4f7caa95d8 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -7,8 +7,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::{HirId, HirIdMap}; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use rustc_middle::span_bug; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode}; use rustc_span::Span; use rustc_span::def_id::LocalDefIdMap; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; @@ -62,6 +61,9 @@ pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) deferred_coroutine_interiors: RefCell)>>, + pub(super) deferred_repeat_expr_checks: + RefCell, Ty<'tcx>, ty::Const<'tcx>)>>, + /// Whenever we introduce an adjustment from `!` into a type variable, /// we record that type variable here. This is later used to inform /// fallback. See the `fallback` module for details. @@ -96,6 +98,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { deferred_transmute_checks: RefCell::new(Vec::new()), deferred_asm_checks: RefCell::new(Vec::new()), deferred_coroutine_interiors: RefCell::new(Vec::new()), + deferred_repeat_expr_checks: RefCell::new(Vec::new()), diverging_type_vars: RefCell::new(Default::default()), infer_var_info: RefCell::new(Default::default()), } diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 9a0b22470585f..37f3786c00abc 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -671,6 +671,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (place, capture_kind) = match capture_clause { hir::CaptureBy::Value { .. } => adjust_for_move_closure(place, capture_kind), + hir::CaptureBy::Use { .. } => adjust_for_use_closure(place, capture_kind), hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind), }; @@ -780,7 +781,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id, base => bug!("Expected upvar, found={:?}", base), }; - let var_ident = self.tcx.hir().ident(var_hir_id); + let var_ident = self.tcx.hir_ident(var_hir_id); let Some(min_cap_list) = root_var_min_capture_list.get_mut(&var_hir_id) else { let mutability = self.determine_capture_mutability(&typeck_results, &place); @@ -987,13 +988,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { let cause_span = self.tcx.hir().span(*capture_expr_id); lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", - self.tcx.hir().name(*var_hir_id), + self.tcx.hir_name(*var_hir_id), captured_name, )); } UpvarMigrationInfo::CapturingNothing { use_span } => { lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", - self.tcx.hir().name(*var_hir_id), + self.tcx.hir_name(*var_hir_id), )); } @@ -1008,13 +1009,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &lint_note.captures_info { UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", - self.tcx.hir().name(*var_hir_id), + self.tcx.hir_name(*var_hir_id), captured_name, )); } UpvarMigrationInfo::CapturingNothing { use_span: _ } => { lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", - v = self.tcx.hir().name(*var_hir_id), + v = self.tcx.hir_name(*var_hir_id), )); } } @@ -1025,7 +1026,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // not capturing something anymore cannot cause a trait to fail to be implemented: match &lint_note.captures_info { UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { - let var_name = self.tcx.hir().name(*var_hir_id); + let var_name = self.tcx.hir_name(*var_hir_id); lint.span_label(closure_head_span, format!("\ in Rust 2018, this closure implements {missing_trait} \ as `{var_name}` implements {missing_trait}, but in Rust 2021, \ @@ -1165,7 +1166,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = match closure_clause { hir::CaptureBy::Value { .. } => ty, // For move closure the capture kind should be by value - hir::CaptureBy::Ref => { + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => { // For non move closure the capture kind is the max capture kind of all captures // according to the ordering ImmBorrow < UniqueImmBorrow < MutBorrow < ByValue let mut max_capture_info = root_var_min_capture_list.first().unwrap().info; @@ -1292,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(UpvarMigrationInfo::CapturingNothing { use_span: upvar.span }); return Some(diagnostics_info); } - hir::CaptureBy::Ref => {} + hir::CaptureBy::Ref | hir::CaptureBy::Use { .. } => {} } return None; @@ -1305,7 +1306,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for captured_place in root_var_min_capture_list.iter() { match captured_place.info.capture_kind { // Only care about captures that are moved into the closure - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { projections_list.push(captured_place.place.projections.as_slice()); diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise { source_expr: captured_place.info.path_expr_id, @@ -1689,10 +1690,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // If the data will be moved out of this place, then the place will be truncated // at the first Deref in `adjust_for_move_closure` and then moved into the closure. + // + // For example: + // + // struct Buffer<'a> { + // x: &'a String, + // y: Vec, + // } + // + // fn get<'a>(b: Buffer<'a>) -> impl Sized + 'a { + // let c = move || b.x; + // drop(b); + // c + // } + // + // Even though the closure is declared as move, when we are capturing borrowed data (in + // this case, *b.x) we prefer to capture by reference. + // Otherwise you'd get an error in 2021 immediately because you'd be trying to take + // ownership of the (borrowed) String or else you'd take ownership of b, as in 2018 and + // before, which is also an error. hir::CaptureBy::Value { .. } if !place.deref_tys().any(Ty::is_ref) => { ty::UpvarCapture::ByValue } - hir::CaptureBy::Value { .. } | hir::CaptureBy::Ref => { + hir::CaptureBy::Use { .. } if !place.deref_tys().any(Ty::is_ref) => { + ty::UpvarCapture::ByUse + } + hir::CaptureBy::Value { .. } | hir::CaptureBy::Use { .. } | hir::CaptureBy::Ref => { ty::UpvarCapture::ByRef(BorrowKind::Immutable) } } @@ -1927,7 +1950,7 @@ fn apply_capture_kind_on_capture_ty<'tcx>( region: ty::Region<'tcx>, ) -> Ty<'tcx> { match capture_kind { - ty::UpvarCapture::ByValue => ty, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => ty, ty::UpvarCapture::ByRef(kind) => Ty::new_ref(tcx, region, ty, kind.to_mutbl_lossy()), } } @@ -2023,6 +2046,21 @@ impl<'tcx> euv::Delegate<'tcx> for InferBorrowKind<'tcx> { )); } + #[instrument(skip(self), level = "debug")] + fn use_cloned(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { + let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return }; + assert_eq!(self.closure_def_id, upvar_id.closure_expr_id); + + self.capture_information.push(( + place_with_id.place.clone(), + ty::CaptureInfo { + capture_kind_expr_id: Some(diag_expr_id), + path_expr_id: Some(diag_expr_id), + capture_kind: ty::UpvarCapture::ByUse, + }, + )); + } + #[instrument(skip(self), level = "debug")] fn borrow( &mut self, @@ -2164,6 +2202,20 @@ fn adjust_for_move_closure( (place, ty::UpvarCapture::ByValue) } +/// Truncate deref of any reference. +fn adjust_for_use_closure( + mut place: Place<'_>, + mut kind: ty::UpvarCapture, +) -> (Place<'_>, ty::UpvarCapture) { + let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); + + if let Some(idx) = first_deref { + truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); + } + + (place, ty::UpvarCapture::ByUse) +} + /// Adjust closure capture just that if taking ownership of data, only move data /// from enclosing stack frame. fn adjust_for_non_move_closure( @@ -2174,7 +2226,7 @@ fn adjust_for_non_move_closure( place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref); match kind { - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => { if let Some(idx) = contains_deref { truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx); } @@ -2219,6 +2271,7 @@ fn construct_capture_kind_reason_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), + ty::UpvarCapture::ByUse => "ByUse".into(), ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; @@ -2240,13 +2293,14 @@ fn construct_capture_info_string<'tcx>( let capture_kind_str = match capture_info.capture_kind { ty::UpvarCapture::ByValue => "ByValue".into(), + ty::UpvarCapture::ByUse => "ByUse".into(), ty::UpvarCapture::ByRef(kind) => format!("{kind:?}"), }; format!("{place_str} -> {capture_kind_str}") } fn var_name(tcx: TyCtxt<'_>, var_hir_id: HirId) -> Symbol { - tcx.hir().name(var_hir_id) + tcx.hir_name(var_hir_id) } #[instrument(level = "debug", skip(tcx))] @@ -2335,8 +2389,11 @@ fn determine_capture_info( // expressions. let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) { (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true, + (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) => true, (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b, - (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false, + (ty::UpvarCapture::ByValue, _) + | (ty::UpvarCapture::ByUse, _) + | (ty::UpvarCapture::ByRef(_), _) => false, }; if eq_capture_kind { @@ -2346,10 +2403,20 @@ fn determine_capture_info( } } else { // We select the CaptureKind which ranks higher based the following priority order: - // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow + // (ByUse | ByValue) > MutBorrow > UniqueImmBorrow > ImmBorrow match (capture_info_a.capture_kind, capture_info_b.capture_kind) { - (ty::UpvarCapture::ByValue, _) => capture_info_a, - (_, ty::UpvarCapture::ByValue) => capture_info_b, + (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByValue) + | (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByUse) => { + bug!("Same capture can't be ByUse and ByValue at the same time") + } + (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) + | (ty::UpvarCapture::ByUse, ty::UpvarCapture::ByUse) + | (ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse, ty::UpvarCapture::ByRef(_)) => { + capture_info_a + } + (ty::UpvarCapture::ByRef(_), ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse) => { + capture_info_b + } (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => { match (ref_a, ref_b) { // Take LHS: @@ -2401,7 +2468,7 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>( } ty::UpvarCapture::ByRef(..) => {} - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} } place.projections.truncate(len); diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 8c50cc59c1d5e..6a3417ae5d6fb 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -11,9 +11,9 @@ use rustc_hir::{self as hir, AmbigArg, HirId}; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, fold_regions}; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperFoldable}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, fold_regions, +}; use rustc_span::{Span, sym}; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::solve; @@ -48,13 +48,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for param in body.params { wbcx.visit_node_id(param.pat.span, param.hir_id); } - // Type only exists for constants and statics, not functions. match self.tcx.hir_body_owner_kind(item_def_id) { - hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => { + // Visit the type of a const or static, which is used during THIR building. + hir::BodyOwnerKind::Const { .. } + | hir::BodyOwnerKind::Static(_) + | hir::BodyOwnerKind::GlobalAsm => { let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id); wbcx.visit_node_id(body.value.span, item_hir_id); } - hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), + // For closures and consts, we already plan to visit liberated signatures. + hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => {} } wbcx.visit_body(body); wbcx.visit_min_capture_map(); @@ -245,13 +248,6 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } } - - fn visit_const_block(&mut self, span: Span, anon_const: &hir::ConstBlock) { - self.visit_node_id(span, anon_const.hir_id); - - let body = self.tcx().hir_body(anon_const.body); - self.visit_body(body); - } } /////////////////////////////////////////////////////////////////////////// @@ -281,9 +277,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => { self.visit_field_id(e.hir_id); } - hir::ExprKind::ConstBlock(ref anon_const) => { - self.visit_const_block(e.span, anon_const); - } _ => {} } @@ -294,6 +287,14 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { self.fix_index_builtin_expr(e); } + fn visit_inline_const(&mut self, anon_const: &hir::ConstBlock) { + let span = self.tcx().def_span(anon_const.def_id); + self.visit_node_id(span, anon_const.hir_id); + + let body = self.tcx().hir_body(anon_const.body); + self.visit_body(body); + } + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { match &p.kind { hir::GenericParamKind::Lifetime { .. } => { @@ -316,11 +317,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { match p.kind { hir::PatKind::Binding(..) => { let typeck_results = self.fcx.typeck_results.borrow(); - if let Some(bm) = - typeck_results.extract_binding_mode(self.tcx().sess, p.hir_id, p.span) - { - self.typeck_results.pat_binding_modes_mut().insert(p.hir_id, bm); - } + let bm = typeck_results.extract_binding_mode(self.tcx().sess, p.hir_id, p.span); + self.typeck_results.pat_binding_modes_mut().insert(p.hir_id, bm); } hir::PatKind::Struct(_, fields, _) => { for field in fields { @@ -340,9 +338,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> { fn visit_pat_expr(&mut self, expr: &'tcx hir::PatExpr<'tcx>) { self.visit_node_id(expr.span, expr.hir_id); - if let hir::PatExprKind::ConstBlock(c) = &expr.kind { - self.visit_const_block(expr.span, c); - } intravisit::walk_pat_expr(self, expr); } diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 46a63b02e8469..db0a584188755 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -1,17 +1,18 @@ [package] name = "rustc_incremental" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start -rand = "0.8.4" +rand = "0.9.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_graphviz = { path = "../rustc_graphviz" } +rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index d4407559202f0..1b2056f541f3e 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -123,7 +123,7 @@ impl<'tcx> IfThisChanged<'tcx> { fn process_attrs(&mut self, def_id: LocalDefId) { let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id()); let hir_id = self.tcx.local_def_id_to_hir_id(def_id); - let attrs = self.tcx.hir().attrs(hir_id); + let attrs = self.tcx.hir_attrs(hir_id); for attr in attrs { if attr.has_name(sym::rustc_if_this_changed) { let dep_node_interned = self.argument(attr); @@ -137,13 +137,13 @@ impl<'tcx> IfThisChanged<'tcx> { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { - span: attr.span, + span: attr.span(), name: n, }), } } }; - self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node)); + self.if_this_changed.push((attr.span(), def_id.to_def_id(), dep_node)); } else if attr.has_name(sym::rustc_then_this_would_need) { let dep_node_interned = self.argument(attr); let dep_node = match dep_node_interned { @@ -151,17 +151,17 @@ impl<'tcx> IfThisChanged<'tcx> { match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) { Ok(n) => n, Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode { - span: attr.span, + span: attr.span(), name: n, }), } } None => { - self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span }); + self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span() }); } }; self.then_this_would_need.push(( - attr.span, + attr.span(), dep_node_interned.unwrap(), hir_id, dep_node, diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 563ed7614c609..dabfb6a90cade 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -2,12 +2,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![deny(missing_docs)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(file_buffered)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod assert_dep_graph; diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index 118a6fed036ed..d40a0d514f6f9 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -199,7 +199,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let loaded_from_disk = self.loaded_from_disk(attr); for e in except.items().into_sorted_stable_ord() { if !auto.remove(e) { - self.tcx.dcx().emit_fatal(errors::AssertionAuto { span: attr.span, name, e }); + self.tcx.dcx().emit_fatal(errors::AssertionAuto { span: attr.span(), name, e }); } } Assertion { clean: auto, dirty: except, loaded_from_disk } @@ -261,7 +261,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { HirItem::ForeignMod { .. } => ("ItemForeignMod", LABELS_HIR_ONLY), // Module-level inline assembly (from global_asm!) - HirItem::GlobalAsm(..) => ("ItemGlobalAsm", LABELS_HIR_ONLY), + HirItem::GlobalAsm { .. } => ("ItemGlobalAsm", LABELS_HIR_ONLY), // A type alias, e.g., `type Foo = Bar` HirItem::TyAlias(..) => ("ItemTy", LABELS_HIR_ONLY), @@ -282,7 +282,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL), _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirtyItem { - span: attr.span, + span: attr.span(), kind: format!("{:?}", item.kind), }), } @@ -298,7 +298,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL), }, _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirty { - span: attr.span, + span: attr.span(), kind: format!("{node:?}"), }), }; @@ -375,7 +375,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> { let Some(assertion) = self.assertion_maybe(item_id, attr) else { continue; }; - self.checked_attrs.insert(attr.id); + self.checked_attrs.insert(attr.id()); for label in assertion.clean.items().into_sorted_stable_ord() { let dep_node = DepNode::from_label_string(self.tcx, label, def_path_hash).unwrap(); self.assert_clean(item_span, dep_node); @@ -405,12 +405,13 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) { - tcx.dcx().emit_err(errors::UnknownItem { span: attr.span, name: item.name_or_empty() }); + tcx.dcx() + .emit_err(errors::UnknownItem { span: attr.span(), name: item.name_or_empty() }); } } match cfg { - None => tcx.dcx().emit_fatal(errors::NoCfg { span: attr.span }), + None => tcx.dcx().emit_fatal(errors::NoCfg { span: attr.span() }), Some(c) => c, } } @@ -444,9 +445,9 @@ impl<'tcx> FindAllAttrs<'tcx> { fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet) { for attr in &self.found_attrs { - if !checked_attrs.contains(&attr.id) { - self.tcx.dcx().emit_err(errors::UncheckedClean { span: attr.span }); - checked_attrs.insert(attr.id); + if !checked_attrs.contains(&attr.id()) { + self.tcx.dcx().emit_err(errors::UncheckedClean { span: attr.span() }); + checked_attrs.insert(attr.id()); } } } diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 4c664ea6ba0f4..9cec2702a4171 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -123,7 +123,7 @@ pub(crate) fn read_file( // Check HEADER_FORMAT_VERSION { - debug_assert!(::std::mem::size_of_val(&HEADER_FORMAT_VERSION) == 2); + debug_assert!(size_of_val(&HEADER_FORMAT_VERSION) == 2); let mut header_format_version = [0u8; 2]; file.read_exact(&mut header_format_version)?; let header_format_version = diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 19cca48af6127..76a1ff3cf3828 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -108,7 +108,7 @@ use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use rand::{RngCore, thread_rng}; +use rand::{RngCore, rng}; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_data_structures::svh::Svh; @@ -445,7 +445,7 @@ fn copy_files(sess: &Session, target_dir: &Path, source_dir: &Path) -> Result PathBuf { let timestamp = timestamp_to_string(SystemTime::now()); debug!("generate_session_dir_path: timestamp = {}", timestamp); - let random_number = thread_rng().next_u32(); + let random_number = rng().next_u32(); debug!("generate_session_dir_path: random_number = {}", random_number); // Chop the first 3 characters off the timestamp. Those 3 bytes will be zero for a while. diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 7977bcc68911d..50e47533ab6ca 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -5,6 +5,7 @@ use std::sync::Arc; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::unord::UnordMap; +use rustc_hashes::Hash64; use rustc_middle::dep_graph::{DepGraph, DepsType, SerializedDepGraph, WorkProductMap}; use rustc_middle::query::on_disk_cache::OnDiskCache; use rustc_serialize::Decodable; @@ -154,7 +155,7 @@ fn load_dep_graph(sess: &Session) -> LoadResult<(Arc, WorkPr sess.dcx().emit_warn(errors::CorruptFile { path: &path }); return LoadResult::DataOutOfDate; }; - let prev_commandline_args_hash = u64::decode(&mut decoder); + let prev_commandline_args_hash = Hash64::decode(&mut decoder); if prev_commandline_args_hash != expected_hash { if sess.opts.unstable_opts.incremental_info { diff --git a/compiler/rustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml index f27db7a5400ad..3d83a3c98daf8 100644 --- a/compiler/rustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_index" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index f12df831cb503..07934389158e5 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -1,11 +1,13 @@ use std::marker::PhantomData; +#[cfg(not(feature = "nightly"))] +use std::mem; use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds, Shl}; use std::rc::Rc; -use std::{fmt, iter, mem, slice}; +use std::{fmt, iter, slice}; use Chunk::*; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; use smallvec::{SmallVec, smallvec}; use crate::{Idx, IndexVec}; @@ -14,7 +16,7 @@ use crate::{Idx, IndexVec}; mod tests; type Word = u64; -const WORD_BYTES: usize = mem::size_of::(); +const WORD_BYTES: usize = size_of::(); const WORD_BITS: usize = WORD_BYTES * 8; // The choice of chunk size has some trade-offs. @@ -112,7 +114,7 @@ macro_rules! bit_relations_inherent_impls { /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. /// -#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] +#[cfg_attr(feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext))] #[derive(Eq, PartialEq, Hash)] pub struct DenseBitSet { domain_size: usize, @@ -723,7 +725,7 @@ impl ChunkedBitSet { match self.chunks.get(chunk_index) { Some(Zeros(_chunk_domain_size)) => ChunkIter::Zeros, Some(Ones(chunk_domain_size)) => ChunkIter::Ones(0..*chunk_domain_size as usize), - Some(Mixed(chunk_domain_size, _, ref words)) => { + Some(Mixed(chunk_domain_size, _, words)) => { let num_words = num_words(*chunk_domain_size as usize); ChunkIter::Mixed(BitIter::new(&words[0..num_words])) } @@ -752,11 +754,7 @@ impl BitRelations> for ChunkedBitSet { changed = true; } ( - Mixed( - self_chunk_domain_size, - ref mut self_chunk_count, - ref mut self_chunk_words, - ), + Mixed(self_chunk_domain_size, self_chunk_count, self_chunk_words), Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), ) => { // First check if the operation would change @@ -836,11 +834,7 @@ impl BitRelations> for ChunkedBitSet { Mixed(*self_chunk_domain_size, self_chunk_count, Rc::new(self_chunk_words)); } ( - Mixed( - self_chunk_domain_size, - ref mut self_chunk_count, - ref mut self_chunk_words, - ), + Mixed(self_chunk_domain_size, self_chunk_count, self_chunk_words), Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), ) => { // See [`>>::union`] for the explanation @@ -891,11 +885,7 @@ impl BitRelations> for ChunkedBitSet { *self_chunk = other_chunk.clone(); } ( - Mixed( - self_chunk_domain_size, - ref mut self_chunk_count, - ref mut self_chunk_words, - ), + Mixed(self_chunk_domain_size, self_chunk_count, self_chunk_words), Mixed(_other_chunk_domain_size, _other_chunk_count, other_chunk_words), ) => { // See [`>>::union`] for the explanation @@ -1402,7 +1392,7 @@ impl From> for GrowableBitSet { /// /// All operations that involve a row and/or column index will panic if the /// index exceeds the relevant bound. -#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] +#[cfg_attr(feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext))] #[derive(Clone, Eq, PartialEq, Hash)] pub struct BitMatrix { num_rows: usize, @@ -1678,7 +1668,7 @@ impl SparseBitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter(&self, row: R) -> impl Iterator + '_ { + pub fn iter(&self, row: R) -> impl Iterator { self.row(row).into_iter().flat_map(|r| r.iter()) } @@ -1826,7 +1816,7 @@ impl std::fmt::Debug for FiniteBitSet { /// A fixed-sized bitset type represented by an integer type. Indices outwith than the range /// representable by `T` are considered set. -#[cfg_attr(feature = "nightly", derive(Decodable_Generic, Encodable_Generic))] +#[cfg_attr(feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext))] #[derive(Copy, Clone, Eq, PartialEq)] pub struct FiniteBitSet(pub T); diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs index b85160540d872..33f406e21137d 100644 --- a/compiler/rustc_index/src/idx.rs +++ b/compiler/rustc_index/src/idx.rs @@ -1,5 +1,7 @@ use std::fmt::Debug; use std::hash::Hash; +use std::ops; +use std::slice::SliceIndex; /// Represents some newtyped `usize` wrapper. /// @@ -43,3 +45,92 @@ impl Idx for u32 { self as usize } } + +/// Helper trait for indexing operations with a custom index type. +pub trait IntoSliceIdx { + type Output: SliceIndex; + fn into_slice_idx(self) -> Self::Output; +} + +impl IntoSliceIdx for I { + type Output = usize; + #[inline] + fn into_slice_idx(self) -> Self::Output { + self.index() + } +} + +impl IntoSliceIdx for ops::RangeFull { + type Output = ops::RangeFull; + #[inline] + fn into_slice_idx(self) -> Self::Output { + self + } +} + +impl IntoSliceIdx for ops::Range { + type Output = ops::Range; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ops::Range { start: self.start.index(), end: self.end.index() } + } +} + +impl IntoSliceIdx for ops::RangeFrom { + type Output = ops::RangeFrom; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ops::RangeFrom { start: self.start.index() } + } +} + +impl IntoSliceIdx for ops::RangeTo { + type Output = ops::RangeTo; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ..self.end.index() + } +} + +impl IntoSliceIdx for ops::RangeInclusive { + type Output = ops::RangeInclusive; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ops::RangeInclusive::new(self.start().index(), self.end().index()) + } +} + +impl IntoSliceIdx for ops::RangeToInclusive { + type Output = ops::RangeToInclusive; + #[inline] + fn into_slice_idx(self) -> Self::Output { + ..=self.end.index() + } +} + +#[cfg(feature = "nightly")] +impl IntoSliceIdx for core::range::Range { + type Output = core::range::Range; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::Range { start: self.start.index(), end: self.end.index() } + } +} + +#[cfg(feature = "nightly")] +impl IntoSliceIdx for core::range::RangeFrom { + type Output = core::range::RangeFrom; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeFrom { start: self.start.index() } + } +} + +#[cfg(feature = "nightly")] +impl IntoSliceIdx for core::range::RangeInclusive { + type Output = core::range::RangeInclusive; + #[inline] + fn into_slice_idx(self) -> Self::Output { + core::range::RangeInclusive { start: self.start.index(), end: self.end.index() } + } +} diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index a3d87f59567fe..0225c5c4f329a 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -51,7 +51,7 @@ impl IntervalSet { self.map.clear(); } - pub fn iter(&self) -> impl Iterator + '_ + pub fn iter(&self) -> impl Iterator where I: Step, { @@ -59,7 +59,7 @@ impl IntervalSet { } /// Iterates through intervals stored in the set, in order. - pub fn iter_intervals(&self) -> impl Iterator> + '_ + pub fn iter_intervals(&self) -> impl Iterator> where I: Step, { diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index cae55230b0679..cc680838e7e7b 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -2,8 +2,8 @@ #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))] #![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr(feature = "nightly", feature(extend_one, step_trait, test))] +#![cfg_attr(feature = "nightly", feature(new_range_api))] #![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod bit_set; @@ -14,7 +14,7 @@ mod idx; mod slice; mod vec; -pub use idx::Idx; +pub use idx::{Idx, IntoSliceIdx}; pub use rustc_index_macros::newtype_index; pub use slice::IndexSlice; #[doc(no_inline)] diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs index 956d32c9a6943..67ac805c2bfe5 100644 --- a/compiler/rustc_index/src/slice.rs +++ b/compiler/rustc_index/src/slice.rs @@ -1,8 +1,10 @@ +use std::fmt; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; -use std::{fmt, slice}; +use std::slice::GetDisjointMutError::*; +use std::slice::{self, SliceIndex}; -use crate::{Idx, IndexVec}; +use crate::{Idx, IndexVec, IntoSliceIdx}; /// A view into contiguous `T`s, indexed by `I` rather than by `usize`. /// @@ -63,9 +65,9 @@ impl IndexSlice { } #[inline] - pub fn iter_enumerated( - &self, - ) -> impl DoubleEndedIterator + ExactSizeIterator + '_ { + pub fn iter_enumerated(&self) -> impl DoubleEndedIterator + ExactSizeIterator { + // Allow the optimizer to elide the bounds checking when creating each index. + let _ = I::new(self.len()); self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t)) } @@ -73,6 +75,8 @@ impl IndexSlice { pub fn indices( &self, ) -> impl DoubleEndedIterator + ExactSizeIterator + Clone + 'static { + // Allow the optimizer to elide the bounds checking when creating each index. + let _ = I::new(self.len()); (0..self.len()).map(|n| I::new(n)) } @@ -84,7 +88,9 @@ impl IndexSlice { #[inline] pub fn iter_enumerated_mut( &mut self, - ) -> impl DoubleEndedIterator + ExactSizeIterator + '_ { + ) -> impl DoubleEndedIterator + ExactSizeIterator { + // Allow the optimizer to elide the bounds checking when creating each index. + let _ = I::new(self.len()); self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t)) } @@ -99,43 +105,53 @@ impl IndexSlice { } #[inline] - pub fn get(&self, index: I) -> Option<&T> { - self.raw.get(index.index()) + pub fn get>( + &self, + index: R, + ) -> Option<&>::Output> { + self.raw.get(index.into_slice_idx()) } #[inline] - pub fn get_mut(&mut self, index: I) -> Option<&mut T> { - self.raw.get_mut(index.index()) + pub fn get_mut>( + &mut self, + index: R, + ) -> Option<&mut >::Output> { + self.raw.get_mut(index.into_slice_idx()) } /// Returns mutable references to two distinct elements, `a` and `b`. /// - /// Panics if `a == b`. + /// Panics if `a == b` or if some of them are out of bounds. #[inline] pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) { let (ai, bi) = (a.index(), b.index()); - assert!(ai != bi); - - if ai < bi { - let (c1, c2) = self.raw.split_at_mut(bi); - (&mut c1[ai], &mut c2[0]) - } else { - let (c2, c1) = self.pick2_mut(b, a); - (c1, c2) + + match self.raw.get_disjoint_mut([ai, bi]) { + Ok([a, b]) => (a, b), + Err(OverlappingIndices) => panic!("Indices {ai:?} and {bi:?} are not disjoint!"), + Err(IndexOutOfBounds) => { + panic!("Some indices among ({ai:?}, {bi:?}) are out of bounds") + } } } /// Returns mutable references to three distinct elements. /// - /// Panics if the elements are not distinct. + /// Panics if the elements are not distinct or if some of them are out of bounds. #[inline] pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) { let (ai, bi, ci) = (a.index(), b.index(), c.index()); - assert!(ai != bi && bi != ci && ci != ai); - let len = self.raw.len(); - assert!(ai < len && bi < len && ci < len); - let ptr = self.raw.as_mut_ptr(); - unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) } + + match self.raw.get_disjoint_mut([ai, bi, ci]) { + Ok([a, b, c]) => (a, b, c), + Err(OverlappingIndices) => { + panic!("Indices {ai:?}, {bi:?} and {ci:?} are not disjoint!") + } + Err(IndexOutOfBounds) => { + panic!("Some indices among ({ai:?}, {bi:?}, {ci:?}) are out of bounds") + } + } } #[inline] @@ -186,19 +202,19 @@ impl fmt::Debug for IndexSlice { } } -impl Index for IndexSlice { - type Output = T; +impl> Index for IndexSlice { + type Output = >::Output; #[inline] - fn index(&self, index: I) -> &T { - &self.raw[index.index()] + fn index(&self, index: R) -> &Self::Output { + &self.raw[index.into_slice_idx()] } } -impl IndexMut for IndexSlice { +impl> IndexMut for IndexSlice { #[inline] - fn index_mut(&mut self, index: I) -> &mut T { - &mut self.raw[index.index()] + fn index_mut(&mut self, index: R) -> &mut Self::Output { + &mut self.raw[index.into_slice_idx()] } } diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 1cb8bc861af98..13f0dda180be9 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -93,6 +93,8 @@ impl IndexVec { /// be allocated only once, with a capacity of at least `n`.) #[inline] pub fn from_fn_n(func: impl FnMut(I) -> T, n: usize) -> Self { + // Allow the optimizer to elide the bounds checking when creating each index. + let _ = I::new(n); IndexVec::from_raw((0..n).map(I::new).map(func).collect()) } @@ -128,11 +130,13 @@ impl IndexVec { pub fn into_iter_enumerated( self, ) -> impl DoubleEndedIterator + ExactSizeIterator { + // Allow the optimizer to elide the bounds checking when creating each index. + let _ = I::new(self.len()); self.raw.into_iter().enumerate().map(|(n, t)| (I::new(n), t)) } #[inline] - pub fn drain>(&mut self, range: R) -> impl Iterator + '_ { + pub fn drain>(&mut self, range: R) -> impl Iterator { self.raw.drain(range) } @@ -140,7 +144,7 @@ impl IndexVec { pub fn drain_enumerated>( &mut self, range: R, - ) -> impl Iterator + '_ { + ) -> impl Iterator { let begin = match range.start_bound() { std::ops::Bound::Included(i) => *i, std::ops::Bound::Excluded(i) => i.checked_add(1).unwrap(), diff --git a/compiler/rustc_index/src/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs index 381d79c24fcba..5b0ca4b2b924c 100644 --- a/compiler/rustc_index/src/vec/tests.rs +++ b/compiler/rustc_index/src/vec/tests.rs @@ -9,8 +9,6 @@ crate::newtype_index! { #[test] fn index_size_is_optimized() { - use std::mem::size_of; - assert_eq!(size_of::(), 4); // Uses 0xFFFF_FFFB assert_eq!(size_of::>(), 4); diff --git a/compiler/rustc_index_macros/Cargo.toml b/compiler/rustc_index_macros/Cargo.toml index 98bc1b6a29bba..891e7ded61996 100644 --- a/compiler/rustc_index_macros/Cargo.toml +++ b/compiler/rustc_index_macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_index_macros" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] proc-macro = true diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs index 67ec776113399..f0b58eabbff9a 100644 --- a/compiler/rustc_index_macros/src/newtype.rs +++ b/compiler/rustc_index_macros/src/newtype.rs @@ -305,7 +305,7 @@ impl Parse for Newtype { } } -pub fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream { +pub(crate) fn newtype(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as Newtype); input.0.into() } diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml index baf5dbbfd4226..08c0361488493 100644 --- a/compiler/rustc_infer/Cargo.toml +++ b/compiler/rustc_infer/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_infer" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] doctest = false diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index c47f27e871f7a..307110d9fbc2c 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -8,9 +8,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_index::Idx; use rustc_middle::bug; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{ - self, BoundVar, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt, + self, BoundVar, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, }; use smallvec::SmallVec; use tracing::debug; diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index c10df2ec02e1d..f5ee5702d09cc 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -8,8 +8,7 @@ use rustc_macros::extension; use rustc_middle::bug; -use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable}; -use rustc_middle::ty::{self, GenericArgKind, TyCtxt}; +use rustc_middle::ty::{self, FnMutDelegate, GenericArgKind, TyCtxt, TypeFoldable}; use crate::infer::canonical::{Canonical, CanonicalVarValues}; diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs index fb5fc3a53fe61..3be07dbe208f9 100644 --- a/compiler/rustc_infer/src/infer/canonical/mod.rs +++ b/compiler/rustc_infer/src/infer/canonical/mod.rs @@ -24,8 +24,7 @@ pub use instantiate::CanonicalExt; use rustc_index::IndexVec; pub use rustc_middle::infer::canonical::*; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, List, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; use crate::infer::{InferCtxt, RegionVariableOrigin}; diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 23f63af778d07..d53f631cc07a9 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -10,12 +10,10 @@ use std::fmt::Debug; use std::iter; -use rustc_data_structures::captures::Captures; use rustc_index::{Idx, IndexVec}; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt}; +use rustc_middle::ty::{self, BoundVar, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; use rustc_middle::{bug, span_bug}; use tracing::{debug, instrument}; @@ -541,13 +539,13 @@ impl<'tcx> InferCtxt<'tcx> { /// Converts the region constraints resulting from a query into an /// iterator of obligations. - fn query_outlives_constraints_into_obligations<'a>( - &'a self, - cause: &'a ObligationCause<'tcx>, + fn query_outlives_constraints_into_obligations( + &self, + cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, - uninstantiated_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], - result_args: &'a CanonicalVarValues<'tcx>, - ) -> impl Iterator> + 'a + Captures<'tcx> { + uninstantiated_region_constraints: &[QueryOutlivesConstraint<'tcx>], + result_args: &CanonicalVarValues<'tcx>, + ) -> impl Iterator> { uninstantiated_region_constraints.iter().map(move |&constraint| { let predicate = instantiate_value(self.tcx, result_args, constraint); self.query_outlives_constraint_to_obligation(predicate, cause.clone(), param_env) diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index eae69ec3e0fe8..75affa1397705 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -1,10 +1,9 @@ ///! Definition of `InferCtxtLike` from the librarified type layer. use rustc_hir::def_id::DefId; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::relate::RelateResult; use rustc_middle::ty::relate::combine::PredicateEmittingRelation; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use super::{BoundRegionConversionTime, InferCtxt, RegionVariableOrigin, SubregionOrigin}; diff --git a/compiler/rustc_infer/src/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs index 5452ba67497bc..8fa5361121c67 100644 --- a/compiler/rustc_infer/src/infer/free_regions.rs +++ b/compiler/rustc_infer/src/infer/free_regions.rs @@ -38,7 +38,7 @@ pub struct FreeRegionMap<'tcx> { } impl<'tcx> FreeRegionMap<'tcx> { - pub fn elements(&self) -> impl Iterator> + '_ { + pub fn elements(&self) -> impl Iterator> { self.relation.elements().copied() } diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs index 74c8b463fc899..f2bb66ff73689 100644 --- a/compiler/rustc_infer/src/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -35,8 +35,9 @@ use std::collections::hash_map::Entry; use rustc_data_structures::fx::FxHashMap; use rustc_middle::bug; -use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitableExt}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, +}; use super::InferCtxt; diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index e454a88e847fd..91595de97f7d2 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -9,10 +9,9 @@ use rustc_data_structures::graph::implementation::{ use rustc_data_structures::intern::Interned; use rustc_data_structures::unord::UnordSet; use rustc_index::{IndexSlice, IndexVec}; -use rustc_middle::ty::fold::{TypeFoldable, fold_regions}; use rustc_middle::ty::{ self, ReBound, ReEarlyParam, ReErased, ReError, ReLateParam, RePlaceholder, ReStatic, ReVar, - Region, RegionVid, Ty, TyCtxt, + Region, RegionVid, Ty, TyCtxt, TypeFoldable, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; @@ -160,7 +159,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { /// empty region. The `expansion` phase will grow this larger. fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> { LexicalRegionResolutions { - values: IndexVec::from_fn_n( + values: IndexVec::::from_fn_n( |vid| { let vid_universe = self.var_infos[vid].universe; VarValue::Empty(vid_universe) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index de49c246c1555..fa8dea064daaa 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -15,7 +15,6 @@ use region_constraints::{ }; pub use relate::StructurallyRelateAliases; pub use relate::combine::PredicateEmittingRelation; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify as ut; @@ -29,14 +28,11 @@ use rustc_middle::infer::canonical::{CanonicalQueryInput, CanonicalVarValues}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::{ - BoundVarReplacerDelegate, TypeFoldable, TypeFolder, TypeSuperFoldable, fold_regions, -}; -use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{ - self, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, GenericArgsRef, - GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Ty, TyCtxt, TyVid, - TypeVisitable, TypingEnv, TypingMode, + self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, + GenericArgsRef, GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Ty, TyCtxt, + TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, + TypingMode, fold_regions, }; use rustc_span::{Span, Symbol}; use snapshot::undo_log::InferCtxtUndoLogs; @@ -233,7 +229,7 @@ impl<'tcx> InferCtxtInner<'tcx> { // while looping through this. pub fn iter_opaque_types( &self, - ) -> impl Iterator, ty::OpaqueHiddenType<'tcx>)> + '_ { + ) -> impl Iterator, ty::OpaqueHiddenType<'tcx>)> { self.opaque_type_storage.opaque_types.iter().map(|(&k, &v)| (k, v)) } } @@ -1295,9 +1291,7 @@ impl<'tcx> InferCtxt<'tcx> { /// The returned function is used in a fast path. If it returns `true` the variable is /// unchanged, `false` indicates that the status is unknown. #[inline] - pub fn is_ty_infer_var_definitely_unchanged<'a>( - &'a self, - ) -> (impl Fn(TyOrConstInferVar) -> bool + Captures<'tcx> + 'a) { + pub fn is_ty_infer_var_definitely_unchanged(&self) -> impl Fn(TyOrConstInferVar) -> bool { // This hoists the borrow/release out of the loop body. let inner = self.inner.try_borrow(); diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index f6ef3f40e622d..3fa1923121a23 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -5,9 +5,9 @@ use rustc_middle::bug; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{ - self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, + self, BottomUpFolder, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, + TypeVisitableExt, }; use rustc_span::Span; use tracing::{debug, instrument}; diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs index 1afe50e336da2..2a4544c1140d1 100644 --- a/compiler/rustc_infer/src/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -20,7 +20,7 @@ pub(crate) mod verify; #[instrument(level = "debug", skip(param_env), ret)] pub fn explicit_outlives_bounds<'tcx>( param_env: ty::ParamEnv<'tcx>, -) -> impl Iterator> + 'tcx { +) -> impl Iterator> { param_env .caller_bounds() .into_iter() diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs index ce2d07f4af996..e16212955ffee 100644 --- a/compiler/rustc_infer/src/infer/relate/generalize.rs +++ b/compiler/rustc_infer/src/infer/relate/generalize.rs @@ -5,10 +5,9 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::visit::MaxUniverse; use rustc_middle::ty::{ - self, AliasRelationDirection, InferConst, Term, Ty, TyCtxt, TypeVisitable, TypeVisitableExt, - TypingMode, + self, AliasRelationDirection, InferConst, MaxUniverse, Term, Ty, TyCtxt, TypeVisitable, + TypeVisitableExt, TypingMode, }; use rustc_span::Span; use tracing::{debug, instrument, warn}; diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 0998f3c479024..2143f72a3b0a5 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -1,8 +1,7 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, FnMutDelegate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use tracing::{debug, instrument}; use super::RelateResult; @@ -26,8 +25,9 @@ impl<'tcx> InferCtxt<'tcx> { where T: TypeFoldable>, { - if let Some(inner) = binder.clone().no_bound_vars() { - return inner; + // Inlined `no_bound_vars`. + if !binder.as_ref().skip_binder().has_escaping_bound_vars() { + return binder.skip_binder(); } let next_universe = self.create_next_universe(); diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 6ec2e0152f0dc..4a99c2209755d 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,7 +1,8 @@ use rustc_middle::bug; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{ + self, Const, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, +}; use rustc_type_ir::data_structures::DelayedMap; use super::{FixupError, FixupResult, InferCtxt}; diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 3a47b13665d45..b5d3c26b05e0b 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -1,9 +1,11 @@ use std::ops::Range; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use rustc_middle::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; -use rustc_type_ir::visit::TypeVisitableExt; +use rustc_middle::ty::{ + self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, + TypeSuperFoldable, +}; +use rustc_type_ir::TypeVisitableExt; use tracing::instrument; use ut::UnifyKey; diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index a04b2bb2b08b5..ece18f4ea64ee 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -24,7 +24,6 @@ #![feature(let_chains)] #![feature(rustdoc_internals)] #![recursion_limit = "512"] // For rustdoc -#![warn(unreachable_pub)] // tidy-alphabetical-end mod errors; diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs index b346e193d0b84..4335073d9bc6b 100644 --- a/compiler/rustc_infer/src/traits/structural_impls.rs +++ b/compiler/rustc_infer/src/traits/structural_impls.rs @@ -1,8 +1,8 @@ use std::fmt; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitor, try_visit}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{ + self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, try_visit, +}; use crate::traits; use crate::traits::project::Normalized; diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index 295a988d2da5d..9c9660cf50469 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_interface" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs index ca4e556dcdb80..eed729a1777fc 100644 --- a/compiler/rustc_interface/src/errors.rs +++ b/compiler/rustc_interface/src/errors.rs @@ -24,8 +24,9 @@ pub(crate) struct CrateNameInvalid<'a> { pub struct FerrisIdentifier { #[primary_span] pub spans: Vec, - #[suggestion(code = "ferris", applicability = "maybe-incorrect")] + #[suggestion(code = "{ferris_fix}", applicability = "maybe-incorrect")] pub first_span: Span, + pub ferris_fix: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index b35703d8e737b..3f87b1a547be5 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -18,7 +18,7 @@ use rustc_parse::parser::attr::AllowLeadingUnsafe; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::print_query_stack; use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName}; -use rustc_session::filesearch::{self, sysroot_candidates}; +use rustc_session::filesearch::sysroot_candidates; use rustc_session::parse::ParseSess; use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, lint}; use rustc_span::source_map::{FileLoader, RealFileLoader, SourceMapInputs}; @@ -390,7 +390,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se crate::callbacks::setup_callbacks(); - let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone()); + let sysroot = config.opts.sysroot.clone(); let target = config::build_target_config(&early_dcx, &config.opts.target_triple, &sysroot); let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); let path_mapping = config.opts.file_path_mapping(); @@ -424,7 +424,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se let temps_dir = config.opts.unstable_opts.temps_dir.as_deref().map(PathBuf::from); let bundle = match rustc_errors::fluent_bundle( - config.opts.maybe_sysroot.clone(), + config.opts.sysroot.clone(), sysroot_candidates().to_vec(), config.opts.unstable_opts.translate_lang.clone(), config.opts.unstable_opts.translate_additional_ftl.as_deref(), diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index 54cd341698f0b..67e0be93523d9 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -4,7 +4,6 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod callbacks; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d70d9d344b94c..e47385d089944 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -2,14 +2,14 @@ use std::any::Any; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; use std::path::{Path, PathBuf}; -use std::sync::{Arc, LazyLock}; +use std::sync::{Arc, LazyLock, OnceLock}; use std::{env, fs, iter}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; -use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, OnceLock, WorkerLocal}; +use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal}; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; @@ -171,13 +171,15 @@ fn configure_and_expand( new_path.push(path); } } - env::set_var( - "PATH", - &env::join_paths( - new_path.iter().filter(|p| env::join_paths(iter::once(p)).is_ok()), - ) - .unwrap(), - ); + unsafe { + env::set_var( + "PATH", + &env::join_paths( + new_path.iter().filter(|p| env::join_paths(iter::once(p)).is_ok()), + ) + .unwrap(), + ); + } } // Create the config for macro expansion @@ -216,7 +218,9 @@ fn configure_and_expand( } if cfg!(windows) { - env::set_var("PATH", &old_path); + unsafe { + env::set_var("PATH", &old_path); + } } krate @@ -301,8 +305,41 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { for (ident, mut spans) in identifiers.drain(..) { spans.sort(); if ident == sym::ferris { + enum FerrisFix { + SnakeCase, + ScreamingSnakeCase, + PascalCase, + } + + impl FerrisFix { + const fn as_str(self) -> &'static str { + match self { + FerrisFix::SnakeCase => "ferris", + FerrisFix::ScreamingSnakeCase => "FERRIS", + FerrisFix::PascalCase => "Ferris", + } + } + } + let first_span = spans[0]; - sess.dcx().emit_err(errors::FerrisIdentifier { spans, first_span }); + let prev_source = sess.psess.source_map().span_to_prev_source(first_span); + let ferris_fix = prev_source + .map_or(FerrisFix::SnakeCase, |source| { + let mut source_before_ferris = source.trim_end().split_whitespace().rev(); + match source_before_ferris.next() { + Some("struct" | "trait" | "mod" | "union" | "type" | "enum") => { + FerrisFix::PascalCase + } + Some("const" | "static") => FerrisFix::ScreamingSnakeCase, + Some("mut") if source_before_ferris.next() == Some("static") => { + FerrisFix::ScreamingSnakeCase + } + _ => FerrisFix::SnakeCase, + } + }) + .as_str(); + + sess.dcx().emit_err(errors::FerrisIdentifier { spans, first_span, ferris_fix }); } else { sess.dcx().emit_err(errors::EmojiIdentifier { spans, ident }); } diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 00600abb5f1e3..a2c1f1dbeda6b 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -8,7 +8,7 @@ fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option { let mut decls = None; for id in tcx.hir_free_items() { - let attrs = tcx.hir().attrs(id.hir_id()); + let attrs = tcx.hir_attrs(id.hir_id()); if attr::contains_name(attrs, sym::rustc_proc_macro_decls) { decls = Some(id.owner_id.def_id); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index aabd235bcabed..b44be1710edf7 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -21,7 +21,7 @@ use rustc_session::config::{ use rustc_session::lint::Level; use rustc_session::search_paths::SearchPath; use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; -use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, filesearch, getopts}; +use rustc_session::{CompilerIO, EarlyDiagCtxt, Session, build_session, getopts}; use rustc_span::edition::{DEFAULT_EDITION, Edition}; use rustc_span::source_map::{RealFileLoader, SourceMapInputs}; use rustc_span::{FileName, SourceFileHashAlgorithm, sym}; @@ -41,7 +41,7 @@ where let matches = optgroups().parse(args).unwrap(); let sessopts = build_session_options(&mut early_dcx, &matches); - let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone()); + let sysroot = sessopts.sysroot.clone(); let target = rustc_session::config::build_target_config(&early_dcx, &sessopts.target_triple, &sysroot); let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index bc2aae7cd87e2..5cccab893bb35 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -39,11 +39,11 @@ pub(crate) fn add_configuration( ) { let tf = sym::target_feature; - let unstable_target_features = codegen_backend.target_features_cfg(sess, true); - sess.unstable_target_features.extend(unstable_target_features.iter().cloned()); + let (target_features, unstable_target_features) = codegen_backend.target_features_cfg(sess); - let target_features = codegen_backend.target_features_cfg(sess, false); - sess.target_features.extend(target_features.iter().cloned()); + sess.unstable_target_features.extend(unstable_target_features.iter().copied()); + + sess.target_features.extend(target_features.iter().copied()); cfg.extend(target_features.into_iter().map(|feat| (tf, Some(feat)))); diff --git a/compiler/rustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml index 4b3492fdeda25..448a50faf458e 100644 --- a/compiler/rustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -2,7 +2,7 @@ name = "rustc_lexer" version = "0.0.0" license = "MIT OR Apache-2.0" -edition = "2021" +edition = "2024" repository = "https://github.com/rust-lang/rust/" description = """ Rust lexer used by rustc. No stability guarantees are provided. diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c63ab77decac9..61638e45253fd 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -23,7 +23,6 @@ // We want to be able to build this crate with a stable compiler, // so no `#![feature]` attributes should be added. #![deny(unstable_features)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod cursor; @@ -291,7 +290,7 @@ pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> } /// Creates an iterator that produces tokens from the input string. -pub fn tokenize(input: &str) -> impl Iterator + '_ { +pub fn tokenize(input: &str) -> impl Iterator { let mut cursor = Cursor::new(input); std::iter::from_fn(move || { let token = cursor.advance_token(); diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml index cc5a90296332d..7718f16984dab 100644 --- a/compiler/rustc_lint/Cargo.toml +++ b/compiler/rustc_lint/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_lint" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -23,7 +23,7 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_type_ir = { path = "../rustc_type_ir" } +smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" unicode-security = "0.1.0" # tidy-alphabetical-end diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 679367634276d..d51865810b9a8 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -333,6 +333,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len -> *[other] {" "}{$identifier_type} } Unicode general security profile +lint_if_let_dtor = {$dtor_kind -> + [dyn] value may invoke a custom destructor because it contains a trait object + *[concrete] value invokes this custom destructor + } + lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024 .label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion .help = the value is now dropped here in Edition 2024 diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b5f09ff346a7a..b4892e73842c3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -419,7 +419,7 @@ impl MissingDoc { return; } - let attrs = cx.tcx.hir().attrs(cx.tcx.local_def_id_to_hir_id(def_id)); + let attrs = cx.tcx.hir_attrs(cx.tcx.local_def_id_to_hir_id(def_id)); let has_doc = attrs.iter().any(has_doc); if !has_doc { cx.emit_span_lint( @@ -975,10 +975,8 @@ declare_lint! { /// ### Example /// /// ```rust - /// #[no_mangle] - /// fn foo(t: T) { - /// - /// } + /// #[unsafe(no_mangle)] + /// fn foo(t: T) {} /// ``` /// /// {{produces}} @@ -999,7 +997,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { - let attrs = cx.tcx.hir().attrs(it.hir_id()); + let attrs = cx.tcx.hir_attrs(it.hir_id()); let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute, impl_generics: Option<&hir::Generics<'_>>, generics: &hir::Generics<'_>, @@ -1013,7 +1011,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span }, + BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() }, ); break; } @@ -1052,7 +1050,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { if let Some(no_mangle_attr) = - attr::find_by_name(cx.tcx.hir().attrs(it.id.hir_id()), sym::no_mangle) + attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle) { check_no_mangle_on_generic_fn( no_mangle_attr, @@ -1228,7 +1226,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { { cx.emit_span_lint( UNGATED_ASYNC_FN_TRACK_CALLER, - attr.span, + attr.span(), BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess }, ); } @@ -2584,34 +2582,35 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { ) -> Option { let ty = cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty); - use rustc_type_ir::TyKind::*; match ty.kind() { // Primitive types that don't like 0 as a value. - Ref(..) => Some("references must be non-null".into()), - Adt(..) if ty.is_box() => Some("`Box` must be non-null".into()), - FnPtr(..) => Some("function pointers must be non-null".into()), - Never => Some("the `!` type has no valid value".into()), - RawPtr(ty, _) if matches!(ty.kind(), Dynamic(..)) => + ty::Ref(..) => Some("references must be non-null".into()), + ty::Adt(..) if ty.is_box() => Some("`Box` must be non-null".into()), + ty::FnPtr(..) => Some("function pointers must be non-null".into()), + ty::Never => Some("the `!` type has no valid value".into()), + ty::RawPtr(ty, _) if matches!(ty.kind(), ty::Dynamic(..)) => // raw ptr to dyn Trait { Some("the vtable of a wide raw pointer must be non-null".into()) } // Primitive types with other constraints. - Bool if init == InitKind::Uninit => { + ty::Bool if init == InitKind::Uninit => { Some("booleans must be either `true` or `false`".into()) } - Char if init == InitKind::Uninit => { + ty::Char if init == InitKind::Uninit => { Some("characters must be a valid Unicode codepoint".into()) } - Int(_) | Uint(_) if init == InitKind::Uninit => { + ty::Int(_) | ty::Uint(_) if init == InitKind::Uninit => { Some("integers must be initialized".into()) } - Float(_) if init == InitKind::Uninit => Some("floats must be initialized".into()), - RawPtr(_, _) if init == InitKind::Uninit => { + ty::Float(_) if init == InitKind::Uninit => { + Some("floats must be initialized".into()) + } + ty::RawPtr(_, _) if init == InitKind::Uninit => { Some("raw pointers must be initialized".into()) } // Recurse and checks for some compound types. (but not unions) - Adt(adt_def, args) if !adt_def.is_union() => { + ty::Adt(adt_def, args) if !adt_def.is_union() => { // Handle structs. if adt_def.is_struct() { return variant_find_init_error( @@ -2677,11 +2676,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // We couldn't find anything wrong here. None } - Tuple(..) => { + ty::Tuple(..) => { // Proceed recursively, check all fields. ty.tuple_fields().iter().find_map(|field| ty_find_init_error(cx, field, init)) } - Array(ty, len) => { + ty::Array(ty, len) => { if matches!(len.try_to_target_usize(cx.tcx), Some(v) if v > 0) { // Array length known at array non-empty -- recurse. ty_find_init_error(cx, *ty, init) @@ -2909,7 +2908,13 @@ enum AsmLabelKind { impl<'tcx> LateLintPass<'tcx> for AsmLabels { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { if let hir::Expr { - kind: hir::ExprKind::InlineAsm(hir::InlineAsm { template_strs, options, .. }), + kind: + hir::ExprKind::InlineAsm(hir::InlineAsm { + asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm, + template_strs, + options, + .. + }), .. } = expr { diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c74158102c7a5..017ae943e9161 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -6,6 +6,7 @@ use std::cell::Cell; use std::slice; +use rustc_ast::BindingMode; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; @@ -14,6 +15,7 @@ use rustc_feature::Features; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::{Pat, PatKind}; use rustc_middle::bug; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; @@ -139,9 +141,7 @@ impl LintStore { &self.lints } - pub fn get_lint_groups<'t>( - &'t self, - ) -> impl Iterator, bool)> + 't { + pub fn get_lint_groups(&self) -> impl Iterator, bool)> { self.lint_groups .iter() .filter(|(_, LintGroup { depr, .. })| { @@ -685,6 +685,10 @@ impl<'tcx> LateContext<'tcx> { self.tcx.type_is_copy_modulo_regions(self.typing_env(), ty) } + pub fn type_is_use_cloned_modulo_regions(&self, ty: Ty<'tcx>) -> bool { + self.tcx.type_is_use_cloned_modulo_regions(self.typing_env(), ty) + } + /// Gets the type-checking results for the current body, /// or `None` if outside a body. pub fn maybe_typeck_results(&self) -> Option<&'tcx ty::TypeckResults<'tcx>> { @@ -888,7 +892,12 @@ impl<'tcx> LateContext<'tcx> { } && let Some(init) = match parent_node { hir::Node::Expr(expr) => Some(expr), - hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init, + hir::Node::LetStmt(hir::LetStmt { + init, + // Binding is immutable, init cannot be re-assigned + pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. }, + .. + }) => *init, _ => None, } { @@ -933,7 +942,12 @@ impl<'tcx> LateContext<'tcx> { } && let Some(init) = match parent_node { hir::Node::Expr(expr) => Some(expr), - hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init, + hir::Node::LetStmt(hir::LetStmt { + init, + // Binding is immutable, init cannot be re-assigned + pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. }, + .. + }) => *init, hir::Node::Item(item) => match item.kind { hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => { Some(self.tcx.hir_body(body_id).value) diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs index fd6b3e90adabc..91c7922638de5 100644 --- a/compiler/rustc_lint/src/dangling.rs +++ b/compiler/rustc_lint/src/dangling.rs @@ -159,7 +159,10 @@ fn is_temporary_rvalue(expr: &Expr<'_>) -> bool { ExprKind::Path(..) => false, // Calls return rvalues. - ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) => true, + ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Use(..) + | ExprKind::Binary(..) => true, // Inner blocks are rvalues. ExprKind::If(..) | ExprKind::Loop(..) | ExprKind::Match(..) | ExprKind::Block(..) => true, diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 59e38a882dde5..58efca5e994ab 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -133,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { return; } - // At least one of the fields with a default value have been overriden in + // At least one of the fields with a default value have been overridden in // the `Default` implementation. We suggest removing it and relying on `..` // instead. let any_default_field_given = diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs index f418d6d8753b4..ec8f84415759f 100644 --- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs +++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs @@ -12,7 +12,7 @@ declare_lint! { /// for `dyn SubTrait` with a `dyn SuperTrait` type as the `Output` type. /// /// These implementations are "shadowed" by trait upcasting (stabilized since - /// CURRENT_RUSTC_VERSION). The `deref` functions is no longer called implicitly, which might + /// 1.86.0). The `deref` functions is no longer called implicitly, which might /// change behavior compared to previous rustc versions. /// /// ### Example diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index 7ead8eafbd5aa..179f2bcf07f59 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -1,6 +1,5 @@ use rustc_hir as hir; -use rustc_middle::ty::Ty; -use rustc_middle::ty::visit::TypeVisitableExt; +use rustc_middle::ty::{Ty, TypeVisitableExt}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{Span, sym}; diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index ef79f1301e5f6..4c2b82a9a23a6 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -38,7 +38,8 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option) { } LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => { // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok. - let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id; + let attr_id = tcx.hir_attrs(hir_id)[attr_index as usize].id(); + (attr_id, lint_index) } _ => panic!("fulfilled expectations must have a lint index"), diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 636779fe9b4cf..0494c78a7a97c 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -35,12 +35,12 @@ declare_lint! { /// /// ```rust /// mod m { - /// extern "C" { + /// unsafe extern "C" { /// fn foo(); /// } /// } /// - /// extern "C" { + /// unsafe extern "C" { /// fn foo(_: u32); /// } /// ``` @@ -182,7 +182,7 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName { // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. - (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span) + (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span()) }) { SymbolName::Link(overridden_link_name, overridden_link_name_span) @@ -270,14 +270,12 @@ fn structurally_same_type_impl<'tcx>( true } else { // Do a full, depth-first comparison between the two. - use rustc_type_ir::TyKind::*; - let is_primitive_or_pointer = - |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), RawPtr(..) | Ref(..)); + |ty: Ty<'tcx>| ty.is_primitive() || matches!(ty.kind(), ty::RawPtr(..) | ty::Ref(..)); ensure_sufficient_stack(|| { match (a.kind(), b.kind()) { - (&Adt(a_def, a_gen_args), &Adt(b_def, b_gen_args)) => { + (&ty::Adt(a_def, a_gen_args), &ty::Adt(b_def, b_gen_args)) => { // Only `repr(C)` types can be compared structurally. if !(a_def.repr().c() && b_def.repr().c()) { return false; @@ -308,30 +306,30 @@ fn structurally_same_type_impl<'tcx>( }, ) } - (Array(a_ty, a_len), Array(b_ty, b_len)) => { + (ty::Array(a_ty, a_len), ty::Array(b_ty, b_len)) => { // For arrays, we also check the length. a_len == b_len && structurally_same_type_impl( seen_types, tcx, typing_env, *a_ty, *b_ty, ckind, ) } - (Slice(a_ty), Slice(b_ty)) => { + (ty::Slice(a_ty), ty::Slice(b_ty)) => { structurally_same_type_impl(seen_types, tcx, typing_env, *a_ty, *b_ty, ckind) } - (RawPtr(a_ty, a_mutbl), RawPtr(b_ty, b_mutbl)) => { + (ty::RawPtr(a_ty, a_mutbl), ty::RawPtr(b_ty, b_mutbl)) => { a_mutbl == b_mutbl && structurally_same_type_impl( seen_types, tcx, typing_env, *a_ty, *b_ty, ckind, ) } - (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => { + (ty::Ref(_a_region, a_ty, a_mut), ty::Ref(_b_region, b_ty, b_mut)) => { // For structural sameness, we don't need the region to be same. a_mut == b_mut && structurally_same_type_impl( seen_types, tcx, typing_env, *a_ty, *b_ty, ckind, ) } - (FnDef(..), FnDef(..)) => { + (ty::FnDef(..), ty::FnDef(..)) => { let a_poly_sig = a.fn_sig(tcx); let b_poly_sig = b.fn_sig(tcx); @@ -354,35 +352,38 @@ fn structurally_same_type_impl<'tcx>( ckind, ) } - (Tuple(..), Tuple(..)) => { + (ty::Tuple(..), ty::Tuple(..)) => { // Tuples are not `repr(C)` so these cannot be compared structurally. false } // For these, it's not quite as easy to define structural-sameness quite so easily. // For the purposes of this lint, take the conservative approach and mark them as // not structurally same. - (Dynamic(..), Dynamic(..)) - | (Error(..), Error(..)) - | (Closure(..), Closure(..)) - | (Coroutine(..), Coroutine(..)) - | (CoroutineWitness(..), CoroutineWitness(..)) - | (Alias(ty::Projection, ..), Alias(ty::Projection, ..)) - | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..)) - | (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false, + (ty::Dynamic(..), ty::Dynamic(..)) + | (ty::Error(..), ty::Error(..)) + | (ty::Closure(..), ty::Closure(..)) + | (ty::Coroutine(..), ty::Coroutine(..)) + | (ty::CoroutineWitness(..), ty::CoroutineWitness(..)) + | (ty::Alias(ty::Projection, ..), ty::Alias(ty::Projection, ..)) + | (ty::Alias(ty::Inherent, ..), ty::Alias(ty::Inherent, ..)) + | (ty::Alias(ty::Opaque, ..), ty::Alias(ty::Opaque, ..)) => false, // These definitely should have been caught above. - (Bool, Bool) | (Char, Char) | (Never, Never) | (Str, Str) => unreachable!(), + (ty::Bool, ty::Bool) + | (ty::Char, ty::Char) + | (ty::Never, ty::Never) + | (ty::Str, ty::Str) => unreachable!(), // An Adt and a primitive or pointer type. This can be FFI-safe if non-null // enum layout optimisation is being applied. - (Adt(..) | Pat(..), _) if is_primitive_or_pointer(b) => { + (ty::Adt(..) | ty::Pat(..), _) if is_primitive_or_pointer(b) => { if let Some(a_inner) = types::repr_nullable_ptr(tcx, typing_env, a, ckind) { a_inner == b } else { false } } - (_, Adt(..) | Pat(..)) if is_primitive_or_pointer(a) => { + (_, ty::Adt(..) | ty::Pat(..)) if is_primitive_or_pointer(a) => { if let Some(b_inner) = types::repr_nullable_ptr(tcx, typing_env, b, ckind) { b_inner == a } else { diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index c1aa95667da68..39ea8d8e3246c 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -1,18 +1,23 @@ use std::iter::repeat; use std::ops::ControlFlow; -use hir::intravisit::Visitor; +use hir::intravisit::{self, Visitor}; use rustc_ast::Recovered; use rustc_errors::{ Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle, }; use rustc_hir::{self as hir, HirIdSet}; -use rustc_macros::LintDiagnostic; -use rustc_middle::ty::TyCtxt; +use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_middle::ty::adjustment::Adjust; +use rustc_middle::ty::significant_drop_order::{ + extract_component_with_significant_dtor, ty_dtor_span, +}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::{FutureIncompatibilityReason, LintId}; use rustc_session::{declare_lint, impl_lint_pass}; -use rustc_span::Span; use rustc_span::edition::Edition; +use rustc_span::{DUMMY_SP, Span}; +use smallvec::SmallVec; use crate::{LateContext, LateLintPass}; @@ -129,6 +134,7 @@ impl IfLetRescope { hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(), _ => return, }; + let mut seen_dyn = false; let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr); let mut significant_droppers = vec![]; let mut lifetime_ends = vec![]; @@ -136,6 +142,7 @@ impl IfLetRescope { let mut alt_heads = vec![]; let mut match_heads = vec![]; let mut consequent_heads = vec![]; + let mut destructors = vec![]; let mut first_if_to_lint = None; let mut first_if_to_rewrite = false; let mut empty_alt = false; @@ -159,11 +166,25 @@ impl IfLetRescope { let before_conseq = conseq.span.shrink_to_lo(); let lifetime_end = source_map.end_point(conseq.span); - if let ControlFlow::Break(significant_dropper) = - (FindSignificantDropper { cx }).visit_expr(init) + if let ControlFlow::Break((drop_span, drop_tys)) = + (FindSignificantDropper { cx }).check_if_let_scrutinee(init) { + destructors.extend(drop_tys.into_iter().filter_map(|ty| { + if let Some(span) = ty_dtor_span(tcx, ty) { + Some(DestructorLabel { span, dtor_kind: "concrete" }) + } else if matches!(ty.kind(), ty::Dynamic(..)) { + if seen_dyn { + None + } else { + seen_dyn = true; + Some(DestructorLabel { span: DUMMY_SP, dtor_kind: "dyn" }) + } + } else { + None + } + })); first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id))); - significant_droppers.push(significant_dropper); + significant_droppers.push(drop_span); lifetime_ends.push(lifetime_end); if ty_ascription.is_some() || !expr.span.can_be_used_for_suggestions() @@ -226,6 +247,7 @@ impl IfLetRescope { hir_id, span, IfLetRescopeLint { + destructors, significant_droppers, lifetime_ends, rewrite: first_if_to_rewrite.then_some(IfLetRescopeRewrite { @@ -287,6 +309,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope { #[derive(LintDiagnostic)] #[diag(lint_if_let_rescope)] struct IfLetRescopeLint { + #[subdiagnostic] + destructors: Vec, #[label] significant_droppers: Vec, #[help] @@ -346,6 +370,14 @@ impl Subdiagnostic for IfLetRescopeRewrite { } } +#[derive(Subdiagnostic)] +#[note(lint_if_let_dtor)] +struct DestructorLabel { + #[primary_span] + span: Span, + dtor_kind: &'static str, +} + struct AltHead(Span); struct ConsequentRewrite { @@ -363,96 +395,107 @@ enum SingleArmMatchBegin { WithoutOpenBracket(Span), } -struct FindSignificantDropper<'tcx, 'a> { +struct FindSignificantDropper<'a, 'tcx> { cx: &'a LateContext<'tcx>, } -impl<'tcx, 'a> Visitor<'tcx> for FindSignificantDropper<'tcx, 'a> { - type Result = ControlFlow; +impl<'tcx> FindSignificantDropper<'_, 'tcx> { + /// Check the scrutinee of an `if let` to see if it promotes any temporary values + /// that would change drop order in edition 2024. Specifically, it checks the value + /// of the scrutinee itself, and also recurses into the expression to find any ref + /// exprs (or autoref) which would promote temporaries that would be scoped to the + /// end of this `if`. + fn check_if_let_scrutinee( + &mut self, + init: &'tcx hir::Expr<'tcx>, + ) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> { + self.check_promoted_temp_with_drop(init)?; + self.visit_expr(init) + } - fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result { - if self - .cx - .typeck_results() - .expr_ty(expr) - .has_significant_drop(self.cx.tcx, self.cx.typing_env()) - { - return ControlFlow::Break(expr.span); + /// Check that an expression is not a promoted temporary with a significant + /// drop impl. + /// + /// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref) + /// or is the scrutinee of the `if let`, *and* the expression is not a place + /// expr, and it has a significant drop. + fn check_promoted_temp_with_drop( + &self, + expr: &'tcx hir::Expr<'tcx>, + ) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> { + if expr.is_place_expr(|base| { + self.cx + .typeck_results() + .adjustments() + .get(base.hir_id) + .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) + }) { + return ControlFlow::Continue(()); } - match expr.kind { - hir::ExprKind::ConstBlock(_) - | hir::ExprKind::Lit(_) - | hir::ExprKind::Path(_) - | hir::ExprKind::Assign(_, _, _) - | hir::ExprKind::AssignOp(_, _, _) - | hir::ExprKind::Break(_, _) - | hir::ExprKind::Continue(_) - | hir::ExprKind::Ret(_) - | hir::ExprKind::Become(_) - | hir::ExprKind::InlineAsm(_) - | hir::ExprKind::OffsetOf(_, _) - | hir::ExprKind::Repeat(_, _) - | hir::ExprKind::Err(_) - | hir::ExprKind::Struct(_, _, _) - | hir::ExprKind::Closure(_) - | hir::ExprKind::Block(_, _) - | hir::ExprKind::DropTemps(_) - | hir::ExprKind::Loop(_, _, _, _) => ControlFlow::Continue(()), - hir::ExprKind::Tup(exprs) | hir::ExprKind::Array(exprs) => { - for expr in exprs { - self.visit_expr(expr)?; - } - ControlFlow::Continue(()) - } - hir::ExprKind::Call(callee, args) => { - self.visit_expr(callee)?; - for expr in args { - self.visit_expr(expr)?; - } - ControlFlow::Continue(()) - } - hir::ExprKind::MethodCall(_, receiver, args, _) => { - self.visit_expr(receiver)?; - for expr in args { - self.visit_expr(expr)?; + let drop_tys = extract_component_with_significant_dtor( + self.cx.tcx, + self.cx.typing_env(), + self.cx.typeck_results().expr_ty(expr), + ); + if drop_tys.is_empty() { + return ControlFlow::Continue(()); + } + + ControlFlow::Break((expr.span, drop_tys)) + } +} + +impl<'tcx> Visitor<'tcx> for FindSignificantDropper<'_, 'tcx> { + type Result = ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)>; + + fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> Self::Result { + // Blocks introduce temporary terminating scope for all of its + // statements, so just visit the tail expr, skipping over any + // statements. This prevents false positives like `{ let x = &Drop; }`. + if let Some(expr) = b.expr { self.visit_expr(expr) } else { ControlFlow::Continue(()) } + } + + fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Self::Result { + // Check for promoted temporaries from autoref, e.g. + // `if let None = TypeWithDrop.as_ref() {} else {}` + // where `fn as_ref(&self) -> Option<...>`. + for adj in self.cx.typeck_results().expr_adjustments(expr) { + match adj.kind { + // Skip when we hit the first deref expr. + Adjust::Deref(_) => break, + Adjust::Borrow(_) => { + self.check_promoted_temp_with_drop(expr)?; } - ControlFlow::Continue(()) - } - hir::ExprKind::Index(left, right, _) | hir::ExprKind::Binary(_, left, right) => { - self.visit_expr(left)?; - self.visit_expr(right) + _ => {} } - hir::ExprKind::Unary(_, expr) - | hir::ExprKind::Cast(expr, _) - | hir::ExprKind::Type(expr, _) - | hir::ExprKind::UnsafeBinderCast(_, expr, _) - | hir::ExprKind::Yield(expr, _) - | hir::ExprKind::AddrOf(_, _, expr) - | hir::ExprKind::Match(expr, _, _) - | hir::ExprKind::Field(expr, _) - | hir::ExprKind::Let(&hir::LetExpr { - init: expr, - span: _, - pat: _, - ty: _, - recovered: Recovered::No, - }) => self.visit_expr(expr), - hir::ExprKind::Let(_) => ControlFlow::Continue(()), + } - hir::ExprKind::If(cond, _, _) => { - if let hir::ExprKind::Let(hir::LetExpr { - init, - span: _, - pat: _, - ty: _, - recovered: Recovered::No, - }) = cond.kind - { - self.visit_expr(init)?; - } - ControlFlow::Continue(()) + match expr.kind { + // Account for cases like `if let None = Some(&Drop) {} else {}`. + hir::ExprKind::AddrOf(_, _, expr) => { + self.check_promoted_temp_with_drop(expr)?; + intravisit::walk_expr(self, expr) + } + // `(Drop, ()).1` introduces a temporary and then moves out of + // part of it, therefore we should check it for temporaries. + // FIXME: This may have false positives if we move the part + // that actually has drop, but oh well. + hir::ExprKind::Index(expr, _, _) | hir::ExprKind::Field(expr, _) => { + self.check_promoted_temp_with_drop(expr)?; + intravisit::walk_expr(self, expr) } + // If always introduces a temporary terminating scope for its cond and arms, + // so don't visit them. + hir::ExprKind::If(..) => ControlFlow::Continue(()), + // Match introduces temporary terminating scopes for arms, so don't visit + // them, and only visit the scrutinee to account for cases like: + // `if let None = match &Drop { _ => Some(1) } {} else {}`. + hir::ExprKind::Match(scrut, _, _) => self.visit_expr(scrut), + // Self explanatory. + hir::ExprKind::DropTemps(_) => ControlFlow::Continue(()), + // Otherwise, walk into the expr's parts. + _ => intravisit::walk_expr(self, expr), } } } diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 0b3af7d6aba98..c2404a7b84326 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -506,9 +506,9 @@ impl<'tcx> TypeRelation> for FunctionalVariances<'tcx> { self.tcx } - fn relate_with_variance>>( + fn relate_with_variance>>( &mut self, - variance: rustc_type_ir::Variance, + variance: ty::Variance, _: ty::VarianceDiagInfo>, a: T, b: T, diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index d22515d62d60e..852bb01c09655 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -48,7 +48,7 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { where F: FnOnce(&mut Self), { - let attrs = self.context.tcx.hir().attrs(id); + let attrs = self.context.tcx.hir_attrs(id); let prev = self.context.last_node_with_lint_attrs; self.context.last_node_with_lint_attrs = id; debug!("late context: enter_attrs({:?})", attrs); @@ -74,7 +74,7 @@ impl<'tcx, T: LateLintPass<'tcx>> LateContextAndPass<'tcx, T> { fn process_mod(&mut self, m: &'tcx hir::Mod<'tcx>, n: HirId) { lint_callback!(self, check_mod, m, n); - hir_visit::walk_mod(self, m, n); + hir_visit::walk_mod(self, m); } } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 4ede9b4408798..8718fb807ecf5 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -152,7 +152,7 @@ fn lints_that_dont_need_to_run(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { #[instrument(level = "trace", skip(tcx), ret)] fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLevelMap { let store = unerased_lint_store(tcx.sess); - let attrs = tcx.hir_attrs(owner); + let attrs = tcx.hir_attr_map(owner); let mut levels = LintLevelsBuilder { sess: tcx.sess, @@ -299,6 +299,11 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> { intravisit::walk_expr(self, e); } + fn visit_pat_field(&mut self, f: &'tcx hir::PatField<'tcx>) -> Self::Result { + self.add_id(f.hir_id); + intravisit::walk_pat_field(self, f); + } + fn visit_expr_field(&mut self, f: &'tcx hir::ExprField<'tcx>) { self.add_id(f.hir_id); intravisit::walk_expr_field(self, f); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 044a613dad62b..c38a754001811 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -21,20 +21,18 @@ // tidy-alphabetical-start #![allow(internal_features)] -#![cfg_attr(bootstrap, feature(trait_upcasting))] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_order_by)] #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod async_closures; @@ -601,6 +599,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, \ see for more information", ); + store.register_removed( + "ptr_cast_add_auto_to_object", + "converted into hard error, see issue #127323 \ + for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 2f9cf98848e94..66e207a451ef0 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -183,7 +183,7 @@ impl EarlyLintPass for NonAsciiIdents { #[allow(rustc::potential_query_instability)] let mut symbols: Vec<_> = symbols.iter().collect(); symbols.sort_by_key(|k| k.1); - for (symbol, &sp) in symbols.iter() { + for &(ref symbol, &sp) in symbols.iter() { let symbol_str = symbol.as_str(); if symbol_str.is_ascii() { continue; @@ -242,7 +242,7 @@ impl EarlyLintPass for NonAsciiIdents { UnordMap::with_capacity(symbols.len()); let mut skeleton_buf = String::new(); - for (&symbol, &sp) in symbols.iter() { + for &(&symbol, &sp) in symbols.iter() { use unicode_security::confusable_detection::skeleton; let symbol_str = symbol.as_str(); @@ -298,7 +298,7 @@ impl EarlyLintPass for NonAsciiIdents { script_states.insert(latin_augmented_script_set, ScriptSetUsage::Verified); let mut has_suspicious = false; - for (symbol, &sp) in symbols.iter() { + for &(ref symbol, &sp) in symbols.iter() { let symbol_str = symbol.as_str(); for ch in symbol_str.chars() { if ch.is_ascii() { diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 5636f80d60020..9e4fdd2b3ceb0 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,13 +1,14 @@ use rustc_abi::ExternAbi; +use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprAttr}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::FnKind; -use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatExprKind, PatKind}; +use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind}; use rustc_middle::ty; use rustc_session::config::CrateType; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::def_id::LocalDefId; use rustc_span::{BytePos, Ident, Span, sym}; -use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_hir as hir}; use crate::lints::{ NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub, @@ -161,10 +162,10 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { - let has_repr_c = it - .attrs - .iter() - .any(|attr| attr::find_repr_attrs(cx.sess(), attr).contains(&attr::ReprC)); + let has_repr_c = matches!( + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, true), + Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) + ); if has_repr_c { return; @@ -273,18 +274,13 @@ impl NonSnakeCase { let ident = ident.trim_start_matches('\''); let ident = ident.trim_matches('_'); - let mut allow_underscore = true; - ident.chars().all(|c| { - allow_underscore = match c { - '_' if !allow_underscore => return false, - '_' => false, - // It would be more obvious to use `c.is_lowercase()`, - // but some characters do not have a lowercase form - c if !c.is_uppercase() => true, - _ => return false, - }; - true - }) + if ident.contains("__") { + return false; + } + + // This correctly handles letters in languages with and without + // cases, as well as numbers and underscores. + !ident.chars().any(char::is_uppercase) } let name = ident.name.as_str(); @@ -341,10 +337,10 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name { Some(Ident::from_str(name)) } else { - ast::attr::find_by_name(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name) - .and_then(|attr| { - if let AttrKind::Normal(n) = &attr.kind - && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: ref lit }, .. } = + ast::attr::find_by_name(cx.tcx.hir_attrs(hir::CRATE_HIR_ID), sym::crate_name).and_then( + |attr| { + if let Attribute::Unparsed(n) = attr + && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } = n.as_ref() && let ast::LitKind::Str(name, ..) = lit.kind { @@ -370,7 +366,8 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } else { None } - }) + }, + ) }; if let Some(ident) = &crate_ident { @@ -499,7 +496,7 @@ impl NonUpperCaseGlobals { impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { - let attrs = cx.tcx.hir().attrs(it.hir_id()); + let attrs = cx.tcx.hir_attrs(it.hir_id()); match it.kind { hir::ItemKind::Static(..) if !ast::attr::contains_name(attrs, sym::no_mangle) => { NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident); diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index 7eaf83f5acf31..f836094191e1d 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -1,9 +1,8 @@ use rustc_hir::{self as hir, AmbigArg}; use rustc_infer::infer::TyCtxtInferExt; use rustc_macros::{LintDiagnostic, Subdiagnostic}; -use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifiersAndPath}; -use rustc_middle::ty::{self, Ty, TypeFoldable}; +use rustc_middle::ty::{self, BottomUpFolder, Ty, TypeFoldable}; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{Span, kw}; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -43,6 +42,7 @@ declare_lint! { /// /// type Tait = impl Sized; /// + /// #[define_opaque(Tait)] /// fn test() -> impl Trait { /// 42 /// } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 68b1f435a4cf7..7be48a769fe33 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,7 +1,7 @@ use std::iter; use std::ops::ControlFlow; -use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange}; +use rustc_abi::{BackendRepr, TagEncoding, VariantIdx, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::intravisit::VisitorExt; @@ -696,7 +696,7 @@ declare_lint! { /// ### Example /// /// ```rust - /// extern "C" { + /// unsafe extern "C" { /// static STATIC: String; /// } /// ``` @@ -882,27 +882,13 @@ fn ty_is_known_nonnull<'tcx>( || Option::unwrap_or_default( try { match **pat { - ty::PatternKind::Range { start, end, include_end } => { - match (start, end) { - (Some(start), None) => { - start.try_to_value()?.try_to_bits(tcx, typing_env)? > 0 - } - (Some(start), Some(end)) => { - let start = - start.try_to_value()?.try_to_bits(tcx, typing_env)?; - let end = - end.try_to_value()?.try_to_bits(tcx, typing_env)?; - - if include_end { - // This also works for negative numbers, as we just need - // to ensure we aren't wrapping over zero. - start > 0 && end >= start - } else { - start > 0 && end > start - } - } - _ => false, - } + ty::PatternKind::Range { start, end } => { + let start = start.try_to_value()?.try_to_bits(tcx, typing_env)?; + let end = end.try_to_value()?.try_to_bits(tcx, typing_env)?; + + // This also works for negative numbers, as we just need + // to ensure we aren't wrapping over zero. + start > 0 && end >= start } } }, @@ -1349,7 +1335,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { ty::FnPtr(sig_tys, hdr) => { let sig = sig_tys.with(hdr); - if self.is_internal_abi(sig.abi()) { + if sig.abi().is_rustic_abi() { return FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_fnptr_reason, @@ -1436,7 +1422,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { struct ProhibitOpaqueTypes; - impl<'tcx> ty::visit::TypeVisitor> for ProhibitOpaqueTypes { + impl<'tcx> ty::TypeVisitor> for ProhibitOpaqueTypes { type Result = ControlFlow>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { @@ -1552,13 +1538,6 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { self.check_type_for_ffi_and_report_errors(span, ty, true, false); } - fn is_internal_abi(&self, abi: ExternAbi) -> bool { - matches!( - abi, - ExternAbi::Rust | ExternAbi::RustCall | ExternAbi::RustCold | ExternAbi::RustIntrinsic - ) - } - /// Find any fn-ptr types with external ABIs in `ty`. /// /// For example, `Option` returns `extern "C" fn()` @@ -1567,17 +1546,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { hir_ty: &hir::Ty<'tcx>, ty: Ty<'tcx>, ) -> Vec<(Ty<'tcx>, Span)> { - struct FnPtrFinder<'a, 'b, 'tcx> { - visitor: &'a ImproperCTypesVisitor<'b, 'tcx>, + struct FnPtrFinder<'tcx> { spans: Vec, tys: Vec>, } - impl<'a, 'b, 'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'a, 'b, 'tcx> { + impl<'tcx> hir::intravisit::Visitor<'_> for FnPtrFinder<'tcx> { fn visit_ty(&mut self, ty: &'_ hir::Ty<'_, AmbigArg>) { debug!(?ty); if let hir::TyKind::BareFn(hir::BareFnTy { abi, .. }) = ty.kind - && !self.visitor.is_internal_abi(*abi) + && !abi.is_rustic_abi() { self.spans.push(ty.span); } @@ -1586,12 +1564,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - impl<'a, 'b, 'tcx> ty::visit::TypeVisitor> for FnPtrFinder<'a, 'b, 'tcx> { - type Result = ControlFlow>; + impl<'tcx> ty::TypeVisitor> for FnPtrFinder<'tcx> { + type Result = (); fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { if let ty::FnPtr(_, hdr) = ty.kind() - && !self.visitor.is_internal_abi(hdr.abi) + && !hdr.abi.is_rustic_abi() { self.tys.push(ty); } @@ -1600,7 +1578,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { } } - let mut visitor = FnPtrFinder { visitor: self, spans: Vec::new(), tys: Vec::new() }; + let mut visitor = FnPtrFinder { spans: Vec::new(), tys: Vec::new() }; ty.visit_with(&mut visitor); visitor.visit_ty_unambig(hir_ty); @@ -1611,17 +1589,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDeclarations { fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, it: &hir::ForeignItem<'tcx>) { let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Declaration }; - let abi = cx.tcx.hir().get_foreign_abi(it.hir_id()); + let abi = cx.tcx.hir_get_foreign_abi(it.hir_id()); match it.kind { hir::ForeignItemKind::Fn(sig, _, _) => { - if vis.is_internal_abi(abi) { + if abi.is_rustic_abi() { vis.check_fn(it.owner_id.def_id, sig.decl) } else { vis.check_foreign_fn(it.owner_id.def_id, sig.decl); } } - hir::ForeignItemKind::Static(ty, _, _) if !vis.is_internal_abi(abi) => { + hir::ForeignItemKind::Static(ty, _, _) if !abi.is_rustic_abi() => { vis.check_foreign_static(it.owner_id, ty.span); } hir::ForeignItemKind::Static(..) | hir::ForeignItemKind::Type => (), @@ -1740,7 +1718,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { hir::ItemKind::Impl(..) | hir::ItemKind::TraitAlias(..) | hir::ItemKind::Trait(..) - | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::GlobalAsm { .. } | hir::ItemKind::ForeignMod { .. } | hir::ItemKind::Mod(..) | hir::ItemKind::Macro(..) @@ -1775,7 +1753,7 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { }; let mut vis = ImproperCTypesVisitor { cx, mode: CItemKind::Definition }; - if vis.is_internal_abi(abi) { + if abi.is_rustic_abi() { vis.check_fn(id, decl); } else { vis.check_foreign_fn(id, decl); @@ -1791,7 +1769,7 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { let t = cx.tcx.type_of(it.owner_id).instantiate_identity(); let ty = cx.tcx.erase_regions(t); let Ok(layout) = cx.layout_of(ty) else { return }; - let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, ref variants, .. } = + let Variants::Multiple { tag_encoding: TagEncoding::Direct, tag, variants, .. } = &layout.variants else { return; diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index 3e4532a6dbeef..7cb00262b6ffa 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -186,7 +186,7 @@ fn report_bin_hex_error( lit_no_suffix, negative_val: actually.clone(), int_ty: int_ty.name_str(), - uint_ty: int_ty.to_unsigned().name_str(), + uint_ty: Integer::fit_unsigned(val).uint_ty_str(), }) }) .flatten(); diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml index 450885e71647f..9ab350daf69d7 100644 --- a/compiler/rustc_lint_defs/Cargo.toml +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_lint_defs" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 10bf4ec77ed93..592c934997c01 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -73,14 +73,12 @@ declare_lint_pass! { NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, NON_CONTIGUOUS_RANGE_ENDPOINTS, NON_EXHAUSTIVE_OMITTED_PATTERNS, - ORDER_DEPENDENT_TRAIT_OBJECTS, OUT_OF_SCOPE_MACRO_CALLS, OVERLAPPING_RANGE_ENDPOINTS, PATTERNS_IN_FNS_WITHOUT_BODY, PRIVATE_BOUNDS, PRIVATE_INTERFACES, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - PTR_CAST_ADD_AUTO_TO_OBJECT, PTR_TO_INTEGER_TRANSMUTE_IN_CONSTS, PUB_USE_OF_PRIVATE_EXTERN_CRATE, REDUNDANT_IMPORTS, @@ -1502,42 +1500,6 @@ declare_lint! { }; } -declare_lint! { - /// The `order_dependent_trait_objects` lint detects a trait coherency - /// violation that would allow creating two trait impls for the same - /// dynamic trait object involving marker traits. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// pub trait Trait {} - /// - /// impl Trait for dyn Send + Sync { } - /// impl Trait for dyn Sync + Send { } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// A previous bug caused the compiler to interpret traits with different - /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types - /// when they were intended to be treated the same. This allowed code to - /// define separate trait implementations when there should be a coherence - /// error. This is a [future-incompatible] lint to transition this to a - /// hard error in the future. See [issue #56484] for more details. - /// - /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484 - /// [future-incompatible]: ../index.md#future-incompatible-lints - pub ORDER_DEPENDENT_TRAIT_OBJECTS, - Deny, - "trait-object types were treated as different depending on marker-trait order", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #56484 ", - }; -} - declare_lint! { /// The `coherence_leak_check` lint detects conflicting implementations of /// a trait that are only distinguished by the old leak-check code. @@ -2711,7 +2673,7 @@ declare_lint! { /// /// ```rust /// const fn foo() -> usize { - /// if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T + /// if size_of::<*mut T>() < 8 { // size of *mut T does not depend on T /// 4 /// } else { /// 8 @@ -2780,7 +2742,7 @@ declare_lint! { /// /// ```rust /// enum Void {} - /// extern { + /// unsafe extern { /// static EXTERN: Void; /// } /// ``` @@ -3782,7 +3744,7 @@ declare_lint! { Warn, "use of unsupported calling convention for function pointer", @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps, + reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, reference: "issue #130260 ", }; } @@ -4011,7 +3973,7 @@ declare_lint! { /// ```rust /// #![warn(ffi_unwind_calls)] /// - /// extern "C-unwind" { + /// unsafe extern "C-unwind" { /// fn foo(); /// } /// @@ -4755,7 +4717,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,edition2021 /// #![warn(missing_unsafe_on_extern)] /// #![allow(dead_code)] /// @@ -4792,7 +4754,7 @@ declare_lint! { /// /// ### Example /// - /// ```rust + /// ```rust,edition2021 /// #![warn(unsafe_attr_outside_unsafe)] /// /// #[no_mangle] @@ -4827,58 +4789,6 @@ declare_lint! { }; } -declare_lint! { - /// The `ptr_cast_add_auto_to_object` lint detects casts of raw pointers to trait - /// objects, which add auto traits. - /// - /// ### Example - /// - /// ```rust,edition2021,compile_fail - /// let ptr: *const dyn core::any::Any = &(); - /// _ = ptr as *const dyn core::any::Any + Send; - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// Adding an auto trait can make the vtable invalid, potentially causing - /// UB in safe code afterwards. For example: - /// - /// ```ignore (causes a warning) - /// #![feature(arbitrary_self_types)] - /// - /// trait Trait { - /// fn f(self: *const Self) - /// where - /// Self: Send; - /// } - /// - /// impl Trait for *const () { - /// fn f(self: *const Self) { - /// unreachable!() - /// } - /// } - /// - /// fn main() { - /// let unsend: *const () = &(); - /// let unsend: *const dyn Trait = &unsend; - /// let send_bad: *const (dyn Trait + Send) = unsend as _; - /// send_bad.f(); // this crashes, since vtable for `*const ()` does not have an entry for `f` - /// } - /// ``` - /// - /// Generally you must ensure that vtable is right for the pointer's type, - /// before passing the pointer to safe code. - pub PTR_CAST_ADD_AUTO_TO_OBJECT, - Warn, - "detects `as` casts from pointers to `dyn Trait` to pointers to `dyn Trait + Auto`", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps, - reference: "issue #127323 ", - }; -} - declare_lint! { /// The `out_of_scope_macro_calls` lint detects `macro_rules` called when they are not in scope, /// above their definition, which may happen in key-value attributes. diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 66fdba28502bd..46b4b1d438386 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,7 +1,3 @@ -// tidy-alphabetical-start -#![warn(unreachable_pub)] -// tidy-alphabetical-end - use rustc_abi::ExternAbi; use rustc_ast::AttrId; use rustc_ast::attr::AttributeExt; @@ -134,8 +130,8 @@ impl LintExpectationId { } pub fn set_lint_index(&mut self, new_lint_index: Option) { - let (LintExpectationId::Unstable { ref mut lint_index, .. } - | LintExpectationId::Stable { ref mut lint_index, .. }) = self; + let (LintExpectationId::Unstable { lint_index, .. } + | LintExpectationId::Stable { lint_index, .. }) = self; *lint_index = new_lint_index } @@ -251,19 +247,23 @@ impl Level { /// Converts an `Attribute` to a level. pub fn from_attr(attr: &impl AttributeExt) -> Option { - Self::from_symbol(attr.name_or_empty(), Some(attr.id())) + Self::from_symbol(attr.name_or_empty(), || Some(attr.id())) } /// Converts a `Symbol` to a level. - pub fn from_symbol(s: Symbol, id: Option) -> Option { - match (s, id) { - (sym::allow, _) => Some(Level::Allow), - (sym::expect, Some(attr_id)) => { - Some(Level::Expect(LintExpectationId::Unstable { attr_id, lint_index: None })) + pub fn from_symbol(s: Symbol, id: impl FnOnce() -> Option) -> Option { + match s { + sym::allow => Some(Level::Allow), + sym::expect => { + if let Some(attr_id) = id() { + Some(Level::Expect(LintExpectationId::Unstable { attr_id, lint_index: None })) + } else { + None + } } - (sym::warn, _) => Some(Level::Warn), - (sym::deny, _) => Some(Level::Deny), - (sym::forbid, _) => Some(Level::Forbid), + sym::warn => Some(Level::Warn), + sym::deny => Some(Level::Deny), + sym::forbid => Some(Level::Forbid), _ => None, } } diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 2168a0df9ec87..061562b2ec5ed 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_llvm" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -12,5 +12,5 @@ libc = "0.2.73" # tidy-alphabetical-start # Pinned so `cargo update` bumps don't cause breakage. Please also update the # pinned `cc` in `rustc_codegen_ssa` if you update `cc` here. -cc = "=1.2.13" +cc = "=1.2.16" # tidy-alphabetical-end diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 48806888b43df..3d1f3b2cd4dd4 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -51,9 +51,13 @@ fn detect_llvm_link() -> (&'static str, &'static str) { fn restore_library_path() { let key = tracked_env_var_os("REAL_LIBRARY_PATH_VAR").expect("REAL_LIBRARY_PATH_VAR"); if let Some(env) = tracked_env_var_os("REAL_LIBRARY_PATH") { - env::set_var(&key, env); + unsafe { + env::set_var(&key, env); + } } else { - env::remove_var(&key); + unsafe { + env::remove_var(&key); + } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 9ce4abdb432e8..86f1bcc46eea1 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -7,6 +7,7 @@ #include "llvm/Analysis/Lint.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/CodeGen/CommandFlags.h" #include "llvm/IR/AssemblyAnnotationWriter.h" #include "llvm/IR/AutoUpgrade.h" @@ -37,6 +38,7 @@ #include "llvm/Transforms/Instrumentation/InstrProfiling.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" +#include "llvm/Transforms/Scalar/AnnotationRemarks.h" #include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/FunctionImportUtils.h" #include "llvm/Transforms/Utils/NameAnonGlobals.h" @@ -195,6 +197,19 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { GEN_SUBTARGETS #undef SUBTARGET +// This struct and various functions are sort of a hack right now, but the +// problem is that we've got in-memory LLVM modules after we generate and +// optimize all codegen-units for one compilation in rustc. To be compatible +// with the LTO support above we need to serialize the modules plus their +// ThinLTO summary into memory. +// +// This structure is basically an owned version of a serialize module, with +// a ThinLTO summary attached. +struct LLVMRustThinLTOBuffer { + std::string data; + std::string thin_link_data; +}; + extern "C" bool LLVMRustHasFeature(LLVMTargetMachineRef TM, const char *Feature) { TargetMachine *Target = unwrap(TM); @@ -469,7 +484,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( if (ArgsCstrBuff != nullptr) { #if LLVM_VERSION_GE(20, 0) - int buffer_offset = 0; + size_t buffer_offset = 0; assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); auto Arg0 = std::string(ArgsCstrBuff); buffer_offset = Arg0.size() + 1; @@ -487,7 +502,7 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.MCOptions.Argv0 = Arg0; Options.MCOptions.CommandlineArgs = CommandlineArgs; #else - int buffer_offset = 0; + size_t buffer_offset = 0; assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); const size_t arg0_len = std::strlen(ArgsCstrBuff); @@ -496,13 +511,13 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( arg0[arg0_len] = '\0'; buffer_offset += arg0_len + 1; - const int num_cmd_arg_strings = std::count( + const size_t num_cmd_arg_strings = std::count( &ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0'); std::string *cmd_arg_strings = new std::string[num_cmd_arg_strings]; - for (int i = 0; i < num_cmd_arg_strings; ++i) { + for (size_t i = 0; i < num_cmd_arg_strings; ++i) { assert(buffer_offset < ArgsCstrBuffLen); - const int len = std::strlen(ArgsCstrBuff + buffer_offset); + const size_t len = std::strlen(ArgsCstrBuff + buffer_offset); cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len); buffer_offset += len + 1; } @@ -704,7 +719,8 @@ extern "C" LLVMRustResult LLVMRustOptimize( LLVMModuleRef ModuleRef, LLVMTargetMachineRef TMRef, LLVMRustPassBuilderOptLevel OptLevelRust, LLVMRustOptStage OptStage, bool IsLinkerPluginLTO, bool NoPrepopulatePasses, bool VerifyIR, - bool LintIR, bool UseThinLTOBuffers, bool MergeFunctions, bool UnrollLoops, + bool LintIR, LLVMRustThinLTOBuffer **ThinLTOBufferRef, bool EmitThinLTO, + bool EmitThinLTOSummary, bool MergeFunctions, bool UnrollLoops, bool SLPVectorize, bool LoopVectorize, bool DisableSimplifyLibCalls, bool EmitLifetimeMarkers, bool RunEnzyme, LLVMRustSanitizerOptions *SanitizerOptions, const char *PGOGenPath, @@ -952,7 +968,10 @@ extern "C" LLVMRustResult LLVMRustOptimize( } ModulePassManager MPM; - bool NeedThinLTOBufferPasses = UseThinLTOBuffers; + bool NeedThinLTOBufferPasses = EmitThinLTO; + auto ThinLTOBuffer = std::make_unique(); + raw_string_ostream ThinLTODataOS(ThinLTOBuffer->data); + raw_string_ostream ThinLinkDataOS(ThinLTOBuffer->thin_link_data); if (!NoPrepopulatePasses) { // The pre-link pipelines don't support O0 and require using // buildO0DefaultPipeline() instead. At the same time, the LTO pipelines do @@ -976,7 +995,25 @@ extern "C" LLVMRustResult LLVMRustOptimize( switch (OptStage) { case LLVMRustOptStage::PreLinkNoLTO: - MPM = PB.buildPerModuleDefaultPipeline(OptLevel); + if (ThinLTOBufferRef) { + // This is similar to LLVM's `buildFatLTODefaultPipeline`, where the + // bitcode for embedding is obtained after performing + // `ThinLTOPreLinkDefaultPipeline`. + MPM.addPass(PB.buildThinLTOPreLinkDefaultPipeline(OptLevel)); + if (EmitThinLTO) { + MPM.addPass(ThinLTOBitcodeWriterPass( + ThinLTODataOS, EmitThinLTOSummary ? &ThinLinkDataOS : nullptr)); + } else { + MPM.addPass(BitcodeWriterPass(ThinLTODataOS)); + } + *ThinLTOBufferRef = ThinLTOBuffer.release(); + MPM.addPass(PB.buildModuleOptimizationPipeline( + OptLevel, ThinOrFullLTOPhase::None)); + MPM.addPass( + createModuleToFunctionPassAdaptor(AnnotationRemarksPass())); + } else { + MPM = PB.buildPerModuleDefaultPipeline(OptLevel); + } break; case LLVMRustOptStage::PreLinkThinLTO: MPM = PB.buildThinLTOPreLinkDefaultPipeline(OptLevel); @@ -1022,6 +1059,16 @@ extern "C" LLVMRustResult LLVMRustOptimize( MPM.addPass(CanonicalizeAliasesPass()); MPM.addPass(NameAnonGlobalPass()); } + // For `-Copt-level=0`, ThinLTO, or LTO. + if (ThinLTOBufferRef && *ThinLTOBufferRef == nullptr) { + if (EmitThinLTO) { + MPM.addPass(ThinLTOBitcodeWriterPass( + ThinLTODataOS, EmitThinLTOSummary ? &ThinLinkDataOS : nullptr)); + } else { + MPM.addPass(BitcodeWriterPass(ThinLTODataOS)); + } + *ThinLTOBufferRef = ThinLTOBuffer.release(); + } // now load "-enzyme" pass: #ifdef ENZYME @@ -1500,19 +1547,6 @@ extern "C" bool LLVMRustPrepareThinLTOImport(const LLVMRustThinLTOData *Data, return true; } -// This struct and various functions are sort of a hack right now, but the -// problem is that we've got in-memory LLVM modules after we generate and -// optimize all codegen-units for one compilation in rustc. To be compatible -// with the LTO support above we need to serialize the modules plus their -// ThinLTO summary into memory. -// -// This structure is basically an owned version of a serialize module, with -// a ThinLTO summary attached. -struct LLVMRustThinLTOBuffer { - std::string data; - std::string thin_link_data; -}; - extern "C" LLVMRustThinLTOBuffer * LLVMRustThinLTOBufferCreate(LLVMModuleRef M, bool is_thin, bool emit_summary) { auto Ret = std::make_unique(); @@ -1648,12 +1682,21 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, #endif // Based on the 'InProcessThinBackend' constructor in LLVM +#if LLVM_VERSION_GE(21, 0) + for (auto &Name : Data->Index.cfiFunctionDefs().symbols()) + CfiFunctionDefs.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + for (auto &Name : Data->Index.cfiFunctionDecls().symbols()) + CfiFunctionDecls.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); +#else for (auto &Name : Data->Index.cfiFunctionDefs()) CfiFunctionDefs.insert( GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); for (auto &Name : Data->Index.cfiFunctionDecls()) CfiFunctionDecls.insert( GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); +#endif #if LLVM_VERSION_GE(20, 0) Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList, diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index b8cef6a7e250e..53df59930f4fd 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -152,8 +152,12 @@ extern "C" LLVMContextRef LLVMRustContextCreate(bool shouldDiscardNames) { } extern "C" void LLVMRustSetNormalizedTarget(LLVMModuleRef M, - const char *Triple) { - unwrap(M)->setTargetTriple(Triple::normalize(Triple)); + const char *Target) { +#if LLVM_VERSION_GE(21, 0) + unwrap(M)->setTargetTriple(Triple(Triple::normalize(Target))); +#else + unwrap(M)->setTargetTriple(Triple::normalize(Target)); +#endif } extern "C" void LLVMRustPrintPassTimings(RustStringRef OutBuf) { @@ -1767,6 +1771,24 @@ extern "C" LLVMValueRef LLVMRustBuildMaxNum(LLVMBuilderRef B, LLVMValueRef LHS, return wrap(unwrap(B)->CreateMaxNum(unwrap(LHS), unwrap(RHS))); } +#if LLVM_VERSION_LT(19, 0) +enum { + LLVMGEPFlagInBounds = (1 << 0), + LLVMGEPFlagNUSW = (1 << 1), + LLVMGEPFlagNUW = (1 << 2), +}; +extern "C" LLVMValueRef +LLVMBuildGEPWithNoWrapFlags(LLVMBuilderRef B, LLVMTypeRef Ty, + LLVMValueRef Pointer, LLVMValueRef *Indices, + unsigned NumIndices, const char *Name, + unsigned NoWrapFlags) { + if (NoWrapFlags & LLVMGEPFlagInBounds) + return LLVMBuildInBoundsGEP2(B, Ty, Pointer, Indices, NumIndices, Name); + else + return LLVMBuildGEP2(B, Ty, Pointer, Indices, NumIndices, Name); +} +#endif + // Transfers ownership of DiagnosticHandler unique_ptr to the caller. extern "C" DiagnosticHandler * LLVMRustContextGetDiagnosticHandler(LLVMContextRef C) { diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index eda9b2b1fc092..68058250a2671 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -4,7 +4,6 @@ #![doc(rust_logo)] #![feature(extern_types)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cell::RefCell; diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml index fe399bc77e32a..30f6e9ba8053f 100644 --- a/compiler/rustc_log/Cargo.toml +++ b/compiler/rustc_log/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_log" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml index d8d2bef496404..f9d3b75835907 100644 --- a/compiler/rustc_macros/Cargo.toml +++ b/compiler/rustc_macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_macros" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] proc-macro = true diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 612a36ba9aa57..060799e981d46 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -760,8 +760,8 @@ impl SubdiagnosticVariant { } ( "applicability", - SubdiagnosticKind::Suggestion { ref mut applicability, .. } - | SubdiagnosticKind::MultipartSuggestion { ref mut applicability, .. }, + SubdiagnosticKind::Suggestion { applicability, .. } + | SubdiagnosticKind::MultipartSuggestion { applicability, .. }, ) => { let value = get_string!(); let value = Applicability::from_str(&value.value()).unwrap_or_else(|()| { diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs index 0df674eb4c909..edb25e799045a 100644 --- a/compiler/rustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -6,7 +6,6 @@ #![feature(proc_macro_diagnostic)] #![feature(proc_macro_span)] #![feature(proc_macro_tracked_env)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use proc_macro::TokenStream; @@ -17,6 +16,7 @@ mod diagnostics; mod extension; mod hash_stable; mod lift; +mod print_attribute; mod query; mod serialize; mod symbols; @@ -74,8 +74,8 @@ decl_derive!( hash_stable::hash_stable_no_context_derive ); -decl_derive!([Decodable_Generic] => serialize::decodable_generic_derive); -decl_derive!([Encodable_Generic] => serialize::encodable_generic_derive); +decl_derive!([Decodable_NoContext] => serialize::decodable_nocontext_derive); +decl_derive!([Encodable_NoContext] => serialize::encodable_nocontext_derive); decl_derive!([Decodable] => serialize::decodable_derive); decl_derive!([Encodable] => serialize::encodable_derive); decl_derive!([TyDecodable] => serialize::type_decodable_derive); @@ -175,3 +175,11 @@ decl_derive! { /// The error type is `u32`. try_from::try_from_u32 } +decl_derive! { + [PrintAttribute] => + /// Derives `PrintAttribute` for `AttributeKind`. + /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in + /// other places. It's deriving something close to `Debug` without printing some extraenous + /// things like spans. + print_attribute::print_attribute +} diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs new file mode 100644 index 0000000000000..42d94e72ee942 --- /dev/null +++ b/compiler/rustc_macros/src/print_attribute.rs @@ -0,0 +1,150 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote, quote_spanned}; +use syn::spanned::Spanned; +use syn::{Data, Fields, Ident}; +use synstructure::Structure; + +fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, TokenStream) { + let string_name = name.to_string(); + let mut disps = vec![quote! {let mut __printed_anything = false;}]; + + match fields { + Fields::Named(fields_named) => { + let mut field_names = Vec::new(); + + for field in &fields_named.named { + let name = field.ident.as_ref().unwrap(); + let string_name = name.to_string(); + disps.push(quote! { + if #name.should_render() { + if __printed_anything { + __p.word_space(","); + } + __p.word(#string_name); + __p.word_space(":"); + __printed_anything = true; + } + #name.print_attribute(__p); + }); + field_names.push(name); + } + + ( + quote! { {#(#field_names),*} }, + quote! { + __p.word(#string_name); + if true #(&& !#field_names.should_render())* { + return; + } + + __p.nbsp(); + __p.word("{"); + #(#disps)* + __p.word("}"); + }, + quote! { true }, + ) + } + Fields::Unnamed(fields_unnamed) => { + let mut field_names = Vec::new(); + + for idx in 0..fields_unnamed.unnamed.len() { + let name = format_ident!("f{idx}"); + disps.push(quote! { + if #name.should_render() { + if __printed_anything { + __p.word_space(","); + } + __printed_anything = true; + } + #name.print_attribute(__p); + }); + field_names.push(name); + } + + ( + quote! { (#(#field_names),*) }, + quote! { + __p.word(#string_name); + + if true #(&& !#field_names.should_render())* { + return; + } + + __p.popen(); + #(#disps)* + __p.pclose(); + }, + quote! { true }, + ) + } + Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }, quote! { true }), + } +} + +pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream { + let span_error = |span, message: &str| { + quote_spanned! { span => const _: () = ::core::compile_error!(#message); } + }; + + // Must be applied to an enum type. + let (code, printed) = match &input.ast().data { + Data::Enum(e) => { + let (arms, printed) = e + .variants + .iter() + .map(|x| { + let ident = &x.ident; + let (pat, code, printed) = print_fields(ident, &x.fields); + + ( + quote! { + Self::#ident #pat => {#code} + }, + quote! { + Self::#ident #pat => {#printed} + }, + ) + }) + .unzip::<_, _, Vec<_>, Vec<_>>(); + + ( + quote! { + match self { + #(#arms)* + } + }, + quote! { + match self { + #(#printed)* + } + }, + ) + } + Data::Struct(s) => { + let (pat, code, printed) = print_fields(&input.ast().ident, &s.fields); + ( + quote! { + let Self #pat = self; + #code + }, + quote! { + let Self #pat = self; + #printed + }, + ) + } + Data::Union(u) => { + return span_error(u.union_token.span(), "can't derive PrintAttribute on unions"); + } + }; + + #[allow(keyword_idents_2024)] + input.gen_impl(quote! { + #[allow(unused)] + gen impl PrintAttribute for @Self { + fn should_render(&self) -> bool { #printed } + fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code } + } + }) +} diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs index 2c33a0ac0aafe..673e6cd618ff8 100644 --- a/compiler/rustc_macros/src/serialize.rs +++ b/compiler/rustc_macros/src/serialize.rs @@ -6,16 +6,11 @@ use syn::spanned::Spanned; pub(super) fn type_decodable_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { + if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { + s.add_impl_generic(parse_quote! { 'tcx }); + } let decoder_ty = quote! { __D }; - let bound = if s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { - quote! { > } - } else if s.ast().generics.type_params().any(|ty| ty.ident == "I") { - quote! { } - } else { - quote! {} - }; - - s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_type_ir::codec::TyDecoder #bound }); + s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_middle::ty::codec::TyDecoder<'tcx> }); s.add_bounds(synstructure::AddBounds::Fields); s.underscore_const(true); @@ -45,12 +40,12 @@ pub(super) fn decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro decodable_body(s, decoder_ty) } -pub(super) fn decodable_generic_derive( +pub(super) fn decodable_nocontext_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { let decoder_ty = quote! { __D }; s.add_impl_generic(parse_quote! { #decoder_ty: ::rustc_serialize::Decoder }); - s.add_bounds(synstructure::AddBounds::Generics); + s.add_bounds(synstructure::AddBounds::Fields); s.underscore_const(true); decodable_body(s, decoder_ty) @@ -132,16 +127,11 @@ fn decode_field(field: &syn::Field) -> proc_macro2::TokenStream { pub(super) fn type_encodable_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { - let bound = if s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { - quote! { > } - } else if s.ast().generics.type_params().any(|ty| ty.ident == "I") { - quote! { } - } else { - quote! {} - }; - let encoder_ty = quote! { __E }; - s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_type_ir::codec::TyEncoder #bound }); + if !s.ast().generics.lifetimes().any(|lt| lt.lifetime.ident == "tcx") { + s.add_impl_generic(parse_quote! { 'tcx }); + } + s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_middle::ty::codec::TyEncoder<'tcx> }); s.add_bounds(synstructure::AddBounds::Fields); s.underscore_const(true); @@ -171,12 +161,12 @@ pub(super) fn encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro encodable_body(s, encoder_ty, false) } -pub(super) fn encodable_generic_derive( +pub(super) fn encodable_nocontext_derive( mut s: synstructure::Structure<'_>, ) -> proc_macro2::TokenStream { let encoder_ty = quote! { __E }; s.add_impl_generic(parse_quote! { #encoder_ty: ::rustc_serialize::Encoder }); - s.add_bounds(synstructure::AddBounds::Generics); + s.add_bounds(synstructure::AddBounds::Fields); s.underscore_const(true); encodable_body(s, encoder_ty, false) diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs index bc3b82c2893fa..c4f584dca430a 100644 --- a/compiler/rustc_macros/src/type_foldable.rs +++ b/compiler/rustc_macros/src/type_foldable.rs @@ -38,16 +38,16 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m bind.to_token_stream() } else { quote! { - ::rustc_middle::ty::fold::TypeFoldable::try_fold_with(#bind, __folder)? + ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)? } } }) }); s.bound_impl( - quote!(::rustc_middle::ty::fold::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>), + quote!(::rustc_middle::ty::TypeFoldable<::rustc_middle::ty::TyCtxt<'tcx>>), quote! { - fn try_fold_with<__F: ::rustc_middle::ty::fold::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( + fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>( self, __folder: &mut __F ) -> Result { diff --git a/compiler/rustc_macros/src/type_visitable.rs b/compiler/rustc_macros/src/type_visitable.rs index a7906d50d0f2d..fb37e1a39edbe 100644 --- a/compiler/rustc_macros/src/type_visitable.rs +++ b/compiler/rustc_macros/src/type_visitable.rs @@ -36,12 +36,12 @@ pub(super) fn type_visitable_derive( s.add_bounds(synstructure::AddBounds::Generics); let body_visit = s.each(|bind| { quote! { - match ::rustc_middle::ty::visit::VisitorResult::branch( - ::rustc_middle::ty::visit::TypeVisitable::visit_with(#bind, __visitor) + match ::rustc_middle::ty::VisitorResult::branch( + ::rustc_middle::ty::TypeVisitable::visit_with(#bind, __visitor) ) { ::core::ops::ControlFlow::Continue(()) => {}, ::core::ops::ControlFlow::Break(r) => { - return ::rustc_middle::ty::visit::VisitorResult::from_residual(r); + return ::rustc_middle::ty::VisitorResult::from_residual(r); }, } } @@ -49,14 +49,14 @@ pub(super) fn type_visitable_derive( s.bind_with(|_| synstructure::BindStyle::Move); s.bound_impl( - quote!(::rustc_middle::ty::visit::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>), + quote!(::rustc_middle::ty::TypeVisitable<::rustc_middle::ty::TyCtxt<'tcx>>), quote! { - fn visit_with<__V: ::rustc_middle::ty::visit::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>( + fn visit_with<__V: ::rustc_middle::ty::TypeVisitor<::rustc_middle::ty::TyCtxt<'tcx>>>( &self, __visitor: &mut __V ) -> __V::Result { match *self { #body_visit } - <__V::Result as ::rustc_middle::ty::visit::VisitorResult>::output() + <__V::Result as ::rustc_middle::ty::VisitorResult>::output() } }, ) diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 0b9fdbbd3da8d..1f5d41014d4f5 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_metadata" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -27,7 +27,6 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -rustc_type_ir = { path = "../rustc_type_ir" } tempfile = "3.2" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index 6fc84b06647f5..20f66fae5c01e 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -47,6 +47,9 @@ metadata_crate_dep_rustc_driver = metadata_crate_location_unknown_type = extern location for {$crate_name} is of an unknown type: {$path} +metadata_crate_not_compiler_builtins = + the crate `{$crate_name}` resolved as `compiler_builtins` but is not `#![compiler_builtins]` + metadata_crate_not_panic_runtime = the crate `{$crate_name}` is not a panic runtime @@ -241,6 +244,9 @@ metadata_prev_alloc_error_handler = metadata_prev_global_alloc = previous global allocator defined here +metadata_raw_dylib_elf_unstable = + link kind `raw-dylib` is unstable on ELF platforms + metadata_raw_dylib_no_nul = link name must not contain NUL characters if link kind is `raw-dylib` diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index c2dda21bb72e6..12503ffd1a67f 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -32,7 +32,7 @@ use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; use rustc_span::edition::Edition; -use rustc_span::{DUMMY_SP, Ident, STDLIB_STABLE_CRATES, Span, Symbol, sym}; +use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; use rustc_target::spec::{PanicStrategy, Target, TargetTuple}; use tracing::{debug, info, trace}; @@ -147,6 +147,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { writeln!(fmt, " cnum: {cnum}")?; writeln!(fmt, " hash: {}", data.hash())?; writeln!(fmt, " reqd: {:?}", data.dep_kind())?; + writeln!(fmt, " priv: {:?}", data.is_private_dep())?; let CrateSource { dylib, rlib, rmeta } = data.source(); if let Some(dylib) = dylib { writeln!(fmt, " dylib: {}", dylib.0.display())?; @@ -162,6 +163,53 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { } } +/// Reason that a crate is being sourced as a dependency. +#[derive(Clone, Copy)] +enum CrateOrigin<'a> { + /// This crate was a dependency of another crate. + IndirectDependency { + /// Where this dependency was included from. + dep_root: &'a CratePaths, + /// True if the parent is private, meaning the dependent should also be private. + parent_private: bool, + /// Dependency info about this crate. + dep: &'a CrateDep, + }, + /// Injected by `rustc`. + Injected, + /// Provided by `extern crate foo` or as part of the extern prelude. + Extern, +} + +impl<'a> CrateOrigin<'a> { + /// Return the dependency root, if any. + fn dep_root(&self) -> Option<&'a CratePaths> { + match self { + CrateOrigin::IndirectDependency { dep_root, .. } => Some(dep_root), + _ => None, + } + } + + /// Return dependency information, if any. + fn dep(&self) -> Option<&'a CrateDep> { + match self { + CrateOrigin::IndirectDependency { dep, .. } => Some(dep), + _ => None, + } + } + + /// `Some(true)` if the dependency is private or its parent is private, `Some(false)` if the + /// dependency is not private, `None` if it could not be determined. + fn private_dep(&self) -> Option { + match self { + CrateOrigin::IndirectDependency { parent_private, dep, .. } => { + Some(dep.is_private || *parent_private) + } + _ => None, + } + } +} + impl CStore { pub fn from_tcx(tcx: TyCtxt<'_>) -> FreezeReadGuard<'_, CStore> { FreezeReadGuard::map(tcx.untracked().cstore.read(), |cstore| { @@ -497,25 +545,13 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { &self, name: Symbol, private_dep: Option, - dep_root: Option<&CratePaths>, + origin: CrateOrigin<'_>, ) -> bool { - // Standard library crates are never private. - if STDLIB_STABLE_CRATES.contains(&name) { - tracing::info!("returning false for {name} is private"); - return false; - } - - let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep); - - // Any descendants of `std` should be private. These crates are usually not marked - // private in metadata, so we ignore that field. - if extern_private.is_none() - && let Some(dep) = dep_root - && STDLIB_STABLE_CRATES.contains(&dep.name) - { + if matches!(origin, CrateOrigin::Injected) { return true; } + let extern_private = self.sess.opts.externs.get(name.as_str()).map(|e| e.is_private_dep); match (extern_private, private_dep) { // Explicit non-private via `--extern`, explicit non-private from metadata, or // unspecified with default to public. @@ -528,7 +564,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { fn register_crate( &mut self, host_lib: Option, - dep_root: Option<&CratePaths>, + origin: CrateOrigin<'_>, lib: Library, dep_kind: CrateDepKind, name: Symbol, @@ -540,7 +576,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { let Library { source, metadata } = lib; let crate_root = metadata.get_root(); let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash()); - let private_dep = self.is_private_dep(name, private_dep, dep_root); + let private_dep = self.is_private_dep(name, private_dep, origin); // Claim this crate number and cache it let feed = self.cstore.intern_stable_crate_id(&crate_root, self.tcx)?; @@ -556,14 +592,15 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Maintain a reference to the top most crate. // Stash paths for top-most crate locally if necessary. let crate_paths; - let dep_root = if let Some(dep_root) = dep_root { + let dep_root = if let Some(dep_root) = origin.dep_root() { dep_root } else { crate_paths = CratePaths::new(crate_root.name(), source.clone()); &crate_paths }; - let cnum_map = self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind)?; + let cnum_map = + self.resolve_crate_deps(dep_root, &crate_root, &metadata, cnum, dep_kind, private_dep)?; let raw_proc_macros = if crate_root.is_proc_macro_crate() { let temp_root; @@ -664,17 +701,19 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { name: Symbol, span: Span, dep_kind: CrateDepKind, + origin: CrateOrigin<'_>, ) -> Option { self.used_extern_options.insert(name); - match self.maybe_resolve_crate(name, dep_kind, None) { + match self.maybe_resolve_crate(name, dep_kind, origin) { Ok(cnum) => { self.cstore.set_used_recursively(cnum); Some(cnum) } Err(err) => { debug!("failed to resolve crate {} {:?}", name, dep_kind); - let missing_core = - self.maybe_resolve_crate(sym::core, CrateDepKind::Explicit, None).is_err(); + let missing_core = self + .maybe_resolve_crate(sym::core, CrateDepKind::Explicit, CrateOrigin::Extern) + .is_err(); err.report(self.sess, span, missing_core); None } @@ -685,20 +724,20 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { &'b mut self, name: Symbol, mut dep_kind: CrateDepKind, - dep_of: Option<(&'b CratePaths, &'b CrateDep)>, + origin: CrateOrigin<'b>, ) -> Result { info!("resolving crate `{}`", name); if !name.as_str().is_ascii() { return Err(CrateError::NonAsciiName(name)); } - let dep_root = dep_of.map(|d| d.0); - let dep = dep_of.map(|d| d.1); + let dep_root = origin.dep_root(); + let dep = origin.dep(); let hash = dep.map(|d| d.hash); let host_hash = dep.map(|d| d.host_hash).flatten(); let extra_filename = dep.map(|d| &d.extra_filename[..]); let path_kind = if dep.is_some() { PathKind::Dependency } else { PathKind::Crate }; - let private_dep = dep.map(|d| d.is_private); + let private_dep = origin.private_dep(); let result = if let Some(cnum) = self.existing_match(name, hash, path_kind) { (LoadResult::Previous(cnum), None) @@ -731,12 +770,12 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { match result { (LoadResult::Previous(cnum), None) => { - info!("library for `{}` was loaded previously", name); + info!("library for `{}` was loaded previously, cnum {cnum}", name); // When `private_dep` is none, it indicates the directly dependent crate. If it is // not specified by `--extern` on command line parameters, it may be // `private-dependency` when `register_crate` is called for the first time. Then it must be updated to // `public-dependency` here. - let private_dep = self.is_private_dep(name, private_dep, dep_root); + let private_dep = self.is_private_dep(name, private_dep, origin); let data = self.cstore.get_crate_data_mut(cnum); if data.is_proc_macro_crate() { dep_kind = CrateDepKind::MacrosOnly; @@ -747,7 +786,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } (LoadResult::Loaded(library), host_library) => { info!("register newly loaded library for `{}`", name); - self.register_crate(host_library, dep_root, library, dep_kind, name, private_dep) + self.register_crate(host_library, origin, library, dep_kind, name, private_dep) } _ => panic!(), } @@ -762,29 +801,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // against a hash, we could load a crate which has the same hash // as an already loaded crate. If this is the case prevent // duplicates by just using the first crate. - // - // Note that we only do this for target triple crates, though, as we - // don't want to match a host crate against an equivalent target one - // already loaded. let root = library.metadata.get_root(); - // FIXME: why is this condition necessary? It was adding in #33625 but I - // don't know why and the original author doesn't remember ... - let can_reuse_cratenum = - locator.tuple == self.sess.opts.target_triple || locator.is_proc_macro; - Ok(Some(if can_reuse_cratenum { - let mut result = LoadResult::Loaded(library); - for (cnum, data) in self.cstore.iter_crate_data() { - if data.name() == root.name() && root.hash() == data.hash() { - assert!(locator.hash.is_none()); - info!("load success, going to previous cnum: {}", cnum); - result = LoadResult::Previous(cnum); - break; - } + let mut result = LoadResult::Loaded(library); + for (cnum, data) in self.cstore.iter_crate_data() { + if data.name() == root.name() && root.hash() == data.hash() { + assert!(locator.hash.is_none()); + info!("load success, going to previous cnum: {}", cnum); + result = LoadResult::Previous(cnum); + break; } - result - } else { - LoadResult::Loaded(library) - })) + } + Ok(Some(result)) } /// Go through the crate metadata and load any crates that it references. @@ -795,6 +822,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { metadata: &MetadataBlob, krate: CrateNum, dep_kind: CrateDepKind, + parent_is_private: bool, ) -> Result { debug!( "resolving deps of external crate `{}` with dep root `{}`", @@ -813,17 +841,26 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { crate_num_map.push(krate); for dep in deps { info!( - "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}`", + "resolving dep `{}`->`{}` hash: `{}` extra filename: `{}` private {}", crate_root.name(), dep.name, dep.hash, - dep.extra_filename + dep.extra_filename, + dep.is_private, ); let dep_kind = match dep_kind { CrateDepKind::MacrosOnly => CrateDepKind::MacrosOnly, _ => dep.kind, }; - let cnum = self.maybe_resolve_crate(dep.name, dep_kind, Some((dep_root, &dep)))?; + let cnum = self.maybe_resolve_crate( + dep.name, + dep_kind, + CrateOrigin::IndirectDependency { + dep_root, + parent_private: parent_is_private, + dep: &dep, + }, + )?; crate_num_map.push(cnum); } @@ -917,7 +954,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { }; info!("panic runtime not found -- loading {}", name); - let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { + let Some(cnum) = + self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) + else { return; }; let data = self.cstore.get_crate_data(cnum); @@ -946,7 +985,9 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { info!("loading profiler"); let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime); - let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else { + let Some(cnum) = + self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit, CrateOrigin::Injected) + else { return; }; let data = self.cstore.get_crate_data(cnum); @@ -1059,12 +1100,54 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { if entry.force { let name_interned = Symbol::intern(name); if !self.used_extern_options.contains(&name_interned) { - self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit); + self.resolve_crate( + name_interned, + DUMMY_SP, + CrateDepKind::Explicit, + CrateOrigin::Extern, + ); } } } } + /// Inject the `compiler_builtins` crate if it is not already in the graph. + fn inject_compiler_builtins(&mut self, krate: &ast::Crate) { + // `compiler_builtins` does not get extern builtins, nor do `#![no_core]` crates + if attr::contains_name(&krate.attrs, sym::compiler_builtins) + || attr::contains_name(&krate.attrs, sym::no_core) + { + info!("`compiler_builtins` unneeded"); + return; + } + + // If a `#![compiler_builtins]` crate already exists, avoid injecting it twice. This is + // the common case since usually it appears as a dependency of `std` or `alloc`. + for (cnum, cmeta) in self.cstore.iter_crate_data() { + if cmeta.is_compiler_builtins() { + info!("`compiler_builtins` already exists (cnum = {cnum}); skipping injection"); + return; + } + } + + // `compiler_builtins` is not yet in the graph; inject it. Error on resolution failure. + let Some(cnum) = self.resolve_crate( + sym::compiler_builtins, + krate.spans.inner_span.shrink_to_lo(), + CrateDepKind::Explicit, + CrateOrigin::Injected, + ) else { + info!("`compiler_builtins` not resolved"); + return; + }; + + // Sanity check that the loaded crate is `#![compiler_builtins]` + let cmeta = self.cstore.get_crate_data(cnum); + if !cmeta.is_compiler_builtins() { + self.dcx().emit_err(errors::CrateNotCompilerBuiltins { crate_name: cmeta.name() }); + } + } + fn inject_dependency_if( &mut self, krate: CrateNum, @@ -1174,6 +1257,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } pub fn postprocess(&mut self, krate: &ast::Crate) { + self.inject_compiler_builtins(krate); self.inject_forced_externs(); self.inject_profiler_runtime(); self.inject_allocator_crate(krate); @@ -1185,6 +1269,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { info!("{:?}", CrateDump(self.cstore)); } + /// Process an `extern crate foo` AST node. pub fn process_extern_crate( &mut self, item: &ast::Item, @@ -1210,7 +1295,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { CrateDepKind::Explicit }; - let cnum = self.resolve_crate(name, item.span, dep_kind)?; + let cnum = self.resolve_crate(name, item.span, dep_kind, CrateOrigin::Extern)?; let path_len = definitions.def_path(def_id).data.len(); self.cstore.update_extern_crate( @@ -1229,7 +1314,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } pub fn process_path_extern(&mut self, name: Symbol, span: Span) -> Option { - let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit)?; + let cnum = self.resolve_crate(name, span, CrateDepKind::Explicit, CrateOrigin::Extern)?; self.cstore.update_extern_crate( cnum, @@ -1246,7 +1331,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { } pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { - self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok() + self.maybe_resolve_crate(name, CrateDepKind::Explicit, CrateOrigin::Extern).ok() } } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index 582c2215d92e1..be31aa629c86e 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -84,7 +84,7 @@ pub(crate) fn calculate(tcx: TyCtxt<'_>) -> Dependencies { fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let sess = &tcx.sess; - if !sess.opts.output_types.should_codegen() { + if !sess.opts.output_types.should_link() { return IndexVec::new(); } diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index a77f9bc623b5b..2ad6389c0b4ac 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -332,6 +332,12 @@ pub struct CrateNotPanicRuntime { pub crate_name: Symbol, } +#[derive(Diagnostic)] +#[diag(metadata_crate_not_compiler_builtins)] +pub struct CrateNotCompilerBuiltins { + pub crate_name: Symbol, +} + #[derive(Diagnostic)] #[diag(metadata_no_panic_strategy)] pub struct NoPanicStrategy { diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index b817b4cb7b83c..028d5c8b60996 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,11 +1,11 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(coroutines)] #![feature(decl_macro)] #![feature(error_iter)] -#![feature(extract_if)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(iter_from_coroutine)] @@ -16,7 +16,6 @@ #![feature(proc_macro_internals)] #![feature(rustdoc_internals)] #![feature(trusted_len)] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate proc_macro; @@ -36,8 +35,8 @@ pub mod locator; pub use creader::{DylibError, load_symbol_from_dylib}; pub use fs::{METADATA_FILENAME, emit_wrapper_file}; pub use native_libs::{ - find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library, - walk_native_lib_search_dirs, + NativeLibSearchFallback, find_native_static_library, try_find_native_dynamic_library, + try_find_native_static_library, walk_native_lib_search_dirs, }; pub use rmeta::{EncodedMetadata, METADATA_HEADER, encode_metadata, rendered_const}; diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 2ddabeb49f70d..d5dd5059aacc6 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -260,7 +260,7 @@ pub(crate) struct CrateLocator<'a> { crate_rejections: CrateRejections, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub(crate) struct CratePaths { pub(crate) name: Symbol, source: CrateSource, @@ -272,7 +272,7 @@ impl CratePaths { } } -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub(crate) enum CrateFlavor { Rlib, Rmeta, @@ -290,7 +290,7 @@ impl fmt::Display for CrateFlavor { } impl IntoDiagArg for CrateFlavor { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { match self { CrateFlavor::Rlib => DiagArgValue::Str(Cow::Borrowed("rlib")), CrateFlavor::Rmeta => DiagArgValue::Str(Cow::Borrowed("rmeta")), @@ -893,13 +893,13 @@ fn get_flavor_from_path(path: &Path) -> CrateFlavor { // ------------------------------------------ Error reporting ------------------------------------- -#[derive(Clone)] +#[derive(Clone, Debug)] struct CrateMismatch { path: PathBuf, got: String, } -#[derive(Clone, Default)] +#[derive(Clone, Debug, Default)] struct CrateRejections { via_hash: Vec, via_triple: Vec, @@ -912,6 +912,7 @@ struct CrateRejections { /// Candidate rejection reasons collected during crate search. /// If no candidate is accepted, then these reasons are presented to the user, /// otherwise they are ignored. +#[derive(Debug)] pub(crate) struct CombinedLocatorError { crate_name: Symbol, dep_root: Option, @@ -921,6 +922,7 @@ pub(crate) struct CombinedLocatorError { crate_rejections: CrateRejections, } +#[derive(Debug)] pub(crate) enum CrateError { NonAsciiName(Symbol), ExternLocationNotExist(Symbol, PathBuf), diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 2a1e4b261e737..1671b7e06b0af 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -17,14 +17,21 @@ use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::{Symbol, sym}; -use rustc_target::spec::LinkSelfContainedComponents; +use rustc_target::spec::{BinaryFormat, LinkSelfContainedComponents}; use crate::{errors, fluent_generated}; +/// The fallback directories are passed to linker, but not used when rustc does the search, +/// because in the latter case the set of fallback directories cannot always be determined +/// consistently at the moment. +pub struct NativeLibSearchFallback<'a> { + pub self_contained_components: LinkSelfContainedComponents, + pub apple_sdk_root: Option<&'a Path>, +} + pub fn walk_native_lib_search_dirs( sess: &Session, - self_contained_components: LinkSelfContainedComponents, - apple_sdk_root: Option<&Path>, + fallback: Option>, mut f: impl FnMut(&Path, bool /*is_framework*/) -> ControlFlow, ) -> ControlFlow { // Library search paths explicitly supplied by user (`-L` on the command line). @@ -38,6 +45,11 @@ pub fn walk_native_lib_search_dirs( } } + let Some(NativeLibSearchFallback { self_contained_components, apple_sdk_root }) = fallback + else { + return ControlFlow::Continue(()); + }; + // The toolchain ships some native library components and self-contained linking was enabled. // Add the self-contained library directory to search paths. if self_contained_components.intersects( @@ -93,23 +105,17 @@ pub fn try_find_native_static_library( if os == unix { vec![os] } else { vec![os, unix] } }; - // FIXME: Account for self-contained linking settings and Apple SDK. - walk_native_lib_search_dirs( - sess, - LinkSelfContainedComponents::empty(), - None, - |dir, is_framework| { - if !is_framework { - for (prefix, suffix) in &formats { - let test = dir.join(format!("{prefix}{name}{suffix}")); - if test.exists() { - return ControlFlow::Break(test); - } + walk_native_lib_search_dirs(sess, None, |dir, is_framework| { + if !is_framework { + for (prefix, suffix) in &formats { + let test = dir.join(format!("{prefix}{name}{suffix}")); + if test.exists() { + return ControlFlow::Break(test); } } - ControlFlow::Continue(()) - }, - ) + } + ControlFlow::Continue(()) + }) .break_value() } @@ -132,22 +138,17 @@ pub fn try_find_native_dynamic_library( vec![os, meson, mingw] }; - walk_native_lib_search_dirs( - sess, - LinkSelfContainedComponents::empty(), - None, - |dir, is_framework| { - if !is_framework { - for (prefix, suffix) in &formats { - let test = dir.join(format!("{prefix}{name}{suffix}")); - if test.exists() { - return ControlFlow::Break(test); - } + walk_native_lib_search_dirs(sess, None, |dir, is_framework| { + if !is_framework { + for (prefix, suffix) in &formats { + let test = dir.join(format!("{prefix}{name}{suffix}")); + if test.exists() { + return ControlFlow::Break(test); } } - ControlFlow::Continue(()) - }, - ) + } + ControlFlow::Continue(()) + }) .break_value() } @@ -263,9 +264,26 @@ impl<'tcx> Collector<'tcx> { NativeLibKind::Framework { as_needed: None } } "raw-dylib" => { - if !sess.target.is_like_windows { + if sess.target.is_like_windows { + // raw-dylib is stable and working on Windows + } else if sess.target.binary_format == BinaryFormat::Elf + && features.raw_dylib_elf() + { + // raw-dylib is unstable on ELF, but the user opted in + } else if sess.target.binary_format == BinaryFormat::Elf + && sess.is_nightly_build() + { + feature_err( + sess, + sym::raw_dylib_elf, + span, + fluent_generated::metadata_raw_dylib_elf_unstable, + ) + .emit(); + } else { sess.dcx().emit_err(errors::RawDylibOnlyWindows { span }); } + NativeLibKind::RawDylib } "link-arg" => { @@ -450,7 +468,7 @@ impl<'tcx> Collector<'tcx> { (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule)); } let Some((name, name_span)) = name else { - sess.dcx().emit_err(errors::LinkRequiresName { span: m.span }); + sess.dcx().emit_err(errors::LinkRequiresName { span: m.span() }); continue; }; @@ -485,7 +503,7 @@ impl<'tcx> Collector<'tcx> { let link_ordinal_attr = self.tcx.get_attr(child_item, sym::link_ordinal).unwrap(); sess.dcx().emit_err(errors::LinkOrdinalRawDylib { - span: link_ordinal_attr.span, + span: link_ordinal_attr.span(), }); } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index e8dcda875e67a..e60904eebeb8b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -2,17 +2,16 @@ use std::iter::TrustedLen; use std::path::Path; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use std::{io, iter, mem}; pub(super) use cstore_impl::provide; use proc_macro::bridge::client::ProcMacro; use rustc_ast as ast; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::owned_slice::OwnedSlice; -use rustc_data_structures::sync::{Lock, OnceLock}; +use rustc_data_structures::sync::Lock; use rustc_data_structures::unhash::UnhashMap; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, DeriveProcMacro}; @@ -387,13 +386,11 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> { } } -impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> { +impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = true; - type I = TyCtxt<'tcx>; - #[inline] - fn interner(&self) -> Self::I { + fn interner(&self) -> TyCtxt<'tcx> { self.tcx() } @@ -963,14 +960,14 @@ impl CrateRoot { pub(crate) fn decode_crate_deps<'a>( &self, metadata: &'a MetadataBlob, - ) -> impl ExactSizeIterator + Captures<'a> { + ) -> impl ExactSizeIterator { self.crate_deps.decode(metadata) } pub(crate) fn decode_target_modifiers<'a>( &self, metadata: &'a MetadataBlob, - ) -> impl ExactSizeIterator + Captures<'a> { + ) -> impl ExactSizeIterator { self.target_modifiers.decode(metadata) } } @@ -1072,7 +1069,6 @@ impl<'a> CrateMetadataRef<'a> { let attrs: Vec<_> = self.get_item_attrs(id, sess).collect(); SyntaxExtension::new( sess, - tcx.features(), kind, self.get_span(id, sess), helper_attrs, @@ -1118,7 +1114,6 @@ impl<'a> CrateMetadataRef<'a> { value: self.get_default_field(did.index), }) .collect(), - adt_kind, parent_did, None, data.is_non_exhaustive, @@ -1276,7 +1271,7 @@ impl<'a> CrateMetadataRef<'a> { self, id: DefIndex, sess: &'a Session, - ) -> impl Iterator + 'a { + ) -> impl Iterator { iter::from_coroutine( #[coroutine] move || { @@ -1326,10 +1321,7 @@ impl<'a> CrateMetadataRef<'a> { .is_some_and(|ident| ident.name == kw::SelfLower) } - fn get_associated_item_or_field_def_ids( - self, - id: DefIndex, - ) -> impl Iterator + 'a { + fn get_associated_item_or_field_def_ids(self, id: DefIndex) -> impl Iterator { self.root .tables .associated_item_or_field_def_ids @@ -1380,7 +1372,7 @@ impl<'a> CrateMetadataRef<'a> { self, id: DefIndex, sess: &'a Session, - ) -> impl Iterator + 'a { + ) -> impl Iterator { self.root .tables .attributes @@ -1417,12 +1409,12 @@ impl<'a> CrateMetadataRef<'a> { } /// Decodes all traits in the crate (for rustdoc and rustc diagnostics). - fn get_traits(self) -> impl Iterator + 'a { + fn get_traits(self) -> impl Iterator { self.root.traits.decode(self).map(move |index| self.local_def_id(index)) } /// Decodes all trait impls in the crate (for rustdoc). - fn get_trait_impls(self) -> impl Iterator + 'a { + fn get_trait_impls(self) -> impl Iterator { self.cdata.trait_impls.values().flat_map(move |impls| { impls.decode(self).map(move |(impl_index, _)| self.local_def_id(impl_index)) }) @@ -1463,7 +1455,7 @@ impl<'a> CrateMetadataRef<'a> { } } - fn get_native_libraries(self, sess: &'a Session) -> impl Iterator + 'a { + fn get_native_libraries(self, sess: &'a Session) -> impl Iterator { self.root.native_libraries.decode((self, sess)) } @@ -1476,7 +1468,7 @@ impl<'a> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator + 'a { + fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator { self.root.foreign_modules.decode((self, sess)) } @@ -1816,7 +1808,7 @@ impl<'a> CrateMetadataRef<'a> { .decode(self) } - fn get_doc_link_traits_in_scope(self, index: DefIndex) -> impl Iterator + 'a { + fn get_doc_link_traits_in_scope(self, index: DefIndex) -> impl Iterator { self.root .tables .doc_link_traits_in_scope @@ -1887,7 +1879,7 @@ impl CrateMetadata { cdata } - pub(crate) fn dependencies(&self) -> impl Iterator + '_ { + pub(crate) fn dependencies(&self) -> impl Iterator { self.dependencies.iter().copied() } @@ -1936,6 +1928,10 @@ impl CrateMetadata { self.root.needs_panic_runtime } + pub(crate) fn is_private_dep(&self) -> bool { + self.private_dep + } + pub(crate) fn is_panic_runtime(&self) -> bool { self.root.panic_runtime } @@ -1944,6 +1940,10 @@ impl CrateMetadata { self.root.profiler_runtime } + pub(crate) fn is_compiler_builtins(&self) -> bool { + self.root.compiler_builtins + } + pub(crate) fn needs_allocator(&self) -> bool { self.root.needs_allocator } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 88a88847e6b8b..2b9113242aa5d 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -378,11 +378,9 @@ impl<'a, 'tcx> Encodable> for [u8] { } } -impl<'a, 'tcx> TyEncoder for EncodeContext<'a, 'tcx> { +impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = true; - type I = TyCtxt<'tcx>; - fn position(&self) -> usize { self.opaque.position() } @@ -1357,8 +1355,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { features: &tcx.features(), }; let attr_iter = tcx - .hir() - .attrs(tcx.local_def_id_to_hir_id(def_id)) + .hir_attrs(tcx.local_def_id_to_hir_id(def_id)) .iter() .filter(|attr| analyze_attr(*attr, &mut state)); @@ -1839,7 +1836,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_info_for_macro(&mut self, def_id: LocalDefId) { let tcx = self.tcx; - let hir::ItemKind::Macro(macro_def, _) = tcx.hir().expect_item(def_id).kind else { bug!() }; + let hir::ItemKind::Macro(macro_def, _) = tcx.hir_expect_item(def_id).kind else { bug!() }; self.tables.is_macro_rules.set(def_id.local_def_index, macro_def.macro_rules); record!(self.tables.macro_definition[def_id.to_def_id()] <- &*macro_def.body); } @@ -1918,11 +1915,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for &proc_macro in &tcx.resolutions(()).proc_macros { let id = proc_macro; let proc_macro = tcx.local_def_id_to_hir_id(proc_macro); - let mut name = hir.name(proc_macro); + let mut name = tcx.hir_name(proc_macro); let span = hir.span(proc_macro); // Proc-macros may have attributes like `#[allow_internal_unstable]`, // so downstream crates need access to them. - let attrs = hir.attrs(proc_macro); + let attrs = tcx.hir_attrs(proc_macro); let macro_kind = if ast::attr::contains_name(attrs, sym::proc_macro) { MacroKind::Bang } else if ast::attr::contains_name(attrs, sym::proc_macro_attribute) { diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 7b34e605c5307..5536c93f84a43 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -10,6 +10,7 @@ use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; +use rustc_hir::PreciseCapturingArgKind; use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId}; use rustc_hir::definitions::DefKey; @@ -440,7 +441,7 @@ define_tables! { coerce_unsized_info: Table>, mir_const_qualif: Table>, rendered_const: Table>, - rendered_precise_capturing_args: Table>, + rendered_precise_capturing_args: Table>>, asyncness: Table, fn_arg_names: Table>, coroutine_kind: Table, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index 389c861c3b524..43c1af642dd56 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_middle" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -14,7 +14,8 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_ast_ir = { path = "../rustc_ast_ir" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } # Used for intra-doc links rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index be8a3403ba956..bd315577efb5e 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -47,10 +47,10 @@ pub struct UnsupportedUnion { // FIXME(autodiff): I should get used somewhere #[derive(Diagnostic)] #[diag(middle_autodiff_unsafe_inner_const_ref)] -pub struct AutodiffUnsafeInnerConstRef { +pub struct AutodiffUnsafeInnerConstRef<'tcx> { #[primary_span] pub span: Span, - pub ty: String, + pub ty: Ty<'tcx>, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 40dd6aa73fd4c..c61c7a4fb026a 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -174,15 +174,12 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] - pub fn hir_free_items(self) -> impl Iterator + 'tcx { + pub fn hir_free_items(self) -> impl Iterator { self.hir_crate_items(()).free_items.iter().copied() } #[inline] - pub fn hir_module_free_items( - self, - module: LocalModDefId, - ) -> impl Iterator + 'tcx { + pub fn hir_module_free_items(self, module: LocalModDefId) -> impl Iterator { self.hir_module_items(module).free_items() } @@ -278,14 +275,15 @@ impl<'tcx> TyCtxt<'tcx> { span_bug!( self.hir().span(hir_id), "body_owned_by: {} has no associated body", - self.hir().node_to_string(hir_id) + self.hir_id_to_string(hir_id) ); }) } - pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator + 'tcx { - self.hir_body(id).params.iter().map(|arg| match arg.pat.kind { + pub fn hir_body_param_names(self, id: BodyId) -> impl Iterator { + self.hir_body(id).params.iter().map(|param| match param.pat.kind { PatKind::Binding(_, _, ident, _) => ident, + PatKind::Wild => Ident::new(kw::Underscore, param.pat.span), _ => Ident::empty(), }) } @@ -305,6 +303,7 @@ impl<'tcx> TyCtxt<'tcx> { DefKind::Static { safety: _, mutability, nested: false } => { BodyOwnerKind::Static(mutability) } + DefKind::GlobalAsm => BodyOwnerKind::GlobalAsm, dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } } @@ -327,7 +326,7 @@ impl<'tcx> TyCtxt<'tcx> { ConstContext::ConstFn } BodyOwnerKind::Fn if self.is_const_default_method(def_id) => ConstContext::ConstFn, - BodyOwnerKind::Fn | BodyOwnerKind::Closure => return None, + BodyOwnerKind::Fn | BodyOwnerKind::Closure | BodyOwnerKind::GlobalAsm => return None, }; Some(ccx) @@ -337,7 +336,7 @@ impl<'tcx> TyCtxt<'tcx> { /// crate. If you would prefer to iterate over the bodies /// themselves, you can do `self.hir().krate().body_ids.iter()`. #[inline] - pub fn hir_body_owners(self) -> impl Iterator + 'tcx { + pub fn hir_body_owners(self) -> impl Iterator { self.hir_crate_items(()).body_owners.iter().copied() } @@ -376,7 +375,7 @@ impl<'tcx> TyCtxt<'tcx> { /// invoking `krate.attrs` because it registers a tighter /// dep-graph access. pub fn hir_krate_attrs(self) -> &'tcx [Attribute] { - self.hir().attrs(CRATE_HIR_ID) + self.hir_attrs(CRATE_HIR_ID) } pub fn hir_rustc_coherence_is_core(self) -> bool { @@ -502,7 +501,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns an iterator for the nodes in the ancestor tree of the `current_id` /// until the crate root is reached. Prefer this over your own loop using `parent_id`. #[inline] - pub fn hir_parent_id_iter(self, current_id: HirId) -> impl Iterator + 'tcx { + pub fn hir_parent_id_iter(self, current_id: HirId) -> impl Iterator { ParentHirIterator::new(self, current_id) } @@ -676,104 +675,178 @@ impl<'tcx> TyCtxt<'tcx> { } } } -} -impl<'hir> Map<'hir> { - pub fn get_foreign_abi(self, hir_id: HirId) -> ExternAbi { - let parent = self.tcx.hir_get_parent_item(hir_id); + /// Get a representation of this `id` for debugging purposes. + /// NOTE: Do NOT use this in diagnostics! + pub fn hir_id_to_string(self, id: HirId) -> String { + let path_str = |def_id: LocalDefId| self.def_path_str(def_id); + + let span_str = || { + self.sess.source_map().span_to_snippet(Map { tcx: self }.span(id)).unwrap_or_default() + }; + let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str()); + + match self.hir_node(id) { + Node::Item(item) => { + let item_str = match item.kind { + ItemKind::ExternCrate(..) => "extern crate", + ItemKind::Use(..) => "use", + ItemKind::Static(..) => "static", + ItemKind::Const(..) => "const", + ItemKind::Fn { .. } => "fn", + ItemKind::Macro(..) => "macro", + ItemKind::Mod(..) => "mod", + ItemKind::ForeignMod { .. } => "foreign mod", + ItemKind::GlobalAsm { .. } => "global asm", + ItemKind::TyAlias(..) => "ty", + ItemKind::Enum(..) => "enum", + ItemKind::Struct(..) => "struct", + ItemKind::Union(..) => "union", + ItemKind::Trait(..) => "trait", + ItemKind::TraitAlias(..) => "trait alias", + ItemKind::Impl { .. } => "impl", + }; + format!("{id} ({item_str} {})", path_str(item.owner_id.def_id)) + } + Node::ForeignItem(item) => { + format!("{id} (foreign item {})", path_str(item.owner_id.def_id)) + } + Node::ImplItem(ii) => { + let kind = match ii.kind { + ImplItemKind::Const(..) => "associated constant", + ImplItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self { + ImplicitSelfKind::None => "associated function", + _ => "method", + }, + ImplItemKind::Type(_) => "associated type", + }; + format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id)) + } + Node::TraitItem(ti) => { + let kind = match ti.kind { + TraitItemKind::Const(..) => "associated constant", + TraitItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self { + ImplicitSelfKind::None => "associated function", + _ => "trait method", + }, + TraitItemKind::Type(..) => "associated type", + }; + + format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id)) + } + Node::Variant(variant) => { + format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id)) + } + Node::Field(field) => { + format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) + } + Node::AnonConst(_) => node_str("const"), + Node::ConstBlock(_) => node_str("const"), + Node::ConstArg(_) => node_str("const"), + Node::Expr(_) => node_str("expr"), + Node::ExprField(_) => node_str("expr field"), + Node::Stmt(_) => node_str("stmt"), + Node::PathSegment(_) => node_str("path segment"), + Node::Ty(_) => node_str("type"), + Node::AssocItemConstraint(_) => node_str("assoc item constraint"), + Node::TraitRef(_) => node_str("trait ref"), + Node::OpaqueTy(_) => node_str("opaque type"), + Node::Pat(_) => node_str("pat"), + Node::TyPat(_) => node_str("pat ty"), + Node::PatField(_) => node_str("pattern field"), + Node::PatExpr(_) => node_str("pattern literal"), + Node::Param(_) => node_str("param"), + Node::Arm(_) => node_str("arm"), + Node::Block(_) => node_str("block"), + Node::Infer(_) => node_str("infer"), + Node::LetStmt(_) => node_str("local"), + Node::Ctor(ctor) => format!( + "{id} (ctor {})", + ctor.ctor_def_id().map_or("".into(), |def_id| path_str(def_id)), + ), + Node::Lifetime(_) => node_str("lifetime"), + Node::GenericParam(param) => { + format!("{id} (generic_param {})", path_str(param.def_id)) + } + Node::Crate(..) => String::from("(root_crate)"), + Node::WherePredicate(_) => node_str("where predicate"), + Node::Synthetic => unreachable!(), + Node::Err(_) => node_str("error"), + Node::PreciseCapturingNonLifetimeArg(_param) => node_str("parameter"), + } + } + + pub fn hir_get_foreign_abi(self, hir_id: HirId) -> ExternAbi { + let parent = self.hir_get_parent_item(hir_id); if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = - self.tcx.hir_owner_node(parent) + self.hir_owner_node(parent) { return *abi; } bug!( "expected foreign mod or inlined parent, found {}", - self.node_to_string(HirId::make_owner(parent.def_id)) + self.hir_id_to_string(HirId::make_owner(parent.def_id)) ) } - pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> { - match self.tcx.expect_hir_owner_node(id) { + pub fn hir_expect_item(self, id: LocalDefId) -> &'tcx Item<'tcx> { + match self.expect_hir_owner_node(id) { OwnerNode::Item(item) => item, - _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))), + _ => bug!("expected item, found {}", self.hir_id_to_string(HirId::make_owner(id))), } } - pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> { - match self.tcx.expect_hir_owner_node(id) { + pub fn hir_expect_impl_item(self, id: LocalDefId) -> &'tcx ImplItem<'tcx> { + match self.expect_hir_owner_node(id) { OwnerNode::ImplItem(item) => item, - _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))), + _ => bug!("expected impl item, found {}", self.hir_id_to_string(HirId::make_owner(id))), } } - pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> { - match self.tcx.expect_hir_owner_node(id) { + pub fn hir_expect_trait_item(self, id: LocalDefId) -> &'tcx TraitItem<'tcx> { + match self.expect_hir_owner_node(id) { OwnerNode::TraitItem(item) => item, - _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))), - } - } - - pub fn get_fn_output(self, def_id: LocalDefId) -> Option<&'hir FnRetTy<'hir>> { - Some(&self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.output) - } - - pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> { - match self.tcx.hir_node(id) { - Node::Variant(variant) => variant, - _ => bug!("expected variant, found {}", self.node_to_string(id)), - } - } - - pub fn expect_field(self, id: HirId) -> &'hir FieldDef<'hir> { - match self.tcx.hir_node(id) { - Node::Field(field) => field, - _ => bug!("expected field, found {}", self.node_to_string(id)), - } - } - - pub fn expect_foreign_item(self, id: OwnerId) -> &'hir ForeignItem<'hir> { - match self.tcx.hir_owner_node(id) { - OwnerNode::ForeignItem(item) => item, _ => { - bug!( - "expected foreign item, found {}", - self.node_to_string(HirId::make_owner(id.def_id)) - ) + bug!("expected trait item, found {}", self.hir_id_to_string(HirId::make_owner(id))) } } } + pub fn hir_get_fn_output(self, def_id: LocalDefId) -> Option<&'tcx FnRetTy<'tcx>> { + Some(&self.opt_hir_owner_node(def_id)?.fn_decl()?.output) + } + #[track_caller] - pub fn expect_opaque_ty(self, id: LocalDefId) -> &'hir OpaqueTy<'hir> { - match self.tcx.hir_node_by_def_id(id) { + pub fn hir_expect_opaque_ty(self, id: LocalDefId) -> &'tcx OpaqueTy<'tcx> { + match self.hir_node_by_def_id(id) { Node::OpaqueTy(opaq) => opaq, _ => { bug!( "expected opaque type definition, found {}", - self.node_to_string(self.tcx.local_def_id_to_hir_id(id)) + self.hir_id_to_string(self.local_def_id_to_hir_id(id)) ) } } } - pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> { - match self.tcx.hir_node(id) { + pub fn hir_expect_expr(self, id: HirId) -> &'tcx Expr<'tcx> { + match self.hir_node(id) { Node::Expr(expr) => expr, - _ => bug!("expected expr, found {}", self.node_to_string(id)), + _ => bug!("expected expr, found {}", self.hir_id_to_string(id)), } } - pub fn opt_delegation_sig_id(self, def_id: LocalDefId) -> Option { - self.tcx.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id() + pub fn hir_opt_delegation_sig_id(self, def_id: LocalDefId) -> Option { + self.opt_hir_owner_node(def_id)?.fn_decl()?.opt_delegation_sig_id() } #[inline] - fn opt_ident(self, id: HirId) -> Option { - match self.tcx.hir_node(id) { + fn hir_opt_ident(self, id: HirId) -> Option { + match self.hir_node(id) { Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), // A `Ctor` doesn't have an identifier itself, but its parent // struct/variant does. Compare with `hir::Map::span`. - Node::Ctor(..) => match self.tcx.parent_hir_node(id) { + Node::Ctor(..) => match self.parent_hir_node(id) { Node::Item(item) => Some(item.ident), Node::Variant(variant) => Some(variant.ident), _ => unreachable!(), @@ -783,30 +856,32 @@ impl<'hir> Map<'hir> { } #[inline] - pub(super) fn opt_ident_span(self, id: HirId) -> Option { - self.opt_ident(id).map(|ident| ident.span) + pub(super) fn hir_opt_ident_span(self, id: HirId) -> Option { + self.hir_opt_ident(id).map(|ident| ident.span) } #[inline] - pub fn ident(self, id: HirId) -> Ident { - self.opt_ident(id).unwrap() + pub fn hir_ident(self, id: HirId) -> Ident { + self.hir_opt_ident(id).unwrap() } #[inline] - pub fn opt_name(self, id: HirId) -> Option { - self.opt_ident(id).map(|ident| ident.name) + pub fn hir_opt_name(self, id: HirId) -> Option { + self.hir_opt_ident(id).map(|ident| ident.name) } - pub fn name(self, id: HirId) -> Symbol { - self.opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.node_to_string(id))) + pub fn hir_name(self, id: HirId) -> Symbol { + self.hir_opt_name(id).unwrap_or_else(|| bug!("no name for {}", self.hir_id_to_string(id))) } /// Given a node ID, gets a list of attributes associated with the AST /// corresponding to the node-ID. - pub fn attrs(self, id: HirId) -> &'hir [Attribute] { - self.tcx.hir_attrs(id.owner).get(id.local_id) + pub fn hir_attrs(self, id: HirId) -> &'tcx [Attribute] { + self.hir_attr_map(id.owner).get(id.local_id) } +} +impl<'hir> Map<'hir> { /// Gets the span of the definition of the specified HIR node. /// This is used by `tcx.def_span`. pub fn span(self, hir_id: HirId) -> Span { @@ -979,12 +1054,6 @@ impl<'hir> Map<'hir> { } } - /// Get a representation of this `id` for debugging purposes. - /// NOTE: Do NOT use this in diagnostics! - pub fn node_to_string(self, id: HirId) -> String { - hir_id_to_string(self, id) - } - /// Returns the HirId of `N` in `struct Foo` when /// called with the HirId for the `{ ... }` anon const pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option { @@ -1149,102 +1218,6 @@ fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> { upstream_crates } -fn hir_id_to_string(map: Map<'_>, id: HirId) -> String { - let path_str = |def_id: LocalDefId| map.tcx.def_path_str(def_id); - - let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default(); - let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str()); - - match map.tcx.hir_node(id) { - Node::Item(item) => { - let item_str = match item.kind { - ItemKind::ExternCrate(..) => "extern crate", - ItemKind::Use(..) => "use", - ItemKind::Static(..) => "static", - ItemKind::Const(..) => "const", - ItemKind::Fn { .. } => "fn", - ItemKind::Macro(..) => "macro", - ItemKind::Mod(..) => "mod", - ItemKind::ForeignMod { .. } => "foreign mod", - ItemKind::GlobalAsm(..) => "global asm", - ItemKind::TyAlias(..) => "ty", - ItemKind::Enum(..) => "enum", - ItemKind::Struct(..) => "struct", - ItemKind::Union(..) => "union", - ItemKind::Trait(..) => "trait", - ItemKind::TraitAlias(..) => "trait alias", - ItemKind::Impl { .. } => "impl", - }; - format!("{id} ({item_str} {})", path_str(item.owner_id.def_id)) - } - Node::ForeignItem(item) => { - format!("{id} (foreign item {})", path_str(item.owner_id.def_id)) - } - Node::ImplItem(ii) => { - let kind = match ii.kind { - ImplItemKind::Const(..) => "associated constant", - ImplItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self { - ImplicitSelfKind::None => "associated function", - _ => "method", - }, - ImplItemKind::Type(_) => "associated type", - }; - format!("{id} ({kind} `{}` in {})", ii.ident, path_str(ii.owner_id.def_id)) - } - Node::TraitItem(ti) => { - let kind = match ti.kind { - TraitItemKind::Const(..) => "associated constant", - TraitItemKind::Fn(fn_sig, _) => match fn_sig.decl.implicit_self { - ImplicitSelfKind::None => "associated function", - _ => "trait method", - }, - TraitItemKind::Type(..) => "associated type", - }; - - format!("{id} ({kind} `{}` in {})", ti.ident, path_str(ti.owner_id.def_id)) - } - Node::Variant(variant) => { - format!("{id} (variant `{}` in {})", variant.ident, path_str(variant.def_id)) - } - Node::Field(field) => { - format!("{id} (field `{}` in {})", field.ident, path_str(field.def_id)) - } - Node::AnonConst(_) => node_str("const"), - Node::ConstBlock(_) => node_str("const"), - Node::ConstArg(_) => node_str("const"), - Node::Expr(_) => node_str("expr"), - Node::ExprField(_) => node_str("expr field"), - Node::Stmt(_) => node_str("stmt"), - Node::PathSegment(_) => node_str("path segment"), - Node::Ty(_) => node_str("type"), - Node::AssocItemConstraint(_) => node_str("assoc item constraint"), - Node::TraitRef(_) => node_str("trait ref"), - Node::OpaqueTy(_) => node_str("opaque type"), - Node::Pat(_) => node_str("pat"), - Node::TyPat(_) => node_str("pat ty"), - Node::PatField(_) => node_str("pattern field"), - Node::PatExpr(_) => node_str("pattern literal"), - Node::Param(_) => node_str("param"), - Node::Arm(_) => node_str("arm"), - Node::Block(_) => node_str("block"), - Node::Infer(_) => node_str("infer"), - Node::LetStmt(_) => node_str("local"), - Node::Ctor(ctor) => format!( - "{id} (ctor {})", - ctor.ctor_def_id().map_or("".into(), |def_id| path_str(def_id)), - ), - Node::Lifetime(_) => node_str("lifetime"), - Node::GenericParam(param) => { - format!("{id} (generic_param {})", path_str(param.def_id)) - } - Node::Crate(..) => String::from("(root_crate)"), - Node::WherePredicate(_) => node_str("where predicate"), - Node::Synthetic => unreachable!(), - Node::Err(_) => node_str("error"), - Node::PreciseCapturingNonLifetimeArg(_param) => node_str("parameter"), - } -} - pub(super) fn hir_module_items(tcx: TyCtxt<'_>, module_id: LocalModDefId) -> ModuleItems { let mut collector = ItemCollector::new(tcx, false); @@ -1358,7 +1331,7 @@ impl<'hir> Visitor<'hir> for ItemCollector<'hir> { self.submodules.push(item.owner_id); // A module collector does not recurse inside nested modules. if self.crate_collector { - intravisit::walk_mod(self, module, item.hir_id()); + intravisit::walk_mod(self, module); } } else { intravisit::walk_item(self, item) diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 2a201e2301553..68b9a4f56b96d 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -40,25 +40,25 @@ impl ModuleItems { /// include foreign items. If you want to e.g. get all functions, use `definitions()` below. /// /// However, this does include the `impl` blocks themselves. - pub fn free_items(&self) -> impl Iterator + '_ { + pub fn free_items(&self) -> impl Iterator { self.free_items.iter().copied() } - pub fn trait_items(&self) -> impl Iterator + '_ { + pub fn trait_items(&self) -> impl Iterator { self.trait_items.iter().copied() } /// Returns all items that are associated with some `impl` block (both inherent and trait impl /// blocks). - pub fn impl_items(&self) -> impl Iterator + '_ { + pub fn impl_items(&self) -> impl Iterator { self.impl_items.iter().copied() } - pub fn foreign_items(&self) -> impl Iterator + '_ { + pub fn foreign_items(&self) -> impl Iterator { self.foreign_items.iter().copied() } - pub fn owners(&self) -> impl Iterator + '_ { + pub fn owners(&self) -> impl Iterator { self.free_items .iter() .map(|id| id.owner_id) @@ -67,15 +67,15 @@ impl ModuleItems { .chain(self.foreign_items.iter().map(|id| id.owner_id)) } - pub fn opaques(&self) -> impl Iterator + '_ { + pub fn opaques(&self) -> impl Iterator { self.opaques.iter().copied() } - pub fn nested_bodies(&self) -> impl Iterator + '_ { + pub fn nested_bodies(&self) -> impl Iterator { self.nested_bodies.iter().copied() } - pub fn definitions(&self) -> impl Iterator + '_ { + pub fn definitions(&self) -> impl Iterator { self.owners().map(|id| id.def_id) } @@ -202,13 +202,13 @@ pub fn provide(providers: &mut Providers) { } }) }; - providers.hir_attrs = |tcx, id| { + providers.hir_attr_map = |tcx, id| { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; providers.def_span = |tcx, def_id| tcx.hir().span(tcx.local_def_id_to_hir_id(def_id)); providers.def_ident_span = |tcx, def_id| { let hir_id = tcx.local_def_id_to_hir_id(def_id); - tcx.hir().opt_ident_span(hir_id) + tcx.hir_opt_ident_span(hir_id) }; providers.fn_arg_names = |tcx, def_id| { let hir = tcx.hir(); diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 66b701523b71f..316ad80eb9857 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -97,7 +97,7 @@ impl<'tcx> Place<'tcx> { /// The types are in the reverse order that they are applied. So if /// `x: &*const u32` and the `Place` is `**x`, then the types returned are ///`*const u32` then `&*const u32`. - pub fn deref_tys(&self) -> impl Iterator> + '_ { + pub fn deref_tys(&self) -> impl Iterator> { self.projections.iter().enumerate().rev().filter_map(move |(index, proj)| { if ProjectionKind::Deref == proj.kind { Some(self.ty_before_projection(index)) diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 95128a5d903bb..1e6178144c921 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,7 +29,7 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] -#![cfg_attr(bootstrap, feature(trait_upcasting))] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(allocator_api)] @@ -45,7 +45,6 @@ #![feature(decl_macro)] #![feature(discriminant_kind)] #![feature(extern_types)] -#![feature(extract_if)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] @@ -63,7 +62,6 @@ #![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end #[cfg(test)] diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index b5f3a0e1482a9..0ae774ebee795 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -59,8 +59,8 @@ macro_rules! TrivialLiftImpls { macro_rules! TrivialTypeTraversalImpls { ($($ty:ty),+ $(,)?) => { $( - impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty { - fn try_fold_with>>( + impl<'tcx> $crate::ty::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty { + fn try_fold_with>>( self, _: &mut F, ) -> ::std::result::Result { @@ -68,7 +68,7 @@ macro_rules! TrivialTypeTraversalImpls { } #[inline] - fn fold_with>>( + fn fold_with>>( self, _: &mut F, ) -> Self { @@ -76,14 +76,14 @@ macro_rules! TrivialTypeTraversalImpls { } } - impl<'tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<'tcx>> for $ty { + impl<'tcx> $crate::ty::TypeVisitable<$crate::ty::TyCtxt<'tcx>> for $ty { #[inline] - fn visit_with>>( + fn visit_with>>( &self, _: &mut F) -> F::Result { - ::output() + ::output() } } )+ diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 311bc60c3cd39..a94ead161c379 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,6 +1,6 @@ use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; -use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 9f71971ea08b1..4587dcaddc487 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -25,7 +25,7 @@ pub mod lib_features { self.stability .to_sorted_stable_ord() .iter() - .map(|(&sym, &(stab, _))| (sym, stab)) + .map(|&(&sym, &(stab, _))| (sym, stab)) .collect() } } diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 2260cad41b97c..ec128c8c47863 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_attr_parsing::{ +use rustc_attr_data_structures::{ self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; use rustc_data_structures::unord::UnordMap; diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs index 171542d1279c7..d0dbf64dc5959 100644 --- a/compiler/rustc_middle/src/mir/basic_blocks.rs +++ b/compiler/rustc_middle/src/mir/basic_blocks.rs @@ -1,8 +1,9 @@ +use std::sync::OnceLock; + use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph; use rustc_data_structures::graph::dominators::{Dominators, dominators}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::OnceLock; use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 923160cc0cc85..34b27c2e1cce5 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -6,7 +6,7 @@ use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, Typ use rustc_session::RemapFileNameExt; use rustc_session::config::RemapPathScopeComponents; use rustc_span::{DUMMY_SP, Span, Symbol}; -use rustc_type_ir::visit::TypeVisitableExt; +use rustc_type_ir::TypeVisitableExt; use super::interpret::ReportedErrorInfo; use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range}; diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 95bc9b71fe0ad..57aafbb26bc8b 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -15,7 +15,8 @@ use provenance_map::*; use rustc_abi::{Align, HasDataLayout, Size}; use rustc_ast::Mutability; use rustc_data_structures::intern::Interned; -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; +use rustc_macros::HashStable; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use super::{ AllocId, BadBytesAccess, CtfeProvenance, InterpErrorKind, InterpResult, Pointer, @@ -77,7 +78,7 @@ impl AllocBytes for Box<[u8]> { /// module provides higher-level access. // Note: for performance reasons when interning, some of the `Allocation` fields can be partially // hashed. (see the `Hash` impl below for more details), so the impl is not derived. -#[derive(Clone, Eq, PartialEq, TyEncodable, TyDecodable)] +#[derive(Clone, Eq, PartialEq)] #[derive(HashStable)] pub struct Allocation> { /// The actual bytes of the allocation. @@ -101,6 +102,117 @@ pub struct Allocation Encodable for AllocFlags { + fn encode(&self, encoder: &mut E) { + // Make sure Align::MAX can be stored with the high 2 bits unset. + const { + let max_supported_align_repr = u8::MAX >> 2; + let max_supported_align = 1 << max_supported_align_repr; + assert!(Align::MAX.bytes() <= max_supported_align) + } + + let mut flags = self.align.bytes().trailing_zeros() as u8; + flags |= match self.mutability { + Mutability::Not => 0, + Mutability::Mut => 1 << 6, + }; + flags |= (self.all_zero as u8) << 7; + flags.encode(encoder); + } +} + +impl Decodable for AllocFlags { + fn decode(decoder: &mut D) -> Self { + let flags: u8 = Decodable::decode(decoder); + let align = flags & 0b0011_1111; + let mutability = flags & 0b0100_0000; + let all_zero = flags & 0b1000_0000; + + let align = Align::from_bytes(1 << align).unwrap(); + let mutability = match mutability { + 0 => Mutability::Not, + _ => Mutability::Mut, + }; + let all_zero = all_zero > 0; + + AllocFlags { align, mutability, all_zero } + } +} + +/// Efficiently detect whether a slice of `u8` is all zero. +/// +/// This is used in encoding of [`Allocation`] to special-case all-zero allocations. It is only +/// optimized a little, because for many allocations the encoding of the actual bytes does not +/// dominate runtime. +#[inline] +fn all_zero(buf: &[u8]) -> bool { + // In the empty case we wouldn't encode any contents even without this system where we + // special-case allocations whose contents are all 0. We can return anything in the empty case. + if buf.is_empty() { + return true; + } + // Just fast-rejecting based on the first element significantly reduces the amount that we end + // up walking the whole array. + if buf[0] != 0 { + return false; + } + + // This strategy of combining all slice elements with & or | is unbeatable for the large + // all-zero case because it is so well-understood by autovectorization. + buf.iter().fold(true, |acc, b| acc & (*b == 0)) +} + +/// Custom encoder for [`Allocation`] to more efficiently represent the case where all bytes are 0. +impl Encodable for Allocation +where + Bytes: AllocBytes, + ProvenanceMap: Encodable, + Extra: Encodable, +{ + fn encode(&self, encoder: &mut E) { + let all_zero = all_zero(&self.bytes); + AllocFlags { align: self.align, mutability: self.mutability, all_zero }.encode(encoder); + + encoder.emit_usize(self.bytes.len()); + if !all_zero { + encoder.emit_raw_bytes(&self.bytes); + } + self.provenance.encode(encoder); + self.init_mask.encode(encoder); + self.extra.encode(encoder); + } +} + +impl Decodable for Allocation +where + Bytes: AllocBytes, + ProvenanceMap: Decodable, + Extra: Decodable, +{ + fn decode(decoder: &mut D) -> Self { + let AllocFlags { align, mutability, all_zero } = Decodable::decode(decoder); + + let len = decoder.read_usize(); + let bytes = if all_zero { vec![0u8; len] } else { decoder.read_raw_bytes(len).to_vec() }; + let bytes = Bytes::from_bytes(bytes, align); + + let provenance = Decodable::decode(decoder); + let init_mask = Decodable::decode(decoder); + let extra = Decodable::decode(decoder); + + Self { bytes, provenance, init_mask, align, mutability, extra } + } +} + /// This is the maximum size we will hash at a time, when interning an `Allocation` and its /// `InitMask`. Note, we hash that amount of bytes twice: at the start, and at the end of a buffer. /// Used when these two structures are large: we only partially hash the larger fields in that @@ -222,7 +334,7 @@ impl AllocError { } /// The information that makes up a memory access: offset and size. -#[derive(Copy, Clone, PartialEq)] +#[derive(Copy, Clone)] pub struct AllocRange { pub start: Size, pub size: Size, @@ -470,7 +582,7 @@ impl Allocation // Find the provenance. let (offset, _prov) = self .provenance - .range_get_ptrs(range, cx) + .range_ptrs_get(range, cx) .first() .copied() .expect("there must be provenance somewhere here"); @@ -679,6 +791,11 @@ impl Allocation // Set provenance of all bytes to wildcard. self.provenance.write_wildcards(self.len()); + // Also expose the provenance of the interpreter-level allocation, so it can + // be written by FFI. The `black_box` is defensive programming as LLVM likes + // to (incorrectly) optimize away ptr2int casts whose result is unused. + std::hint::black_box(self.get_bytes_unchecked_raw_mut().expose_provenance()); + Ok(()) } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index cc6389e2989ef..20492cda4e23c 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -5,9 +5,8 @@ use std::ops::Range; use std::{hash, iter}; use rustc_abi::Size; -use rustc_macros::{HashStable, TyDecodable, TyEncodable}; -use rustc_serialize::{Decodable, Encodable}; -use rustc_type_ir::{TyDecoder, TyEncoder}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable}; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use super::AllocRange; @@ -19,13 +18,13 @@ type Block = u64; /// possible. Currently, if all the blocks have the same value, then the mask represents either a /// fully initialized or fully uninitialized const allocation, so we can only store that single /// value. -#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, Debug, Eq, PartialEq, Encodable_NoContext, Decodable_NoContext, Hash, HashStable)] pub struct InitMask { blocks: InitMaskBlocks, len: Size, } -#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] +#[derive(Clone, Debug, Eq, PartialEq, Encodable_NoContext, Decodable_NoContext, Hash, HashStable)] enum InitMaskBlocks { Lazy { /// Whether the lazy init mask is fully initialized or uninitialized. @@ -194,7 +193,7 @@ struct InitMaskMaterialized { // and also produces more output when the high bits of each `u64` are occupied. // Note: There is probably a remaining optimization for masks that do not use an entire // `Block`. -impl Encodable for InitMaskMaterialized { +impl Encodable for InitMaskMaterialized { fn encode(&self, encoder: &mut E) { encoder.emit_usize(self.blocks.len()); for block in &self.blocks { @@ -204,7 +203,7 @@ impl Encodable for InitMaskMaterialized { } // This implementation is deliberately not derived, see the matching `Encodable` impl. -impl Decodable for InitMaskMaterialized { +impl Decodable for InitMaskMaterialized { fn decode(decoder: &mut D) -> Self { let num_blocks = decoder.read_usize(); let mut blocks = Vec::with_capacity(num_blocks); @@ -223,8 +222,8 @@ impl Decodable for InitMaskMaterialized { // large. impl hash::Hash for InitMaskMaterialized { fn hash(&self, state: &mut H) { - const MAX_BLOCKS_TO_HASH: usize = super::MAX_BYTES_TO_HASH / std::mem::size_of::(); - const MAX_BLOCKS_LEN: usize = super::MAX_HASHED_BUFFER_LEN / std::mem::size_of::(); + const MAX_BLOCKS_TO_HASH: usize = super::MAX_BYTES_TO_HASH / size_of::(); + const MAX_BLOCKS_LEN: usize = super::MAX_HASHED_BUFFER_LEN / size_of::(); // Partially hash the `blocks` buffer when it is large. To limit collisions with common // prefixes and suffixes, we hash the length and some slices of the buffer. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 78196b0536190..c9525df1f7940 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -2,6 +2,7 @@ //! representation for the common case where PTR_SIZE consecutive bytes have the same provenance. use std::cmp; +use std::ops::Range; use rustc_abi::{HasDataLayout, Size}; use rustc_data_structures::sorted_map::SortedMap; @@ -66,24 +67,33 @@ impl ProvenanceMap { } impl ProvenanceMap { + fn adjusted_range_ptrs(range: AllocRange, cx: &impl HasDataLayout) -> Range { + // We have to go back `pointer_size - 1` bytes, as that one would still overlap with + // the beginning of this range. + let adjusted_start = Size::from_bytes( + range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1), + ); + adjusted_start..range.end() + } + /// Returns all ptr-sized provenance in the given range. /// If the range has length 0, returns provenance that crosses the edge between `start-1` and /// `start`. - pub(super) fn range_get_ptrs( + pub(super) fn range_ptrs_get( &self, range: AllocRange, cx: &impl HasDataLayout, ) -> &[(Size, Prov)] { - // We have to go back `pointer_size - 1` bytes, as that one would still overlap with - // the beginning of this range. - let adjusted_start = Size::from_bytes( - range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1), - ); - self.ptrs.range(adjusted_start..range.end()) + self.ptrs.range(Self::adjusted_range_ptrs(range, cx)) + } + + /// `pm.range_ptrs_is_empty(r, cx)` == `pm.range_ptrs_get(r, cx).is_empty()`, but is faster. + pub(super) fn range_ptrs_is_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool { + self.ptrs.range_is_empty(Self::adjusted_range_ptrs(range, cx)) } /// Returns all byte-wise provenance in the given range. - fn range_get_bytes(&self, range: AllocRange) -> &[(Size, Prov)] { + fn range_bytes_get(&self, range: AllocRange) -> &[(Size, Prov)] { if let Some(bytes) = self.bytes.as_ref() { bytes.range(range.start..range.end()) } else { @@ -91,9 +101,14 @@ impl ProvenanceMap { } } + /// Same as `range_bytes_get(range).is_empty()`, but faster. + fn range_bytes_is_empty(&self, range: AllocRange) -> bool { + self.bytes.as_ref().is_none_or(|bytes| bytes.range_is_empty(range.start..range.end())) + } + /// Get the provenance of a single byte. pub fn get(&self, offset: Size, cx: &impl HasDataLayout) -> Option { - let prov = self.range_get_ptrs(alloc_range(offset, Size::from_bytes(1)), cx); + let prov = self.range_ptrs_get(alloc_range(offset, Size::from_bytes(1)), cx); debug_assert!(prov.len() <= 1); if let Some(entry) = prov.first() { // If it overlaps with this byte, it is on this byte. @@ -117,11 +132,11 @@ impl ProvenanceMap { /// limit access to provenance outside of the `Allocation` abstraction. /// pub fn range_empty(&self, range: AllocRange, cx: &impl HasDataLayout) -> bool { - self.range_get_ptrs(range, cx).is_empty() && self.range_get_bytes(range).is_empty() + self.range_ptrs_is_empty(range, cx) && self.range_bytes_is_empty(range) } /// Yields all the provenances stored in this map. - pub fn provenances(&self) -> impl Iterator + '_ { + pub fn provenances(&self) -> impl Iterator { let bytes = self.bytes.iter().flat_map(|b| b.values()); self.ptrs.values().chain(bytes).copied() } @@ -149,12 +164,14 @@ impl ProvenanceMap { // provenance that overlaps with the given range. let (first, last) = { // Find all provenance overlapping the given range. - let provenance = self.range_get_ptrs(range, cx); - if provenance.is_empty() { - // No provenance in this range, we are done. + if self.range_ptrs_is_empty(range, cx) { + // No provenance in this range, we are done. This is the common case. return Ok(()); } + // This redoes some of the work of `range_get_ptrs_is_empty`, but this path is much + // colder than the early return above, so it's worth it. + let provenance = self.range_ptrs_get(range, cx); ( provenance.first().unwrap().0, provenance.last().unwrap().0 + cx.data_layout().pointer_size, @@ -267,8 +284,8 @@ impl ProvenanceMap { // This includes the existing bytewise provenance in the range, and ptr provenance // that overlaps with the begin/end of the range. let mut dest_bytes_box = None; - let begin_overlap = self.range_get_ptrs(alloc_range(src.start, Size::ZERO), cx).first(); - let end_overlap = self.range_get_ptrs(alloc_range(src.end(), Size::ZERO), cx).first(); + let begin_overlap = self.range_ptrs_get(alloc_range(src.start, Size::ZERO), cx).first(); + let end_overlap = self.range_ptrs_get(alloc_range(src.end(), Size::ZERO), cx).first(); if !Prov::OFFSET_IS_ADDR { // There can't be any bytewise provenance, and we cannot split up the begin/end overlap. if let Some(entry) = begin_overlap { @@ -291,10 +308,10 @@ impl ProvenanceMap { } else { trace!("no start overlapping entry"); } + // Then the main part, bytewise provenance from `self.bytes`. - if let Some(all_bytes) = self.bytes.as_ref() { - bytes.extend(all_bytes.range(src.start..src.end())); - } + bytes.extend(self.range_bytes_get(src)); + // And finally possibly parts of a pointer at the end. if let Some(entry) = end_overlap { trace!("end overlapping entry: {entry:?}"); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 743812e3a20a7..890756a17cae7 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -248,7 +248,7 @@ pub enum InvalidMetaKind { } impl IntoDiagArg for InvalidMetaKind { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(match self { InvalidMetaKind::SliceTooBig => "slice_too_big", InvalidMetaKind::TooBig => "too_big", @@ -282,7 +282,7 @@ pub struct Misalignment { macro_rules! impl_into_diag_arg_through_debug { ($($ty:ty),*$(,)?) => {$( impl IntoDiagArg for $ty { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Owned(format!("{self:?}"))) } } @@ -401,7 +401,7 @@ pub enum PointerKind { } impl IntoDiagArg for PointerKind { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str( match self { Self::Ref(_) => "ref", @@ -666,7 +666,7 @@ macro_rules! err_ub_custom { msg: || $msg, add_args: Box::new(move |mut set_arg| { $($( - set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name)); + set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name, &mut None)); )*)? }) } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index c48cfffa05cc4..c2438af6a1e19 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -105,7 +105,7 @@ enum AllocDiscriminant { Static, } -pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder>>( +pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<'tcx>>( encoder: &mut E, tcx: TyCtxt<'tcx>, alloc_id: AllocId, @@ -175,7 +175,7 @@ impl<'s> AllocDecodingSession<'s> { /// Decodes an `AllocId` in a thread-safe way. pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId where - D: TyDecoder>, + D: TyDecoder<'tcx>, { // Read the index of the allocation. let idx = usize::try_from(decoder.read_u32()).unwrap(); @@ -452,12 +452,7 @@ impl<'tcx> TyCtxt<'tcx> { } let id = self.alloc_map.reserve(); debug!("creating alloc {:?} with id {id:?}", alloc_salt.0); - let had_previous = self - .alloc_map - .to_alloc - .lock_shard_by_value(&id) - .insert(id, alloc_salt.0.clone()) - .is_some(); + let had_previous = self.alloc_map.to_alloc.insert(id, alloc_salt.0.clone()).is_some(); // We just reserved, so should always be unique. assert!(!had_previous); dedup.insert(alloc_salt, id); @@ -510,7 +505,7 @@ impl<'tcx> TyCtxt<'tcx> { /// local dangling pointers and allocations in constants/statics. #[inline] pub fn try_get_global_alloc(self, id: AllocId) -> Option> { - self.alloc_map.to_alloc.lock_shard_by_value(&id).get(&id).cloned() + self.alloc_map.to_alloc.get(&id) } #[inline] @@ -529,9 +524,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. pub fn set_alloc_id_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) { - if let Some(old) = - self.alloc_map.to_alloc.lock_shard_by_value(&id).insert(id, GlobalAlloc::Memory(mem)) - { + if let Some(old) = self.alloc_map.to_alloc.insert(id, GlobalAlloc::Memory(mem)) { bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}"); } } @@ -539,11 +532,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at a static item. Trying to /// call this function twice, even with the same `DefId` will ICE the compiler. pub fn set_nested_alloc_id_static(self, id: AllocId, def_id: LocalDefId) { - if let Some(old) = self - .alloc_map - .to_alloc - .lock_shard_by_value(&id) - .insert(id, GlobalAlloc::Static(def_id.to_def_id())) + if let Some(old) = + self.alloc_map.to_alloc.insert(id, GlobalAlloc::Static(def_id.to_def_id())) { bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}"); } @@ -573,7 +563,7 @@ pub fn write_target_uint( #[inline] pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result { // This u128 holds an "any-size uint" (since smaller uints can fits in it) - let mut buf = [0u8; std::mem::size_of::()]; + let mut buf = [0u8; size_of::()]; // So we do not read exactly 16 bytes into the u128, just the "payload". let uint = match endianness { Endian::Little => { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 78749428c6df3..4222a68e5447d 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -10,8 +10,7 @@ use super::{ }; use crate::mir; use crate::query::TyCtxtEnsureOk; -use crate::ty::visit::TypeVisitableExt; -use crate::ty::{self, GenericArgs, TyCtxt}; +use crate::ty::{self, GenericArgs, TyCtxt, TypeVisitableExt}; impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 227cb97c76b57..7090e93549e69 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -12,7 +12,6 @@ use either::Either; use polonius_engine::Atom; use rustc_abi::{FieldIdx, VariantIdx}; pub use rustc_ast::Mutability; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg}; @@ -33,10 +32,9 @@ pub use self::query::*; use crate::mir::interpret::{AllocRange, Scalar}; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::print::{FmtPrinter, Printer, pretty_print_const, with_no_trimmed_paths}; -use crate::ty::visit::TypeVisitableExt; use crate::ty::{ - self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, TypingEnv, - UserTypeAnnotationIndex, + self, AdtDef, GenericArg, GenericArgsRef, Instance, InstanceKind, List, Ty, TyCtxt, + TypeVisitableExt, TypingEnv, UserTypeAnnotationIndex, }; mod basic_blocks; @@ -97,6 +95,17 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { } impl MirPhase { + pub fn name(&self) -> &'static str { + match *self { + MirPhase::Built => "built", + MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", + MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", + MirPhase::Runtime(RuntimePhase::Initial) => "runtime", + MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", + MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", + } + } + /// Gets the (dialect, phase) index of the current `MirPhase`. Both numbers /// are 1-indexed. pub fn index(&self) -> (usize, usize) { @@ -322,13 +331,13 @@ pub struct Body<'tcx> { /// /// ```rust /// fn test() { - /// let _ = [0; std::mem::size_of::<*mut T>()]; + /// let _ = [0; size_of::<*mut T>()]; /// } /// ``` /// /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization /// removed the last mention of all generic params. We do not want to rely on optimizations and - /// potentially allow things like `[u8; std::mem::size_of::() * 0]` due to this. + /// potentially allow things like `[u8; size_of::() * 0]` due to this. pub is_polymorphic: bool, /// The phase at which this MIR should be "injected" into the compilation process. @@ -472,7 +481,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-declared mutable locals. #[inline] - pub fn mut_vars_iter<'a>(&'a self) -> impl Iterator + Captures<'tcx> + 'a { + pub fn mut_vars_iter(&self) -> impl Iterator { (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; @@ -482,9 +491,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all user-declared mutable arguments and locals. #[inline] - pub fn mut_vars_and_args_iter<'a>( - &'a self, - ) -> impl Iterator + Captures<'tcx> + 'a { + pub fn mut_vars_and_args_iter(&self) -> impl Iterator { (1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; @@ -514,7 +521,7 @@ impl<'tcx> Body<'tcx> { } #[inline] - pub fn drain_vars_and_temps<'a>(&'a mut self) -> impl Iterator> + 'a { + pub fn drain_vars_and_temps(&mut self) -> impl Iterator> { self.local_decls.drain(self.arg_count + 1..) } @@ -783,7 +790,7 @@ impl ClearCrossCrate { const TAG_CLEAR_CROSS_CRATE_CLEAR: u8 = 0; const TAG_CLEAR_CROSS_CRATE_SET: u8 = 1; -impl> Encodable for ClearCrossCrate { +impl<'tcx, E: TyEncoder<'tcx>, T: Encodable> Encodable for ClearCrossCrate { #[inline] fn encode(&self, e: &mut E) { if E::CLEAR_CROSS_CRATE { @@ -799,7 +806,7 @@ impl> Encodable for ClearCrossCrate { } } } -impl> Decodable for ClearCrossCrate { +impl<'tcx, D: TyDecoder<'tcx>, T: Decodable> Decodable for ClearCrossCrate { #[inline] fn decode(d: &mut D) -> ClearCrossCrate { if D::CLEAR_CROSS_CRATE { diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 4a21b6ad23706..897119c071223 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -2,7 +2,7 @@ use std::fmt; use std::hash::Hash; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; @@ -243,7 +243,7 @@ impl<'tcx> MonoItem<'tcx> { /// Returns the item's `CrateNum` pub fn krate(&self) -> CrateNum { match self { - MonoItem::Fn(ref instance) => instance.def_id().krate, + MonoItem::Fn(instance) => instance.def_id().krate, MonoItem::Static(def_id) => def_id.krate, MonoItem::GlobalAsm(..) => LOCAL_CRATE, } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 788306a288558..573f7895da2e2 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -319,6 +319,7 @@ pub fn write_mir_pretty<'tcx>( writeln!(w, "// WARNING: This output format is intended for human consumers only")?; writeln!(w, "// and is subject to change without notice. Knock yourself out.")?; + writeln!(w, "// HINT: See also -Z dump-mir for MIR at specific points during compilation.")?; let mut first = true; for def_id in dump_mir_def_ids(tcx, single) { @@ -652,7 +653,10 @@ fn write_mir_sig(tcx: TyCtxt<'_>, body: &Body<'_>, w: &mut dyn io::Write) -> io: write!(w, "static mut ")? } (_, _) if is_function => write!(w, "fn ")?, - (DefKind::AnonConst | DefKind::InlineConst, _) => {} // things like anon const, not an item + // things like anon const, not an item + (DefKind::AnonConst | DefKind::InlineConst, _) => {} + // `global_asm!` have fake bodies, which we may dump after mir-build + (DefKind::GlobalAsm, _) => {} _ => bug!("Unexpected def kind {:?}", kind), } @@ -970,7 +974,7 @@ impl<'tcx> TerminatorKind<'tcx> { } FalseEdge { .. } => write!(fmt, "falseEdge"), FalseUnwind { .. } => write!(fmt, "falseUnwind"), - InlineAsm { template, ref operands, options, .. } => { + InlineAsm { template, operands, options, .. } => { write!(fmt, "asm!(\"{}\"", InlineAsmTemplatePiece::to_string(template))?; for op in operands { write!(fmt, ", ")?; @@ -1199,7 +1203,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { && let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in iter::zip(upvars.keys(), places) { - let var_name = tcx.hir().name(var_id); + let var_name = tcx.hir_name(var_id); struct_fmt.field(var_name.as_str(), place); } } else { @@ -1220,7 +1224,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { && let Some(upvars) = tcx.upvars_mentioned(def_id) { for (&var_id, place) in iter::zip(upvars.keys(), places) { - let var_name = tcx.hir().name(var_id); + let var_name = tcx.hir_name(var_id); struct_fmt.field(var_name.as_str(), place); } } else { @@ -1523,7 +1527,7 @@ pub fn write_allocations<'tcx>( ) -> io::Result<()> { fn alloc_ids_from_alloc( alloc: ConstAllocation<'_>, - ) -> impl DoubleEndedIterator + '_ { + ) -> impl DoubleEndedIterator { alloc.inner().provenance().ptrs().values().map(|p| p.alloc_id()) } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 50494355e3e49..5a9fe10938ae1 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -13,8 +13,7 @@ use rustc_span::{Span, Symbol}; use smallvec::SmallVec; use super::{ConstValue, SourceInfo}; -use crate::ty::fold::fold_regions; -use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt}; +use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt, fold_regions}; rustc_index::newtype_index! { #[derive(HashStable)] diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 595a5e548b011..f05a798949b7e 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -25,6 +25,26 @@ impl Statement<'_> { } impl<'tcx> StatementKind<'tcx> { + /// Returns a simple string representation of a `StatementKind` variant, independent of any + /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`). + pub const fn name(&self) -> &'static str { + match self { + StatementKind::Assign(..) => "Assign", + StatementKind::FakeRead(..) => "FakeRead", + StatementKind::SetDiscriminant { .. } => "SetDiscriminant", + StatementKind::Deinit(..) => "Deinit", + StatementKind::StorageLive(..) => "StorageLive", + StatementKind::StorageDead(..) => "StorageDead", + StatementKind::Retag(..) => "Retag", + StatementKind::PlaceMention(..) => "PlaceMention", + StatementKind::AscribeUserType(..) => "AscribeUserType", + StatementKind::Coverage(..) => "Coverage", + StatementKind::Intrinsic(..) => "Intrinsic", + StatementKind::ConstEvalCounter => "ConstEvalCounter", + StatementKind::Nop => "Nop", + StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", + } + } pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> { match self { StatementKind::Assign(x) => Some(x), @@ -862,3 +882,40 @@ impl<'tcx> BinOp { }) } } + +impl From for RawPtrKind { + fn from(other: Mutability) -> Self { + match other { + Mutability::Mut => RawPtrKind::Mut, + Mutability::Not => RawPtrKind::Const, + } + } +} + +impl RawPtrKind { + pub fn is_fake(self) -> bool { + match self { + RawPtrKind::Mut | RawPtrKind::Const => false, + RawPtrKind::FakeForPtrMetadata => true, + } + } + + pub fn to_mutbl_lossy(self) -> Mutability { + match self { + RawPtrKind::Mut => Mutability::Mut, + RawPtrKind::Const => Mutability::Not, + + // We have no type corresponding to a fake borrow, so use + // `*const` as an approximation. + RawPtrKind::FakeForPtrMetadata => Mutability::Not, + } + } + + pub fn ptr_str(self) -> &'static str { + match self { + RawPtrKind::Mut => "mut", + RawPtrKind::Const => "const", + RawPtrKind::FakeForPtrMetadata => "const (fake)", + } + } +} diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index af6f0e4c55183..4f86703e95376 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -97,19 +97,6 @@ pub enum MirPhase { Runtime(RuntimePhase), } -impl MirPhase { - pub fn name(&self) -> &'static str { - match *self { - MirPhase::Built => "built", - MirPhase::Analysis(AnalysisPhase::Initial) => "analysis", - MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup", - MirPhase::Runtime(RuntimePhase::Initial) => "runtime", - MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup", - MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized", - } - } -} - /// See [`MirPhase::Analysis`]. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(HashStable)] @@ -206,43 +193,6 @@ pub enum RawPtrKind { FakeForPtrMetadata, } -impl From for RawPtrKind { - fn from(other: Mutability) -> Self { - match other { - Mutability::Mut => RawPtrKind::Mut, - Mutability::Not => RawPtrKind::Const, - } - } -} - -impl RawPtrKind { - pub fn is_fake(self) -> bool { - match self { - RawPtrKind::Mut | RawPtrKind::Const => false, - RawPtrKind::FakeForPtrMetadata => true, - } - } - - pub fn to_mutbl_lossy(self) -> Mutability { - match self { - RawPtrKind::Mut => Mutability::Mut, - RawPtrKind::Const => Mutability::Not, - - // We have no type corresponding to a fake borrow, so use - // `*const` as an approximation. - RawPtrKind::FakeForPtrMetadata => Mutability::Not, - } - } - - pub fn ptr_str(self) -> &'static str { - match self { - RawPtrKind::Mut => "mut", - RawPtrKind::Const => "const", - RawPtrKind::FakeForPtrMetadata => "const (fake)", - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable)] pub enum MutBorrowKind { @@ -515,29 +465,6 @@ pub enum StatementKind<'tcx> { }, } -impl StatementKind<'_> { - /// Returns a simple string representation of a `StatementKind` variant, independent of any - /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`). - pub const fn name(&self) -> &'static str { - match self { - StatementKind::Assign(..) => "Assign", - StatementKind::FakeRead(..) => "FakeRead", - StatementKind::SetDiscriminant { .. } => "SetDiscriminant", - StatementKind::Deinit(..) => "Deinit", - StatementKind::StorageLive(..) => "StorageLive", - StatementKind::StorageDead(..) => "StorageDead", - StatementKind::Retag(..) => "Retag", - StatementKind::PlaceMention(..) => "PlaceMention", - StatementKind::AscribeUserType(..) => "AscribeUserType", - StatementKind::Coverage(..) => "Coverage", - StatementKind::Intrinsic(..) => "Intrinsic", - StatementKind::ConstEvalCounter => "ConstEvalCounter", - StatementKind::Nop => "Nop", - StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint", - } - } -} - #[derive( Clone, TyEncodable, @@ -673,12 +600,6 @@ pub enum CallSource { Normal, } -impl CallSource { - pub fn from_hir_call(self) -> bool { - matches!(self, CallSource::Normal) - } -} - #[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] #[derive(TypeFoldable, TypeVisitable)] /// The macro that an inline assembly block was created by @@ -689,15 +610,6 @@ pub enum InlineAsmMacro { NakedAsm, } -impl InlineAsmMacro { - pub const fn diverges(self, options: InlineAsmOptions) -> bool { - match self { - InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), - InlineAsmMacro::NakedAsm => true, - } - } -} - /////////////////////////////////////////////////////////////////////////// // Terminators @@ -999,30 +911,6 @@ pub enum BackwardIncompatibleDropReason { Edition2024, } -impl TerminatorKind<'_> { - /// Returns a simple string representation of a `TerminatorKind` variant, independent of any - /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). - pub const fn name(&self) -> &'static str { - match self { - TerminatorKind::Goto { .. } => "Goto", - TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::UnwindResume => "UnwindResume", - TerminatorKind::UnwindTerminate(_) => "UnwindTerminate", - TerminatorKind::Return => "Return", - TerminatorKind::Unreachable => "Unreachable", - TerminatorKind::Drop { .. } => "Drop", - TerminatorKind::Call { .. } => "Call", - TerminatorKind::TailCall { .. } => "TailCall", - TerminatorKind::Assert { .. } => "Assert", - TerminatorKind::Yield { .. } => "Yield", - TerminatorKind::CoroutineDrop => "CoroutineDrop", - TerminatorKind::FalseEdge { .. } => "FalseEdge", - TerminatorKind::FalseUnwind { .. } => "FalseUnwind", - TerminatorKind::InlineAsm { .. } => "InlineAsm", - } - } -} - #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)] pub struct SwitchTargets { /// Possible values. For each value, the location to branch to is found in diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 49e0f619b1ec6..b2c51ad88645c 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -2,12 +2,13 @@ use std::slice; +use rustc_ast::InlineAsmOptions; use rustc_data_structures::packed::Pu128; use rustc_hir::LangItem; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use smallvec::{SmallVec, smallvec}; -use super::{TerminatorKind, *}; +use super::*; impl SwitchTargets { /// Creates switch targets from an iterator of values and target blocks. @@ -226,7 +227,7 @@ impl AssertKind { { use AssertKind::*; match self { - BoundsCheck { ref len, ref index } => write!( + BoundsCheck { len, index } => write!( f, "\"index out of bounds: the length is {{}} but the index is {{}}\", {len:?}, {index:?}" ), @@ -356,7 +357,7 @@ impl AssertKind { macro_rules! add { ($name: expr, $value: expr) => { - adder($name.into(), $value.into_diag_arg()); + adder($name.into(), $value.into_diag_arg(&mut None)); }; } @@ -414,6 +415,28 @@ impl<'tcx> Terminator<'tcx> { } impl<'tcx> TerminatorKind<'tcx> { + /// Returns a simple string representation of a `TerminatorKind` variant, independent of any + /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). + pub const fn name(&self) -> &'static str { + match self { + TerminatorKind::Goto { .. } => "Goto", + TerminatorKind::SwitchInt { .. } => "SwitchInt", + TerminatorKind::UnwindResume => "UnwindResume", + TerminatorKind::UnwindTerminate(_) => "UnwindTerminate", + TerminatorKind::Return => "Return", + TerminatorKind::Unreachable => "Unreachable", + TerminatorKind::Drop { .. } => "Drop", + TerminatorKind::Call { .. } => "Call", + TerminatorKind::TailCall { .. } => "TailCall", + TerminatorKind::Assert { .. } => "Assert", + TerminatorKind::Yield { .. } => "Yield", + TerminatorKind::CoroutineDrop => "CoroutineDrop", + TerminatorKind::FalseEdge { .. } => "FalseEdge", + TerminatorKind::FalseUnwind { .. } => "FalseUnwind", + TerminatorKind::InlineAsm { .. } => "InlineAsm", + } + } + #[inline] pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) } @@ -431,6 +454,7 @@ mod helper { /// Like [`SwitchTargets::target_for_value`], but returning the same type as /// [`Terminator::successors`]. #[inline] + #[cfg_attr(not(bootstrap), define_opaque(Successors))] pub fn successors_for_value(&self, value: u128) -> Successors<'_> { let target = self.target_for_value(value); (&[]).into_iter().copied().chain(Some(target)) @@ -439,6 +463,7 @@ mod helper { impl<'tcx> TerminatorKind<'tcx> { #[inline] + #[cfg_attr(not(bootstrap), define_opaque(Successors))] pub fn successors(&self) -> Successors<'_> { use self::TerminatorKind::*; match *self { @@ -477,6 +502,7 @@ mod helper { } #[inline] + #[cfg_attr(not(bootstrap), define_opaque(SuccessorsMut))] pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { use self::TerminatorKind::*; match *self { @@ -698,3 +724,18 @@ impl<'tcx> TerminatorKind<'tcx> { } } } + +impl CallSource { + pub fn from_hir_call(self) -> bool { + matches!(self, CallSource::Normal) + } +} + +impl InlineAsmMacro { + pub const fn diverges(self, options: InlineAsmOptions) -> bool { + match self { + InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN), + InlineAsmMacro::NakedAsm => true, + } + } +} diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 5950ac295af19..9308570d89d18 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -23,19 +23,13 @@ pub struct Preorder<'a, 'tcx> { body: &'a Body<'tcx>, visited: DenseBitSet, worklist: Vec, - root_is_start_block: bool, } impl<'a, 'tcx> Preorder<'a, 'tcx> { pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> { let worklist = vec![root]; - Preorder { - body, - visited: DenseBitSet::new_empty(body.basic_blocks.len()), - worklist, - root_is_start_block: root == START_BLOCK, - } + Preorder { body, visited: DenseBitSet::new_empty(body.basic_blocks.len()), worklist } } } @@ -71,15 +65,11 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { } fn size_hint(&self) -> (usize, Option) { - // All the blocks, minus the number of blocks we've visited. - let upper = self.body.basic_blocks.len() - self.visited.count(); + // The worklist might be only things already visited. + let lower = 0; - let lower = if self.root_is_start_block { - // We will visit all remaining blocks exactly once. - upper - } else { - self.worklist.len() - }; + // This is extremely loose, but it's not worth a popcnt loop to do better. + let upper = self.body.basic_blocks.len(); (lower, Some(upper)) } @@ -108,7 +98,6 @@ pub struct Postorder<'a, 'tcx> { basic_blocks: &'a IndexSlice>, visited: DenseBitSet, visit_stack: Vec<(BasicBlock, Successors<'a>)>, - root_is_start_block: bool, /// A non-empty `extra` allows for a precise calculation of the successors. extra: Option<(TyCtxt<'tcx>, Instance<'tcx>)>, } @@ -123,7 +112,6 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { basic_blocks, visited: DenseBitSet::new_empty(basic_blocks.len()), visit_stack: Vec::new(), - root_is_start_block: root == START_BLOCK, extra, }; @@ -211,16 +199,13 @@ impl<'tcx> Iterator for Postorder<'_, 'tcx> { } fn size_hint(&self) -> (usize, Option) { - // All the blocks, minus the number of blocks we've visited. - let upper = self.basic_blocks.len() - self.visited.count(); - - let lower = if self.root_is_start_block { - // We will visit all remaining blocks exactly once. - upper - } else { - self.visit_stack.len() - }; + // These bounds are not at all tight, but that's fine. + // It's not worth a popcnt loop in `DenseBitSet` to improve the upper, + // and in mono-reachable we can't be precise anyway. + // Leaning on amortized growth is fine. + let lower = self.visit_stack.len(); + let upper = self.basic_blocks.len(); (lower, Some(upper)) } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index af09a6d570bab..3c83d962900ae 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -443,7 +443,7 @@ macro_rules! make_mir_visitor { location ) } - StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => { + StatementKind::Intrinsic(box intrinsic) => { match intrinsic { NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location), NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { @@ -886,8 +886,8 @@ macro_rules! make_mir_visitor { self.visit_source_info(source_info); let location = Location::START; if let Some(box VarDebugInfoFragment { - ref $($mutability)? ty, - ref $($mutability)? projection + ty, + projection }) = composite { self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); for elem in projection { diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index cbd60920bc572..7bbaa0496d53d 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -24,10 +24,11 @@ pub trait EraseType: Copy { pub type Erase = Erased; #[inline(always)] +#[cfg_attr(not(bootstrap), define_opaque(Erase))] pub fn erase(src: T) -> Erase { // Ensure the sizes match const { - if std::mem::size_of::() != std::mem::size_of::() { + if size_of::() != size_of::() { panic!("size of T must match erased type T::Result") } }; @@ -47,6 +48,7 @@ pub fn erase(src: T) -> Erase { /// Restores an erased value. #[inline(always)] +#[cfg_attr(not(bootstrap), define_opaque(Erase))] pub fn restore(value: Erase) -> T { let value: Erased<::Result> = value; // See comment in `erase` for why we use `transmute_unchecked`. @@ -231,9 +233,9 @@ trivial! { bool, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, Option, - Option, - Option, - Option, + Option, + Option, + Option, Option, Option, Option, @@ -256,10 +258,10 @@ trivial! { Result, rustc_abi::ReprOptions, rustc_ast::expand::allocator::AllocatorKind, - rustc_attr_parsing::ConstStability, - rustc_attr_parsing::DefaultBodyStability, - rustc_attr_parsing::Deprecation, - rustc_attr_parsing::Stability, + rustc_attr_data_structures::ConstStability, + rustc_attr_data_structures::DefaultBodyStability, + rustc_attr_data_structures::Deprecation, + rustc_attr_data_structures::Stability, rustc_data_structures::svh::Svh, rustc_errors::ErrorGuaranteed, rustc_hir::Constness, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 1489d57aba645..98314b5abfda1 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -508,6 +508,14 @@ impl<'tcx, T: Clone> Key for CanonicalQueryInput<'tcx, T> { } } +impl<'tcx, T: Clone> Key for (CanonicalQueryInput<'tcx, T>, bool) { + type Cache = DefaultCache; + + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl Key for (Symbol, u32, u32) { type Cache = DefaultCache; diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7c4ea06a7461a..94a5a3769a322 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -25,7 +25,7 @@ use rustc_hir::def_id::{ CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap, LocalDefIdSet, LocalModDefId, }; use rustc_hir::lang_items::{LangItem, LanguageItems}; -use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, TraitCandidate}; +use rustc_hir::{Crate, ItemLocalId, ItemLocalMap, PreciseCapturingArgKind, TraitCandidate}; use rustc_index::IndexVec; use rustc_lint_defs::LintId; use rustc_macros::rustc_queries; @@ -41,7 +41,7 @@ use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_target::spec::PanicStrategy; -use {rustc_abi as abi, rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_abi as abi, rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; @@ -143,11 +143,11 @@ rustc_queries! { /// Represents crate as a whole (as distinct from the top-level crate module). /// - /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir().krate()`), + /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir_crate()`), /// we will have to assume that any change means that you need to be recompiled. /// This is because the `hir_crate` query gives you access to all other items. - /// To avoid this fate, do not call `tcx.hir().krate()`; instead, - /// prefer wrappers like `tcx.visit_all_items_in_krate()`. + /// To avoid this fate, do not call `tcx.hir_crate()`; instead, + /// prefer wrappers like [`TyCtxt::hir_visit_all_item_likes_in_crate`]. query hir_crate(key: ()) -> &'tcx Crate<'tcx> { arena_cache eval_always @@ -198,7 +198,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> { + query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> { desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) } feedable } @@ -748,6 +748,15 @@ rustc_queries! { } } + /// Compute the conditions that need to hold for a conditionally-const item to be const. + /// That is, compute the set of `~const` where clauses for a given item. + /// + /// This can be thought of as the `~const` equivalent of `predicates_of`. These are the + /// predicates that need to be proven at usage sites, and can be assumed at definition. + /// + /// This query also computes the `~const` where clauses for associated types, which are + /// not "const", but which have item bounds which may be `~const`. These must hold for + /// the `~const` item bound to hold. query const_conditions( key: DefId ) -> ty::ConstConditions<'tcx> { @@ -757,6 +766,11 @@ rustc_queries! { separate_provide_extern } + /// Compute the const bounds that are implied for a conditionally-const item. + /// + /// This can be though of as the `~const` equivalent of `explicit_item_bounds`. These + /// are the predicates that need to proven at definition sites, and can be assumed at + /// usage sites. query explicit_implied_const_bounds( key: DefId ) -> ty::EarlyBinder<'tcx, &'tcx [(ty::PolyTraitRef<'tcx>, Span)]> { @@ -985,12 +999,6 @@ rustc_queries! { separate_provide_extern } - query self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( - key: DefId - ) -> Option>> { - desc { |tcx| "computing self type wrt issue #33140 `{}`", tcx.def_path_str(key) } - } - /// Maps a `DefId` of a type to a list of its inherent impls. /// Contains implementations of methods that are inherent to a type. /// Methods in these implementations don't need to be exported. @@ -1416,7 +1424,7 @@ rustc_queries! { } /// Gets the rendered precise capturing args for an opaque for use in rustdoc. - query rendered_precise_capturing_args(def_id: DefId) -> Option<&'tcx [Symbol]> { + query rendered_precise_capturing_args(def_id: DefId) -> Option<&'tcx [PreciseCapturingArgKind]> { desc { |tcx| "rendering precise capturing args for `{}`", tcx.def_path_str(def_id) } separate_provide_extern } @@ -1519,6 +1527,11 @@ rustc_queries! { query is_copy_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Copy`", env.value } } + /// Trait selection queries. These are best used by invoking `ty.is_use_cloned_modulo_regions()`, + /// `ty.is_use_cloned()`, etc, since that will prune the environment where possible. + query is_use_cloned_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { + desc { "computing whether `{}` is `UseCloned`", env.value } + } /// Query backing `Ty::is_sized`. query is_sized_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { desc { "computing whether `{}` is `Sized`", env.value } @@ -2248,22 +2261,13 @@ rustc_queries! { desc { "normalizing `{}`", goal.value } } - query implied_outlives_bounds_compat( - goal: CanonicalImpliedOutlivesBoundsGoal<'tcx> - ) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, - NoSolution, - > { - desc { "computing implied outlives bounds for `{}`", goal.canonical.value.value.ty } - } - query implied_outlives_bounds( - goal: CanonicalImpliedOutlivesBoundsGoal<'tcx> + key: (CanonicalImpliedOutlivesBoundsGoal<'tcx>, bool) ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, NoSolution, > { - desc { "computing implied outlives bounds v2 for `{}`", goal.canonical.value.value.ty } + desc { "computing implied outlives bounds for `{}` (hack disabled = {:?})", key.0.canonical.value.value.ty, key.1 } } /// Do not call this query directly: diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index d9035efaf56d0..e66958dfcb8dd 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -518,8 +518,7 @@ where value } -impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> { - type I = TyCtxt<'tcx>; +impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = false; #[inline] @@ -943,8 +942,7 @@ impl<'a, 'tcx> SpanEncoder for CacheEncoder<'a, 'tcx> { } } -impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> { - type I = TyCtxt<'tcx>; +impl<'a, 'tcx> TyEncoder<'tcx> for CacheEncoder<'a, 'tcx> { const CLEAR_CROSS_CRATE: bool = false; #[inline] diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 690b8128b1aef..4834444ed1d7a 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -165,7 +165,7 @@ impl<'tcx> TyCtxt<'tcx> { } } -#[inline] +#[inline(always)] pub fn query_get_at<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option, @@ -258,7 +258,7 @@ macro_rules! query_if_arena { }; } -/// If `separate_provide_if_extern`, then the key can be projected to its +/// If `separate_provide_extern`, then the key can be projected to its /// local key via `<$K as AsLocalKey>::LocalKey`. macro_rules! local_key_if_separate_extern { ([] $($K:tt)*) => { @@ -370,7 +370,7 @@ macro_rules! define_callbacks { // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(target_pointer_width = "64")] const _: () = { - if mem::size_of::>() > 88 { + if size_of::>() > 88 { panic!("{}", concat!( "the query `", stringify!($name), @@ -386,7 +386,7 @@ macro_rules! define_callbacks { #[cfg(target_pointer_width = "64")] #[cfg(not(feature = "rustc_randomized_layouts"))] const _: () = { - if mem::size_of::>() > 64 { + if size_of::>() > 64 { panic!("{}", concat!( "the query `", stringify!($name), diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 98cc00c367cfe..f7b98d935d4de 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -19,7 +19,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{BindingMode, ByRef, HirId, MatchSource, RangeEnd}; use rustc_index::{IndexVec, newtype_index}; -use rustc_macros::{HashStable, TypeVisitable}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeVisitable}; use rustc_span::def_id::LocalDefId; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -49,10 +49,13 @@ macro_rules! thir_with_elements { } )* + // Note: Making `Thir` implement `Clone` is useful for external tools that need access to + // THIR bodies even after the `Steal` query result has been stolen. + // One such tool is https://github.com/rust-corpus/qrates/. /// A container for a THIR body. /// /// This can be indexed directly by any THIR index (e.g. [`ExprId`]). - #[derive(Debug, HashStable)] + #[derive(Debug, HashStable, Clone)] pub struct Thir<'tcx> { pub body_type: BodyTy<'tcx>, $( @@ -90,14 +93,15 @@ thir_with_elements! { params: ParamId => Param<'tcx> => "p{}", } -#[derive(Debug, HashStable)] +#[derive(Debug, HashStable, Clone)] pub enum BodyTy<'tcx> { Const(Ty<'tcx>), Fn(FnSig<'tcx>), + GlobalAsm(Ty<'tcx>), } /// Description of a type-checked function parameter. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Param<'tcx> { /// The pattern that appears in the parameter list, or None for implicit parameters. pub pat: Option>>, @@ -117,7 +121,7 @@ pub enum LintLevel { Explicit(HirId), } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Block { /// Whether the block itself has a label. Used by `label: {}` /// and `try` blocks. @@ -137,7 +141,7 @@ pub struct Block { type UserTy<'tcx> = Option>>; -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct AdtExpr<'tcx> { /// The ADT we're constructing. pub adt_def: AdtDef<'tcx>, @@ -154,7 +158,7 @@ pub struct AdtExpr<'tcx> { pub base: AdtExprBase<'tcx>, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum AdtExprBase<'tcx> { /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`. None, @@ -167,7 +171,7 @@ pub enum AdtExprBase<'tcx> { DefaultFields(Box<[Ty<'tcx>]>), } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct ClosureExpr<'tcx> { pub closure_id: LocalDefId, pub args: UpvarArgs<'tcx>, @@ -176,7 +180,7 @@ pub struct ClosureExpr<'tcx> { pub fake_reads: Vec<(ExprId, FakeReadCause, HirId)>, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct InlineAsmExpr<'tcx> { pub asm_macro: AsmMacro, pub template: &'tcx [InlineAsmTemplatePiece], @@ -194,12 +198,12 @@ pub enum BlockSafety { ExplicitUnsafe(HirId), } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Stmt<'tcx> { pub kind: StmtKind<'tcx>, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum StmtKind<'tcx> { /// An expression with a trailing semicolon. Expr { @@ -239,11 +243,11 @@ pub enum StmtKind<'tcx> { }, } -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, HashStable)] +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] pub struct LocalVarId(pub HirId); /// A THIR expression. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Expr<'tcx> { /// kind of expression pub kind: ExprKind<'tcx>, @@ -270,7 +274,7 @@ pub struct TempLifetime { pub backwards_incompatible: Option, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum ExprKind<'tcx> { /// `Scope`s are used to explicitly mark destruction scopes, /// and to track the `HirId` of the expressions within the scope. @@ -311,6 +315,14 @@ pub enum ExprKind<'tcx> { /// (e.g. `foo(a, b)` in `x.foo(a, b)`). fn_span: Span, }, + /// A use expression `x.use`. + ByUse { + /// The expression on which use is applied. + expr: ExprId, + /// The span of use, without the dot and receiver + /// (e.g. `use` in `x.use`). + span: Span, + }, /// A *non-overloaded* dereference. Deref { arg: ExprId, @@ -547,20 +559,20 @@ pub enum ExprKind<'tcx> { /// Represents the association of a field identifier and an expression. /// /// This is used in struct constructors. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct FieldExpr { pub name: FieldIdx, pub expr: ExprId, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct FruInfo<'tcx> { pub base: ExprId, pub field_types: Box<[Ty<'tcx>]>, } /// A `match` arm. -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub struct Arm<'tcx> { pub pattern: Box>, pub guard: Option, @@ -578,7 +590,7 @@ pub enum LogicalOp { Or, } -#[derive(Debug, HashStable)] +#[derive(Clone, Debug, HashStable)] pub enum InlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, @@ -605,8 +617,7 @@ pub enum InlineAsmOperand<'tcx> { span: Span, }, SymFn { - value: mir::Const<'tcx>, - span: Span, + value: ExprId, }, SymStatic { def_id: DefId, @@ -616,13 +627,13 @@ pub enum InlineAsmOperand<'tcx> { }, } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct FieldPat<'tcx> { pub field: FieldIdx, pub pattern: Pat<'tcx>, } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Pat<'tcx> { pub ty: Ty<'tcx>, pub span: Span, @@ -678,8 +689,7 @@ impl<'tcx> Pat<'tcx> { subpatterns.iter().for_each(|field| field.pattern.walk_(it)) } Or { pats } => pats.iter().for_each(|p| p.walk_(it)), - Array { box ref prefix, ref slice, box ref suffix } - | Slice { box ref prefix, ref slice, box ref suffix } => { + Array { box prefix, slice, box suffix } | Slice { box prefix, slice, box suffix } => { prefix.iter().chain(slice.as_deref()).chain(suffix.iter()).for_each(|p| p.walk_(it)) } } @@ -730,7 +740,7 @@ impl<'tcx> Pat<'tcx> { } } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub struct Ascription<'tcx> { pub annotation: CanonicalUserTypeAnnotation<'tcx>, /// Variance to use when relating the `user_ty` to the **type of the value being @@ -754,7 +764,7 @@ pub struct Ascription<'tcx> { pub variance: ty::Variance, } -#[derive(Debug, HashStable, TypeVisitable)] +#[derive(Clone, Debug, HashStable, TypeVisitable)] pub enum PatKind<'tcx> { /// A wildcard pattern: `_`. Wild, diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 13b8af55e518e..d208692f4e711 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -59,6 +59,9 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( visitor.visit_expr(&visitor.thir()[arg]); } } + ByUse { expr, span: _ } => { + visitor.visit_expr(&visitor.thir()[expr]); + } Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { visitor.visit_expr(&visitor.thir()[lhs]); @@ -172,7 +175,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } - | SymFn { value: _, span: _ } + | SymFn { value: _ } | SymStatic { def_id: _ } => {} Label { block } => visitor.visit_block(&visitor.thir()[*block]), } @@ -194,7 +197,7 @@ pub fn walk_stmt<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( initializer, remainder_scope: _, init_scope: _, - ref pattern, + pattern, lint_level: _, else_block, span: _, diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 54cd8cc3efe75..7e6151745e2f8 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -144,14 +144,6 @@ impl<'tcx> ObligationCause<'tcx> { } } -#[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] -#[derive(TypeVisitable, TypeFoldable)] -pub struct UnifyReceiverContext<'tcx> { - pub assoc_item: ty::AssocItem, - pub param_env: ty::ParamEnv<'tcx>, - pub args: GenericArgsRef<'tcx>, -} - /// A compact form of `ObligationCauseCode`. #[derive(Clone, PartialEq, Eq, Default, HashStable)] #[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)] @@ -274,7 +266,7 @@ pub enum ObligationCauseCode<'tcx> { }, /// Constant expressions must be sized. - ConstSized, + SizedConstOrStatic, /// `static` items must have `Sync` type. SharedStatic, @@ -360,8 +352,6 @@ pub enum ObligationCauseCode<'tcx> { /// Method receiver MethodReceiver, - UnifyReceiver(Box>), - /// `return` with no expression ReturnNoExpression, @@ -407,9 +397,9 @@ pub enum ObligationCauseCode<'tcx> { RustCall, - /// Obligations to prove that a `std::ops::Drop` impl is not stronger than + /// Obligations to prove that a `Drop` or negative auto trait impl is not stronger than /// the ADT it's being implemented for. - DropImpl, + AlwaysApplicableImpl, /// Requirement for a `const N: Ty` to implement `Ty: ConstParamTy` ConstParam(Ty<'tcx>), @@ -786,7 +776,7 @@ impl DynCompatibilityViolation { pub fn error_msg(&self) -> Cow<'static, str> { match self { DynCompatibilityViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - DynCompatibilityViolation::SupertraitSelf(ref spans) => { + DynCompatibilityViolation::SupertraitSelf(spans) => { if spans.iter().any(|sp| *sp != DUMMY_SP) { "it uses `Self` as a type parameter".into() } else { @@ -990,12 +980,9 @@ pub enum CodegenObligationError { /// overflow bug, since I believe this is the only case /// where ambiguity can result. Ambiguity, - /// This can trigger when we probe for the source of a `'static` lifetime requirement - /// on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound. - /// This can also trigger when we have a global bound that is not actually satisfied, - /// but was included during typeck due to the trivial_bounds feature. + /// This can trigger when we have a global bound that is not actually satisfied + /// due to trivial bounds. Unimplemented, - FulfillmentError, /// The selected impl has unconstrained generic parameters. This will emit an error /// during impl WF checking. UnconstrainedParam(ErrorGuaranteed), diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 9c74f6263b3ce..145561b76c4e2 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -3,9 +3,9 @@ use rustc_macros::HashStable; use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; -use crate::ty::visit::try_visit; use crate::ty::{ self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, + try_visit, }; pub type Goal<'tcx, P> = ir::solve::Goal, P>; diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index ed7c98ee0e011..05c19db4caa8c 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -6,8 +6,7 @@ use rustc_span::sym; use crate::error::StrictCoherenceNeedsNegativeCoherence; use crate::ty::fast_reject::SimplifiedType; -use crate::ty::visit::TypeVisitableExt; -use crate::ty::{self, TyCtxt}; +use crate::ty::{self, TyCtxt, TypeVisitableExt}; /// A per-trait graph of impls in specialization order. At the moment, this /// graph forms a tree rooted with the trait itself, with all other nodes @@ -72,10 +71,10 @@ impl OverlapMode { .as_local() .into_iter() .flat_map(|local_def_id| { - tcx.hir().attrs(tcx.local_def_id_to_hir_id(local_def_id)) + tcx.hir_attrs(tcx.local_def_id_to_hir_id(local_def_id)) }) .find(|attr| attr.has_name(sym::rustc_strict_coherence)) - .map(|attr| attr.span); + .map(|attr| attr.span()); tcx.dcx().emit_err(StrictCoherenceNeedsNegativeCoherence { span: tcx.def_span(trait_id), attr_span, diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index b529d17540a82..c1dc6a894cae5 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -4,7 +4,6 @@ use std::ops::Range; use std::str; use rustc_abi::{FIRST_VARIANT, ReprOptions, VariantIdx}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; @@ -54,8 +53,6 @@ bitflags::bitflags! { const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8; /// Indicates whether the type is `UnsafeCell`. const IS_UNSAFE_CELL = 1 << 9; - /// Indicates whether the type is anonymous. - const IS_ANONYMOUS = 1 << 10; } } rustc_data_structures::external_bitflags_debug! { AdtFlags } @@ -403,12 +400,6 @@ impl<'tcx> AdtDef<'tcx> { self.flags().contains(AdtFlags::IS_MANUALLY_DROP) } - /// Returns `true` if this is an anonymous adt - #[inline] - pub fn is_anonymous(self) -> bool { - self.flags().contains(AdtFlags::IS_ANONYMOUS) - } - /// Returns `true` if this type has a destructor. pub fn has_dtor(self, tcx: TyCtxt<'tcx>) -> bool { self.destructor(tcx).is_some() @@ -540,7 +531,7 @@ impl<'tcx> AdtDef<'tcx> { pub fn discriminants( self, tcx: TyCtxt<'tcx>, - ) -> impl Iterator)> + Captures<'tcx> { + ) -> impl Iterator)> { assert!(self.is_enum()); let repr_type = self.repr().discr_type(); let initial = repr_type.initial_discriminant(tcx); diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index 6309dd2e490ff..ce4c08aa485e5 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -3,7 +3,7 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_macros::{Decodable, Encodable, HashStable}; -use rustc_span::{Ident, Symbol}; +use rustc_span::{Ident, Symbol, sym}; use super::{TyCtxt, Visibility}; use crate::ty; @@ -108,6 +108,24 @@ impl AssocItem { pub fn is_impl_trait_in_trait(&self) -> bool { self.opt_rpitit_info.is_some() } + + /// Returns true if: + /// - This trait associated item has the `#[type_const]` attribute, + /// - If it is in a trait impl, the item from the original trait has this attribute, or + /// - It is an inherent assoc const. + pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool { + if self.kind != ty::AssocKind::Const { + return false; + } + + let def_id = match (self.container, self.trait_item_def_id) { + (AssocItemContainer::Trait, _) => self.def_id, + (AssocItemContainer::Impl, Some(trait_item_did)) => trait_item_did, + // Inherent impl but this attr is only applied to trait assoc items. + (AssocItemContainer::Impl, None) => return true, + }; + tcx.has_attr(def_id, sym::type_const) + } } #[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)] diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index c4d5367e2f03a..703b6ce92471f 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -1,6 +1,5 @@ use std::fmt::Write; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_hir::HirId; @@ -52,6 +51,9 @@ pub enum UpvarCapture { /// depending on inference. ByValue, + /// Upvar is captured by use. This is true when the closure is labeled `use`. + ByUse, + /// Upvar is captured by reference. ByRef(BorrowKind), } @@ -179,7 +181,7 @@ impl<'tcx> CapturedPlace<'tcx> { pub fn is_by_ref(&self) -> bool { match self.info.capture_kind { - ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => false, ty::UpvarCapture::ByRef(..) => true, } } @@ -215,7 +217,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn closure_captures(self, def_id: LocalDefId) -> &'tcx [&'tcx ty::CapturedPlace<'tcx>] { if !self.is_closure_like(def_id.to_def_id()) { return &[]; - }; + } self.closure_typeinfo(def_id).captures } } @@ -294,7 +296,7 @@ pub struct CaptureInfo { pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String { let mut curr_string: String = match place.base { - HirPlaceBase::Upvar(upvar_id) => tcx.hir().name(upvar_id.var_path.hir_id).to_string(), + HirPlaceBase::Upvar(upvar_id) => tcx.hir_name(upvar_id.var_path.hir_id).to_string(), _ => bug!("Capture_information should only contain upvars"), }; @@ -415,7 +417,7 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>( parent_captures: impl IntoIterator>, child_captures: impl IntoIterator>, mut for_each: impl FnMut((usize, &'a CapturedPlace<'tcx>), (usize, &'a CapturedPlace<'tcx>)) -> T, -) -> impl Iterator + Captures<'a> + Captures<'tcx> { +) -> impl Iterator { std::iter::from_coroutine( #[coroutine] move || { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 41958949836a7..74b34afe616b9 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -14,9 +14,8 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::LocalDefId; use rustc_serialize::{Decodable, Encodable}; -use rustc_span::Span; use rustc_span::source_map::Spanned; -pub use rustc_type_ir::{TyDecoder, TyEncoder}; +use rustc_span::{Span, SpanDecoder, SpanEncoder}; use crate::arena::ArenaAllocatable; use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; @@ -31,13 +30,45 @@ use crate::ty::{self, AdtDef, GenericArgsRef, Ty, TyCtxt}; /// This offset is also chosen so that the first byte is never < 0x80. pub const SHORTHAND_OFFSET: usize = 0x80; -pub trait EncodableWithShorthand: Copy + Eq + Hash { +pub trait TyEncoder<'tcx>: SpanEncoder { + const CLEAR_CROSS_CRATE: bool; + + fn position(&self) -> usize; + + fn type_shorthands(&mut self) -> &mut FxHashMap, usize>; + + fn predicate_shorthands(&mut self) -> &mut FxHashMap, usize>; + + fn encode_alloc_id(&mut self, alloc_id: &AllocId); +} + +pub trait TyDecoder<'tcx>: SpanDecoder { + const CLEAR_CROSS_CRATE: bool; + + fn interner(&self) -> TyCtxt<'tcx>; + + fn cached_ty_for_shorthand(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx> + where + F: FnOnce(&mut Self) -> Ty<'tcx>; + + fn with_position(&mut self, pos: usize, f: F) -> R + where + F: FnOnce(&mut Self) -> R; + + fn positioned_at_shorthand(&self) -> bool { + (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0 + } + + fn decode_alloc_id(&mut self) -> AllocId; +} + +pub trait EncodableWithShorthand<'tcx, E: TyEncoder<'tcx>>: Copy + Eq + Hash { type Variant: Encodable; fn variant(&self) -> &Self::Variant; } #[allow(rustc::usage_of_ty_tykind)] -impl<'tcx, E: TyEncoder>> EncodableWithShorthand for Ty<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> { type Variant = ty::TyKind<'tcx>; #[inline] @@ -46,7 +77,7 @@ impl<'tcx, E: TyEncoder>> EncodableWithShorthand for Ty<'tcx } } -impl<'tcx, E: TyEncoder>> EncodableWithShorthand for ty::PredicateKind<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::PredicateKind<'tcx> { type Variant = ty::PredicateKind<'tcx>; #[inline] @@ -65,16 +96,16 @@ impl<'tcx, E: TyEncoder>> EncodableWithShorthand for ty::Pre /// /// `Decodable` can still be implemented in cases where `Decodable` is required /// by a trait bound. -pub trait RefDecodable<'tcx, D: TyDecoder>> { +pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> { fn decode(d: &mut D) -> &'tcx Self; } /// Encode the given value or a previously cached shorthand. pub fn encode_with_shorthand<'tcx, E, T, M>(encoder: &mut E, value: &T, cache: M) where - E: TyEncoder>, + E: TyEncoder<'tcx>, M: for<'b> Fn(&'b mut E) -> &'b mut FxHashMap, - T: EncodableWithShorthand, + T: EncodableWithShorthand<'tcx, E>, // The discriminant and shorthand must have the same size. T::Variant: DiscriminantKind, { @@ -108,13 +139,13 @@ where } } -impl<'tcx, E: TyEncoder>> Encodable for Ty<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for Ty<'tcx> { fn encode(&self, e: &mut E) { encode_with_shorthand(e, self, TyEncoder::type_shorthands); } } -impl<'tcx, E: TyEncoder>> Encodable for ty::Predicate<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Predicate<'tcx> { fn encode(&self, e: &mut E) { let kind = self.kind(); kind.bound_vars().encode(e); @@ -122,76 +153,72 @@ impl<'tcx, E: TyEncoder>> Encodable for ty::Predicate<'tcx> } } -impl<'tcx, E: TyEncoder>> Encodable for ty::Clause<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Clause<'tcx> { fn encode(&self, e: &mut E) { self.as_predicate().encode(e); } } -impl<'tcx, E: TyEncoder>> Encodable for ty::Region<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Region<'tcx> { fn encode(&self, e: &mut E) { self.kind().encode(e); } } -impl<'tcx, E: TyEncoder>> Encodable for ty::Const<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Const<'tcx> { fn encode(&self, e: &mut E) { self.0.0.encode(e); } } -impl<'tcx, E: TyEncoder>> Encodable for ty::Pattern<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::Pattern<'tcx> { fn encode(&self, e: &mut E) { self.0.0.encode(e); } } -impl<'tcx, E: TyEncoder>> Encodable for ty::ValTree<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::ValTree<'tcx> { fn encode(&self, e: &mut E) { self.0.0.encode(e); } } -impl<'tcx, E: TyEncoder>> Encodable for ConstAllocation<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ConstAllocation<'tcx> { fn encode(&self, e: &mut E) { self.inner().encode(e) } } -impl<'tcx, E: TyEncoder>> Encodable for AdtDef<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for AdtDef<'tcx> { fn encode(&self, e: &mut E) { self.0.0.encode(e) } } -impl<'tcx, E: TyEncoder>> Encodable for AllocId { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for AllocId { fn encode(&self, e: &mut E) { e.encode_alloc_id(self) } } -impl<'tcx, E: TyEncoder>> Encodable for CtfeProvenance { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for CtfeProvenance { fn encode(&self, e: &mut E) { self.into_parts().encode(e); } } -impl<'tcx, E: TyEncoder>> Encodable for ty::ParamEnv<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for ty::ParamEnv<'tcx> { fn encode(&self, e: &mut E) { self.caller_bounds().encode(e); } } #[inline] -fn decode_arena_allocable< - 'tcx, - D: TyDecoder>, - T: ArenaAllocatable<'tcx> + Decodable, ->( +fn decode_arena_allocable<'tcx, D: TyDecoder<'tcx>, T: ArenaAllocatable<'tcx> + Decodable>( decoder: &mut D, ) -> &'tcx T where - D: TyDecoder, + D: TyDecoder<'tcx>, { decoder.interner().arena.alloc(Decodable::decode(decoder)) } @@ -199,18 +226,18 @@ where #[inline] fn decode_arena_allocable_slice< 'tcx, - D: TyDecoder>, + D: TyDecoder<'tcx>, T: ArenaAllocatable<'tcx> + Decodable, >( decoder: &mut D, ) -> &'tcx [T] where - D: TyDecoder, + D: TyDecoder<'tcx>, { decoder.interner().arena.alloc_from_iter( as Decodable>::decode(decoder)) } -impl<'tcx, D: TyDecoder>> Decodable for Ty<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for Ty<'tcx> { #[allow(rustc::usage_of_ty_tykind)] fn decode(decoder: &mut D) -> Ty<'tcx> { // Handle shorthands first, if we have a usize > 0x80. @@ -224,12 +251,12 @@ impl<'tcx, D: TyDecoder>> Decodable for Ty<'tcx> { }) } else { let tcx = decoder.interner(); - tcx.mk_ty_from_kind(rustc_type_ir::TyKind::decode(decoder)) + tcx.mk_ty_from_kind(ty::TyKind::decode(decoder)) } } } -impl<'tcx, D: TyDecoder>> Decodable for ty::Predicate<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Predicate<'tcx> { fn decode(decoder: &mut D) -> ty::Predicate<'tcx> { let bound_vars = Decodable::decode(decoder); // Handle shorthands first, if we have a usize > 0x80. @@ -249,14 +276,14 @@ impl<'tcx, D: TyDecoder>> Decodable for ty::Predicate<'tcx> } } -impl<'tcx, D: TyDecoder>> Decodable for ty::Clause<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Clause<'tcx> { fn decode(decoder: &mut D) -> ty::Clause<'tcx> { let pred: ty::Predicate<'tcx> = Decodable::decode(decoder); pred.expect_clause() } } -impl<'tcx, D: TyDecoder>> Decodable for GenericArgsRef<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for GenericArgsRef<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); let tcx = decoder.interner(); @@ -266,7 +293,7 @@ impl<'tcx, D: TyDecoder>> Decodable for GenericArgsRef<'tcx> } } -impl<'tcx, D: TyDecoder>> Decodable for mir::Place<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for mir::Place<'tcx> { fn decode(decoder: &mut D) -> Self { let local: mir::Local = Decodable::decode(decoder); let len = decoder.read_usize(); @@ -277,13 +304,13 @@ impl<'tcx, D: TyDecoder>> Decodable for mir::Place<'tcx> { } } -impl<'tcx, D: TyDecoder>> Decodable for ty::Region<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Region<'tcx> { fn decode(decoder: &mut D) -> Self { ty::Region::new_from_kind(decoder.interner(), Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder>> Decodable for CanonicalVarInfos<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for CanonicalVarInfos<'tcx> { fn decode(decoder: &mut D) -> Self { let len = decoder.read_usize(); decoder.interner().mk_canonical_var_infos_from_iter( @@ -292,26 +319,26 @@ impl<'tcx, D: TyDecoder>> Decodable for CanonicalVarInfos<'t } } -impl<'tcx, D: TyDecoder>> Decodable for AllocId { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for AllocId { fn decode(decoder: &mut D) -> Self { decoder.decode_alloc_id() } } -impl<'tcx, D: TyDecoder>> Decodable for CtfeProvenance { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for CtfeProvenance { fn decode(decoder: &mut D) -> Self { let parts = Decodable::decode(decoder); CtfeProvenance::from_parts(parts) } } -impl<'tcx, D: TyDecoder>> Decodable for ty::SymbolName<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::SymbolName<'tcx> { fn decode(decoder: &mut D) -> Self { ty::SymbolName::new(decoder.interner(), decoder.read_str()) } } -impl<'tcx, D: TyDecoder>> Decodable for ty::ParamEnv<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::ParamEnv<'tcx> { fn decode(d: &mut D) -> Self { let caller_bounds = Decodable::decode(d); ty::ParamEnv::new(caller_bounds) @@ -320,7 +347,7 @@ impl<'tcx, D: TyDecoder>> Decodable for ty::ParamEnv<'tcx> { macro_rules! impl_decodable_via_ref { ($($t:ty,)+) => { - $(impl<'tcx, D: TyDecoder>> Decodable for $t { + $(impl<'tcx, D: TyDecoder<'tcx>> Decodable for $t { fn decode(decoder: &mut D) -> Self { RefDecodable::decode(decoder) } @@ -328,7 +355,7 @@ macro_rules! impl_decodable_via_ref { } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List> { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder @@ -337,7 +364,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List>> RefDecodable<'tcx, D> +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { fn decode(decoder: &mut D) -> &'tcx Self { @@ -348,38 +375,38 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> } } -impl<'tcx, D: TyDecoder>> Decodable for ty::Const<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Const<'tcx> { fn decode(decoder: &mut D) -> Self { let kind: ty::ConstKind<'tcx> = Decodable::decode(decoder); decoder.interner().mk_ct_from_kind(kind) } } -impl<'tcx, D: TyDecoder>> Decodable for ty::Pattern<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::Pattern<'tcx> { fn decode(decoder: &mut D) -> Self { decoder.interner().mk_pat(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder>> Decodable for ty::ValTree<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ty::ValTree<'tcx> { fn decode(decoder: &mut D) -> Self { decoder.interner().intern_valtree(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder>> Decodable for ConstAllocation<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for ConstAllocation<'tcx> { fn decode(decoder: &mut D) -> Self { decoder.interner().mk_const_alloc(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder>> Decodable for AdtDef<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for AdtDef<'tcx> { fn decode(decoder: &mut D) -> Self { decoder.interner().mk_adt_def_from_data(Decodable::decode(decoder)) } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Clause<'tcx>, Span)] { fn decode(decoder: &mut D) -> &'tcx Self { decoder .interner() @@ -388,9 +415,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [(ty::Claus } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> - for [(ty::PolyTraitRef<'tcx>, Span)] -{ +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::PolyTraitRef<'tcx>, Span)] { fn decode(decoder: &mut D) -> &'tcx Self { decoder .interner() @@ -399,7 +424,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [Spanned>] { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [Spanned>] { fn decode(decoder: &mut D) -> &'tcx Self { decoder .interner() @@ -408,9 +433,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [Spanned>> RefDecodable<'tcx, D> - for ty::List -{ +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder.interner().mk_bound_variable_kinds_from_iter( @@ -419,7 +442,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List> { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List> { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder.interner().mk_const_list_from_iter( @@ -428,7 +451,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List>> RefDecodable<'tcx, D> +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::ListWithCachedTypeInfo> { fn decode(decoder: &mut D) -> &'tcx Self { @@ -439,7 +462,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder @@ -448,7 +471,7 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List>> RefDecodable<'tcx, D> for ty::List { +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder.interner().mk_local_def_ids_from_iter( @@ -457,15 +480,13 @@ impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for ty::List>> Decodable for &'tcx ty::List { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for &'tcx ty::List { fn decode(d: &mut D) -> Self { RefDecodable::decode(d) } } -impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> - for ty::List<(VariantIdx, FieldIdx)> -{ +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<(VariantIdx, FieldIdx)> { fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder.interner().mk_offset_of_from_iter( @@ -503,14 +524,14 @@ macro_rules! impl_arena_allocatable_decoder { ([]$args:tt) => {}; ([decode $(, $attrs:ident)*] [$name:ident: $ty:ty]) => { - impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for $ty { + impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty { #[inline] fn decode(decoder: &mut D) -> &'tcx Self { decode_arena_allocable(decoder) } } - impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [$ty] { + impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] { #[inline] fn decode(decoder: &mut D) -> &'tcx Self { decode_arena_allocable_slice(decoder) @@ -532,14 +553,14 @@ arena_types!(impl_arena_allocatable_decoders); macro_rules! impl_arena_copy_decoder { (<$tcx:tt> $($ty:ty,)*) => { - $(impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for $ty { + $(impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty { #[inline] fn decode(decoder: &mut D) -> &'tcx Self { decoder.interner().arena.alloc(Decodable::decode(decoder)) } } - impl<'tcx, D: TyDecoder>> RefDecodable<'tcx, D> for [$ty] { + impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] { #[inline] fn decode(decoder: &mut D) -> &'tcx Self { decoder.interner().arena.alloc_from_iter( as Decodable>::decode(decoder)) diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index d30520a0222fc..ae1c6c670cbca 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -34,7 +34,7 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> { } } -impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> { +impl<'tcx> rustc_type_ir::Flags for Const<'tcx> { fn flags(&self) -> TypeFlags { self.0.flags } diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs index b72edc1c53255..9f5e31d894cb3 100644 --- a/compiler/rustc_middle/src/ty/consts/int.rs +++ b/compiler/rustc_middle/src/ty/consts/int.rs @@ -118,7 +118,7 @@ impl std::fmt::Debug for ConstInt { impl IntoDiagArg for ConstInt { // FIXME this simply uses the Debug impl, but we could probably do better by converting both // to an inherent method that returns `Cow`. - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(format!("{self:?}").into()) } } @@ -408,7 +408,7 @@ macro_rules! from_x_for_scalar_int { fn from(u: $ty) -> Self { Self { data: u128::from(u), - size: NonZero::new(std::mem::size_of::<$ty>() as u8).unwrap(), + size: NonZero::new(size_of::<$ty>() as u8).unwrap(), } } } @@ -424,7 +424,7 @@ macro_rules! from_scalar_int_for_x { fn from(int: ScalarInt) -> Self { // The `unwrap` cannot fail because to_bits (if it succeeds) // is guaranteed to return a value that fits into the size. - int.to_bits(Size::from_bytes(std::mem::size_of::<$ty>())) + int.to_bits(Size::from_bytes(size_of::<$ty>())) .try_into().unwrap() } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 32a9e67f9ad53..f54dd2b0040ae 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -49,11 +49,10 @@ use rustc_session::{Limit, MetadataKind, Session}; use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_type_ir::TyKind::*; -use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; use rustc_type_ir::{ - CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, elaborate, search_graph, + CollectAndApply, Interner, TypeFlags, TypeFoldable, WithCachedTypeInfo, elaborate, search_graph, }; use tracing::{debug, instrument}; @@ -324,11 +323,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.features() } - fn bound_coroutine_hidden_types( + fn coroutine_hidden_types( self, def_id: DefId, - ) -> impl IntoIterator>>> { - self.bound_coroutine_hidden_types(def_id) + ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List>>> { + self.coroutine_hidden_types(def_id) } fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { @@ -594,6 +593,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_is_auto(trait_def_id) } + fn trait_is_coinductive(self, trait_def_id: DefId) -> bool { + self.trait_is_coinductive(trait_def_id) + } + fn trait_is_alias(self, trait_def_id: DefId) -> bool { self.trait_is_alias(trait_def_id) } @@ -812,32 +815,38 @@ pub struct CtxtInterners<'tcx> { impl<'tcx> CtxtInterners<'tcx> { fn new(arena: &'tcx WorkerLocal>) -> CtxtInterners<'tcx> { + // Default interner size - this value has been chosen empirically, and may need to be adjusted + // as the compiler evolves. + const N: usize = 2048; CtxtInterners { arena, - type_: Default::default(), - const_lists: Default::default(), - args: Default::default(), - type_lists: Default::default(), - region: Default::default(), - poly_existential_predicates: Default::default(), - canonical_var_infos: Default::default(), - predicate: Default::default(), - clauses: Default::default(), - projs: Default::default(), - place_elems: Default::default(), - const_: Default::default(), - pat: Default::default(), - const_allocation: Default::default(), - bound_variable_kinds: Default::default(), - layout: Default::default(), - adt_def: Default::default(), - external_constraints: Default::default(), - predefined_opaques_in_body: Default::default(), - fields: Default::default(), - local_def_ids: Default::default(), - captures: Default::default(), - offset_of: Default::default(), - valtree: Default::default(), + // The factors have been chosen by @FractalFir based on observed interner sizes, and local perf runs. + // To get the interner sizes, insert `eprintln` printing the size of the interner in functions like `intern_ty`. + // Bigger benchmarks tend to give more accurate ratios, so use something like `x perf eprintln --includes cargo`. + type_: InternedSet::with_capacity(N * 16), + const_lists: InternedSet::with_capacity(N * 4), + args: InternedSet::with_capacity(N * 4), + type_lists: InternedSet::with_capacity(N * 4), + region: InternedSet::with_capacity(N * 4), + poly_existential_predicates: InternedSet::with_capacity(N / 4), + canonical_var_infos: InternedSet::with_capacity(N / 2), + predicate: InternedSet::with_capacity(N), + clauses: InternedSet::with_capacity(N), + projs: InternedSet::with_capacity(N * 4), + place_elems: InternedSet::with_capacity(N * 2), + const_: InternedSet::with_capacity(N * 2), + pat: InternedSet::with_capacity(N), + const_allocation: InternedSet::with_capacity(N), + bound_variable_kinds: InternedSet::with_capacity(N * 2), + layout: InternedSet::with_capacity(N), + adt_def: InternedSet::with_capacity(N), + external_constraints: InternedSet::with_capacity(N), + predefined_opaques_in_body: InternedSet::with_capacity(N), + fields: InternedSet::with_capacity(N * 4), + local_def_ids: InternedSet::with_capacity(N), + captures: InternedSet::with_capacity(N), + offset_of: InternedSet::with_capacity(N), + valtree: InternedSet::with_capacity(N), } } @@ -1289,7 +1298,7 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { ), bodies, }))); - self.feed_owner_id().hir_attrs(attrs); + self.feed_owner_id().hir_attr_map(attrs); } } @@ -1317,6 +1326,11 @@ pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } +// Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its +// field are asserted to implement these traits below, so this is trivially safe, and it greatly +// speeds-up compilation of this crate and its dependents. +unsafe impl DynSend for TyCtxt<'_> {} +unsafe impl DynSync for TyCtxt<'_> {} fn _assert_tcx_fields() { sync::assert_dyn_sync::<&'_ GlobalCtxt<'_>>(); sync::assert_dyn_send::<&'_ GlobalCtxt<'_>>(); @@ -1472,7 +1486,11 @@ impl<'tcx> TyCtxt<'tcx> { self.codegen_fn_attrs(def_id) } else if matches!( def_kind, - DefKind::AnonConst | DefKind::AssocConst | DefKind::Const | DefKind::InlineConst + DefKind::AnonConst + | DefKind::AssocConst + | DefKind::Const + | DefKind::InlineConst + | DefKind::GlobalAsm ) { CodegenFnAttrs::EMPTY } else { @@ -1538,7 +1556,7 @@ impl<'tcx> TyCtxt<'tcx> { Bound::Included(a.get()) } else { self.dcx().span_delayed_bug( - attr.span, + attr.span(), "invalid rustc_layout_scalar_valid_range attribute", ); Bound::Unbounded @@ -1871,7 +1889,7 @@ impl<'tcx> TyCtxtAt<'tcx> { pub fn create_def( self, parent: LocalDefId, - name: Symbol, + name: Option, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { let feed = self.tcx.create_def(parent, name, def_kind); @@ -1886,7 +1904,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn create_def( self, parent: LocalDefId, - name: Symbol, + name: Option, def_kind: DefKind, ) -> TyCtxtFeed<'tcx, LocalDefId> { let data = def_kind.def_path_data(name); @@ -1939,7 +1957,7 @@ impl<'tcx> TyCtxt<'tcx> { Ok(TyCtxtFeed { key: num, tcx: self }) } - pub fn iter_local_def_id(self) -> impl Iterator + 'tcx { + pub fn iter_local_def_id(self) -> impl Iterator { // Create a dependency to the red node to be sure we re-execute this when the amount of // definitions change. self.dep_graph.read_index(DepNodeIndex::FOREVER_RED_NODE); @@ -2171,14 +2189,14 @@ impl<'tcx> TyCtxt<'tcx> { } /// All traits in the crate graph, including those not visible to the user. - pub fn all_traits(self) -> impl Iterator + 'tcx { + pub fn all_traits(self) -> impl Iterator { iter::once(LOCAL_CRATE) .chain(self.crates(()).iter().copied()) .flat_map(move |cnum| self.traits(cnum).iter().copied()) } /// All traits that are visible within the crate graph (i.e. excluding private dependencies). - pub fn visible_traits(self) -> impl Iterator + 'tcx { + pub fn visible_traits(self) -> impl Iterator { let visible_crates = self.crates(()).iter().copied().filter(move |cnum| self.is_user_visible_dep(*cnum)); @@ -2195,7 +2213,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the origin of the opaque type `def_id`. #[instrument(skip(self), level = "trace", ret)] pub fn local_opaque_ty_origin(self, def_id: LocalDefId) -> hir::OpaqueTyOrigin { - self.hir().expect_opaque_ty(def_id).origin + self.hir_expect_opaque_ty(def_id).origin } pub fn finish(self) { @@ -2317,8 +2335,8 @@ macro_rules! sty_debug_print { $(let mut $variant = total;)* for shard in tcx.interners.type_.lock_shards() { - let types = shard.keys(); - for &InternedInSet(t) in types { + let types = shard.iter(); + for &(InternedInSet(t), ()) in types { let variant = match t.internee { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, @@ -2363,7 +2381,7 @@ macro_rules! sty_debug_print { } impl<'tcx> TyCtxt<'tcx> { - pub fn debug_stats(self) -> impl fmt::Debug + 'tcx { + pub fn debug_stats(self) -> impl fmt::Debug { fmt::from_fn(move |fmt| { sty_debug_print!( fmt, @@ -3099,9 +3117,11 @@ impl<'tcx> TyCtxt<'tcx> { pub fn late_bound_vars(self, id: HirId) -> &'tcx List { self.mk_bound_variable_kinds( - &self.late_bound_vars_map(id.owner).get(&id.local_id).cloned().unwrap_or_else(|| { - bug!("No bound vars found for {}", self.hir().node_to_string(id)) - }), + &self + .late_bound_vars_map(id.owner) + .get(&id.local_id) + .cloned() + .unwrap_or_else(|| bug!("No bound vars found for {}", self.hir_id_to_string(id))), ) } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index cb218a27e6237..881381a5ee61e 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -19,8 +19,16 @@ use crate::ty::{ TypeSuperVisitable, TypeVisitable, TypeVisitor, }; +impl IntoDiagArg for Ty<'_> { + fn into_diag_arg(self, path: &mut Option) -> rustc_errors::DiagArgValue { + ty::tls::with(|tcx| { + let ty = tcx.short_string(self, path); + rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(ty)) + }) + } +} + into_diag_arg_using_display! { - Ty<'_>, ty::Region<'_>, } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index ecca1d4490769..f25c48cf42ab7 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -1,8 +1,9 @@ use tracing::debug; use crate::query::Providers; -use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; -use crate::ty::{self, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; +use crate::ty::{ + self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, +}; pub(super) fn provide(providers: &mut Providers) { *providers = Providers { erase_regions_ty, ..*providers }; diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 8c1991ddb36ee..a0e67929c5289 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -213,10 +213,9 @@ impl<'tcx> Ty<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String + pub fn string_with_limit(self, p: T, length_limit: usize) -> String where - T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift> + Copy, - >>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>, + T: Copy + for<'a, 'b> Lift, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { let mut type_limit = 50; let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { @@ -253,10 +252,9 @@ impl<'tcx> TyCtxt<'tcx> { /// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps /// the existence of a "long type" anywhere in the diagnostic, so the note telling the user /// where we wrote the file to is only printed once. - pub fn short_string<'a, T>(self, p: T, path: &mut Option) -> String + pub fn short_string(self, p: T, path: &mut Option) -> String where - T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift> + Copy + Hash, - >>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>, + T: Copy + Hash + for<'a, 'b> Lift, Lifted: Print<'b, FmtPrinter<'a, 'b>>>, { let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { self.lift(p).expect("could not lift for printing").print(cx) diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index ec0498b168c01..0b8f0e8cd41d9 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -220,13 +220,9 @@ impl FlagComputation { &ty::Pat(ty, pat) => { self.add_ty(ty); match *pat { - ty::PatternKind::Range { start, end, include_end: _ } => { - if let Some(start) = start { - self.add_const(start) - } - if let Some(end) = end { - self.add_const(end) - } + ty::PatternKind::Range { start, end } => { + self.add_const(start); + self.add_const(end); } } } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 4ea4050ed8b1d..dc2c9e3d9f119 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,12 +1,11 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; use rustc_type_ir::data_structures::DelayedMap; -pub use rustc_type_ir::fold::{ - FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, fold_regions, shift_region, - shift_vars, -}; -use crate::ty::{self, Binder, BoundTy, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{ + self, Binder, BoundTy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, +}; /////////////////////////////////////////////////////////////////////////// // Some sample folders @@ -129,7 +128,7 @@ where ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => { let ty = self.delegate.replace_ty(bound_ty); debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST)); - ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32()) + ty::shift_vars(self.tcx, ty, self.current_index.as_u32()) } _ => { if !t.has_vars_bound_at_or_above(self.current_index) { @@ -169,7 +168,7 @@ where ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => { let ct = self.delegate.replace_const(bound_const); debug_assert!(!ct.has_vars_bound_above(ty::INNERMOST)); - ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32()) + ty::shift_vars(self.tcx, ct, self.current_index.as_u32()) } _ => ct.super_fold_with(self), } diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index b74ddb817103e..e87859a55eddd 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -2,23 +2,22 @@ use core::intrinsics; use std::marker::PhantomData; -use std::mem; use std::num::NonZero; use std::ptr::NonNull; use rustc_data_structures::intern::Interned; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_hir::def_id::DefId; -use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension}; +use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_serialize::{Decodable, Encodable}; use rustc_type_ir::WithCachedTypeInfo; use smallvec::SmallVec; use crate::ty::codec::{TyDecoder, TyEncoder}; -use crate::ty::fold::{FallibleTypeFolder, TypeFoldable}; -use crate::ty::visit::{TypeVisitable, TypeVisitor, VisitorResult, walk_visitable_list}; use crate::ty::{ - self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, InlineConstArgs, Lift, List, Ty, TyCtxt, + self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, InlineConstArgs, + Lift, List, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, VisitorResult, + walk_visitable_list, }; pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind>; @@ -159,8 +158,8 @@ unsafe impl<'tcx> Sync for GenericArg<'tcx> where } impl<'tcx> IntoDiagArg for GenericArg<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { + self.to_string().into_diag_arg(&mut None) } } @@ -176,17 +175,17 @@ impl<'tcx> GenericArgKind<'tcx> { let (tag, ptr) = match self { GenericArgKind::Lifetime(lt) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*lt.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*lt.0.0) & TAG_MASK, 0); (REGION_TAG, NonNull::from(lt.0.0).cast()) } GenericArgKind::Type(ty) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ty.0.0) & TAG_MASK, 0); (TYPE_TAG, NonNull::from(ty.0.0).cast()) } GenericArgKind::Const(ct) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ct.0.0) & TAG_MASK, 0); (CONST_TAG, NonNull::from(ct.0.0).cast()) } }; @@ -335,13 +334,13 @@ impl<'tcx> TypeVisitable> for GenericArg<'tcx> { } } -impl<'tcx, E: TyEncoder>> Encodable for GenericArg<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for GenericArg<'tcx> { fn encode(&self, e: &mut E) { self.unpack().encode(e) } } -impl<'tcx, D: TyDecoder>> Decodable for GenericArg<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for GenericArg<'tcx> { fn decode(d: &mut D) -> GenericArg<'tcx> { GenericArgKind::decode(d).pack() } @@ -479,25 +478,23 @@ impl<'tcx> GenericArgs<'tcx> { } #[inline] - pub fn types(&'tcx self) -> impl DoubleEndedIterator> + 'tcx { + pub fn types(&self) -> impl DoubleEndedIterator> { self.iter().filter_map(|k| k.as_type()) } #[inline] - pub fn regions(&'tcx self) -> impl DoubleEndedIterator> + 'tcx { + pub fn regions(&self) -> impl DoubleEndedIterator> { self.iter().filter_map(|k| k.as_region()) } #[inline] - pub fn consts(&'tcx self) -> impl DoubleEndedIterator> + 'tcx { + pub fn consts(&self) -> impl DoubleEndedIterator> { self.iter().filter_map(|k| k.as_const()) } /// Returns generic arguments that are not lifetimes. #[inline] - pub fn non_erasable_generics( - &'tcx self, - ) -> impl DoubleEndedIterator> + 'tcx { + pub fn non_erasable_generics(&self) -> impl DoubleEndedIterator> { self.iter().filter_map(|k| match k.unpack() { ty::GenericArgKind::Lifetime(_) => None, generic => Some(generic), diff --git a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs index 505c7278176f3..953ad62be0a86 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/inhabited_predicate.rs @@ -236,6 +236,11 @@ impl<'tcx> InhabitedPredicate<'tcx> { self.instantiate_opt(tcx, args).unwrap_or(self) } + /// Same as [`Self::instantiate`], but if there is no generics to + /// instantiate, returns `None`. This is useful because it lets us avoid + /// allocating a recursive copy of everything when the result is unchanged. + /// + /// Only used to implement `instantiate` itself. fn instantiate_opt(self, tcx: TyCtxt<'tcx>, args: ty::GenericArgsRef<'tcx>) -> Option { match self { Self::ConstIsZero(c) => { @@ -260,7 +265,10 @@ impl<'tcx> InhabitedPredicate<'tcx> { Some(InhabitedPredicate::True) => Some(InhabitedPredicate::True), Some(a) => Some(a.or(tcx, b.instantiate_opt(tcx, args).unwrap_or(b))), }, - _ => None, + Self::True | Self::False | Self::NotInModule(_) => None, + Self::OpaqueType(_) => { + bug!("unexpected OpaqueType in InhabitedPredicate"); + } } } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e9c19331e4a0b..b99148f336847 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -111,8 +111,9 @@ pub enum InstanceKind<'tcx> { /// Dynamic dispatch to `::fn`. /// - /// This `InstanceKind` does not have callable MIR. Calls to `Virtual` instances must be - /// codegen'd as virtual calls through the vtable. + /// This `InstanceKind` may have a callable MIR as the default implementation. + /// Calls to `Virtual` instances must be codegen'd as virtual calls through the vtable. + /// *This means we might not know exactly what is being called.* /// /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more /// details on that). @@ -202,7 +203,7 @@ impl<'tcx> Instance<'tcx> { if !tcx.sess.opts.share_generics() // However, if the def_id is marked inline(never), then it's fine to just reuse the // upstream monomorphization. - && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_parsing::InlineAttr::Never + && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_data_structures::InlineAttr::Never { return None; } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index eb14ed20fbace..ebb6a8c08a54c 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,20 +1,17 @@ -use std::num::NonZero; use std::ops::Bound; use std::{cmp, fmt}; use rustc_abi::{ - AddressSpace, Align, BackendRepr, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, - PointeeInfo, PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, + AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo, + PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout, TyAbiInterface, VariantIdx, Variants, }; use rustc_error_messages::DiagMessage; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; -use rustc_hashes::Hash64; use rustc_hir::LangItem; use rustc_hir::def_id::DefId; -use rustc_index::IndexVec; use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -185,12 +182,7 @@ pub const WIDE_PTR_ADDR: usize = 0; /// - For a slice, this is the length. pub const WIDE_PTR_EXTRA: usize = 1; -/// The maximum supported number of lanes in a SIMD vector. -/// -/// This value is selected based on backend support: -/// * LLVM does not appear to have a vector width limit. -/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer. -pub const MAX_SIMD_LANES: u64 = 1 << 0xF; +pub const MAX_SIMD_LANES: u64 = rustc_abi::MAX_SIMD_LANES; /// Used in `check_validity_requirement` to indicate the kind of initialization /// that is checked to be valid @@ -315,8 +307,8 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> { } impl<'tcx> IntoDiagArg for LayoutError<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { + self.to_string().into_diag_arg(&mut None) } } @@ -762,11 +754,9 @@ where variant_index: VariantIdx, ) -> TyAndLayout<'tcx> { let layout = match this.variants { - Variants::Single { index } - // If all variants but one are uninhabited, the variant layout is the enum layout. - if index == variant_index => - { - this.layout + // If all variants but one are uninhabited, the variant layout is the enum layout. + Variants::Single { index } if index == variant_index => { + return this; } Variants::Single { .. } | Variants::Empty => { @@ -783,29 +773,18 @@ where } let fields = match this.ty.kind() { - ty::Adt(def, _) if def.variants().is_empty() => - bug!("for_variant called on zero-variant enum {}", this.ty), + ty::Adt(def, _) if def.variants().is_empty() => { + bug!("for_variant called on zero-variant enum {}", this.ty) + } ty::Adt(def, _) => def.variant(variant_index).fields.len(), _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty), }; - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: variant_index }, - fields: match NonZero::new(fields) { - Some(fields) => FieldsShape::Union(fields), - None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, - }, - backend_repr: BackendRepr::Memory { sized: true }, - largest_niche: None, - uninhabited: true, - align: tcx.data_layout.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: tcx.data_layout.i8_align.abi, - randomization_seed: Hash64::ZERO, - }) + tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields)) } - Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()), + Variants::Multiple { ref variants, .. } => { + cx.tcx().mk_layout(variants[variant_index].clone()) + } }; assert_eq!(*layout.variants(), Variants::Single { index: variant_index }); diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 6718493f6b32a..0fd370a56195a 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -93,7 +93,7 @@ impl RawList { T: Copy, { assert!(!mem::needs_drop::()); - assert!(mem::size_of::() != 0); + assert!(size_of::() != 0); assert!(!slice.is_empty()); let (layout, _offset) = @@ -155,7 +155,7 @@ macro_rules! impl_list_empty { static EMPTY: ListSkeleton<$header_ty, MaxAlign> = ListSkeleton { header: $header_init, len: 0, data: [] }; - assert!(mem::align_of::() <= mem::align_of::()); + assert!(align_of::() <= align_of::()); // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bd1fb0ca41cf9..a508487c796bf 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -17,7 +17,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::num::NonZero; use std::ptr::NonNull; -use std::{fmt, mem, str}; +use std::{fmt, str}; pub use adt::*; pub use assoc::*; @@ -27,10 +27,13 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; +pub use rustc_ast_ir::{Movability, Mutability, try_visit}; +use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::LangItem; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; @@ -47,10 +50,10 @@ pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym}; pub use rustc_type_ir::relate::VarianceDiagInfo; -pub use rustc_type_ir::{Movability, Mutability, *}; +pub use rustc_type_ir::*; use tracing::{debug, instrument}; pub use vtable::*; -use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; pub use self::closure::{ BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo, @@ -66,7 +69,7 @@ pub use self::context::{ CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls, }; -pub use self::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; +pub use self::fold::*; pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::opaque_types::OpaqueTypeKey; @@ -96,13 +99,14 @@ pub use self::typeck_results::{ CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, IsIdentity, Rust2024IncompatiblePatInfo, TypeckResults, UserType, UserTypeAnnotationIndex, UserTypeKind, }; -pub use self::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; +pub use self::visit::*; use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, CoroutineLayout}; use crate::query::{IntoQueryParam, Providers}; use crate::ty; +use crate::ty::codec::{TyDecoder, TyEncoder}; pub use crate::ty::diagnostics::*; use crate::ty::fast_reject::SimplifiedType; use crate::ty::util::Discr; @@ -114,16 +118,15 @@ pub mod codec; pub mod error; pub mod fast_reject; pub mod flags; -pub mod fold; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; pub mod pattern; pub mod print; pub mod relate; +pub mod significant_drop_order; pub mod trait_def; pub mod util; -pub mod visit; pub mod vtable; pub mod walk; @@ -135,6 +138,7 @@ mod context; mod diagnostics; mod elaborate_impl; mod erase_regions; +mod fold; mod generic_args; mod generics; mod impls_ty; @@ -151,6 +155,7 @@ mod structural_impls; #[allow(hidden_glob_reexports)] mod sty; mod typeck_results; +mod visit; // Data types @@ -165,7 +170,7 @@ pub struct ResolverGlobalCtxt { /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`. pub expn_that_defined: FxHashMap, pub effective_visibilities: EffectiveVisibilities, - pub extern_crate_map: FxHashMap, + pub extern_crate_map: UnordMap, pub maybe_unused_trait_imports: FxIndexSet, pub module_children: LocalDefIdMap>, pub glob_map: FxHashMap>, @@ -439,7 +444,7 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for Ty<'tcx> { } } -impl<'tcx> rustc_type_ir::visit::Flags for Ty<'tcx> { +impl<'tcx> rustc_type_ir::Flags for Ty<'tcx> { fn flags(&self) -> TypeFlags { self.0.flags } @@ -546,13 +551,13 @@ impl<'tcx> TypeVisitable> for Term<'tcx> { } } -impl<'tcx, E: TyEncoder>> Encodable for Term<'tcx> { +impl<'tcx, E: TyEncoder<'tcx>> Encodable for Term<'tcx> { fn encode(&self, e: &mut E) { self.unpack().encode(e) } } -impl<'tcx, D: TyDecoder>> Decodable for Term<'tcx> { +impl<'tcx, D: TyDecoder<'tcx>> Decodable for Term<'tcx> { fn decode(d: &mut D) -> Self { let res: TermKind<'tcx> = Decodable::decode(d); res.pack() @@ -635,12 +640,12 @@ impl<'tcx> TermKind<'tcx> { let (tag, ptr) = match self { TermKind::Ty(ty) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ty.0.0) & TAG_MASK, 0); (TYPE_TAG, NonNull::from(ty.0.0).cast()) } TermKind::Const(ct) => { // Ensure we can use the tag bits. - assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0); + assert_eq!(align_of_val(&*ct.0.0) & TAG_MASK, 0); (CONST_TAG, NonNull::from(ct.0.0).cast()) } }; @@ -935,7 +940,7 @@ impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst { pub type Clauses<'tcx> = &'tcx ListWithCachedTypeInfo>; -impl<'tcx> rustc_type_ir::visit::Flags for Clauses<'tcx> { +impl<'tcx> rustc_type_ir::Flags for Clauses<'tcx> { fn flags(&self) -> TypeFlags { (**self).flags() } @@ -990,12 +995,6 @@ impl<'tcx> ParamEnv<'tcx> { ParamEnv { caller_bounds } } - /// Returns this same environment but with no caller bounds. - #[inline] - pub fn without_caller_bounds(self) -> Self { - Self::new(ListWithCachedTypeInfo::empty()) - } - /// Creates a pair of param-env and value for use in queries. pub fn and>>(self, value: T) -> ParamEnvAnd<'tcx, T> { ParamEnvAnd { param_env: self, value } @@ -1154,7 +1153,7 @@ pub struct VariantDef { /// `DefId` that identifies the variant's constructor. /// If this variant is a struct variant, then this is `None`. pub ctor: Option<(CtorKind, DefId)>, - /// Variant or struct name, maybe empty for anonymous adt (struct or union). + /// Variant or struct name. pub name: Symbol, /// Discriminant of this variant. pub discr: VariantDiscr, @@ -1183,23 +1182,17 @@ impl VariantDef { /// /// If someone speeds up attribute loading to not be a performance concern, they can /// remove this hack and use the constructor `DefId` everywhere. + #[instrument(level = "debug")] pub fn new( name: Symbol, variant_did: Option, ctor: Option<(CtorKind, DefId)>, discr: VariantDiscr, fields: IndexVec, - adt_kind: AdtKind, parent_did: DefId, recover_tainted: Option, is_field_list_non_exhaustive: bool, ) -> Self { - debug!( - "VariantDef::new(name = {:?}, variant_did = {:?}, ctor = {:?}, discr = {:?}, - fields = {:?}, adt_kind = {:?}, parent_did = {:?})", - name, variant_did, ctor, discr, fields, adt_kind, parent_did, - ); - let mut flags = VariantFlags::NO_VARIANT_FLAGS; if is_field_list_non_exhaustive { flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; @@ -1424,39 +1417,6 @@ pub enum ImplOverlapKind { /// Whether or not the impl is permitted due to the trait being a `#[marker]` trait marker: bool, }, - /// These impls are allowed to overlap, but that raises an - /// issue #33140 future-compatibility warning (tracked in #56484). - /// - /// Some background: in Rust 1.0, the trait-object types `Send + Sync` (today's - /// `dyn Send + Sync`) and `Sync + Send` (now `dyn Sync + Send`) were different. - /// - /// The widely-used version 0.1.0 of the crate `traitobject` had accidentally relied on - /// that difference, doing what reduces to the following set of impls: - /// - /// ```compile_fail,(E0119) - /// trait Trait {} - /// impl Trait for dyn Send + Sync {} - /// impl Trait for dyn Sync + Send {} - /// ``` - /// - /// Obviously, once we made these types be identical, that code causes a coherence - /// error and a fairly big headache for us. However, luckily for us, the trait - /// `Trait` used in this case is basically a marker trait, and therefore having - /// overlapping impls for it is sound. - /// - /// To handle this, we basically regard the trait as a marker trait, with an additional - /// future-compatibility warning. To avoid accidentally "stabilizing" this feature, - /// it has the following restrictions: - /// - /// 1. The trait must indeed be a marker-like trait (i.e., no items), and must be - /// positive impls. - /// 2. The trait-ref of both impls must be equal. - /// 3. The trait-ref of both impls must be a trait object type consisting only of - /// marker traits. - /// 4. Neither of the impls can have any where-clauses. - /// - /// Once `traitobject` 0.1.0 is no longer an active concern, this hack can be removed. - FutureCompatOrderDepTraitObjects, } /// Useful source information about where a desugared associated type for an @@ -1495,9 +1455,10 @@ impl<'tcx> TyCtxt<'tcx> { field_shuffle_seed ^= user_seed; } - for attr in self.get_attrs(did, sym::repr) { - for r in attr::parse_repr_attr(self.sess, attr) { - flags.insert(match r { + if let Some(reprs) = attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr(r) => r) + { + for (r, _) in reprs { + flags.insert(match *r { attr::ReprRust => ReprFlags::empty(), attr::ReprC => ReprFlags::IS_C, attr::ReprPacked(pack) => { @@ -1535,6 +1496,10 @@ impl<'tcx> TyCtxt<'tcx> { max_align = max_align.max(Some(align)); ReprFlags::empty() } + attr::ReprEmpty => { + /* skip these, they're just for diagnostics */ + ReprFlags::empty() + } }); } } @@ -1629,7 +1594,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Returns `true` if the impls are the same polarity and the trait either + /// Returns `Some` if the impls are the same polarity and the trait either /// has no items or is annotated `#[marker]` and prevents item overrides. #[instrument(level = "debug", skip(self), ret)] pub fn impls_are_allowed_to_overlap( @@ -1670,18 +1635,6 @@ impl<'tcx> TyCtxt<'tcx> { return Some(ImplOverlapKind::Permitted { marker: true }); } - if let Some(self_ty1) = - self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id1) - && let Some(self_ty2) = - self.self_ty_of_trait_impl_enabling_order_dep_trait_object_hack(def_id2) - { - if self_ty1 == self_ty2 { - return Some(ImplOverlapKind::FutureCompatOrderDepTraitObjects); - } else { - debug!("found {self_ty1:?} != {self_ty2:?}"); - } - } - None } @@ -1745,7 +1698,7 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME(@lcnr): Remove this function. pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [hir::Attribute] { if let Some(did) = did.as_local() { - self.hir().attrs(self.local_def_id_to_hir_id(did)) + self.hir_attrs(self.local_def_id_to_hir_id(did)) } else { self.attrs_for_def(did) } @@ -1756,14 +1709,22 @@ impl<'tcx> TyCtxt<'tcx> { self, did: impl Into, attr: Symbol, + ) -> impl Iterator { + self.get_all_attrs(did).filter(move |a: &&hir::Attribute| a.has_name(attr)) + } + + /// Gets all attributes. + /// + /// To see if an item has a specific attribute, you should use [`rustc_attr_data_structures::find_attr!`] so you can use matching. + pub fn get_all_attrs( + self, + did: impl Into, ) -> impl Iterator { let did: DefId = did.into(); - let filter_fn = move |a: &&hir::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { - self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + self.hir_attrs(self.local_def_id_to_hir_id(did)).iter() } else { - debug_assert!(rustc_feature::encode_cross_crate(attr)); - self.attrs_for_def(did).iter().filter(filter_fn) + self.attrs_for_def(did).iter() } } @@ -1798,17 +1759,14 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn get_attrs_by_path<'attr>( + pub fn get_attrs_by_path( self, did: DefId, - attr: &'attr [Symbol], - ) -> impl Iterator + 'attr - where - 'tcx: 'attr, - { + attr: &[Symbol], + ) -> impl Iterator { let filter_fn = move |a: &&hir::Attribute| a.path_matches(attr); if let Some(did) = did.as_local() { - self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + self.hir_attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) } else { self.attrs_for_def(did).iter().filter(filter_fn) } diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index e86e01451fefb..f2a4a5a4ecf78 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -11,8 +11,10 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use tracing::{debug, instrument}; use crate::traits::query::NoSolution; -use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder}; -use crate::ty::{self, EarlyBinder, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; +use crate::ty::{ + self, EarlyBinder, FallibleTypeFolder, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, + TypeVisitableExt, +}; #[derive(Debug, Copy, Clone, HashStable, TyEncodable, TyDecodable)] pub enum NormalizationError<'tcx> { diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index cf789807bb04a..56c44c8a84c04 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -4,8 +4,9 @@ use rustc_span::def_id::DefId; use tracing::{debug, instrument, trace}; use crate::error::ConstNotUsedTraitAlias; -use crate::ty::fold::{TypeFolder, TypeSuperFoldable}; -use crate::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{ + self, GenericArg, GenericArgKind, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, +}; pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey>; diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 8eaf0a58f7086..19e2b57456327 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use rustc_data_structures::unord::UnordMap; use rustc_hir::def_id::DefIndex; use rustc_index::{Idx, IndexVec}; +use rustc_span::Symbol; use crate::ty; @@ -80,10 +81,10 @@ trivially_parameterized_over_tcx! { rustc_ast::Attribute, rustc_ast::DelimArgs, rustc_ast::expand::StrippedCfgItem, - rustc_attr_parsing::ConstStability, - rustc_attr_parsing::DefaultBodyStability, - rustc_attr_parsing::Deprecation, - rustc_attr_parsing::Stability, + rustc_attr_data_structures::ConstStability, + rustc_attr_data_structures::DefaultBodyStability, + rustc_attr_data_structures::Deprecation, + rustc_attr_data_structures::Stability, rustc_hir::Constness, rustc_hir::Defaultness, rustc_hir::Safety, @@ -96,6 +97,7 @@ trivially_parameterized_over_tcx! { rustc_hir::def_id::DefIndex, rustc_hir::definitions::DefKey, rustc_hir::OpaqueTyOrigin, + rustc_hir::PreciseCapturingArgKind, rustc_index::bit_set::DenseBitSet, rustc_index::bit_set::FiniteBitSet, rustc_session::cstore::ForeignModule, diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index e604aedd05e32..4cad1ab209916 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -26,18 +26,30 @@ impl<'tcx> fmt::Debug for Pattern<'tcx> { impl<'tcx> fmt::Debug for PatternKind<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - PatternKind::Range { start, end, include_end } => { - if let Some(start) = start { - write!(f, "{start}")?; + PatternKind::Range { start, end } => { + write!(f, "{start}")?; + + if let Some(c) = end.try_to_value() { + let end = c.valtree.unwrap_leaf(); + let size = end.size(); + let max = match c.ty.kind() { + ty::Int(_) => { + Some(ty::ScalarInt::truncate_from_int(size.signed_int_max(), size)) + } + ty::Uint(_) => { + Some(ty::ScalarInt::truncate_from_uint(size.unsigned_int_max(), size)) + } + ty::Char => Some(ty::ScalarInt::truncate_from_uint(char::MAX, size)), + _ => None, + }; + if let Some((max, _)) = max + && end == max + { + return write!(f, ".."); + } } - write!(f, "..")?; - if include_end { - write!(f, "=")?; - } - if let Some(end) = end { - write!(f, "{end}")?; - } - Ok(()) + + write!(f, "..={end}") } } } @@ -46,5 +58,5 @@ impl<'tcx> fmt::Debug for PatternKind<'tcx> { #[derive(Clone, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] pub enum PatternKind<'tcx> { - Range { start: Option>, end: Option>, include_end: bool }, + Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> }, } diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 584cac22ae8dd..02e316dfc3db7 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -1,11 +1,9 @@ use std::cmp::Ordering; -use rustc_data_structures::captures::Captures; use rustc_data_structures::intern::Interned; use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, extension}; use rustc_type_ir as ir; -use tracing::instrument; use crate::ty::{ self, DebruijnIndex, EarlyBinder, PredicatePolarity, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom, @@ -52,10 +50,6 @@ impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> self.as_clause() } - fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool { - self.is_coinductive(interner) - } - fn allow_normalization(self) -> bool { self.allow_normalization() } @@ -69,7 +63,7 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> { } } -impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> { +impl<'tcx> rustc_type_ir::Flags for Predicate<'tcx> { fn flags(&self) -> TypeFlags { self.0.flags } @@ -120,17 +114,6 @@ impl<'tcx> Predicate<'tcx> { Some(tcx.mk_predicate(kind)) } - #[instrument(level = "debug", skip(tcx), ret)] - pub fn is_coinductive(self, tcx: TyCtxt<'tcx>) -> bool { - match self.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { - tcx.trait_is_coinductive(data.def_id()) - } - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true, - _ => false, - } - } - /// Whether this projection can be soundly normalized. /// /// Wf predicates must not be normalized, as normalization @@ -159,15 +142,21 @@ impl<'tcx> Predicate<'tcx> { } } -impl rustc_errors::IntoDiagArg for Predicate<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(self.to_string())) +impl<'tcx> rustc_errors::IntoDiagArg for Predicate<'tcx> { + fn into_diag_arg(self, path: &mut Option) -> rustc_errors::DiagArgValue { + ty::tls::with(|tcx| { + let pred = tcx.short_string(self, path); + rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(pred)) + }) } } -impl rustc_errors::IntoDiagArg for Clause<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(self.to_string())) +impl<'tcx> rustc_errors::IntoDiagArg for Clause<'tcx> { + fn into_diag_arg(self, path: &mut Option) -> rustc_errors::DiagArgValue { + ty::tls::with(|tcx| { + let clause = tcx.short_string(self, path); + rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(clause)) + }) } } @@ -336,9 +325,9 @@ impl<'tcx> ty::List> { } #[inline] - pub fn projection_bounds<'a>( - &'a self, - ) -> impl Iterator>> + 'a { + pub fn projection_bounds( + &self, + ) -> impl Iterator>> { self.iter().filter_map(|predicate| { predicate .map_bound(|pred| match pred { @@ -350,16 +339,14 @@ impl<'tcx> ty::List> { } #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator + Captures<'tcx> + 'a { + pub fn auto_traits(&self) -> impl Iterator { self.iter().filter_map(|predicate| match predicate.skip_binder() { ExistentialPredicate::AutoTrait(did) => Some(did), _ => None, }) } - pub fn without_auto_traits( - &self, - ) -> impl Iterator> + '_ { + pub fn without_auto_traits(&self) -> impl Iterator> { self.iter().filter(|predicate| { !matches!(predicate.as_ref().skip_binder(), ExistentialPredicate::AutoTrait(_)) }) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 11b430dd358dd..d200b1437c567 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -63,6 +63,18 @@ thread_local! { static FORCE_TRIMMED_PATH: Cell = const { Cell::new(false) }; static REDUCED_QUERIES: Cell = const { Cell::new(false) }; static NO_VISIBLE_PATH: Cell = const { Cell::new(false) }; + static RTN_MODE: Cell = const { Cell::new(RtnMode::ForDiagnostic) }; +} + +/// Rendering style for RTN types. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum RtnMode { + /// Print the RTN type as an impl trait with its path, i.e.e `impl Sized { T::method(..) }`. + ForDiagnostic, + /// Print the RTN type as an impl trait, i.e. `impl Sized`. + ForSignature, + /// Print the RTN type as a value path, i.e. `T::method(..): ...`. + ForSuggestion, } macro_rules! define_helper { @@ -124,6 +136,38 @@ define_helper!( fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH); ); +#[must_use] +pub struct RtnModeHelper(RtnMode); + +impl RtnModeHelper { + pub fn with(mode: RtnMode) -> RtnModeHelper { + RtnModeHelper(RTN_MODE.with(|c| c.replace(mode))) + } +} + +impl Drop for RtnModeHelper { + fn drop(&mut self) { + RTN_MODE.with(|c| c.set(self.0)) + } +} + +/// Print types for the purposes of a suggestion. +/// +/// Specifically, this will render RPITITs as `T::method(..)` which is suitable for +/// things like where-clauses. +pub macro with_types_for_suggestion($e:expr) {{ + let _guard = $crate::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSuggestion); + $e +}} + +/// Print types for the purposes of a signature suggestion. +/// +/// Specifically, this will render RPITITs as `impl Trait` rather than `T::method(..)`. +pub macro with_types_for_signature($e:expr) {{ + let _guard = $crate::ty::print::pretty::RtnModeHelper::with(RtnMode::ForSignature); + $e +}} + /// Avoids running any queries during prints. pub macro with_no_queries($e:expr) {{ $crate::ty::print::with_reduced_queries!($crate::ty::print::with_forced_impl_filename_line!( @@ -133,6 +177,20 @@ pub macro with_no_queries($e:expr) {{ )) }} +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum WrapBinderMode { + ForAll, + Unsafe, +} +impl WrapBinderMode { + pub fn start_str(self) -> &'static str { + match self { + WrapBinderMode::ForAll => "for<", + WrapBinderMode::Unsafe => "unsafe<", + } + } +} + /// The "region highlights" are used to control region printing during /// specific error messages. When a "region highlight" is enabled, it /// gives an alternate way to print specific regions. For now, we @@ -219,7 +277,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.print_def_path(def_id, args) } - fn in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> + fn print_in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> where T: Print<'tcx, Self> + TypeFoldable>, { @@ -229,10 +287,11 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { fn wrap_binder Result<(), fmt::Error>>( &mut self, value: &ty::Binder<'tcx, T>, + _mode: WrapBinderMode, f: F, ) -> Result<(), PrintError> where - T: Print<'tcx, Self> + TypeFoldable>, + T: TypeFoldable>, { f(value.as_ref().skip_binder(), self) } @@ -554,7 +613,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // the children of the visible parent (as was done when computing // `visible_parent_map`), looking for the specific child we currently have and then // have access to the re-exported name. - DefPathData::TypeNs(ref mut name) if Some(visible_parent) != actual_parent => { + DefPathData::TypeNs(Some(ref mut name)) if Some(visible_parent) != actual_parent => { // Item might be re-exported several times, but filter for the one // that's public and whose identifier isn't `_`. let reexport = self @@ -575,7 +634,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Re-exported `extern crate` (#43189). DefPathData::CrateRoot => { - data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate)); + data = DefPathData::TypeNs(Some(self.tcx().crate_name(def_id.krate))); } _ => {} } @@ -703,8 +762,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } ty::FnPtr(ref sig_tys, hdr) => p!(print(sig_tys.with(hdr))), ty::UnsafeBinder(ref bound_ty) => { - // FIXME(unsafe_binders): Make this print `unsafe<>` rather than `for<>`. - self.wrap_binder(bound_ty, |ty, cx| cx.pretty_print_type(*ty))?; + self.wrap_binder(bound_ty, WrapBinderMode::Unsafe, |ty, cx| { + cx.pretty_print_type(*ty) + })?; } ty::Infer(infer_ty) => { if self.should_print_verbose() { @@ -1056,7 +1116,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { // Insert parenthesis around (Fn(A, B) -> C) if the opaque ty has more than one other trait let paren_needed = fn_traits.len() > 1 || traits.len() > 0 || !has_sized_bound; - for ((bound_args, is_async), entry) in fn_traits { + for ((bound_args_and_self_ty, is_async), entry) in fn_traits { write!(self, "{}", if first { "" } else { " + " })?; write!(self, "{}", if paren_needed { "(" } else { "" })?; @@ -1067,35 +1127,43 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }; if let Some(return_ty) = entry.return_ty { - self.wrap_binder(&bound_args, |args, cx| { - define_scoped_cx!(cx); - p!(write("{}", tcx.item_name(trait_def_id))); - p!("("); - - for (idx, ty) in args.iter().enumerate() { - if idx > 0 { - p!(", "); + self.wrap_binder( + &bound_args_and_self_ty, + WrapBinderMode::ForAll, + |(args, _), cx| { + define_scoped_cx!(cx); + p!(write("{}", tcx.item_name(trait_def_id))); + p!("("); + + for (idx, ty) in args.iter().enumerate() { + if idx > 0 { + p!(", "); + } + p!(print(ty)); } - p!(print(ty)); - } - p!(")"); - if let Some(ty) = return_ty.skip_binder().as_type() { - if !ty.is_unit() { - p!(" -> ", print(return_ty)); + p!(")"); + if let Some(ty) = return_ty.skip_binder().as_type() { + if !ty.is_unit() { + p!(" -> ", print(return_ty)); + } } - } - p!(write("{}", if paren_needed { ")" } else { "" })); + p!(write("{}", if paren_needed { ")" } else { "" })); - first = false; - Ok(()) - })?; + first = false; + Ok(()) + }, + )?; } else { // Otherwise, render this like a regular trait. traits.insert( - bound_args.map_bound(|args| ty::TraitPredicate { + bound_args_and_self_ty.map_bound(|(args, self_ty)| ty::TraitPredicate { polarity: ty::PredicatePolarity::Positive, - trait_ref: ty::TraitRef::new(tcx, trait_def_id, [Ty::new_tup(tcx, args)]), + trait_ref: ty::TraitRef::new( + tcx, + trait_def_id, + [self_ty, Ty::new_tup(tcx, args)], + ), }), FxIndexMap::default(), ); @@ -1106,7 +1174,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { for (trait_pred, assoc_items) in traits { write!(self, "{}", if first { "" } else { " + " })?; - self.wrap_binder(&trait_pred, |trait_pred, cx| { + self.wrap_binder(&trait_pred, WrapBinderMode::ForAll, |trait_pred, cx| { define_scoped_cx!(cx); if trait_pred.polarity == ty::PredicatePolarity::Negative { @@ -1199,22 +1267,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } } - if self.tcx().features().return_type_notation() - && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = - self.tcx().opt_rpitit_info(def_id) - && let ty::Alias(_, alias_ty) = - self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() - && alias_ty.def_id == def_id - && let generics = self.tcx().generics_of(fn_def_id) - // FIXME(return_type_notation): We only support lifetime params for now. - && generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime)) - { - let num_args = generics.count(); - write!(self, " {{ ")?; - self.print_def_path(fn_def_id, &args[..num_args])?; - write!(self, "(..) }}")?; - } - Ok(()) } @@ -1229,7 +1281,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { FxIndexMap>>, >, fn_traits: &mut FxIndexMap< - (ty::Binder<'tcx, &'tcx ty::List>>, bool), + (ty::Binder<'tcx, (&'tcx ty::List>, Ty<'tcx>)>, bool), OpaqueFnEntry<'tcx>, >, ) { @@ -1249,7 +1301,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { && let ty::Tuple(types) = *trait_pred.skip_binder().trait_ref.args.type_at(1).kind() { let entry = fn_traits - .entry((trait_pred.rebind(types), is_async)) + .entry((trait_pred.rebind((types, trait_pred.skip_binder().self_ty())), is_async)) .or_insert_with(|| OpaqueFnEntry { kind, return_ty: None }); if kind.extends(entry.kind) { entry.kind = kind; @@ -1282,6 +1334,46 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ) } + fn pretty_print_rpitit( + &mut self, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + ) -> Result<(), PrintError> { + let fn_args = if self.tcx().features().return_type_notation() + && let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, .. }) = + self.tcx().opt_rpitit_info(def_id) + && let ty::Alias(_, alias_ty) = + self.tcx().fn_sig(fn_def_id).skip_binder().output().skip_binder().kind() + && alias_ty.def_id == def_id + && let generics = self.tcx().generics_of(fn_def_id) + // FIXME(return_type_notation): We only support lifetime params for now. + && generics.own_params.iter().all(|param| matches!(param.kind, ty::GenericParamDefKind::Lifetime)) + { + let num_args = generics.count(); + Some((fn_def_id, &args[..num_args])) + } else { + None + }; + + match (fn_args, RTN_MODE.with(|c| c.get())) { + (Some((fn_def_id, fn_args)), RtnMode::ForDiagnostic) => { + self.pretty_print_opaque_impl_type(def_id, args)?; + write!(self, " {{ ")?; + self.print_def_path(fn_def_id, fn_args)?; + write!(self, "(..) }}")?; + } + (Some((fn_def_id, fn_args)), RtnMode::ForSuggestion) => { + self.print_def_path(fn_def_id, fn_args)?; + write!(self, "(..)")?; + } + _ => { + self.pretty_print_opaque_impl_type(def_id, args)?; + } + } + + Ok(()) + } + fn ty_infer_name(&self, _: ty::TyVid) -> Option { None } @@ -1298,7 +1390,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let mut first = true; if let Some(bound_principal) = predicates.principal() { - self.wrap_binder(&bound_principal, |principal, cx| { + self.wrap_binder(&bound_principal, WrapBinderMode::ForAll, |principal, cx| { define_scoped_cx!(cx); p!(print_def_path(principal.def_id, &[])); @@ -1512,10 +1604,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::ExprKind::Binop(op) => { let (_, _, c1, c2) = expr.binop_args(); - let precedence = |binop: crate::mir::BinOp| { - use rustc_ast::util::parser::AssocOp; - AssocOp::from_ast_binop(binop.to_hir_binop()).precedence() - }; + let precedence = |binop: crate::mir::BinOp| binop.to_hir_binop().precedence(); let op_precedence = precedence(op); let formatted_op = op.to_hir_binop().as_str(); let (lhs_parenthesized, rhs_parenthesized) = match (c1.kind(), c2.kind()) { @@ -1926,7 +2015,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let kind = closure.kind_ty().to_opt_closure_kind().unwrap_or(ty::ClosureKind::Fn); write!(self, "impl ")?; - self.wrap_binder(&sig, |sig, cx| { + self.wrap_binder(&sig, WrapBinderMode::ForAll, |sig, cx| { define_scoped_cx!(cx); p!(write("{kind}(")); @@ -2366,22 +2455,23 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> { Ok(()) } - fn in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> + fn print_in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError> where T: Print<'tcx, Self> + TypeFoldable>, { - self.pretty_in_binder(value) + self.pretty_print_in_binder(value) } fn wrap_binder Result<(), PrintError>>( &mut self, value: &ty::Binder<'tcx, T>, + mode: WrapBinderMode, f: C, ) -> Result<(), PrintError> where - T: Print<'tcx, Self> + TypeFoldable>, + T: TypeFoldable>, { - self.pretty_wrap_binder(value, f) + self.pretty_wrap_binder(value, mode, f) } fn typed_value( @@ -2631,9 +2721,10 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { pub fn name_all_regions( &mut self, value: &ty::Binder<'tcx, T>, + mode: WrapBinderMode, ) -> Result<(T, UnordMap>), fmt::Error> where - T: Print<'tcx, Self> + TypeFoldable>, + T: TypeFoldable>, { fn name_by_region_index( index: usize, @@ -2704,9 +2795,13 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { // anyways. let (new_value, map) = if self.should_print_verbose() { for var in value.bound_vars().iter() { - start_or_continue(self, "for<", ", "); + start_or_continue(self, mode.start_str(), ", "); write!(self, "{var:?}")?; } + // Unconditionally render `unsafe<>`. + if value.bound_vars().is_empty() && mode == WrapBinderMode::Unsafe { + start_or_continue(self, mode.start_str(), ""); + } start_or_continue(self, "", "> "); (value.clone().skip_binder(), UnordMap::default()) } else { @@ -2771,8 +2866,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { } }; - if !trim_path { - start_or_continue(self, "for<", ", "); + // Unconditionally render `unsafe<>`. + if !trim_path || mode == WrapBinderMode::Unsafe { + start_or_continue(self, mode.start_str(), ", "); do_continue(self, name); } ty::Region::new_bound(tcx, ty::INNERMOST, ty::BoundRegion { var: br.var, kind }) @@ -2785,9 +2881,12 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { }; let new_value = value.clone().skip_binder().fold_with(&mut folder); let region_map = folder.region_map; - if !trim_path { - start_or_continue(self, "", "> "); + + if mode == WrapBinderMode::Unsafe && region_map.is_empty() { + start_or_continue(self, mode.start_str(), ""); } + start_or_continue(self, "", "> "); + (new_value, region_map) }; @@ -2796,12 +2895,15 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { Ok((new_value, map)) } - pub fn pretty_in_binder(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), fmt::Error> + pub fn pretty_print_in_binder( + &mut self, + value: &ty::Binder<'tcx, T>, + ) -> Result<(), fmt::Error> where T: Print<'tcx, Self> + TypeFoldable>, { let old_region_index = self.region_index; - let (new_value, _) = self.name_all_regions(value)?; + let (new_value, _) = self.name_all_regions(value, WrapBinderMode::ForAll)?; new_value.print(self)?; self.region_index = old_region_index; self.binder_depth -= 1; @@ -2811,13 +2913,14 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { pub fn pretty_wrap_binder Result<(), fmt::Error>>( &mut self, value: &ty::Binder<'tcx, T>, + mode: WrapBinderMode, f: C, ) -> Result<(), fmt::Error> where - T: Print<'tcx, Self> + TypeFoldable>, + T: TypeFoldable>, { let old_region_index = self.region_index; - let (new_value, _) = self.name_all_regions(value)?; + let (new_value, _) = self.name_all_regions(value, mode)?; f(&new_value, self)?; self.region_index = old_region_index; self.binder_depth -= 1; @@ -2842,7 +2945,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> { } } - impl<'tcx> ty::visit::TypeVisitor> for RegionNameCollector<'tcx> { + impl<'tcx> ty::TypeVisitor> for RegionNameCollector<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) { trace!("address: {:p}", r.0.0); @@ -2876,7 +2979,7 @@ where T: Print<'tcx, P> + TypeFoldable>, { fn print(&self, cx: &mut P) -> Result<(), PrintError> { - cx.in_binder(self) + cx.print_in_binder(self) } } @@ -2894,12 +2997,15 @@ where /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait path. That is, it will print `Trait` instead of /// `>`. -#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)] pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>); impl<'tcx> rustc_errors::IntoDiagArg for TraitRefPrintOnlyTraitPath<'tcx> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> rustc_errors::DiagArgValue { + ty::tls::with(|tcx| { + let trait_ref = tcx.short_string(self, path); + rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(trait_ref)) + }) } } @@ -2911,12 +3017,15 @@ impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> { /// Wrapper type for `ty::TraitRef` which opts-in to pretty printing only /// the trait path, and additionally tries to "sugar" `Fn(...)` trait bounds. -#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)] pub struct TraitRefPrintSugared<'tcx>(ty::TraitRef<'tcx>); impl<'tcx> rustc_errors::IntoDiagArg for TraitRefPrintSugared<'tcx> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, path: &mut Option) -> rustc_errors::DiagArgValue { + ty::tls::with(|tcx| { + let trait_ref = tcx.short_string(self, path); + rustc_errors::DiagArgValue::Str(std::borrow::Cow::Owned(trait_ref)) + }) } } @@ -3082,22 +3191,21 @@ define_print! { ty::AliasTerm<'tcx> { match self.kind(cx.tcx()) { ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), - ty::AliasTermKind::ProjectionTy - | ty::AliasTermKind::WeakTy - | ty::AliasTermKind::OpaqueTy - | ty::AliasTermKind::UnevaluatedConst - | ty::AliasTermKind::ProjectionConst => { - // If we're printing verbosely, or don't want to invoke queries - // (`is_impl_trait_in_trait`), then fall back to printing the def path. - // This is likely what you want if you're debugging the compiler anyways. + ty::AliasTermKind::ProjectionTy => { if !(cx.should_print_verbose() || with_reduced_queries()) && cx.tcx().is_impl_trait_in_trait(self.def_id) { - return cx.pretty_print_opaque_impl_type(self.def_id, self.args); + p!(pretty_print_rpitit(self.def_id, self.args)) } else { p!(print_def_path(self.def_id, self.args)); } } + | ty::AliasTermKind::WeakTy + | ty::AliasTermKind::OpaqueTy + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => { + p!(print_def_path(self.def_id, self.args)); + } } } diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs index 14a2e5befe696..fb52cf96b0297 100644 --- a/compiler/rustc_middle/src/ty/region.rs +++ b/compiler/rustc_middle/src/ty/region.rs @@ -26,7 +26,7 @@ impl<'tcx> rustc_type_ir::inherent::IntoKind for Region<'tcx> { } } -impl<'tcx> rustc_type_ir::visit::Flags for Region<'tcx> { +impl<'tcx> rustc_type_ir::Flags for Region<'tcx> { fn flags(&self) -> TypeFlags { self.type_flags() } diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 839c1c346a47b..b1dfcb80bde57 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -51,22 +51,12 @@ impl<'tcx> Relate> for ty::Pattern<'tcx> { ) -> RelateResult<'tcx, Self> { match (&*a, &*b) { ( - &ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a }, - &ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b }, + &ty::PatternKind::Range { start: start_a, end: end_a }, + &ty::PatternKind::Range { start: start_b, end: end_b }, ) => { - // FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`). - let mut relate_opt_const = |a, b| match (a, b) { - (None, None) => Ok(None), - (Some(a), Some(b)) => relation.relate(a, b).map(Some), - // FIXME(pattern_types): report a better error - _ => Err(TypeError::Mismatch), - }; - let start = relate_opt_const(start_a, start_b)?; - let end = relate_opt_const(end_a, end_b)?; - if inc_a != inc_b { - todo!() - } - Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a })) + let start = relation.relate(start_a, start_b)?; + let end = relation.relate(end_a, end_b)?; + Ok(relation.cx().mk_pat(ty::PatternKind::Range { start, end })) } } } diff --git a/compiler/rustc_middle/src/ty/significant_drop_order.rs b/compiler/rustc_middle/src/ty/significant_drop_order.rs new file mode 100644 index 0000000000000..2d9e0331451fd --- /dev/null +++ b/compiler/rustc_middle/src/ty/significant_drop_order.rs @@ -0,0 +1,174 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::unord::UnordSet; +use rustc_hir::def_id::DefId; +use rustc_span::Span; +use smallvec::{SmallVec, smallvec}; +use tracing::{debug, instrument}; + +use crate::ty::{self, Ty, TyCtxt}; + +/// An additional filter to exclude well-known types from the ecosystem +/// because their drops are trivial. +/// This returns additional types to check if the drops are delegated to those. +/// A typical example is `hashbrown::HashMap`, whose drop is delegated to `K` and `V`. +fn true_significant_drop_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, +) -> Option; 2]>> { + if let ty::Adt(def, args) = ty.kind() { + let mut did = def.did(); + let mut name_rev = vec![]; + loop { + let key = tcx.def_key(did); + + match key.disambiguated_data.data { + rustc_hir::definitions::DefPathData::CrateRoot => { + name_rev.push(tcx.crate_name(did.krate)); + } + rustc_hir::definitions::DefPathData::TypeNs(symbol) => { + name_rev.push(symbol.unwrap()); + } + _ => return None, + } + if let Some(parent) = key.parent { + did = DefId { krate: did.krate, index: parent }; + } else { + break; + } + } + let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect(); + debug!(?name_str); + match name_str[..] { + // These are the types from Rust core ecosystem + ["syn" | "proc_macro2", ..] + | ["core" | "std", "task", "LocalWaker" | "Waker"] + | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]), + // These are important types from Rust ecosystem + ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]), + ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => { + if let [ty, ..] = &***args + && let Some(ty) = ty.as_type() + { + Some(smallvec![ty]) + } else { + None + } + } + ["hashbrown", "raw", "RawDrain"] => { + if let [_, ty, ..] = &***args + && let Some(ty) = ty.as_type() + { + Some(smallvec![ty]) + } else { + None + } + } + _ => None, + } + } else { + None + } +} + +/// Returns the list of types with a "potentially sigificant" that may be dropped +/// by dropping a value of type `ty`. +#[instrument(level = "trace", skip(tcx, typing_env))] +pub fn extract_component_raw<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, + ty_seen: &mut UnordSet>, +) -> SmallVec<[Ty<'tcx>; 4]> { + // Droppiness does not depend on regions, so let us erase them. + let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); + + let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty)); + debug!(?ty, "components"); + let mut out_tys = smallvec![]; + for ty in tys { + if let Some(tys) = true_significant_drop_ty(tcx, ty) { + // Some types can be further opened up because the drop is simply delegated + for ty in tys { + if ty_seen.insert(ty) { + out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen)); + } + } + } else { + if ty_seen.insert(ty) { + out_tys.push(ty); + } + } + } + out_tys +} + +#[instrument(level = "trace", skip(tcx, typing_env))] +pub fn extract_component_with_significant_dtor<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, +) -> SmallVec<[Ty<'tcx>; 4]> { + let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default()); + let mut deduplicate = FxHashSet::default(); + tys.retain(|oty| deduplicate.insert(*oty)); + tys.into_iter().collect() +} + +/// Extract the span of the custom destructor of a type +/// especially the span of the `impl Drop` header or its entire block +/// when we are working with current local crate. +#[instrument(level = "trace", skip(tcx))] +pub fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { + match ty.kind() { + ty::Bool + | ty::Char + | ty::Int(_) + | ty::Uint(_) + | ty::Float(_) + | ty::Error(_) + | ty::Str + | ty::Never + | ty::RawPtr(_, _) + | ty::Ref(_, _, _) + | ty::FnPtr(_, _) + | ty::Tuple(_) + | ty::Dynamic(_, _, _) + | ty::Alias(_, _) + | ty::Bound(_, _) + | ty::Pat(_, _) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::Slice(_) + | ty::Array(_, _) + | ty::UnsafeBinder(_) => None, + + ty::Adt(adt_def, _) => { + let did = adt_def.did(); + let try_local_did_span = |did: DefId| { + if let Some(local) = did.as_local() { + tcx.source_span(local) + } else { + tcx.def_span(did) + } + }; + let dtor = if let Some(dtor) = tcx.adt_destructor(did) { + dtor.did + } else if let Some(dtor) = tcx.adt_async_destructor(did) { + dtor.future + } else { + return Some(try_local_did_span(did)); + }; + let def_key = tcx.def_key(dtor); + let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) }; + let parent_did = DefId { index: parent_index, krate: dtor.krate }; + Some(try_local_did_span(parent_did)) + } + ty::Coroutine(did, _) + | ty::CoroutineWitness(did, _) + | ty::CoroutineClosure(did, _) + | ty::Closure(did, _) + | ty::FnDef(did, _) + | ty::Foreign(did) => Some(tcx.def_span(did)), + ty::Param(_) => None, + } +} diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index b2286c744020f..60fd531b4d0ee 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -11,16 +11,16 @@ use rustc_hir::def::Namespace; use rustc_hir::def_id::LocalDefId; use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_type_ir::ConstKind; -use rustc_type_ir::visit::{VisitorResult, try_visit}; +use rustc_type_ir::{ConstKind, VisitorResult, try_visit}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Pattern, Region}; use crate::mir::PlaceElem; -use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; -use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt}; +use crate::ty::{ + self, FallibleTypeFolder, InferConst, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, + TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, +}; impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -50,7 +50,7 @@ impl<'tcx> fmt::Debug for ty::AdtDef<'tcx> { impl fmt::Debug for ty::UpvarId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let name = ty::tls::with(|tcx| tcx.hir().name(self.var_path.hir_id)); + let name = ty::tls::with(|tcx| tcx.hir_name(self.var_path.hir_id)); write!(f, "UpvarId({:?};`{}`;{:?})", self.var_path.hir_id, name, self.closure_expr_id) } } @@ -284,6 +284,7 @@ TrivialTypeTraversalImpls! { rustc_hir::def_id::LocalDefId, rustc_hir::HirId, rustc_hir::MatchSource, + rustc_hir::RangeEnd, rustc_span::Ident, rustc_span::Span, rustc_span::Symbol, @@ -447,23 +448,23 @@ impl<'tcx> TypeSuperVisitable> for Ty<'tcx> { } ty::Slice(typ) => typ.visit_with(visitor), ty::Adt(_, args) => args.visit_with(visitor), - ty::Dynamic(ref trait_ty, ref reg, _) => { + ty::Dynamic(trait_ty, reg, _) => { try_visit!(trait_ty.visit_with(visitor)); reg.visit_with(visitor) } ty::Tuple(ts) => ts.visit_with(visitor), ty::FnDef(_, args) => args.visit_with(visitor), - ty::FnPtr(ref sig_tys, _) => sig_tys.visit_with(visitor), - ty::UnsafeBinder(ref f) => f.visit_with(visitor), + ty::FnPtr(sig_tys, _) => sig_tys.visit_with(visitor), + ty::UnsafeBinder(f) => f.visit_with(visitor), ty::Ref(r, ty, _) => { try_visit!(r.visit_with(visitor)); ty.visit_with(visitor) } - ty::Coroutine(_did, ref args) => args.visit_with(visitor), - ty::CoroutineWitness(_did, ref args) => args.visit_with(visitor), - ty::Closure(_did, ref args) => args.visit_with(visitor), - ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor), - ty::Alias(_, ref data) => data.visit_with(visitor), + ty::Coroutine(_did, args) => args.visit_with(visitor), + ty::CoroutineWitness(_did, args) => args.visit_with(visitor), + ty::Closure(_did, args) => args.visit_with(visitor), + ty::CoroutineClosure(_did, args) => args.visit_with(visitor), + ty::Alias(_, data) => data.visit_with(visitor), ty::Pat(ty, pat) => { try_visit!(ty.visit_with(visitor)); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 9eda760870716..74a94d8278453 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -9,7 +9,6 @@ use std::ops::{ControlFlow, Range}; use hir::def::{CtorKind, DefKind}; use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx}; -use rustc_data_structures::captures::Captures; use rustc_errors::{ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::LangItem; @@ -17,8 +16,7 @@ use rustc_hir::def_id::DefId; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use rustc_type_ir::TyKind::*; -use rustc_type_ir::visit::TypeVisitableExt; -use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, elaborate}; +use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate}; use tracing::instrument; use ty::util::{AsyncDropGlueMorphology, IntTypeExt}; @@ -105,7 +103,7 @@ impl<'tcx> ty::CoroutineArgs> { self, def_id: DefId, tcx: TyCtxt<'tcx>, - ) -> impl Iterator)> + Captures<'tcx> { + ) -> impl Iterator)> { self.variant_range(def_id, tcx).map(move |index| { (index, Discr { val: index.as_usize() as u128, ty: self.discr_ty(tcx) }) }) @@ -139,7 +137,7 @@ impl<'tcx> ty::CoroutineArgs> { self, def_id: DefId, tcx: TyCtxt<'tcx>, - ) -> impl Iterator> + Captures<'tcx>> { + ) -> impl Iterator>> { let layout = tcx.coroutine_layout(def_id, self.kind_ty()).unwrap(); layout.variant_fields.iter().map(move |variant| { variant.iter().map(move |field| { @@ -343,6 +341,7 @@ impl ParamConst { ParamConst::new(def.index, def.name) } + #[instrument(level = "debug")] pub fn find_ty_from_env<'tcx>(self, env: ParamEnv<'tcx>) -> Ty<'tcx> { let mut candidates = env.caller_bounds().iter().filter_map(|clause| { // `ConstArgHasType` are never desugared to be higher ranked. @@ -462,7 +461,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn new_param(tcx: TyCtxt<'tcx>, index: u32, name: Symbol) -> Ty<'tcx> { - tcx.mk_ty_from_kind(Param(ParamTy { index, name })) + Ty::new(tcx, Param(ParamTy { index, name })) } #[inline] @@ -1149,7 +1148,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_param(self, index: u32) -> bool { match self.kind() { - ty::Param(ref data) => data.index == index, + ty::Param(data) => data.index == index, _ => false, } } diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 17e90c15d4136..8fa1c569737a0 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -188,7 +188,7 @@ impl<'tcx> TyCtxt<'tcx> { self, trait_def_id: DefId, self_ty: Ty<'tcx>, - ) -> impl Iterator + 'tcx { + ) -> impl Iterator { let impls = self.trait_impls_of(trait_def_id); if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::InstantiateWithInfer) @@ -204,7 +204,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns an iterator containing all impls for `trait_def_id`. /// /// `trait_def_id` MUST BE the `DefId` of a trait. - pub fn all_impls(self, trait_def_id: DefId) -> impl Iterator + 'tcx { + pub fn all_impls(self, trait_def_id: DefId) -> impl Iterator { let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(trait_def_id); blanket_impls.iter().chain(non_blanket_impls.iter().flat_map(|(_, v)| v)).cloned() diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index b8c73d2584379..06054e22e7601 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -310,7 +310,7 @@ impl<'tcx> TypeckResults<'tcx> { pub fn node_type(&self, id: HirId) -> Ty<'tcx> { self.node_type_opt(id).unwrap_or_else(|| { - bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir().node_to_string(id))) + bug!("node_type: no type for node {}", tls::with(|tcx| tcx.hir_id_to_string(id))) }) } @@ -394,8 +394,10 @@ impl<'tcx> TypeckResults<'tcx> { matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _)))) } - pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option { - self.pat_binding_modes().get(id).copied().or_else(|| { + /// Returns the computed binding mode for a `PatKind::Binding` pattern + /// (after match ergonomics adjustments). + pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> BindingMode { + self.pat_binding_modes().get(id).copied().unwrap_or_else(|| { s.dcx().span_bug(sp, "missing binding mode"); }) } @@ -552,7 +554,7 @@ fn invalid_hir_id_for_typeck_results(hir_owner: OwnerId, hir_id: HirId) { ty::tls::with(|tcx| { bug!( "node {} cannot be placed in TypeckResults with hir_owner {:?}", - tcx.hir().node_to_string(hir_id), + tcx.hir_id_to_string(hir_id), hir_owner ) }); @@ -575,7 +577,7 @@ impl<'a, V> LocalTableInContext<'a, V> { } pub fn items( - &'a self, + &self, ) -> UnordItems<(hir::ItemLocalId, &'a V), impl Iterator> { self.data.items().map(|(id, value)| (*id, value)) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 88d5749854231..c0d4130336e52 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -23,11 +23,10 @@ use super::TypingEnv; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir; use crate::query::Providers; -use crate::ty::fold::fold_regions; use crate::ty::layout::{FloatExt, IntegerExt}; use crate::ty::{ self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable, - TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, fold_regions, }; #[derive(Copy, Clone, Debug)] @@ -192,6 +191,18 @@ impl<'tcx> TyCtxt<'tcx> { ty.is_trivially_pure_clone_copy() || self.is_copy_raw(typing_env.as_query_input(ty)) } + /// Checks whether `ty: UseCloned` holds while ignoring region constraints. + /// + /// This function should not be used if there is an `InferCtxt` available. + /// Use `InferCtxt::type_is_copy_modulo_regions` instead. + pub fn type_is_use_cloned_modulo_regions( + self, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + ty.is_trivially_pure_clone_copy() || self.is_use_cloned_raw(typing_env.as_query_input(ty)) + } + /// Returns the deeply last field of nested structures, or the same type if /// not a structure at all. Corresponds to the only possible unsized field, /// and its type can be used to determine unsizing strategy. @@ -208,6 +219,20 @@ impl<'tcx> TyCtxt<'tcx> { tcx.struct_tail_raw(ty, |ty| tcx.normalize_erasing_regions(typing_env, ty), || {}) } + /// Returns true if a type has metadata. + pub fn type_has_metadata(self, ty: Ty<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + if ty.is_sized(self, typing_env) { + return false; + } + + let tail = self.struct_tail_for_codegen(ty, typing_env); + match tail.kind() { + ty::Foreign(..) => false, + ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail), + } + } + /// Returns the deeply last field of nested structures, or the same type if /// not a structure at all. Corresponds to the only possible unsized field, /// and its type can be used to determine unsizing strategy. @@ -725,52 +750,38 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Return the set of types that should be taken into account when checking - /// trait bounds on a coroutine's internal state. - // FIXME(compiler-errors): We should remove this when the old solver goes away; - // and all other usages of this function should go through `bound_coroutine_hidden_types` - // instead. - pub fn coroutine_hidden_types( - self, - def_id: DefId, - ) -> impl Iterator>> { - let coroutine_layout = self.mir_coroutine_witnesses(def_id); - coroutine_layout - .as_ref() - .map_or_else(|| [].iter(), |l| l.field_tys.iter()) - .filter(|decl| !decl.ignore_for_traits) - .map(|decl| ty::EarlyBinder::bind(decl.ty)) - } - /// Return the set of types that should be taken into account when checking /// trait bounds on a coroutine's internal state. This properly replaces /// `ReErased` with new existential bound lifetimes. - pub fn bound_coroutine_hidden_types( + pub fn coroutine_hidden_types( self, def_id: DefId, - ) -> impl Iterator>>> { + ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, &'tcx ty::List>>> { let coroutine_layout = self.mir_coroutine_witnesses(def_id); - coroutine_layout - .as_ref() - .map_or_else(|| [].iter(), |l| l.field_tys.iter()) - .filter(|decl| !decl.ignore_for_traits) - .map(move |decl| { - let mut vars = vec![]; - let ty = fold_regions(self, decl.ty, |re, debruijn| { - assert_eq!(re, self.lifetimes.re_erased); - let var = ty::BoundVar::from_usize(vars.len()); - vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)); - ty::Region::new_bound( - self, - debruijn, - ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, - ) - }); - ty::EarlyBinder::bind(ty::Binder::bind_with_vars( - ty, - self.mk_bound_variable_kinds(&vars), - )) - }) + let mut vars = vec![]; + let bound_tys = self.mk_type_list_from_iter( + coroutine_layout + .as_ref() + .map_or_else(|| [].iter(), |l| l.field_tys.iter()) + .filter(|decl| !decl.ignore_for_traits) + .map(|decl| { + let ty = fold_regions(self, decl.ty, |re, debruijn| { + assert_eq!(re, self.lifetimes.re_erased); + let var = ty::BoundVar::from_usize(vars.len()); + vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)); + ty::Region::new_bound( + self, + debruijn, + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, + ) + }); + ty + }), + ); + ty::EarlyBinder::bind(ty::Binder::bind_with_vars( + bound_tys, + self.mk_bound_variable_kinds(&vars), + )) } /// Expands the given impl trait type, stopping if the type is recursive. @@ -1755,13 +1766,12 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option { - !has_body - } - _ => true, - }; + let must_be_overridden = match tcx.hir_node_by_def_id(def_id) { + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => { + !has_body + } + _ => true, + }; Some(ty::IntrinsicDef { name: tcx.item_name(def_id.into()), must_be_overridden, diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 95256b55bb4a1..e3b7a258c395c 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,10 +1,11 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxIndexSet; -use rustc_type_ir::fold::TypeFoldable; -pub use rustc_type_ir::visit::*; +use rustc_type_ir::TypeFoldable; -use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags}; +use crate::ty::{ + self, Binder, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor, +}; /////////////////////////////////////////////////////////////////////////// // Region folder diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 3e8a3d1a28923..a23316ae6fc88 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -137,9 +137,9 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) ty::Pat(ty, pat) => { match *pat { - ty::PatternKind::Range { start, end, include_end: _ } => { - stack.extend(end.map(Into::into)); - stack.extend(start.map(Into::into)); + ty::PatternKind::Range { start, end } => { + stack.push(end.into()); + stack.push(start.into()); } } stack.push(ty.into()); diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml index 1f3689926bcf3..d70d70a31a4a7 100644 --- a/compiler/rustc_mir_build/Cargo.toml +++ b/compiler/rustc_mir_build/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_mir_build" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_mir_build/src/builder/block.rs b/compiler/rustc_mir_build/src/builder/block.rs index 93ee90011a581..7c76e02fcef6a 100644 --- a/compiler/rustc_mir_build/src/builder/block.rs +++ b/compiler/rustc_mir_build/src/builder/block.rs @@ -244,7 +244,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { StmtKind::Let { remainder_scope, init_scope, - ref pattern, + pattern, initializer, lint_level, else_block: None, diff --git a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs index 84c9297e65898..f743ea60a456c 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_constant.rs @@ -117,7 +117,12 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx> ConstValue::Scalar(Scalar::from_uint(result, width)) }; - let value = match (lit, ty.kind()) { + let lit_ty = match *ty.kind() { + ty::Pat(base, _) => base, + _ => ty, + }; + + let value = match (lit, lit_ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 308ca442b40cc..50ca924baf9c8 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -216,11 +216,11 @@ fn to_upvars_resolved_place_builder<'tcx>( /// Supports only HIR projection kinds that represent a path that might be /// captured by a closure or a coroutine, i.e., an `Index` or a `Subslice` /// projection kinds are unsupported. -fn strip_prefix<'a, 'tcx>( +fn strip_prefix<'tcx>( mut base_ty: Ty<'tcx>, - projections: &'a [PlaceElem<'tcx>], + projections: &[PlaceElem<'tcx>], prefix_projections: &[HirProjection<'tcx>], -) -> impl Iterator> + 'a { +) -> impl Iterator> { let mut iter = projections .iter() .copied() @@ -582,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | ExprKind::Yield { .. } | ExprKind::ThreadLocalRef(_) | ExprKind::Call { .. } + | ExprKind::ByUse { .. } | ExprKind::WrapUnsafeBinder { .. } => { // these are not places, so we need to make a temporary. debug_assert!(!matches!(Category::of(&expr.kind), Some(Category::Place))); diff --git a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs index 2c9a1de7f9978..97d34b85f50da 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_rvalue.rs @@ -572,6 +572,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); block.and(Rvalue::Use(operand)) } + + ExprKind::ByUse { expr, span: _ } => { + let operand = unpack!( + block = + this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No) + ); + block.and(Rvalue::Use(operand)) + } } } diff --git a/compiler/rustc_mir_build/src/builder/expr/category.rs b/compiler/rustc_mir_build/src/builder/expr/category.rs index ca55d36bfc659..34524aed40678 100644 --- a/compiler/rustc_mir_build/src/builder/expr/category.rs +++ b/compiler/rustc_mir_build/src/builder/expr/category.rs @@ -56,6 +56,7 @@ impl Category { | ExprKind::RawBorrow { .. } | ExprKind::Yield { .. } | ExprKind::Call { .. } + | ExprKind::ByUse { .. } | ExprKind::InlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::Into)), ExprKind::Array { .. } diff --git a/compiler/rustc_mir_build/src/builder/expr/into.rs b/compiler/rustc_mir_build/src/builder/expr/into.rs index 65dd061003d8d..333e69475c508 100644 --- a/compiler/rustc_mir_build/src/builder/expr/into.rs +++ b/compiler/rustc_mir_build/src/builder/expr/into.rs @@ -4,11 +4,14 @@ use rustc_ast::{AsmMacro, InlineAsmOptions}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; +use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::thir::*; -use rustc_middle::ty::CanonicalUserTypeAnnotation; +use rustc_middle::ty::{CanonicalUserTypeAnnotation, Ty}; +use rustc_span::DUMMY_SP; use rustc_span::source_map::Spanned; +use rustc_trait_selection::infer::InferCtxtExt; use tracing::{debug, instrument}; use crate::builder::expr::category::{Category, RvalueFunc}; @@ -289,6 +292,57 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(block); success.unit() } + ExprKind::ByUse { expr, span } => { + let place = unpack!(block = this.as_place(block, expr)); + let ty = place.ty(&this.local_decls, this.tcx).ty; + + if this.tcx.type_is_copy_modulo_regions(this.infcx.typing_env(this.param_env), ty) { + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Use(Operand::Copy(place)), + ); + block.unit() + } else if this.infcx.type_is_use_cloned_modulo_regions(this.param_env, ty) { + // Convert `expr.use` to a call like `Clone::clone(&expr)` + let success = this.cfg.start_new_block(); + let clone_trait = this.tcx.require_lang_item(LangItem::Clone, None); + let clone_fn = this.tcx.associated_item_def_ids(clone_trait)[0]; + let func = Operand::function_handle(this.tcx, clone_fn, [ty.into()], expr_span); + let ref_ty = Ty::new_imm_ref(this.tcx, this.tcx.lifetimes.re_erased, ty); + let ref_place = this.temp(ref_ty, span); + this.cfg.push_assign( + block, + source_info, + ref_place, + Rvalue::Ref(this.tcx.lifetimes.re_erased, BorrowKind::Shared, place), + ); + this.cfg.terminate( + block, + source_info, + TerminatorKind::Call { + func, + args: [Spanned { node: Operand::Move(ref_place), span: DUMMY_SP }] + .into(), + destination, + target: Some(success), + unwind: UnwindAction::Unreachable, + call_source: CallSource::Misc, + fn_span: expr_span, + }, + ); + success.unit() + } else { + this.cfg.push_assign( + block, + source_info, + destination, + Rvalue::Use(Operand::Move(place)), + ); + block.unit() + } + } ExprKind::Use { source } => this.expr_into_dest(destination, block, source), ExprKind::Borrow { arg, borrow_kind } => { // We don't do this in `as_rvalue` because we use `as_place` @@ -482,15 +536,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }), } } - thir::InlineAsmOperand::SymFn { value, span } => { - mir::InlineAsmOperand::SymFn { - value: Box::new(ConstOperand { - span, - user_ty: None, - const_: value, - }), - } - } + thir::InlineAsmOperand::SymFn { value } => mir::InlineAsmOperand::SymFn { + value: Box::new(this.as_constant(&this.thir[value])), + }, thir::InlineAsmOperand::SymStatic { def_id } => { mir::InlineAsmOperand::SymStatic { def_id } } @@ -518,10 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } let asm_macro = match asm_macro { - AsmMacro::Asm => InlineAsmMacro::Asm, - AsmMacro::GlobalAsm => { - span_bug!(expr_span, "unexpected global_asm! in inline asm") - } + AsmMacro::Asm | AsmMacro::GlobalAsm => InlineAsmMacro::Asm, AsmMacro::NakedAsm => InlineAsmMacro::NakedAsm, }; diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index ee331713736e7..c6f3e22e95f6f 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -1,32 +1,30 @@ use std::sync::Arc; use rustc_middle::mir::*; -use rustc_middle::thir::{self, *}; +use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; -use crate::builder::matches::{FlatPat, MatchPairTree, TestCase}; +use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestCase}; impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Builds and returns [`MatchPairTree`] subtrees, one for each pattern in + /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or /// [`PatKind::Leaf`]. /// /// Used internally by [`MatchPairTree::for_pattern`]. fn field_match_pairs( &mut self, + match_pairs: &mut Vec>, + extra_data: &mut PatternExtraData<'tcx>, place: PlaceBuilder<'tcx>, subpatterns: &[FieldPat<'tcx>], - ) -> Vec> { - subpatterns - .iter() - .map(|fieldpat| { - let place = - place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPairTree::for_pattern(place, &fieldpat.pattern, self) - }) - .collect() + ) { + for fieldpat in subpatterns { + let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); + MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data); + } } /// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an @@ -36,6 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn prefix_slice_suffix( &mut self, match_pairs: &mut Vec>, + extra_data: &mut PatternExtraData<'tcx>, place: &PlaceBuilder<'tcx>, prefix: &[Pat<'tcx>], opt_slice: &Option>>, @@ -56,11 +55,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ((prefix.len() + suffix.len()).try_into().unwrap(), false) }; - match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { + for (idx, subpattern) in prefix.iter().enumerate() { let elem = ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; - MatchPairTree::for_pattern(place.clone_project(elem), subpattern, self) - })); + let place = place.clone_project(elem); + MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + } if let Some(subslice_pat) = opt_slice { let suffix_len = suffix.len() as u64; @@ -69,10 +69,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { to: if exact_size { min_length - suffix_len } else { suffix_len }, from_end: !exact_size, }); - match_pairs.push(MatchPairTree::for_pattern(subslice, subslice_pat, self)); + MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); } - match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { + for (idx, subpattern) in suffix.iter().rev().enumerate() { let end_offset = (idx + 1) as u64; let elem = ProjectionElem::ConstantIndex { offset: if exact_size { min_length - end_offset } else { end_offset }, @@ -80,19 +80,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { from_end: !exact_size, }; let place = place.clone_project(elem); - MatchPairTree::for_pattern(place, subpattern, self) - })); + MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) + } } } impl<'tcx> MatchPairTree<'tcx> { /// Recursively builds a match pair tree for the given pattern and its /// subpatterns. - pub(in crate::builder) fn for_pattern( + pub(super) fn for_pattern( mut place_builder: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>, - ) -> MatchPairTree<'tcx> { + match_pairs: &mut Vec, // Newly-created nodes are added to this vector + extra_data: &mut PatternExtraData<'tcx>, // Bindings/ascriptions are added here + ) { // Force the place type to the pattern's type. // FIXME(oli-obk): can we use this to simplify slice/array pattern hacks? if let Some(resolved) = place_builder.resolve_upvar(cx) { @@ -113,64 +115,102 @@ impl<'tcx> MatchPairTree<'tcx> { place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty)); } + // Place can be none if the pattern refers to a non-captured place in a closure. let place = place_builder.try_to_place(cx); - let default_irrefutable = || TestCase::Irrefutable { binding: None, ascription: None }; let mut subpairs = Vec::new(); let test_case = match pattern.kind { - PatKind::Wild | PatKind::Error(_) => default_irrefutable(), + PatKind::Wild | PatKind::Error(_) => None, - PatKind::Or { ref pats } => TestCase::Or { + PatKind::Or { ref pats } => Some(TestCase::Or { pats: pats.iter().map(|pat| FlatPat::new(place_builder.clone(), pat, cx)).collect(), - }, + }), PatKind::Range(ref range) => { if range.is_full_range(cx.tcx) == Some(true) { - default_irrefutable() + None } else { - TestCase::Range(Arc::clone(range)) + Some(TestCase::Range(Arc::clone(range))) } } - PatKind::Constant { value } => TestCase::Constant { value }, + PatKind::Constant { value } => Some(TestCase::Constant { value }), PatKind::AscribeUserType { - ascription: thir::Ascription { ref annotation, variance }, + ascription: Ascription { ref annotation, variance }, ref subpattern, .. } => { + MatchPairTree::for_pattern( + place_builder, + subpattern, + cx, + &mut subpairs, + extra_data, + ); + // Apply the type ascription to the value at `match_pair.place` - let ascription = place.map(|source| super::Ascription { - annotation: annotation.clone(), - source, - variance, - }); - - subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); - TestCase::Irrefutable { ascription, binding: None } + if let Some(source) = place { + let annotation = annotation.clone(); + extra_data.ascriptions.push(super::Ascription { source, annotation, variance }); + } + + None } PatKind::Binding { mode, var, ref subpattern, .. } => { - let binding = place.map(|source| super::Binding { - span: pattern.span, - source, - var_id: var, - binding_mode: mode, - }); + // In order to please the borrow checker, when lowering a pattern + // like `x @ subpat` we must establish any bindings in `subpat` + // before establishing the binding for `x`. + // + // For example (from #69971): + // + // ```ignore (illustrative) + // struct NonCopyStruct { + // copy_field: u32, + // } + // + // fn foo1(x: NonCopyStruct) { + // let y @ NonCopyStruct { copy_field: z } = x; + // // the above should turn into + // let z = x.copy_field; + // let y = x; + // } + // ``` + // First, recurse into the subpattern, if any. if let Some(subpattern) = subpattern.as_ref() { // this is the `x @ P` case; have to keep matching against `P` now - subpairs.push(MatchPairTree::for_pattern(place_builder, subpattern, cx)); + MatchPairTree::for_pattern( + place_builder, + subpattern, + cx, + &mut subpairs, + extra_data, + ); } - TestCase::Irrefutable { ascription: None, binding } + + // Then push this binding, after any bindings in the subpattern. + if let Some(source) = place { + extra_data.bindings.push(super::Binding { + span: pattern.span, + source, + var_id: var, + binding_mode: mode, + }); + } + + None } PatKind::ExpandedConstant { subpattern: ref pattern, def_id: _, is_inline: false } => { - subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); - default_irrefutable() + MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); + None } PatKind::ExpandedConstant { subpattern: ref pattern, def_id, is_inline: true } => { + MatchPairTree::for_pattern(place_builder, pattern, cx, &mut subpairs, extra_data); + // Apply a type ascription for the inline constant to the value at `match_pair.place` - let ascription = place.map(|source| { + if let Some(source) = place { let span = pattern.span; let parent_id = cx.tcx.typeck_root_def_id(cx.def_id.to_def_id()); let args = ty::InlineConstArgs::new( @@ -189,33 +229,47 @@ impl<'tcx> MatchPairTree<'tcx> { span, user_ty: Box::new(user_ty), }; - super::Ascription { annotation, source, variance: ty::Contravariant } - }); + let variance = ty::Contravariant; + extra_data.ascriptions.push(super::Ascription { annotation, source, variance }); + } - subpairs.push(MatchPairTree::for_pattern(place_builder, pattern, cx)); - TestCase::Irrefutable { ascription, binding: None } + None } PatKind::Array { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); - default_irrefutable() + cx.prefix_slice_suffix( + &mut subpairs, + extra_data, + &place_builder, + prefix, + slice, + suffix, + ); + None } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix(&mut subpairs, &place_builder, prefix, slice, suffix); + cx.prefix_slice_suffix( + &mut subpairs, + extra_data, + &place_builder, + prefix, + slice, + suffix, + ); if prefix.is_empty() && slice.is_some() && suffix.is_empty() { - default_irrefutable() + None } else { - TestCase::Slice { + Some(TestCase::Slice { len: prefix.len() + suffix.len(), variable_length: slice.is_some(), - } + }) } } PatKind::Variant { adt_def, variant_index, args, ref subpatterns } => { let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` - subpairs = cx.field_match_pairs(downcast_place, subpatterns); + cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns); let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| { i == variant_index @@ -225,21 +279,23 @@ impl<'tcx> MatchPairTree<'tcx> { .apply_ignore_module(cx.tcx, cx.infcx.typing_env(cx.param_env)) }) && (adt_def.did().is_local() || !adt_def.is_variant_list_non_exhaustive()); - if irrefutable { - default_irrefutable() - } else { - TestCase::Variant { adt_def, variant_index } - } + if irrefutable { None } else { Some(TestCase::Variant { adt_def, variant_index }) } } PatKind::Leaf { ref subpatterns } => { - subpairs = cx.field_match_pairs(place_builder, subpatterns); - default_irrefutable() + cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns); + None } PatKind::Deref { ref subpattern } => { - subpairs.push(MatchPairTree::for_pattern(place_builder.deref(), subpattern, cx)); - default_irrefutable() + MatchPairTree::for_pattern( + place_builder.deref(), + subpattern, + cx, + &mut subpairs, + extra_data, + ); + None } PatKind::DerefPattern { ref subpattern, mutability } => { @@ -249,23 +305,32 @@ impl<'tcx> MatchPairTree<'tcx> { Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability), pattern.span, ); - subpairs.push(MatchPairTree::for_pattern( + MatchPairTree::for_pattern( PlaceBuilder::from(temp).deref(), subpattern, cx, - )); - TestCase::Deref { temp, mutability } + &mut subpairs, + extra_data, + ); + Some(TestCase::Deref { temp, mutability }) } - PatKind::Never => TestCase::Never, + PatKind::Never => Some(TestCase::Never), }; - MatchPairTree { - place, - test_case, - subpairs, - pattern_ty: pattern.ty, - pattern_span: pattern.span, + if let Some(test_case) = test_case { + // This pattern is refutable, so push a new match-pair node. + match_pairs.push(MatchPairTree { + place: place.expect("refutable patterns should always have a place to inspect"), + test_case, + subpairs, + pattern_ty: pattern.ty, + pattern_span: pattern.span, + }) + } else { + // This pattern is irrefutable, so it doesn't need its own match-pair node. + // Just push its refutable subpatterns instead, if any. + match_pairs.extend(subpairs); } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index d05d5b151ff48..b05052a3455ea 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -26,7 +26,6 @@ use crate::builder::{ // helper functions, broken out by category: mod match_pair; -mod simplify; mod test; mod util; @@ -987,18 +986,16 @@ impl<'tcx> PatternExtraData<'tcx> { } /// A pattern in a form suitable for lowering the match tree, with all irrefutable -/// patterns simplified away, and or-patterns sorted to the end. +/// patterns simplified away. /// -/// Here, "flat" indicates that the pattern's match pairs have been recursively -/// simplified by [`Builder::simplify_match_pairs`]. They are not necessarily -/// flat in an absolute sense. +/// Here, "flat" indicates that irrefutable nodes in the pattern tree have been +/// recursively replaced with their refutable subpatterns. They are not +/// necessarily flat in an absolute sense. /// /// Will typically be incorporated into a [`Candidate`]. #[derive(Debug, Clone)] struct FlatPat<'tcx> { /// To match the pattern, all of these must be satisfied... - // Invariant: all the match pairs are recursively simplified. - // Invariant: or-patterns must be sorted to the end. match_pairs: Vec>, extra_data: PatternExtraData<'tcx>, @@ -1008,17 +1005,15 @@ impl<'tcx> FlatPat<'tcx> { /// Creates a `FlatPat` containing a simplified [`MatchPairTree`] list/forest /// for the given pattern. fn new(place: PlaceBuilder<'tcx>, pattern: &Pat<'tcx>, cx: &mut Builder<'_, 'tcx>) -> Self { - // First, recursively build a tree of match pairs for the given pattern. - let mut match_pairs = vec![MatchPairTree::for_pattern(place, pattern, cx)]; + // Recursively build a tree of match pairs for the given pattern. + let mut match_pairs = vec![]; let mut extra_data = PatternExtraData { span: pattern.span, bindings: Vec::new(), ascriptions: Vec::new(), is_never: pattern.is_never_pattern(), }; - // Recursively remove irrefutable match pairs, while recording their - // bindings/ascriptions, and sort or-patterns after other match pairs. - cx.simplify_match_pairs(&mut match_pairs, &mut extra_data); + MatchPairTree::for_pattern(place, pattern, cx, &mut match_pairs, &mut extra_data); Self { match_pairs, extra_data } } @@ -1055,7 +1050,6 @@ struct Candidate<'tcx> { /// (see [`Builder::test_remaining_match_pairs_after_or`]). /// /// Invariants: - /// - All [`TestCase::Irrefutable`] patterns have been removed by simplification. /// - All or-patterns ([`TestCase::Or`]) have been sorted to the end. match_pairs: Vec>, @@ -1126,7 +1120,7 @@ impl<'tcx> Candidate<'tcx> { /// Incorporates an already-simplified [`FlatPat`] into a new candidate. fn from_flat_pat(flat_pat: FlatPat<'tcx>, has_guard: bool) -> Self { - Candidate { + let mut this = Candidate { match_pairs: flat_pat.match_pairs, extra_data: flat_pat.extra_data, has_guard, @@ -1135,7 +1129,14 @@ impl<'tcx> Candidate<'tcx> { otherwise_block: None, pre_binding_block: None, false_edge_start_block: None, - } + }; + this.sort_match_pairs(); + this + } + + /// Restores the invariant that or-patterns must be sorted to the end. + fn sort_match_pairs(&mut self) { + self.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. })); } /// Returns whether the first match pair of this candidate is an or-pattern. @@ -1227,17 +1228,11 @@ struct Ascription<'tcx> { /// - [`Builder::pick_test_for_match_pair`] (to choose a test) /// - [`Builder::sort_candidate`] (to see how the test interacts with a match pair) /// -/// Two variants are unlike the others and deserve special mention: -/// -/// - [`Self::Irrefutable`] is only used temporarily when building a [`MatchPairTree`]. -/// They are then flattened away by [`Builder::simplify_match_pairs`], with any -/// bindings/ascriptions incorporated into the enclosing [`FlatPat`]. -/// - [`Self::Or`] are not tested directly like the other variants. Instead they -/// participate in or-pattern expansion, where they are transformed into subcandidates. -/// - See [`Builder::expand_and_match_or_candidates`]. +/// Note that or-patterns are not tested directly like the other variants. +/// Instead they participate in or-pattern expansion, where they are transformed into +/// subcandidates. See [`Builder::expand_and_match_or_candidates`]. #[derive(Debug, Clone)] enum TestCase<'tcx> { - Irrefutable { binding: Option>, ascription: Option> }, Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, Constant { value: mir::Const<'tcx> }, Range(Arc>), @@ -1261,19 +1256,9 @@ impl<'tcx> TestCase<'tcx> { #[derive(Debug, Clone)] pub(crate) struct MatchPairTree<'tcx> { /// This place... - /// - /// --- - /// This can be `None` if it referred to a non-captured place in a closure. - /// - /// Invariant: Can only be `None` when `test_case` is `Irrefutable`. - /// Therefore this must be `Some(_)` after simplification. - place: Option>, + place: Place<'tcx>, /// ... must pass this test... - /// - /// --- - /// Invariant: after creation and simplification in [`FlatPat::new`], - /// this must not be [`TestCase::Irrefutable`]. test_case: TestCase<'tcx>, /// ... and these subpairs must match. @@ -2091,11 +2076,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Extract the match-pair from the highest priority candidate let match_pair = &candidates[0].match_pairs[0]; let test = self.pick_test_for_match_pair(match_pair); - // Unwrap is ok after simplification. - let match_place = match_pair.place.unwrap(); debug!(?test, ?match_pair); - (match_place, test) + (match_pair.place, test) } /// Given a test, we partition the input candidates into several buckets. diff --git a/compiler/rustc_mir_build/src/builder/matches/simplify.rs b/compiler/rustc_mir_build/src/builder/matches/simplify.rs deleted file mode 100644 index 15c860151dc9e..0000000000000 --- a/compiler/rustc_mir_build/src/builder/matches/simplify.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Simplifying Candidates -//! -//! *Simplifying* a match pair `place @ pattern` means breaking it down -//! into bindings or other, simpler match pairs. For example: -//! -//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]` -//! - `place @ x` can be simplified to `[]` by binding `x` to `place` -//! -//! The `simplify_match_pairs` routine just repeatedly applies these -//! sort of simplifications until there is nothing left to -//! simplify. Match pairs cannot be simplified if they require some -//! sort of test: for example, testing which variant an enum is, or -//! testing a value against a constant. - -use std::mem; - -use tracing::{debug, instrument}; - -use crate::builder::Builder; -use crate::builder::matches::{MatchPairTree, PatternExtraData, TestCase}; - -impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and - /// ascriptions in `extra_data`. - #[instrument(skip(self), level = "debug")] - pub(super) fn simplify_match_pairs( - &mut self, - match_pairs: &mut Vec>, - extra_data: &mut PatternExtraData<'tcx>, - ) { - // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the - // bindings in `pat` before `x`. E.g. (#69971): - // - // struct NonCopyStruct { - // copy_field: u32, - // } - // - // fn foo1(x: NonCopyStruct) { - // let y @ NonCopyStruct { copy_field: z } = x; - // // the above should turn into - // let z = x.copy_field; - // let y = x; - // } - // - // We therefore lower bindings from left-to-right, except we lower the `x` in `x @ pat` - // after any bindings in `pat`. This doesn't work for or-patterns: the current structure of - // match lowering forces us to lower bindings inside or-patterns last. - for mut match_pair in mem::take(match_pairs) { - self.simplify_match_pairs(&mut match_pair.subpairs, extra_data); - if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case { - if let Some(binding) = binding { - extra_data.bindings.push(binding); - } - if let Some(ascription) = ascription { - extra_data.ascriptions.push(ascription); - } - // Simplifiable pattern; we replace it with its already simplified subpairs. - match_pairs.append(&mut match_pair.subpairs); - } else { - // Unsimplifiable pattern; we keep it. - match_pairs.push(match_pair); - } - } - - // Move or-patterns to the end, because they can result in us - // creating additional candidates, so we want to test them as - // late as possible. - match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. })); - debug!(simplified = ?match_pairs, "simplify_match_pairs"); - } -} diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index a7a028bff97f7..e5d61bc9e556a 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -55,12 +55,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Or-patterns are not tested directly; instead they are expanded into subcandidates, // which are then distinguished by testing whatever non-or patterns they contain. TestCase::Or { .. } => bug!("or-patterns should have already been handled"), - - TestCase::Irrefutable { .. } => span_bug!( - match_pair.pattern_span, - "simplifiable pattern found: {:?}", - match_pair.pattern_span - ), }; Test { span: match_pair.pattern_span, kind } @@ -546,11 +540,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // than one, but it'd be very unusual to have two sides that // both require tests; you'd expect one side to be simplified // away.) - let (match_pair_index, match_pair) = candidate - .match_pairs - .iter() - .enumerate() - .find(|&(_, mp)| mp.place == Some(test_place))?; + let (match_pair_index, match_pair) = + candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == test_place)?; // If true, the match pair is completely entailed by its corresponding test // branch, so it can be removed. If false, the match pair is _compatible_ @@ -593,7 +584,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate .match_pairs .iter() - .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case)) + .any(|mp| mp.place == test_place && is_covering_range(&mp.test_case)) }; if sorted_candidates .get(&TestBranch::Failure) @@ -769,7 +760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let match_pair = candidate.match_pairs.remove(match_pair_index); candidate.match_pairs.extend(match_pair.subpairs); // Move or-patterns to the end. - candidate.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. })); + candidate.sort_match_pairs(); } ret diff --git a/compiler/rustc_mir_build/src/builder/matches/util.rs b/compiler/rustc_mir_build/src/builder/matches/util.rs index 589e350a03fc3..ed3b652e4ef5d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/util.rs +++ b/compiler/rustc_mir_build/src/builder/matches/util.rs @@ -173,14 +173,10 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> { // } // ``` // Hence we fake borrow using a deep borrow. - if let Some(place) = match_pair.place { - self.fake_borrow(place, FakeBorrowKind::Deep); - } + self.fake_borrow(match_pair.place, FakeBorrowKind::Deep); } else { // Insert a Shallow borrow of any place that is switched on. - if let Some(place) = match_pair.place { - self.fake_borrow(place, FakeBorrowKind::Shallow); - } + self.fake_borrow(match_pair.place, FakeBorrowKind::Shallow); for subpair in &match_pair.subpairs { self.visit_match_pair(subpair); diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 4348b7a4b4cc9..2909dea98b747 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -37,7 +37,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( .map(|captured_place| { let name = captured_place.to_symbol(); match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue => name, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => name, ty::UpvarCapture::ByRef(..) => Symbol::intern(&format!("_ref__{name}")), } }) @@ -61,7 +61,9 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { Ok((thir, expr)) => { let build_mir = |thir: &Thir<'tcx>| match thir.body_type { thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, thir, expr, fn_sig), - thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty), + thir::BodyTy::Const(ty) | thir::BodyTy::GlobalAsm(ty) => { + construct_const(tcx, def, thir, expr, ty) + } }; // this must run before MIR dump, because @@ -483,7 +485,7 @@ fn construct_fn<'tcx>( }; if let Some(custom_mir_attr) = - tcx.hir().attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir) + tcx.hir_attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir) { return custom::build_custom_mir( tcx, @@ -576,6 +578,7 @@ fn construct_const<'a, 'tcx>( let span = tcx.def_span(def); (span, span) } + Node::Item(hir::Item { kind: hir::ItemKind::GlobalAsm { .. }, span, .. }) => (*span, *span), _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def), }; @@ -609,7 +612,8 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - | DefKind::AssocConst | DefKind::AnonConst | DefKind::InlineConst - | DefKind::Static { .. } => (vec![], tcx.type_of(def_id).instantiate_identity(), None), + | DefKind::Static { .. } + | DefKind::GlobalAsm => (vec![], tcx.type_of(def_id).instantiate_identity(), None), DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => { let sig = tcx.liberate_late_bound_regions( def_id.to_def_id(), @@ -737,7 +741,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { coroutine: Option>>, ) -> Builder<'a, 'tcx> { let tcx = infcx.tcx; - let attrs = tcx.hir().attrs(hir_id); + let attrs = tcx.hir_attrs(hir_id); // Some functions always have overflow checks enabled, // however, they may not get codegen'd, depending on // the settings for the crate they are codegened in. @@ -868,7 +872,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut projs = closure_env_projs.clone(); projs.push(ProjectionElem::Field(FieldIdx::new(i), ty)); match capture { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} ty::UpvarCapture::ByRef(..) => { projs.push(ProjectionElem::Deref); } diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 8156123949121..27ff01b48034b 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -942,14 +942,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { assert_eq!(orig_id.owner, self.hir_id.owner); let mut id = orig_id; - let hir = self.tcx.hir(); loop { if id == self.hir_id { // This is a moderately common case, mostly hit for previously unseen nodes. break; } - if hir.attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) { + if self.tcx.hir_attrs(id).iter().any(|attr| Level::from_attr(attr).is_some()) { // This is a rare case. It's for a node path that doesn't reach the root due to an // intervening lint level attribute. This result doesn't get cached. return id; diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index d65c2097d226e..7f2e7d5ca8385 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -2,6 +2,7 @@ use std::borrow::Cow; use std::mem; use std::ops::Bound; +use rustc_ast::AsmMacro; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::DiagArgValue; use rustc_hir::def::DefKind; @@ -450,6 +451,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { | ExprKind::Tuple { .. } | ExprKind::Unary { .. } | ExprKind::Call { .. } + | ExprKind::ByUse { .. } | ExprKind::Assign { .. } | ExprKind::AssignOp { .. } | ExprKind::Break { .. } @@ -559,7 +561,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } } ExprKind::InlineAsm(box InlineAsmExpr { - asm_macro: _, + asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm, ref operands, template: _, options: _, @@ -583,7 +585,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { } Out { expr: None, reg: _, late: _ } | Const { value: _, span: _ } - | SymFn { value: _, span: _ } + | SymFn { value: _ } | SymStatic { def_id: _ } => {} Label { block } => { // Label blocks are safe context. @@ -751,6 +753,11 @@ impl UnsafeOpKind { span: Span, suggest_unsafe_block: bool, ) { + if tcx.hir_opt_delegation_sig_id(hir_id.owner.def_id).is_some() { + // The body of the delegation item is synthesized, so it makes no sense + // to emit this lint. + return; + } let parent_id = tcx.hir_get_parent_item(hir_id); let parent_owner = tcx.hir_owner_node(parent_id); let should_suggest = parent_owner.fn_sig().is_some_and(|sig| { diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index f1753be845d4f..17b22f25dbb0a 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -828,7 +828,7 @@ pub(crate) struct IrrefutableLetPatternsWhileLet { #[derive(Diagnostic)] #[diag(mir_build_borrow_of_moved_value)] -pub(crate) struct BorrowOfMovedValue { +pub(crate) struct BorrowOfMovedValue<'tcx> { #[primary_span] #[label] #[label(mir_build_occurs_because_label)] @@ -836,7 +836,7 @@ pub(crate) struct BorrowOfMovedValue { #[label(mir_build_value_borrowed_label)] pub(crate) conflicts_ref: Vec, pub(crate) name: Ident, - pub(crate) ty: String, + pub(crate) ty: Ty<'tcx>, #[suggestion(code = "ref ", applicability = "machine-applicable")] pub(crate) suggest_borrowing: Option, } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index fa5db32d9134c..a25697ba086d8 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -3,12 +3,12 @@ // tidy-alphabetical-start #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(let_chains)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end // The `builder` module used to be named `build`, but that was causing GitHub's diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index d0fca76fcf05d..b8af77245f25d 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -429,9 +429,7 @@ impl<'tcx> ThirBuildCx<'tcx> { let user_provided_types = self.typeck_results.user_provided_types(); let user_ty = user_provided_types.get(fun.hir_id).copied().map(|mut u_ty| { - if let ty::UserTypeKind::TypeOf(ref mut did, _) = - &mut u_ty.value.kind - { + if let ty::UserTypeKind::TypeOf(did, _) = &mut u_ty.value.kind { *did = adt_def.did(); } Box::new(u_ty) @@ -466,6 +464,10 @@ impl<'tcx> ThirBuildCx<'tcx> { } } + hir::ExprKind::Use(expr, span) => { + ExprKind::ByUse { expr: self.mirror_expr(expr), span } + } + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, mutbl, arg) => { ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg: self.mirror_expr(arg) } } @@ -650,7 +652,7 @@ impl<'tcx> ThirBuildCx<'tcx> { } }, - hir::ExprKind::Closure { .. } => { + hir::ExprKind::Closure(hir::Closure { .. }) => { let closure_ty = self.typeck_results.expr_ty(expr); let (def_id, args, movability) = match *closure_ty.kind() { ty::Closure(def_id, args) => (def_id, UpvarArgs::Closure(args), None), @@ -732,20 +734,23 @@ impl<'tcx> ThirBuildCx<'tcx> { } } hir::InlineAsmOperand::Const { ref anon_const } => { - let value = - mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id()) - .instantiate_identity(); - let span = tcx.def_span(anon_const.def_id); - - InlineAsmOperand::Const { value, span } + let ty = self.typeck_results.node_type(anon_const.hir_id); + let did = anon_const.def_id.to_def_id(); + let typeck_root_def_id = tcx.typeck_root_def_id(did); + let parent_args = tcx.erase_regions(GenericArgs::identity_for_item( + tcx, + typeck_root_def_id, + )); + let args = + InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }) + .args; + + let uneval = mir::UnevaluatedConst::new(did, args); + let value = mir::Const::Unevaluated(uneval, ty); + InlineAsmOperand::Const { value, span: tcx.def_span(did) } } - hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = - mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id()) - .instantiate_identity(); - let span = tcx.def_span(anon_const.def_id); - - InlineAsmOperand::SymFn { value, span } + hir::InlineAsmOperand::SymFn { expr } => { + InlineAsmOperand::SymFn { value: self.mirror_expr(expr) } } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { InlineAsmOperand::SymStatic { def_id } @@ -1036,7 +1041,7 @@ impl<'tcx> ThirBuildCx<'tcx> { "Should have already errored about late bound consts: {def_id:?}" ); }; - let name = self.tcx.hir().name(hir_id); + let name = self.tcx.hir_name(hir_id); let param = ty::ParamConst::new(index, name); ExprKind::ConstParam { param, def_id } @@ -1247,6 +1252,17 @@ impl<'tcx> ThirBuildCx<'tcx> { match upvar_capture { ty::UpvarCapture::ByValue => captured_place_expr, + ty::UpvarCapture::ByUse => { + let span = captured_place_expr.span; + let expr_id = self.thir.exprs.push(captured_place_expr); + + Expr { + temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible }, + ty: upvar_ty, + span: closure_expr.span, + kind: ExprKind::ByUse { expr: expr_id, span }, + } + } ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow { ty::BorrowKind::Immutable => BorrowKind::Shared, diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 7a9f6e4630456..b3daed8a7e017 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -73,26 +73,31 @@ struct ThirBuildCx<'tcx> { impl<'tcx> ThirBuildCx<'tcx> { fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self { let typeck_results = tcx.typeck(def); - let hir = tcx.hir(); let hir_id = tcx.local_def_id_to_hir_id(def); - let body_type = if tcx.hir_body_owner_kind(def).is_fn_or_closure() { - // fetch the fully liberated fn signature (that is, all bound - // types/lifetimes replaced) - BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) - } else { - // Get the revealed type of this const. This is *not* the adjusted - // type of its body, which may be a subtype of this type. For - // example: - // - // fn foo(_: &()) {} - // static X: fn(&'static ()) = foo; - // - // The adjusted type of the body of X is `for<'a> fn(&'a ())` which - // is not the same as the type of X. We need the type of the return - // place to be the type of the constant because NLL typeck will - // equate them. - BodyTy::Const(typeck_results.node_type(hir_id)) + let body_type = match tcx.hir_body_owner_kind(def) { + rustc_hir::BodyOwnerKind::Fn | rustc_hir::BodyOwnerKind::Closure => { + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id]) + } + rustc_hir::BodyOwnerKind::Const { .. } | rustc_hir::BodyOwnerKind::Static(_) => { + // Get the revealed type of this const. This is *not* the adjusted + // type of its body, which may be a subtype of this type. For + // example: + // + // fn foo(_: &()) {} + // static X: fn(&'static ()) = foo; + // + // The adjusted type of the body of X is `for<'a> fn(&'a ())` which + // is not the same as the type of X. We need the type of the return + // place to be the type of the constant because NLL typeck will + // equate them. + BodyTy::Const(typeck_results.node_type(hir_id)) + } + rustc_hir::BodyOwnerKind::GlobalAsm => { + BodyTy::GlobalAsm(typeck_results.node_type(hir_id)) + } }; Self { @@ -105,8 +110,8 @@ impl<'tcx> ThirBuildCx<'tcx> { typeck_results, rvalue_scopes: &typeck_results.rvalue_scopes, body_owner: def.to_def_id(), - apply_adjustments: hir - .attrs(hir_id) + apply_adjustments: tcx + .hir_attrs(hir_id) .iter() .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir), } @@ -159,12 +164,12 @@ impl<'tcx> ThirBuildCx<'tcx> { }) } - fn explicit_params<'a>( - &'a mut self, + fn explicit_params( + &mut self, owner_id: HirId, fn_decl: &'tcx hir::FnDecl<'tcx>, body: &'tcx hir::Body<'tcx>, - ) -> impl Iterator> + 'a { + ) -> impl Iterator> { let fn_sig = self.typeck_results.liberated_fn_sigs()[owner_id]; body.params.iter().enumerate().map(move |(index, param)| { @@ -201,7 +206,7 @@ impl<'tcx> ThirBuildCx<'tcx> { &self, hir_id: HirId, ) -> Option> { - crate::thir::util::user_args_applied_to_ty_of_hir_id(self.typeck_results, hir_id) + crate::thir::util::user_args_applied_to_ty_of_hir_id(self.tcx, self.typeck_results, hir_id) } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 18305db28c281..cbd29ba837ef6 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -345,6 +345,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> { | Borrow { .. } | Box { .. } | Call { .. } + | ByUse { .. } | Closure { .. } | ConstBlock { .. } | ConstParam { .. } @@ -786,17 +787,13 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: } }); if !conflicts_ref.is_empty() { - let mut path = None; - let ty = cx.tcx.short_string(ty, &mut path); - let mut err = sess.dcx().create_err(BorrowOfMovedValue { + sess.dcx().emit_err(BorrowOfMovedValue { binding_span: pat.span, conflicts_ref, name: Ident::new(name, pat.span), ty, suggest_borrowing: Some(pat.span.shrink_to_lo()), }); - *err.long_ty_path() = path; - err.emit(); } return; } @@ -1046,7 +1043,7 @@ fn find_fallback_pattern_typo<'tcx>( for item in cx.tcx.hir_crate_items(()).free_items() { if let DefKind::Use = cx.tcx.def_kind(item.owner_id) { // Look for consts being re-exported. - let item = cx.tcx.hir().expect_item(item.owner_id.def_id); + let item = cx.tcx.hir_expect_item(item.owner_id.def_id); let use_name = item.ident.name; let hir::ItemKind::Use(path, _) = item.kind else { continue; @@ -1097,7 +1094,7 @@ fn find_fallback_pattern_typo<'tcx>( } } if let Some((i, &const_name)) = - accessible.iter().enumerate().find(|(_, &const_name)| const_name == name) + accessible.iter().enumerate().find(|&(_, &const_name)| const_name == name) { // The pattern name is an exact match, so the pattern needed to be imported. lint.wanted_constant = Some(WantedConstant { @@ -1115,7 +1112,7 @@ fn find_fallback_pattern_typo<'tcx>( const_path: name.to_string(), }); } else if let Some(i) = - imported.iter().enumerate().find(|(_, &const_name)| const_name == name).map(|(i, _)| i) + imported.iter().enumerate().find(|&(_, &const_name)| const_name == name).map(|(i, _)| i) { // The const with the exact name wasn't re-exported from an import in this // crate, we point at the import. diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8dc3f998e0916..4bfeab44bf4b9 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -539,7 +539,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { &self, hir_id: hir::HirId, ) -> Option> { - crate::thir::util::user_args_applied_to_ty_of_hir_id(self.typeck_results, hir_id) + crate::thir::util::user_args_applied_to_ty_of_hir_id(self.tcx, self.typeck_results, hir_id) } /// Takes a HIR Path. If the path is a constant, evaluates it and feeds diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 9ab87dd99ffc0..16cef0ec3acbc 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -246,6 +246,13 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, "}", depth_lvl); } + ByUse { expr, span } => { + print_indented!(self, "ByUse {", depth_lvl); + print_indented!(self, "expr:", depth_lvl + 1); + self.print_expr(*expr, depth_lvl + 2); + print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "}", depth_lvl); + } Deref { arg } => { print_indented!(self, "Deref {", depth_lvl); self.print_expr(*arg, depth_lvl + 1); @@ -921,10 +928,10 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); print_indented!(self, "}", depth_lvl + 1); } - InlineAsmOperand::SymFn { value, span } => { + InlineAsmOperand::SymFn { value } => { print_indented!(self, "InlineAsmOperand::SymFn {", depth_lvl); - print_indented!(self, format!("value: {:?}", *value), depth_lvl + 1); - print_indented!(self, format!("span: {:?}", span), depth_lvl + 1); + print_indented!(self, "value: ", depth_lvl + 1); + self.print_expr(*value, depth_lvl + 2); print_indented!(self, "}", depth_lvl + 1); } InlineAsmOperand::SymStatic { def_id } => { diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs index 4dff093afd0d9..457957f5fce95 100644 --- a/compiler/rustc_mir_build/src/thir/util.rs +++ b/compiler/rustc_mir_build/src/thir/util.rs @@ -1,12 +1,16 @@ +use std::assert_matches::assert_matches; + use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_middle::bug; -use rustc_middle::ty::{self, CanonicalUserType}; +use rustc_middle::ty::{self, CanonicalUserType, TyCtxt}; use tracing::debug; /// Looks up the type associated with this hir-id and applies the /// user-given generic parameters; the hir-id must map to a suitable /// type. pub(crate) fn user_args_applied_to_ty_of_hir_id<'tcx>( + tcx: TyCtxt<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, hir_id: hir::HirId, ) -> Option> { @@ -16,7 +20,23 @@ pub(crate) fn user_args_applied_to_ty_of_hir_id<'tcx>( let ty = typeck_results.node_type(hir_id); match ty.kind() { ty::Adt(adt_def, ..) => { - if let ty::UserTypeKind::TypeOf(ref mut did, _) = &mut user_ty.value.kind { + // This "fixes" user type annotations for tupled ctor patterns for ADTs. + // That's because `type_of(ctor_did)` returns a FnDef, but we actually + // want to be annotating the type of the ADT itself. It's a bit goofy, + // but it's easier to adjust this here rather than in the path lowering + // code for patterns in HIR. + if let ty::UserTypeKind::TypeOf(did, _) = &mut user_ty.value.kind { + // This is either already set up correctly (struct, union, enum, or variant), + // or needs adjusting (ctor). Make sure we don't start adjusting other + // user annotations like consts or fn calls. + assert_matches!( + tcx.def_kind(*did), + DefKind::Ctor(..) + | DefKind::Struct + | DefKind::Enum + | DefKind::Union + | DefKind::Variant + ); *did = adt_def.did(); } Some(user_ty) diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml index f84a06638976e..293bcbef21b85 100644 --- a/compiler/rustc_mir_dataflow/Cargo.toml +++ b/compiler/rustc_mir_dataflow/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_mir_dataflow" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index a8a56baa1ffc0..82c57ef5678dc 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(assert_matches)] #![feature(associated_type_defaults)] #![feature(box_patterns)] @@ -7,7 +8,6 @@ #![feature(let_chains)] #![feature(never_type)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_middle::ty; diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 8aea8d2ae3ca7..18985ba0da259 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -343,7 +343,7 @@ impl<'tcx> MovePathLookup<'tcx> { /// `MovePathIndex`es. pub fn iter_locals_enumerated( &self, - ) -> impl DoubleEndedIterator + '_ { + ) -> impl DoubleEndedIterator { self.locals.iter_enumerated().filter_map(|(l, &idx)| Some((l, idx?))) } } diff --git a/compiler/rustc_mir_dataflow/src/un_derefer.rs b/compiler/rustc_mir_dataflow/src/un_derefer.rs index b803ecc575ee0..b38dd9d40f521 100644 --- a/compiler/rustc_mir_dataflow/src/un_derefer.rs +++ b/compiler/rustc_mir_dataflow/src/un_derefer.rs @@ -28,7 +28,7 @@ impl<'tcx> UnDerefer<'tcx> { pub(crate) fn iter_projections( &self, place: PlaceRef<'tcx>, - ) -> impl Iterator, PlaceElem<'tcx>)> + '_ { + ) -> impl Iterator, PlaceElem<'tcx>)> { ProjectionIter::new(self.deref_chain(place.local), place) } } @@ -91,7 +91,7 @@ impl SlicePlusOne<'_, T> { #[inline] fn advance(&mut self) { match self.slice { - [_, ref remainder @ ..] => { + [_, remainder @ ..] => { self.slice = remainder; } [] => self.last = None, diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 104a2e8c09100..36fb1c2b36d02 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -2,7 +2,6 @@ use std::fmt::{Debug, Formatter}; use std::ops::Range; use rustc_abi::{FieldIdx, VariantIdx}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxIndexSet, StdEntry}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::IndexVec; @@ -125,7 +124,7 @@ impl State { pub fn all_bottom(&self) -> bool { match self { State::Unreachable => false, - State::Reachable(ref values) => + State::Reachable(values) => { #[allow(rustc::potential_query_instability)] values.map.values().all(V::is_bottom) @@ -349,7 +348,7 @@ impl JoinSemiLattice for State { *self = other.clone(); true } - (State::Reachable(this), State::Reachable(ref other)) => this.join(other), + (State::Reachable(this), State::Reachable(other)) => this.join(other), } } } @@ -676,10 +675,7 @@ impl<'tcx> Map<'tcx> { } /// Iterate over all direct children. - fn children( - &self, - parent: PlaceIndex, - ) -> impl Iterator + Captures<'_> + Captures<'tcx> { + fn children(&self, parent: PlaceIndex) -> impl Iterator { Children::new(self, parent) } diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml index 2f233f787f0cc..9e4b4534dcc54 100644 --- a/compiler/rustc_mir_transform/Cargo.toml +++ b/compiler/rustc_mir_transform/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_mir_transform" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -26,7 +26,6 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_type_ir = { path = "../rustc_type_ir" } smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs index 55694cacd92e0..bacff287859d0 100644 --- a/compiler/rustc_mir_transform/src/add_call_guards.rs +++ b/compiler/rustc_mir_transform/src/add_call_guards.rs @@ -32,14 +32,27 @@ pub(super) use self::AddCallGuards::*; impl<'tcx> crate::MirPass<'tcx> for AddCallGuards { fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let mut pred_count: IndexVec<_, _> = - body.basic_blocks.predecessors().iter().map(|ps| ps.len()).collect(); - pred_count[START_BLOCK] += 1; + let mut pred_count = IndexVec::from_elem(0u8, &body.basic_blocks); + for (_, data) in body.basic_blocks.iter_enumerated() { + for succ in data.terminator().successors() { + pred_count[succ] = pred_count[succ].saturating_add(1); + } + } // We need a place to store the new blocks generated let mut new_blocks = Vec::new(); let cur_len = body.basic_blocks.len(); + let mut new_block = |source_info: SourceInfo, is_cleanup: bool, target: BasicBlock| { + let block = BasicBlockData { + statements: vec![], + is_cleanup, + terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }), + }; + let idx = cur_len + new_blocks.len(); + new_blocks.push(block); + BasicBlock::new(idx) + }; for block in body.basic_blocks_mut() { match block.terminator { @@ -47,25 +60,34 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards { kind: TerminatorKind::Call { target: Some(ref mut destination), unwind, .. }, source_info, }) if pred_count[*destination] > 1 - && (matches!( - unwind, - UnwindAction::Cleanup(_) | UnwindAction::Terminate(_) - ) || self == &AllCallEdges) => + && (generates_invoke(unwind) || self == &AllCallEdges) => { // It's a critical edge, break it - let call_guard = BasicBlockData { - statements: vec![], - is_cleanup: block.is_cleanup, - terminator: Some(Terminator { - source_info, - kind: TerminatorKind::Goto { target: *destination }, - }), - }; - - // Get the index it will be when inserted into the MIR - let idx = cur_len + new_blocks.len(); - new_blocks.push(call_guard); - *destination = BasicBlock::new(idx); + *destination = new_block(source_info, block.is_cleanup, *destination); + } + Some(Terminator { + kind: + TerminatorKind::InlineAsm { + asm_macro: InlineAsmMacro::Asm, + ref mut targets, + ref operands, + unwind, + .. + }, + source_info, + }) if self == &CriticalCallEdges => { + let has_outputs = operands.iter().any(|op| { + matches!(op, InlineAsmOperand::InOut { .. } | InlineAsmOperand::Out { .. }) + }); + let has_labels = + operands.iter().any(|op| matches!(op, InlineAsmOperand::Label { .. })); + if has_outputs && (has_labels || generates_invoke(unwind)) { + for target in targets.iter_mut() { + if pred_count[*target] > 1 { + *target = new_block(source_info, block.is_cleanup, *target); + } + } + } } _ => {} } @@ -80,3 +102,11 @@ impl<'tcx> crate::MirPass<'tcx> for AddCallGuards { true } } + +/// Returns true if this unwind action is code generated as an invoke as opposed to a call. +fn generates_invoke(unwind: UnwindAction) -> bool { + match unwind { + UnwindAction::Continue | UnwindAction::Unreachable => false, + UnwindAction::Cleanup(_) | UnwindAction::Terminate(_) => true, + } +} diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs index d693f739180f4..2d04b62193585 100644 --- a/compiler/rustc_mir_transform/src/check_pointers.rs +++ b/compiler/rustc_mir_transform/src/check_pointers.rs @@ -71,8 +71,7 @@ pub(crate) fn check_pointers<'tcx, F>( // statements/blocks after. Iterating or visiting the MIR in order would require updating // our current location after every insertion. By iterating backwards, we dodge this issue: // The only Locations that an insertion changes have already been handled. - for block in (0..basic_blocks.len()).rev() { - let block = block.into(); + for block in basic_blocks.indices().rev() { for statement_index in (0..basic_blocks[block].statements.len()).rev() { let location = Location { block, statement_index }; let statement = &basic_blocks[block].statements[statement_index]; 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 0f5fcb0d8eb99..89a306c610477 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -78,7 +78,6 @@ use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{self, dump_mir}; use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; -use rustc_span::kw; pub(crate) fn coroutine_by_move_body_def_id<'tcx>( tcx: TyCtxt<'tcx>, @@ -170,7 +169,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( // this when building the field projection in the MIR body later on. let mut parent_capture_ty = parent_capture.place.ty(); parent_capture_ty = match parent_capture.info.capture_kind { - ty::UpvarCapture::ByValue => parent_capture_ty, + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => parent_capture_ty, ty::UpvarCapture::ByRef(kind) => Ty::new_ref( tcx, tcx.lifetimes.re_erased, @@ -179,7 +178,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( ), }; - ( + Some(( FieldIdx::from_usize(child_field_idx + num_args), ( FieldIdx::from_usize(parent_field_idx + num_args), @@ -187,9 +186,10 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( peel_deref, child_precise_captures, ), - ) + )) }, ) + .flatten() .collect(); if coroutine_kind == ty::ClosureKind::FnOnce { @@ -214,7 +214,7 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`. - let body_def = tcx.create_def(parent_def_id, kw::Empty, DefKind::SyntheticCoroutineBody); + let body_def = tcx.create_def(parent_def_id, None, DefKind::SyntheticCoroutineBody); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); @@ -313,10 +313,46 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { self.super_place(place, context, location); } + fn visit_statement(&mut self, statement: &mut mir::Statement<'tcx>, location: mir::Location) { + // Remove fake borrows of closure captures if that capture has been + // replaced with a by-move version of that capture. + // + // For example, imagine we capture `Foo` in the parent and `&Foo` + // in the child. We will emit two fake borrows like: + // + // ``` + // _2 = &fake shallow (*(_1.0: &Foo)); + // _3 = &fake shallow (_1.0: &Foo); + // ``` + // + // However, since this transform is responsible for replacing + // `_1.0: &Foo` with `_1.0: Foo`, that makes the second fake borrow + // obsolete, and we should replace it with a nop. + // + // As a side-note, we don't actually even care about fake borrows + // here at all since they're fully a MIR borrowck artifact, and we + // don't need to borrowck by-move MIR bodies. But it's best to preserve + // as much as we can between these two bodies :) + if let mir::StatementKind::Assign(box (_, rvalue)) = &statement.kind + && let mir::Rvalue::Ref(_, mir::BorrowKind::Fake(mir::FakeBorrowKind::Shallow), place) = + rvalue + && let mir::PlaceRef { + local: ty::CAPTURE_STRUCT_LOCAL, + projection: [mir::ProjectionElem::Field(idx, _)], + } = place.as_ref() + && let Some(&(_, _, true, _)) = self.field_remapping.get(&idx) + { + statement.kind = mir::StatementKind::Nop; + } + + self.super_statement(statement, location); + } + fn visit_local_decl(&mut self, local: mir::Local, local_decl: &mut mir::LocalDecl<'tcx>) { // Replace the type of the self arg. if local == ty::CAPTURE_STRUCT_LOCAL { local_decl.ty = self.by_move_coroutine_ty; } + self.super_local_decl(local, local_decl); } } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index b23d8b9e73729..00a8293966b04 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -37,29 +37,11 @@ impl<'b, 'tcx> CostChecker<'b, 'tcx> { /// and even the full `Inline` doesn't call `visit_body`, so there's nowhere /// to put this logic in the visitor. pub(super) fn add_function_level_costs(&mut self) { - fn is_call_like(bbd: &BasicBlockData<'_>) -> bool { - use TerminatorKind::*; - match bbd.terminator().kind { - Call { .. } | TailCall { .. } | Drop { .. } | Assert { .. } | InlineAsm { .. } => { - true - } - - Goto { .. } - | SwitchInt { .. } - | UnwindResume - | UnwindTerminate(_) - | Return - | Unreachable => false, - - Yield { .. } | CoroutineDrop | FalseEdge { .. } | FalseUnwind { .. } => { - unreachable!() - } - } - } - // If the only has one Call (or similar), inlining isn't increasing the total // number of calls, so give extra encouragement to inlining that. - if self.callee_body.basic_blocks.iter().filter(|bbd| is_call_like(bbd)).count() == 1 { + if self.callee_body.basic_blocks.iter().filter(|bbd| is_call_like(bbd.terminator())).count() + == 1 + { self.bonus += CALL_PENALTY; } } @@ -193,3 +175,26 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { } } } + +/// A terminator that's more call-like (might do a bunch of work, might panic, etc) +/// than it is goto-/return-like (no side effects, etc). +/// +/// Used to treat multi-call functions (which could inline exponentially) +/// different from those that only do one or none of these "complex" things. +pub(super) fn is_call_like(terminator: &Terminator<'_>) -> bool { + use TerminatorKind::*; + match terminator.kind { + Call { .. } | TailCall { .. } | Drop { .. } | Assert { .. } | InlineAsm { .. } => true, + + Goto { .. } + | SwitchInt { .. } + | UnwindResume + | UnwindTerminate(_) + | Return + | Unreachable => false, + + Yield { .. } | CoroutineDrop | FalseEdge { .. } | FalseUnwind { .. } => { + unreachable!() + } + } +} diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 039f346495be0..5568d42ab8f3c 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -50,7 +50,7 @@ fn make_node_flow_priority_list( // A "reloop" node has exactly one out-edge, which jumps back to the top // of an enclosing loop. Reloop nodes are typically visited more times // than loop-exit nodes, so try to avoid giving them physical counters. - let is_reloop_node = IndexVec::from_fn_n( + let is_reloop_node = IndexVec::::from_fn_n( |node| match graph.successors[node].as_slice() { &[succ] => graph.dominates(succ, node), _ => false, diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 6d84248ddfbdd..dcc7c5b91d76a 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -2,7 +2,6 @@ use std::cmp::Ordering; use std::ops::{Index, IndexMut}; use std::{mem, slice}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::graph::{self, DirectedGraph, StartNode}; @@ -43,7 +42,7 @@ impl CoverageGraph { // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so // de-duplication is required. This is done without reordering the successors. - let successors = IndexVec::from_fn_n( + let successors = IndexVec::::from_fn_n( |bcb| { let mut seen_bcbs = FxHashSet::default(); let terminator = mir_body[bcbs[bcb].last_bb()].terminator(); @@ -218,7 +217,7 @@ impl CoverageGraph { pub(crate) fn reloop_predecessors( &self, to_bcb: BasicCoverageBlock, - ) -> impl Iterator + Captures<'_> { + ) -> impl Iterator { self.predecessors[to_bcb].iter().copied().filter(move |&pred| self.dominates(to_bcb, pred)) } } diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index ef86358b2057a..ccf76dc710874 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,4 +1,3 @@ -use rustc_data_structures::captures::Captures; use rustc_index::bit_set::DenseBitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::coverage::{BasicCoverageBlock, CoverageIdsInfo, CoverageKind, MappingKind}; @@ -66,7 +65,7 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { Some(_) | None => { // Other possibilities should have been rejected by `rustc_parse::validate_attr`. // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880). - tcx.dcx().span_delayed_bug(attr.span, "unexpected value of coverage attribute"); + tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute"); } } } @@ -153,7 +152,7 @@ fn coverage_ids_info<'tcx>( fn all_coverage_in_mir_body<'a, 'tcx>( body: &'a Body<'tcx>, -) -> impl Iterator + Captures<'tcx> { +) -> impl Iterator { body.basic_blocks.iter().flat_map(|bb_data| &bb_data.statements).filter_map(|statement| { match statement.kind { StatementKind::Coverage(ref kind) if !is_inlined(body, statement) => Some(kind), diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 314a86ea52f0a..b9ed6984ddb21 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,6 +1,5 @@ use std::collections::VecDeque; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; @@ -182,7 +181,7 @@ fn divide_spans_into_buckets(input_covspans: Vec, holes: &[Hole]) -> Ve fn drain_front_while<'a, T>( queue: &'a mut VecDeque, mut pred_fn: impl FnMut(&T) -> bool, -) -> impl Iterator + Captures<'a> { +) -> impl Iterator { std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) } diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 049f13ce96d74..a0db8bdb7ed88 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -80,35 +80,6 @@ impl<'tcx> Visitor<'tcx> for DeduceReadOnly { // `f` passes. Note that function arguments are the only situation in which this problem can // arise: every other use of `move` in MIR doesn't actually write to the value it moves // from. - // - // Anyway, right now this situation doesn't actually arise in practice. Instead, the MIR for - // that function looks like this: - // - // fn f(_1: BigStruct) -> () { - // let mut _0: (); - // let mut _2: BigStruct; - // bb0: { - // _2 = move _1; - // _0 = g(move _2) -> bb1; - // } - // ... - // } - // - // Because of that extra move that MIR construction inserts, `x` (i.e. `_1`) can *in - // practice* safely be marked `readonly`. - // - // To handle the possibility that other optimizations (for example, destination propagation) - // might someday generate MIR like the first example above, we panic upon seeing an argument - // to *our* function that is directly moved into *another* function as an argument. Having - // eliminated that problematic case, we can safely treat moves as copies in this analysis. - // - // In the future, if MIR optimizations cause arguments of a caller to be directly moved into - // the argument of a callee, we can just add that argument to `mutated_args` instead of - // panicking. - // - // Note that, because the problematic MIR is never actually generated, we can't add a test - // case for this. - if let TerminatorKind::Call { ref args, .. } = terminator.kind { for arg in args { if let Operand::Move(place) = arg.node { diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 7b3553e7afd06..abbff1c48dd9a 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -53,11 +53,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { // Rust calls cannot themselves create foreign unwinds. // We assume this is true for intrinsics as well. - if let ExternAbi::RustIntrinsic - | ExternAbi::Rust - | ExternAbi::RustCall - | ExternAbi::RustCold = sig.abi() - { + if sig.abi().is_rustic_abi() { continue; }; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 2f8a305019999..0a54c780f31e5 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -872,8 +872,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.simplify_place_projection(place, location); return self.new_pointer(*place, AddressKind::Address(mutbl)); } - Rvalue::WrapUnsafeBinder(ref mut op, _) => { - return self.simplify_operand(op, location); + Rvalue::WrapUnsafeBinder(ref mut op, ty) => { + let value = self.simplify_operand(op, location)?; + Value::Cast { + kind: CastKind::Transmute, + value, + from: op.ty(self.local_decls, self.tcx), + to: ty, + } } // Operations. @@ -1259,7 +1265,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let layout = self.ecx.layout_of(lhs_ty).ok()?; - let as_bits = |value| { + let as_bits = |value: VnIndex| { let constant = self.evaluated[value].as_ref()?; if layout.backend_repr.is_scalar() { let scalar = self.ecx.read_scalar(constant).discard_err()?; @@ -1567,7 +1573,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { BackendRepr::ScalarPair(a, b) => { !a.is_always_valid(&self.ecx) || !b.is_always_valid(&self.ecx) } - BackendRepr::Vector { .. } | BackendRepr::Memory { .. } => false, + BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => false, } } diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 5981b5031c649..0ab24e48d443c 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1,5 +1,6 @@ //! Inlining pass for MIR functions. +use std::assert_matches::debug_assert_matches; use std::iter; use std::ops::{Range, RangeFrom}; @@ -18,7 +19,7 @@ use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; use tracing::{debug, instrument, trace, trace_span}; -use crate::cost_checker::CostChecker; +use crate::cost_checker::{CostChecker, is_call_like}; use crate::deref_separator::deref_finder; use crate::simplify::simplify_cfg; use crate::validate::validate_types; @@ -26,6 +27,7 @@ use crate::{check_inline, util}; pub(crate) mod cycle; +const HISTORY_DEPTH_LIMIT: usize = 20; const TOP_DOWN_DEPTH_LIMIT: usize = 5; #[derive(Clone, Debug)] @@ -117,6 +119,11 @@ trait Inliner<'tcx> { /// Should inlining happen for a given callee? fn should_inline_for_callee(&self, def_id: DefId) -> bool; + fn check_codegen_attributes_extra( + &self, + callee_attrs: &CodegenFnAttrs, + ) -> Result<(), &'static str>; + fn check_caller_mir_body(&self, body: &Body<'tcx>) -> bool; /// Returns inlining decision that is based on the examination of callee MIR body. @@ -128,10 +135,6 @@ trait Inliner<'tcx> { callee_attrs: &CodegenFnAttrs, ) -> Result<(), &'static str>; - // How many callsites in a body are we allowed to inline? We need to limit this in order - // to prevent super-linear growth in MIR size. - fn inline_limit_for_block(&self) -> Option; - /// Called when inlining succeeds. fn on_inline_success( &mut self, @@ -142,9 +145,6 @@ trait Inliner<'tcx> { /// Called when inlining failed or was not performed. fn on_inline_failure(&self, callsite: &CallSite<'tcx>, reason: &'static str); - - /// Called when the inline limit for a body is reached. - fn on_inline_limit_reached(&self) -> bool; } struct ForceInliner<'tcx> { @@ -191,6 +191,14 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { ForceInline::should_run_pass_for_callee(self.tcx(), def_id) } + fn check_codegen_attributes_extra( + &self, + callee_attrs: &CodegenFnAttrs, + ) -> Result<(), &'static str> { + debug_assert_matches!(callee_attrs.inline, InlineAttr::Force { .. }); + Ok(()) + } + fn check_caller_mir_body(&self, _: &Body<'tcx>) -> bool { true } @@ -224,10 +232,6 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { } } - fn inline_limit_for_block(&self) -> Option { - Some(usize::MAX) - } - fn on_inline_success( &mut self, callsite: &CallSite<'tcx>, @@ -261,10 +265,6 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> { justification: justification.map(|sym| crate::errors::ForceInlineJustification { sym }), }); } - - fn on_inline_limit_reached(&self) -> bool { - false - } } struct NormalInliner<'tcx> { @@ -278,6 +278,10 @@ struct NormalInliner<'tcx> { /// The number of `DefId`s is finite, so checking history is enough /// to ensure that we do not loop endlessly while inlining. history: Vec, + /// How many (multi-call) callsites have we inlined for the top-level call? + /// + /// We need to limit this in order to prevent super-linear growth in MIR size. + top_down_counter: usize, /// Indicates that the caller body has been modified. changed: bool, /// Indicates that the caller is #[inline] and just calls another function, @@ -285,6 +289,12 @@ struct NormalInliner<'tcx> { caller_is_inline_forwarder: bool, } +impl<'tcx> NormalInliner<'tcx> { + fn past_depth_limit(&self) -> bool { + self.history.len() > HISTORY_DEPTH_LIMIT || self.top_down_counter > TOP_DOWN_DEPTH_LIMIT + } +} + impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { fn new(tcx: TyCtxt<'tcx>, def_id: DefId, body: &Body<'tcx>) -> Self { let typing_env = body.typing_env(tcx); @@ -295,6 +305,7 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { typing_env, def_id, history: Vec::new(), + top_down_counter: 0, changed: false, caller_is_inline_forwarder: matches!( codegen_fn_attrs.inline, @@ -327,6 +338,17 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { true } + fn check_codegen_attributes_extra( + &self, + callee_attrs: &CodegenFnAttrs, + ) -> Result<(), &'static str> { + if self.past_depth_limit() && matches!(callee_attrs.inline, InlineAttr::None) { + Err("Past depth limit so not inspecting unmarked callee") + } else { + Ok(()) + } + } + fn check_caller_mir_body(&self, body: &Body<'tcx>) -> bool { // Avoid inlining into coroutines, since their `optimized_mir` is used for layout computation, // which can create a cycle, even when no attempt is made to inline the function in the other @@ -351,7 +373,11 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { return Err("body has errors"); } - let mut threshold = if self.caller_is_inline_forwarder { + if self.past_depth_limit() && callee_body.basic_blocks.len() > 1 { + return Err("Not inlining multi-block body as we're past a depth limit"); + } + + let mut threshold = if self.caller_is_inline_forwarder || self.past_depth_limit() { tcx.sess.opts.unstable_opts.inline_mir_forwarder_threshold.unwrap_or(30) } else if tcx.cross_crate_inlinable(callsite.callee.def_id()) { tcx.sess.opts.unstable_opts.inline_mir_hint_threshold.unwrap_or(100) @@ -431,14 +457,6 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { } } - fn inline_limit_for_block(&self) -> Option { - match self.history.len() { - 0 => Some(usize::MAX), - 1..=TOP_DOWN_DEPTH_LIMIT => Some(1), - _ => None, - } - } - fn on_inline_success( &mut self, callsite: &CallSite<'tcx>, @@ -447,13 +465,21 @@ impl<'tcx> Inliner<'tcx> for NormalInliner<'tcx> { ) { self.changed = true; + let new_calls_count = new_blocks + .clone() + .filter(|&bb| is_call_like(caller_body.basic_blocks[bb].terminator())) + .count(); + if new_calls_count > 1 { + self.top_down_counter += 1; + } + self.history.push(callsite.callee.def_id()); process_blocks(self, caller_body, new_blocks); self.history.pop(); - } - fn on_inline_limit_reached(&self) -> bool { - true + if self.history.is_empty() { + self.top_down_counter = 0; + } } fn on_inline_failure(&self, _: &CallSite<'tcx>, _: &'static str) {} @@ -482,8 +508,6 @@ fn process_blocks<'tcx, I: Inliner<'tcx>>( caller_body: &mut Body<'tcx>, blocks: Range, ) { - let Some(inline_limit) = inliner.inline_limit_for_block() else { return }; - let mut inlined_count = 0; for bb in blocks { let bb_data = &caller_body[bb]; if bb_data.is_cleanup { @@ -505,13 +529,6 @@ fn process_blocks<'tcx, I: Inliner<'tcx>>( Ok(new_blocks) => { debug!("inlined {}", callsite.callee); inliner.on_inline_success(&callsite, caller_body, new_blocks); - - inlined_count += 1; - if inlined_count == inline_limit { - if inliner.on_inline_limit_reached() { - return; - } - } } } } @@ -584,6 +601,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id()); check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; check_codegen_attributes(inliner, callsite, callee_attrs)?; + inliner.check_codegen_attributes_extra(callee_attrs)?; let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; @@ -606,14 +624,14 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( ty::EarlyBinder::bind(callee_body.clone()), ) else { debug!("failed to normalize callee body"); - return Err("implementation limitation"); + return Err("implementation limitation -- could not normalize callee body"); }; // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. if !validate_types(tcx, inliner.typing_env(), &callee_body, &caller_body).is_empty() { debug!("failed to validate callee body"); - return Err("implementation limitation"); + return Err("implementation limitation -- callee body failed validation"); } // Check call signature compatibility. @@ -622,17 +640,9 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( let output_type = callee_body.return_ty(); if !util::sub_types(tcx, inliner.typing_env(), output_type, destination_ty) { trace!(?output_type, ?destination_ty); - debug!("failed to normalize return type"); - return Err("implementation limitation"); + return Err("implementation limitation -- return type mismatch"); } if callsite.fn_sig.abi() == ExternAbi::RustCall { - // FIXME: Don't inline user-written `extern "rust-call"` functions, - // since this is generally perf-negative on rustc, and we hope that - // LLVM will inline these functions instead. - if callee_body.spread_arg.is_some() { - return Err("user-written rust-call functions"); - } - let (self_arg, arg_tuple) = match &args[..] { [arg_tuple] => (None, arg_tuple), [self_arg, arg_tuple] => (Some(self_arg), arg_tuple), @@ -642,12 +652,17 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( let self_arg_ty = self_arg.map(|self_arg| self_arg.node.ty(&caller_body.local_decls, tcx)); let arg_tuple_ty = arg_tuple.node.ty(&caller_body.local_decls, tcx); - let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else { - bug!("Closure arguments are not passed as a tuple"); + let arg_tys = if callee_body.spread_arg.is_some() { + std::slice::from_ref(&arg_tuple_ty) + } else { + let ty::Tuple(arg_tuple_tys) = *arg_tuple_ty.kind() else { + bug!("Closure arguments are not passed as a tuple"); + }; + arg_tuple_tys.as_slice() }; for (arg_ty, input) in - self_arg_ty.into_iter().chain(arg_tuple_tys).zip(callee_body.args_iter()) + self_arg_ty.into_iter().chain(arg_tys.iter().copied()).zip(callee_body.args_iter()) { let input_type = callee_body.local_decls[input].ty; if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) { @@ -663,7 +678,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( if !util::sub_types(tcx, inliner.typing_env(), input_type, arg_ty) { trace!(?arg_ty, ?input_type); debug!("failed to normalize argument type"); - return Err("implementation limitation"); + return Err("implementation limitation -- arg mismatch"); } } } @@ -693,13 +708,13 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( // won't cause cycles on this. if !inliner.tcx().is_mir_available(callee_def_id) { debug!("item MIR unavailable"); - return Err("implementation limitation"); + return Err("implementation limitation -- MIR unavailable"); } } // These have no own callable MIR. InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { debug!("instance without MIR (intrinsic / virtual)"); - return Err("implementation limitation"); + return Err("implementation limitation -- cannot inline intrinsic"); } // FIXME(#127030): `ConstParamHasTy` has bad interactions with @@ -709,7 +724,7 @@ fn check_mir_is_available<'tcx, I: Inliner<'tcx>>( // substituted. InstanceKind::DropGlue(_, Some(ty)) if ty.has_type_flags(TypeFlags::HAS_CT_PARAM) => { debug!("still needs substitution"); - return Err("implementation limitation"); + return Err("implementation limitation -- HACK for dropping polymorphic type"); } // This cannot result in an immediate cycle since the callee MIR is a shim, which does @@ -773,6 +788,8 @@ fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>( return Err("has DoNotOptimize attribute"); } + inliner.check_codegen_attributes_extra(callee_attrs)?; + // Reachability pass defines which functions are eligible for inlining. Generally inlining // other functions is incorrect because they could reference symbols that aren't exported. let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); @@ -1060,8 +1077,7 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>( closure_ref_arg.chain(tuple_tmp_args).collect() } else { - // FIXME(edition_2024): switch back to a normal method call. - <_>::into_iter(args) + args.into_iter() .map(|a| create_temp_if_necessary(inliner, a.node, callsite, caller_body, return_block)) .collect() } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 17084eca6e388..0a72a9d669fe6 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -172,11 +172,11 @@ impl HasBottom for ConditionSet<'_> { } impl<'a> ConditionSet<'a> { - fn iter(self) -> impl Iterator + 'a { + fn iter(self) -> impl Iterator { self.0.iter().copied() } - fn iter_matches(self, value: ScalarInt) -> impl Iterator + 'a { + fn iter_matches(self, value: ScalarInt) -> impl Iterator { self.iter().filter(move |c| c.matches(value)) } @@ -467,7 +467,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { state.insert_place_idx(rhs, lhs, &self.map); } // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. - Rvalue::Aggregate(box ref kind, ref operands) => { + Rvalue::Aggregate(box kind, operands) => { let agg_ty = lhs_place.ty(self.body, self.tcx).ty; let lhs = match kind { // Do not support unions. diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 59de6ca84a71b..f8db8de4e82c9 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -509,7 +509,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // other overflow checks. AssertKind::Overflow(*bin_op, eval_to_int(op1), eval_to_int(op2)) } - AssertKind::BoundsCheck { ref len, ref index } => { + AssertKind::BoundsCheck { len, index } => { let len = eval_to_int(len); let index = eval_to_int(index); AssertKind::BoundsCheck { len, index } @@ -782,10 +782,10 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { self.super_terminator(terminator, location); match &terminator.kind { - TerminatorKind::Assert { expected, ref msg, ref cond, .. } => { + TerminatorKind::Assert { expected, msg, cond, .. } => { self.check_assertion(*expected, msg, cond, location); } - TerminatorKind::SwitchInt { ref discr, ref targets } => { + TerminatorKind::SwitchInt { discr, targets } => { if let Some(ref value) = self.eval_operand(discr) && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) && let Some(constant) = value_const.to_bits(value_const.size()).discard_err() diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 04c9375b83176..205d388f4fb50 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -1,4 +1,5 @@ // tidy-alphabetical-start +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -12,7 +13,6 @@ #![feature(never_type)] #![feature(try_blocks)] #![feature(yeet_expr)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use hir::ConstContext; @@ -316,6 +316,10 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet { // All body-owners have MIR associated with them. let mut set: FxIndexSet<_> = tcx.hir_body_owners().collect(); + // Remove the fake bodies for `global_asm!`, since they're not useful + // to be emitted (`--emit=mir`) or encoded (in metadata). + set.retain(|&def_id| !matches!(tcx.def_kind(def_id), DefKind::GlobalAsm)); + // Coroutine-closures (e.g. async closures) have an additional by-move MIR // body that isn't in the HIR. for body_owner in tcx.hir_body_owners() { @@ -513,6 +517,24 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & body.tainted_by_errors = Some(error_reported); } + // Also taint the body if it's within a top-level item that is not well formed. + // + // We do this check here and not during `mir_promoted` because that may result + // in borrowck cycles if WF requires looking into an opaque hidden type. + let root = tcx.typeck_root_def_id(def.to_def_id()); + match tcx.def_kind(root) { + DefKind::Fn + | DefKind::AssocFn + | DefKind::Static { .. } + | DefKind::Const + | DefKind::AssocConst => { + if let Err(guar) = tcx.check_well_formed(root.expect_local()) { + body.tainted_by_errors = Some(guar); + } + } + _ => {} + } + run_analysis_to_runtime_passes(tcx, &mut body); tcx.alloc_steal_mir(body) diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 50d10883d2cad..29a9133abe93d 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -2,11 +2,11 @@ use std::cell::RefCell; use std::collections::hash_map; use std::rc::Rc; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Subdiagnostic; use rustc_hir::CRATE_HIR_ID; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; @@ -15,16 +15,17 @@ use rustc_middle::mir::{ self, BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind, dump_mir, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::significant_drop_order::{ + extract_component_with_significant_dtor, ty_dtor_span, +}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex}; use rustc_mir_dataflow::{Analysis, MaybeReachable, ResultsCursor}; use rustc_session::lint::builtin::TAIL_EXPR_DROP_ORDER; use rustc_session::lint::{self}; use rustc_span::{DUMMY_SP, Span, Symbol}; -use rustc_type_ir::data_structures::IndexMap; -use smallvec::{SmallVec, smallvec}; -use tracing::{debug, instrument}; +use tracing::debug; fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool { left.local == right.local @@ -155,170 +156,6 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { } } -/// An additional filter to exclude well-known types from the ecosystem -/// because their drops are trivial. -/// This returns additional types to check if the drops are delegated to those. -/// A typical example is `hashbrown::HashMap`, whose drop is delegated to `K` and `V`. -fn true_significant_drop_ty<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Option; 2]>> { - if let ty::Adt(def, args) = ty.kind() { - let mut did = def.did(); - let mut name_rev = vec![]; - loop { - let key = tcx.def_key(did); - - match key.disambiguated_data.data { - rustc_hir::definitions::DefPathData::CrateRoot => { - name_rev.push(tcx.crate_name(did.krate)) - } - rustc_hir::definitions::DefPathData::TypeNs(symbol) => name_rev.push(symbol), - _ => return None, - } - if let Some(parent) = key.parent { - did = DefId { krate: did.krate, index: parent }; - } else { - break; - } - } - let name_str: Vec<_> = name_rev.iter().rev().map(|x| x.as_str()).collect(); - debug!(?name_str); - match name_str[..] { - // These are the types from Rust core ecosystem - ["sym" | "proc_macro2", ..] - | ["core" | "std", "task", "LocalWaker" | "Waker"] - | ["core" | "std", "task", "wake", "LocalWaker" | "Waker"] => Some(smallvec![]), - // These are important types from Rust ecosystem - ["tracing", "instrument", "Instrumented"] | ["bytes", "Bytes"] => Some(smallvec![]), - ["hashbrown", "raw", "RawTable" | "RawIntoIter"] => { - if let [ty, ..] = &***args - && let Some(ty) = ty.as_type() - { - Some(smallvec![ty]) - } else { - None - } - } - ["hashbrown", "raw", "RawDrain"] => { - if let [_, ty, ..] = &***args - && let Some(ty) = ty.as_type() - { - Some(smallvec![ty]) - } else { - None - } - } - _ => None, - } - } else { - None - } -} - -/// Returns the list of types with a "potentially sigificant" that may be dropped -/// by dropping a value of type `ty`. -#[instrument(level = "debug", skip(tcx, typing_env))] -fn extract_component_raw<'tcx>( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ty: Ty<'tcx>, - ty_seen: &mut UnordSet>, -) -> SmallVec<[Ty<'tcx>; 4]> { - // Droppiness does not depend on regions, so let us erase them. - let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty); - - let tys = tcx.list_significant_drop_tys(typing_env.as_query_input(ty)); - debug!(?ty, "components"); - let mut out_tys = smallvec![]; - for ty in tys { - if let Some(tys) = true_significant_drop_ty(tcx, ty) { - // Some types can be further opened up because the drop is simply delegated - for ty in tys { - if ty_seen.insert(ty) { - out_tys.extend(extract_component_raw(tcx, typing_env, ty, ty_seen)); - } - } - } else { - if ty_seen.insert(ty) { - out_tys.push(ty); - } - } - } - out_tys -} - -#[instrument(level = "debug", skip(tcx, typing_env))] -fn extract_component_with_significant_dtor<'tcx>( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ty: Ty<'tcx>, -) -> SmallVec<[Ty<'tcx>; 4]> { - let mut tys = extract_component_raw(tcx, typing_env, ty, &mut Default::default()); - let mut deduplicate = FxHashSet::default(); - tys.retain(|oty| deduplicate.insert(*oty)); - tys.into_iter().collect() -} - -/// Extract the span of the custom destructor of a type -/// especially the span of the `impl Drop` header or its entire block -/// when we are working with current local crate. -#[instrument(level = "debug", skip(tcx))] -fn ty_dtor_span<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option { - match ty.kind() { - ty::Bool - | ty::Char - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Error(_) - | ty::Str - | ty::Never - | ty::RawPtr(_, _) - | ty::Ref(_, _, _) - | ty::FnPtr(_, _) - | ty::Tuple(_) - | ty::Dynamic(_, _, _) - | ty::Alias(_, _) - | ty::Bound(_, _) - | ty::Pat(_, _) - | ty::Placeholder(_) - | ty::Infer(_) - | ty::Slice(_) - | ty::Array(_, _) - | ty::UnsafeBinder(_) => None, - - ty::Adt(adt_def, _) => { - let did = adt_def.did(); - let try_local_did_span = |did: DefId| { - if let Some(local) = did.as_local() { - tcx.source_span(local) - } else { - tcx.def_span(did) - } - }; - let dtor = if let Some(dtor) = tcx.adt_destructor(did) { - dtor.did - } else if let Some(dtor) = tcx.adt_async_destructor(did) { - dtor.future - } else { - return Some(try_local_did_span(did)); - }; - let def_key = tcx.def_key(dtor); - let Some(parent_index) = def_key.parent else { return Some(try_local_did_span(dtor)) }; - let parent_did = DefId { index: parent_index, krate: dtor.krate }; - Some(try_local_did_span(parent_did)) - } - ty::Coroutine(did, _) - | ty::CoroutineWitness(did, _) - | ty::CoroutineClosure(did, _) - | ty::Closure(did, _) - | ty::FnDef(did, _) - | ty::Foreign(did) => Some(tcx.def_span(did)), - ty::Param(_) => None, - } -} - /// Check if a moved place at `idx` is a part of a BID. /// The use of this check is that we will consider drops on these /// as a drop of the overall BID and, thus, we can exclude it from the diagnosis. @@ -361,7 +198,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< // and, for each block, the vector of locations. // // We group them per-block because they tend to scheduled in the same drop ladder block. - let mut bid_per_block = IndexMap::default(); + let mut bid_per_block = FxIndexMap::default(); let mut bid_places = UnordSet::new(); let mut ty_dropped_components = UnordMap::default(); @@ -617,8 +454,8 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< } /// Extract binding names if available for diagnosis -fn collect_user_names(body: &Body<'_>) -> IndexMap { - let mut names = IndexMap::default(); +fn collect_user_names(body: &Body<'_>) -> FxIndexMap { + let mut names = FxIndexMap::default(); for var_debug_info in &body.var_debug_info { if let mir::VarDebugInfoContents::Place(place) = &var_debug_info.value && let Some(local) = place.local_or_deref_local() @@ -632,9 +469,9 @@ fn collect_user_names(body: &Body<'_>) -> IndexMap { /// Assign names for anonymous or temporary values for diagnosis fn assign_observables_names( locals: impl IntoIterator, - user_names: &IndexMap, -) -> IndexMap { - let mut names = IndexMap::default(); + user_names: &FxIndexMap, +) -> FxIndexMap { + let mut names = FxIndexMap::default(); let mut assigned_names = FxHashSet::default(); let mut idx = 0u64; let mut fresh_name = || { diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 9db37bf5a0721..0d9d0368d3729 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -5,7 +5,6 @@ use rustc_index::IndexSlice; use rustc_middle::mir::*; use rustc_middle::ty::layout::{IntegerExt, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; -use rustc_type_ir::TyKind::*; use tracing::instrument; use super::simplify::simplify_cfg; @@ -293,13 +292,13 @@ fn can_cast( ) -> bool { let from_scalar = ScalarInt::try_from_uint(src_val.into(), src_layout.size).unwrap(); let v = match src_layout.ty.kind() { - Uint(_) => from_scalar.to_uint(src_layout.size), - Int(_) => from_scalar.to_int(src_layout.size) as u128, + ty::Uint(_) => from_scalar.to_uint(src_layout.size), + ty::Int(_) => from_scalar.to_int(src_layout.size) as u128, _ => unreachable!("invalid int"), }; let size = match *cast_ty.kind() { - Int(t) => Integer::from_int_ty(&tcx, t).size(), - Uint(t) => Integer::from_uint_ty(&tcx, t).size(), + ty::Int(t) => Integer::from_int_ty(&tcx, t).size(), + ty::Uint(t) => Integer::from_uint_ty(&tcx, t).size(), _ => unreachable!("invalid int"), }; let v = size.truncate(v); diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs index f5c57418467a1..9fd8d81d64a26 100644 --- a/compiler/rustc_mir_transform/src/mentioned_items.rs +++ b/compiler/rustc_mir_transform/src/mentioned_items.rs @@ -51,7 +51,7 @@ impl<'tcx> Visitor<'tcx> for MentionedItemsVisitor<'_, 'tcx> { let ty = place.ty(self.body, self.tcx).ty; self.mentioned_items.push(Spanned { node: MentionedItem::Drop(ty), span: span() }); } - mir::TerminatorKind::InlineAsm { ref operands, .. } => { + mir::TerminatorKind::InlineAsm { operands, .. } => { for op in operands { match *op { mir::InlineAsmOperand::SymFn { ref value } => { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 67070f03dedbd..84905f4a400f3 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -568,9 +568,9 @@ fn remove_unused_definitions_helper(used_locals: &mut UsedLocals, body: &mut Bod } StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local), - StatementKind::SetDiscriminant { ref place, .. } - | StatementKind::BackwardIncompatibleDropHint { ref place, reason: _ } - | StatementKind::Deinit(ref place) => used_locals.is_used(place.local), + StatementKind::SetDiscriminant { place, .. } + | StatementKind::BackwardIncompatibleDropHint { place, reason: _ } + | StatementKind::Deinit(place) => used_locals.is_used(place.local), StatementKind::Nop => false, _ => true, }; diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index 12c3503879fb9..886f4d6e50900 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -24,7 +24,7 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition { // Simplify `assume` of a known value: either a NOP or unreachable. if let StatementKind::Intrinsic(box ref intrinsic) = stmt.kind && let NonDivergingIntrinsic::Assume(discr) = intrinsic - && let Operand::Constant(ref c) = discr + && let Operand::Constant(c) = discr && let Some(constant) = c.const_.try_eval_bool(tcx, typing_env) { if constant { diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs index 21bc51ecca14e..bd00823073139 100644 --- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs +++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs @@ -89,10 +89,10 @@ impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral { use Operand::*; match rhs { - Rvalue::BinaryOp(_, box (ref mut left @ Move(_), Constant(_))) => { + Rvalue::BinaryOp(_, box (left @ Move(_), Constant(_))) => { *left = Copy(opt.to_switch_on); } - Rvalue::BinaryOp(_, box (Constant(_), ref mut right @ Move(_))) => { + Rvalue::BinaryOp(_, box (Constant(_), right @ Move(_))) => { *right = Copy(opt.to_switch_on); } _ => (), diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 28de99f9193d9..7c6ccc89c4f30 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -185,7 +185,7 @@ impl<'tcx> ReplacementMap<'tcx> { fn place_fragments( &self, place: Place<'tcx>, - ) -> Option, Local)> + '_> { + ) -> Option, Local)>> { let local = place.as_local()?; let fields = self.fragments[local].as_ref()?; Some(fields.iter_enumerated().filter_map(|(field, &opt_ty_local)| { diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index 9f769077e77e2..3d512fb064ec4 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -138,7 +138,7 @@ impl SsaLocals { pub(super) fn assignments<'a, 'tcx>( &'a self, body: &'a Body<'tcx>, - ) -> impl Iterator, Location)> + 'a { + ) -> impl Iterator, Location)> { self.assignment_order.iter().filter_map(|&local| { if let Set1::One(DefLocation::Assignment(loc)) = self.assignments[local] { let stmt = body.stmt_at(loc).left()?; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 4ac3a268c9c33..231d7c2ef0225 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -13,11 +13,10 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ - self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Variance, + self, CoroutineArgsExt, InstanceKind, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Upcast, Variance, }; use rustc_middle::{bug, span_bug}; use rustc_trait_selection::traits::ObligationCtxt; -use rustc_type_ir::Upcast; use crate::util::{self, is_within_packed}; diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml index 5462105e5e8e4..36b76d261de68 100644 --- a/compiler/rustc_monomorphize/Cargo.toml +++ b/compiler/rustc_monomorphize/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_monomorphize" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl index 463c42b69b1af..bdeab12ab503b 100644 --- a/compiler/rustc_monomorphize/messages.ftl +++ b/compiler/rustc_monomorphize/messages.ftl @@ -1,18 +1,40 @@ -monomorphize_abi_error_disabled_vector_type_call = - this function call uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled in the caller - .label = function called here - .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) -monomorphize_abi_error_disabled_vector_type_def = - this function definition uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled - .label = function defined here +monomorphize_abi_error_disabled_vector_type = + this function {$is_call -> + [true] call + *[false] definition + } uses SIMD vector type `{$ty}` which (with the chosen ABI) requires the `{$required_feature}` target feature, which is not enabled{$is_call -> + [true] {" "}in the caller + *[false] {""} + } + .label = function {$is_call -> + [true] called + *[false] defined + } here .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) -monomorphize_abi_error_unsupported_vector_type_call = - this function call uses SIMD vector type `{$ty}` which is not currently supported with the chosen ABI - .label = function called here -monomorphize_abi_error_unsupported_vector_type_def = - this function definition uses SIMD vector type `{$ty}` which is not currently supported with the chosen ABI - .label = function defined here +monomorphize_abi_error_unsupported_vector_type = + this function {$is_call -> + [true] call + *[false] definition + } uses SIMD vector type `{$ty}` which is not currently supported with the chosen ABI + .label = function {$is_call -> + [true] called + *[false] defined + } here + +monomorphize_abi_required_target_feature = + this function {$is_call -> + [true] call + *[false] definition + } uses ABI "{$abi}" which requires the `{$required_feature}` target feature, which is not enabled{$is_call -> + [true] {" "}in the caller + *[false] {""} + } + .label = function {$is_call -> + [true] called + *[false] defined + } here + .help = consider enabling it globally (`-C target-feature=+{$required_feature}`) or locally (`#[target_feature(enable="{$required_feature}")]`) monomorphize_couldnt_dump_mono_stats = unexpected error occurred while dumping monomorphization stats: {$error} diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 1195c25e13087..67fca1d7c2947 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -209,7 +209,7 @@ use std::path::PathBuf; use rustc_attr_parsing::InlineAttr; use rustc_data_structures::fx::FxIndexMap; -use rustc_data_structures::sync::{LRef, MTLock, par_for_each_in}; +use rustc_data_structures::sync::{MTLock, par_for_each_in}; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -323,7 +323,7 @@ impl<'tcx> MonoItems<'tcx> { self.items.entry(item.node).or_insert(item.span); } - fn items(&self) -> impl Iterator> + '_ { + fn items(&self) -> impl Iterator> { self.items.keys().cloned() } } @@ -357,7 +357,7 @@ impl<'tcx> Extend>> for MonoItems<'tcx> { fn collect_items_rec<'tcx>( tcx: TyCtxt<'tcx>, starting_item: Spanned>, - state: LRef<'_, SharedState<'tcx>>, + state: &SharedState<'tcx>, recursion_depths: &mut DefIdMap, recursion_limit: Limit, mode: CollectionMode, @@ -479,24 +479,23 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; let item = tcx.hir_item(item_id); - if let hir::ItemKind::GlobalAsm(asm) = item.kind { + if let hir::ItemKind::GlobalAsm { asm, .. } = item.kind { for (op, op_sp) in asm.operands { - match op { + match *op { hir::InlineAsmOperand::Const { .. } => { // Only constants which resolve to a plain integer // are supported. Therefore the value should not // depend on any other items. } - hir::InlineAsmOperand::SymFn { anon_const } => { - let fn_ty = - tcx.typeck_body(anon_const.body).node_type(anon_const.hir_id); + hir::InlineAsmOperand::SymFn { expr } => { + let fn_ty = tcx.typeck(item_id.owner_id).expr_ty(expr); visit_fn_use(tcx, fn_ty, false, *op_sp, &mut used_items); } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { - let instance = Instance::mono(tcx, *def_id); + let instance = Instance::mono(tcx, def_id); if tcx.should_codegen_locally(instance) { trace!("collecting static {:?}", def_id); - used_items.push(dummy_spanned(MonoItem::Static(*def_id))); + used_items.push(dummy_spanned(MonoItem::Static(def_id))); } } hir::InlineAsmOperand::In { .. } @@ -752,7 +751,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { /// This does not walk the MIR of the constant as that is not needed for codegen, all we need is /// to ensure that the constant evaluates successfully and walk the result. #[instrument(skip(self), level = "debug")] - fn visit_const_operand(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) { + fn visit_const_operand(&mut self, constant: &mir::ConstOperand<'tcx>, _location: Location) { // No `super_constant` as we don't care about `visit_ty`/`visit_ty_const`. let Some(val) = self.eval_constant(constant) else { return }; collect_const_value(self.tcx, val, self.used_items); @@ -1044,18 +1043,7 @@ fn find_vtable_types_for_unsizing<'tcx>( ) -> (Ty<'tcx>, Ty<'tcx>) { let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| { let typing_env = ty::TypingEnv::fully_monomorphized(); - let type_has_metadata = |ty: Ty<'tcx>| -> bool { - if ty.is_sized(tcx.tcx, typing_env) { - return false; - } - let tail = tcx.struct_tail_for_codegen(ty, typing_env); - match tail.kind() { - ty::Foreign(..) => false, - ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, - _ => bug!("unexpected unsized tail: {:?}", tail), - } - }; - if type_has_metadata(inner_source) { + if tcx.type_has_metadata(inner_source, typing_env) { (inner_source, inner_target) } else { tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env) @@ -1683,30 +1671,26 @@ pub(crate) fn collect_crate_mono_items<'tcx>( debug!("building mono item graph, beginning at roots"); - let mut state = SharedState { + let state = SharedState { visited: MTLock::new(UnordSet::default()), mentioned: MTLock::new(UnordSet::default()), usage_map: MTLock::new(UsageMap::new()), }; let recursion_limit = tcx.recursion_limit(); - { - let state: LRef<'_, _> = &mut state; - - tcx.sess.time("monomorphization_collector_graph_walk", || { - par_for_each_in(roots, |root| { - let mut recursion_depths = DefIdMap::default(); - collect_items_rec( - tcx, - dummy_spanned(root), - state, - &mut recursion_depths, - recursion_limit, - CollectionMode::UsedItems, - ); - }); + tcx.sess.time("monomorphization_collector_graph_walk", || { + par_for_each_in(roots, |root| { + let mut recursion_depths = DefIdMap::default(); + collect_items_rec( + tcx, + dummy_spanned(root), + &state, + &mut recursion_depths, + recursion_limit, + CollectionMode::UsedItems, + ); }); - } + }); // The set of MonoItems was created in an inherently indeterministic order because // of parallelism. We sort it here to ensure that the output is deterministic. diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs index 75687a80b82ae..8dafbbca905f7 100644 --- a/compiler/rustc_monomorphize/src/errors.rs +++ b/compiler/rustc_monomorphize/src/errors.rs @@ -70,37 +70,36 @@ pub(crate) struct UnknownCguCollectionMode<'a> { } #[derive(LintDiagnostic)] -#[diag(monomorphize_abi_error_disabled_vector_type_def)] +#[diag(monomorphize_abi_error_disabled_vector_type)] #[help] -pub(crate) struct AbiErrorDisabledVectorTypeDef<'a> { +pub(crate) struct AbiErrorDisabledVectorType<'a> { #[label] pub span: Span, pub required_feature: &'a str, pub ty: Ty<'a>, + /// Whether this is a problem at a call site or at a declaration. + pub is_call: bool, } #[derive(LintDiagnostic)] -#[diag(monomorphize_abi_error_disabled_vector_type_call)] -#[help] -pub(crate) struct AbiErrorDisabledVectorTypeCall<'a> { - #[label] - pub span: Span, - pub required_feature: &'a str, - pub ty: Ty<'a>, -} - -#[derive(LintDiagnostic)] -#[diag(monomorphize_abi_error_unsupported_vector_type_def)] -pub(crate) struct AbiErrorUnsupportedVectorTypeDef<'a> { +#[diag(monomorphize_abi_error_unsupported_vector_type)] +pub(crate) struct AbiErrorUnsupportedVectorType<'a> { #[label] pub span: Span, pub ty: Ty<'a>, + /// Whether this is a problem at a call site or at a declaration. + pub is_call: bool, } -#[derive(LintDiagnostic)] -#[diag(monomorphize_abi_error_unsupported_vector_type_call)] -pub(crate) struct AbiErrorUnsupportedVectorTypeCall<'a> { +#[derive(Diagnostic)] +#[diag(monomorphize_abi_required_target_feature)] +#[help] +pub(crate) struct AbiRequiredTargetFeature<'a> { + #[primary_span] #[label] pub span: Span, - pub ty: Ty<'a>, + pub required_feature: &'a str, + pub abi: &'a str, + /// Whether this is a problem at a call site or at a declaration. + pub is_call: bool, } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 714b64b3a231c..5dbae50c499f9 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -1,10 +1,10 @@ // tidy-alphabetical-start +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] #![feature(let_chains)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs index 8e93bdc61d04a..06d6c3ab8050e 100644 --- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs +++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs @@ -1,18 +1,15 @@ //! This module ensures that if a function's ABI requires a particular target feature, //! that target feature is enabled both on the callee and all callers. -use rustc_abi::{BackendRepr, ExternAbi, RegKind}; +use rustc_abi::{BackendRepr, RegKind}; use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::{self, traversal}; use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt}; use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES; use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, Span, Symbol}; -use rustc_target::callconv::{FnAbi, PassMode}; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; +use rustc_target::callconv::{Conv, FnAbi, PassMode}; -use crate::errors::{ - AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef, - AbiErrorUnsupportedVectorTypeCall, AbiErrorUnsupportedVectorTypeDef, -}; +use crate::errors; fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { match mode { @@ -21,22 +18,27 @@ fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool { cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector)) || cast.rest.unit.kind == RegKind::Vector } - PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::Vector { .. }), + PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }), } } /// Checks whether a certain function ABI is compatible with the target features currently enabled /// for a certain function. -/// If not, `emit_err` is called, with `Some(feature)` if a certain feature should be enabled and -/// with `None` if no feature is known that would make the ABI compatible. +/// `is_call` indicates whether this is a call-site check or a definition-site check; +/// this is only relevant for the wording in the emitted error. fn do_check_abi<'tcx>( tcx: TyCtxt<'tcx>, abi: &FnAbi<'tcx, Ty<'tcx>>, - target_feature_def: DefId, - mut emit_err: impl FnMut(Ty<'tcx>, Option<&'static str>), + def_id: DefId, + is_call: bool, + span: impl Fn() -> Span, ) { let feature_def = tcx.sess.target.features_for_correct_vector_abi(); - let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def); + let codegen_attrs = tcx.codegen_fn_attrs(def_id); + let have_feature = |feat: Symbol| { + tcx.sess.unstable_target_features.contains(&feat) + || codegen_attrs.target_features.iter().any(|x| x.name == feat) + }; for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { let size = arg_abi.layout.size; if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) { @@ -44,18 +46,46 @@ fn do_check_abi<'tcx>( let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { Some((_, feature)) => feature, None => { - emit_err(arg_abi.layout.ty, None); + let span = span(); + tcx.emit_node_span_lint( + ABI_UNSUPPORTED_VECTOR_TYPES, + CRATE_HIR_ID, + span, + errors::AbiErrorUnsupportedVectorType { + span, + ty: arg_abi.layout.ty, + is_call, + }, + ); continue; } }; - let feature_sym = Symbol::intern(feature); - if !tcx.sess.unstable_target_features.contains(&feature_sym) - && !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym) - { - emit_err(arg_abi.layout.ty, Some(&feature)); + if !have_feature(Symbol::intern(feature)) { + // Emit error. + let span = span(); + tcx.emit_node_span_lint( + ABI_UNSUPPORTED_VECTOR_TYPES, + CRATE_HIR_ID, + span, + errors::AbiErrorDisabledVectorType { + span, + required_feature: feature, + ty: arg_abi.layout.ty, + is_call, + }, + ); } } } + // The `vectorcall` ABI is special in that it requires SSE2 no matter which types are being passed. + if abi.conv == Conv::X86VectorCall && !have_feature(sym::sse2) { + tcx.dcx().emit_err(errors::AbiRequiredTargetFeature { + span: span(), + required_feature: "sse2", + abi: "vectorcall", + is_call, + }); + } } /// Checks that the ABI of a given instance of a function does not contain vector-passed arguments @@ -68,24 +98,13 @@ fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // function. return; }; - do_check_abi(tcx, abi, instance.def_id(), |ty, required_feature| { - let span = tcx.def_span(instance.def_id()); - if let Some(required_feature) = required_feature { - tcx.emit_node_span_lint( - ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, - span, - AbiErrorDisabledVectorTypeDef { span, required_feature, ty }, - ); - } else { - tcx.emit_node_span_lint( - ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, - span, - AbiErrorUnsupportedVectorTypeDef { span, ty }, - ); - } - }) + do_check_abi( + tcx, + abi, + instance.def_id(), + /*is_call*/ false, + || tcx.def_span(instance.def_id()), + ) } /// Checks that a call expression does not try to pass a vector-passed argument which requires a @@ -96,8 +115,8 @@ fn check_call_site_abi<'tcx>( span: Span, caller: InstanceKind<'tcx>, ) { - if callee.fn_sig(tcx).abi() == ExternAbi::Rust { - // "Rust" ABI never passes arguments in vector registers. + if callee.fn_sig(tcx).abi().is_rustic_abi() { + // we directly handle the soundness of Rust ABIs return; } let typing_env = ty::TypingEnv::fully_monomorphized(); @@ -122,23 +141,7 @@ fn check_call_site_abi<'tcx>( // ABI failed to compute; this will not get through codegen. return; }; - do_check_abi(tcx, callee_abi, caller.def_id(), |ty, required_feature| { - if let Some(required_feature) = required_feature { - tcx.emit_node_span_lint( - ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, - span, - AbiErrorDisabledVectorTypeCall { span, required_feature, ty }, - ); - } else { - tcx.emit_node_span_lint( - ABI_UNSUPPORTED_VECTOR_TYPES, - CRATE_HIR_ID, - span, - AbiErrorUnsupportedVectorTypeCall { span, ty }, - ); - } - }); + do_check_abi(tcx, callee_abi, caller.def_id(), /*is_call*/ true, || span); } fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index d826d03918e08..b1b6f10e0fe2c 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -1269,7 +1269,7 @@ fn dump_mono_items_stats<'tcx>( output_directory: &Option, crate_name: Symbol, ) -> Result<(), Box> { - let output_directory = if let Some(ref directory) = output_directory { + let output_directory = if let Some(directory) = output_directory { fs::create_dir_all(directory)?; directory } else { diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs index 0c855508434e0..ebe0b258c1b6a 100644 --- a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs +++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs @@ -12,21 +12,15 @@ fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec if !matches!(fn_ty.kind(), ty::FnDef(..)) { bug!("expected fn def for autodiff, got {:?}", fn_ty); } - let fnc_binder: ty::Binder<'_, ty::FnSig<'_>> = fn_ty.fn_sig(tcx); - // If rustc compiles the unmodified primal, we know that this copy of the function - // also has correct lifetimes. We know that Enzyme won't free the shadow too early - // (or actually at all), so let's strip lifetimes when computing the layout. - let x = tcx.instantiate_bound_regions_with_erased(fnc_binder); + // We don't actually pass the types back into the type system. + // All we do is decide how to handle the arguments. + let sig = fn_ty.fn_sig(tcx).skip_binder(); + let mut new_activities = vec![]; let mut new_positions = vec![]; - for (i, ty) in x.inputs().iter().enumerate() { + for (i, ty) in sig.inputs().iter().enumerate() { if let Some(inner_ty) = ty.builtin_deref(true) { - if ty.is_fn_ptr() { - // FIXME(ZuseZ4): add a nicer error, or just figure out how to support them, - // since Enzyme itself can handle them. - tcx.dcx().err("function pointers are currently not supported in autodiff"); - } if inner_ty.is_slice() { // We know that the length will be passed as extra arg. if !da.is_empty() { diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index eacb6002f5a41..63aa60f2f26b9 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_next_trait_solver" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 9cae7f27947b4..bbb4a162027dc 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -1,13 +1,11 @@ use std::cmp::Ordering; use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack}; -use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; -use rustc_type_ir::visit::TypeVisitableExt; use rustc_type_ir::{ self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike, - Interner, + Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use crate::delegate::SolverDelegate; diff --git a/compiler/rustc_next_trait_solver/src/coherence.rs b/compiler/rustc_next_trait_solver/src/coherence.rs index 408742747c2a1..5329020360053 100644 --- a/compiler/rustc_next_trait_solver/src/coherence.rs +++ b/compiler/rustc_next_trait_solver/src/coherence.rs @@ -3,8 +3,9 @@ use std::ops::ControlFlow; use derive_where::derive_where; use rustc_type_ir::inherent::*; -use rustc_type_ir::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; +use rustc_type_ir::{ + self as ty, InferCtxtLike, Interner, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; use tracing::instrument; /// Whether we do the orphan check relative to this crate or to some remote crate. diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index a64941cce3afd..259b39e2b9eed 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,8 +1,7 @@ use std::ops::Deref; -use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable}; pub trait SolverDelegate: Deref + Sized { type Infcx: InferCtxtLike; @@ -102,7 +101,6 @@ pub trait SolverDelegate: Deref + Sized { fn is_transmutable( &self, - param_env: ::ParamEnv, dst: ::Ty, src: ::Ty, assume: ::Const, diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index d67ae2550d967..f6963a790675f 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -6,7 +6,6 @@ // tidy-alphabetical-start #![allow(rustc::usage_of_type_ir_inherent)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod canonicalizer; diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 71c87714745ee..992c5ddf504ef 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,8 +1,9 @@ use rustc_type_ir::data_structures::DelayedMap; -use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; -use rustc_type_ir::visit::TypeVisitableExt; -use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; +use rustc_type_ir::{ + self as ty, InferCtxtLike, Interner, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, +}; use crate::delegate::SolverDelegate; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index bfb590e87679d..384a304c4a9d6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -3,11 +3,11 @@ pub(super) mod structural_traits; use derive_where::derive_where; -use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::visit::TypeVisitableExt as _; -use rustc_type_ir::{self as ty, Interner, TypingMode, Upcast as _, elaborate}; +use rustc_type_ir::{ + self as ty, Interner, TypeFoldable, TypeVisitableExt as _, TypingMode, Upcast as _, elaborate, +}; use tracing::{debug, instrument}; use super::trait_goals::TraitGoalProvenVia; diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index dc0f4c4483e6f..a5142de2d3905 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -3,10 +3,12 @@ use derive_where::derive_where; use rustc_type_ir::data_structures::HashMap; -use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; -use rustc_type_ir::{self as ty, Interner, Movability, Mutability, Upcast as _, elaborate}; +use rustc_type_ir::{ + self as ty, Interner, Movability, Mutability, TypeFoldable, TypeFolder, TypeSuperFoldable, + Upcast as _, elaborate, +}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::instrument; @@ -18,7 +20,7 @@ use crate::solve::{AdtDestructorKind, EvalCtxt, Goal, NoSolution}; pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( ecx: &EvalCtxt<'_, D>, ty: I::Ty, -) -> Result>, NoSolution> +) -> Result>, NoSolution> where D: SolverDelegate, I: Interner, @@ -33,10 +35,10 @@ where | ty::FnPtr(..) | ty::Error(_) | ty::Never - | ty::Char => Ok(vec![]), + | ty::Char => Ok(ty::Binder::dummy(vec![])), // Treat `str` like it's defined as `struct str([u8]);` - ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(cx, Ty::new_u8(cx)))]), + ty::Str => Ok(ty::Binder::dummy(vec![Ty::new_slice(cx, Ty::new_u8(cx))])), ty::Dynamic(..) | ty::Param(..) @@ -49,53 +51,49 @@ where } ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { - Ok(vec![ty::Binder::dummy(element_ty)]) + Ok(ty::Binder::dummy(vec![element_ty])) } ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => { - Ok(vec![ty::Binder::dummy(element_ty)]) + Ok(ty::Binder::dummy(vec![element_ty])) } ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().map(ty::Binder::dummy).collect()) + Ok(ty::Binder::dummy(tys.to_vec())) } - ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), + ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])), ty::CoroutineClosure(_, args) => { - Ok(vec![ty::Binder::dummy(args.as_coroutine_closure().tupled_upvars_ty())]) + Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()])) } ty::Coroutine(_, args) => { let coroutine_args = args.as_coroutine(); - Ok(vec![ - ty::Binder::dummy(coroutine_args.tupled_upvars_ty()), - ty::Binder::dummy(coroutine_args.witness()), - ]) + Ok(ty::Binder::dummy(vec![coroutine_args.tupled_upvars_ty(), coroutine_args.witness()])) } ty::CoroutineWitness(def_id, args) => Ok(ecx .cx() - .bound_coroutine_hidden_types(def_id) - .into_iter() - .map(|bty| bty.instantiate(cx, args)) - .collect()), + .coroutine_hidden_types(def_id) + .instantiate(cx, args) + .map_bound(|tys| tys.to_vec())), - ty::UnsafeBinder(bound_ty) => Ok(vec![bound_ty.into()]), + ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])), // For `PhantomData`, we pass `T`. - ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]), + ty::Adt(def, args) if def.is_phantom_data() => Ok(ty::Binder::dummy(vec![args.type_at(0)])), ty::Adt(def, args) => { - Ok(def.all_field_tys(cx).iter_instantiated(cx, args).map(ty::Binder::dummy).collect()) + Ok(ty::Binder::dummy(def.all_field_tys(cx).iter_instantiated(cx, args).collect())) } ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - Ok(vec![ty::Binder::dummy(cx.type_of(def_id).instantiate(cx, args))]) + Ok(ty::Binder::dummy(vec![cx.type_of(def_id).instantiate(cx, args)])) } } } @@ -104,7 +102,7 @@ where pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( ecx: &EvalCtxt<'_, D>, ty: I::Ty, -) -> Result>, NoSolution> +) -> Result>, NoSolution> where D: SolverDelegate, I: Interner, @@ -130,7 +128,7 @@ where | ty::CoroutineClosure(..) | ty::Never | ty::Dynamic(_, _, ty::DynStar) - | ty::Error(_) => Ok(vec![]), + | ty::Error(_) => Ok(ty::Binder::dummy(vec![])), ty::Str | ty::Slice(_) @@ -145,11 +143,11 @@ where panic!("unexpected type `{ty:?}`") } - ty::UnsafeBinder(bound_ty) => Ok(vec![bound_ty.into()]), + ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])), // impl Sized for () // impl Sized for (T1, T2, .., Tn) where Tn: Sized if n >= 1 - ty::Tuple(tys) => Ok(tys.last().map_or_else(Vec::new, |ty| vec![ty::Binder::dummy(ty)])), + ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.last().map_or_else(Vec::new, |ty| vec![ty]))), // impl Sized for Adt where sized_constraint(Adt): Sized // `sized_constraint(Adt)` is the deepest struct trail that can be determined @@ -162,9 +160,9 @@ where // if the ADT is sized for all possible args. ty::Adt(def, args) => { if let Some(sized_crit) = def.sized_constraint(ecx.cx()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.cx(), args))]) + Ok(ty::Binder::dummy(vec![sized_crit.instantiate(ecx.cx(), args)])) } else { - Ok(vec![]) + Ok(ty::Binder::dummy(vec![])) } } } @@ -174,14 +172,14 @@ where pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait( ecx: &EvalCtxt<'_, D>, ty: I::Ty, -) -> Result>, NoSolution> +) -> Result>, NoSolution> where D: SolverDelegate, I: Interner, { match ty.kind() { // impl Copy/Clone for FnDef, FnPtr - ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(vec![]), + ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Ok(ty::Binder::dummy(vec![])), // Implementations are provided in core ty::Uint(_) @@ -197,7 +195,7 @@ where // Cannot implement in core, as we can't be generic over patterns yet, // so we'd have to list all patterns and type combinations. - ty::Pat(ty, ..) => Ok(vec![ty::Binder::dummy(ty)]), + ty::Pat(ty, ..) => Ok(ty::Binder::dummy(vec![ty])), ty::Dynamic(..) | ty::Str @@ -215,14 +213,14 @@ where } // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone - ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), + ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.to_vec())), // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone - ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), + ty::Closure(_, args) => Ok(ty::Binder::dummy(vec![args.as_closure().tupled_upvars_ty()])), // impl Copy/Clone for CoroutineClosure where Self::TupledUpvars: Copy/Clone ty::CoroutineClosure(_, args) => { - Ok(vec![ty::Binder::dummy(args.as_coroutine_closure().tupled_upvars_ty())]) + Ok(ty::Binder::dummy(vec![args.as_coroutine_closure().tupled_upvars_ty()])) } // only when `coroutine_clone` is enabled and the coroutine is movable @@ -232,10 +230,7 @@ where Movability::Movable => { if ecx.cx().features().coroutine_clone() { let coroutine = args.as_coroutine(); - Ok(vec![ - ty::Binder::dummy(coroutine.tupled_upvars_ty()), - ty::Binder::dummy(coroutine.witness()), - ]) + Ok(ty::Binder::dummy(vec![coroutine.tupled_upvars_ty(), coroutine.witness()])) } else { Err(NoSolution) } @@ -247,10 +242,9 @@ where // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types ty::CoroutineWitness(def_id, args) => Ok(ecx .cx() - .bound_coroutine_hidden_types(def_id) - .into_iter() - .map(|bty| bty.instantiate(ecx.cx(), args)) - .collect()), + .coroutine_hidden_types(def_id) + .instantiate(ecx.cx(), args) + .map_bound(|tys| tys.to_vec())), } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index 2491f09a0e288..ac6b521f665b6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -12,16 +12,17 @@ use std::iter; use rustc_index::IndexVec; -use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::solver_relating::RelateExt; -use rustc_type_ir::{self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner}; +use rustc_type_ir::{ + self as ty, Canonical, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, +}; use tracing::{debug, instrument, trace}; use crate::canonicalizer::Canonicalizer; use crate::delegate::SolverDelegate; use crate::resolve::EagerResolver; -use crate::solve::eval_ctxt::NestedGoals; +use crate::solve::eval_ctxt::{CurrentGoalKind, NestedGoals}; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, EvalCtxt, ExternalConstraintsData, Goal, MaybeCause, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput, @@ -109,18 +110,22 @@ where // // As we return all ambiguous nested goals, we can ignore the certainty returned // by `try_evaluate_added_goals()`. - let (certainty, normalization_nested_goals) = if self.is_normalizes_to_goal { - let NestedGoals { normalizes_to_goals, goals } = std::mem::take(&mut self.nested_goals); - if cfg!(debug_assertions) { - assert!(normalizes_to_goals.is_empty()); - if goals.is_empty() { - assert!(matches!(goals_certainty, Certainty::Yes)); + let (certainty, normalization_nested_goals) = match self.current_goal_kind { + CurrentGoalKind::NormalizesTo => { + let NestedGoals { normalizes_to_goals, goals } = + std::mem::take(&mut self.nested_goals); + if cfg!(debug_assertions) { + assert!(normalizes_to_goals.is_empty()); + if goals.is_empty() { + assert!(matches!(goals_certainty, Certainty::Yes)); + } } + (certainty, NestedNormalizationGoals(goals)) + } + CurrentGoalKind::Misc | CurrentGoalKind::CoinductiveTrait => { + let certainty = certainty.unify_with(goals_certainty); + (certainty, NestedNormalizationGoals::empty()) } - (certainty, NestedNormalizationGoals(goals)) - } else { - let certainty = certainty.unify_with(goals_certainty); - (certainty, NestedNormalizationGoals::empty()) }; if let Certainty::Maybe(cause @ MaybeCause::Overflow { .. }) = certainty { @@ -163,19 +168,24 @@ where // ambiguous alias types which get replaced with fresh inference variables // during generalization. This prevents hangs caused by an exponential blowup, // see tests/ui/traits/next-solver/coherence-alias-hang.rs. - // - // We don't do so for `NormalizesTo` goals as we erased the expected term and - // bailing with overflow here would prevent us from detecting a type-mismatch, - // causing a coherence error in diesel, see #131969. We still bail with overflow - // when later returning from the parent AliasRelate goal. - if !self.is_normalizes_to_goal { - let num_non_region_vars = - canonical.variables.iter().filter(|c| !c.is_region() && c.is_existential()).count(); - if num_non_region_vars > self.cx().recursion_limit() { - debug!(?num_non_region_vars, "too many inference variables -> overflow"); - return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow { - suggest_increasing_limit: true, - })); + match self.current_goal_kind { + // We don't do so for `NormalizesTo` goals as we erased the expected term and + // bailing with overflow here would prevent us from detecting a type-mismatch, + // causing a coherence error in diesel, see #131969. We still bail with overflow + // when later returning from the parent AliasRelate goal. + CurrentGoalKind::NormalizesTo => {} + CurrentGoalKind::Misc | CurrentGoalKind::CoinductiveTrait => { + let num_non_region_vars = canonical + .variables + .iter() + .filter(|c| !c.is_region() && c.is_existential()) + .count(); + if num_non_region_vars > self.cx().recursion_limit() { + debug!(?num_non_region_vars, "too many inference variables -> overflow"); + return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow { + suggest_increasing_limit: true, + })); + } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index b0a34b9ce7560..0322c9e4ab011 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -2,15 +2,18 @@ use std::ops::ControlFlow; use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; use rustc_type_ir::fast_reject::DeepRejectCtxt; -use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; use rustc_type_ir::relate::solver_relating::RelateExt; -use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_type_ir::{self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypingMode}; +use rustc_type_ir::search_graph::PathKind; +use rustc_type_ir::{ + self as ty, CanonicalVarValues, InferCtxtLike, Interner, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, + TypingMode, +}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use tracing::{instrument, trace}; @@ -20,12 +23,51 @@ use crate::solve::inspect::{self, ProofTreeBuilder}; use crate::solve::search_graph::SearchGraph; use crate::solve::{ CanonicalInput, Certainty, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluationKind, GoalSource, - HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryResult, + HasChanged, NestedNormalizationGoals, NoSolution, PredefinedOpaquesData, QueryInput, + QueryResult, }; pub(super) mod canonical; mod probe; +/// The kind of goal we're currently proving. +/// +/// This has effects on cycle handling handling and on how we compute +/// query responses, see the variant descriptions for more info. +#[derive(Debug, Copy, Clone)] +enum CurrentGoalKind { + Misc, + /// We're proving an trait goal for a coinductive trait, either an auto trait or `Sized`. + /// + /// These are currently the only goals whose impl where-clauses are considered to be + /// productive steps. + CoinductiveTrait, + /// Unlike other goals, `NormalizesTo` goals act like functions with the expected term + /// always being fully unconstrained. This would weaken inference however, as the nested + /// goals never get the inference constraints from the actual normalized-to type. + /// + /// Because of this we return any ambiguous nested goals from `NormalizesTo` to the + /// caller when then adds these to its own context. The caller is always an `AliasRelate` + /// goal so this never leaks out of the solver. + NormalizesTo, +} + +impl CurrentGoalKind { + fn from_query_input(cx: I, input: QueryInput) -> CurrentGoalKind { + match input.goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { + if cx.trait_is_coinductive(pred.trait_ref.def_id) { + CurrentGoalKind::CoinductiveTrait + } else { + CurrentGoalKind::Misc + } + } + ty::PredicateKind::NormalizesTo(_) => CurrentGoalKind::NormalizesTo, + _ => CurrentGoalKind::Misc, + } + } +} + pub struct EvalCtxt<'a, D, I = ::Interner> where D: SolverDelegate, @@ -51,14 +93,10 @@ where /// The variable info for the `var_values`, only used to make an ambiguous response /// with no constraints. variables: I::CanonicalVars, - /// Whether we're currently computing a `NormalizesTo` goal. Unlike other goals, - /// `NormalizesTo` goals act like functions with the expected term always being - /// fully unconstrained. This would weaken inference however, as the nested goals - /// never get the inference constraints from the actual normalized-to type. Because - /// of this we return any ambiguous nested goals from `NormalizesTo` to the caller - /// when then adds these to its own context. The caller is always an `AliasRelate` - /// goal so this never leaks out of the solver. - is_normalizes_to_goal: bool, + + /// What kind of goal we're currently computing, see the enum definition + /// for more info. + current_goal_kind: CurrentGoalKind, pub(super) var_values: CanonicalVarValues, predefined_opaques_in_body: I::PredefinedOpaques, @@ -93,7 +131,10 @@ where #[derive_where(Clone, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] struct NestedGoals { /// These normalizes-to goals are treated specially during the evaluation /// loop. In each iteration we take the RHS of the projection, replace it with @@ -226,8 +267,49 @@ where self.delegate.typing_mode() } - pub(super) fn set_is_normalizes_to_goal(&mut self) { - self.is_normalizes_to_goal = true; + /// Computes the `PathKind` for the step from the current goal to the + /// nested goal required due to `source`. + /// + /// See #136824 for a more detailed reasoning for this behavior. We + /// consider cycles to be coinductive if they 'step into' a where-clause + /// of a coinductive trait. We will likely extend this function in the future + /// and will need to clearly document it in the rustc-dev-guide before + /// stabilization. + pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind { + match source { + // We treat these goals as unknown for now. It is likely that most miscellaneous + // nested goals will be converted to an inductive variant in the future. + // + // Having unknown cycles is always the safer option, as changing that to either + // succeed or hard error is backwards compatible. If we incorrectly treat a cycle + // as inductive even though it should not be, it may be unsound during coherence and + // fixing it may cause inference breakage or introduce ambiguity. + GoalSource::Misc => PathKind::Unknown, + GoalSource::NormalizeGoal(path_kind) => path_kind, + GoalSource::ImplWhereBound => { + // We currently only consider a cycle coinductive if it steps + // into a where-clause of a coinductive trait. + // + // We probably want to make all traits coinductive in the future, + // so we treat cycles involving their where-clauses as ambiguous. + if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind { + PathKind::Coinductive + } else { + PathKind::Unknown + } + } + // Relating types is always unproductive. If we were to map proof trees to + // corecursive functions as explained in #136824, relating types never + // introduces a constructor which could cause the recursion to be guarded. + GoalSource::TypeRelating => PathKind::Inductive, + // Instantiating a higher ranked goal can never cause the recursion to be + // guarded and is therefore unproductive. + GoalSource::InstantiateHigherRanked => PathKind::Inductive, + // These goal sources are likely unproductive and can be changed to + // `PathKind::Inductive`. Keeping them as unknown until we're confident + // about this and have an example where it is necessary. + GoalSource::AliasBoundConstCondition | GoalSource::AliasWellFormed => PathKind::Unknown, + } } /// Creates a root evaluation context and search graph. This should only be @@ -256,7 +338,7 @@ where max_input_universe: ty::UniverseIndex::ROOT, variables: Default::default(), var_values: CanonicalVarValues::dummy(), - is_normalizes_to_goal: false, + current_goal_kind: CurrentGoalKind::Misc, origin_span, tainted: Ok(()), }; @@ -294,7 +376,7 @@ where delegate, variables: canonical_input.canonical.variables, var_values, - is_normalizes_to_goal: false, + current_goal_kind: CurrentGoalKind::from_query_input(cx, input), predefined_opaques_in_body: input.predefined_opaques_in_body, max_input_universe: canonical_input.canonical.max_universe, search_graph, @@ -340,6 +422,7 @@ where cx: I, search_graph: &'a mut SearchGraph, canonical_input: CanonicalInput, + step_kind_from_parent: PathKind, goal_evaluation: &mut ProofTreeBuilder, ) -> QueryResult { let mut canonical_goal_evaluation = @@ -352,6 +435,7 @@ where search_graph.with_new_goal( cx, canonical_input, + step_kind_from_parent, &mut canonical_goal_evaluation, |search_graph, canonical_goal_evaluation| { EvalCtxt::enter_canonical( @@ -395,12 +479,10 @@ where /// `NormalizesTo` is only used by `AliasRelate`, all other callsites /// should use [`EvalCtxt::evaluate_goal`] which discards that empty /// storage. - // FIXME(-Znext-solver=coinduction): `_source` is currently unused but will - // be necessary once we implement the new coinduction approach. pub(super) fn evaluate_goal_raw( &mut self, goal_evaluation_kind: GoalEvaluationKind, - _source: GoalSource, + source: GoalSource, goal: Goal, ) -> Result<(NestedNormalizationGoals, HasChanged, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); @@ -410,6 +492,7 @@ where self.cx(), self.search_graph, canonical_goal, + self.step_kind_for_source(source), &mut goal_evaluation, ); let response = match canonical_response { @@ -555,7 +638,7 @@ where let (NestedNormalizationGoals(nested_goals), _, certainty) = self.evaluate_goal_raw( GoalEvaluationKind::Nested, - GoalSource::Misc, + GoalSource::TypeRelating, unconstrained_goal, )?; // Add the nested goals from normalization to our own nested goals. @@ -630,8 +713,11 @@ where #[instrument(level = "trace", skip(self))] pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal>) { - goal.predicate = - goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env)); + goal.predicate = goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new( + self, + GoalSource::TypeRelating, + goal.param_env, + )); self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); } @@ -639,7 +725,7 @@ where #[instrument(level = "debug", skip(self))] pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal) { goal.predicate = - goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env)); + goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, source, goal.param_env)); self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); self.nested_goals.goals.push((source, goal)); } @@ -885,7 +971,15 @@ where rhs: T, ) -> Result<(), NoSolution> { let goals = self.delegate.relate(param_env, lhs, variance, rhs, self.origin_span)?; - self.add_goals(GoalSource::Misc, goals); + if cfg!(debug_assertions) { + for g in goals.iter() { + match g.predicate.kind().skip_binder() { + ty::PredicateKind::Subtype { .. } | ty::PredicateKind::AliasRelate(..) => {} + p => unreachable!("unexpected nested goal in `relate`: {p:?}"), + } + } + } + self.add_goals(GoalSource::TypeRelating, goals); Ok(()) } @@ -913,7 +1007,7 @@ where /// `enter_forall`, but takes `&mut self` and passes it back through the /// callback since it can't be aliased during the call. - pub(super) fn enter_forall + Copy, U>( + pub(super) fn enter_forall, U>( &mut self, value: ty::Binder, f: impl FnOnce(&mut Self, T) -> U, @@ -1037,12 +1131,11 @@ where pub(super) fn is_transmutable( &mut self, - param_env: I::ParamEnv, dst: I::Ty, src: I::Ty, assume: I::Const, ) -> Result { - self.delegate.is_transmutable(param_env, dst, src, assume) + self.delegate.is_transmutable(dst, src, assume) } } @@ -1053,6 +1146,13 @@ where /// /// This is a performance optimization to more eagerly detect cycles during trait /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. +/// +/// The emitted goals get evaluated in the context of the parent goal; by +/// replacing aliases in nested goals we essentially pull the normalization out of +/// the nested goal. We want to treat the goal as if the normalization still happens +/// inside of the nested goal by inheriting the `step_kind` of the nested goal and +/// storing it in the `GoalSource` of the emitted `AliasRelate` goals. +/// This is necessary for tests/ui/sized/coinductive-1.rs to compile. struct ReplaceAliasWithInfer<'me, 'a, D, I> where D: SolverDelegate, @@ -1060,6 +1160,7 @@ where { ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv, + normalization_goal_source: GoalSource, cache: HashMap, } @@ -1068,8 +1169,18 @@ where D: SolverDelegate, I: Interner, { - fn new(ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv) -> Self { - ReplaceAliasWithInfer { ecx, param_env, cache: Default::default() } + fn new( + ecx: &'me mut EvalCtxt<'a, D>, + for_goal_source: GoalSource, + param_env: I::ParamEnv, + ) -> Self { + let step_kind = ecx.step_kind_for_source(for_goal_source); + ReplaceAliasWithInfer { + ecx, + param_env, + normalization_goal_source: GoalSource::NormalizeGoal(step_kind), + cache: Default::default(), + } } } @@ -1092,7 +1203,7 @@ where ty::AliasRelationDirection::Equate, ); self.ecx.add_goal( - GoalSource::Misc, + self.normalization_goal_source, Goal::new(self.cx(), self.param_env, normalizes_to), ); infer_ty @@ -1121,7 +1232,7 @@ where ty::AliasRelationDirection::Equate, ); self.ecx.add_goal( - GoalSource::Misc, + self.normalization_goal_source, Goal::new(self.cx(), self.param_env, normalizes_to), ); infer_ct diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs index add96a1fdf7a0..0a9e7fafaea62 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/probe.rs @@ -34,7 +34,7 @@ where delegate, variables: outer_ecx.variables, var_values: outer_ecx.var_values, - is_normalizes_to_goal: outer_ecx.is_normalizes_to_goal, + current_goal_kind: outer_ecx.current_goal_kind, predefined_opaques_in_body: outer_ecx.predefined_opaques_in_body, max_input_universe, search_graph: outer_ecx.search_graph, diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 1607fbb1b6a7b..6a8e0790f7cb4 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -421,7 +421,7 @@ impl, I: Interner> ProofTreeBuilder { self.add_goal( delegate, max_input_universe, - GoalSource::Misc, + GoalSource::TypeRelating, goal.with(delegate.cx(), goal.predicate), ); } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 1fa35b60304cf..199f0c7512e1b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -313,7 +313,9 @@ where ty::AliasRelationDirection::Equate, ), ); - self.add_goal(GoalSource::Misc, alias_relate_goal); + // We normalize the self type to be able to relate it with + // types from candidates. + self.add_goal(GoalSource::TypeRelating, alias_relate_goal); self.try_evaluate_added_goals()?; Ok(self.resolve_vars_if_possible(normalized_term)) } else { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 25e8708a3322c..1d1ff09ee4104 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -39,7 +39,7 @@ where // // FIXME(-Znext-solver=coinductive): I think this should be split // and we tag the impl bounds with `GoalSource::ImplWhereBound`? - // Right not this includes both the impl and the assoc item where bounds, + // Right now this includes both the impl and the assoc item where bounds, // and I don't think the assoc item where-bounds are allowed to be coinductive. self.add_goals( GoalSource::Misc, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index 88002e1a88a87..de6d21da0f592 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -28,7 +28,6 @@ where &mut self, goal: Goal>, ) -> QueryResult { - self.set_is_normalizes_to_goal(); debug_assert!(self.term_is_fully_unconstrained(goal)); let cx = self.cx(); match goal.predicate.alias.kind(cx) { diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index 60c20762a30ab..817dffa127bc1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -2,9 +2,8 @@ //! behaves differently depending on the current `TypingMode`. use rustc_index::bit_set::GrowableBitSet; -use rustc_type_ir::fold::fold_regions; use rustc_type_ir::inherent::*; -use rustc_type_ir::{self as ty, Interner, TypingMode}; +use rustc_type_ir::{self as ty, Interner, TypingMode, fold_regions}; use crate::delegate::SolverDelegate; use crate::solve::{Certainty, EvalCtxt, Goal, NoSolution, QueryResult, inspect}; diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs index d945288007174..944d5f0e042d7 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -24,7 +24,8 @@ where ty::AliasRelationDirection::Equate, ), ); - self.add_goal(GoalSource::Misc, goal); + // A projection goal holds if the alias is equal to the expected term. + self.add_goal(GoalSource::TypeRelating, goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index 843200ca184ea..eba496fa22659 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -1,10 +1,9 @@ use std::convert::Infallible; use std::marker::PhantomData; -use rustc_type_ir::Interner; -use rustc_type_ir::inherent::*; use rustc_type_ir::search_graph::{self, PathKind}; -use rustc_type_ir::solve::{CanonicalInput, Certainty, QueryResult}; +use rustc_type_ir::solve::{CanonicalInput, Certainty, NoSolution, QueryResult}; +use rustc_type_ir::{Interner, TypingMode}; use super::inspect::ProofTreeBuilder; use super::{FIXPOINT_STEP_LIMIT, has_no_inference_or_external_constraints}; @@ -48,7 +47,24 @@ where ) -> QueryResult { match kind { PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes), - PathKind::Inductive => response_no_constraints(cx, input, Certainty::overflow(false)), + PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)), + // Even though we know these cycles to be unproductive, we still return + // overflow during coherence. This is both as we are not 100% confident in + // the implementation yet and any incorrect errors would be unsound there. + // The affected cases are also fairly artificial and not necessarily desirable + // so keeping this as ambiguity is fine for now. + // + // See `tests/ui/traits/next-solver/cycles/unproductive-in-coherence.rs` for an + // example where this would matter. We likely should change these cycles to `NoSolution` + // even in coherence once this is a bit more settled. + PathKind::Inductive => match input.typing_mode { + TypingMode::Coherence => { + response_no_constraints(cx, input, Certainty::overflow(false)) + } + TypingMode::Analysis { .. } + | TypingMode::PostBorrowckAnalysis { .. } + | TypingMode::PostAnalysis => Err(NoSolution), + }, } } @@ -58,12 +74,7 @@ where input: CanonicalInput, result: QueryResult, ) -> bool { - match kind { - PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes) == result, - PathKind::Inductive => { - response_no_constraints(cx, input, Certainty::overflow(false)) == result - } - } + Self::initial_provisional_result(cx, kind, input) == result } fn on_stack_overflow( @@ -94,10 +105,6 @@ where let certainty = from_result.unwrap().value.certainty; response_no_constraints(cx, for_input, certainty) } - - fn step_is_coinductive(cx: I, input: CanonicalInput) -> bool { - input.canonical.value.goal.predicate.is_coinductive(cx) - } } fn response_no_constraints( diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 1665dbb30189e..b72f776e5cb48 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -5,9 +5,9 @@ use rustc_type_ir::fast_reject::DeepRejectCtxt; use rustc_type_ir::inherent::*; use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::CanonicalResponse; -use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{ - self as ty, Interner, Movability, TraitPredicate, TypingMode, Upcast as _, elaborate, + self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode, + Upcast as _, elaborate, }; use tracing::{instrument, trace}; @@ -617,7 +617,6 @@ where )?; let certainty = ecx.is_transmutable( - goal.param_env, goal.predicate.trait_ref.args.type_at(0), goal.predicate.trait_ref.args.type_at(1), assume, @@ -787,13 +786,6 @@ where ) } - // `(A, B, T)` -> `(A, B, U)` where `T: Unsize` - (ty::Tuple(a_tys), ty::Tuple(b_tys)) - if a_tys.len() == b_tys.len() && !a_tys.is_empty() => - { - result_to_single(ecx.consider_builtin_tuple_unsize(goal, a_tys, b_tys)) - } - _ => vec![], } }) @@ -1085,48 +1077,6 @@ where .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } - /// We generate the following builtin impl for tuples of all sizes. - /// - /// This impl is still unstable and we emit a feature error when it - /// when it is used by a coercion. - /// ```ignore (builtin impl example) - /// impl Unsize<(T, V)> for (T, U) - /// where - /// U: Unsize, - /// {} - /// ``` - fn consider_builtin_tuple_unsize( - &mut self, - goal: Goal, - a_tys: I::Tys, - b_tys: I::Tys, - ) -> Result, NoSolution> { - let cx = self.cx(); - let Goal { predicate: (_a_ty, b_ty), .. } = goal; - - let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); - let b_last_ty = b_tys.last().unwrap(); - - // Instantiate just the tail field of B., and require that they're equal. - let unsized_a_ty = Ty::new_tup_from_iter(cx, a_rest_tys.iter().copied().chain([b_last_ty])); - self.eq(goal.param_env, unsized_a_ty, b_ty)?; - - // Similar to ADTs, require that we can unsize the tail. - self.add_goal( - GoalSource::ImplWhereBound, - goal.with( - cx, - ty::TraitRef::new( - cx, - cx.require_lang_item(TraitSolverLangItem::Unsize), - [a_last_ty, b_last_ty], - ), - ), - ); - self.probe_builtin_trait_candidate(BuiltinImplSource::TupleUnsizing) - .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) - } - // Return `Some` if there is an impl (built-in or user provided) that may // hold for the self type of the goal, which for coherence and soundness // purposes must disqualify the built-in auto impl assembled by considering @@ -1239,17 +1189,15 @@ where constituent_tys: impl Fn( &EvalCtxt<'_, D>, I::Ty, - ) -> Result>, NoSolution>, + ) -> Result>, NoSolution>, ) -> Result, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { - let goals = constituent_tys(ecx, goal.predicate.self_ty())? - .into_iter() - .map(|ty| { - ecx.enter_forall(ty, |ecx, ty| { - goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)) - }) - }) - .collect::>(); + let goals = + ecx.enter_forall(constituent_tys(ecx, goal.predicate.self_ty())?, |ecx, tys| { + tys.into_iter() + .map(|ty| goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty))) + .collect::>() + }); ecx.add_goals(GoalSource::ImplWhereBound, goals); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 2360914a0aba1..c9dcab0c871dd 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_parse" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 563081c7240c4..6d4308cda1a60 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -26,6 +26,11 @@ parse_async_move_block_in_2015 = `async move` blocks are only allowed in Rust 20 parse_async_move_order_incorrect = the order of `move` and `async` is incorrect .suggestion = try switching the order +parse_async_use_block_in_2015 = `async use` blocks are only allowed in Rust 2018 or later + +parse_async_use_order_incorrect = the order of `use` and `async` is incorrect + .suggestion = try switching the order + parse_at_dot_dot_in_struct_pattern = `@ ..` is not supported in struct patterns .suggestion = bind to each field separately or, if you don't need them, just remove `{$ident} @` @@ -348,6 +353,9 @@ parse_incorrect_use_of_await = incorrect use of `await` parse_incorrect_use_of_await_postfix_suggestion = `await` is a postfix operation +parse_incorrect_use_of_use = incorrect use of `use` + .parentheses_suggestion = `use` is not a method call, try removing the parentheses + parse_incorrect_visibility_restriction = incorrect visibility restriction .help = some possible visibility restrictions are: `pub(crate)`: visible only on the current crate @@ -424,7 +432,7 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction -parse_invalid_meta_item = expected unsuffixed literal, found `{$token}` +parse_invalid_meta_item = expected unsuffixed literal, found {$descr} .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal parse_invalid_offset_of = offset_of expects dot-separated field and variant names diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index dc03d6f9521d4..e090d9cf7600e 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -106,6 +106,19 @@ pub(crate) struct IncorrectUseOfAwait { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_incorrect_use_of_use)] +pub(crate) struct IncorrectUseOfUse { + #[primary_span] + #[suggestion( + parse_parentheses_suggestion, + style = "verbose", + code = "", + applicability = "machine-applicable" + )] + pub span: Span, +} + #[derive(Subdiagnostic)] #[multipart_suggestion( parse_incorrect_use_of_await_postfix_suggestion, @@ -772,7 +785,6 @@ pub(crate) struct LabeledLoopInBreak { } #[derive(Subdiagnostic)] - pub(crate) enum WrapInParentheses { #[multipart_suggestion( parse_sugg_wrap_expression_in_parentheses, @@ -1025,7 +1037,7 @@ pub(crate) struct SuffixedLiteralInAttribute { pub(crate) struct InvalidMetaItem { #[primary_span] pub span: Span, - pub token: Token, + pub descr: String, #[subdiagnostic] pub quote_ident_sugg: Option, } @@ -1500,6 +1512,14 @@ pub(crate) struct AsyncMoveOrderIncorrect { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_use_order_incorrect)] +pub(crate) struct AsyncUseOrderIncorrect { + #[primary_span] + #[suggestion(style = "verbose", code = "async use", applicability = "maybe-incorrect")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_double_colon_in_bound)] pub(crate) struct DoubleColonInBound { @@ -1668,6 +1688,13 @@ pub(crate) struct AsyncMoveBlockIn2015 { pub span: Span, } +#[derive(Diagnostic)] +#[diag(parse_async_use_block_in_2015)] +pub(crate) struct AsyncUseBlockIn2015 { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_async_bound_modifier_in_2015)] pub(crate) struct AsyncBoundModifierIn2015 { @@ -2923,8 +2950,9 @@ pub(crate) struct AddBoxNew { #[diag(parse_bad_return_type_notation_output)] pub(crate) struct BadReturnTypeNotationOutput { #[primary_span] - #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] pub span: Span, + #[suggestion(code = "", applicability = "maybe-incorrect", style = "verbose")] + pub suggestion: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 792e2cc26ef1c..1d17290e1c706 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -384,17 +384,17 @@ impl<'psess, 'src> Lexer<'psess, 'src> { rustc_lexer::TokenKind::Colon => token::Colon, rustc_lexer::TokenKind::Dollar => token::Dollar, rustc_lexer::TokenKind::Eq => token::Eq, - rustc_lexer::TokenKind::Bang => token::Not, + rustc_lexer::TokenKind::Bang => token::Bang, rustc_lexer::TokenKind::Lt => token::Lt, rustc_lexer::TokenKind::Gt => token::Gt, - rustc_lexer::TokenKind::Minus => token::BinOp(token::Minus), - rustc_lexer::TokenKind::And => token::BinOp(token::And), - rustc_lexer::TokenKind::Or => token::BinOp(token::Or), - rustc_lexer::TokenKind::Plus => token::BinOp(token::Plus), - rustc_lexer::TokenKind::Star => token::BinOp(token::Star), - rustc_lexer::TokenKind::Slash => token::BinOp(token::Slash), - rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret), - rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), + rustc_lexer::TokenKind::Minus => token::Minus, + rustc_lexer::TokenKind::And => token::And, + rustc_lexer::TokenKind::Or => token::Or, + rustc_lexer::TokenKind::Plus => token::Plus, + rustc_lexer::TokenKind::Star => token::Star, + rustc_lexer::TokenKind::Slash => token::Slash, + rustc_lexer::TokenKind::Caret => token::Caret, + rustc_lexer::TokenKind::Percent => token::Percent, rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => { // Don't emit diagnostics for sequences of the same invalid token diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index 648a352efd9bd..ff03b42484b41 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -308,11 +308,11 @@ pub(super) static UNICODE_ARRAY: &[(char, &str, &str)] = &[ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ (" ", "Space", None), ("_", "Underscore", Some(token::Ident(kw::Underscore, token::IdentIsRaw::No))), - ("-", "Minus/Hyphen", Some(token::BinOp(token::Minus))), + ("-", "Minus/Hyphen", Some(token::Minus)), (",", "Comma", Some(token::Comma)), (";", "Semicolon", Some(token::Semi)), (":", "Colon", Some(token::Colon)), - ("!", "Exclamation Mark", Some(token::Not)), + ("!", "Exclamation Mark", Some(token::Bang)), ("?", "Question Mark", Some(token::Question)), (".", "Period", Some(token::Dot)), ("(", "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))), @@ -321,11 +321,11 @@ const ASCII_ARRAY: &[(&str, &str, Option)] = &[ ("]", "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))), ("{", "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))), ("}", "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))), - ("*", "Asterisk", Some(token::BinOp(token::Star))), - ("/", "Slash", Some(token::BinOp(token::Slash))), + ("*", "Asterisk", Some(token::Star)), + ("/", "Slash", Some(token::Slash)), ("\\", "Backslash", None), - ("&", "Ampersand", Some(token::BinOp(token::And))), - ("+", "Plus Sign", Some(token::BinOp(token::Plus))), + ("&", "Ampersand", Some(token::And)), + ("+", "Plus Sign", Some(token::Plus)), ("<", "Less-Than Sign", Some(token::Lt)), ("=", "Equals Sign", Some(token::Eq)), ("==", "Double Equals Sign", Some(token::EqEq)), diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 1a104ff5e3375..79939aab7fc2b 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -4,6 +4,7 @@ #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(array_windows)] #![feature(assert_matches)] #![feature(box_patterns)] @@ -12,7 +13,6 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(string_from_utf8_lossy_owned)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 2691e6f56d68b..53614049f087a 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -1,4 +1,6 @@ -use rustc_ast::{self as ast, Attribute, attr, token}; +use rustc_ast as ast; +use rustc_ast::token::{self, MetaVarKind}; +use rustc_ast::{Attribute, attr}; use rustc_errors::codes::*; use rustc_errors::{Diag, PResult}; use rustc_span::{BytePos, Span}; @@ -9,7 +11,7 @@ use super::{ AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, ParserRange, PathStyle, Trailing, UsePreAttrPos, }; -use crate::{errors, exp, fluent_generated as fluent, maybe_whole}; +use crate::{errors, exp, fluent_generated as fluent}; // Public for rustfmt usage #[derive(Debug)] @@ -125,12 +127,29 @@ impl<'a> Parser<'a> { let lo = self.token.span; // Attributes can't have attributes of their own [Editor's note: not with that attitude] self.collect_tokens_no_attrs(|this| { + let pound_hi = this.token.span.hi(); assert!(this.eat(exp!(Pound)), "parse_attribute called in non-attribute position"); + let not_lo = this.token.span.lo(); let style = - if this.eat(exp!(Not)) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer }; + if this.eat(exp!(Bang)) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer }; - this.expect(exp!(OpenBracket))?; + let mut bracket_res = this.expect(exp!(OpenBracket)); + // If `#!` is not followed by `[` + if let Err(err) = &mut bracket_res + && style == ast::AttrStyle::Inner + && pound_hi == not_lo + { + err.note( + "the token sequence `#!` here looks like the start of \ + a shebang interpreter directive but it is not", + ); + err.help( + "if you meant this to be a shebang interpreter directive, \ + move it to the very start of the file", + ); + } + bracket_res?; let item = this.parse_attr_item(ForceCollect::No)?; this.expect(exp!(CloseBracket))?; let attr_sp = lo.to(this.prev_token.span); @@ -269,7 +288,12 @@ impl<'a> Parser<'a> { /// PATH `=` UNSUFFIXED_LIT /// The delimiters or `=` are still put into the resulting token stream. pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> { - maybe_whole!(self, NtMeta, |attr| attr.into_inner()); + if let Some(item) = self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Meta { .. }), + |this| this.parse_attr_item(force_collect), + ) { + return Ok(item); + } // Attr items don't have attributes. self.collect_tokens(None, AttrWrapper::empty(), force_collect, |this, _empty_attrs| { @@ -305,7 +329,7 @@ impl<'a> Parser<'a> { loop { let start_pos = self.num_bump_calls; // Only try to parse if it is an inner attribute (has `!`). - let attr = if self.check(exp!(Pound)) && self.look_ahead(1, |t| t == &token::Not) { + let attr = if self.check(exp!(Pound)) && self.look_ahead(1, |t| t == &token::Bang) { Some(self.parse_attribute(InnerAttrPolicy::Permitted)?) } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind { if attr_style == ast::AttrStyle::Inner { @@ -396,18 +420,17 @@ impl<'a> Parser<'a> { &mut self, unsafe_allowed: AllowLeadingUnsafe, ) -> PResult<'a, ast::MetaItem> { - // We can't use `maybe_whole` here because it would bump in the `None` - // case, which we don't want. - if let token::Interpolated(nt) = &self.token.kind - && let token::NtMeta(attr_item) = &**nt - { - match attr_item.meta(attr_item.path.span) { - Some(meta) => { - self.bump(); - return Ok(meta); - } - None => self.unexpected()?, - } + if let Some(MetaVarKind::Meta { has_meta_form }) = self.token.is_metavar_seq() { + return if has_meta_form { + let attr_item = self + .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { + this.parse_attr_item(ForceCollect::No) + }) + .unwrap(); + Ok(attr_item.meta(attr_item.path.span).unwrap()) + } else { + self.unexpected_any() + }; } let lo = self.token.span; @@ -464,7 +487,7 @@ impl<'a> Parser<'a> { let mut err = errors::InvalidMetaItem { span: self.token.span, - token: self.token.clone(), + descr: super::token_descr(&self.token), quote_ident_sugg: None, }; diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 67abc2d539401..716ababb00802 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1,17 +1,15 @@ use std::mem::take; use std::ops::{Deref, DerefMut}; -use std::sync::Arc; use ast::token::IdentIsRaw; use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind}; -use rustc_ast::tokenstream::AttrTokenTree; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block, - BlockCheckMode, Expr, ExprKind, GenericArg, Generics, HasTokens, Item, ItemKind, Param, Pat, - PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind, + BlockCheckMode, Expr, ExprKind, GenericArg, Generics, Item, ItemKind, Param, Pat, PatKind, + Path, PathSegment, QSelf, Recovered, Ty, TyKind, }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; @@ -33,15 +31,15 @@ use super::{ SeqSep, TokenType, }; use crate::errors::{ - AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AttributeOnParamType, AwaitSuggestion, - BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, ComparisonOperatorsCannotBeChained, - ComparisonOperatorsCannotBeChainedSugg, ConstGenericWithoutBraces, - ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + AddParen, AmbiguousPlus, AsyncMoveBlockIn2015, AsyncUseBlockIn2015, AttributeOnParamType, + AwaitSuggestion, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi, + ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, HelpIdentifierStartsWithNumber, HelpUseLatestEdition, InInTypo, IncorrectAwait, - IncorrectSemicolon, IncorrectUseOfAwait, PatternMethodParamWithoutBody, QuestionMarkInType, - QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, + IncorrectSemicolon, IncorrectUseOfAwait, IncorrectUseOfUse, PatternMethodParamWithoutBody, + QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, TernaryOperator, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, @@ -574,10 +572,17 @@ impl<'a> Parser<'a> { return Err(self.dcx().create_err(UseEqInstead { span: self.token.span })); } - if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) { - // The 2015 edition is in use because parsing of `async move` has failed. + if (self.token.is_keyword(kw::Move) || self.token.is_keyword(kw::Use)) + && self.prev_token.is_keyword(kw::Async) + { + // The 2015 edition is in use because parsing of `async move` or `async use` has failed. let span = self.prev_token.span.to(self.token.span); - return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + if self.token.is_keyword(kw::Move) { + return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span })); + } else { + // kw::Use + return Err(self.dcx().create_err(AsyncUseBlockIn2015 { span })); + } } let expect = tokens_to_string(&expected); @@ -1169,7 +1174,7 @@ impl<'a> Parser<'a> { let mut number_of_gt = 0; while self.look_ahead(position, |t| { trace!("check_trailing_angle_brackets: t={:?}", t); - if *t == token::BinOp(token::BinOpToken::Shr) { + if *t == token::Shr { number_of_shr += 1; true } else if *t == token::Gt { @@ -1224,7 +1229,7 @@ impl<'a> Parser<'a> { let span = lo.to(self.prev_token.span); // Detect trailing `>` like in `x.collect::Vec<_>>()`. let mut trailing_span = self.prev_token.span.shrink_to_hi(); - while self.token == token::BinOp(token::Shr) || self.token == token::Gt { + while self.token == token::Shr || self.token == token::Gt { trailing_span = trailing_span.to(self.token.span); self.bump(); } @@ -1350,13 +1355,13 @@ impl<'a> Parser<'a> { } return match (op.node, &outer_op.node) { // `x == y == z` - (BinOpKind::Eq, AssocOp::Equal) | + (BinOpKind::Eq, AssocOp::Binary(BinOpKind::Eq)) | // `x < y < z` and friends. - (BinOpKind::Lt, AssocOp::Less | AssocOp::LessEqual) | - (BinOpKind::Le, AssocOp::LessEqual | AssocOp::Less) | + (BinOpKind::Lt, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) | + (BinOpKind::Le, AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le)) | // `x > y > z` and friends. - (BinOpKind::Gt, AssocOp::Greater | AssocOp::GreaterEqual) | - (BinOpKind::Ge, AssocOp::GreaterEqual | AssocOp::Greater) => { + (BinOpKind::Gt, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) | + (BinOpKind::Ge, AssocOp::Binary(BinOpKind::Gt | BinOpKind::Ge)) => { let expr_to_str = |e: &Expr| { self.span_to_snippet(e.span) .unwrap_or_else(|_| pprust::expr_to_string(e)) @@ -1368,7 +1373,10 @@ impl<'a> Parser<'a> { false // Keep the current parse behavior, where the AST is `(x < y) < z`. } // `x == y < z` - (BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => { + ( + BinOpKind::Eq, + AssocOp::Binary(BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge) + ) => { // Consume `z`/outer-op-rhs. let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_expr() { @@ -1389,7 +1397,10 @@ impl<'a> Parser<'a> { } } // `x > y == z` - (BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, AssocOp::Equal) => { + ( + BinOpKind::Lt | BinOpKind::Le | BinOpKind::Gt | BinOpKind::Ge, + AssocOp::Binary(BinOpKind::Eq) + ) => { let snapshot = self.create_snapshot_for_diagnostic(); // At this point it is always valid to enclose the lhs in parentheses, no // further checks are necessary. @@ -1457,15 +1468,14 @@ impl<'a> Parser<'a> { // Include `<` to provide this recommendation even in a case like // `Foo>>` - if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Less - || outer_op.node == AssocOp::Greater + if op.node == BinOpKind::Lt && outer_op.node == AssocOp::Binary(BinOpKind::Lt) + || outer_op.node == AssocOp::Binary(BinOpKind::Gt) { - if outer_op.node == AssocOp::Less { + if outer_op.node == AssocOp::Binary(BinOpKind::Lt) { let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); // So far we have parsed `foo Parser<'a> { &mut self, await_sp: Span, ) -> PResult<'a, P> { - let (hi, expr, is_question) = if self.token == token::Not { + let (hi, expr, is_question) = if self.token == token::Bang { // Handle `await!()`. self.recover_await_macro()? } else { @@ -1970,7 +1980,7 @@ impl<'a> Parser<'a> { } fn recover_await_macro(&mut self) -> PResult<'a, (Span, P, bool)> { - self.expect(exp!(Not))?; + self.expect(exp!(Bang))?; self.expect(exp!(OpenParen))?; let expr = self.parse_expr()?; self.expect(exp!(CloseParen))?; @@ -1988,7 +1998,7 @@ impl<'a> Parser<'a> { self.parse_expr() } .map_err(|mut err| { - err.span_label(await_sp, "while parsing this incorrect await expression"); + err.span_label(await_sp, format!("while parsing this incorrect await expression")); err })?; Ok((expr.span, expr, is_question)) @@ -2027,10 +2037,25 @@ impl<'a> Parser<'a> { self.dcx().emit_err(IncorrectUseOfAwait { span }); } } + /// + /// If encountering `x.use()`, consumes and emits an error. + pub(super) fn recover_from_use(&mut self) { + if self.token == token::OpenDelim(Delimiter::Parenthesis) + && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis)) + { + // var.use() + let lo = self.token.span; + self.bump(); // ( + let span = lo.to(self.token.span); + self.bump(); // ) + + self.dcx().emit_err(IncorrectUseOfUse { span }); + } + } pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P> { let is_try = self.token.is_keyword(kw::Try); - let is_questionmark = self.look_ahead(1, |t| t == &token::Not); //check for ! + let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); //check for ! let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(Delimiter::Parenthesis)); //check for ( if is_try && is_questionmark && is_open { @@ -2082,7 +2107,7 @@ impl<'a> Parser<'a> { ast::GenericBound::Trait(poly) => Some(poly), _ => None, }) - .last() + .next_back() { err.span_suggestion_verbose( poly.span.shrink_to_hi(), @@ -2400,52 +2425,6 @@ impl<'a> Parser<'a> { err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp)); } err.span_label(span, "expected expression"); - - // Walk the chain of macro expansions for the current token to point at how the original - // code was interpreted. This helps the user realize when a macro argument of one type is - // later reinterpreted as a different type, like `$x:expr` being reinterpreted as `$x:pat` - // in a subsequent macro invocation (#71039). - let mut tok = self.token.clone(); - let mut labels = vec![]; - while let TokenKind::Interpolated(nt) = &tok.kind { - let tokens = nt.tokens(); - labels.push(Arc::clone(nt)); - if let Some(tokens) = tokens - && let tokens = tokens.to_attr_token_stream() - && let tokens = tokens.0.deref() - && let [AttrTokenTree::Token(token, _)] = &tokens[..] - { - tok = token.clone(); - } else { - break; - } - } - let mut iter = labels.into_iter().peekable(); - let mut show_link = false; - while let Some(nt) = iter.next() { - let descr = nt.descr(); - if let Some(next) = iter.peek() { - let next_descr = next.descr(); - if next_descr != descr { - err.span_label(next.use_span(), format!("this is expected to be {next_descr}")); - err.span_label( - nt.use_span(), - format!( - "this is interpreted as {}, but it is expected to be {}", - next_descr, descr, - ), - ); - show_link = true; - } - } - } - if show_link { - err.note( - "when forwarding a matched fragment to another macro-by-example, matchers in the \ - second macro will see an opaque AST of the fragment type, not the underlying \ - tokens", - ); - } err } @@ -2635,10 +2614,12 @@ impl<'a> Parser<'a> { ) -> PResult<'a, GenericArg> { let is_op_or_dot = AssocOp::from_token(&self.token) .and_then(|op| { - if let AssocOp::Greater - | AssocOp::Less - | AssocOp::ShiftRight - | AssocOp::GreaterEqual + if let AssocOp::Binary( + BinOpKind::Gt + | BinOpKind::Lt + | BinOpKind::Shr + | BinOpKind::Ge + ) // Don't recover from `foo::`, because this could be an attempt to // assign a value to a defaulted generic parameter. | AssocOp::Assign @@ -2653,8 +2634,7 @@ impl<'a> Parser<'a> { || self.token == TokenKind::Dot; // This will be true when a trait object type `Foo +` or a path which was a `const fn` with // type params has been parsed. - let was_op = - matches!(self.prev_token.kind, token::BinOp(token::Plus | token::Shr) | token::Gt); + let was_op = matches!(self.prev_token.kind, token::Plus | token::Shr | token::Gt); if !is_op_or_dot && !was_op { // We perform these checks and early return to avoid taking a snapshot unnecessarily. return Err(err); @@ -3032,8 +3012,7 @@ impl<'a> Parser<'a> { pub(super) fn recover_vcs_conflict_marker(&mut self) { // <<<<<<< - let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) - else { + let Some(start) = self.conflict_marker(&TokenKind::Shl, &TokenKind::Lt) else { return; }; let mut spans = Vec::with_capacity(3); @@ -3048,15 +3027,13 @@ impl<'a> Parser<'a> { if self.token == TokenKind::Eof { break; } - if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::BinOp(token::Or)) - { + if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::Or) { middlediff3 = Some(span); } if let Some(span) = self.conflict_marker(&TokenKind::EqEq, &TokenKind::Eq) { middle = Some(span); } - if let Some(span) = self.conflict_marker(&TokenKind::BinOp(token::Shr), &TokenKind::Gt) - { + if let Some(span) = self.conflict_marker(&TokenKind::Shr, &TokenKind::Gt) { spans.push(span); end = Some(span); break; diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e0e6c2177da54..0774324eae742 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -4,7 +4,7 @@ use core::mem; use core::ops::{Bound, ControlFlow}; use ast::mut_visit::{self, MutVisitor}; -use ast::token::IdentIsRaw; +use ast::token::{IdentIsRaw, MetaVarKind}; use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -171,7 +171,7 @@ impl<'a> Parser<'a> { break; } // Check for deprecated `...` syntax - if self.token == token::DotDotDot && op.node == AssocOp::DotDotEq { + if self.token == token::DotDotDot && op.node == AssocOp::Range(RangeLimits::Closed) { self.err_dotdotdot_syntax(self.token.span); } @@ -188,17 +188,12 @@ impl<'a> Parser<'a> { } // Look for JS' `===` and `!==` and recover - if (op.node == AssocOp::Equal || op.node == AssocOp::NotEqual) + if let AssocOp::Binary(bop @ BinOpKind::Eq | bop @ BinOpKind::Ne) = op.node && self.token == token::Eq && self.prev_token.span.hi() == self.token.span.lo() { let sp = op.span.to(self.token.span); - let sugg = match op.node { - AssocOp::Equal => "==", - AssocOp::NotEqual => "!=", - _ => unreachable!(), - } - .into(); + let sugg = bop.as_str().into(); let invalid = format!("{sugg}="); self.dcx().emit_err(errors::InvalidComparisonOperator { span: sp, @@ -213,7 +208,7 @@ impl<'a> Parser<'a> { } // Look for PHP's `<>` and recover - if op.node == AssocOp::Less + if op.node == AssocOp::Binary(BinOpKind::Lt) && self.token == token::Gt && self.prev_token.span.hi() == self.token.span.lo() { @@ -231,7 +226,7 @@ impl<'a> Parser<'a> { } // Look for C++'s `<=>` and recover - if op.node == AssocOp::LessEqual + if op.node == AssocOp::Binary(BinOpKind::Le) && self.token == token::Gt && self.prev_token.span.hi() == self.token.span.lo() { @@ -244,8 +239,8 @@ impl<'a> Parser<'a> { self.bump(); } - if self.prev_token == token::BinOp(token::Plus) - && self.token == token::BinOp(token::Plus) + if self.prev_token == token::Plus + && self.token == token::Plus && self.prev_token.span.between(self.token.span).is_empty() { let op_span = self.prev_token.span.to(self.token.span); @@ -255,8 +250,8 @@ impl<'a> Parser<'a> { continue; } - if self.prev_token == token::BinOp(token::Minus) - && self.token == token::BinOp(token::Minus) + if self.prev_token == token::Minus + && self.token == token::Minus && self.prev_token.span.between(self.token.span).is_empty() && !self.look_ahead(1, |tok| tok.can_begin_expr()) { @@ -269,13 +264,13 @@ impl<'a> Parser<'a> { let op = op.node; // Special cases: - if op == AssocOp::As { + if op == AssocOp::Cast { lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?; continue; - } else if op == AssocOp::DotDot || op == AssocOp::DotDotEq { + } else if let AssocOp::Range(limits) = op { // If we didn't have to handle `x..`/`x..=`, it would be pretty easy to // generalise it to the Fixity::None code. - lhs = self.parse_expr_range(prec, lhs, op, cur_op_span)?; + lhs = self.parse_expr_range(prec, lhs, limits, cur_op_span)?; break; } @@ -290,46 +285,16 @@ impl<'a> Parser<'a> { let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); lhs = match op { - AssocOp::Add - | AssocOp::Subtract - | AssocOp::Multiply - | AssocOp::Divide - | AssocOp::Modulus - | AssocOp::LAnd - | AssocOp::LOr - | AssocOp::BitXor - | AssocOp::BitAnd - | AssocOp::BitOr - | AssocOp::ShiftLeft - | AssocOp::ShiftRight - | AssocOp::Equal - | AssocOp::Less - | AssocOp::LessEqual - | AssocOp::NotEqual - | AssocOp::Greater - | AssocOp::GreaterEqual => { - let ast_op = op.to_ast_binop().unwrap(); + AssocOp::Binary(ast_op) => { let binary = self.mk_binary(source_map::respan(cur_op_span, ast_op), lhs, rhs); self.mk_expr(span, binary) } AssocOp::Assign => self.mk_expr(span, ExprKind::Assign(lhs, rhs, cur_op_span)), - AssocOp::AssignOp(k) => { - let aop = match k { - token::Plus => BinOpKind::Add, - token::Minus => BinOpKind::Sub, - token::Star => BinOpKind::Mul, - token::Slash => BinOpKind::Div, - token::Percent => BinOpKind::Rem, - token::Caret => BinOpKind::BitXor, - token::And => BinOpKind::BitAnd, - token::Or => BinOpKind::BitOr, - token::Shl => BinOpKind::Shl, - token::Shr => BinOpKind::Shr, - }; + AssocOp::AssignOp(aop) => { let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs); self.mk_expr(span, aopexpr) } - AssocOp::As | AssocOp::DotDot | AssocOp::DotDotEq => { + AssocOp::Cast | AssocOp::Range(_) => { self.dcx().span_bug(span, "AssocOp should have been handled by special case") } }; @@ -347,13 +312,14 @@ impl<'a> Parser<'a> { // An exhaustive check is done in the following block, but these are checked first // because they *are* ambiguous but also reasonable looking incorrect syntax, so we // want to keep their span info to improve diagnostics in these cases in a later stage. - (true, Some(AssocOp::Multiply)) | // `{ 42 } *foo = bar;` or `{ 42 } * 3` - (true, Some(AssocOp::Subtract)) | // `{ 42 } -5` - (true, Some(AssocOp::Add)) | // `{ 42 } + 42` (unary plus) - (true, Some(AssocOp::LAnd)) | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` - (true, Some(AssocOp::LOr)) | // `{ 42 } || 42` ("logical or" or closure) - (true, Some(AssocOp::BitOr)) // `{ 42 } | 42` or `{ 42 } |x| 42` - => { + (true, Some(AssocOp::Binary( + BinOpKind::Mul | // `{ 42 } *foo = bar;` or `{ 42 } * 3` + BinOpKind::Sub | // `{ 42 } -5` + BinOpKind::Add | // `{ 42 } + 42` (unary plus) + BinOpKind::And | // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` + BinOpKind::Or | // `{ 42 } || 42` ("logical or" or closure) + BinOpKind::BitOr // `{ 42 } | 42` or `{ 42 } |x| 42` + ))) => { // These cases are ambiguous and can't be identified in the parser alone. // // Bitwise AND is left out because guessing intent is hard. We can make @@ -392,23 +358,21 @@ impl<'a> Parser<'a> { // When parsing const expressions, stop parsing when encountering `>`. ( Some( - AssocOp::ShiftRight - | AssocOp::Greater - | AssocOp::GreaterEqual - | AssocOp::AssignOp(token::BinOpToken::Shr), + AssocOp::Binary(BinOpKind::Shr | BinOpKind::Gt | BinOpKind::Ge) + | AssocOp::AssignOp(BinOpKind::Shr), ), _, ) if self.restrictions.contains(Restrictions::CONST_EXPR) => { return None; } - // When recovering patterns as expressions, stop parsing when encountering an assignment `=`, an alternative `|`, or a range `..`. + // When recovering patterns as expressions, stop parsing when encountering an + // assignment `=`, an alternative `|`, or a range `..`. ( Some( AssocOp::Assign | AssocOp::AssignOp(_) - | AssocOp::BitOr - | AssocOp::DotDot - | AssocOp::DotDotEq, + | AssocOp::Binary(BinOpKind::BitOr) + | AssocOp::Range(_), ), _, ) if self.restrictions.contains(Restrictions::IS_PAT) => { @@ -423,7 +387,7 @@ impl<'a> Parser<'a> { incorrect: "and".into(), sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span), }); - (AssocOp::LAnd, span) + (AssocOp::Binary(BinOpKind::And), span) } (None, Some((Ident { name: sym::or, span }, IdentIsRaw::No))) if self.may_recover() => { self.dcx().emit_err(errors::InvalidLogicalOperator { @@ -431,7 +395,7 @@ impl<'a> Parser<'a> { incorrect: "or".into(), sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span), }); - (AssocOp::LOr, span) + (AssocOp::Binary(BinOpKind::Or), span) } _ => return None, }; @@ -449,7 +413,7 @@ impl<'a> Parser<'a> { &mut self, prec: ExprPrecedence, lhs: P, - op: AssocOp, + limits: RangeLimits, cur_op_span: Span, ) -> PResult<'a, P> { let rhs = if self.is_at_start_of_range_notation_rhs() { @@ -465,8 +429,6 @@ impl<'a> Parser<'a> { }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); - let limits = - if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; let range = self.mk_range(Some(lhs), rhs, limits); Ok(self.mk_expr(span, range)) } @@ -543,23 +505,23 @@ impl<'a> Parser<'a> { // Note: when adding new unary operators, don't forget to adjust TokenKind::can_begin_expr() match this.token.uninterpolate().kind { // `!expr` - token::Not => make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)), + token::Bang => make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Not)), // `~expr` token::Tilde => make_it!(this, attrs, |this, _| this.recover_tilde_expr(lo)), // `-expr` - token::BinOp(token::Minus) => { + token::Minus => { make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Neg)) } // `*expr` - token::BinOp(token::Star) => { + token::Star => { make_it!(this, attrs, |this, _| this.parse_expr_unary(lo, UnOp::Deref)) } // `&expr` and `&&expr` - token::BinOp(token::And) | token::AndAnd => { + token::And | token::AndAnd => { make_it!(this, attrs, |this, _| this.parse_expr_borrow(lo)) } // `+lit` - token::BinOp(token::Plus) if this.look_ahead(1, |tok| tok.is_numeric_lit()) => { + token::Plus if this.look_ahead(1, |tok| tok.is_numeric_lit()) => { let mut err = errors::LeadingPlusNotSupported { span: lo, remove_plus: None, @@ -579,9 +541,7 @@ impl<'a> Parser<'a> { this.parse_expr_prefix(attrs) } // Recover from `++x`: - token::BinOp(token::Plus) - if this.look_ahead(1, |t| *t == token::BinOp(token::Plus)) => - { + token::Plus if this.look_ahead(1, |t| *t == token::Plus) => { let starts_stmt = this.prev_token == token::Semi || this.prev_token == token::CloseDelim(Delimiter::Brace); let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span)); @@ -605,7 +565,11 @@ impl<'a> Parser<'a> { fn parse_expr_prefix_common(&mut self, lo: Span) -> PResult<'a, (Span, P)> { self.bump(); let attrs = self.parse_outer_attributes()?; - let expr = self.parse_expr_prefix(attrs)?; + let expr = if self.token.is_range_separator() { + self.parse_expr_prefix_range(attrs) + } else { + self.parse_expr_prefix(attrs) + }?; let span = self.interpolated_or_expr_span(&expr); Ok((lo.to(span), expr)) } @@ -761,14 +725,12 @@ impl<'a> Parser<'a> { suggestion, }) } - token::BinOp(token::Shl) => { - self.dcx().emit_err(errors::ShiftInterpretedAsGeneric { - shift: self.token.span, - r#type: path, - args: args_span, - suggestion, - }) - } + token::Shl => self.dcx().emit_err(errors::ShiftInterpretedAsGeneric { + shift: self.token.span, + r#type: path, + args: args_span, + suggestion, + }), _ => { // We can end up here even without `<` being the next token, for // example because `parse_ty_no_plus` returns `Err` on keywords, @@ -816,6 +778,7 @@ impl<'a> Parser<'a> { ExprKind::MethodCall(_) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_, _) => "`.await`", + ExprKind::Use(_, _) => "`.use`", ExprKind::Match(_, _, MatchKind::Postfix) => "a postfix match", ExprKind::Err(_) => return Ok(with_postfix), _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), @@ -1334,6 +1297,12 @@ impl<'a> Parser<'a> { return Ok(self.mk_await_expr(self_arg, lo)); } + if self.eat_keyword(exp!(Use)) { + let use_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::ergonomic_clones, use_span); + return Ok(self.mk_use_expr(self_arg, lo)); + } + // Post-fix match if self.eat_keyword(exp!(Match)) { let match_span = self.prev_token.span; @@ -1382,6 +1351,7 @@ impl<'a> Parser<'a> { fn parse_expr_bottom(&mut self) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); + let span = self.token.span; if let token::Interpolated(nt) = &self.token.kind { match &**nt { token::NtExpr(e) | token::NtLiteral(e) => { @@ -1389,18 +1359,16 @@ impl<'a> Parser<'a> { self.bump(); return Ok(e); } - token::NtPath(path) => { - let path = (**path).clone(); - self.bump(); - return Ok(self.mk_expr(self.prev_token.span, ExprKind::Path(None, path))); - } token::NtBlock(block) => { let block = block.clone(); self.bump(); return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); } - _ => {} }; + } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { + this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) + }) { + return Ok(self.mk_expr(span, ExprKind::Path(None, path))); } // Outer attributes are already parsed and will be @@ -1435,6 +1403,7 @@ impl<'a> Parser<'a> { } else if this.check_path() { this.parse_expr_path_start() } else if this.check_keyword(exp!(Move)) + || this.check_keyword(exp!(Use)) || this.check_keyword(exp!(Static)) || this.check_const_closure() { @@ -1612,7 +1581,7 @@ impl<'a> Parser<'a> { }; // `!`, as an operator, is prefix, so we know this isn't that. - let (span, kind) = if self.eat(exp!(Not)) { + let (span, kind) = if self.eat(exp!(Bang)) { // MACRO INVOCATION expression if qself.is_some() { self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span)); @@ -2426,7 +2395,7 @@ impl<'a> Parser<'a> { Ok(closure) } - /// Parses an optional `move` prefix to a closure-like construct. + /// Parses an optional `move` or `use` prefix to a closure-like construct. fn parse_capture_clause(&mut self) -> PResult<'a, CaptureBy> { if self.eat_keyword(exp!(Move)) { let move_kw_span = self.prev_token.span; @@ -2439,6 +2408,16 @@ impl<'a> Parser<'a> { } else { Ok(CaptureBy::Value { move_kw: move_kw_span }) } + } else if self.eat_keyword(exp!(Use)) { + let use_kw_span = self.prev_token.span; + self.psess.gated_spans.gate(sym::ergonomic_clones, use_kw_span); + // Check for `use async` and recover + if self.check_keyword(exp!(Async)) { + let use_async_span = self.token.span.with_lo(self.prev_token.span.data().lo); + Err(self.dcx().create_err(errors::AsyncUseOrderIncorrect { span: use_async_span })) + } else { + Ok(CaptureBy::Use { use_kw: use_kw_span }) + } } else { Ok(CaptureBy::Ref) } @@ -2609,7 +2588,8 @@ impl<'a> Parser<'a> { } /// Parses the condition of a `if` or `while` expression. - fn parse_expr_cond(&mut self) -> PResult<'a, P> { + // Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions. + pub fn parse_expr_cond(&mut self) -> PResult<'a, P> { let attrs = self.parse_outer_attributes()?; let (mut cond, _) = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?; @@ -2633,7 +2613,7 @@ impl<'a> Parser<'a> { missing_let: None, comparison: None, }; - if self.prev_token == token::BinOp(token::Or) { + if self.prev_token == token::Or { // This was part of a closure, the that part of the parser recover. return Err(self.dcx().create_err(err)); } else { @@ -3084,7 +3064,7 @@ impl<'a> Parser<'a> { } self.restore_snapshot(pre_pat_snapshot); - match self.parse_stmt_without_recovery(true, ForceCollect::No) { + match self.parse_stmt_without_recovery(true, ForceCollect::No, false) { // Consume statements for as long as possible. Ok(Some(stmt)) => { stmts.push(stmt); @@ -3125,10 +3105,11 @@ impl<'a> Parser<'a> { let mut result = if armless { // A pattern without a body, allowed for never patterns. arm_body = None; + let span = lo.to(this.prev_token.span); this.expect_one_of(&[exp!(Comma)], &[exp!(CloseBrace)]).map(|x| { // Don't gate twice if !pat.contains_never_pattern() { - this.psess.gated_spans.gate(sym::never_patterns, pat.span); + this.psess.gated_spans.gate(sym::never_patterns, span); } x }) @@ -3452,7 +3433,7 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(lookahead, &[kw]) && (( // `async move {` - self.is_keyword_ahead(lookahead + 1, &[kw::Move]) + self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use]) && self.look_ahead(lookahead + 2, |t| { *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block() }) @@ -3855,6 +3836,13 @@ impl<'a> Parser<'a> { await_expr } + fn mk_use_expr(&mut self, self_arg: P, lo: Span) -> P { + let span = lo.to(self.prev_token.span); + let use_expr = self.mk_expr(span, ExprKind::Use(self_arg, self.prev_token.span)); + self.recover_from_use(); + use_expr + } + pub(crate) fn mk_expr_with_attrs(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P { P(Expr { kind, span, attrs, id: DUMMY_NODE_ID, tokens: None }) } @@ -4003,6 +3991,7 @@ impl MutVisitor for CondChecker<'_> { } ExprKind::Unary(_, _) | ExprKind::Await(_, _) + | ExprKind::Use(_, _) | ExprKind::AssignOp(_, _, _) | ExprKind::Range(_, _, _) | ExprKind::Try(_) diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 11f0e579de5a1..c3f71dd8b3066 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -367,34 +367,47 @@ impl<'a> Parser<'a> { loop { let where_sp = where_lo.to(self.prev_token.span); + let attrs = self.parse_outer_attributes()?; let pred_lo = self.token.span; - let kind = if self.check_lifetime() && self.look_ahead(1, |t| !t.is_like_plus()) { - let lifetime = self.expect_lifetime(); - // Bounds starting with a colon are mandatory, but possibly empty. - self.expect(exp!(Colon))?; - let bounds = self.parse_lt_param_bounds(); - ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate { - lifetime, - bounds, - }) - } else if self.check_type() { - match self.parse_ty_where_predicate_kind_or_recover_tuple_struct_body( - struct_, pred_lo, where_sp, - )? { - PredicateKindOrStructBody::PredicateKind(kind) => kind, - PredicateKindOrStructBody::StructBody(body) => { - tuple_struct_body = Some(body); - break; - } + let predicate = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { + for attr in &attrs { + self.psess.gated_spans.gate(sym::where_clause_attrs, attr.span); } - } else { - break; - }; - where_clause.predicates.push(ast::WherePredicate { - kind, - id: DUMMY_NODE_ID, - span: pred_lo.to(self.prev_token.span), - }); + let kind = if this.check_lifetime() && this.look_ahead(1, |t| !t.is_like_plus()) { + let lifetime = this.expect_lifetime(); + // Bounds starting with a colon are mandatory, but possibly empty. + this.expect(exp!(Colon))?; + let bounds = this.parse_lt_param_bounds(); + Some(ast::WherePredicateKind::RegionPredicate(ast::WhereRegionPredicate { + lifetime, + bounds, + })) + } else if this.check_type() { + match this.parse_ty_where_predicate_kind_or_recover_tuple_struct_body( + struct_, pred_lo, where_sp, + )? { + PredicateKindOrStructBody::PredicateKind(kind) => Some(kind), + PredicateKindOrStructBody::StructBody(body) => { + tuple_struct_body = Some(body); + None + } + } + } else { + None + }; + let predicate = kind.map(|kind| ast::WherePredicate { + attrs, + kind, + id: DUMMY_NODE_ID, + span: pred_lo.to(this.prev_token.span), + is_placeholder: false, + }); + Ok((predicate, Trailing::No, UsePreAttrPos::No)) + })?; + match predicate { + Some(predicate) => where_clause.predicates.push(predicate), + None => break, + } let prev_token = self.prev_token.span; let ate_comma = self.eat(exp!(Comma)); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c923717ecaf27..2388463ecfcbf 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -4,7 +4,7 @@ use std::mem; use ast::token::IdentIsRaw; use rustc_ast::ast::*; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, TokenKind}; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; use rustc_ast::util::case::Case; use rustc_ast::{self as ast}; @@ -21,10 +21,10 @@ use super::diagnostics::{ConsumeClosingDelim, dummy_arg}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle, - Trailing, UsePreAttrPos, + Recovered, Trailing, UsePreAttrPos, }; use crate::errors::{self, MacroExpandsToAdtField}; -use crate::{exp, fluent_generated as fluent, maybe_whole}; +use crate::{exp, fluent_generated as fluent}; impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. @@ -142,10 +142,13 @@ impl<'a> Parser<'a> { fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option> { - maybe_whole!(self, NtItem, |item| { + if let Some(item) = + self.eat_metavar_seq(MetaVarKind::Item, |this| this.parse_item(ForceCollect::Yes)) + { + let mut item = item.expect("an actual item"); attrs.prepend_to_nt_inner(&mut item.attrs); - Some(item.into_inner()) - }); + return Ok(Some(item.into_inner())); + } self.collect_tokens(None, attrs, force_collect, |this, mut attrs| { let lo = this.token.span; @@ -209,7 +212,7 @@ impl<'a> Parser<'a> { let check_pub = def == &Defaultness::Final; let mut def_ = || mem::replace(def, Defaultness::Final); - let info = if self.eat_keyword_case(exp!(Use), case) { + let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) { self.parse_use_item()? } else if self.check_fn_front_matter(check_pub, case) { // FUNCTION ITEM @@ -217,7 +220,14 @@ impl<'a> Parser<'a> { self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?; ( ident, - ItemKind::Fn(Box::new(Fn { defaultness: def_(), sig, generics, contract, body })), + ItemKind::Fn(Box::new(Fn { + defaultness: def_(), + sig, + generics, + contract, + body, + define_opaque: None, + })), ) } else if self.eat_keyword(exp!(Extern)) { if self.eat_keyword(exp!(Crate)) { @@ -382,7 +392,7 @@ impl<'a> Parser<'a> { /// Are we sure this could not possibly be a macro invocation? fn isnt_macro_invocation(&mut self) -> bool { - self.check_ident() && self.look_ahead(1, |t| *t != token::Not && *t != token::PathSep) + self.check_ident() && self.look_ahead(1, |t| *t != token::Bang && *t != token::PathSep) } /// Recover on encountering a struct, enum, or method definition where the user @@ -480,7 +490,7 @@ impl<'a> Parser<'a> { /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` - self.expect(exp!(Not))?; // `!` + self.expect(exp!(Bang))?; // `!` match self.parse_delim_args() { // `( .. )` or `[ .. ]` (followed by `;`), or `{ .. }`. Ok(args) => { @@ -540,7 +550,7 @@ impl<'a> Parser<'a> { fn parse_polarity(&mut self) -> ast::ImplPolarity { // Disambiguate `impl !Trait for Type { ... }` and `impl ! { ... }` for the never type. - if self.check(exp!(Not)) && self.look_ahead(1, |t| t.can_begin_type()) { + if self.check(exp!(Bang)) && self.look_ahead(1, |t| t.can_begin_type()) { self.bump(); // `!` ast::ImplPolarity::Negative(self.prev_token.span) } else { @@ -639,7 +649,7 @@ impl<'a> Parser<'a> { let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?; - let item_kind = match ty_second { + let (of_trait, self_ty) = match ty_second { Some(ty_second) => { // impl Trait for Type if !has_for { @@ -672,31 +682,20 @@ impl<'a> Parser<'a> { }; let trait_ref = TraitRef { path, ref_id: ty_first.id }; - ItemKind::Impl(Box::new(Impl { - safety, - polarity, - defaultness, - constness, - generics, - of_trait: Some(trait_ref), - self_ty: ty_second, - items: impl_items, - })) - } - None => { - // impl Type - ItemKind::Impl(Box::new(Impl { - safety, - polarity, - defaultness, - constness, - generics, - of_trait: None, - self_ty: ty_first, - items: impl_items, - })) + (Some(trait_ref), ty_second) } + None => (None, ty_first), // impl Type }; + let item_kind = ItemKind::Impl(Box::new(Impl { + safety, + polarity, + defaultness, + constness, + generics, + of_trait, + self_ty, + items: impl_items, + })); Ok((Ident::empty(), item_kind)) } @@ -1277,6 +1276,21 @@ impl<'a> Parser<'a> { None } + fn is_use_closure(&self) -> bool { + if self.token.is_keyword(kw::Use) { + // Check if this could be a closure. + self.look_ahead(1, |token| { + // Move or Async here would be an error but still we're parsing a closure + let dist = + if token.is_keyword(kw::Move) || token.is_keyword(kw::Async) { 2 } else { 1 }; + + self.look_ahead(dist, |token| matches!(token.kind, token::Or | token::OrOr)) + }) + } else { + false + } + } + fn is_unsafe_foreign_mod(&self) -> bool { self.token.is_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Extern]) @@ -1290,10 +1304,10 @@ impl<'a> Parser<'a> { if self.check_keyword(exp!(Static)) { // Check if this could be a closure. !self.look_ahead(1, |token| { - if token.is_keyword(kw::Move) { + if token.is_keyword(kw::Move) || token.is_keyword(kw::Use) { return true; } - matches!(token.kind, token::BinOp(token::Or) | token::OrOr) + matches!(token.kind, token::Or | token::OrOr) }) } else { // `$qual static` @@ -1579,7 +1593,7 @@ impl<'a> Parser<'a> { } let ident = this.parse_field_ident("enum", vlo)?; - if this.token == token::Not { + if this.token == token::Bang { if let Err(err) = this.unexpected() { err.with_note(fluent::parse_macro_expands_to_enum_variant).emit(); } @@ -1814,7 +1828,7 @@ impl<'a> Parser<'a> { let attrs = p.parse_outer_attributes()?; p.collect_tokens(None, attrs, ForceCollect::No, |p, attrs| { let mut snapshot = None; - if p.is_vcs_conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) { + if p.is_vcs_conflict_marker(&TokenKind::Shl, &TokenKind::Lt) { // Account for `<<<<<<<` diff markers. We can't proactively error here because // that can be a valid type start, so we snapshot and reparse only we've // encountered another parse error. @@ -2034,7 +2048,7 @@ impl<'a> Parser<'a> { attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; - if self.token == token::Not { + if self.token == token::Bang { if let Err(mut err) = self.unexpected() { // Encounter the macro invocation err.subdiagnostic(MacroExpandsToAdtField { adt_ty }); @@ -2184,7 +2198,7 @@ impl<'a> Parser<'a> { if self.check_keyword(exp!(MacroRules)) { let macro_rules_span = self.token.span; - if self.look_ahead(1, |t| *t == token::Not) && self.look_ahead(2, |t| t.is_ident()) { + if self.look_ahead(1, |t| *t == token::Bang) && self.look_ahead(2, |t| t.is_ident()) { return IsMacroRulesItem::Yes { has_bang: true }; } else if self.look_ahead(1, |t| (t.is_ident())) { // macro_rules foo @@ -2209,11 +2223,11 @@ impl<'a> Parser<'a> { self.expect_keyword(exp!(MacroRules))?; // `macro_rules` if has_bang { - self.expect(exp!(Not))?; // `!` + self.expect(exp!(Bang))?; // `!` } let ident = self.parse_ident()?; - if self.eat(exp!(Not)) { + if self.eat(exp!(Bang)) { // Handle macro_rules! foo! let span = self.prev_token.span; self.dcx().emit_err(errors::MacroNameRemoveBang { span }); @@ -2954,14 +2968,27 @@ impl<'a> Parser<'a> { } _ => unreachable!(), }; + // is lifetime `n` tokens ahead? + let is_lifetime = |this: &Self, n| this.look_ahead(n, |t| t.is_lifetime()); // Is `self` `n` tokens ahead? let is_isolated_self = |this: &Self, n| { this.is_keyword_ahead(n, &[kw::SelfLower]) && this.look_ahead(n + 1, |t| t != &token::PathSep) }; + // Is `pin const self` `n` tokens ahead? + let is_isolated_pin_const_self = |this: &Self, n| { + this.look_ahead(n, |token| token.is_ident_named(sym::pin)) + && this.is_keyword_ahead(n + 1, &[kw::Const]) + && is_isolated_self(this, n + 2) + }; // Is `mut self` `n` tokens ahead? let is_isolated_mut_self = |this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1); + // Is `pin mut self` `n` tokens ahead? + let is_isolated_pin_mut_self = |this: &Self, n| { + this.look_ahead(n, |token| token.is_ident_named(sym::pin)) + && is_isolated_mut_self(this, n + 1) + }; // Parse `self` or `self: TYPE`. We already know the current token is `self`. let parse_self_possibly_typed = |this: &mut Self, m| { let eself_ident = expect_self_ident(this); @@ -3011,27 +3038,36 @@ impl<'a> Parser<'a> { // else is parsed as a normal function parameter list, so some lookahead is required. let eself_lo = self.token.span; let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind { - token::BinOp(token::And) => { - let eself = if is_isolated_self(self, 1) { - // `&self` - self.bump(); - SelfKind::Region(None, Mutability::Not) - } else if is_isolated_mut_self(self, 1) { - // `&mut self` - self.bump(); - self.bump(); - SelfKind::Region(None, Mutability::Mut) - } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) { - // `&'lt self` - self.bump(); - let lt = self.expect_lifetime(); - SelfKind::Region(Some(lt), Mutability::Not) - } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) { - // `&'lt mut self` - self.bump(); - let lt = self.expect_lifetime(); - self.bump(); - SelfKind::Region(Some(lt), Mutability::Mut) + token::And => { + let has_lifetime = is_lifetime(self, 1); + let skip_lifetime_count = has_lifetime as usize; + let eself = if is_isolated_self(self, skip_lifetime_count + 1) { + // `&{'lt} self` + self.bump(); // & + let lifetime = has_lifetime.then(|| self.expect_lifetime()); + SelfKind::Region(lifetime, Mutability::Not) + } else if is_isolated_mut_self(self, skip_lifetime_count + 1) { + // `&{'lt} mut self` + self.bump(); // & + let lifetime = has_lifetime.then(|| self.expect_lifetime()); + self.bump(); // mut + SelfKind::Region(lifetime, Mutability::Mut) + } else if is_isolated_pin_const_self(self, skip_lifetime_count + 1) { + // `&{'lt} pin const self` + self.bump(); // & + let lifetime = has_lifetime.then(|| self.expect_lifetime()); + self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); + self.bump(); // pin + self.bump(); // const + SelfKind::Pinned(lifetime, Mutability::Not) + } else if is_isolated_pin_mut_self(self, skip_lifetime_count + 1) { + // `&{'lt} pin mut self` + self.bump(); // & + let lifetime = has_lifetime.then(|| self.expect_lifetime()); + self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); + self.bump(); // pin + self.bump(); // mut + SelfKind::Pinned(lifetime, Mutability::Mut) } else { // `¬_self` return Ok(None); @@ -3041,12 +3077,12 @@ impl<'a> Parser<'a> { (eself, self_ident, hi) } // `*self` - token::BinOp(token::Star) if is_isolated_self(self, 1) => { + token::Star if is_isolated_self(self, 1) => { self.bump(); recover_self_ptr(self)? } // `*mut self` and `*const self` - token::BinOp(token::Star) + token::Star if self.look_ahead(1, |t| t.is_mutability()) && is_isolated_self(self, 2) => { self.bump(); @@ -3071,11 +3107,13 @@ impl<'a> Parser<'a> { fn is_named_param(&self) -> bool { let offset = match &self.token.kind { - token::Interpolated(nt) => match &**nt { - token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon), + token::OpenDelim(Delimiter::Invisible(origin)) => match origin { + InvisibleOrigin::MetaVar(MetaVarKind::Pat(_)) => { + return self.check_noexpect_past_close_delim(&token::Colon); + } _ => 0, }, - token::BinOp(token::And) | token::AndAnd => 1, + token::And | token::AndAnd => 1, _ if self.token.is_keyword(kw::Mut) => 1, _ => 0, }; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index bbd73dec2e472..323c0c1d6d000 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -24,7 +24,8 @@ pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{ - self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, Token, TokenKind, + self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtPatKind, Token, + TokenKind, }; use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree}; use rustc_ast::util::case::Case; @@ -812,9 +813,9 @@ impl<'a> Parser<'a> { self.is_keyword_ahead(0, &[kw::Const]) && self.look_ahead(1, |t| match &t.kind { // async closures do not work with const closures, so we do not parse that here. - token::Ident(kw::Move | kw::Static, IdentIsRaw::No) + token::Ident(kw::Move | kw::Use | kw::Static, IdentIsRaw::No) | token::OrOr - | token::BinOp(token::Or) => true, + | token::Or => true, _ => false, }) } @@ -1075,10 +1076,12 @@ impl<'a> Parser<'a> { let initial_semicolon = self.token.span; while self.eat(exp!(Semi)) { - let _ = self.parse_stmt_without_recovery(false, ForceCollect::No).unwrap_or_else(|e| { - e.cancel(); - None - }); + let _ = self + .parse_stmt_without_recovery(false, ForceCollect::No, false) + .unwrap_or_else(|e| { + e.cancel(); + None + }); } expect_err @@ -1650,14 +1653,14 @@ impl<'a> Parser<'a> { /// `::{` or `::*` fn is_import_coupler(&mut self) -> bool { self.check_path_sep_and_look_ahead(|t| { - matches!(t.kind, token::OpenDelim(Delimiter::Brace) | token::BinOp(token::Star)) + matches!(t.kind, token::OpenDelim(Delimiter::Brace) | token::Star) }) } // Debug view of the parser's token stream, up to `{lookahead}` tokens. // Only used when debugging. #[allow(unused)] - pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug + '_ { + pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug { fmt::from_fn(move |f| { let mut dbg_fmt = f.debug_struct("Parser"); // or at least, one view of @@ -1745,7 +1748,12 @@ pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), + Item(P), + Stmt(P), + Pat(P, NtPatKind), Ty(P), + Meta(P), + Path(P), Vis(P), /// This variant will eventually be removed, along with `Token::Interpolate`. diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index f202f85752e19..1123755ce0037 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -32,7 +32,7 @@ impl<'a> Parser<'a> { | MetaVarKind::Expr { .. } | MetaVarKind::Ty { .. } | MetaVarKind::Literal // `true`, `false` - | MetaVarKind::Meta + | MetaVarKind::Meta { .. } | MetaVarKind::Path => true, MetaVarKind::Item @@ -48,14 +48,11 @@ impl<'a> Parser<'a> { /// Old variant of `may_be_ident`. Being phased out. fn nt_may_be_ident(nt: &Nonterminal) -> bool { match nt { - NtStmt(_) - | NtPat(_) - | NtExpr(_) + NtExpr(_) | NtLiteral(_) // `true`, `false` - | NtMeta(_) - | NtPath(_) => true, + => true, - NtItem(_) | NtBlock(_) => false, + NtBlock(_) => false, } } @@ -98,8 +95,7 @@ impl<'a> Parser<'a> { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { - NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, - NtItem(_) | NtPat(_) | NtMeta(_) | NtPath(_) => false, + NtBlock(_) | NtExpr(_) | NtLiteral(_) => true, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -109,7 +105,7 @@ impl<'a> Parser<'a> { MetaVarKind::Item | MetaVarKind::Pat(_) | MetaVarKind::Ty { .. } - | MetaVarKind::Meta + | MetaVarKind::Meta { .. } | MetaVarKind::Path | MetaVarKind::Vis => false, MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => { @@ -149,7 +145,7 @@ impl<'a> Parser<'a> { // Note that TT is treated differently to all the others. NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { - Some(item) => NtItem(item), + Some(item) => return Ok(ParseNtResult::Item(item)), None => { return Err(self .dcx() @@ -162,7 +158,7 @@ impl<'a> Parser<'a> { NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(s) => NtStmt(P(s)), + Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))), None => { return Err(self .dcx() @@ -170,15 +166,18 @@ impl<'a> Parser<'a> { } }, NonterminalKind::Pat(pat_kind) => { - NtPat(self.collect_tokens_no_attrs(|this| match pat_kind { - PatParam { .. } => this.parse_pat_no_top_alt(None, None), - PatWithOr => this.parse_pat_no_top_guard( - None, - RecoverComma::No, - RecoverColon::No, - CommaRecoveryMode::EitherTupleOrPipe, - ), - })?) + return Ok(ParseNtResult::Pat( + self.collect_tokens_no_attrs(|this| match pat_kind { + PatParam { .. } => this.parse_pat_no_top_alt(None, None), + PatWithOr => this.parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ), + })?, + pat_kind, + )); } NonterminalKind::Expr(_) => NtExpr(self.parse_expr_force_collect()?), NonterminalKind::Literal => { @@ -203,9 +202,13 @@ impl<'a> Parser<'a> { }; } NonterminalKind::Path => { - NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?)) + return Ok(ParseNtResult::Path(P( + self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))? + ))); + } + NonterminalKind::Meta => { + return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?))); } - NonterminalKind::Meta => NtMeta(P(self.parse_attr_item(ForceCollect::Yes)?)), NonterminalKind::Vis => { return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| { this.parse_visibility(FollowedByType::Yes) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8ce749ec81417..ec14c5718da53 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -2,7 +2,8 @@ use std::ops::Bound; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token}; +use rustc_ast::token::NtPatKind::*; +use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token}; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::visit::{self, Visitor}; use rustc_ast::{ @@ -30,7 +31,7 @@ use crate::errors::{ UnexpectedVertVertInPattern, WrapInParens, }; use crate::parser::expr::{DestructuredFloat, could_be_unclosed_char_literal}; -use crate::{exp, maybe_recover_from_interpolated_ty_qpath, maybe_whole}; +use crate::{exp, maybe_recover_from_interpolated_ty_qpath}; #[derive(PartialEq, Copy, Clone)] pub enum Expected { @@ -357,7 +358,7 @@ impl<'a> Parser<'a> { ) }); match (is_end_ahead, &self.token.kind) { - (true, token::BinOp(token::Or) | token::OrOr) => { + (true, token::Or | token::OrOr) => { // A `|` or possibly `||` token shouldn't be here. Ban it. self.dcx().emit_err(TrailingVertNotAllowed { span: self.token.span, @@ -431,7 +432,11 @@ impl<'a> Parser<'a> { // `[` is included for indexing operations, // `[]` is excluded as `a[]` isn't an expression and should be recovered as `a, []` (cf. `tests/ui/parser/pat-lt-bracket-7.rs`), // `as` is included for type casts - let has_trailing_operator = matches!(self.token.kind, token::BinOp(op) if op != BinOpToken::Or) + let has_trailing_operator = matches!( + self.token.kind, + token::Plus | token::Minus | token::Star | token::Slash | token::Percent + | token::Caret | token::And | token::Shl | token::Shr // excludes `Or` + ) || self.token == token::Question || (self.token == token::OpenDelim(Delimiter::Bracket) && self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket))) // excludes `[]` @@ -689,6 +694,27 @@ impl<'a> Parser<'a> { PatVisitor { parser: self, stmt, arm: None, field: None }.visit_stmt(stmt); } + fn eat_metavar_pat(&mut self) -> Option> { + // Must try both kinds of pattern nonterminals. + if let Some(pat) = self.eat_metavar_seq_with_matcher( + |mv_kind| matches!(mv_kind, MetaVarKind::Pat(PatParam { .. })), + |this| this.parse_pat_no_top_alt(None, None), + ) { + Some(pat) + } else if let Some(pat) = self.eat_metavar_seq(MetaVarKind::Pat(PatWithOr), |this| { + this.parse_pat_no_top_guard( + None, + RecoverComma::No, + RecoverColon::No, + CommaRecoveryMode::EitherTupleOrPipe, + ) + }) { + Some(pat) + } else { + None + } + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -698,7 +724,10 @@ impl<'a> Parser<'a> { syntax_loc: Option, ) -> PResult<'a, P> { maybe_recover_from_interpolated_ty_qpath!(self, true); - maybe_whole!(self, NtPat, |pat| pat); + + if let Some(pat) = self.eat_metavar_pat() { + return Ok(pat); + } let mut lo = self.token.span; @@ -738,7 +767,7 @@ impl<'a> Parser<'a> { self.recover_dotdotdot_rest_pat(lo) } else if let Some(form) = self.parse_range_end() { self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`. - } else if self.eat(exp!(Not)) { + } else if self.eat(exp!(Bang)) { // Parse `!` self.psess.gated_spans.gate(sym::never_patterns, self.prev_token.span); PatKind::Never @@ -794,7 +823,7 @@ impl<'a> Parser<'a> { }; let span = lo.to(self.prev_token.span); - if qself.is_none() && self.check(exp!(Not)) { + if qself.is_none() && self.check(exp!(Bang)) { self.parse_pat_mac_invoc(path)? } else if let Some(form) = self.parse_range_end() { let begin = self.mk_expr(span, ExprKind::Path(qself, path)); @@ -1043,10 +1072,8 @@ impl<'a> Parser<'a> { self.recover_additional_muts(); // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtPat(..) = &**nt { - self.expected_ident_found_err().emit(); - } + if let Some(MetaVarKind::Pat(_)) = self.token.is_metavar_seq() { + self.expected_ident_found_err().emit(); } // Parse the pattern we hope to be an identifier. @@ -1232,7 +1259,7 @@ impl<'a> Parser<'a> { || self.look_ahead(dist, |t| { t.is_path_start() // e.g. `MY_CONST`; || *t == token::Dot // e.g. `.5` for recovery; - || matches!(t.kind, token::Literal(..) | token::BinOp(token::Minus)) + || matches!(t.kind, token::Literal(..) | token::Minus) || t.is_bool_lit() || t.is_whole_expr() || t.is_lifetime() // recover `'a` instead of `'a'` @@ -1308,7 +1335,7 @@ impl<'a> Parser<'a> { | token::OpenDelim(Delimiter::Brace) // A struct pattern. | token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern. | token::PathSep // A tuple / struct variant pattern. - | token::Not)) // A macro expanding to a pattern. + | token::Bang)) // A macro expanding to a pattern. } /// Parses `ident` or `ident @ pat`. diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index c24305ea9a866..9c6830c36727b 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -15,9 +15,9 @@ use tracing::debug; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::errors::{PathSingleColon, PathTripleColon}; +use crate::errors::{self, PathSingleColon, PathTripleColon}; +use crate::exp; use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; -use crate::{errors, exp, maybe_whole}; /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] @@ -194,7 +194,11 @@ impl<'a> Parser<'a> { } }; - maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner())); + if let Some(path) = + self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type)) + { + return Ok(reject_generics_if_mod_style(self, path)); + } // If we have a `ty` metavar in the form of a path, reparse it directly as a path, instead // of reparsing it as a `ty` and then extracting the path. @@ -301,10 +305,7 @@ impl<'a> Parser<'a> { let is_args_start = |token: &Token| { matches!( token.kind, - token::Lt - | token::BinOp(token::Shl) - | token::OpenDelim(Delimiter::Parenthesis) - | token::LArrow + token::Lt | token::Shl | token::OpenDelim(Delimiter::Parenthesis) | token::LArrow ) }; let check_args_start = |this: &mut Self| { @@ -378,11 +379,14 @@ impl<'a> Parser<'a> { self.psess.gated_spans.gate(sym::return_type_notation, span); + let prev_lo = self.prev_token.span.shrink_to_hi(); if self.eat_noexpect(&token::RArrow) { let lo = self.prev_token.span; let ty = self.parse_ty()?; + let span = lo.to(ty.span); + let suggestion = prev_lo.to(ty.span); self.dcx() - .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); + .emit_err(errors::BadReturnTypeNotationOutput { span, suggestion }); } P(ast::GenericArgs::ParenthesizedElided(span)) diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index a2699b077fcff..0896bd88b4cd3 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -5,7 +5,7 @@ use std::ops::Bound; use ast::Label; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, TokenKind}; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::util::classify::{self, TrailingBrace}; use rustc_ast::{ AttrStyle, AttrVec, Block, BlockCheckMode, DUMMY_NODE_ID, Expr, ExprKind, HasAttrs, Local, @@ -33,8 +33,8 @@ impl<'a> Parser<'a> { /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of /// whether or not we have attributes. // Public for rustfmt usage. - pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option> { - Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { + pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option> { + Ok(self.parse_stmt_without_recovery(false, force_collect, false).unwrap_or_else(|e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None @@ -42,23 +42,27 @@ impl<'a> Parser<'a> { } /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of - /// whether or not we have attributes. - // Public for `cfg_eval` macro expansion. + /// whether or not we have attributes. If `force_full_expr` is true, parses the stmt without + /// using `Restriction::STMT_EXPR`. Public for `cfg_eval` macro expansion. pub fn parse_stmt_without_recovery( &mut self, capture_semi: bool, force_collect: ForceCollect, + force_full_expr: bool, ) -> PResult<'a, Option> { let pre_attr_pos = self.collect_pos(); let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - maybe_whole!(self, NtStmt, |stmt| { + if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| { + this.parse_stmt_without_recovery(false, ForceCollect::Yes, false) + }) { + let mut stmt = stmt.expect("an actual statement"); stmt.visit_attrs(|stmt_attrs| { attrs.prepend_to_nt_inner(stmt_attrs); }); - Some(stmt.into_inner()) - }); + return Ok(Some(stmt)); + } if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) { self.bump(); @@ -147,12 +151,14 @@ impl<'a> Parser<'a> { } else if self.token != token::CloseDelim(Delimiter::Brace) { // Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case // above. + let restrictions = + if force_full_expr { Restrictions::empty() } else { Restrictions::STMT_EXPR }; let e = self.collect_tokens( Some(pre_attr_pos), AttrWrapper::empty(), force_collect, |this, _empty_attrs| { - let (expr, _) = this.parse_expr_res(Restrictions::STMT_EXPR, attrs)?; + let (expr, _) = this.parse_expr_res(restrictions, attrs)?; Ok((expr, Trailing::No, UsePreAttrPos::Yes)) }, )?; @@ -176,7 +182,7 @@ impl<'a> Parser<'a> { let stmt = self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { let path = this.parse_path(PathStyle::Expr)?; - if this.eat(exp!(Not)) { + if this.eat(exp!(Bang)) { let stmt_mac = this.parse_stmt_mac(lo, attrs, path)?; return Ok(( stmt_mac, @@ -229,11 +235,15 @@ impl<'a> Parser<'a> { let mac = P(MacCall { path, args }); let kind = if (style == MacStmtStyle::Braces - && self.token != token::Dot - && self.token != token::Question) - || self.token == token::Semi - || self.token == token::Eof - { + && !matches!(self.token.kind, token::Dot | token::Question)) + || matches!( + self.token.kind, + token::Semi + | token::Eof + | token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Stmt + ))) + ) { StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) } else { // Since none of the above applied, this is an expression statement macro. @@ -442,7 +452,16 @@ impl<'a> Parser<'a> { /// Parses the RHS of a local variable declaration (e.g., `= 14;`). fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option>> { let eq_consumed = match self.token.kind { - token::BinOpEq(..) => { + token::PlusEq + | token::MinusEq + | token::StarEq + | token::SlashEq + | token::PercentEq + | token::CaretEq + | token::AndEq + | token::OrEq + | token::ShlEq + | token::ShrEq => { // Recover `let x = 1` as `let x = 1` We must not use `+ BytePos(1)` here // because `` can be a multi-byte lookalike that was recovered, e.g. `➖=` (the // `➖` is a U+2796 Heavy Minus Sign Unicode Character) that was recovered as a @@ -492,7 +511,7 @@ impl<'a> Parser<'a> { // bar; // // which is valid in other languages, but not Rust. - match self.parse_stmt_without_recovery(false, ForceCollect::No) { + match self.parse_stmt_without_recovery(false, ForceCollect::No, false) { // If the next token is an open brace, e.g., we have: // // if expr other_expr { @@ -688,7 +707,7 @@ impl<'a> Parser<'a> { if self.token == token::Eof { break; } - if self.is_vcs_conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) { + if self.is_vcs_conflict_marker(&TokenKind::Shl, &TokenKind::Lt) { // Account for `<<<<<<<` diff markers. We can't proactively error here because // that can be a valid path start, so we snapshot and reparse only we've // encountered another parse error. @@ -801,10 +820,24 @@ impl<'a> Parser<'a> { &mut self, recover: AttemptLocalParseRecovery, ) -> PResult<'a, Option> { - // Skip looking for a trailing semicolon when we have an interpolated statement. - maybe_whole!(self, NtStmt, |stmt| Some(stmt.into_inner())); + // Skip looking for a trailing semicolon when we have a metavar seq. + if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| { + // Why pass `true` for `force_full_expr`? Statement expressions are less expressive + // than "full" expressions, due to the `STMT_EXPR` restriction, and sometimes need + // parentheses. E.g. the "full" expression `match paren_around_match {} | true` when + // used in statement context must be written `(match paren_around_match {} | true)`. + // However, if the expression we are parsing in this statement context was pasted by a + // declarative macro, it may have come from a "full" expression context, and lack + // these parentheses. So we lift the `STMT_EXPR` restriction to ensure the statement + // will reparse successfully. + this.parse_stmt_without_recovery(false, ForceCollect::No, true) + }) { + let stmt = stmt.expect("an actual statement"); + return Ok(Some(stmt)); + } - let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No)? else { + let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No, false)? + else { return Ok(None); }; diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 8b8c81a77a01a..471966d086d5f 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -2291,7 +2291,7 @@ fn string_to_tts_macro() { Token { kind: token::Ident(name_macro_rules, IdentIsRaw::No), .. }, _, ), - TokenTree::Token(Token { kind: token::Not, .. }, _), + TokenTree::Token(Token { kind: token::Bang, .. }, _), TokenTree::Token(Token { kind: token::Ident(name_zip, IdentIsRaw::No), .. }, _), TokenTree::Delimited(.., macro_delim, macro_tts), ] if name_macro_rules == &kw::MacroRules && name_zip.as_str() == "zip" => { diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs index 40631d9154d37..886438fd583a3 100644 --- a/compiler/rustc_parse/src/parser/token_type.rs +++ b/compiler/rustc_parse/src/parser/token_type.rs @@ -25,7 +25,7 @@ pub enum TokenType { Gt, AndAnd, OrOr, - Not, + Bang, Tilde, // BinOps @@ -172,7 +172,7 @@ impl TokenType { Gt, AndAnd, OrOr, - Not, + Bang, Tilde, Plus, @@ -366,7 +366,7 @@ impl TokenType { TokenType::Gt => "`>`", TokenType::AndAnd => "`&&`", TokenType::OrOr => "`||`", - TokenType::Not => "`!`", + TokenType::Bang => "`!`", TokenType::Tilde => "`~`", TokenType::Plus => "`+`", @@ -445,12 +445,6 @@ macro_rules! exp { token_type: $crate::parser::token_type::TokenType::$tok } }; - (@binop, $op:ident) => { - $crate::parser::token_type::ExpTokenPair { - tok: &rustc_ast::token::BinOp(rustc_ast::token::BinOpToken::$op), - token_type: $crate::parser::token_type::TokenType::$op, - } - }; (@open, $delim:ident, $token_type:ident) => { $crate::parser::token_type::ExpTokenPair { tok: &rustc_ast::token::OpenDelim(rustc_ast::token::Delimiter::$delim), @@ -485,8 +479,13 @@ macro_rules! exp { (Gt) => { exp!(@tok, Gt) }; (AndAnd) => { exp!(@tok, AndAnd) }; (OrOr) => { exp!(@tok, OrOr) }; - (Not) => { exp!(@tok, Not) }; + (Bang) => { exp!(@tok, Bang) }; (Tilde) => { exp!(@tok, Tilde) }; + (Plus) => { exp!(@tok, Plus) }; + (Minus) => { exp!(@tok, Minus) }; + (Star) => { exp!(@tok, Star) }; + (And) => { exp!(@tok, And) }; + (Or) => { exp!(@tok, Or) }; (At) => { exp!(@tok, At) }; (Dot) => { exp!(@tok, Dot) }; (DotDot) => { exp!(@tok, DotDot) }; @@ -502,12 +501,6 @@ macro_rules! exp { (Question) => { exp!(@tok, Question) }; (Eof) => { exp!(@tok, Eof) }; - (Plus) => { exp!(@binop, Plus) }; - (Minus) => { exp!(@binop, Minus) }; - (Star) => { exp!(@binop, Star) }; - (And) => { exp!(@binop, And) }; - (Or) => { exp!(@binop, Or) }; - (OpenParen) => { exp!(@open, Parenthesis, OpenParen) }; (OpenBrace) => { exp!(@open, Brace, OpenBrace) }; (OpenBracket) => { exp!(@open, Bracket, OpenBracket) }; @@ -626,7 +619,7 @@ impl Iterator for TokenTypeSetIter { type Item = TokenType; fn next(&mut self) -> Option { - let num_bits: u32 = (std::mem::size_of_val(&self.0.0) * 8) as u32; + let num_bits: u32 = (size_of_val(&self.0.0) * 8) as u32; assert_eq!(num_bits, 128); let z = self.0.0.trailing_zeros(); if z == num_bits { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 18af0a1c79aa2..b45ebae079cbc 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -1,5 +1,5 @@ use rustc_ast::ptr::P; -use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind}; +use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind}; use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy, @@ -86,7 +86,7 @@ enum AllowCVariadic { /// Types can also be of the form `IDENT(u8, u8) -> u8`, however this assumes /// that `IDENT` is not the ident of a fn trait. fn can_continue_type_after_non_fn_ident(t: &Token) -> bool { - t == &token::PathSep || t == &token::Lt || t == &token::BinOp(token::Shl) + t == &token::PathSep || t == &token::Lt || t == &token::Shl } fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { @@ -260,7 +260,7 @@ impl<'a> Parser<'a> { let mut impl_dyn_multi = false; let kind = if self.check(exp!(OpenParen)) { self.parse_ty_tuple_or_parens(lo, allow_plus)? - } else if self.eat(exp!(Not)) { + } else if self.eat(exp!(Bang)) { // Never type `!` TyKind::Never } else if self.eat(exp!(Star)) { @@ -399,7 +399,7 @@ impl<'a> Parser<'a> { let mut trailing_plus = false; let (ts, trailing) = self.parse_paren_comma_seq(|p| { let ty = p.parse_ty()?; - trailing_plus = p.prev_token == TokenKind::BinOp(token::Plus); + trailing_plus = p.prev_token == TokenKind::Plus; Ok(ty) })?; @@ -735,7 +735,7 @@ impl<'a> Parser<'a> { // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; - *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::BinOp(token::Plus); + *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds)) } @@ -747,11 +747,7 @@ impl<'a> Parser<'a> { self.expect_lt()?; let (args, _, _) = self.parse_seq_to_before_tokens( &[exp!(Gt)], - &[ - &TokenKind::Ge, - &TokenKind::BinOp(BinOpToken::Shr), - &TokenKind::BinOpEq(BinOpToken::Shr), - ], + &[&TokenKind::Ge, &TokenKind::Shr, &TokenKind::Shr], SeqSep::trailing_allowed(exp!(Comma)), |self_| { if self_.check_keyword(exp!(SelfUpper)) { @@ -781,7 +777,7 @@ impl<'a> Parser<'a> { self.check_keyword(exp!(Dyn)) && (self.token.uninterpolated_span().at_least_rust_2018() || self.look_ahead(1, |t| { - (can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::BinOp(token::Star)) + (can_begin_dyn_bound_in_edition_2015(t) || *t == TokenKind::Star) && !can_continue_type_after_non_fn_ident(t) })) } @@ -803,7 +799,7 @@ impl<'a> Parser<'a> { // Always parse bounds greedily for better error recovery. let bounds = self.parse_generic_bounds()?; - *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::BinOp(token::Plus); + *impl_dyn_multi = bounds.len() > 1 || self.prev_token == TokenKind::Plus; Ok(TyKind::TraitObject(bounds, syntax)) } @@ -821,7 +817,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, TyKind> { // Simple path let path = self.parse_path_inner(PathStyle::Type, ty_generics)?; - if self.eat(exp!(Not)) { + if self.eat(exp!(Bang)) { // Macro invocation in type position Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? }))) } else if allow_plus == AllowPlus::Yes && self.check_plus() { @@ -874,7 +870,7 @@ impl<'a> Parser<'a> { fn can_begin_bound(&mut self) -> bool { self.check_path() || self.check_lifetime() - || self.check(exp!(Not)) + || self.check(exp!(Bang)) || self.check(exp!(Question)) || self.check(exp!(Tilde)) || self.check_keyword(exp!(For)) @@ -1025,7 +1021,7 @@ impl<'a> Parser<'a> { let polarity = if self.eat(exp!(Question)) { BoundPolarity::Maybe(self.prev_token.span) - } else if self.eat(exp!(Not)) { + } else if self.eat(exp!(Bang)) { self.psess.gated_spans.gate(sym::negative_bounds, self.prev_token.span); BoundPolarity::Negative(self.prev_token.span) } else { diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml index 707c4e318474a..a39cca716d23e 100644 --- a/compiler/rustc_parse_format/Cargo.toml +++ b/compiler/rustc_parse_format/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_parse_format" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 3b985621b5772..5b8a2fe52d3f5 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -13,7 +13,6 @@ html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub use Alignment::*; @@ -190,7 +189,7 @@ pub enum DebugHex { #[derive(Copy, Clone, Debug, PartialEq)] pub enum Count<'a> { /// The count is specified explicitly. - CountIs(usize), + CountIs(u16), /// The count is specified by the argument with the given name. CountIsName(&'a str, InnerSpan), /// The count is specified by the argument at the given index. @@ -565,7 +564,7 @@ impl<'a> Parser<'a> { /// consuming a macro argument, `None` if it's the case. fn position(&mut self) -> Option> { if let Some(i) = self.integer() { - Some(ArgumentIs(i)) + Some(ArgumentIs(i.into())) } else { match self.cur.peek() { Some(&(lo, c)) if rustc_lexer::is_id_start(c) => { @@ -771,7 +770,7 @@ impl<'a> Parser<'a> { /// width. fn count(&mut self, start: usize) -> Count<'a> { if let Some(i) = self.integer() { - if self.consume('$') { CountIsParam(i) } else { CountIs(i) } + if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } } else { let tmp = self.cur.clone(); let word = self.word(); @@ -822,15 +821,15 @@ impl<'a> Parser<'a> { word } - fn integer(&mut self) -> Option { - let mut cur: usize = 0; + fn integer(&mut self) -> Option { + let mut cur: u16 = 0; let mut found = false; let mut overflow = false; let start = self.current_pos(); while let Some(&(_, c)) = self.cur.peek() { if let Some(i) = c.to_digit(10) { let (tmp, mul_overflow) = cur.overflowing_mul(10); - let (tmp, add_overflow) = tmp.overflowing_add(i as usize); + let (tmp, add_overflow) = tmp.overflowing_add(i as u16); if mul_overflow || add_overflow { overflow = true; } @@ -847,11 +846,11 @@ impl<'a> Parser<'a> { let overflowed_int = &self.input[start..end]; self.err( format!( - "integer `{}` does not fit into the type `usize` whose range is `0..={}`", + "integer `{}` does not fit into the type `u16` whose range is `0..={}`", overflowed_int, - usize::MAX + u16::MAX ), - "integer out of range for `usize`", + "integer out of range for `u16`", self.span(start, end), ); } diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml index f592a12ab75c1..ba81ef3103bd9 100644 --- a/compiler/rustc_passes/Cargo.toml +++ b/compiler/rustc_passes/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_passes" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 978cb7af2427f..ed498d9d34429 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -311,9 +311,6 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} -passes_empty_confusables = - expected at least one confusable name - passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static @@ -365,9 +362,6 @@ passes_incorrect_do_not_recommend_args = passes_incorrect_do_not_recommend_location = `#[diagnostic::do_not_recommend]` can only be placed on trait implementations -passes_incorrect_meta_item = expected a quoted string literal -passes_incorrect_meta_item_suggestion = consider surrounding this with quotes - passes_incorrect_target = `{$name}` lang item must be applied to a {$kind} with {$at_least -> [true] at least {$num} @@ -641,13 +635,12 @@ passes_repr_align_greater_than_target_max = passes_repr_conflicting = conflicting representation hints -passes_repr_ident = - meta item in `repr` must be an identifier - passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` .label = not a `const fn` +passes_rustc_const_stable_indirect_pairing = + `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled @@ -732,6 +725,12 @@ passes_target_feature_on_statement = .warn = {-passes_previously_accepted} .label = {passes_should_be_applied_to_fn.label} +passes_trait_impl_const_stability_mismatch = const stability on the impl does not match the const stability on the trait +passes_trait_impl_const_stability_mismatch_impl_stable = this impl is (implicitly) stable... +passes_trait_impl_const_stability_mismatch_impl_unstable = this impl is unstable... +passes_trait_impl_const_stability_mismatch_trait_stable = ...but the trait is stable +passes_trait_impl_const_stability_mismatch_trait_unstable = ...but the trait is unstable + passes_trait_impl_const_stable = trait implementations cannot be const stable yet .note = see issue #67792 for more information @@ -774,16 +773,16 @@ passes_unreachable_due_to_uninhabited = unreachable {$descr} passes_unrecognized_field = unrecognized field name `{$name}` -passes_unrecognized_repr_hint = - unrecognized representation hint - .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` - passes_unstable_attr_for_already_stable_feature = can't mark as unstable using an already stable feature .label = this feature is already stable .item = the stability attribute annotates this item .help = consider removing the attribute +passes_unsupported_attributes_in_where = + most attributes are not supported in `where` clauses + .help = only `#[cfg]` and `#[cfg_attr]` are supported + passes_unused = unused attribute .suggestion = remove this attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 9a4db612cfed8..ece5a53aaa9c4 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1,3 +1,4 @@ +// FIXME(jdonszelmann): should become rustc_attr_validation //! This module implements some validity checks for attributes. //! In particular it verifies that `#[inline]` and `#[repr]` attributes are //! attached to items that actually support them and if there are @@ -7,16 +8,18 @@ use std::cell::Cell; use std::collections::hash_map::Entry; -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; +use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalModDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ - self as hir, self, AssocItemKind, AttrKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, - ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem, + self as hir, self, AssocItemKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem, + HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem, }; use rustc_macros::LintDiagnostic; use rustc_middle::hir::nested_filter; @@ -49,7 +52,7 @@ fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) hir::ImplItemKind::Const(..) => Target::AssocConst, hir::ImplItemKind::Fn(..) => { let parent_def_id = tcx.hir_get_parent_item(impl_item.hir_id()).def_id; - let containing_item = tcx.hir().expect_item(parent_def_id); + let containing_item = tcx.hir_expect_item(parent_def_id); let containing_impl_is_for_trait = match &containing_item.kind { hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(), _ => bug!("parent of an ImplItem must be an Impl"), @@ -78,13 +81,13 @@ pub(crate) enum ProcMacroKind { } impl IntoDiagArg for ProcMacroKind { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { match self { ProcMacroKind::Attribute => "attribute proc macro", ProcMacroKind::Derive => "derive proc macro", ProcMacroKind::FunctionLike => "function-like proc macro", } - .into_diag_arg() + .into_diag_arg(&mut None) } } @@ -111,192 +114,206 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut doc_aliases = FxHashMap::default(); let mut specified_inline = None; let mut seen = FxHashMap::default(); - let attrs = self.tcx.hir().attrs(hir_id); + let attrs = self.tcx.hir_attrs(hir_id); for attr in attrs { - match attr.path().as_slice() { - [sym::diagnostic, sym::do_not_recommend, ..] => { - self.check_do_not_recommend(attr.span, hir_id, target, attr, item) - } - [sym::diagnostic, sym::on_unimplemented, ..] => { - self.check_diagnostic_on_unimplemented(attr.span, hir_id, target) - } - [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), - [sym::coverage, ..] => self.check_coverage(attr, span, target), - [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target), - [sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target), - [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item), - [sym::marker, ..] => self.check_marker(hir_id, attr, span, target), - [sym::target_feature, ..] => { - self.check_target_feature(hir_id, attr, span, target, attrs) - } - [sym::thread_local, ..] => self.check_thread_local(attr, span, target), - [sym::track_caller, ..] => { - self.check_track_caller(hir_id, attr.span, attrs, span, target) - } - [sym::doc, ..] => self.check_doc_attrs( - attr, - hir_id, - target, - &mut specified_inline, - &mut doc_aliases, - ), - [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), - [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target), - [sym::rustc_layout_scalar_valid_range_start, ..] - | [sym::rustc_layout_scalar_valid_range_end, ..] => { - self.check_rustc_layout_scalar_valid_range(attr, span, target) - } - [sym::allow_internal_unstable, ..] => { - self.check_allow_internal_unstable(hir_id, attr, span, target, attrs) - } - [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), - [sym::rustc_allow_const_fn_unstable, ..] => { - self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) - } - [sym::rustc_std_internal_symbol, ..] => { - self.check_rustc_std_internal_symbol(attr, span, target) - } - [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), - [sym::rustc_as_ptr, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_never_returns_null_ptr, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_legacy_const_generics, ..] => { - self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) - } - [sym::rustc_lint_query_instability, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_lint_untracked_query_information, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_lint_diagnostics, ..] => { - self.check_applied_to_fn_or_method(hir_id, attr, span, target) - } - [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target), - [sym::rustc_lint_opt_deny_field_access, ..] => { - self.check_rustc_lint_opt_deny_field_access(attr, span, target) - } - [sym::rustc_clean, ..] - | [sym::rustc_dirty, ..] - | [sym::rustc_if_this_changed, ..] - | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), - [sym::rustc_coinductive, ..] - | [sym::rustc_must_implement_one_of, ..] - | [sym::rustc_deny_explicit_impl, ..] - | [sym::rustc_do_not_implement_via_object, ..] - | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), - [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), - [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), - [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), - [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr), - [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), - [sym::rustc_allow_incoherent_impl, ..] => { - self.check_allow_incoherent_impl(attr, span, target) - } - [sym::rustc_has_incoherent_inherent_impls, ..] => { - self.check_has_incoherent_inherent_impls(attr, span, target) - } - [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span, attrs, target), - [sym::ffi_const, ..] => self.check_ffi_const(attr.span, target), - [sym::rustc_const_unstable, ..] - | [sym::rustc_const_stable, ..] - | [sym::unstable, ..] - | [sym::stable, ..] - | [sym::rustc_allowed_through_unstable_modules, ..] - | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target), - [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), - [sym::rustc_confusables, ..] => self.check_confusables(attr, target), - [sym::cold, ..] => self.check_cold(hir_id, attr, span, target), - [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), - [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), - [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), - [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target), - [sym::macro_use, ..] | [sym::macro_escape, ..] => { - self.check_macro_use(hir_id, attr, target) - } - [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod), - [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), - [sym::ignore, ..] | [sym::should_panic, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Fn) - } - [sym::automatically_derived, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Impl) - } - [sym::no_implicit_prelude, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Mod) - } - [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id), - [sym::proc_macro, ..] => { - self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) - } - [sym::proc_macro_attribute, ..] => { - self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); - } - [sym::proc_macro_derive, ..] => { - self.check_generic_attr(hir_id, attr, target, Target::Fn); - self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) - } - [sym::autodiff, ..] => { - self.check_autodiff(hir_id, attr, span, target) - } - [sym::coroutine, ..] => { - self.check_coroutine(attr, target); - } - [sym::linkage, ..] => self.check_linkage(attr, span, target), - [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs), - [ - // ok - sym::allow - | sym::expect - | sym::warn - | sym::deny - | sym::forbid - | sym::cfg - | sym::cfg_attr - // need to be fixed - | sym::cfi_encoding // FIXME(cfi_encoding) - | sym::pointee // FIXME(derive_coerce_pointee) - | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) - | sym::used // handled elsewhere to restrict to static items - | sym::repr // handled elsewhere to restrict to type decls items - | sym::instruction_set // broken on stable!!! - | sym::windows_subsystem // broken on stable!!! - | sym::patchable_function_entry // FIXME(patchable_function_entry) - | sym::deprecated_safe // FIXME(deprecated_safe) - // internal - | sym::prelude_import - | sym::panic_handler - | sym::allow_internal_unsafe - | sym::fundamental - | sym::lang - | sym::needs_allocator - | sym::default_lib_allocator - | sym::custom_mir, - .. - ] => {} - [name, ..] => { - match BUILTIN_ATTRIBUTE_MAP.get(name) { - // checked below - Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} - Some(_) => { - // FIXME: differentiate between unstable and internal attributes just - // like we do with features instead of just accepting `rustc_` - // attributes by name. That should allow trimming the above list, too. - if !name.as_str().starts_with("rustc_") { - span_bug!( - attr.span, - "builtin attribute {name:?} not handled by `CheckAttrVisitor`" - ) + match attr { + Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => { + self.check_confusables(*first_span, target); + } + Attribute::Parsed( + AttributeKind::Stability { span, .. } + | AttributeKind::ConstStability { span, .. }, + ) => self.check_stability_promotable(*span, target), + Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self + .check_allow_internal_unstable( + hir_id, + syms.first().unwrap().1, + span, + target, + attrs, + ), + _ => { + match attr.path().as_slice() { + [sym::diagnostic, sym::do_not_recommend, ..] => { + self.check_do_not_recommend(attr.span(), hir_id, target, attr, item) + } + [sym::diagnostic, sym::on_unimplemented, ..] => { + self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) + } + [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), + [sym::coverage, ..] => self.check_coverage(attr, span, target), + [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target), + [sym::no_sanitize, ..] => { + self.check_no_sanitize(attr, span, target) + } + [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item), + [sym::marker, ..] => self.check_marker(hir_id, attr, span, target), + [sym::target_feature, ..] => { + self.check_target_feature(hir_id, attr, span, target, attrs) + } + [sym::thread_local, ..] => self.check_thread_local(attr, span, target), + [sym::track_caller, ..] => { + self.check_track_caller(hir_id, attr.span(), attrs, span, target) + } + [sym::doc, ..] => self.check_doc_attrs( + attr, + hir_id, + target, + &mut specified_inline, + &mut doc_aliases, + ), + [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target), + [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target), + [sym::rustc_layout_scalar_valid_range_start, ..] + | [sym::rustc_layout_scalar_valid_range_end, ..] => { + self.check_rustc_layout_scalar_valid_range(attr, span, target) + } + [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), + [sym::rustc_allow_const_fn_unstable, ..] => { + self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) + } + [sym::rustc_std_internal_symbol, ..] => { + self.check_rustc_std_internal_symbol(attr, span, target) + } + [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs), + [sym::rustc_as_ptr, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_never_returns_null_ptr, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_legacy_const_generics, ..] => { + self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item) + } + [sym::rustc_lint_query_instability, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_lint_untracked_query_information, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_lint_diagnostics, ..] => { + self.check_applied_to_fn_or_method(hir_id, attr, span, target) + } + [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target), + [sym::rustc_lint_opt_deny_field_access, ..] => { + self.check_rustc_lint_opt_deny_field_access(attr, span, target) + } + [sym::rustc_clean, ..] + | [sym::rustc_dirty, ..] + | [sym::rustc_if_this_changed, ..] + | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr), + [sym::rustc_coinductive, ..] + | [sym::rustc_must_implement_one_of, ..] + | [sym::rustc_deny_explicit_impl, ..] + | [sym::rustc_do_not_implement_via_object, ..] + | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target), + [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target), + [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target), + [sym::must_use, ..] => self.check_must_use(hir_id, attr, target), + [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr), + [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target), + [sym::rustc_allow_incoherent_impl, ..] => { + self.check_allow_incoherent_impl(attr, span, target) + } + [sym::rustc_has_incoherent_inherent_impls, ..] => { + self.check_has_incoherent_inherent_impls(attr, span, target) + } + [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target), + [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), + [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), + [sym::cold, ..] => self.check_cold(hir_id, attr, span, target), + [sym::link, ..] => self.check_link(hir_id, attr, span, target), + [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), + [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), + [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), + [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target), + [sym::macro_use, ..] | [sym::macro_escape, ..] => { + self.check_macro_use(hir_id, attr, target) + } + [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod), + [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target), + [sym::ignore, ..] | [sym::should_panic, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Fn) + } + [sym::automatically_derived, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Impl) + } + [sym::no_implicit_prelude, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Mod) + } + [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id), + [sym::proc_macro, ..] => { + self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike) + } + [sym::proc_macro_attribute, ..] => { + self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute); + } + [sym::proc_macro_derive, ..] => { + self.check_generic_attr(hir_id, attr, target, Target::Fn); + self.check_proc_macro(hir_id, target, ProcMacroKind::Derive) + } + [sym::autodiff, ..] => { + self.check_autodiff(hir_id, attr, span, target) + } + [sym::coroutine, ..] => { + self.check_coroutine(attr, target); + } + [sym::type_const, ..] => { + self.check_type_const(hir_id,attr, target); + } + [sym::linkage, ..] => self.check_linkage(attr, span, target), + [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span(), span, attrs), + [ + // ok + sym::allow + | sym::expect + | sym::warn + | sym::deny + | sym::forbid + | sym::cfg + | sym::cfg_attr + // need to be fixed + | sym::cfi_encoding // FIXME(cfi_encoding) + | sym::pointee // FIXME(derive_coerce_pointee) + | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) + | sym::used // handled elsewhere to restrict to static items + | sym::repr // handled elsewhere to restrict to type decls items + | sym::instruction_set // broken on stable!!! + | sym::windows_subsystem // broken on stable!!! + | sym::patchable_function_entry // FIXME(patchable_function_entry) + | sym::deprecated_safe // FIXME(deprecated_safe) + // internal + | sym::prelude_import + | sym::panic_handler + | sym::allow_internal_unsafe + | sym::fundamental + | sym::lang + | sym::needs_allocator + | sym::default_lib_allocator + | sym::custom_mir, + .. + ] => {} + [name, ..] => { + match BUILTIN_ATTRIBUTE_MAP.get(name) { + // checked below + Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {} + Some(_) => { + // FIXME: differentiate between unstable and internal attributes just + // like we do with features instead of just accepting `rustc_` + // attributes by name. That should allow trimming the above list, too. + if !name.as_str().starts_with("rustc_") { + span_bug!( + attr.span(), + "builtin attribute {name:?} not handled by `CheckAttrVisitor`" + ) + } + } + None => (), } } - None => (), + [] => unreachable!(), } } - [] => unreachable!(), } let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); @@ -305,17 +322,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)) { - match attr.style { + match attr.style() { ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::OuterCrateLevelAttr, ), ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::InnerCrateLevelAttr, ), } @@ -338,16 +355,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::IgnoredAttrWithMacro { sym }, ); } - fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { + fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr_span, errors::IgnoredAttr { sym }, ); } @@ -407,7 +424,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::IgnoredInlineAttrFnProto, ) } @@ -418,7 +435,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::AssocConst => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::IgnoredInlineAttrConstants, ), // FIXME(#80564): Same for fields, arms, and macro defs @@ -427,7 +444,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::InlineNotFnOrClosure { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, }); } @@ -459,7 +476,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } self.dcx().emit_err(errors::CoverageAttributeNotAllowed { - attr_span: attr.span, + attr_span: attr.span(), not_fn_impl_mod, no_body, help: (), @@ -477,7 +494,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); if !is_valid { self.dcx().emit_err(errors::OptimizeInvalidTarget { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -528,7 +545,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::OnlyHasEffectOn { attr_name: attr.name_or_empty(), target_name: allowed_target.name().replace(' ', "_"), @@ -568,6 +585,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::warn, sym::deny, sym::forbid, + // FIXME(jdonszelmann): not used, because already a new-style attr (ugh) sym::deprecated, sym::must_use, // abi, linking and FFI @@ -595,10 +613,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { continue; } + // FIXME(jdonszelmann): once naked uses new-style parsing, + // this check can be part of the parser and be removed here + match other_attr { + Attribute::Parsed( + AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. }, + ) => { + continue; + } + _ => {} + } + if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { - span: other_attr.span, - naked_span: attr.span, + span: other_attr.span(), + naked_span: attr.span(), attr: other_attr.name_or_empty(), }); @@ -615,7 +644,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -648,9 +677,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::MacroDef => {} _ => { - self.tcx - .dcx() - .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span }); + self.tcx.dcx().emit_err(errors::CollapseDebuginfo { + attr_span: attr.span(), + defn_span: span, + }); } } } @@ -720,7 +750,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && fields.iter().any(|f| f.default.is_some()) { self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, }); } @@ -735,7 +765,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::NonExhaustiveWrongLocation { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, }); } @@ -755,7 +785,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, }); } @@ -784,7 +814,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap(); self.dcx().emit_err(errors::LangItemWithTargetFeature { - attr_span: attr.span, + attr_span: attr.span(), name: lang_item, sig_span: sig.span, }); @@ -796,7 +826,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::TargetFeatureOnStatement, ); } @@ -809,7 +839,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -823,7 +853,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::ForeignStatic | Target::Static => {} _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, }); } @@ -869,7 +899,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(location) = match target { Target::AssocTy => { let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id; - let containing_item = self.tcx.hir().expect_item(parent_def_id); + let containing_item = self.tcx.hir_expect_item(parent_def_id); if Target::from_item(containing_item) == Target::Impl { Some("type alias in implementation block") } else { @@ -878,7 +908,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } Target::AssocConst => { let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id; - let containing_item = self.tcx.hir().expect_item(parent_def_id); + let containing_item = self.tcx.hir_expect_item(parent_def_id); // We can't link to trait impl's consts. let err = "associated constant in trait implementation block"; match containing_item.kind { @@ -893,7 +923,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::Arm | Target::ForeignMod | Target::Closure - | Target::Impl => Some(target.name()), + | Target::Impl + | Target::WherePredicate => Some(target.name()), Target::ExternCrate | Target::Use | Target::Static @@ -921,7 +952,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location }); return; } - let item_name = self.tcx.hir().name(hir_id); + let item_name = self.tcx.hir_name(hir_id); if item_name == doc_alias { tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str }); return; @@ -1093,7 +1124,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocInlineOnlyUse { attr_span: meta.span(), - item_span: (attr.style == AttrStyle::Outer) + item_span: (attr.style() == AttrStyle::Outer) .then(|| self.tcx.hir().span(hir_id)), }, ); @@ -1115,7 +1146,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocMaskedOnlyExternCrate { attr_span: meta.span(), - item_span: (attr.style == AttrStyle::Outer) + item_span: (attr.style() == AttrStyle::Outer) .then(|| self.tcx.hir().span(hir_id)), }, ); @@ -1129,7 +1160,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { meta.span(), errors::DocMaskedNotExternCrateSelf { attr_span: meta.span(), - item_span: (attr.style == AttrStyle::Outer) + item_span: (attr.style() == AttrStyle::Outer) .then(|| self.tcx.hir().span(hir_id)), }, ); @@ -1159,11 +1190,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) -> bool { if hir_id != CRATE_HIR_ID { // insert a bang between `#` and `[...` - let bang_span = attr.span.lo() + BytePos(1); - let sugg = (attr.style == AttrStyle::Outer + let bang_span = attr.span().lo() + BytePos(1); + let sugg = (attr.style() == AttrStyle::Outer && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID) .then_some(errors::AttrCrateLevelOnlySugg { - attr: attr.span.with_lo(bang_span).with_hi(bang_span), + attr: attr.span().with_lo(bang_span).with_hi(bang_span), }); self.tcx.emit_node_span_lint( INVALID_DOC_ATTRIBUTES, @@ -1337,11 +1368,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { errors::DocTestUnknownInclude { path, value: value.to_string(), - inner: match attr.style { + inner: match attr.style() { AttrStyle::Inner => "!", AttrStyle::Outer => "", }, - sugg: (attr.span, applicability), + sugg: (attr.span(), applicability), }, ); } else if i_meta.has_name(sym::passes) @@ -1387,7 +1418,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct | Target::Enum | Target::TyAlias => {} _ => { - self.dcx().emit_err(errors::PassByValue { attr_span: attr.span, span }); + self.dcx().emit_err(errors::PassByValue { attr_span: attr.span(), span }); } } } @@ -1396,7 +1427,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Method(MethodKind::Inherent) => {} _ => { - self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span }); + self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span(), span }); } } } @@ -1407,7 +1438,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span }); + .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span(), span }); } } } @@ -1450,7 +1481,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // `#[must_use]` can be applied to a trait method definition with a default body if let Target::Method(MethodKind::Trait { body: true }) = target && let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id - && let containing_item = self.tcx.hir().expect_item(parent_def_id) + && let containing_item = self.tcx.hir_expect_item(parent_def_id) && let hir::ItemKind::Trait(..) = containing_item.kind { return; @@ -1470,7 +1501,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::MustUseNoEffect { article, target }, ); } @@ -1480,7 +1511,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct | Target::Enum | Target::Union | Target::Trait => {} _ => { - self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span, span }); + self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span(), span }); } } } @@ -1503,7 +1534,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { return; } - self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span }); + self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span() }); } /// Checks if `#[cold]` is applied to a non-function. @@ -1523,7 +1554,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID }, ); } @@ -1543,7 +1574,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::Link { span: (target != Target::ForeignMod).then_some(span) }, ); } @@ -1562,19 +1593,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { // FIXME: #[cold] was previously allowed on non-functions/statics and some crates // used this, so only emit a warning. - let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span); + let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span()); if let Some(s) = attr.value_str() { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::LinkName { span, attr_span, value: s.as_str() }, ); } else { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::LinkName { span, attr_span, value: "..." }, ); }; @@ -1594,7 +1625,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link"); } _ => { - self.dcx().emit_err(errors::NoLink { attr_span: attr.span, span }); + self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span }); } } } @@ -1616,7 +1647,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name"); } _ => { - self.dcx().emit_err(errors::ExportName { attr_span: attr.span, span }); + self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span }); } } } @@ -1624,7 +1655,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) { if target != Target::Struct { self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct { - attr_span: attr.span, + attr_span: attr.span(), span, }); return; @@ -1637,7 +1668,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) { self.tcx .dcx() - .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); + .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() }); } } @@ -1653,7 +1684,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_function = matches!(target, Target::Fn); if !is_function { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -1678,7 +1709,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { hir::GenericParamKind::Const { .. } => {} _ => { self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly { - attr_span: attr.span, + attr_span: attr.span(), param_span: param.span, }); return; @@ -1688,7 +1719,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if list.len() != generics.params.len() { self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex { - attr_span: attr.span, + attr_span: attr.span(), generics_span: generics.span, }); return; @@ -1728,7 +1759,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let is_function = matches!(target, Target::Fn | Target::Method(..)); if !is_function { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, on_crate: hir_id == CRATE_HIR_ID, }); @@ -1740,7 +1771,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Struct => {} _ => { - self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span, span }); + self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span(), span }); } } } @@ -1752,7 +1783,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span }); + .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span }); } } } @@ -1761,7 +1792,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// option is passed to the compiler. fn check_rustc_dirty_clean(&self, attr: &Attribute) { if !self.tcx.sess.opts.unstable_opts.query_dep_graph { - self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span }); + self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span() }); } } @@ -1771,7 +1802,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::Trait => {} _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { - attr_span: attr.span, + attr_span: attr.span(), defn_span: span, }); } @@ -1795,7 +1826,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::LinkSection { span }, ); } @@ -1826,8 +1857,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, - errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind }, + attr.span(), + errors::NoMangleForeign { span, attr_span: attr.span(), foreign_item_kind }, ); } _ => { @@ -1836,7 +1867,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::NoMangle { span }, ); } @@ -1857,12 +1888,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // #[repr(foo)] // #[repr(bar, align(8))] // ``` - let hints: Vec<_> = attrs - .iter() - .filter(|attr| attr.has_name(sym::repr)) - .filter_map(|attr| attr.meta_item_list()) - .flatten() - .collect(); + let reprs = find_attr!(attrs, AttributeKind::Repr(r) => r.as_slice()).unwrap_or(&[]); let mut int_reprs = 0; let mut is_explicit_rust = false; @@ -1870,66 +1896,33 @@ impl<'tcx> CheckAttrVisitor<'tcx> { let mut is_simd = false; let mut is_transparent = false; - // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) - if hints.is_empty() && item.is_some() { - for attr in attrs.iter().filter(|attr| attr.has_name(sym::repr)) { - match target { - Target::Struct | Target::Union | Target::Enum => {} - Target::Fn | Target::Method(_) => { - feature_err( - &self.tcx.sess, - sym::fn_align, - attr.span, - fluent::passes_repr_align_function, - ) - .emit(); - } - _ => { - self.dcx().emit_err( - errors::AttrApplication::StructEnumFunctionMethodUnion { - hint_span: attr.span, - span, - }, - ); - } - } - } - - return; - } - - for hint in &hints { - if !hint.is_meta_item() { - self.dcx().emit_err(errors::ReprIdent { span: hint.span() }); - continue; - } - - match hint.name_or_empty() { - sym::Rust => { + for (repr, repr_span) in reprs { + match repr { + ReprAttr::ReprRust => { is_explicit_rust = true; match target { Target::Struct | Target::Union | Target::Enum => continue, _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: hint.span(), + hint_span: *repr_span, span, }); } } } - sym::C => { + ReprAttr::ReprC => { is_c = true; match target { Target::Struct | Target::Union | Target::Enum => continue, _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: hint.span(), + hint_span: *repr_span, span, }); } } } - sym::align => { + ReprAttr::ReprAlign(align) => { match target { Target::Struct | Target::Union | Target::Enum => {} Target::Fn | Target::Method(_) => { @@ -1937,7 +1930,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { feature_err( &self.tcx.sess, sym::fn_align, - hint.span(), + *repr_span, fluent::passes_repr_align_function, ) .emit(); @@ -1946,83 +1939,97 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.dcx().emit_err( errors::AttrApplication::StructEnumFunctionMethodUnion { - hint_span: hint.span(), + hint_span: *repr_span, span, }, ); } } - self.check_align_value(hint); + self.check_align_value(*align, *repr_span); } - sym::packed => { + ReprAttr::ReprPacked(_) => { if target != Target::Struct && target != Target::Union { self.dcx().emit_err(errors::AttrApplication::StructUnion { - hint_span: hint.span(), + hint_span: *repr_span, span, }); } else { continue; } } - sym::simd => { + ReprAttr::ReprSimd => { is_simd = true; if target != Target::Struct { self.dcx().emit_err(errors::AttrApplication::Struct { - hint_span: hint.span(), + hint_span: *repr_span, span, }); } else { continue; } } - sym::transparent => { + ReprAttr::ReprTransparent => { is_transparent = true; match target { Target::Struct | Target::Union | Target::Enum => continue, _ => { self.dcx().emit_err(errors::AttrApplication::StructEnumUnion { - hint_span: hint.span(), + hint_span: *repr_span, span, }); } } } - sym::i8 - | sym::u8 - | sym::i16 - | sym::u16 - | sym::i32 - | sym::u32 - | sym::i64 - | sym::u64 - | sym::i128 - | sym::u128 - | sym::isize - | sym::usize => { + ReprAttr::ReprInt(_) => { int_reprs += 1; if target != Target::Enum { self.dcx().emit_err(errors::AttrApplication::Enum { - hint_span: hint.span(), + hint_span: *repr_span, span, }); } else { continue; } } - _ => { - self.dcx().emit_err(errors::UnrecognizedReprHint { span: hint.span() }); - continue; + // FIXME(jdonszelmann): move the diagnostic for unused repr attrs here, I think + // it's a better place for it. + ReprAttr::ReprEmpty => { + // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`) + if item.is_some() { + match target { + Target::Struct | Target::Union | Target::Enum => continue, + Target::Fn | Target::Method(_) => { + feature_err( + &self.tcx.sess, + sym::fn_align, + *repr_span, + fluent::passes_repr_align_function, + ) + .emit(); + } + _ => { + self.dcx().emit_err( + errors::AttrApplication::StructEnumFunctionMethodUnion { + hint_span: *repr_span, + span, + }, + ); + } + } + } + + return; } }; } // Just point at all repr hints if there are any incompatibilities. // This is not ideal, but tracking precisely which ones are at fault is a huge hassle. - let hint_spans = hints.iter().map(|hint| hint.span()); + let hint_spans = reprs.iter().map(|(_, span)| *span); // Error on repr(transparent, ). - if is_transparent && hints.len() > 1 { + if is_transparent && reprs.len() > 1 { let hint_spans = hint_spans.clone().collect(); self.dcx().emit_err(errors::TransparentIncompatible { hint_spans, @@ -2051,41 +2058,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - fn check_align_value(&self, item: &MetaItemInner) { - match item.singleton_lit_list() { - Some(( - _, - MetaItemLit { - kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), .. - }, - )) => { - let val = literal.get() as u64; - if val > 2_u64.pow(29) { - // for values greater than 2^29, a different error will be emitted, make sure that happens - self.dcx().span_delayed_bug( - item.span(), - "alignment greater than 2^29 should be errored on elsewhere", - ); - } else { - // only do this check when <= 2^29 to prevent duplicate errors: - // alignment greater than 2^29 not supported - // alignment is too large for the current target - - let max = - Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; - if val > max { - self.dcx().emit_err(errors::InvalidReprAlignForTarget { - span: item.span(), - size: max, - }); - } - } - } + fn check_align_value(&self, align: Align, span: Span) { + if align.bytes() > 2_u64.pow(29) { + // for values greater than 2^29, a different error will be emitted, make sure that happens + self.dcx().span_delayed_bug( + span, + "alignment greater than 2^29 should be errored on elsewhere", + ); + } else { + // only do this check when <= 2^29 to prevent duplicate errors: + // alignment greater than 2^29 not supported + // alignment is too large for the current target - // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None - // but an error will have already been emitted, so this code should just skip such attributes - Some((_, _)) | None => { - self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))"); + let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64; + if align.bytes() > max { + self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max }); } } } @@ -2096,7 +2083,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) { if target != Target::Static { self.dcx().emit_err(errors::UsedStatic { - attr_span: attr.span, + attr_span: attr.span(), span: target_span, target: target.name(), }); @@ -2105,12 +2092,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match inner.as_deref() { Some([item]) if item.has_name(sym::linker) => { if used_linker_span.is_none() { - used_linker_span = Some(attr.span); + used_linker_span = Some(attr.span()); } } Some([item]) if item.has_name(sym::compiler) => { if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span); + used_compiler_span = Some(attr.span()); } } Some(_) => { @@ -2119,7 +2106,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { None => { // Default case (compiler) when arg isn't defined. if used_compiler_span.is_none() { - used_compiler_span = Some(attr.span); + used_compiler_span = Some(attr.span()); } } } @@ -2133,41 +2120,44 @@ impl<'tcx> CheckAttrVisitor<'tcx> { /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. /// (Allows proc_macro functions) + // FIXME(jdonszelmann): if possible, move to attr parsing fn check_allow_internal_unstable( &self, hir_id: HirId, - attr: &Attribute, + attr_span: Span, span: Span, target: Target, attrs: &[Attribute], ) { - debug!("Checking target: {:?}", target); match target { Target::Fn => { for attr in attrs { if attr.is_proc_macro_attr() { - debug!("Is proc macro attr"); + // return on proc macros return; } } - debug!("Is not proc macro attr"); + // continue out of the match } - Target::MacroDef => {} + // return on decl macros + Target::MacroDef => return, // FIXME(#80564): We permit struct fields and match arms to have an // `#[allow_internal_unstable]` attribute with just a lint, because we previously // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. - Target::Field | Target::Arm => self.inline_attr_str_error_without_macro_def( - hir_id, - attr, - "allow_internal_unstable", - ), - _ => { - self.tcx - .dcx() - .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span }); + Target::Field | Target::Arm => { + self.inline_attr_str_error_without_macro_def( + hir_id, + attr_span, + "allow_internal_unstable", + ); + return; } + // otherwise continue out of the match + _ => {} } + + self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span }); } /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. @@ -2179,7 +2169,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Mod => {} _ => { - self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span }); + self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() }); } } } @@ -2206,7 +2196,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span }); + .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span(), span }); } } } @@ -2217,15 +2207,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> { _ => { self.tcx .dcx() - .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span }); + .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span(), span }); } } } - fn check_stability_promotable(&self, attr: &Attribute, target: Target) { + fn check_stability_promotable(&self, span: Span, target: Target) { match target { Target::Expression => { - self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span }); + self.dcx().emit_err(errors::StabilityPromotable { attr_span: span }); } _ => {} } @@ -2235,41 +2225,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::ForeignFn | Target::ForeignStatic => {} _ => { - self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span }); + self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span() }); } } } - fn check_confusables(&self, attr: &Attribute, target: Target) { - match target { - Target::Method(MethodKind::Inherent) => { - let Some(metas) = attr.meta_item_list() else { - return; - }; - - let mut candidates = Vec::new(); - - for meta in metas { - let MetaItemInner::Lit(meta_lit) = meta else { - self.dcx().emit_err(errors::IncorrectMetaItem { - span: meta.span(), - suggestion: errors::IncorrectMetaItemSuggestion { - lo: meta.span().shrink_to_lo(), - hi: meta.span().shrink_to_hi(), - }, - }); - return; - }; - candidates.push(meta_lit.symbol); - } - - if candidates.is_empty() { - self.dcx().emit_err(errors::EmptyConfusables { span: attr.span }); - } - } - _ => { - self.dcx().emit_err(errors::Confusables { attr_span: attr.span }); - } + fn check_confusables(&self, span: Span, target: Target) { + if !matches!(target, Target::Method(MethodKind::Inherent)) { + self.dcx().emit_err(errors::Confusables { attr_span: span }); } } @@ -2279,7 +2242,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::Deprecated, ); } @@ -2295,7 +2258,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::MacroUse { name }, ); } @@ -2307,7 +2270,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::MacroExport::Normal, ); } else if let Some(meta_item_list) = attr.meta_item_list() @@ -2317,7 +2280,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( INVALID_MACRO_EXPORT_ARGUMENTS, hir_id, - attr.span, + attr.span(), errors::MacroExport::TooManyItems, ); } else if meta_item_list[0].name_or_empty() != sym::local_inner_macros { @@ -2337,7 +2300,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::MacroExport::OnDeclMacro, ); } @@ -2345,8 +2308,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) { + // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very + // ugly now but can 100% be removed later. + if let Attribute::Parsed(p) = attr { + match p { + AttributeKind::Repr(reprs) => { + for (r, span) in reprs { + if let ReprAttr::ReprEmpty = r { + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + *span, + errors::Unused { + attr_span: *span, + note: errors::UnusedNote::EmptyList { name: sym::repr }, + }, + ); + } + } + return; + } + _ => {} + } + } + // Warn on useless empty attributes. - let note = if matches!( + let note = if (matches!( attr.name_or_empty(), sym::macro_use | sym::allow @@ -2355,9 +2342,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::deny | sym::forbid | sym::feature - | sym::repr | sym::target_feature - ) && attr.meta_item_list().is_some_and(|list| list.is_empty()) + ) && attr.meta_item_list().is_some_and(|list| list.is_empty())) { errors::UnusedNote::EmptyList { name: attr.name_or_empty() } } else if matches!( @@ -2379,17 +2365,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { }) { if hir_id != CRATE_HIR_ID { - match attr.style { + match attr.style() { ast::AttrStyle::Outer => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::OuterCrateLevelAttr, ), ast::AttrStyle::Inner => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, + attr.span(), errors::InnerCrateLevelAttr, ), }; @@ -2415,8 +2401,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span, - errors::Unused { attr_span: attr.span, note }, + attr.span(), + errors::Unused { attr_span: attr.span(), note }, ); } @@ -2532,11 +2518,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match target { Target::Closure => return, _ => { - self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span }); + self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() }); } } } + fn check_type_const(&self, hir_id: HirId, attr: &Attribute, target: Target) { + let tcx = self.tcx; + if target == Target::AssocConst + && let parent = tcx.parent(hir_id.expect_owner().to_def_id()) + && self.tcx.def_kind(parent) == DefKind::Trait + { + return; + } else { + self.dcx() + .struct_span_err( + attr.span(), + "`#[type_const]` must only be applied to trait associated constants", + ) + .emit(); + } + } + fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) { match target { Target::Fn @@ -2545,18 +2548,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | Target::ForeignStatic | Target::ForeignFn => {} _ => { - self.dcx().emit_err(errors::Linkage { attr_span: attr.span, span }); + self.dcx().emit_err(errors::Linkage { attr_span: attr.span(), span }); } } } fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) { - if !attrs - .iter() - .filter(|attr| attr.has_name(sym::repr)) - .filter_map(|attr| attr.meta_item_list()) - .flatten() - .any(|nmi| nmi.has_name(sym::transparent)) + if !find_attr!(attrs, AttributeKind::Repr(r) => r.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent)) + .unwrap_or(false) { self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span }); } @@ -2573,7 +2572,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { match (target, force_inline_attr) { (Target::Closure, None) => { let is_coro = matches!( - self.tcx.hir().expect_expr(hir_id).kind, + self.tcx.hir_expect_expr(hir_id).kind, hir::ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Coroutine(..) | hir::ClosureKind::CoroutineClosure(..), @@ -2588,14 +2587,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { && is_coro { self.dcx().emit_err(errors::RustcForceInlineCoro { - attr_span: attr.span, + attr_span: attr.span(), span: parent_span, }); } } (Target::Fn, _) => (), (_, Some(attr)) => { - self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span, span }); + self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span(), span }); } (_, None) => (), } @@ -2637,6 +2636,31 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_item(self, item) } + fn visit_where_predicate(&mut self, where_predicate: &'tcx hir::WherePredicate<'tcx>) { + // FIXME(where_clause_attrs): Currently, as the following check shows, + // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed + // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`) + // in where clauses. After that, only `self.check_attributes` should be enough. + const ATTRS_ALLOWED: &[Symbol] = &[sym::cfg, sym::cfg_attr]; + let spans = self + .tcx + .hir_attrs(where_predicate.hir_id) + .iter() + .filter(|attr| !ATTRS_ALLOWED.iter().any(|&sym| attr.has_name(sym))) + .map(|attr| attr.span()) + .collect::>(); + if !spans.is_empty() { + self.tcx.dcx().emit_err(errors::UnsupportedAttributesInWhere { span: spans.into() }); + } + self.check_attributes( + where_predicate.hir_id, + where_predicate.span, + Target::WherePredicate, + None, + ); + intravisit::walk_where_predicate(self, where_predicate) + } + fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) { let target = Target::from_generic_param(generic_param); self.check_attributes(generic_param.hir_id, generic_param.span, target, None); @@ -2733,7 +2757,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { // resolution for the attribute macro error. const ATTRS_TO_CHECK: &[Symbol] = &[ sym::macro_export, - sym::repr, sym::path, sym::automatically_derived, sym::rustc_main, @@ -2745,57 +2768,56 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { ]; for attr in attrs { - // This function should only be called with crate attributes - // which are inner attributes always but lets check to make sure - if attr.style == AttrStyle::Inner { - for attr_to_check in ATTRS_TO_CHECK { - if attr.has_name(*attr_to_check) { - let item = tcx - .hir_free_items() - .map(|id| tcx.hir_item(id)) - .find(|item| !item.span.is_dummy()) // Skip prelude `use`s - .map(|item| errors::ItemFollowingInnerAttr { - span: item.ident.span, - kind: item.kind.descr(), - }); - let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel { - span: attr.span, - sugg_span: tcx - .sess - .source_map() - .span_to_snippet(attr.span) - .ok() - .filter(|src| src.starts_with("#![")) - .map(|_| { - attr.span - .with_lo(attr.span.lo() + BytePos(1)) - .with_hi(attr.span.lo() + BytePos(2)) - }), - name: *attr_to_check, - item, - }); + // FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day. + let (span, name) = if let Some(a) = + ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check)) + { + (attr.span(), *a) + } else if let Attribute::Parsed(AttributeKind::Repr(r)) = attr { + (r.first().unwrap().1, sym::repr) + } else { + continue; + }; - if let AttrKind::Normal(ref p) = attr.kind { - tcx.dcx().try_steal_replace_and_emit_err( - p.path.span, - StashKey::UndeterminedMacroResolution, - err, - ); - } else { - err.emit(); - } - } - } + let item = tcx + .hir_free_items() + .map(|id| tcx.hir_item(id)) + .find(|item| !item.span.is_dummy()) // Skip prelude `use`s + .map(|item| errors::ItemFollowingInnerAttr { + span: item.ident.span, + kind: item.kind.descr(), + }); + let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel { + span, + sugg_span: tcx + .sess + .source_map() + .span_to_snippet(span) + .ok() + .filter(|src| src.starts_with("#![")) + .map(|_| span.with_lo(span.lo() + BytePos(1)).with_hi(span.lo() + BytePos(2))), + name, + item, + }); + + if let Attribute::Unparsed(p) = attr { + tcx.dcx().try_steal_replace_and_emit_err( + p.path.span, + StashKey::UndeterminedMacroResolution, + err, + ); + } else { + err.emit(); } } } fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { - let attrs = tcx.hir().attrs(item.hir_id()); + let attrs = tcx.hir_attrs(item.hir_id()); for attr in attrs { if attr.has_name(sym::inline) { - tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span }); + tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span() }); } } } @@ -2833,10 +2855,10 @@ fn check_duplicates( match seen.entry(attr.name_or_empty()) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, FutureWarnPreceding) { - let to_remove = entry.insert(attr.span); - (to_remove, attr.span) + let to_remove = entry.insert(attr.span()); + (to_remove, attr.span()) } else { - (attr.span, *entry.get()) + (attr.span(), *entry.get()) }; tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, @@ -2853,17 +2875,17 @@ fn check_duplicates( ); } Entry::Vacant(entry) => { - entry.insert(attr.span); + entry.insert(attr.span()); } } } ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) { Entry::Occupied(mut entry) => { let (this, other) = if matches!(duplicates, ErrorPreceding) { - let to_remove = entry.insert(attr.span); - (to_remove, attr.span) + let to_remove = entry.insert(attr.span()); + (to_remove, attr.span()) } else { - (attr.span, *entry.get()) + (attr.span(), *entry.get()) }; tcx.dcx().emit_err(errors::UnusedMultiple { this, @@ -2872,7 +2894,7 @@ fn check_duplicates( }); } Entry::Vacant(entry) => { - entry.insert(attr.span); + entry.insert(attr.span()); } }, } diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 7b4fecf2ed193..7029c60c3439b 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -184,7 +184,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { rhs: &'tcx hir::Expr<'tcx>, ) -> bool { match (&lhs.kind, &rhs.kind) { - (hir::ExprKind::Path(ref qpath_l), hir::ExprKind::Path(ref qpath_r)) => { + (hir::ExprKind::Path(qpath_l), hir::ExprKind::Path(qpath_r)) => { if let (Res::Local(id_l), Res::Local(id_r)) = ( typeck_results.qpath_res(qpath_l, lhs.hir_id), typeck_results.qpath_res(qpath_r, rhs.hir_id), @@ -361,7 +361,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { self.tcx.hir_fn_sig_by_hir_id(self.tcx.local_def_id_to_hir_id(local_def_id)) && matches!(fn_sig.decl.implicit_self, hir::ImplicitSelfKind::None) && let TyKind::Path(hir::QPath::Resolved(_, path)) = - self.tcx.hir().expect_item(local_impl_of).expect_impl().self_ty.kind + self.tcx.hir_expect_item(local_impl_of).expect_impl().self_ty.kind && let Res::Def(def_kind, did) = path.res { match def_kind { @@ -424,7 +424,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { for impl_def_id in self.tcx.all_impls(item.owner_id.to_def_id()) { if let Some(local_def_id) = impl_def_id.as_local() && let ItemKind::Impl(impl_ref) = - self.tcx.hir().expect_item(local_def_id).kind + self.tcx.hir_expect_item(local_def_id).kind { // skip items // mark dependent traits live @@ -448,7 +448,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { for impl_id in self.tcx.all_impls(trait_id) { if let Some(local_impl_id) = impl_id.as_local() && let ItemKind::Impl(impl_ref) = - self.tcx.hir().expect_item(local_impl_id).kind + self.tcx.hir_expect_item(local_impl_id).kind { if !matches!(trait_item.kind, hir::TraitItemKind::Type(..)) && !ty_ref_to_pub_struct(self.tcx, impl_ref.self_ty) diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 323b414cca04c..e13d94c1031ac 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -19,7 +19,7 @@ use rustc_span::{Symbol, sym}; use crate::errors::DuplicateDiagnosticItemInCrate; fn observe_item<'tcx>(tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, owner: OwnerId) { - let attrs = tcx.hir().attrs(owner.into()); + let attrs = tcx.hir_attrs(owner.into()); if let Some(name) = extract(attrs) { // insert into our table collect_item(tcx, diagnostic_items, name, owner.to_def_id()); diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index c2225ea1e642d..d2729876ebbb4 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -31,7 +31,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } // If the user wants no main function at all, then stop here. - if attr::contains_name(tcx.hir().attrs(CRATE_HIR_ID), sym::no_main) { + if attr::contains_name(tcx.hir_attrs(CRATE_HIR_ID), sym::no_main) { return None; } @@ -45,8 +45,8 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { } fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option { - let attrs = ctxt.tcx.hir().attrs(id.hir_id()); - attr::find_by_name(attrs, sym).map(|attr| attr.span) + let attrs = ctxt.tcx.hir_attrs(id.hir_id()); + attr::find_by_name(attrs, sym).map(|attr| attr.span()) } fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { @@ -61,7 +61,7 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID); - let attrs = ctxt.tcx.hir().attrs(id.hir_id()); + let attrs = ctxt.tcx.hir_attrs(id.hir_id()); let entry_point_type = rustc_ast::entry::entry_point_type( attrs, at_root, diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9bcdd2385470c..b8359c27e538f 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -582,13 +582,6 @@ pub(crate) struct NoMangle { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_repr_ident, code = E0565)] -pub(crate) struct ReprIdent { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] #[diag(passes_repr_conflicting, code = E0566)] pub(crate) struct ReprConflicting { @@ -736,31 +729,6 @@ pub(crate) struct Linkage { pub span: Span, } -#[derive(Diagnostic)] -#[diag(passes_empty_confusables)] -pub(crate) struct EmptyConfusables { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_incorrect_meta_item, code = E0539)] -pub(crate) struct IncorrectMetaItem { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub suggestion: IncorrectMetaItemSuggestion, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(passes_incorrect_meta_item_suggestion, applicability = "maybe-incorrect")] -pub(crate) struct IncorrectMetaItemSuggestion { - #[suggestion_part(code = "\"")] - pub lo: Span, - #[suggestion_part(code = "\"")] - pub hi: Span, -} - #[derive(Diagnostic)] #[diag(passes_stability_promotable)] pub(crate) struct StabilityPromotable { @@ -1037,10 +1005,10 @@ pub(crate) struct LayoutHomogeneousAggregate { #[derive(Diagnostic)] #[diag(passes_layout_of)] -pub(crate) struct LayoutOf { +pub(crate) struct LayoutOf<'tcx> { #[primary_span] pub span: Span, - pub normalized_ty: String, + pub normalized_ty: Ty<'tcx>, pub ty_layout: String, } @@ -1475,14 +1443,6 @@ pub(crate) struct ObjectLifetimeErr { pub repr: String, } -#[derive(Diagnostic)] -#[diag(passes_unrecognized_repr_hint, code = E0552)] -#[help] -pub(crate) struct UnrecognizedReprHint { - #[primary_span] - pub span: Span, -} - #[derive(Diagnostic)] pub(crate) enum AttrApplication { #[diag(passes_attr_application_enum, code = E0517)] @@ -1592,6 +1552,45 @@ pub(crate) struct TraitImplConstStable { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes_trait_impl_const_stability_mismatch)] +pub(crate) struct TraitImplConstStabilityMismatch { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub impl_stability: ImplConstStability, + #[subdiagnostic] + pub trait_stability: TraitConstStability, +} + +#[derive(Subdiagnostic)] +pub(crate) enum TraitConstStability { + #[note(passes_trait_impl_const_stability_mismatch_trait_stable)] + Stable { + #[primary_span] + span: Span, + }, + #[note(passes_trait_impl_const_stability_mismatch_trait_unstable)] + Unstable { + #[primary_span] + span: Span, + }, +} + +#[derive(Subdiagnostic)] +pub(crate) enum ImplConstStability { + #[note(passes_trait_impl_const_stability_mismatch_impl_stable)] + Stable { + #[primary_span] + span: Span, + }, + #[note(passes_trait_impl_const_stability_mismatch_impl_unstable)] + Unstable { + #[primary_span] + span: Span, + }, +} + #[derive(Diagnostic)] #[diag(passes_unknown_feature, code = E0635)] pub(crate) struct UnknownFeature { @@ -1902,3 +1901,19 @@ pub(crate) struct NoSanitize<'a> { pub accepted_kind: &'a str, pub attr_str: &'a str, } + +// FIXME(jdonszelmann): move back to rustc_attr +#[derive(Diagnostic)] +#[diag(passes_rustc_const_stable_indirect_pairing)] +pub(crate) struct RustcConstStableIndirectPairing { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(passes_unsupported_attributes_in_where)] +#[help] +pub(crate) struct UnsupportedAttributesInWhere { + #[primary_span] + pub span: MultiSpan, +} diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index 509c2f5477524..84b92d49f24c2 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -60,19 +60,18 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { .expect("owning item has no entry"); if max != self.hir_ids_seen.len() - 1 { - let hir = self.tcx.hir(); let pretty_owner = self.tcx.hir_def_path(owner.def_id).to_string_no_crate_verbose(); let missing_items: Vec<_> = (0..=max as u32) .map(|i| ItemLocalId::from_u32(i)) .filter(|&local_id| !self.hir_ids_seen.contains(local_id)) - .map(|local_id| hir.node_to_string(HirId { owner, local_id })) + .map(|local_id| self.tcx.hir_id_to_string(HirId { owner, local_id })) .collect(); let seen_items: Vec<_> = self .hir_ids_seen .iter() - .map(|local_id| hir.node_to_string(HirId { owner, local_id })) + .map(|local_id| self.tcx.hir_id_to_string(HirId { owner, local_id })) .collect(); self.error(|| { @@ -137,7 +136,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { self.error(|| { format!( "HirIdValidator: The recorded owner of {} is {} instead of {}", - self.tcx.hir().node_to_string(hir_id), + self.tcx.hir_id_to_string(hir_id), self.tcx.hir_def_path(hir_id.owner.def_id).to_string_no_crate_verbose(), self.tcx.hir_def_path(owner.def_id).to_string_no_crate_verbose() ) diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 92ea49f18e5d1..1278e98afcf61 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -107,12 +107,12 @@ impl<'k> StatCollector<'k> { let node = self.nodes.entry(label1).or_insert(Node::new()); node.stats.count += 1; - node.stats.size = std::mem::size_of_val(val); + node.stats.size = size_of_val(val); if let Some(label2) = label2 { let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new()); subnode.count += 1; - subnode.size = std::mem::size_of_val(val); + subnode.size = size_of_val(val); } } @@ -255,9 +255,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_body(self, b); } - fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, n: HirId) { + fn visit_mod(&mut self, m: &'v hir::Mod<'v>, _s: Span, _n: HirId) { self.record("Mod", None, m); - hir_visit::walk_mod(self, m, n) + hir_visit::walk_mod(self, m) } fn visit_foreign_item(&mut self, i: &'v hir::ForeignItem<'v>) { @@ -328,6 +328,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { Array, Call, MethodCall, + Use, Tup, Binary, Unary, @@ -626,7 +627,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { (self, e, e.kind, None, ast, Expr, ExprKind), [ Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, - If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, + If, While, ForLoop, Loop, Match, Closure, Block, Await, Use, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Become, IncludedBytes, Gen, UnsafeBinderCast, Err, Dummy diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 1133cf93304d5..d4512c9417eb4 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -112,8 +112,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) { } sym::debug => { - let normalized_ty = - format!("{}", tcx.normalize_erasing_regions(typing_env, ty)); + let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty); // FIXME: using the `Debug` impl here isn't ideal. let ty_layout = format!("{:#?}", *ty_layout); tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout }); diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 1aa077ad2bb57..6f6115af96c87 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -6,13 +6,13 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(let_chains)] #![feature(map_try_insert)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_middle::query::Providers; diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index e123fbac1bee6..7353c1ead5a78 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -4,7 +4,7 @@ //! but are not declared in one single location (unlike lang features), which means we need to //! collect them instead. -use rustc_attr_parsing::VERSION_PLACEHOLDER; +use rustc_attr_parsing::{AttributeKind, StabilityLevel, StableSince}; use rustc_hir::Attribute; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; @@ -26,62 +26,29 @@ impl<'tcx> LibFeatureCollector<'tcx> { } fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, Span)> { - let stab_attrs = [ - sym::stable, - sym::unstable, - sym::rustc_const_stable, - sym::rustc_const_unstable, - sym::rustc_default_body_unstable, - ]; - - // Find a stability attribute: one of #[stable(…)], #[unstable(…)], - // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable]. - if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) { - if let Some(metas) = attr.meta_item_list() { - let mut feature = None; - let mut since = None; - for meta in metas { - if let Some(mi) = meta.meta_item() { - // Find the `feature = ".."` meta-item. - match (mi.name_or_empty(), mi.value_str()) { - (sym::feature, val) => feature = val, - (sym::since, val) => since = val, - _ => {} - } - } - } - - if let Some(s) = since - && s.as_str() == VERSION_PLACEHOLDER - { - since = Some(sym::env_CFG_RELEASE); - } - - if let Some(feature) = feature { - // This additional check for stability is to make sure we - // don't emit additional, irrelevant errors for malformed - // attributes. - let is_unstable = matches!( - *stab_attr, - sym::unstable - | sym::rustc_const_unstable - | sym::rustc_default_body_unstable - ); - if is_unstable { - return Some((feature, FeatureStability::Unstable, attr.span)); - } - if let Some(since) = since { - return Some((feature, FeatureStability::AcceptedSince(since), attr.span)); - } - } - // We need to iterate over the other attributes, because - // `rustc_const_unstable` is not mutually exclusive with - // the other stability attributes, so we can't just `break` - // here. + let (feature, level, span) = match attr { + Attribute::Parsed(AttributeKind::Stability { stability, span }) => { + (stability.feature, stability.level, *span) } - } - - None + Attribute::Parsed(AttributeKind::ConstStability { stability, span }) => { + (stability.feature, stability.level, *span) + } + Attribute::Parsed(AttributeKind::BodyStability { stability, span }) => { + (stability.feature, stability.level, *span) + } + _ => return None, + }; + + let feature_stability = match level { + StabilityLevel::Unstable { .. } => FeatureStability::Unstable, + StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since { + StableSince::Version(v) => Symbol::intern(&v.to_string()), + StableSince::Current => sym::env_CFG_RELEASE, + StableSince::Err => return None, + }), + }; + + Some((feature, feature_stability, span)) } fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span: Span) { diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 24dc018c66124..ed70d9ee91f5a 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -157,7 +157,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) { if let Some(upvars) = tcx.upvars_mentioned(def_id) { for &var_hir_id in upvars.keys() { - let var_name = tcx.hir().name(var_hir_id); + let var_name = tcx.hir_name(var_hir_id); maps.add_variable(Upvar(var_hir_id, var_name)); } } @@ -426,6 +426,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { | hir::ExprKind::Array(..) | hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Use(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | hir::ExprKind::AddrOf(..) @@ -705,7 +706,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ); self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} } } } @@ -1031,6 +1032,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(receiver, succ) } + hir::ExprKind::Use(expr, _) => { + let succ = self.check_is_ty_uninhabited(expr, succ); + self.propagate_through_expr(expr, succ) + } + hir::ExprKind::Tup(exprs) => self.propagate_through_exprs(exprs, succ), hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => { @@ -1418,6 +1424,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) { // no correctness conditions related to liveness hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Use(..) | hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Index(..) @@ -1493,7 +1500,7 @@ impl<'tcx> Liveness<'_, 'tcx> { for (&var_hir_id, min_capture_list) in closure_min_captures { for captured_place in min_capture_list { match captured_place.info.capture_kind { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue | ty::UpvarCapture::ByUse => {} ty::UpvarCapture::ByRef(..) => continue, }; let span = captured_place.get_capture_kind_span(self.ir.tcx); diff --git a/compiler/rustc_passes/src/liveness/rwu_table.rs b/compiler/rustc_passes/src/liveness/rwu_table.rs index 6e2f976e5b08f..4c1f6ea141e66 100644 --- a/compiler/rustc_passes/src/liveness/rwu_table.rs +++ b/compiler/rustc_passes/src/liveness/rwu_table.rs @@ -39,7 +39,7 @@ impl RWUTable { /// Size of packed RWU in bits. const RWU_BITS: usize = 4; /// Size of a word in bits. - const WORD_BITS: usize = std::mem::size_of::() * 8; + const WORD_BITS: usize = size_of::() * 8; /// Number of packed RWUs that fit into a single word. const WORD_RWU_COUNT: usize = Self::WORD_BITS / Self::RWU_BITS; diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index 8e59c0b3251ca..b06f16cc7bd2f 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -222,7 +222,7 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { if let Some(break_expr) = opt_expr { let (head, loop_label, loop_kind) = if let Some(loop_id) = loop_id { - match self.tcx.hir().expect_expr(loop_id).kind { + match self.tcx.hir_expect_expr(loop_id).kind { hir::ExprKind::Loop(_, label, source, sp) => { (Some(sp), label, Some(source)) } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index cb17b0f6cf528..d35aedf9a5647 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -182,6 +182,7 @@ impl CheckInlineAssembly { | ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::MethodCall(..) + | ExprKind::Use(..) | ExprKind::Tup(..) | ExprKind::Binary(..) | ExprKind::Unary(..) diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 1fe44bd3d21a9..599a08bac20de 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -246,7 +246,7 @@ impl<'tcx> ReachableContext<'tcx> { | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) | hir::ItemKind::Union(..) - | hir::ItemKind::GlobalAsm(..) => {} + | hir::ItemKind::GlobalAsm { .. } => {} } } Node::TraitItem(trait_method) => { @@ -291,7 +291,7 @@ impl<'tcx> ReachableContext<'tcx> { _ => { bug!( "found unexpected node kind in worklist: {} ({:?})", - self.tcx.hir().node_to_string(self.tcx.local_def_id_to_hir_id(search_item)), + self.tcx.hir_id_to_string(self.tcx.local_def_id_to_hir_id(search_item)), node, ); } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 4124e8a4dd1f8..aea4386295f31 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -6,8 +6,8 @@ use std::num::NonZero; use rustc_ast_lowering::stability::extern_abi_stability; use rustc_attr_parsing::{ - self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince, - UnstableReason, VERSION_PLACEHOLDER, + self as attr, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, Stability, + StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr, }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; @@ -118,10 +118,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { ) where F: FnOnce(&mut Self), { - let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); + let attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); - let depr = attr::find_deprecation(self.tcx.sess, self.tcx.features(), attrs); + let depr = attr::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span)); + let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect); + let mut is_deprecated = false; if let Some((depr, span)) = &depr { is_deprecated = true; @@ -154,9 +156,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if inherit_deprecation.yes() && stab.is_unstable() { self.index.stab_map.insert(def_id, stab); if fn_sig.is_some_and(|s| s.header.is_const()) { - let const_stab = - attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab); - self.index.const_stab_map.insert(def_id, const_stab); + self.index.const_stab_map.insert( + def_id, + ConstStability::unmarked(const_stability_indirect, stab), + ); } } } @@ -171,9 +174,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // # Regular and body stability - - let stab = attr::find_stability(self.tcx.sess, attrs, item_sp); - let body_stab = attr::find_body_stability(self.tcx.sess, attrs); + let stab = attr::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span)); + let body_stab = + attr::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability); if let Some((depr, span)) = &depr && depr.is_since_rustc_version() @@ -182,7 +185,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span }); } - if let Some((body_stab, _span)) = body_stab { + if let Some(body_stab) = body_stab { // FIXME: check that this item can have body stability self.index.default_body_stab_map.insert(def_id, body_stab); @@ -260,10 +263,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // # Const stability - let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp); + let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span)); // If the current node is a function with const stability attributes (directly given or - // implied), check if the function/method is const. + // implied), check if the function/method is const or the parent impl block is const. if let Some(fn_sig) = fn_sig && !fn_sig.header.is_const() && const_stab.is_some() @@ -285,7 +288,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Stable *language* features shouldn't be used as unstable library features. // (Not doing this for stable library features is checked by tidy.) if let Some(( - ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }, + PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. }, const_span, )) = const_stab { @@ -297,12 +300,20 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } } + if let Some((stab, span)) = &const_stab + && stab.is_const_stable() + && const_stability_indirect + { + self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span }); + } + // After checking the immediate attributes, get rid of the span and compute implied // const stability: inherit feature gate from regular stability. - let mut const_stab = const_stab.map(|(stab, _span)| stab); + let mut const_stab = const_stab + .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect)); // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability. - if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && + if fn_sig.is_some_and(|s| s.header.is_const()) && const_stab.is_none() && // We only ever inherit unstable features. let Some(inherit_regular_stab) = final_stab.filter(|s| s.is_unstable()) @@ -780,17 +791,15 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { // individually as it's possible to have a stable trait with unstable // items. hir::ItemKind::Impl(hir::Impl { - of_trait: Some(ref t), - self_ty, - items, - constness, - .. + of_trait: Some(t), self_ty, items, constness, .. }) => { let features = self.tcx.features(); if features.staged_api() { - let attrs = self.tcx.hir().attrs(item.hir_id()); - let stab = attr::find_stability(self.tcx.sess, attrs, item.span); - let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span); + let attrs = self.tcx.hir_attrs(item.hir_id()); + let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span)); + + // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem + let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability); // If this impl block has an #[unstable] attribute, give an // error if all involved types and traits are stable, because @@ -817,24 +826,56 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable - // needs to have an error emitted. if features.const_trait_impl() - && self.tcx.is_const_trait_impl(item.owner_id.to_def_id()) - && const_stab.is_some_and(|(stab, _)| stab.is_const_stable()) + && let hir::Constness::Const = constness { - self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span }); + let stable_or_implied_stable = match const_stab { + None => true, + Some(stab) if stab.is_const_stable() => { + // `#![feature(const_trait_impl)]` is unstable, so any impl declared stable + // needs to have an error emitted. + // Note: Remove this error once `const_trait_impl` is stabilized + self.tcx + .dcx() + .emit_err(errors::TraitImplConstStable { span: item.span }); + true + } + Some(_) => false, + }; + + if let Some(trait_id) = t.trait_def_id() + && let Some(const_stab) = self.tcx.lookup_const_stability(trait_id) + { + // the const stability of a trait impl must match the const stability on the trait. + if const_stab.is_const_stable() != stable_or_implied_stable { + let trait_span = self.tcx.def_ident_span(trait_id).unwrap(); + + let impl_stability = if stable_or_implied_stable { + errors::ImplConstStability::Stable { span: item.span } + } else { + errors::ImplConstStability::Unstable { span: item.span } + }; + let trait_stability = if const_stab.is_const_stable() { + errors::TraitConstStability::Stable { span: trait_span } + } else { + errors::TraitConstStability::Unstable { span: trait_span } + }; + + self.tcx.dcx().emit_err(errors::TraitImplConstStabilityMismatch { + span: item.span, + impl_stability, + trait_stability, + }); + } + } } } - match constness { - rustc_hir::Constness::Const => { - if let Some(def_id) = t.trait_def_id() { - // FIXME(const_trait_impl): Improve the span here. - self.tcx.check_const_stability(def_id, t.path.span, t.path.span); - } - } - rustc_hir::Constness::NotConst => {} + if let hir::Constness::Const = constness + && let Some(def_id) = t.trait_def_id() + { + // FIXME(const_trait_impl): Improve the span here. + self.tcx.check_const_stability(def_id, t.path.span, t.path.span); } for impl_item_ref in *items { @@ -993,7 +1034,7 @@ fn is_unstable_reexport(tcx: TyCtxt<'_>, id: hir::HirId) -> bool { } // If this is a path that isn't a use, we don't need to do anything special - if !matches!(tcx.hir().expect_item(def_id).kind, ItemKind::Use(..)) { + if !matches!(tcx.hir_expect_item(def_id).kind, ItemKind::Use(..)) { return false; } diff --git a/compiler/rustc_pattern_analysis/Cargo.toml b/compiler/rustc_pattern_analysis/Cargo.toml index 16eea9e4ff90a..40d549630acae 100644 --- a/compiler/rustc_pattern_analysis/Cargo.toml +++ b/compiler/rustc_pattern_analysis/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_pattern_analysis" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index fec44d5af55da..eeea724a29b45 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -6,7 +6,6 @@ #![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(feature = "rustc", feature(let_chains))] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod constructor; @@ -61,11 +60,11 @@ pub trait PatCx: Sized + fmt::Debug { fn ctor_arity(&self, ctor: &Constructor, ty: &Self::Ty) -> usize; /// The types of the fields for this constructor. The result must contain `ctor_arity()` fields. - fn ctor_sub_tys<'a>( - &'a self, - ctor: &'a Constructor, - ty: &'a Self::Ty, - ) -> impl Iterator + ExactSizeIterator + Captures<'a>; + fn ctor_sub_tys( + &self, + ctor: &Constructor, + ty: &Self::Ty, + ) -> impl Iterator + ExactSizeIterator; /// The set of all the constructors for `ty`. /// diff --git a/compiler/rustc_pattern_analysis/src/pat_column.rs b/compiler/rustc_pattern_analysis/src/pat_column.rs index eb4e095c1c662..814eb8afcfc0d 100644 --- a/compiler/rustc_pattern_analysis/src/pat_column.rs +++ b/compiler/rustc_pattern_analysis/src/pat_column.rs @@ -1,6 +1,6 @@ use crate::constructor::{Constructor, SplitConstructorSet}; use crate::pat::{DeconstructedPat, PatOrWild}; -use crate::{Captures, MatchArm, PatCx}; +use crate::{MatchArm, PatCx}; /// A column of patterns in a match, where a column is the intuitive notion of "subpatterns that /// inspect the same subvalue/place". @@ -41,7 +41,7 @@ impl<'p, Cx: PatCx> PatternColumn<'p, Cx> { pub fn head_ty(&self) -> Option<&Cx::Ty> { self.patterns.first().map(|pat| pat.ty()) } - pub fn iter<'a>(&'a self) -> impl Iterator> + Captures<'a> { + pub fn iter(&self) -> impl Iterator> { self.patterns.iter().copied() } diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 0b1e954d64d4b..88194c737a6cc 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -25,7 +25,7 @@ use crate::lints::lint_nonexhaustive_missing_variants; use crate::pat_column::PatternColumn; use crate::rustc::print::EnumInfo; use crate::usefulness::{PlaceValidity, compute_match_usefulness}; -use crate::{Captures, PatCx, PrivateUninhabitedField, errors}; +use crate::{PatCx, PrivateUninhabitedField, errors}; mod print; @@ -175,8 +175,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { &self, ty: RevealedTy<'tcx>, variant: &'tcx VariantDef, - ) -> impl Iterator)> + Captures<'p> + Captures<'_> - { + ) -> impl Iterator)> { let ty::Adt(_, args) = ty.kind() else { bug!() }; variant.fields.iter().map(move |field| { let ty = field.ty(self.tcx, args); @@ -203,13 +202,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { /// Returns the types of the fields for a given constructor. The result must have a length of /// `ctor.arity()`. - pub(crate) fn ctor_sub_tys<'a>( - &'a self, - ctor: &'a Constructor<'p, 'tcx>, + pub(crate) fn ctor_sub_tys( + &self, + ctor: &Constructor<'p, 'tcx>, ty: RevealedTy<'tcx>, - ) -> impl Iterator, PrivateUninhabitedField)> - + ExactSizeIterator - + Captures<'a> { + ) -> impl Iterator, PrivateUninhabitedField)> + ExactSizeIterator { fn reveal_and_alloc<'a, 'tcx>( cx: &'a RustcPatCtxt<'_, 'tcx>, iter: impl Iterator>, @@ -936,12 +933,11 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { fn ctor_arity(&self, ctor: &crate::constructor::Constructor, ty: &Self::Ty) -> usize { self.ctor_arity(ctor, *ty) } - fn ctor_sub_tys<'a>( - &'a self, - ctor: &'a crate::constructor::Constructor, - ty: &'a Self::Ty, - ) -> impl Iterator + ExactSizeIterator + Captures<'a> - { + fn ctor_sub_tys( + &self, + ctor: &crate::constructor::Constructor, + ty: &Self::Ty, + ) -> impl Iterator + ExactSizeIterator { self.ctor_sub_tys(ctor, *ty) } fn ctors_for_ty( diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 1dff76141da5d..11ebbea07fa4e 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -719,7 +719,7 @@ use tracing::{debug, instrument}; use self::PlaceValidity::*; use crate::constructor::{Constructor, ConstructorSet, IntRange}; use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat}; -use crate::{Captures, MatchArm, PatCx, PrivateUninhabitedField}; +use crate::{MatchArm, PatCx, PrivateUninhabitedField}; #[cfg(not(feature = "rustc"))] pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { f() @@ -902,11 +902,11 @@ struct PlaceInfo { impl PlaceInfo { /// Given a constructor for the current place, we return one `PlaceInfo` for each field of the /// constructor. - fn specialize<'a>( - &'a self, - cx: &'a Cx, - ctor: &'a Constructor, - ) -> impl Iterator + ExactSizeIterator + Captures<'a> { + fn specialize( + &self, + cx: &Cx, + ctor: &Constructor, + ) -> impl Iterator + ExactSizeIterator { let ctor_sub_tys = cx.ctor_sub_tys(ctor, &self.ty); let ctor_sub_validity = self.validity.specialize(ctor); ctor_sub_tys.map(move |(ty, PrivateUninhabitedField(private_uninhabited))| PlaceInfo { @@ -1046,13 +1046,13 @@ impl<'p, Cx: PatCx> PatStack<'p, Cx> { self.pats[0] } - fn iter(&self) -> impl Iterator> + Captures<'_> { + fn iter(&self) -> impl Iterator> { self.pats.iter().copied() } // Expand the first or-pattern into its subpatterns. Only useful if the pattern is an // or-pattern. Panics if `self` is empty. - fn expand_or_pat(&self) -> impl Iterator> + Captures<'_> { + fn expand_or_pat(&self) -> impl Iterator> { self.head().expand_or_pat().into_iter().map(move |pat| { let mut new = self.clone(); new.pats[0] = pat; @@ -1157,15 +1157,12 @@ impl<'p, Cx: PatCx> MatrixRow<'p, Cx> { self.pats.head() } - fn iter(&self) -> impl Iterator> + Captures<'_> { + fn iter(&self) -> impl Iterator> { self.pats.iter() } // Expand the first or-pattern (if any) into its subpatterns. Panics if `self` is empty. - fn expand_or_pat( - &self, - parent_row: usize, - ) -> impl Iterator> + Captures<'_> { + fn expand_or_pat(&self, parent_row: usize) -> impl Iterator> { let is_or_pat = self.pats.head().is_or_pat(); self.pats.expand_or_pat().map(move |patstack| MatrixRow { pats: patstack, @@ -1275,7 +1272,7 @@ impl<'p, Cx: PatCx> Matrix<'p, Cx> { } /// Iterate over the first pattern of each row. - fn heads(&self) -> impl Iterator> + Clone + Captures<'_> { + fn heads(&self) -> impl Iterator> + Clone { self.rows().map(|r| r.head()) } diff --git a/compiler/rustc_pattern_analysis/tests/common/mod.rs b/compiler/rustc_pattern_analysis/tests/common/mod.rs index 23560ad64190c..8980b644f59b1 100644 --- a/compiler/rustc_pattern_analysis/tests/common/mod.rs +++ b/compiler/rustc_pattern_analysis/tests/common/mod.rs @@ -2,10 +2,10 @@ use rustc_pattern_analysis::constructor::{ Constructor, ConstructorSet, IntRange, MaybeInfiniteInt, RangeEnd, VariantVisibility, }; use rustc_pattern_analysis::usefulness::{PlaceValidity, UsefulnessReport}; -use rustc_pattern_analysis::{Captures, MatchArm, PatCx, PrivateUninhabitedField}; +use rustc_pattern_analysis::{MatchArm, PatCx, PrivateUninhabitedField}; /// Sets up `tracing` for easier debugging. Tries to look like the `rustc` setup. -pub fn init_tracing() { +fn init_tracing() { use tracing_subscriber::Layer; use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::util::SubscriberInitExt; @@ -24,7 +24,7 @@ pub fn init_tracing() { /// A simple set of types. #[allow(dead_code)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum Ty { +pub(super) enum Ty { /// Booleans Bool, /// 8-bit unsigned integers @@ -41,7 +41,7 @@ pub enum Ty { /// The important logic. impl Ty { - pub fn sub_tys(&self, ctor: &Constructor) -> Vec { + pub(super) fn sub_tys(&self, ctor: &Constructor) -> Vec { use Constructor::*; match (ctor, *self) { (Struct, Ty::Tuple(tys)) => tys.iter().copied().collect(), @@ -63,7 +63,7 @@ impl Ty { } } - pub fn ctor_set(&self) -> ConstructorSet { + fn ctor_set(&self) -> ConstructorSet { match *self { Ty::Bool => ConstructorSet::Bool, Ty::U8 => ConstructorSet::Integers { @@ -104,7 +104,7 @@ impl Ty { } } - pub fn write_variant_name( + fn write_variant_name( &self, f: &mut std::fmt::Formatter<'_>, ctor: &Constructor, @@ -120,7 +120,7 @@ impl Ty { } /// Compute usefulness in our simple context (and set up tracing for easier debugging). -pub fn compute_match_usefulness<'p>( +pub(super) fn compute_match_usefulness<'p>( arms: &[MatchArm<'p, Cx>], ty: Ty, scrut_validity: PlaceValidity, @@ -137,7 +137,7 @@ pub fn compute_match_usefulness<'p>( } #[derive(Debug)] -pub struct Cx; +pub(super) struct Cx; /// The context for pattern analysis. Forwards anything interesting to `Ty` methods. impl PatCx for Cx { @@ -156,12 +156,11 @@ impl PatCx for Cx { ty.sub_tys(ctor).len() } - fn ctor_sub_tys<'a>( - &'a self, - ctor: &'a Constructor, - ty: &'a Self::Ty, - ) -> impl Iterator + ExactSizeIterator + Captures<'a> - { + fn ctor_sub_tys( + &self, + ctor: &Constructor, + ty: &Self::Ty, + ) -> impl Iterator + ExactSizeIterator { ty.sub_tys(ctor).into_iter().map(|ty| (ty, PrivateUninhabitedField(false))) } diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml index eb48155919fee..242c67d732aff 100644 --- a/compiler/rustc_privacy/Cargo.toml +++ b/compiler/rustc_privacy/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_privacy" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 6faa2c1a00d23..cf32f237b8676 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,12 +1,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(associated_type_defaults)] #![feature(let_chains)] #![feature(rustdoc_internals)] #![feature(try_blocks)] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod errors; @@ -22,6 +22,7 @@ use errors::{ }; use rustc_ast::MacroDef; use rustc_ast::visit::{VisitorResult, try_visit}; +use rustc_attr_parsing::AttributeKind; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; use rustc_errors::{MultiSpan, listify}; @@ -39,7 +40,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::hygiene::Transparency; -use rustc_span::{Ident, Span, Symbol, kw, sym}; +use rustc_span::{Ident, Span, Symbol, sym}; use tracing::debug; use {rustc_attr_parsing as attr, rustc_hir as hir}; @@ -492,8 +493,12 @@ impl<'tcx> EmbargoVisitor<'tcx> { ) { // Non-opaque macros cannot make other items more accessible than they already are. let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); - let attrs = self.tcx.hir().attrs(hir_id); - if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque { + let attrs = self.tcx.hir_attrs(hir_id); + + if attr::find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x) + .unwrap_or(Transparency::fallback(md.macro_rules)) + != Transparency::Opaque + { return; } @@ -568,7 +573,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { // have normal hygiene, so we can treat them like other items without type // privacy and mark them reachable. DefKind::Macro(_) => { - let item = self.tcx.hir().expect_item(def_id); + let item = self.tcx.hir_expect_item(def_id); if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind { if vis.is_accessible_from(module, self.tcx) { self.update(def_id, macro_ev, Level::Reachable); @@ -592,7 +597,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { DefKind::Struct | DefKind::Union => { // While structs and unions have type privacy, their fields do not. - let item = self.tcx.hir().expect_item(def_id); + let item = self.tcx.hir_expect_item(def_id); if let hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) = item.kind { @@ -645,7 +650,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // The interface is empty, and no nested items. hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(..) - | hir::ItemKind::GlobalAsm(..) => {} + | hir::ItemKind::GlobalAsm { .. } => {} // The interface is empty, and all nested items are processed by `visit_item`. hir::ItemKind::Mod(..) => {} hir::ItemKind::Macro(macro_def, _) => { @@ -930,8 +935,8 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } // definition of the field - let ident = Ident::new(kw::Empty, use_ctxt); - let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; + let ident = Ident::new(sym::dummy, use_ctxt); + let (_, def_id) = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id); !field.vis.is_accessible_from(def_id, self.tcx) } diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index fd1d21b6a8929..c85156e059e5a 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "rustc_query_impl" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start measureme = "11" +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hashes = { path = "../rustc_hashes" } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 73c205fdb17d1..a83c388c747b6 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,12 +3,12 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(unused_parens)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(min_specialization)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_data_structures::stable_hasher::HashStable; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index f98d6421307ad..fa31ef5eeb02d 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -19,9 +19,10 @@ use rustc_middle::query::Key; use rustc_middle::query::on_disk_cache::{ AbsoluteBytePos, CacheDecoder, CacheEncoder, EncodedDepNodeIndex, }; +use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::print::with_reduced_queries; use rustc_middle::ty::tls::{self, ImplicitCtxt}; -use rustc_middle::ty::{self, TyCtxt, TyEncoder}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext}; use rustc_query_system::ich::StableHashingContext; use rustc_query_system::query::{ diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml index d9560f3eb0fad..3e8ccb51021e1 100644 --- a/compiler/rustc_query_system/Cargo.toml +++ b/compiler/rustc_query_system/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_query_system" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -9,6 +9,7 @@ parking_lot = "0.12" rustc-rayon-core = { version = "0.5.0" } rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 5e6bee1dbd5a1..3109d53cd2caa 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -1,5 +1,4 @@ use std::assert_matches::assert_matches; -use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; @@ -9,7 +8,7 @@ use std::sync::atomic::{AtomicU32, Ordering}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{QueryInvocationId, SelfProfilerRef}; -use rustc_data_structures::sharded::{self, Sharded}; +use rustc_data_structures::sharded::{self, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{AtomicU64, Lock}; use rustc_data_structures::unord::UnordMap; @@ -619,7 +618,7 @@ impl DepGraphData { if let Some(prev_index) = self.previous.node_to_index_opt(dep_node) { self.current.prev_index_to_index.lock()[prev_index] } else { - self.current.new_node_to_index.lock_shard_by_value(dep_node).get(dep_node).copied() + self.current.new_node_to_index.get(dep_node) } } @@ -1048,7 +1047,7 @@ rustc_index::newtype_index! { /// first, and `data` second. pub(super) struct CurrentDepGraph { encoder: GraphEncoder, - new_node_to_index: Sharded>, + new_node_to_index: ShardedHashMap, prev_index_to_index: Lock>>, /// This is used to verify that fingerprints do not change between the creation of a node @@ -1117,12 +1116,9 @@ impl CurrentDepGraph { profiler, previous, ), - new_node_to_index: Sharded::new(|| { - FxHashMap::with_capacity_and_hasher( - new_node_count_estimate / sharded::shards(), - Default::default(), - ) - }), + new_node_to_index: ShardedHashMap::with_capacity( + new_node_count_estimate / sharded::shards(), + ), prev_index_to_index: Lock::new(IndexVec::from_elem_n(None, prev_graph_node_count)), anon_id_seed, #[cfg(debug_assertions)] @@ -1152,14 +1148,9 @@ impl CurrentDepGraph { edges: EdgesVec, current_fingerprint: Fingerprint, ) -> DepNodeIndex { - let dep_node_index = match self.new_node_to_index.lock_shard_by_value(&key).entry(key) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let dep_node_index = self.encoder.send(key, current_fingerprint, edges); - entry.insert(dep_node_index); - dep_node_index - } - }; + let dep_node_index = self + .new_node_to_index + .get_or_insert_with(key, || self.encoder.send(key, current_fingerprint, edges)); #[cfg(debug_assertions)] self.record_edge(dep_node_index, key, current_fingerprint); @@ -1257,7 +1248,7 @@ impl CurrentDepGraph { ) { let node = &prev_graph.index_to_node(prev_index); debug_assert!( - !self.new_node_to_index.lock_shard_by_value(node).contains_key(node), + !self.new_node_to_index.get(node).is_some(), "node from previous graph present in new node collection" ); } @@ -1299,12 +1290,11 @@ impl Default for TaskDeps { #[cfg(debug_assertions)] node: None, reads: EdgesVec::new(), - read_set: FxHashSet::default(), + read_set: FxHashSet::with_capacity_and_hasher(128, Default::default()), phantom_data: PhantomData, } } } - // A data structure that stores Option values as a contiguous // array, using one u32 per entry. struct DepNodeColorMap { @@ -1383,7 +1373,7 @@ fn panic_on_forbidden_read(data: &DepGraphData, dep_node_index: DepN if dep_node.is_none() { // Try to find it among the new nodes for shard in data.current.new_node_to_index.lock_shards() { - if let Some((node, _)) = shard.iter().find(|(_, index)| **index == dep_node_index) { + if let Some((node, _)) = shard.iter().find(|(_, index)| *index == dep_node_index) { dep_node = Some(*node); break; } diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index a4fb0a5b07220..2c6fd7d494f02 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -63,7 +63,7 @@ rustc_index::newtype_index! { pub struct SerializedDepNodeIndex {} } -const DEP_NODE_SIZE: usize = std::mem::size_of::(); +const DEP_NODE_SIZE: usize = size_of::(); /// Amount of padding we need to add to the edge list data so that we can retrieve every /// SerializedDepNodeIndex with a fixed-size read then mask. const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1; @@ -98,7 +98,7 @@ impl SerializedDepGraph { pub fn edge_targets_from( &self, source: SerializedDepNodeIndex, - ) -> impl Iterator + Clone + '_ { + ) -> 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 @@ -175,7 +175,7 @@ impl EdgeHeader { #[inline] fn mask(bits: usize) -> usize { - usize::MAX >> ((std::mem::size_of::() * 8) - bits) + usize::MAX >> ((size_of::() * 8) - bits) } impl SerializedDepGraph { @@ -208,9 +208,8 @@ impl SerializedDepGraph { // for a node with length 64, which means the spilled 1-byte leb128 length is 1 byte of at // least (34 byte header + 1 byte len + 64 bytes edge data), which is ~1%. A 2-byte leb128 // length is about the same fractional overhead and it amortizes for yet greater lengths. - let mut edge_list_data = Vec::with_capacity( - graph_bytes - node_count * std::mem::size_of::>(), - ); + let mut edge_list_data = + Vec::with_capacity(graph_bytes - node_count * size_of::>()); for _index in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size @@ -300,7 +299,7 @@ struct Unpacked { // M..M+N bytes per index // M+N..16 kind impl SerializedNodeHeader { - const TOTAL_BITS: usize = std::mem::size_of::() * 8; + const TOTAL_BITS: usize = size_of::() * 8; const LEN_BITS: usize = Self::TOTAL_BITS - Self::KIND_BITS - Self::WIDTH_BITS; const WIDTH_BITS: usize = DEP_NODE_WIDTH_BITS; const KIND_BITS: usize = Self::TOTAL_BITS - D::DEP_KIND_MAX.leading_zeros() as usize; diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs index cf50e61e72ba1..e1b6adc6cc17d 100644 --- a/compiler/rustc_query_system/src/ich/hcx.rs +++ b/compiler/rustc_query_system/src/ich/hcx.rs @@ -129,3 +129,4 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> { } impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {} +impl<'a> rustc_attr_data_structures::HashStableContext for StableHashingContext<'a> {} diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 7d508b8201bdf..1dcd5d9058f4e 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -2,7 +2,7 @@ //! from various crates in no particular order. use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_hir as hir; +use rustc_hir::{self as hir, HashIgnoredAttrId}; use rustc_span::SourceFile; use smallvec::SmallVec; @@ -23,6 +23,7 @@ impl<'a> HashStable> for [hir::Attribute] { .iter() .filter(|attr| { !attr.is_doc_comment() + // FIXME(jdonszelmann) have a better way to handle ignored attrs && !attr.ident().is_some_and(|ident| hcx.is_ignored_attr(ident.name)) }) .collect(); @@ -35,19 +36,8 @@ impl<'a> HashStable> for [hir::Attribute] { } impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> { - fn hash_attr(&mut self, attr: &hir::Attribute, hasher: &mut StableHasher) { - // Make sure that these have been filtered out. - debug_assert!(!attr.ident().is_some_and(|ident| self.is_ignored_attr(ident.name))); - debug_assert!(!attr.is_doc_comment()); - - let hir::Attribute { kind, id: _, style, span } = attr; - if let hir::AttrKind::Normal(item) = kind { - item.hash_stable(self, hasher); - style.hash_stable(self, hasher); - span.hash_stable(self, hasher); - } else { - unreachable!(); - } + fn hash_attr_id(&mut self, _id: &HashIgnoredAttrId, _hasher: &mut StableHasher) { + /* we don't hash HashIgnoredAttrId, we ignore them */ } } diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index ee984095ad84b..2aedd365adc89 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -3,10 +3,8 @@ #![feature(assert_matches)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(hash_raw_entry)] #![feature(let_chains)] #![feature(min_specialization)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod cache; diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index e11123dff26a7..30b5d7e595491 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -1,9 +1,8 @@ use std::fmt::Debug; use std::hash::Hash; +use std::sync::OnceLock; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sharded::{self, Sharded}; -use rustc_data_structures::sync::OnceLock; +use rustc_data_structures::sharded::ShardedHashMap; pub use rustc_data_structures::vec_cache::VecCache; use rustc_hir::def_id::LOCAL_CRATE; use rustc_index::Idx; @@ -36,7 +35,7 @@ pub trait QueryCache: Sized { /// In-memory cache for queries whose keys aren't suitable for any of the /// more specialized kinds of cache. Backed by a sharded hashmap. pub struct DefaultCache { - cache: Sharded>, + cache: ShardedHashMap, } impl Default for DefaultCache { @@ -55,19 +54,14 @@ where #[inline(always)] fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { - let key_hash = sharded::make_hash(key); - let lock = self.cache.lock_shard_by_hash(key_hash); - let result = lock.raw_entry().from_key_hashed_nocheck(key_hash, key); - - if let Some((_, value)) = result { Some(*value) } else { None } + self.cache.get(key) } #[inline] fn complete(&self, key: K, value: V, index: DepNodeIndex) { - let mut lock = self.cache.lock_shard_by_value(&key); // We may be overwriting another value. This is all right, since the dep-graph // will check that the fingerprint matches. - lock.insert(key, (value, index)); + self.cache.insert(key, (value, index)); } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index a8c2aa98cd083..37b305d0a8b50 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -477,8 +477,8 @@ fn remove_cycle( /// Detects query cycles by using depth first search over all active query jobs. /// If a query cycle is found it will break the cycle by finding an edge which /// uses a query latch and then resuming that waiter. -/// There may be multiple cycles involved in a deadlock, so this searches -/// all active queries for cycles before finally resuming all the waiters at once. +/// There may be multiple cycles involved in a deadlock, but we only search +/// one cycle at a call and resume one waiter at once. See `FIXME` below. pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) { let mut wakelist = Vec::new(); let mut jobs: Vec = query_map.keys().cloned().collect(); @@ -488,6 +488,19 @@ pub fn break_query_cycles(query_map: QueryMap, registry: &rayon_core::Registry) while jobs.len() > 0 { if remove_cycle(&query_map, &mut jobs, &mut wakelist) { found_cycle = true; + + // FIXME(#137731): Resume all the waiters at once may cause deadlocks, + // so we resume one waiter at a call for now. It's still unclear whether + // it's due to possible issues in rustc-rayon or instead in the handling + // of query cycles. + // This seem to only appear when multiple query cycles errors + // are involved, so this reduction in parallelism, while suboptimal, is not + // universal and only the deadlock handler will encounter these cases. + // The workaround shows loss of potential gains, but there still are big + // improvements in the common case, and no regressions compared to the + // single-threaded case. More investigation is still needed, and once fixed, + // we can wake up all the waiters up. + break; } } diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml index 309227176d4e5..f4771f1af2cfd 100644 --- a/compiler/rustc_resolve/Cargo.toml +++ b/compiler/rustc_resolve/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_resolve" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index b13de2875bc20..817aa5b43852b 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -125,9 +125,6 @@ resolve_const_param_in_enum_discriminant = resolve_const_param_in_non_trivial_anon_const = const parameters may only be used as standalone arguments, i.e. `{$name}` -resolve_const_param_in_ty_of_const_param = - const parameters may not be used in the type of const parameters - resolve_constructor_private_if_any_field_private = a constructor is private if any of the fields is private @@ -156,9 +153,13 @@ resolve_extern_crate_self_requires_renaming = `extern crate self;` requires renaming .suggestion = rename the `self` crate to be able to import it +resolve_forward_declared_generic_in_const_param_ty = + const parameter types cannot reference parameters before they are declared + .label = const parameter type cannot reference `{$param}` before it is declared + resolve_forward_declared_generic_param = - generic parameters with a default cannot use forward declared identifiers - .label = defaulted generic parameters cannot be forward declared + generic parameter defaults cannot reference parameters before they are declared + .label = cannot reference `{$param}` before it is declared resolve_found_an_item_configured_out = found an item that was configured out @@ -250,9 +251,6 @@ resolve_lifetime_param_in_enum_discriminant = resolve_lifetime_param_in_non_trivial_anon_const = lifetime parameters may not be used in const expressions -resolve_lifetime_param_in_ty_of_const_param = - lifetime parameters may not be used in the type of const parameters - resolve_lowercase_self = attempt to use a non-constant value in a constant .suggestion = try using `Self` @@ -383,9 +381,11 @@ resolve_self_imports_only_allowed_within_multipart_suggestion = resolve_self_imports_only_allowed_within_suggestion = consider importing the module directly +resolve_self_in_const_generic_ty = + cannot use `Self` in const parameter type + resolve_self_in_generic_param_default = generic parameters cannot use `Self` in their defaults - .label = `Self` in generic parameter default resolve_similarly_named_defined_here = similarly named {$candidate_descr} `{$candidate}` defined here @@ -437,9 +437,6 @@ resolve_type_param_in_enum_discriminant = resolve_type_param_in_non_trivial_anon_const = type parameters may not be used in const expressions -resolve_type_param_in_ty_of_const_param = - type parameters may not be used in the type of const parameters - resolve_undeclared_label = use of undeclared label `{$name}` .label = undeclared label `{$name}` diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 87f7eda391d9d..763e9207a126b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1115,6 +1115,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { } }); } else { + #[allow(rustc::potential_query_instability)] // FIXME for ident in single_imports.iter().cloned() { let result = self.r.maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), @@ -1529,6 +1530,14 @@ impl<'a, 'ra, 'tcx> Visitor<'a> for BuildReducedGraphVisitor<'a, 'ra, 'tcx> { visit::walk_variant(self, variant); } + fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) { + if p.is_placeholder { + self.visit_invoc(p.id); + } else { + visit::walk_where_predicate(self, p); + } + } + fn visit_crate(&mut self, krate: &'a ast::Crate) { if krate.is_placeholder { self.visit_invoc_in_module(krate.id); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 5eb8e420fa4ed..33f529851ae4f 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -3,12 +3,13 @@ use std::mem; use rustc_ast::visit::FnKind; use rustc_ast::*; use rustc_ast_pretty::pprust; +use rustc_attr_parsing::{AttributeParser, OmitDoc}; use rustc_expand::expand::AstFragment; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind}; use rustc_hir::def_id::LocalDefId; use rustc_span::hygiene::LocalExpnId; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{Span, Symbol, sym}; use tracing::debug; use crate::{ImplTraitContext, InvocationParent, Resolver}; @@ -37,7 +38,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { fn create_def( &mut self, node_id: NodeId, - name: Symbol, + name: Option, def_kind: DefKind, span: Span, ) -> LocalDefId { @@ -88,7 +89,7 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> { self.visit_macro_invoc(field.id); } else { let name = field.ident.map_or_else(|| sym::integer(index(self)), |ident| ident.name); - let def = self.create_def(field.id, name, DefKind::Field, field.span); + let def = self.create_def(field.id, Some(name), DefKind::Field, field.span); self.with_parent(def, |this| visit::walk_field_def(this, field)); } } @@ -132,8 +133,24 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn, ItemKind::MacroDef(def) => { let edition = i.span.edition(); + + // FIXME(jdonszelmann) make one of these in the resolver? + // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. + // Does that prevents errors from happening? maybe + let parser = AttributeParser::new( + &self.resolver.tcx.sess, + self.resolver.tcx.features(), + Vec::new(), + ); + let attrs = parser.parse_attribute_list( + &i.attrs, + i.span, + OmitDoc::Skip, + std::convert::identity, + ); + let macro_data = - self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition); + self.resolver.compile_macro(def, i.ident, &attrs, i.span, i.id, edition); let macro_kind = macro_data.ext.macro_kind(); opt_macro_data = Some(macro_data); DefKind::Macro(macro_kind) @@ -144,7 +161,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { return self.visit_macro_invoc(i.id); } }; - let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span); + let def_id = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); if let Some(macro_data) = opt_macro_data { self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); @@ -158,7 +175,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(struct_def) { this.create_def( ctor_node_id, - kw::Empty, + None, DefKind::Ctor(CtorOf::Struct, ctor_kind), i.span, ); @@ -194,20 +211,15 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } let (return_id, return_span) = coroutine_kind.return_id(); - let return_def = - self.create_def(return_id, kw::Empty, DefKind::OpaqueTy, return_span); + let return_def = self.create_def(return_id, None, DefKind::OpaqueTy, return_span); self.with_parent(return_def, |this| this.visit_fn_ret_ty(output)); // If this async fn has no body (i.e. it's an async fn signature in a trait) // then the closure_def will never be used, and we should avoid generating a // def-id for it. if let Some(body) = body { - let closure_def = self.create_def( - coroutine_kind.closure_id(), - kw::Empty, - DefKind::Closure, - span, - ); + let closure_def = + self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span); self.with_parent(closure_def, |this| this.visit_block(body)); } } @@ -218,7 +230,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // Async closures desugar to closures inside of closures, so // we must create two defs. let coroutine_def = - self.create_def(coroutine_kind.closure_id(), kw::Empty, DefKind::Closure, span); + self.create_def(coroutine_kind.closure_id(), None, DefKind::Closure, span); self.with_parent(coroutine_def, |this| this.visit_expr(body)); } _ => visit::walk_fn(self, fn_kind), @@ -226,7 +238,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) { - self.create_def(id, kw::Empty, DefKind::Use, use_tree.span); + self.create_def(id, None, DefKind::Use, use_tree.span); visit::walk_use_tree(self, use_tree, id); } @@ -245,7 +257,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ForeignItemKind::MacCall(_) => return self.visit_macro_invoc(fi.id), }; - let def = self.create_def(fi.id, fi.ident.name, def_kind, fi.span); + let def = self.create_def(fi.id, Some(fi.ident.name), def_kind, fi.span); self.with_parent(def, |this| visit::walk_item(this, fi)); } @@ -254,12 +266,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { if v.is_placeholder { return self.visit_macro_invoc(v.id); } - let def = self.create_def(v.id, v.ident.name, DefKind::Variant, v.span); + let def = self.create_def(v.id, Some(v.ident.name), DefKind::Variant, v.span); self.with_parent(def, |this| { if let Some((ctor_kind, ctor_node_id)) = CtorKind::from_ast(&v.data) { this.create_def( ctor_node_id, - kw::Empty, + None, DefKind::Ctor(CtorOf::Variant, ctor_kind), v.span, ); @@ -268,6 +280,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { }); } + fn visit_where_predicate(&mut self, pred: &'a WherePredicate) { + if pred.is_placeholder { + self.visit_macro_invoc(pred.id) + } else { + visit::walk_where_predicate(self, pred) + } + } + fn visit_variant_data(&mut self, data: &'a VariantData) { // The assumption here is that non-`cfg` macro expansion cannot change field indices. // It currently holds because only inert attributes are accepted on fields, @@ -287,7 +307,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { GenericParamKind::Type { .. } => DefKind::TyParam, GenericParamKind::Const { .. } => DefKind::ConstParam, }; - self.create_def(param.id, param.ident.name, def_kind, param.ident.span); + self.create_def(param.id, Some(param.ident.name), def_kind, param.ident.span); // impl-Trait can happen inside generic parameters, like // ``` @@ -310,7 +330,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } }; - let def = self.create_def(i.id, i.ident.name, def_kind, i.span); + let def = self.create_def(i.id, Some(i.ident.name), def_kind, i.span); self.with_parent(def, |this| visit::walk_assoc_item(this, i, ctxt)); } @@ -322,8 +342,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { } fn visit_anon_const(&mut self, constant: &'a AnonConst) { - let parent = - self.create_def(constant.id, kw::Empty, DefKind::AnonConst, constant.value.span); + let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); } @@ -331,18 +350,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let parent_def = match expr.kind { ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), ExprKind::Closure(..) | ExprKind::Gen(..) => { - self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span) + self.create_def(expr.id, None, DefKind::Closure, expr.span) } ExprKind::ConstBlock(ref constant) => { for attr in &expr.attrs { visit::walk_attribute(self, attr); } - let def = self.create_def( - constant.id, - kw::Empty, - DefKind::InlineConst, - constant.value.span, - ); + let def = + self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span); self.with_parent(def, |this| visit::walk_anon_const(this, constant)); return; } @@ -366,7 +381,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { ImplTraitContext::Existential => DefKind::OpaqueTy, ImplTraitContext::InBinding => return visit::walk_ty(self, ty), }; - let id = self.create_def(*id, name, kind, ty.span); + let id = self.create_def(*id, Some(name), kind, ty.span); match self.impl_trait_context { // Do not nest APIT, as we desugar them as `impl_trait: bounds`, // so the `impl_trait` node is not a parent to `bounds`. @@ -442,4 +457,43 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { visit::walk_attribute(self, attr); self.in_attr = orig_in_attr; } + + fn visit_inline_asm(&mut self, asm: &'a InlineAsm) { + let InlineAsm { + asm_macro: _, + template: _, + template_strs: _, + operands, + clobber_abis: _, + options: _, + line_spans: _, + } = asm; + for (op, _span) in operands { + match op { + InlineAsmOperand::In { expr, reg: _ } + | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ } + | InlineAsmOperand::InOut { expr, reg: _, late: _ } => { + self.visit_expr(expr); + } + InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {} + InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + self.visit_expr(in_expr); + if let Some(expr) = out_expr { + self.visit_expr(expr); + } + } + InlineAsmOperand::Const { anon_const } => { + let def = self.create_def( + anon_const.id, + None, + DefKind::InlineConst, + anon_const.value.span, + ); + self.with_parent(def, |this| visit::walk_anon_const(this, anon_const)); + } + InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym), + InlineAsmOperand::Label { block } => self.visit_block(block), + } + } + } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 5db6f83f3ee51..5361af98f3c74 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -6,6 +6,7 @@ use rustc_ast::{ }; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, @@ -42,10 +43,10 @@ use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize, - HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, ModuleKind, - ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, - ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, VisResolutionError, - errors as errs, path_names_to_string, + ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, + ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, + PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, + VisResolutionError, errors as errs, path_names_to_string, }; type Res = def::Res; @@ -887,12 +888,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { participle, name, }), - ResolutionError::ForwardDeclaredGenericParam => { - self.dcx().create_err(errs::ForwardDeclaredGenericParam { span }) + ResolutionError::ForwardDeclaredGenericParam(param, reason) => match reason { + ForwardGenericParamBanReason::Default => { + self.dcx().create_err(errs::ForwardDeclaredGenericParam { param, span }) + } + ForwardGenericParamBanReason::ConstParamTy => self + .dcx() + .create_err(errs::ForwardDeclaredGenericInConstParamTy { param, span }), + }, + ResolutionError::ParamInTyOfConstParam { name } => { + self.dcx().create_err(errs::ParamInTyOfConstParam { span, name }) } - ResolutionError::ParamInTyOfConstParam { name, param_kind: is_type } => self - .dcx() - .create_err(errs::ParamInTyOfConstParam { span, name, param_kind: is_type }), ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => { self.dcx().create_err(errs::ParamInNonTrivialAnonConst { span, @@ -908,9 +914,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self .dcx() .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }), - ResolutionError::SelfInGenericParamDefault => { - self.dcx().create_err(errs::SelfInGenericParamDefault { span }) - } + ResolutionError::ForwardDeclaredSelf(reason) => match reason { + ForwardGenericParamBanReason::Default => { + self.dcx().create_err(errs::SelfInGenericParamDefault { span }) + } + ForwardGenericParamBanReason::ConstParamTy => { + self.dcx().create_err(errs::SelfInConstGenericTy { span }) + } + }, ResolutionError::UnreachableLabel { name, definition_span, suggestion } => { let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) = match suggestion { @@ -1457,6 +1468,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } + #[allow(rustc::potential_query_instability)] // FIXME let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| { if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None } }); @@ -1806,7 +1818,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && !def_id.is_local() && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive) { - non_exhaustive = Some(attr.span); + non_exhaustive = Some(attr.span()); } else if let Some(span) = ctor_fields_span { let label = errors::ConstructorPrivateIfAnyFieldPrivate { span }; err.subdiagnostic(label); @@ -2252,7 +2264,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { #[instrument(level = "debug", skip(self, parent_scope))] pub(crate) fn make_path_suggestion( &mut self, - span: Span, mut path: Vec, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec, Option)> { @@ -2267,7 +2278,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { && !first.ident.is_path_segment_keyword() => { // Insert a placeholder that's later replaced by `self`/`super`/etc. - path.insert(0, Segment::from_ident(Ident::empty())); + path.insert(0, Segment::from_ident(Ident::dummy())); } _ => return None, } @@ -2480,7 +2491,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // or `use a::{b, c, d}};` // ^^^^^^^^^^^ let (has_nested, after_crate_name) = - find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span); + find_span_immediately_after_crate_name(self.tcx.sess, import.use_span); debug!(has_nested, ?after_crate_name); let source_map = self.tcx.sess.source_map(); @@ -2687,11 +2698,7 @@ fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option /// // ^^^^^^^^^^^^^^^ -- true /// ``` #[instrument(level = "debug", skip(sess))] -fn find_span_immediately_after_crate_name( - sess: &Session, - module_name: Symbol, - use_span: Span, -) -> (bool, Span) { +fn find_span_immediately_after_crate_name(sess: &Session, use_span: Span) -> (bool, Span) { let source_map = sess.source_map(); // Using `use issue_59764::foo::{baz, makro};` as an example throughout.. @@ -2858,18 +2865,11 @@ fn show_candidates( } else { // Get the unique item kinds and if there's only one, we use the right kind name // instead of the more generic "items". - let mut kinds = accessible_path_strings + let kinds = accessible_path_strings .iter() .map(|(_, descr, _, _, _)| *descr) - .collect::>() - .into_iter(); - let kind = if let Some(kind) = kinds.next() - && let None = kinds.next() - { - kind - } else { - "item" - }; + .collect::>(); + let kind = if let Some(kind) = kinds.get_only() { kind } else { "item" }; let s = if kind.ends_with('s') { "es" } else { "s" }; ("one of these", kind, s, String::new(), "") diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 7eb795034b030..2ae6892bc93e6 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -338,6 +338,16 @@ pub(crate) struct ForwardDeclaredGenericParam { #[primary_span] #[label] pub(crate) span: Span, + pub(crate) param: Symbol, +} + +#[derive(Diagnostic)] +#[diag(resolve_forward_declared_generic_in_const_param_ty)] +pub(crate) struct ForwardDeclaredGenericInConstParamTy { + #[primary_span] + #[label] + pub(crate) span: Span, + pub(crate) param: Symbol, } #[derive(Diagnostic)] @@ -347,26 +357,19 @@ pub(crate) struct ParamInTyOfConstParam { #[label] pub(crate) span: Span, pub(crate) name: Symbol, - #[subdiagnostic] - pub(crate) param_kind: Option, -} - -#[derive(Debug)] -#[derive(Subdiagnostic)] -pub(crate) enum ParamKindInTyOfConstParam { - #[note(resolve_type_param_in_ty_of_const_param)] - Type, - #[note(resolve_const_param_in_ty_of_const_param)] - Const, - #[note(resolve_lifetime_param_in_ty_of_const_param)] - Lifetime, } #[derive(Diagnostic)] #[diag(resolve_self_in_generic_param_default, code = E0735)] pub(crate) struct SelfInGenericParamDefault { #[primary_span] - #[label] + pub(crate) span: Span, +} + +#[derive(Diagnostic)] +#[diag(resolve_self_in_const_generic_ty)] +pub(crate) struct SelfInConstGenericTy { + #[primary_span] pub(crate) span: Span, } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 499b9bca4d2ad..27d63198836a3 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -946,6 +946,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check if one of single imports can still define the name, // if it can then our result is not determined and can be invalidated. + #[allow(rustc::potential_query_instability)] // FIXME for single_import in &resolution.single_imports { if ignore_import == Some(*single_import) { // This branch handles a cycle in single imports. @@ -1117,13 +1118,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { debug!("validate_res_from_ribs({:?})", res); let ribs = &all_ribs[rib_index + 1..]; - // An invalid forward use of a generic parameter from a previous default. - if let RibKind::ForwardGenericParamBan = all_ribs[rib_index].kind { + // An invalid forward use of a generic parameter from a previous default + // or in a const param ty. + if let RibKind::ForwardGenericParamBan(reason) = all_ribs[rib_index].kind { if let Some(span) = finalize { let res_error = if rib_ident.name == kw::SelfUpper { - ResolutionError::SelfInGenericParamDefault + ResolutionError::ForwardDeclaredSelf(reason) } else { - ResolutionError::ForwardDeclaredGenericParam + ResolutionError::ForwardDeclaredGenericParam(rib_ident.name, reason) }; self.report_error(span, res_error); } @@ -1142,7 +1144,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | RibKind::FnOrCoroutine | RibKind::Module(..) | RibKind::MacroDefinition(..) - | RibKind::ForwardGenericParamBan => { + | RibKind::ForwardGenericParamBan(_) => { // Nothing to do. Continue. } RibKind::Item(..) | RibKind::AssocItem => { @@ -1209,10 +1211,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if let Some(span) = finalize { self.report_error( span, - ParamInTyOfConstParam { - name: rib_ident.name, - param_kind: None, - }, + ParamInTyOfConstParam { name: rib_ident.name }, ); } return Res::Err; @@ -1239,11 +1238,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | RibKind::MacroDefinition(..) | RibKind::InlineAsmSym | RibKind::AssocItem - | RibKind::ForwardGenericParamBan => { + | RibKind::ForwardGenericParamBan(_) => { // Nothing to do. Continue. continue; } + RibKind::ConstParamTy => { + if !self.tcx.features().generic_const_parameter_types() { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInTyOfConstParam { + name: rib_ident.name, + }, + ); + } + return Res::Err; + } else { + continue; + } + } + RibKind::ConstantItem(trivial, _) => { if let ConstantHasGenerics::No(cause) = trivial { // HACK(min_const_generics): If we encounter `Self` in an anonymous @@ -1292,18 +1307,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { RibKind::Item(has_generic_params, def_kind) => { (has_generic_params, def_kind) } - RibKind::ConstParamTy => { - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::ParamInTyOfConstParam { - name: rib_ident.name, - param_kind: Some(errors::ParamKindInTyOfConstParam::Type), - }, - ); - } - return Res::Err; - } }; if let Some(span) = finalize { @@ -1328,7 +1331,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { | RibKind::MacroDefinition(..) | RibKind::InlineAsmSym | RibKind::AssocItem - | RibKind::ForwardGenericParamBan => continue, + | RibKind::ForwardGenericParamBan(_) => continue, + + RibKind::ConstParamTy => { + if !self.tcx.features().generic_const_parameter_types() { + if let Some(span) = finalize { + self.report_error( + span, + ResolutionError::ParamInTyOfConstParam { + name: rib_ident.name, + }, + ); + } + return Res::Err; + } else { + continue; + } + } RibKind::ConstantItem(trivial, _) => { if let ConstantHasGenerics::No(cause) = trivial { @@ -1361,18 +1380,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { RibKind::Item(has_generic_params, def_kind) => { (has_generic_params, def_kind) } - RibKind::ConstParamTy => { - if let Some(span) = finalize { - self.report_error( - span, - ResolutionError::ParamInTyOfConstParam { - name: rib_ident.name, - param_kind: Some(errors::ParamKindInTyOfConstParam::Const), - }, - ); - } - return Res::Err; - } }; // This was an attempt to use a const parameter outside its scope. @@ -1391,6 +1398,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } _ => {} } + res } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 46e52e1f131b0..89b9a07435183 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -98,13 +98,13 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { use ImportKind::*; match self { Single { - ref source, - ref target, - ref source_bindings, - ref target_bindings, - ref type_ns_only, - ref nested, - ref id, + source, + target, + source_bindings, + target_bindings, + type_ns_only, + nested, + id, } => f .debug_struct("Single") .field("source", source) @@ -122,13 +122,13 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { .field("nested", nested) .field("id", id) .finish(), - Glob { ref is_prelude, ref max_vis, ref id } => f + Glob { is_prelude, max_vis, id } => f .debug_struct("Glob") .field("is_prelude", is_prelude) .field("max_vis", max_vis) .field("id", id) .finish(), - ExternCrate { ref source, ref target, ref id } => f + ExternCrate { source, target, id } => f .debug_struct("ExternCrate") .field("source", source) .field("target", target) @@ -955,11 +955,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { None }; - let err = match self.make_path_suggestion( - span, - import.module_path.clone(), - &import.parent_scope, - ) { + let err = match self + .make_path_suggestion(import.module_path.clone(), &import.parent_scope) + { Some((suggestion, note)) => UnresolvedImportError { span, label: None, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 03aeb8720ca62..6056a69ee71f6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -18,6 +18,7 @@ use rustc_ast::visit::{ }; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, DiagArgValue, ErrorGuaranteed, IntoDiagArg, StashKey, Suggestions, @@ -47,8 +48,6 @@ mod diagnostics; type Res = def::Res; -type IdentMap = FxHashMap; - use diagnostics::{ElisionFnParameter, LifetimeElisionCandidate, MissingLifetime}; #[derive(Copy, Clone, Debug)] @@ -78,6 +77,7 @@ struct IsNeverPattern; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum AnonConstKind { EnumDiscriminant, + FieldDefaultValue, InlineConst, ConstArg(IsRepeatExpr), } @@ -94,7 +94,7 @@ impl PatternSource { } impl IntoDiagArg for PatternSource { - fn into_diag_arg(self) -> DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { DiagArgValue::Str(Cow::Borrowed(self.descr())) } } @@ -206,7 +206,7 @@ pub(crate) enum RibKind<'ra> { /// All bindings in this rib are generic parameters that can't be used /// from the default of a generic parameter because they're not declared /// before said generic parameter. Also see the `visit_generics` override. - ForwardGenericParamBan, + ForwardGenericParamBan(ForwardGenericParamBanReason), /// We are inside of the type of a const parameter. Can't refer to any /// parameters. @@ -217,6 +217,12 @@ pub(crate) enum RibKind<'ra> { InlineAsmSym, } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub(crate) enum ForwardGenericParamBanReason { + Default, + ConstParamTy, +} + impl RibKind<'_> { /// Whether this rib kind contains generic parameters, as opposed to local /// variables. @@ -227,9 +233,11 @@ impl RibKind<'_> { | RibKind::ConstantItem(..) | RibKind::Module(_) | RibKind::MacroDefinition(_) - | RibKind::ConstParamTy | RibKind::InlineAsmSym => false, - RibKind::AssocItem | RibKind::Item(..) | RibKind::ForwardGenericParamBan => true, + RibKind::ConstParamTy + | RibKind::AssocItem + | RibKind::Item(..) + | RibKind::ForwardGenericParamBan(_) => true, } } @@ -243,7 +251,7 @@ impl RibKind<'_> { | RibKind::Item(..) | RibKind::ConstantItem(..) | RibKind::Module(..) - | RibKind::ForwardGenericParamBan + | RibKind::ForwardGenericParamBan(_) | RibKind::ConstParamTy | RibKind::InlineAsmSym => true, } @@ -264,8 +272,8 @@ impl RibKind<'_> { /// resolving, the name is looked up from inside out. #[derive(Debug)] pub(crate) struct Rib<'ra, R = Res> { - pub bindings: IdentMap, - pub patterns_with_skipped_bindings: FxHashMap)>>, + pub bindings: FxHashMap, + pub patterns_with_skipped_bindings: UnordMap)>>, pub kind: RibKind<'ra>, } @@ -394,32 +402,37 @@ pub(crate) enum AliasPossibility { #[derive(Copy, Clone, Debug)] pub(crate) enum PathSource<'a> { - // Type paths `Path`. + /// Type paths `Path`. Type, - // Trait paths in bounds or impls. + /// Trait paths in bounds or impls. Trait(AliasPossibility), - // Expression paths `path`, with optional parent context. + /// Expression paths `path`, with optional parent context. Expr(Option<&'a Expr>), - // Paths in path patterns `Path`. + /// Paths in path patterns `Path`. Pat, - // Paths in struct expressions and patterns `Path { .. }`. + /// Paths in struct expressions and patterns `Path { .. }`. Struct, - // Paths in tuple struct patterns `Path(..)`. + /// Paths in tuple struct patterns `Path(..)`. TupleStruct(Span, &'a [Span]), - // `m::A::B` in `::B::C`. + /// `m::A::B` in `::B::C`. TraitItem(Namespace), - // Paths in delegation item + /// Paths in delegation item Delegation, /// An arg in a `use<'a, N>` precise-capturing bound. PreciseCapturingArg(Namespace), - // Paths that end with `(..)`, for return type notation. + /// Paths that end with `(..)`, for return type notation. ReturnTypeNotation, + /// Paths from `#[define_opaque]` attributes + DefineOpaques, } impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { - PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, + PathSource::Type + | PathSource::Trait(_) + | PathSource::Struct + | PathSource::DefineOpaques => TypeNS, PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) @@ -440,6 +453,7 @@ impl<'a> PathSource<'a> { | PathSource::ReturnTypeNotation => true, PathSource::Trait(_) | PathSource::TraitItem(..) + | PathSource::DefineOpaques | PathSource::Delegation | PathSource::PreciseCapturingArg(..) => false, } @@ -447,6 +461,7 @@ impl<'a> PathSource<'a> { fn descr_expected(self) -> &'static str { match &self { + PathSource::DefineOpaques => "type alias or associated type with opaqaue types", PathSource::Type => "type", PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct, unit variant or constant", @@ -490,6 +505,19 @@ impl<'a> PathSource<'a> { pub(crate) fn is_expected(self, res: Res) -> bool { match self { + PathSource::DefineOpaques => { + matches!( + res, + Res::Def( + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::TyAlias + | DefKind::AssocTy, + _ + ) | Res::SelfTyAlias { .. } + ) + } PathSource::Type => matches!( res, Res::Def( @@ -569,16 +597,16 @@ impl<'a> PathSource<'a> { match (self, has_unexpected_resolution) { (PathSource::Trait(_), true) => E0404, (PathSource::Trait(_), false) => E0405, - (PathSource::Type, true) => E0573, - (PathSource::Type, false) => E0412, + (PathSource::Type | PathSource::DefineOpaques, true) => E0573, + (PathSource::Type | PathSource::DefineOpaques, false) => E0412, (PathSource::Struct, true) => E0574, (PathSource::Struct, false) => E0422, (PathSource::Expr(..), true) | (PathSource::Delegation, true) => E0423, (PathSource::Expr(..), false) | (PathSource::Delegation, false) => E0425, (PathSource::Pat | PathSource::TupleStruct(..), true) => E0532, (PathSource::Pat | PathSource::TupleStruct(..), false) => E0531, - (PathSource::TraitItem(..), true) | (PathSource::ReturnTypeNotation, true) => E0575, - (PathSource::TraitItem(..), false) | (PathSource::ReturnTypeNotation, false) => E0576, + (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, true) => E0575, + (PathSource::TraitItem(..) | PathSource::ReturnTypeNotation, false) => E0576, (PathSource::PreciseCapturingArg(..), true) => E0799, (PathSource::PreciseCapturingArg(..), false) => E0800, } @@ -621,7 +649,7 @@ pub(crate) struct UnnecessaryQualification<'ra> { pub removal_span: Span, } -#[derive(Default)] +#[derive(Default, Debug)] struct DiagMetadata<'ast> { /// The current trait's associated items' ident, used for diagnostic suggestions. current_trait_assoc_items: Option<&'ast [P]>, @@ -1191,7 +1219,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r debug!("visit_generic_arg({:?})", arg); let prev = replace(&mut self.diag_metadata.currently_processing_generic_args, true); match arg { - GenericArg::Type(ref ty) => { + GenericArg::Type(ty) => { // We parse const arguments as path types as we cannot distinguish them during // parsing. We try to resolve that ambiguity by attempting resolution the type // namespace first, and if that fails we try again in the value namespace. If @@ -1200,7 +1228,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r if let TyKind::Path(None, ref path) = ty.kind // We cannot disambiguate multi-segment paths right now as that requires type // checking. - && path.is_potential_trivial_const_arg() + && path.is_potential_trivial_const_arg(false) { let mut check_ns = |ns| { self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) @@ -1404,7 +1432,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r visit_opt!(self, visit_ident, ident); try_visit!(self.visit_ty(ty)); if let Some(v) = &default { - self.resolve_anon_const(v, AnonConstKind::ConstArg(IsRepeatExpr::No)); + self.resolve_anon_const(v, AnonConstKind::FieldDefaultValue); } } } @@ -1538,8 +1566,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // provide previous type parameters as they're built. We // put all the parameters on the ban list and then remove // them one by one as they are processed and become available. - let mut forward_ty_ban_rib = Rib::new(RibKind::ForwardGenericParamBan); - let mut forward_const_ban_rib = Rib::new(RibKind::ForwardGenericParamBan); + let mut forward_ty_ban_rib = + Rib::new(RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::Default)); + let mut forward_const_ban_rib = + Rib::new(RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::Default)); for param in params.iter() { match param.kind { GenericParamKind::Type { .. } => { @@ -1570,6 +1600,25 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { forward_ty_ban_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), Res::Err); } + // NOTE: We use different ribs here not for a technical reason, but just + // for better diagnostics. + let mut forward_ty_ban_rib_const_param_ty = Rib { + bindings: forward_ty_ban_rib.bindings.clone(), + patterns_with_skipped_bindings: Default::default(), + kind: RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::ConstParamTy), + }; + let mut forward_const_ban_rib_const_param_ty = Rib { + bindings: forward_const_ban_rib.bindings.clone(), + patterns_with_skipped_bindings: Default::default(), + kind: RibKind::ForwardGenericParamBan(ForwardGenericParamBanReason::ConstParamTy), + }; + // We'll ban these with a `ConstParamTy` rib, so just clear these ribs for better + // diagnostics, so we don't mention anything about const param tys having generics at all. + if !self.r.tcx.features().generic_const_parameter_types() { + forward_ty_ban_rib_const_param_ty.bindings.clear(); + forward_const_ban_rib_const_param_ty.bindings.clear(); + } + self.with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| { for param in params { match param.kind { @@ -1583,7 +1632,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { this.visit_param_bound(bound, BoundKind::Bound); } - if let Some(ref ty) = default { + if let Some(ty) = default { this.ribs[TypeNS].push(forward_ty_ban_rib); this.ribs[ValueNS].push(forward_const_ban_rib); this.visit_ty(ty); @@ -1592,23 +1641,31 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } // Allow all following defaults to refer to this type parameter. - forward_ty_ban_rib - .bindings - .remove(&Ident::with_dummy_span(param.ident.name)); + let i = &Ident::with_dummy_span(param.ident.name); + forward_ty_ban_rib.bindings.remove(i); + forward_ty_ban_rib_const_param_ty.bindings.remove(i); } GenericParamKind::Const { ref ty, kw_span: _, ref default } => { // Const parameters can't have param bounds. assert!(param.bounds.is_empty()); - this.ribs[TypeNS].push(Rib::new(RibKind::ConstParamTy)); - this.ribs[ValueNS].push(Rib::new(RibKind::ConstParamTy)); - this.with_lifetime_rib(LifetimeRibKind::ConstParamTy, |this| { + this.ribs[TypeNS].push(forward_ty_ban_rib_const_param_ty); + this.ribs[ValueNS].push(forward_const_ban_rib_const_param_ty); + if this.r.tcx.features().generic_const_parameter_types() { this.visit_ty(ty) - }); - this.ribs[TypeNS].pop().unwrap(); - this.ribs[ValueNS].pop().unwrap(); + } else { + this.ribs[TypeNS].push(Rib::new(RibKind::ConstParamTy)); + this.ribs[ValueNS].push(Rib::new(RibKind::ConstParamTy)); + this.with_lifetime_rib(LifetimeRibKind::ConstParamTy, |this| { + this.visit_ty(ty) + }); + this.ribs[TypeNS].pop().unwrap(); + this.ribs[ValueNS].pop().unwrap(); + } + forward_const_ban_rib_const_param_ty = this.ribs[ValueNS].pop().unwrap(); + forward_ty_ban_rib_const_param_ty = this.ribs[TypeNS].pop().unwrap(); - if let Some(ref expr) = default { + if let Some(expr) = default { this.ribs[TypeNS].push(forward_ty_ban_rib); this.ribs[ValueNS].push(forward_const_ban_rib); this.resolve_anon_const( @@ -1620,9 +1677,9 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } // Allow all following defaults to refer to this const parameter. - forward_const_ban_rib - .bindings - .remove(&Ident::with_dummy_span(param.ident.name)); + let i = &Ident::with_dummy_span(param.ident.name); + forward_const_ban_rib.bindings.remove(i); + forward_const_ban_rib_const_param_ty.bindings.remove(i); } } } @@ -1984,6 +2041,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { | PathSource::Pat | PathSource::Struct | PathSource::TupleStruct(..) + | PathSource::DefineOpaques | PathSource::Delegation => true, }; if inferred { @@ -2275,7 +2333,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let local_candidates = self.lifetime_elision_candidates.take(); if let Some(candidates) = local_candidates { - let distinct: FxHashSet<_> = candidates.iter().map(|(res, _)| *res).collect(); + let distinct: UnordSet<_> = candidates.iter().map(|(res, _)| *res).collect(); let lifetime_count = distinct.len(); if lifetime_count != 0 { parameter_info.push(ElisionFnParameter { @@ -2299,14 +2357,13 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } })); } - let mut distinct_iter = distinct.into_iter(); - if let Some(res) = distinct_iter.next() { + if !distinct.is_empty() { match elision_lifetime { // We are the first parameter to bind lifetimes. Elision::None => { - if distinct_iter.next().is_none() { + if let Some(res) = distinct.get_only() { // We have a single lifetime => success. - elision_lifetime = Elision::Param(res) + elision_lifetime = Elision::Param(*res) } else { // We have multiple lifetimes => error. elision_lifetime = Elision::Err; @@ -2597,7 +2654,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); } - ItemKind::Fn(box Fn { ref generics, .. }) => { + ItemKind::Fn(box Fn { ref generics, ref define_opaque, .. }) => { self.with_generic_param_rib( &generics.params, RibKind::Item(HasGenericParams::Yes(generics.span), def_kind), @@ -2608,6 +2665,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, |this| visit::walk_item(this, item), ); + + for (id, path) in define_opaque.iter().flatten() { + self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); + } } ItemKind::Enum(_, ref generics) @@ -2827,6 +2888,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { break; } + #[allow(rustc::potential_query_instability)] // FIXME seen_bindings .extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span))); } @@ -2973,7 +3035,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } // HACK(min_const_generics, generic_const_exprs): We - // want to keep allowing `[0; std::mem::size_of::<*mut T>()]` + // want to keep allowing `[0; size_of::<*mut T>()]` // with a future compat lint for now. We do this by adding an // additional special case for repeat expressions. // @@ -3078,8 +3140,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, ); } - AssocItemKind::Fn(box Fn { generics, .. }) => { + AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { walk_assoc_item(self, generics, LifetimeBinderKind::Function, item); + + for (id, path) in define_opaque.iter().flatten() { + self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); + } } AssocItemKind::Delegation(delegation) => { self.with_generic_param_rib( @@ -3125,6 +3191,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::Trait(AliasPossibility::No), Finalize::new(trait_ref.ref_id, trait_ref.path.span), RecordPartialRes::Yes, + None, ); self.diag_metadata.currently_processing_impl_trait = None; if let Some(def_id) = res.expect_full_res().opt_def_id() { @@ -3288,7 +3355,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, ); } - AssocItemKind::Fn(box Fn { generics, .. }) => { + AssocItemKind::Fn(box Fn { generics, define_opaque, .. }) => { debug!("resolve_implementation AssocItemKind::Fn"); // We also need a new scope for the impl item type parameters. self.with_generic_param_rib( @@ -3315,6 +3382,10 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { visit::walk_assoc_item(this, item, AssocCtxt::Impl) }, ); + + for (id, path) in define_opaque.iter().flatten() { + self.smart_resolve_path(*id, &None, path, PathSource::DefineOpaques); + } } AssocItemKind::Type(box TyAlias { generics, .. }) => { self.diag_metadata.in_non_gat_assoc_type = Some(generics.params.is_empty()); @@ -3932,7 +4003,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } } - fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut IdentMap { + fn innermost_rib_bindings(&mut self, ns: Namespace) -> &mut FxHashMap { &mut self.ribs[ns].last_mut().unwrap().bindings } @@ -4051,6 +4122,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { source, Finalize::new(id, path.span), RecordPartialRes::Yes, + None, ); } @@ -4062,14 +4134,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { source: PathSource<'ast>, finalize: Finalize, record_partial_res: RecordPartialRes, + parent_qself: Option<&QSelf>, ) -> PartialRes { let ns = source.namespace(); let Finalize { node_id, path_span, .. } = finalize; let report_errors = |this: &mut Self, res: Option| { if this.should_report_errs() { - let (err, candidates) = - this.smart_resolve_report_errors(path, None, path_span, source, res); + let (err, candidates) = this.smart_resolve_report_errors( + path, + None, + path_span, + source, + res, + parent_qself, + ); let def_id = this.parent_scope.module.nearest_parent_mod(); let instead = res.is_some(); @@ -4138,6 +4217,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { path_span, PathSource::Type, None, + parent_qself, ); // There are two different error messages user might receive at @@ -4415,6 +4495,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::Trait(AliasPossibility::No), Finalize::new(finalize.node_id, qself.path_span), RecordPartialRes::No, + Some(&qself), ); if trait_res.expect_full_res() == Res::Err { @@ -4439,6 +4520,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { PathSource::TraitItem(ns), Finalize::with_root_span(finalize.node_id, finalize.path_span, qself.path_span), RecordPartialRes::No, + Some(&qself), ); // The remaining segments (the `C` in our example) will @@ -4609,11 +4691,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { constant, anon_const_kind ); - self.resolve_anon_const_manual( - constant.value.is_potential_trivial_const_arg(), - anon_const_kind, - |this| this.resolve_expr(&constant.value, None), - ) + let is_trivial_const_arg = constant + .value + .is_potential_trivial_const_arg(self.r.tcx.features().min_generic_const_args()); + self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| { + this.resolve_expr(&constant.value, None) + }) } /// There are a few places that we need to resolve an anon const but we did not parse an @@ -4637,6 +4720,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { AnonConstKind::EnumDiscriminant => { ConstantHasGenerics::No(NoConstantGenericsReason::IsEnumDiscriminant) } + AnonConstKind::FieldDefaultValue => ConstantHasGenerics::Yes, AnonConstKind::InlineConst => ConstantHasGenerics::Yes, AnonConstKind::ConstArg(_) => { if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg { @@ -4773,8 +4857,11 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // Constant arguments need to be treated as AnonConst since // that is how they will be later lowered to HIR. if const_args.contains(&idx) { + let is_trivial_const_arg = argument.is_potential_trivial_const_arg( + self.r.tcx.features().min_generic_const_args(), + ); self.resolve_anon_const_manual( - argument.is_potential_trivial_const_arg(), + is_trivial_const_arg, AnonConstKind::ConstArg(IsRepeatExpr::No), |this| this.resolve_expr(argument, None), ); @@ -5029,12 +5116,18 @@ struct ItemInfoCollector<'a, 'ra, 'tcx> { } impl ItemInfoCollector<'_, '_, '_> { - fn collect_fn_info(&mut self, sig: &FnSig, id: NodeId, attrs: &[Attribute]) { + fn collect_fn_info( + &mut self, + header: FnHeader, + decl: &FnDecl, + id: NodeId, + attrs: &[Attribute], + ) { let sig = DelegationFnSig { - header: sig.header, - param_count: sig.decl.inputs.len(), - has_self: sig.decl.has_self(), - c_variadic: sig.decl.c_variadic(), + header, + param_count: decl.inputs.len(), + has_self: decl.has_self(), + c_variadic: decl.c_variadic(), target_feature: attrs.iter().any(|attr| attr.has_name(sym::target_feature)), }; self.r.delegation_fn_sigs.insert(self.r.local_def_id(id), sig); @@ -5044,17 +5137,17 @@ impl ItemInfoCollector<'_, '_, '_> { impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { fn visit_item(&mut self, item: &'ast Item) { match &item.kind { - ItemKind::TyAlias(box TyAlias { ref generics, .. }) - | ItemKind::Const(box ConstItem { ref generics, .. }) - | ItemKind::Fn(box Fn { ref generics, .. }) - | ItemKind::Enum(_, ref generics) - | ItemKind::Struct(_, ref generics) - | ItemKind::Union(_, ref generics) - | ItemKind::Impl(box Impl { ref generics, .. }) - | ItemKind::Trait(box Trait { ref generics, .. }) - | ItemKind::TraitAlias(ref generics, _) => { - if let ItemKind::Fn(box Fn { ref sig, .. }) = &item.kind { - self.collect_fn_info(sig, item.id, &item.attrs); + ItemKind::TyAlias(box TyAlias { generics, .. }) + | ItemKind::Const(box ConstItem { generics, .. }) + | ItemKind::Fn(box Fn { generics, .. }) + | ItemKind::Enum(_, generics) + | ItemKind::Struct(_, generics) + | ItemKind::Union(_, generics) + | ItemKind::Impl(box Impl { generics, .. }) + | ItemKind::Trait(box Trait { generics, .. }) + | ItemKind::TraitAlias(generics, _) => { + if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind { + self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); } let def_id = self.r.local_def_id(item.id); @@ -5066,8 +5159,17 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { self.r.item_generics_num_lifetimes.insert(def_id, count); } + ItemKind::ForeignMod(ForeignMod { extern_span, safety: _, abi, items }) => { + for foreign_item in items { + if let ForeignItemKind::Fn(box Fn { sig, .. }) = &foreign_item.kind { + let new_header = + FnHeader { ext: Extern::from_abi(*abi, *extern_span), ..sig.header }; + self.collect_fn_info(new_header, &sig.decl, foreign_item.id, &item.attrs); + } + } + } + ItemKind::Mod(..) - | ItemKind::ForeignMod(..) | ItemKind::Static(..) | ItemKind::Use(..) | ItemKind::ExternCrate(..) @@ -5086,8 +5188,8 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> { } fn visit_assoc_item(&mut self, item: &'ast AssocItem, ctxt: AssocCtxt) { - if let AssocItemKind::Fn(box Fn { ref sig, .. }) = &item.kind { - self.collect_fn_info(sig, item.id, &item.attrs); + if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind { + self.collect_fn_info(sig.header, &sig.decl, item.id, &item.attrs); } visit::walk_assoc_item(self, item, ctxt); } @@ -5099,6 +5201,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut late_resolution_visitor = LateResolutionVisitor::new(self); late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID)); visit::walk_crate(&mut late_resolution_visitor, krate); + #[allow(rustc::potential_query_instability)] // FIXME for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() { self.lint_buffer.buffer_lint( lint::builtin::UNUSED_LABELS, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index b37c684a0556a..bcfcc8000c718 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -24,7 +24,7 @@ use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_hir::{MissingLifetimeKind, PrimTy}; use rustc_middle::ty; use rustc_session::{Session, lint}; -use rustc_span::edit_distance::find_best_match_for_name; +use rustc_span::edit_distance::{edit_distance, find_best_match_for_name}; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; @@ -35,7 +35,7 @@ use super::NoConstantGenericsReason; use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; use crate::late::{ AliasPossibility, LateResolutionVisitor, LifetimeBinderKind, LifetimeRes, LifetimeRibKind, - LifetimeUseSet, RibKind, + LifetimeUseSet, QSelf, RibKind, }; use crate::ty::fast_reject::SimplifiedType; use crate::{ @@ -421,6 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { span: Span, source: PathSource<'_>, res: Option, + qself: Option<&QSelf>, ) -> (Diag<'tcx>, Vec) { debug!(?res, ?source); let base_error = self.make_base_error(path, span, source, res); @@ -429,6 +430,14 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let mut err = self.r.dcx().struct_span_err(base_error.span, base_error.msg.clone()); err.code(code); + // Try to get the span of the identifier within the path's syntax context + // (if that's different). + if let Some(within_macro_span) = + base_error.span.within_macro(span, self.r.tcx.sess.source_map()) + { + err.span_label(within_macro_span, "due to this macro variable"); + } + self.detect_missing_binding_available_from_pattern(&mut err, path, following_seg); self.suggest_at_operator_in_slice_pat_with_range(&mut err, path); self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span); @@ -453,6 +462,15 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.suggest_self_or_self_ref(&mut err, path, span); self.detect_assoc_type_constraint_meant_as_path(&mut err, &base_error); + self.detect_rtn_with_fully_qualified_path( + &mut err, + path, + following_seg, + span, + source, + res, + qself, + ); if self.suggest_self_ty(&mut err, source, path, span) || self.suggest_self_value(&mut err, source, path, span) { @@ -501,6 +519,33 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { (err, candidates) } + fn detect_rtn_with_fully_qualified_path( + &self, + err: &mut Diag<'_>, + path: &[Segment], + following_seg: Option<&Segment>, + span: Span, + source: PathSource<'_>, + res: Option, + qself: Option<&QSelf>, + ) { + if let Some(Res::Def(DefKind::AssocFn, _)) = res + && let PathSource::TraitItem(TypeNS) = source + && let None = following_seg + && let Some(qself) = qself + && let TyKind::Path(None, ty_path) = &qself.ty.kind + && ty_path.segments.len() == 1 + && self.diag_metadata.current_where_predicate.is_some() + { + err.span_suggestion_verbose( + span, + "you might have meant to use the return type notation syntax", + format!("{}::{}(..)", ty_path.segments[0].ident, path[path.len() - 1].ident), + Applicability::MaybeIncorrect, + ); + } + } + fn detect_assoc_type_constraint_meant_as_path( &self, err: &mut Diag<'_>, @@ -516,7 +561,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let Some(params) = &segment.args else { continue; }; - let ast::GenericArgs::AngleBracketed(ref params) = params.deref() else { + let ast::GenericArgs::AngleBracketed(params) = params.deref() else { continue; }; for param in ¶ms.args { @@ -785,6 +830,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(rib) = &self.last_block_rib && let RibKind::Normal = rib.kind { + #[allow(rustc::potential_query_instability)] // FIXME for (ident, &res) in &rib.bindings { if let Res::Local(_) = res && path.len() == 1 @@ -973,6 +1019,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if let Some(err_code) = err.code { if err_code == E0425 { for label_rib in &self.label_ribs { + #[allow(rustc::potential_query_instability)] // FIXME for (label_ident, node_id) in &label_rib.bindings { let ident = path.last().unwrap().ident; if format!("'{ident}") == label_ident.to_string() { @@ -1132,7 +1179,10 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let [segment] = path else { return }; let None = following_seg else { return }; for rib in self.ribs[ValueNS].iter().rev() { - for (def_id, spans) in &rib.patterns_with_skipped_bindings { + let patterns_with_skipped_bindings = self.r.tcx.with_stable_hashing_context(|hcx| { + rib.patterns_with_skipped_bindings.to_sorted(&hcx, true) + }); + for (def_id, spans) in patterns_with_skipped_bindings { if let DefKind::Struct | DefKind::Variant = self.r.tcx.def_kind(*def_id) && let Some(fields) = self.r.field_idents(*def_id) { @@ -1668,7 +1718,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ); } if let PathSource::Expr(Some(Expr { - kind: ExprKind::Call(path, ref args), + kind: ExprKind::Call(path, args), span: call_span, .. })) = source @@ -1802,7 +1852,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } // e.g. `let _ = Enum::TupleVariant(field1, field2);` PathSource::Expr(Some(Expr { - kind: ExprKind::Call(path, ref args), + kind: ExprKind::Call(path, args), span: call_span, .. })) => { @@ -2007,7 +2057,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { if self .r .extern_crate_map - .iter() + .items() // FIXME: This doesn't include impls like `impl Default for String`. .flat_map(|(_, crate_)| self.r.tcx.implementations_of_trait((*crate_, default_trait))) .filter_map(|(_, simplified_self_ty)| *simplified_self_ty) @@ -2216,6 +2266,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { }; // Locals and type parameters + #[allow(rustc::potential_query_instability)] // FIXME for (ident, &res) in &rib.bindings { if filter_fn(res) && ident.span.ctxt() == rib_ctxt { names.push(TypoSuggestion::typo_from_ident(*ident, res)); @@ -2743,6 +2794,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let within_scope = self.is_label_valid_from_rib(rib_index); let rib = &self.label_ribs[rib_index]; + #[allow(rustc::potential_query_instability)] // FIXME let names = rib .bindings .iter() @@ -2754,6 +2806,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Upon finding a similar name, get the ident that it was from - the span // contained within helps make a useful diagnostic. In addition, determine // whether this candidate is within scope. + #[allow(rustc::potential_query_instability)] // FIXME let (ident, _) = rib.bindings.iter().find(|(ident, _)| ident.name == symbol).unwrap(); (*ident, within_scope) }) @@ -2874,23 +2927,35 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ) .with_span_label(lifetime_ref.ident.span, "undeclared lifetime") }; - self.suggest_introducing_lifetime( - &mut err, - Some(lifetime_ref.ident.name.as_str()), - |err, _, span, message, suggestion, span_suggs| { - err.multipart_suggestion_with_style( - message, - std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), - Applicability::MaybeIncorrect, - if span_suggs.is_empty() { - SuggestionStyle::ShowCode - } else { - SuggestionStyle::ShowAlways - }, - ); - true - }, - ); + + // Check if this is a typo of `'static`. + if edit_distance(lifetime_ref.ident.name.as_str(), "'static", 2).is_some() { + err.span_suggestion_verbose( + lifetime_ref.ident.span, + "you may have misspelled the `'static` lifetime", + "'static", + Applicability::MachineApplicable, + ); + } else { + self.suggest_introducing_lifetime( + &mut err, + Some(lifetime_ref.ident.name.as_str()), + |err, _, span, message, suggestion, span_suggs| { + err.multipart_suggestion_with_style( + message, + std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(), + Applicability::MaybeIncorrect, + if span_suggs.is_empty() { + SuggestionStyle::ShowCode + } else { + SuggestionStyle::ShowAlways + }, + ); + true + }, + ); + } + err.emit(); } @@ -3052,7 +3117,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .create_err(errors::ParamInTyOfConstParam { span: lifetime_ref.ident.span, name: lifetime_ref.ident.name, - param_kind: Some(errors::ParamKindInTyOfConstParam::Lifetime), }) .emit(); } @@ -3516,12 +3580,6 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } } - - // Record as using the suggested resolution. - let (_, (_, res)) = in_scope_lifetimes[0]; - for < in &lifetime_refs { - self.r.lifetimes_res_map.insert(lt.id, res); - } } _ => { let lifetime_spans: Vec<_> = diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index eb4ac6ce77c9c..447d5283e27ec 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -9,19 +9,16 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] #![feature(box_patterns)] -#![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::cell::{Cell, RefCell}; @@ -31,11 +28,12 @@ use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; use effective_visibilities::EffectiveVisibilitiesVisitor; -use errors::{ - ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam, -}; +use errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst}; use imports::{Import, ImportData, ImportKind, NameResolution}; -use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification}; +use late::{ + ForwardGenericParamBanReason, HasGenericParams, PathSource, PatternSource, + UnnecessaryQualification, +}; use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use rustc_arena::{DroplessArena, TypedArena}; use rustc_ast::expand::StrippedCfgItem; @@ -48,6 +46,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::FreezeReadGuard; +use rustc_data_structures::unord::UnordMap; use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; @@ -276,9 +275,11 @@ enum ResolutionError<'ra> { shadowed_binding_span: Span, }, /// Error E0128: generic parameters with a default cannot use forward-declared identifiers. - ForwardDeclaredGenericParam, + ForwardDeclaredGenericParam(Symbol, ForwardGenericParamBanReason), + // FIXME(generic_const_parameter_types): This should give custom output specifying it's only + // problematic to use *forward declared* parameters when the feature is enabled. /// ERROR E0770: the type of const parameters must not depend on other generic parameters. - ParamInTyOfConstParam { name: Symbol, param_kind: Option }, + ParamInTyOfConstParam { name: Symbol }, /// generic parameters must not be used inside const evaluations. /// /// This error is only emitted when using `min_const_generics`. @@ -288,7 +289,7 @@ enum ResolutionError<'ra> { /// This error is emitted even with `generic_const_exprs`. ParamInEnumDiscriminant { name: Symbol, param_kind: ParamKindInEnumDiscriminant }, /// Error E0735: generic parameters with a default cannot use `Self` - SelfInGenericParamDefault, + ForwardDeclaredSelf(ForwardGenericParamBanReason), /// Error E0767: use of unreachable label UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option }, /// Error E0323, E0324, E0325: mismatch between trait item and impl item. @@ -1045,7 +1046,7 @@ pub struct Resolver<'ra, 'tcx> { graph_root: Module<'ra>, prelude: Option>, - extern_prelude: FxHashMap>, + extern_prelude: FxIndexMap>, /// N.B., this is used only for better diagnostics, not name resolution itself. field_names: LocalDefIdMap>, @@ -1078,7 +1079,7 @@ pub struct Resolver<'ra, 'tcx> { extra_lifetime_params_map: NodeMap>, /// `CrateNum` resolutions of `extern crate` items. - extern_crate_map: FxHashMap, + extern_crate_map: UnordMap, module_children: LocalDefIdMap>, trait_map: NodeMap>, @@ -1101,7 +1102,7 @@ pub struct Resolver<'ra, 'tcx> { /// some AST passes can generate identifiers that only resolve to local or /// lang items. empty_module: Module<'ra>, - module_map: FxHashMap>, + module_map: FxIndexMap>, binding_parent_modules: FxHashMap, Module<'ra>>, underscore_disambiguator: u32, @@ -1135,7 +1136,7 @@ pub struct Resolver<'ra, 'tcx> { macro_names: FxHashSet, builtin_macros: FxHashMap, registered_tools: &'tcx RegisteredTools, - macro_use_prelude: FxHashMap>, + macro_use_prelude: FxIndexMap>, macro_map: FxHashMap, dummy_ext_bang: Arc, dummy_ext_derive: Arc, @@ -1144,7 +1145,7 @@ pub struct Resolver<'ra, 'tcx> { ast_transform_scopes: FxHashMap>, unused_macros: FxHashMap, /// A map from the macro to all its potentially unused arms. - unused_macro_rules: FxIndexMap>, + unused_macro_rules: FxIndexMap>, proc_macro_stubs: FxHashSet, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: @@ -1258,7 +1259,7 @@ impl<'ra> ResolverArenas<'ra> { expn_id: ExpnId, span: Span, no_implicit_prelude: bool, - module_map: &mut FxHashMap>, + module_map: &mut FxIndexMap>, module_self_bindings: &mut FxHashMap, NameBinding<'ra>>, ) -> Module<'ra> { let module = Module(Interned::new_unchecked(self.modules.alloc(ModuleData::new( @@ -1341,7 +1342,7 @@ impl<'tcx> Resolver<'_, 'tcx> { &mut self, parent: LocalDefId, node_id: ast::NodeId, - name: Symbol, + name: Option, def_kind: DefKind, expn_id: ExpnId, span: Span, @@ -1403,7 +1404,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { arenas: &'ra ResolverArenas<'ra>, ) -> Resolver<'ra, 'tcx> { let root_def_id = CRATE_DEF_ID.to_def_id(); - let mut module_map = FxHashMap::default(); + let mut module_map = FxIndexMap::default(); let mut module_self_bindings = FxHashMap::default(); let graph_root = arenas.new_module( None, @@ -1420,8 +1421,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ExpnId::root(), DUMMY_SP, true, - &mut FxHashMap::default(), - &mut FxHashMap::default(), + &mut Default::default(), + &mut Default::default(), ); let mut def_id_to_node_id = IndexVec::default(); @@ -1436,7 +1437,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut invocation_parents = FxHashMap::default(); invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT); - let mut extern_prelude: FxHashMap> = tcx + let mut extern_prelude: FxIndexMap> = tcx .sess .opts .externs @@ -1535,7 +1536,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { macro_names: FxHashSet::default(), builtin_macros: Default::default(), registered_tools, - macro_use_prelude: FxHashMap::default(), + macro_use_prelude: Default::default(), macro_map: FxHashMap::default(), dummy_ext_bang: Arc::new(SyntaxExtension::dummy_bang(edition)), dummy_ext_derive: Arc::new(SyntaxExtension::dummy_derive(edition)), diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index a70def2f6c93c..7100d89ad61a8 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -5,7 +5,6 @@ use std::cell::Cell; use std::mem; use std::sync::Arc; -use rustc_ast::attr::AttributeExt; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; @@ -324,6 +323,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } fn check_unused_macros(&mut self) { + #[allow(rustc::potential_query_instability)] // FIXME for (_, &(node_id, ident)) in self.unused_macros.iter() { self.lint_buffer.buffer_lint( UNUSED_MACROS, @@ -334,10 +334,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { } for (&def_id, unused_arms) in self.unused_macro_rules.iter() { - let mut unused_arms = unused_arms.iter().collect::>(); - unused_arms.sort_by_key(|&(&arm_i, _)| arm_i); - - for (&arm_i, &(ident, rule_span)) in unused_arms { + for (&arm_i, &(ident, rule_span)) in unused_arms.to_sorted_stable_ord() { if self.unused_macros.contains_key(&def_id) { // We already lint the entire macro as unused continue; @@ -1112,7 +1109,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, macro_def: &ast::MacroDef, ident: Ident, - attrs: &[impl AttributeExt], + attrs: &[rustc_hir::Attribute], span: Span, node_id: NodeId, edition: Edition, diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml index 5623a493cf009..900cd4243b13c 100644 --- a/compiler/rustc_sanitizers/Cargo.toml +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "rustc_sanitizers" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] bitflags = "2.5.0" tracing = "0.1" twox-hash = "1.6.3" rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_middle = { path = "../rustc_middle" } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 5f0c1afdf6420..e088417d72e35 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -468,7 +468,7 @@ pub(crate) fn encode_ty<'tcx>( )] tcx.dcx() .struct_span_err( - cfi_encoding.span, + cfi_encoding.span(), format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), ) .emit(); @@ -519,7 +519,7 @@ pub(crate) fn encode_ty<'tcx>( )] tcx.dcx() .struct_span_err( - cfi_encoding.span, + cfi_encoding.span(), format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), ) .emit(); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index b711c238d594b..129a32c6edd81 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -9,10 +9,9 @@ use std::iter; use rustc_hir as hir; use rustc_hir::LangItem; use rustc_middle::bug; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::{ self, ExistentialPredicateStableCmpExt as _, Instance, InstanceKind, IntTy, List, TraitRef, Ty, - TyCtxt, TypeFoldable, TypeVisitableExt, UintTy, + TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy, }; use rustc_span::def_id::DefId; use rustc_span::sym; diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs index 55be931bcd6d4..c4a9cab24d07a 100644 --- a/compiler/rustc_sanitizers/src/lib.rs +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -4,8 +4,8 @@ //! compiler. // tidy-alphabetical-start +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(let_chains)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod cfi; diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml index a6815c7a44768..948242352e7a8 100644 --- a/compiler/rustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_serialize" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs index aa7c285846661..4a47580569731 100644 --- a/compiler/rustc_serialize/src/leb128.rs +++ b/compiler/rustc_serialize/src/leb128.rs @@ -7,7 +7,7 @@ use crate::serialize::Decoder; /// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type pub const fn max_leb128_len() -> usize { // The longest LEB128 encoding for an integer uses 7 bits per byte. - (std::mem::size_of::() * 8 + 6) / 7 + (size_of::() * 8 + 6) / 7 } /// Returns the length of the longest LEB128 encoding of all supported integer types. diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index 47f72298e22ce..13c1a273eb816 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -13,9 +13,7 @@ #![feature(core_intrinsics)] #![feature(min_specialization)] #![feature(never_type)] -#![feature(ptr_sub_ptr)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub use self::serialize::{Decodable, Decoder, Encodable, Encoder}; diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 27e9f817894f3..d4907b69b720b 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -280,13 +280,13 @@ impl<'a> MemDecoder<'a> { #[inline] pub fn len(&self) -> usize { // SAFETY: This recovers the length of the original slice, only using members we never modify. - unsafe { self.end.sub_ptr(self.start) } + unsafe { self.end.offset_from_unsigned(self.start) } } #[inline] pub fn remaining(&self) -> usize { // SAFETY: This type guarantees current <= end. - unsafe { self.end.sub_ptr(self.current) } + unsafe { self.end.offset_from_unsigned(self.current) } } #[cold] @@ -400,7 +400,7 @@ impl<'a> Decoder for MemDecoder<'a> { #[inline] fn position(&self) -> usize { // SAFETY: This type guarantees start <= current - unsafe { self.current.sub_ptr(self.start) } + unsafe { self.current.offset_from_unsigned(self.start) } } } diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs index 0543e176ae5aa..5aeedbdcd4e23 100644 --- a/compiler/rustc_serialize/tests/opaque.rs +++ b/compiler/rustc_serialize/tests/opaque.rs @@ -3,11 +3,11 @@ use std::fmt::Debug; use std::fs; -use rustc_macros::{Decodable_Generic, Encodable_Generic}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext}; use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Encodable}; -#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)] +#[derive(PartialEq, Clone, Debug, Encodable_NoContext, Decodable_NoContext)] struct Struct { a: (), b: u8, @@ -210,7 +210,7 @@ fn test_struct() { }]); } -#[derive(PartialEq, Clone, Debug, Encodable_Generic, Decodable_Generic)] +#[derive(PartialEq, Clone, Debug, Encodable_NoContext, Decodable_NoContext)] enum Enum { Variant1, Variant2(usize, u32), @@ -259,7 +259,7 @@ fn test_tuples() { #[test] fn test_unit_like_struct() { - #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] + #[derive(Encodable_NoContext, Decodable_NoContext, PartialEq, Debug)] struct UnitLikeStruct; check_round_trip(vec![UnitLikeStruct]); @@ -267,7 +267,7 @@ fn test_unit_like_struct() { #[test] fn test_box() { - #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] + #[derive(Encodable_NoContext, Decodable_NoContext, PartialEq, Debug)] struct A { foo: Box<[bool]>, } @@ -280,12 +280,12 @@ fn test_box() { fn test_cell() { use std::cell::{Cell, RefCell}; - #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] + #[derive(Encodable_NoContext, Decodable_NoContext, PartialEq, Debug)] struct A { baz: isize, } - #[derive(Encodable_Generic, Decodable_Generic, PartialEq, Debug)] + #[derive(Encodable_NoContext, Decodable_NoContext, PartialEq, Debug)] struct B { foo: Cell, bar: RefCell, diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 31892c1343805..a087725d34dd1 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_session" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 4f44eaf6437b6..34755249b60b1 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -42,6 +42,32 @@ mod cfg; mod native_libs; pub mod sigpipe; +pub const PRINT_KINDS: &[(&str, PrintKind)] = &[ + // tidy-alphabetical-start + ("all-target-specs-json", PrintKind::AllTargetSpecs), + ("calling-conventions", PrintKind::CallingConventions), + ("cfg", PrintKind::Cfg), + ("check-cfg", PrintKind::CheckCfg), + ("code-models", PrintKind::CodeModels), + ("crate-name", PrintKind::CrateName), + ("deployment-target", PrintKind::DeploymentTarget), + ("file-names", PrintKind::FileNames), + ("host-tuple", PrintKind::HostTuple), + ("link-args", PrintKind::LinkArgs), + ("native-static-libs", PrintKind::NativeStaticLibs), + ("relocation-models", PrintKind::RelocationModels), + ("split-debuginfo", PrintKind::SplitDebuginfo), + ("stack-protector-strategies", PrintKind::StackProtectorStrategies), + ("sysroot", PrintKind::Sysroot), + ("target-cpus", PrintKind::TargetCPUs), + ("target-features", PrintKind::TargetFeatures), + ("target-libdir", PrintKind::TargetLibdir), + ("target-list", PrintKind::TargetList), + ("target-spec-json", PrintKind::TargetSpec), + ("tls-models", PrintKind::TlsModels), + // tidy-alphabetical-end +]; + /// The different settings that the `-C strip` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum Strip { @@ -539,7 +565,10 @@ impl FromStr for SplitDwarfKind { #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)] #[derive(Encodable, Decodable)] pub enum OutputType { + /// This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode, + /// depending on the specific request type. Bitcode, + /// This is the summary or index data part of the ThinLTO bitcode. ThinLinkBitcode, Assembly, LlvmAssembly, @@ -652,10 +681,14 @@ impl OutputType { } /// The type of diagnostics output to generate. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] pub enum ErrorOutputType { /// Output meant for the consumption of humans. - HumanReadable(HumanReadableErrorType, ColorConfig), + #[default] + HumanReadable { + kind: HumanReadableErrorType = HumanReadableErrorType::Default, + color_config: ColorConfig = ColorConfig::Auto, + }, /// Output that's consumed by other tools such as `rustfix` or the `RLS`. Json { /// Render the JSON in a human readable way (with indents and newlines). @@ -667,12 +700,6 @@ pub enum ErrorOutputType { }, } -impl Default for ErrorOutputType { - fn default() -> Self { - Self::HumanReadable(HumanReadableErrorType::Default, ColorConfig::Auto) - } -} - #[derive(Clone, Hash, Debug)] pub enum ResolveDocLinks { /// Do not resolve doc links. @@ -869,18 +896,13 @@ pub enum PrintKind { DeploymentTarget, } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Default)] pub struct NextSolverConfig { /// Whether the new trait solver should be enabled in coherence. - pub coherence: bool, + pub coherence: bool = true, /// Whether the new trait solver should be enabled everywhere. /// This is only `true` if `coherence` is also enabled. - pub globally: bool, -} -impl Default for NextSolverConfig { - fn default() -> Self { - NextSolverConfig { coherence: true, globally: false } - } + pub globally: bool = false, } #[derive(Clone)] @@ -1192,7 +1214,7 @@ impl Default for Options { describe_lints: false, output_types: OutputTypes(BTreeMap::new()), search_paths: vec![], - maybe_sysroot: None, + sysroot: filesearch::materialize_sysroot(None), target_triple: TargetTuple::from_tuple(host_tuple()), test: false, incremental: None, @@ -1505,6 +1527,13 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE ) }); +static PRINT_KINDS_STRING: LazyLock = LazyLock::new(|| { + format!( + "[{}]", + PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::>().join("|") + ) +}); + /// Returns all rustc command line options, including metadata for /// each option, such as whether the option is stable. pub fn rustc_optgroups() -> Vec { @@ -1565,10 +1594,7 @@ pub fn rustc_optgroups() -> Vec { "", "print", "Compiler information to print on stdout", - "[crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|\ - target-list|target-cpus|target-features|relocation-models|code-models|\ - tls-models|target-spec-json|all-target-specs-json|native-static-libs|\ - stack-protector-strategies|link-args|deployment-target]", + &PRINT_KINDS_STRING, ), opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""), opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""), @@ -1792,7 +1818,7 @@ pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Json pub fn parse_error_format( early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches, - color: ColorConfig, + color_config: ColorConfig, json_color: ColorConfig, json_rendered: HumanReadableErrorType, ) -> ErrorOutputType { @@ -1802,27 +1828,26 @@ pub fn parse_error_format( // `opt_present` because the latter will panic. let error_format = if matches.opts_present(&["error-format".to_owned()]) { match matches.opt_str("error-format").as_deref() { - None | Some("human") => { - ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color) - } - Some("human-annotate-rs") => { - ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet, color) - } + None | Some("human") => ErrorOutputType::HumanReadable { color_config, .. }, + Some("human-annotate-rs") => ErrorOutputType::HumanReadable { + kind: HumanReadableErrorType::AnnotateSnippet, + color_config, + }, Some("json") => { ErrorOutputType::Json { pretty: false, json_rendered, color_config: json_color } } Some("pretty-json") => { ErrorOutputType::Json { pretty: true, json_rendered, color_config: json_color } } - Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short, color), - Some("human-unicode") => { - ErrorOutputType::HumanReadable(HumanReadableErrorType::Unicode, color) + Some("short") => { + ErrorOutputType::HumanReadable { kind: HumanReadableErrorType::Short, color_config } } + Some("human-unicode") => ErrorOutputType::HumanReadable { + kind: HumanReadableErrorType::Unicode, + color_config, + }, Some(arg) => { - early_dcx.set_error_format(ErrorOutputType::HumanReadable( - HumanReadableErrorType::Default, - color, - )); + early_dcx.set_error_format(ErrorOutputType::HumanReadable { color_config, .. }); early_dcx.early_fatal(format!( "argument for `--error-format` must be `human`, `human-annotate-rs`, \ `human-unicode`, `json`, `pretty-json` or `short` (instead was `{arg}`)" @@ -1830,7 +1855,7 @@ pub fn parse_error_format( } } } else { - ErrorOutputType::HumanReadable(HumanReadableErrorType::Default, color) + ErrorOutputType::HumanReadable { color_config, .. } }; match error_format { @@ -1885,7 +1910,7 @@ fn check_error_format_stability( } let format = match format { ErrorOutputType::Json { pretty: true, .. } => "pretty-json", - ErrorOutputType::HumanReadable(format, _) => match format { + ErrorOutputType::HumanReadable { kind, .. } => match kind { HumanReadableErrorType::AnnotateSnippet => "human-annotate-rs", HumanReadableErrorType::Unicode => "human-unicode", _ => return, @@ -1996,32 +2021,6 @@ fn collect_print_requests( cg.target_feature = String::new(); } - const PRINT_KINDS: &[(&str, PrintKind)] = &[ - // tidy-alphabetical-start - ("all-target-specs-json", PrintKind::AllTargetSpecs), - ("calling-conventions", PrintKind::CallingConventions), - ("cfg", PrintKind::Cfg), - ("check-cfg", PrintKind::CheckCfg), - ("code-models", PrintKind::CodeModels), - ("crate-name", PrintKind::CrateName), - ("deployment-target", PrintKind::DeploymentTarget), - ("file-names", PrintKind::FileNames), - ("host-tuple", PrintKind::HostTuple), - ("link-args", PrintKind::LinkArgs), - ("native-static-libs", PrintKind::NativeStaticLibs), - ("relocation-models", PrintKind::RelocationModels), - ("split-debuginfo", PrintKind::SplitDebuginfo), - ("stack-protector-strategies", PrintKind::StackProtectorStrategies), - ("sysroot", PrintKind::Sysroot), - ("target-cpus", PrintKind::TargetCPUs), - ("target-features", PrintKind::TargetFeatures), - ("target-libdir", PrintKind::TargetLibdir), - ("target-list", PrintKind::TargetList), - ("target-spec-json", PrintKind::TargetSpec), - ("tls-models", PrintKind::TlsModels), - // tidy-alphabetical-end - ]; - // We disallow reusing the same path in multiple prints, such as `--print // cfg=output.txt --print link-args=output.txt`, because outputs are printed // by disparate pieces of the compiler, and keeping track of which files @@ -2619,7 +2618,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M describe_lints, output_types, search_paths, - maybe_sysroot: Some(sysroot), + sysroot, target_triple, test, incremental, @@ -2710,7 +2709,12 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateType::Cdylib, "bin" => CrateType::Executable, "proc-macro" => CrateType::ProcMacro, - _ => return Err(format!("unknown crate type: `{part}`")), + _ => { + return Err(format!( + "unknown crate type: `{part}`, expected one of: \ + `lib`, `rlib`, `staticlib`, `dylib`, `cdylib`, `bin`, `proc-macro`", + )); + } }; if !crate_types.contains(&new_part) { crate_types.push(new_part) @@ -2807,8 +2811,8 @@ impl fmt::Display for CrateType { } impl IntoDiagArg for CrateType { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, _: &mut Option) -> DiagArgValue { + self.to_string().into_diag_arg(&mut None) } } @@ -2880,14 +2884,6 @@ impl PpMode { | StableMir => true, } } - pub fn needs_hir(&self) -> bool { - use PpMode::*; - match *self { - Source(_) | AstTree | AstTreeExpanded => false, - - Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG | StableMir => true, - } - } pub fn needs_analysis(&self) -> bool { use PpMode::*; @@ -2921,12 +2917,13 @@ pub enum WasiExecModel { /// how the hash should be calculated when adding a new command-line argument. pub(crate) mod dep_tracking { use std::collections::BTreeMap; - use std::hash::{DefaultHasher, Hash}; + use std::hash::Hash; use std::num::NonZero; use std::path::PathBuf; use rustc_abi::Align; use rustc_data_structures::fx::FxIndexMap; + use rustc_data_structures::stable_hasher::StableHasher; use rustc_errors::LanguageIdentifier; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; @@ -2953,7 +2950,7 @@ pub(crate) mod dep_tracking { pub(crate) trait DepTrackingHash { fn hash( &self, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ); @@ -2962,7 +2959,7 @@ pub(crate) mod dep_tracking { macro_rules! impl_dep_tracking_hash_via_hash { ($($t:ty),+ $(,)?) => {$( impl DepTrackingHash for $t { - fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) { + fn hash(&self, hasher: &mut StableHasher, _: ErrorOutputType, _for_crate_hash: bool) { Hash::hash(self, hasher); } } @@ -2972,7 +2969,7 @@ pub(crate) mod dep_tracking { impl DepTrackingHash for Option { fn hash( &self, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ) { @@ -3057,7 +3054,7 @@ pub(crate) mod dep_tracking { { fn hash( &self, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ) { @@ -3076,7 +3073,7 @@ pub(crate) mod dep_tracking { { fn hash( &self, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ) { @@ -3092,7 +3089,7 @@ pub(crate) mod dep_tracking { impl DepTrackingHash for Vec { fn hash( &self, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ) { @@ -3107,7 +3104,7 @@ pub(crate) mod dep_tracking { impl DepTrackingHash for FxIndexMap { fn hash( &self, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ) { @@ -3122,7 +3119,7 @@ pub(crate) mod dep_tracking { impl DepTrackingHash for OutputTypes { fn hash( &self, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ) { @@ -3139,7 +3136,7 @@ pub(crate) mod dep_tracking { // This is a stable hash because BTreeMap is a sorted container pub(crate) fn stable_hash( sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, - hasher: &mut DefaultHasher, + hasher: &mut StableHasher, error_format: ErrorOutputType, for_crate_hash: bool, ) { diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index ec83761da4a92..50f09c57107e6 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -92,7 +92,7 @@ fn current_dll_path() -> Result { if libc::loadquery( libc::L_GETINFO, buffer.as_mut_ptr() as *mut u8, - (std::mem::size_of::() * buffer.len()) as u32, + (size_of::() * buffer.len()) as u32, ) >= 0 { break; @@ -160,8 +160,7 @@ fn current_dll_path() -> Result { pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> { let target = crate::config::host_tuple(); - let mut sysroot_candidates: SmallVec<[PathBuf; 2]> = - smallvec![get_or_default_sysroot().expect("Failed finding sysroot")]; + let mut sysroot_candidates: SmallVec<[PathBuf; 2]> = smallvec![get_or_default_sysroot()]; let path = current_dll_path().and_then(|s| try_canonicalize(s).map_err(|e| e.to_string())); if let Ok(dll) = path { // use `parent` twice to chop off the file name and then also the @@ -195,12 +194,12 @@ pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> { /// Returns the provided sysroot or calls [`get_or_default_sysroot`] if it's none. /// Panics if [`get_or_default_sysroot`] returns an error. pub fn materialize_sysroot(maybe_sysroot: Option) -> PathBuf { - maybe_sysroot.unwrap_or_else(|| get_or_default_sysroot().expect("Failed finding sysroot")) + maybe_sysroot.unwrap_or_else(|| get_or_default_sysroot()) } /// This function checks if sysroot is found using env::args().next(), and if it /// is not found, finds sysroot from current rustc_driver dll. -pub fn get_or_default_sysroot() -> Result { +pub fn get_or_default_sysroot() -> PathBuf { // Follow symlinks. If the resolved path is relative, make it absolute. fn canonicalize(path: PathBuf) -> PathBuf { let path = try_canonicalize(&path).unwrap_or(path); @@ -255,30 +254,25 @@ pub fn get_or_default_sysroot() -> Result { // binary able to locate Rust libraries in systems using content-addressable // storage (CAS). fn from_env_args_next() -> Option { - match env::args_os().next() { - Some(first_arg) => { - let mut p = PathBuf::from(first_arg); - - // Check if sysroot is found using env::args().next() only if the rustc in argv[0] - // is a symlink (see #79253). We might want to change/remove it to conform with - // https://www.gnu.org/prep/standards/standards.html#Finding-Program-Files in the - // future. - if fs::read_link(&p).is_err() { - // Path is not a symbolic link or does not exist. - return None; - } - - // Pop off `bin/rustc`, obtaining the suspected sysroot. - p.pop(); - p.pop(); - // Look for the target rustlib directory in the suspected sysroot. - let mut rustlib_path = rustc_target::relative_target_rustlib_path(&p, "dummy"); - rustlib_path.pop(); // pop off the dummy target. - rustlib_path.exists().then_some(p) - } - None => None, + let mut p = PathBuf::from(env::args_os().next()?); + + // Check if sysroot is found using env::args().next() only if the rustc in argv[0] + // is a symlink (see #79253). We might want to change/remove it to conform with + // https://www.gnu.org/prep/standards/standards.html#Finding-Program-Files in the + // future. + if fs::read_link(&p).is_err() { + // Path is not a symbolic link or does not exist. + return None; } + + // Pop off `bin/rustc`, obtaining the suspected sysroot. + p.pop(); + p.pop(); + // Look for the target rustlib directory in the suspected sysroot. + let mut rustlib_path = rustc_target::relative_target_rustlib_path(&p, "dummy"); + rustlib_path.pop(); // pop off the dummy target. + rustlib_path.exists().then_some(p) } - Ok(from_env_args_next().unwrap_or(default_from_rustc_driver_dll()?)) + from_env_args_next().unwrap_or(default_from_rustc_driver_dll().expect("Failed finding sysroot")) } diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 112adde3740bc..0e19b982a133e 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,12 +1,12 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![feature(default_field_values)] #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(rustc_attrs)] // To generate CodegenOptionsTargetModifiers and UnstableOptionsTargetModifiers enums // with macro_rules, it is necessary to use recursive mechanic ("Incremental TT Munchers"). #![recursion_limit = "256"] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod errors; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 0b94b4f122c4a..804b46a9bec41 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1,5 +1,4 @@ use std::collections::BTreeMap; -use std::hash::{DefaultHasher, Hasher}; use std::num::{IntErrorKind, NonZero}; use std::path::PathBuf; use std::str; @@ -7,6 +6,7 @@ use std::str; use rustc_abi::Align; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::profiling::TimePassesFormat; +use rustc_data_structures::stable_hasher::StableHasher; use rustc_errors::{ColorConfig, LanguageIdentifier, TerminalUrl}; use rustc_feature::UnstableFeatures; use rustc_hashes::Hash64; @@ -251,7 +251,7 @@ macro_rules! top_level_options { } impl Options { - pub fn dep_tracking_hash(&self, for_crate_hash: bool) -> u64 { + pub fn dep_tracking_hash(&self, for_crate_hash: bool) -> Hash64 { let mut sub_hashes = BTreeMap::new(); $({ hash_opt!($opt, @@ -260,7 +260,7 @@ macro_rules! top_level_options { for_crate_hash, [$dep_tracking_marker]); })* - let mut hasher = DefaultHasher::new(); + let mut hasher = StableHasher::new(); dep_tracking::stable_hash(sub_hashes, &mut hasher, self.error_format, @@ -333,7 +333,7 @@ top_level_options!( output_types: OutputTypes [TRACKED], search_paths: Vec [UNTRACKED], libs: Vec [TRACKED], - maybe_sysroot: Option [UNTRACKED], + sysroot: PathBuf [UNTRACKED], target_triple: TargetTuple [TRACKED], @@ -545,7 +545,7 @@ macro_rules! options { build_options(early_dcx, matches, target_modifiers, $stat, $prefix, $outputname) } - fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 { + fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> Hash64 { let mut sub_hashes = BTreeMap::new(); $({ hash_opt!($opt, @@ -554,7 +554,7 @@ macro_rules! options { for_crate_hash, [$dep_tracking_marker]); })* - let mut hasher = DefaultHasher::new(); + let mut hasher = StableHasher::new(); dep_tracking::stable_hash(sub_hashes, &mut hasher, error_format, diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index e0405a71f65af..1fe521bd32d54 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -329,7 +329,7 @@ impl ParseSess { self.proc_macro_quoted_spans.push(span) } - pub fn proc_macro_quoted_spans(&self) -> impl Iterator + '_ { + pub fn proc_macro_quoted_spans(&self) -> impl Iterator { // This is equivalent to `.iter().copied().enumerate()`, but that isn't possible for // AppendOnlyVec, so we resort to this scheme. self.proc_macro_quoted_spans.iter_enumerated() diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs index b750d870cb6f7..00e12b45bafb1 100644 --- a/compiler/rustc_session/src/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -20,12 +20,11 @@ pub struct FilesIndex(Vec<(Arc, SearchPathFile)>); impl FilesIndex { /// Look up [SearchPathFile] by (prefix, suffix) pair. - pub fn query<'this, 'prefix, 'suffix>( - &'this self, - prefix: &'prefix str, - suffix: &'suffix str, - ) -> Option + use<'this, 'prefix, 'suffix>> - { + pub fn query<'s>( + &'s self, + prefix: &str, + suffix: &str, + ) -> Option> { let start = self.0.partition_point(|(k, _)| **k < *prefix); if start == self.0.len() { return None; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index c4d45ee02eea1..1c9adea281dc7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -109,8 +109,8 @@ impl Mul for Limit { } impl rustc_errors::IntoDiagArg for Limit { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - self.to_string().into_diag_arg() + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { + self.to_string().into_diag_arg(&mut None) } } @@ -143,7 +143,6 @@ pub struct Session { pub target: Target, pub host: Target, pub opts: config::Options, - pub host_tlib_path: Arc, pub target_tlib_path: Arc, pub psess: ParseSess, pub sysroot: PathBuf, @@ -913,7 +912,7 @@ fn default_emitter( let source_map = if sopts.unstable_opts.link_only { None } else { Some(source_map) }; match sopts.error_format { - config::ErrorOutputType::HumanReadable(kind, color_config) => { + config::ErrorOutputType::HumanReadable { kind, color_config } => { let short = kind.short(); if let HumanReadableErrorType::AnnotateSnippet = kind { @@ -930,7 +929,6 @@ fn default_emitter( .fluent_bundle(bundle) .sm(source_map) .short_message(short) - .teach(sopts.unstable_opts.teach) .diagnostic_width(sopts.diagnostic_width) .macro_backtrace(macro_backtrace) .track_diagnostics(track_diagnostics) @@ -1019,8 +1017,7 @@ pub fn build_session( let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile { - let directory = - if let Some(ref directory) = d { directory } else { std::path::Path::new(".") }; + let directory = if let Some(directory) = d { directory } else { std::path::Path::new(".") }; let profiler = SelfProfiler::new( directory, @@ -1044,6 +1041,7 @@ pub fn build_session( let host_triple = config::host_tuple(); let target_triple = sopts.target_triple.tuple(); + // FIXME use host sysroot? let host_tlib_path = Arc::new(SearchPath::from_sysroot_and_triple(&sysroot, host_triple)); let target_tlib_path = if host_triple == target_triple { // Use the same `SearchPath` if host and target triple are identical to avoid unnecessary @@ -1072,7 +1070,6 @@ pub fn build_session( target, host, opts: sopts, - host_tlib_path, target_tlib_path, psess, sysroot, @@ -1431,7 +1428,7 @@ fn mk_emitter(output: ErrorOutputType) -> Box { let fallback_bundle = fallback_fluent_bundle(vec![rustc_errors::DEFAULT_LOCALE_RESOURCE], false); let emitter: Box = match output { - config::ErrorOutputType::HumanReadable(kind, color_config) => { + config::ErrorOutputType::HumanReadable { kind, color_config } => { let short = kind.short(); Box::new( HumanEmitter::new(stderr_destination(color_config), fallback_bundle) diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index 9182789cf0269..fcede379b893a 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -34,6 +34,7 @@ pub enum NativeLibKind { as_needed: Option, }, /// Dynamic library (e.g. `foo.dll` on Windows) without a corresponding import library. + /// On Linux, it refers to a generated shared library stub. RawDylib, /// A macOS-specific kind of dynamic libraries. Framework { diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml index 29ce24e8b7849..a11df9a9c9bc9 100644 --- a/compiler/rustc_smir/Cargo.toml +++ b/compiler/rustc_smir/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_smir" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs index 2215e2f01ade0..eaba14bbf30f5 100644 --- a/compiler/rustc_smir/src/lib.rs +++ b/compiler/rustc_smir/src/lib.rs @@ -9,13 +9,13 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::usage_of_ty_tykind)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc( html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(attr(allow(unused_variables), deny(warnings))) )] #![doc(rust_logo)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub mod rustc_internal; diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 50cf605ba2a82..bb2b2dea2f37f 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -88,10 +88,9 @@ impl RustcInternal for Pattern { type T<'tcx> = rustc_ty::Pattern<'tcx>; fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { tcx.mk_pat(match self { - Pattern::Range { start, end, include_end } => rustc_ty::PatternKind::Range { - start: start.as_ref().map(|c| c.internal(tables, tcx)), - end: end.as_ref().map(|c| c.internal(tables, tcx)), - include_end: *include_end, + Pattern::Range { start, end, include_end: _ } => rustc_ty::PatternKind::Range { + start: start.as_ref().unwrap().internal(tables, tcx), + end: end.as_ref().unwrap().internal(tables, tcx), }, }) } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 71e7b9c04ca16..aa1921fc8e784 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::iter; use rustc_abi::HasDataLayout; -use rustc_hir::LangItem; +use rustc_hir::{Attribute, LangItem}; use rustc_middle::ty::layout::{ FnAbiOf, FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOf, LayoutOfHelpers, }; @@ -243,7 +243,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { } } - fn get_attrs_by_path( + fn tool_attrs( &self, def_id: stable_mir::DefId, attr: &[stable_mir::Symbol], @@ -253,30 +253,40 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let did = tables[def_id]; let attr_name: Vec<_> = attr.iter().map(|seg| rustc_span::Symbol::intern(&seg)).collect(); tcx.get_attrs_by_path(did, &attr_name) - .map(|attribute| { - let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); - let span = attribute.span; - stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + .filter_map(|attribute| { + if let Attribute::Unparsed(u) = attribute { + let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); + Some(stable_mir::crate_def::Attribute::new( + attr_str, + u.span.stable(&mut *tables), + )) + } else { + None + } }) .collect() } - fn get_all_attrs(&self, def_id: stable_mir::DefId) -> Vec { + fn all_tool_attrs(&self, def_id: stable_mir::DefId) -> Vec { let mut tables = self.0.borrow_mut(); let tcx = tables.tcx; let did = tables[def_id]; - let filter_fn = - move |a: &&rustc_hir::Attribute| matches!(a.kind, rustc_hir::AttrKind::Normal(_)); let attrs_iter = if let Some(did) = did.as_local() { - tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn) + tcx.hir_attrs(tcx.local_def_id_to_hir_id(did)).iter() } else { - tcx.attrs_for_def(did).iter().filter(filter_fn) + tcx.attrs_for_def(did).iter() }; attrs_iter - .map(|attribute| { - let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); - let span = attribute.span; - stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables)) + .filter_map(|attribute| { + if let Attribute::Unparsed(u) = attribute { + let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute); + Some(stable_mir::crate_def::Attribute::new( + attr_str, + u.span.stable(&mut *tables), + )) + } else { + None + } }) .collect() } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index a627e0e69b62f..62cbab9b723cc 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -206,7 +206,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::BackendRepr { rustc_abi::BackendRepr::ScalarPair(first, second) => { ValueAbi::ScalarPair(first.stable(tables), second.stable(tables)) } - rustc_abi::BackendRepr::Vector { element, count } => { + rustc_abi::BackendRepr::SimdVector { element, count } => { ValueAbi::Vector { element: element.stable(tables), count } } rustc_abi::BackendRepr::Memory { sized } => ValueAbi::Aggregate { sized }, diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index a0faf20c79a67..aa0eac628dd0f 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -405,10 +405,11 @@ impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { match **self { - ty::PatternKind::Range { start, end, include_end } => stable_mir::ty::Pattern::Range { - start: start.stable(tables), - end: end.stable(tables), - include_end, + ty::PatternKind::Range { start, end } => stable_mir::ty::Pattern::Range { + // FIXME(SMIR): update data structures to not have an Option here anymore + start: Some(start.stable(tables)), + end: Some(end.stable(tables)), + include_end: true, }, } } diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml index 991c75cc98df8..43a2d692577eb 100644 --- a/compiler/rustc_span/Cargo.toml +++ b/compiler/rustc_span/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_span" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_span/src/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs index 47cc16b623d10..6384fa06c21b0 100644 --- a/compiler/rustc_span/src/analyze_source_file.rs +++ b/compiler/rustc_span/src/analyze_source_file.rs @@ -29,132 +29,6 @@ pub(crate) fn analyze_source_file(src: &str) -> (Vec, Vec { - fn analyze_source_file_dispatch( - src: &str, - lines: &mut Vec, - multi_byte_chars: &mut Vec, - ) { - if is_x86_feature_detected!("sse2") { - unsafe { - analyze_source_file_sse2(src, lines, multi_byte_chars); - } - } else { - analyze_source_file_generic( - src, - src.len(), - RelativeBytePos::from_u32(0), - lines, - multi_byte_chars, - ); - } - } - - /// Checks 16 byte chunks of text at a time. If the chunk contains - /// something other than printable ASCII characters and newlines, the - /// function falls back to the generic implementation. Otherwise it uses - /// SSE2 intrinsics to quickly find all newlines. - #[target_feature(enable = "sse2")] - unsafe fn analyze_source_file_sse2( - src: &str, - lines: &mut Vec, - multi_byte_chars: &mut Vec, - ) { - #[cfg(target_arch = "x86")] - use std::arch::x86::*; - #[cfg(target_arch = "x86_64")] - use std::arch::x86_64::*; - - const CHUNK_SIZE: usize = 16; - - let src_bytes = src.as_bytes(); - - let chunk_count = src.len() / CHUNK_SIZE; - - // This variable keeps track of where we should start decoding a - // chunk. If a multi-byte character spans across chunk boundaries, - // we need to skip that part in the next chunk because we already - // handled it. - let mut intra_chunk_offset = 0; - - for chunk_index in 0..chunk_count { - let ptr = src_bytes.as_ptr() as *const __m128i; - // We don't know if the pointer is aligned to 16 bytes, so we - // use `loadu`, which supports unaligned loading. - let chunk = unsafe { _mm_loadu_si128(ptr.add(chunk_index)) }; - - // For character in the chunk, see if its byte value is < 0, which - // indicates that it's part of a UTF-8 char. - let multibyte_test = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)) }; - // Create a bit mask from the comparison results. - let multibyte_mask = unsafe { _mm_movemask_epi8(multibyte_test) }; - - // If the bit mask is all zero, we only have ASCII chars here: - if multibyte_mask == 0 { - assert!(intra_chunk_offset == 0); - - // Check for newlines in the chunk - let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) }; - let mut newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) }; - - let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1); - - while newlines_mask != 0 { - let index = newlines_mask.trailing_zeros(); - - lines.push(RelativeBytePos(index) + output_offset); - - // Clear the bit, so we can find the next one. - newlines_mask &= newlines_mask - 1; - } - } else { - // The slow path. - // There are multibyte chars in here, fallback to generic decoding. - let scan_start = chunk_index * CHUNK_SIZE + intra_chunk_offset; - intra_chunk_offset = analyze_source_file_generic( - &src[scan_start..], - CHUNK_SIZE - intra_chunk_offset, - RelativeBytePos::from_usize(scan_start), - lines, - multi_byte_chars, - ); - } - } - - // There might still be a tail left to analyze - let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset; - if tail_start < src.len() { - analyze_source_file_generic( - &src[tail_start..], - src.len() - tail_start, - RelativeBytePos::from_usize(tail_start), - lines, - multi_byte_chars, - ); - } - } - } - _ => { - // The target (or compiler version) does not support SSE2 ... - fn analyze_source_file_dispatch( - src: &str, - lines: &mut Vec, - multi_byte_chars: &mut Vec, - ) { - analyze_source_file_generic( - src, - src.len(), - RelativeBytePos::from_u32(0), - lines, - multi_byte_chars, - ); - } - } -} - -#[cfg(not(bootstrap))] cfg_match! { any(target_arch = "x86", target_arch = "x86_64") => { fn analyze_source_file_dispatch( @@ -194,9 +68,7 @@ cfg_match! { const CHUNK_SIZE: usize = 16; - let src_bytes = src.as_bytes(); - - let chunk_count = src.len() / CHUNK_SIZE; + let (chunks, tail) = src.as_bytes().as_chunks::(); // This variable keeps track of where we should start decoding a // chunk. If a multi-byte character spans across chunk boundaries, @@ -204,25 +76,24 @@ cfg_match! { // handled it. let mut intra_chunk_offset = 0; - for chunk_index in 0..chunk_count { - let ptr = src_bytes.as_ptr() as *const __m128i; + for (chunk_index, chunk) in chunks.iter().enumerate() { // We don't know if the pointer is aligned to 16 bytes, so we // use `loadu`, which supports unaligned loading. - let chunk = unsafe { _mm_loadu_si128(ptr.add(chunk_index)) }; + let chunk = unsafe { _mm_loadu_si128(chunk.as_ptr() as *const __m128i) }; // For character in the chunk, see if its byte value is < 0, which // indicates that it's part of a UTF-8 char. - let multibyte_test = unsafe { _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)) }; + let multibyte_test = _mm_cmplt_epi8(chunk, _mm_set1_epi8(0)); // Create a bit mask from the comparison results. - let multibyte_mask = unsafe { _mm_movemask_epi8(multibyte_test) }; + let multibyte_mask = _mm_movemask_epi8(multibyte_test); // If the bit mask is all zero, we only have ASCII chars here: if multibyte_mask == 0 { assert!(intra_chunk_offset == 0); // Check for newlines in the chunk - let newlines_test = unsafe { _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)) }; - let mut newlines_mask = unsafe { _mm_movemask_epi8(newlines_test) }; + let newlines_test = _mm_cmpeq_epi8(chunk, _mm_set1_epi8(b'\n' as i8)); + let mut newlines_mask = _mm_movemask_epi8(newlines_test); let output_offset = RelativeBytePos::from_usize(chunk_index * CHUNK_SIZE + 1); @@ -249,7 +120,7 @@ cfg_match! { } // There might still be a tail left to analyze - let tail_start = chunk_count * CHUNK_SIZE + intra_chunk_offset; + let tail_start = src.len() - tail.len() + intra_chunk_offset; if tail_start < src.len() { analyze_source_file_generic( &src[tail_start..], diff --git a/compiler/rustc_span/src/edition.rs b/compiler/rustc_span/src/edition.rs index 36f9b4cff60b0..da298080ed2f6 100644 --- a/compiler/rustc_span/src/edition.rs +++ b/compiler/rustc_span/src/edition.rs @@ -23,11 +23,27 @@ pub enum Edition { Edition2021, /// The 2024 edition Edition2024, + /// The future edition - this variant will always exist and features associated with this + /// edition can be moved to the next 20XX edition when it is established and it is confirmed + /// that those features will be part of that edition. + /// + /// This variant allows edition changes to be implemented before being assigned to a concrete + /// edition - primarily when there are two different unstable behaviours that need tested across + /// an edition boundary. + /// + /// This edition will be permanently unstable and any features associated with this edition + /// must also be behind a feature gate. + EditionFuture, } // Must be in order from oldest to newest. -pub const ALL_EDITIONS: &[Edition] = - &[Edition::Edition2015, Edition::Edition2018, Edition::Edition2021, Edition::Edition2024]; +pub const ALL_EDITIONS: &[Edition] = &[ + Edition::Edition2015, + Edition::Edition2018, + Edition::Edition2021, + Edition::Edition2024, + Edition::EditionFuture, +]; pub const EDITION_NAME_LIST: &str = "2015|2018|2021|2024"; @@ -42,6 +58,7 @@ impl fmt::Display for Edition { Edition::Edition2018 => "2018", Edition::Edition2021 => "2021", Edition::Edition2024 => "2024", + Edition::EditionFuture => "future", }; write!(f, "{s}") } @@ -54,6 +71,7 @@ impl Edition { Edition::Edition2018 => "rust_2018_compatibility", Edition::Edition2021 => "rust_2021_compatibility", Edition::Edition2024 => "rust_2024_compatibility", + Edition::EditionFuture => "edition_future_compatibility", } } @@ -63,6 +81,7 @@ impl Edition { Edition::Edition2018 => true, Edition::Edition2021 => true, Edition::Edition2024 => true, + Edition::EditionFuture => false, } } @@ -85,6 +104,11 @@ impl Edition { pub fn at_least_rust_2024(self) -> bool { self >= Edition::Edition2024 } + + /// Are we allowed to use features from the future edition? + pub fn at_least_edition_future(self) -> bool { + self >= Edition::EditionFuture + } } impl FromStr for Edition { @@ -95,6 +119,7 @@ impl FromStr for Edition { "2018" => Ok(Edition::Edition2018), "2021" => Ok(Edition::Edition2021), "2024" => Ok(Edition::Edition2024), + "future" => Ok(Edition::EditionFuture), _ => Err(()), } } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 9bf1d305e5413..62027caa3537d 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -175,6 +175,12 @@ pub enum Transparency { Opaque, } +impl Transparency { + pub fn fallback(macro_rules: bool) -> Self { + if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque } + } +} + impl LocalExpnId { /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST. pub const ROOT: LocalExpnId = LocalExpnId::ZERO; @@ -976,6 +982,8 @@ pub struct ExpnData { /// Should debuginfo for the macro be collapsed to the outermost expansion site (in other /// words, was the macro definition annotated with `#[collapse_debuginfo]`)? pub(crate) collapse_debuginfo: bool, + /// When true, we do not display the note telling people to use the `-Zmacro-backtrace` flag. + pub hide_backtrace: bool, } impl !PartialEq for ExpnData {} @@ -994,6 +1002,7 @@ impl ExpnData { allow_internal_unsafe: bool, local_inner_macros: bool, collapse_debuginfo: bool, + hide_backtrace: bool, ) -> ExpnData { ExpnData { kind, @@ -1008,6 +1017,7 @@ impl ExpnData { allow_internal_unsafe, local_inner_macros, collapse_debuginfo, + hide_backtrace, } } @@ -1032,6 +1042,7 @@ impl ExpnData { allow_internal_unsafe: false, local_inner_macros: false, collapse_debuginfo: false, + hide_backtrace: false, } } @@ -1167,6 +1178,8 @@ pub enum DesugaringKind { BoundModifier, /// Calls to contract checks (`#[requires]` to precond, `#[ensures]` to postcond) Contract, + /// A pattern type range start/end + PatTyRange, } impl DesugaringKind { @@ -1184,6 +1197,7 @@ impl DesugaringKind { DesugaringKind::WhileLoop => "`while` loop", DesugaringKind::BoundModifier => "trait bound modifier", DesugaringKind::Contract => "contract check", + DesugaringKind::PatTyRange => "pattern type", } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 695edc956cdb5..f19d4d9f3624e 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -31,7 +31,7 @@ #![feature(round_char_boundary)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] +#![feature(slice_as_chunks)] // tidy-alphabetical-end // The code produced by the `Encodable`/`Decodable` derive macros refer to @@ -404,7 +404,7 @@ impl fmt::Display for FileNameDisplay<'_> { impl<'a> FileNameDisplay<'a> { pub fn to_string_lossy(&self) -> Cow<'a, str> { match self.inner { - FileName::Real(ref inner) => inner.to_string_lossy(self.display_pref), + FileName::Real(inner) => inner.to_string_lossy(self.display_pref), _ => Cow::from(self.to_string()), } } @@ -1056,6 +1056,37 @@ impl Span { } } + /// Returns the `Span` within the syntax context of "within". This is useful when + /// "self" is an expansion from a macro variable, since this can be used for + /// providing extra macro expansion context for certain errors. + /// + /// ```text + /// macro_rules! m { + /// ($ident:ident) => { ($ident,) } + /// } + /// + /// m!(outer_ident); + /// ``` + /// + /// If "self" is the span of the outer_ident, and "within" is the span of the `($ident,)` + /// expr, then this will return the span of the `$ident` macro variable. + pub fn within_macro(self, within: Span, sm: &SourceMap) -> Option { + match Span::prepare_to_combine(self, within) { + // Only return something if it doesn't overlap with the original span, + // and the span isn't "imported" (i.e. from unavailable sources). + // FIXME: This does limit the usefulness of the error when the macro is + // from a foreign crate; we could also take into account `-Zmacro-backtrace`, + // which doesn't redact this span (but that would mean passing in even more + // args to this function, lol). + Ok((self_, _, parent)) + if self_.hi < self.lo() || self.hi() < self_.lo && !sm.is_imported(within) => + { + Some(Span::new(self_.lo, self_.hi, self_.ctxt, parent)) + } + _ => None, + } + } + pub fn from_inner(self, inner: InnerSpan) -> Span { let span = self.data(); Span::new( @@ -1442,7 +1473,7 @@ pub enum ExternalSourceKind { impl ExternalSource { pub fn get_source(&self) -> Option<&str> { match self { - ExternalSource::Foreign { kind: ExternalSourceKind::Present(ref src), .. } => Some(src), + ExternalSource::Foreign { kind: ExternalSourceKind::Present(src), .. } => Some(src), _ => None, } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d4d435d9b7467..8a8bec35d8194 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -33,6 +33,15 @@ symbols! { // Special reserved identifiers used internally for elided lifetimes, // unnamed method parameters, crate root module, error recovery etc. // Matching predicates: `is_any_keyword`, `is_special`/`is_reserved` + // + // Notes about `kw::Empty`: + // - Its use can blur the lines between "empty symbol" and "no symbol". + // Using `Option` is preferable, where possible, because that + // is unambiguous. + // - For dummy symbols that are never used and absolutely must be + // present, it's better to use `sym::dummy` than `kw::Empty`, because + // it's clearer that it's intended as a dummy value, and more likely + // to be detected if it accidentally does get used. Empty: "", PathRoot: "{{root}}", DollarCrate: "$crate", @@ -308,6 +317,9 @@ symbols! { RangeFull, RangeInclusive, RangeInclusiveCopy, + RangeMax, + RangeMin, + RangeSub, RangeTo, RangeToInclusive, Rc, @@ -776,6 +788,7 @@ symbols! { default_method_body_is_const, default_type_parameter_fallback, default_type_params, + define_opaque, delayed_bug_from_inside_query, deny, deprecated, @@ -830,6 +843,7 @@ symbols! { drop_types_in_const, dropck_eyepatch, dropck_parametricity, + dummy: "", // use this instead of `kw::Empty` for symbols that won't be used dummy_cgu_name, dylib, dyn_compatible_for_dispatch, @@ -859,6 +873,7 @@ symbols! { eprint_macro, eprintln_macro, eq, + ergonomic_clones, ermsb_target_feature, exact_div, except, @@ -1012,6 +1027,7 @@ symbols! { from_residual, from_size_align_unchecked, from_str_method, + from_u16, from_usize, from_yeet, fs_create_dir, @@ -1037,6 +1053,7 @@ symbols! { generic_associated_types_extended, generic_const_exprs, generic_const_items, + generic_const_parameter_types, generic_param_attrs, generic_pattern_types, get_context, @@ -1367,10 +1384,6 @@ symbols! { native_link_modifiers_whole_archive, natvis_file, ne, - nearbyintf128, - nearbyintf16, - nearbyintf32, - nearbyintf64, needs_allocator, needs_drop, needs_panic_runtime, @@ -1525,6 +1538,7 @@ symbols! { pattern_complexity_limit, pattern_parentheses, pattern_type, + pattern_type_range_trait, pattern_types, permissions_from_mode, phantom_data, @@ -1628,6 +1642,7 @@ symbols! { quote, range_inclusive_new, raw_dylib, + raw_dylib_elf, raw_eq, raw_identifiers, raw_ref_op, @@ -1688,20 +1703,16 @@ symbols! { return_position_impl_trait_in_trait, return_type_notation, rhs, - rintf128, - rintf16, - rintf32, - rintf64, riscv_target_feature, rlib, ropi, ropi_rwpi: "ropi-rwpi", rotate_left, rotate_right, - roundevenf128, - roundevenf16, - roundevenf32, - roundevenf64, + round_ties_even_f128, + round_ties_even_f16, + round_ties_even_f32, + round_ties_even_f64, roundf128, roundf16, roundf32, @@ -1719,6 +1730,7 @@ symbols! { rust_cold_cc, rust_eh_catch_typeinfo, rust_eh_personality, + rust_future, rust_logo, rust_out, rustc, @@ -1772,7 +1784,6 @@ symbols! { rustc_insignificant_dtor, rustc_intrinsic, rustc_intrinsic_const_stable_indirect, - rustc_intrinsic_must_be_overridden, rustc_layout, rustc_layout_scalar_valid_range_end, rustc_layout_scalar_valid_range_start, @@ -1886,8 +1897,6 @@ symbols! { simd_fma, simd_fmax, simd_fmin, - simd_fpow, - simd_fpowi, simd_fsin, simd_fsqrt, simd_gather, @@ -1924,7 +1933,7 @@ symbols! { simd_shl, simd_shr, simd_shuffle, - simd_shuffle_generic, + simd_shuffle_const_generic, simd_sub, simd_trunc, simd_with_exposed_provenance, @@ -2093,6 +2102,7 @@ symbols! { type_ascribe, type_ascription, type_changing_struct_update, + type_const, type_id, type_ir_inherent, type_length_limit, @@ -2189,6 +2199,7 @@ symbols! { unwrap, unwrap_binder, unwrap_or, + use_cloned, use_extern_macros, use_nested_groups, used, @@ -2244,6 +2255,7 @@ symbols! { wasm_abi, wasm_import_module, wasm_target_feature, + where_clause_attrs, while_let, windows, windows_subsystem, @@ -2303,11 +2315,23 @@ impl Ident { Ident::new(name, DUMMY_SP) } + /// This is best avoided, because it blurs the lines between "empty + /// identifier" and "no identifier". Using `Option` is preferable, + /// where possible, because that is unambiguous. #[inline] pub fn empty() -> Ident { Ident::with_dummy_span(kw::Empty) } + // For dummy identifiers that are never used and absolutely must be + // present, it's better to use `Ident::dummy` than `Ident::Empty`, because + // it's clearer that it's intended as a dummy value, and more likely to be + // detected if it accidentally does get used. + #[inline] + pub fn dummy() -> Ident { + Ident::with_dummy_span(sym::dummy) + } + /// Maps a string to an identifier with a dummy span. pub fn from_str(string: &str) -> Ident { Ident::with_dummy_span(Symbol::intern(string)) diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 4c51c908f541f..90ddf4c8a0403 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_symbol_mangling" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -9,6 +9,7 @@ punycode = "0.4.0" rustc-demangle = "0.1.21" rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_hashes = { path = "../rustc_hashes" } diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 4312c82815c16..c4558b5ce8be3 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -89,11 +89,11 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(let_chains)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_hir::def::DefKind; diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index 7fda81126c443..ddeeadff13d17 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -62,18 +62,18 @@ impl SymbolNamesTest<'_> { ); let mangled = tcx.symbol_name(instance); tcx.dcx().emit_err(TestOutput { - span: attr.span, + span: attr.span(), kind: Kind::SymbolName, content: format!("{mangled}"), }); if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { tcx.dcx().emit_err(TestOutput { - span: attr.span, + span: attr.span(), kind: Kind::Demangling, content: format!("{demangling}"), }); tcx.dcx().emit_err(TestOutput { - span: attr.span, + span: attr.span(), kind: Kind::DemanglingAlt, content: format!("{demangling:#}"), }); @@ -82,7 +82,7 @@ impl SymbolNamesTest<'_> { for attr in tcx.get_attrs(def_id, DEF_PATH) { tcx.dcx().emit_err(TestOutput { - span: attr.span, + span: attr.span(), kind: Kind::DefPath, content: with_no_trimmed_paths!(tcx.def_path_str(def_id)), }); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 4fafd1ac3509a..bc3923e4b4d67 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -169,7 +169,7 @@ impl<'tcx> SymbolMangler<'tcx> { Ok(()) } - fn in_binder( + fn wrap_binder( &mut self, value: &ty::Binder<'tcx, T>, print_value: impl FnOnce(&mut Self, &T) -> Result<(), PrintError>, @@ -413,12 +413,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { } ty::Pat(ty, pat) => match *pat { - ty::PatternKind::Range { start, end, include_end } => { - let consts = [ - start.unwrap_or(self.tcx.consts.unit), - end.unwrap_or(self.tcx.consts.unit), - ty::Const::from_bool(self.tcx, include_end), - ]; + ty::PatternKind::Range { start, end } => { + let consts = [start, end]; // HACK: Represent as tuple until we have something better. // HACK: constants are used in arrays, even if the types don't match. self.push("T"); @@ -471,7 +467,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty::FnPtr(sig_tys, hdr) => { let sig = sig_tys.with(hdr); self.push("F"); - self.in_binder(&sig, |cx, sig| { + self.wrap_binder(&sig, |cx, sig| { if sig.safety.is_unsafe() { cx.push("U"); } @@ -554,7 +550,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // [ [{}]] [{}] // Since any predicates after the first one shouldn't change the binders, // just put them all in the binders of the first. - self.in_binder(&predicates[0], |cx, _| { + self.wrap_binder(&predicates[0], |cx, _| { for predicate in predicates.iter() { // It would be nice to be able to validate bound vars here, but // projections can actually include bound vars from super traits diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml index e33431ba12259..189b19b028617 100644 --- a/compiler/rustc_target/Cargo.toml +++ b/compiler/rustc_target/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_target" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 3fa67c624a7be..209d7483e612a 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -25,7 +25,7 @@ struct CannotUseFpConv; fn is_loongarch_aggregate(arg: &ArgAbi<'_, Ty>) -> bool { match arg.layout.backend_repr { - BackendRepr::Vector { .. } => true, + BackendRepr::SimdVector { .. } => true, _ => arg.layout.is_aggregate(), } } @@ -80,7 +80,7 @@ where } } }, - BackendRepr::Vector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 1c044fe98b3ef..6d0ee3c7ee58a 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -31,6 +31,7 @@ mod sparc64; mod wasm; mod x86; mod x86_64; +mod x86_win32; mod x86_win64; mod xtensa; @@ -357,7 +358,7 @@ impl<'a, Ty> ArgAbi<'a, Ty> { scalar_attrs(&layout, a, Size::ZERO), scalar_attrs(&layout, b, a.size(cx).align_to(b.align(cx).abi)), ), - BackendRepr::Vector { .. } => PassMode::Direct(ArgAttributes::new()), + BackendRepr::SimdVector { .. } => PassMode::Direct(ArgAttributes::new()), BackendRepr::Memory { .. } => Self::indirect_pass_mode(&layout), }; ArgAbi { layout, mode } @@ -649,7 +650,11 @@ impl<'a, Ty> FnAbi<'a, Ty> { }; let reg_struct_return = cx.x86_abi_opt().reg_struct_return; let opts = x86::X86Options { flavor, regparm, reg_struct_return }; - x86::compute_abi_info(cx, self, opts); + if spec.is_like_msvc { + x86_win32::compute_abi_info(cx, self, opts); + } else { + x86::compute_abi_info(cx, self, opts); + } } "x86_64" => match abi { ExternAbi::SysV64 { .. } => x86_64::compute_abi_info(cx, self), @@ -759,7 +764,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { if arg_idx.is_none() && arg.layout.size > Primitive::Pointer(AddressSpace::DATA).size(cx) * 2 - && !matches!(arg.layout.backend_repr, BackendRepr::Vector { .. }) + && !matches!(arg.layout.backend_repr, BackendRepr::SimdVector { .. }) { // Return values larger than 2 registers using a return area // pointer. LLVM and Cranelift disagree about how to return @@ -826,7 +831,7 @@ impl<'a, Ty> FnAbi<'a, Ty> { } } - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { // This is a fun case! The gist of what this is doing is // that we want callers and callees to always agree on the // ABI of how they pass SIMD arguments. If we were to *not* diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 785175229b031..7368e225efa74 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -31,7 +31,7 @@ struct CannotUseFpConv; fn is_riscv_aggregate(arg: &ArgAbi<'_, Ty>) -> bool { match arg.layout.backend_repr { - BackendRepr::Vector { .. } => true, + BackendRepr::SimdVector { .. } => true, _ => arg.layout.is_aggregate(), } } @@ -86,7 +86,7 @@ where } } }, - BackendRepr::Vector { .. } => return Err(CannotUseFpConv), + BackendRepr::SimdVector { .. } => return Err(CannotUseFpConv), BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => match arg_layout.fields { FieldsShape::Primitive => { unreachable!("aggregates can't have `FieldsShape::Primitive`") diff --git a/compiler/rustc_target/src/callconv/s390x.rs b/compiler/rustc_target/src/callconv/s390x.rs index 4f69e32b2e3df..1ba792c5acc5a 100644 --- a/compiler/rustc_target/src/callconv/s390x.rs +++ b/compiler/rustc_target/src/callconv/s390x.rs @@ -8,7 +8,7 @@ use crate::spec::HasTargetSpec; fn classify_ret(ret: &mut ArgAbi<'_, Ty>) { let size = ret.layout.size; - if size.bits() <= 128 && matches!(ret.layout.backend_repr, BackendRepr::Vector { .. }) { + if size.bits() <= 128 && matches!(ret.layout.backend_repr, BackendRepr::SimdVector { .. }) { return; } if !ret.layout.is_aggregate() && size.bits() <= 64 { @@ -40,7 +40,7 @@ where let size = arg.layout.size; if size.bits() <= 128 { - if let BackendRepr::Vector { .. } = arg.layout.backend_repr { + if let BackendRepr::SimdVector { .. } = arg.layout.backend_repr { // pass non-wrapped vector types using `PassMode::Direct` return; } diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 7e5aab0201b6d..6f112b4940057 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -36,7 +36,7 @@ where if t.abi_return_struct_as_int || opts.reg_struct_return { // According to Clang, everyone but MSVC returns single-element // float aggregates directly in a floating-point register. - if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) { + if fn_abi.ret.layout.is_single_fp_element(cx) { match fn_abi.ret.layout.size.bytes() { 4 => fn_abi.ret.cast_to(Reg::f32()), 8 => fn_abi.ret.cast_to(Reg::f64()), @@ -64,31 +64,11 @@ where continue; } - // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 - // See https://reviews.llvm.org/D72114 for Clang behavior - let t = cx.target_spec(); let align_4 = Align::from_bytes(4).unwrap(); let align_16 = Align::from_bytes(16).unwrap(); - if t.is_like_msvc - && arg.layout.is_adt() - && let Some(max_repr_align) = arg.layout.max_repr_align - && max_repr_align > align_4 - { - // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. - // Summarized here: - // - Arguments with _requested_ alignment > 4 are passed indirectly. - // - For backwards compatibility, arguments with natural alignment > 4 are still passed - // on stack (via `byval`). For example, this includes `double`, `int64_t`, - // and structs containing them, provided they lack an explicit alignment attribute. - assert!( - arg.layout.align.abi >= max_repr_align, - "abi alignment {:?} less than requested alignment {max_repr_align:?}", - arg.layout.align.abi, - ); - arg.make_indirect(); - } else if arg.layout.is_aggregate() { + if arg.layout.is_aggregate() { // We need to compute the alignment of the `byval` argument. The rules can be found in // `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. Summarized // here, they are: @@ -109,7 +89,7 @@ where { match layout.backend_repr { BackendRepr::Scalar(_) | BackendRepr::ScalarPair(..) => false, - BackendRepr::Vector { .. } => true, + BackendRepr::SimdVector { .. } => true, BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { if contains_vector(cx, layout.field(cx, i)) { diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index ab306e202396b..300b19f62e722 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -56,7 +56,7 @@ where Primitive::Float(_) => Class::Sse, }, - BackendRepr::Vector { .. } => Class::Sse, + BackendRepr::SimdVector { .. } => Class::Sse, BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => { for i in 0..layout.fields.count() { diff --git a/compiler/rustc_target/src/callconv/x86_win32.rs b/compiler/rustc_target/src/callconv/x86_win32.rs new file mode 100644 index 0000000000000..554a7368848b5 --- /dev/null +++ b/compiler/rustc_target/src/callconv/x86_win32.rs @@ -0,0 +1,81 @@ +use rustc_abi::{Align, HasDataLayout, Reg, TyAbiInterface}; + +use crate::callconv::FnAbi; +use crate::spec::HasTargetSpec; + +pub(crate) fn compute_abi_info<'a, Ty, C>( + cx: &C, + fn_abi: &mut FnAbi<'a, Ty>, + opts: super::x86::X86Options, +) where + Ty: TyAbiInterface<'a, C> + Copy, + C: HasDataLayout + HasTargetSpec, +{ + if !fn_abi.ret.is_ignore() { + if fn_abi.ret.layout.is_aggregate() && fn_abi.ret.layout.is_sized() { + // Returning a structure. Most often, this will use + // a hidden first argument. On some platforms, though, + // small structs are returned as integers. + // + // Some links: + // https://www.angelcode.com/dev/callconv/callconv.html + // Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp + let t = cx.target_spec(); + // MSVC does not special-case 1-element float aggregates, unlike others. + // GCC used to apply the SysV rule here, breaking windows-gnu's ABI, but was fixed: + // - reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028 + // - fixed in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85667 + if t.abi_return_struct_as_int || opts.reg_struct_return { + match fn_abi.ret.layout.size.bytes() { + 1 => fn_abi.ret.cast_to(Reg::i8()), + 2 => fn_abi.ret.cast_to(Reg::i16()), + 4 => fn_abi.ret.cast_to(Reg::i32()), + 8 => fn_abi.ret.cast_to(Reg::i64()), + _ => fn_abi.ret.make_indirect(), + } + } else { + fn_abi.ret.make_indirect(); + } + } else { + fn_abi.ret.extend_integer_width_to(32); + } + } + + for arg in fn_abi.args.iter_mut() { + if arg.is_ignore() || !arg.layout.is_sized() { + continue; + } + + // FIXME: MSVC 2015+ will pass the first 3 vector arguments in [XYZ]MM0-2 + // See https://reviews.llvm.org/D72114 for Clang behavior + + let align_4 = Align::from_bytes(4).unwrap(); + + if arg.layout.is_adt() + && let Some(max_repr_align) = arg.layout.max_repr_align + && max_repr_align > align_4 + { + // MSVC has special rules for overaligned arguments: https://reviews.llvm.org/D72114. + // Summarized here: + // - Arguments with _requested_ alignment > 4 are passed indirectly. + // - For backwards compatibility, arguments with natural alignment > 4 are still passed + // on stack (via `byval`). For example, this includes `double`, `int64_t`, + // and structs containing them, provided they lack an explicit alignment attribute. + assert!( + arg.layout.align.abi >= max_repr_align, + "abi alignment {:?} less than requested alignment {max_repr_align:?}", + arg.layout.align.abi, + ); + arg.make_indirect(); + } else if arg.layout.is_aggregate() { + // Alignment of the `byval` argument. + // The rules can be found in `X86_32ABIInfo::getTypeStackAlignInBytes` in Clang's `TargetInfo.cpp`. + let byval_align = align_4; + arg.pass_by_stack_offset(Some(byval_align)); + } else { + arg.extend_integer_width_to(32); + } + } + + super::x86::fill_inregs(cx, fn_abi, opts, false); +} diff --git a/compiler/rustc_target/src/callconv/x86_win64.rs b/compiler/rustc_target/src/callconv/x86_win64.rs index 4d99a9f9ba064..8f8597ea662a8 100644 --- a/compiler/rustc_target/src/callconv/x86_win64.rs +++ b/compiler/rustc_target/src/callconv/x86_win64.rs @@ -18,7 +18,7 @@ pub(crate) fn compute_abi_info(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<' _ => a.make_indirect(), } } - BackendRepr::Vector { .. } => { + BackendRepr::SimdVector { .. } => { // FIXME(eddyb) there should be a size cap here // (probably what clang calls "illegal vectors"). } diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index 6c030cb3bf770..b687f0e20c660 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -116,7 +116,7 @@ where fn is_xtensa_aggregate<'a, Ty>(arg: &ArgAbi<'a, Ty>) -> bool { match arg.layout.backend_repr { - BackendRepr::Vector { .. } => true, + BackendRepr::SimdVector { .. } => true, _ => arg.layout.is_aggregate(), } } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 7ebe96960ed0f..a8d7da5692de4 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -16,7 +16,6 @@ #![feature(let_chains)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/base/aix.rs b/compiler/rustc_target/src/spec/base/aix.rs index a92d104f9108e..aa42b4d1c5027 100644 --- a/compiler/rustc_target/src/spec/base/aix.rs +++ b/compiler/rustc_target/src/spec/base/aix.rs @@ -1,6 +1,8 @@ use rustc_abi::Endian; -use crate::spec::{Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions, crt_objects, cvs}; +use crate::spec::{ + BinaryFormat, Cc, CodeModel, LinkOutputKind, LinkerFlavor, TargetOptions, crt_objects, cvs, +}; pub(crate) fn opts() -> TargetOptions { TargetOptions { @@ -21,6 +23,7 @@ pub(crate) fn opts() -> TargetOptions { linker: Some("ld".into()), eh_frame_header: false, is_like_aix: true, + binary_format: BinaryFormat::Xcoff, default_dwarf_version: 3, function_sections: true, pre_link_objects: crt_objects::new(&[ diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 1b56143545f61..66c85146c2944 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -2,8 +2,8 @@ use std::borrow::Cow; use std::env; use crate::spec::{ - Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, RustcAbi, SplitDebuginfo, - StackProbeType, StaticCow, TargetOptions, cvs, + BinaryFormat, Cc, DebuginfoKind, FloatAbi, FramePointer, LinkerFlavor, Lld, RustcAbi, + SplitDebuginfo, StackProbeType, StaticCow, TargetOptions, cvs, }; #[cfg(test)] @@ -116,6 +116,7 @@ pub(crate) fn base( dynamic_linking: true, families: cvs!["unix"], is_like_osx: true, + binary_format: BinaryFormat::MachO, // LLVM notes that macOS 10.11+ and iOS 9+ default // to v4, so we do the same. // https://github.com/llvm/llvm-project/blob/378778a0d10c2f8d5df8ceff81f95b6002984a4b/clang/lib/Driver/ToolChains/Darwin.cpp#L1203 diff --git a/compiler/rustc_target/src/spec/base/cygwin.rs b/compiler/rustc_target/src/spec/base/cygwin.rs index fe3efb3f46ba0..819d1d68a71d9 100644 --- a/compiler/rustc_target/src/spec/base/cygwin.rs +++ b/compiler/rustc_target/src/spec/base/cygwin.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs}; +use crate::spec::{ + BinaryFormat, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs, +}; pub(crate) fn opts() -> TargetOptions { let mut pre_link_args = TargetOptions::link_args( @@ -32,6 +34,7 @@ pub(crate) fn opts() -> TargetOptions { exe_suffix: ".exe".into(), families: cvs!["unix"], is_like_windows: true, + binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, late_link_args, diff --git a/compiler/rustc_target/src/spec/base/fuchsia.rs b/compiler/rustc_target/src/spec/base/fuchsia.rs index 9deafcac27f15..92cb0299ddb2f 100644 --- a/compiler/rustc_target/src/spec/base/fuchsia.rs +++ b/compiler/rustc_target/src/spec/base/fuchsia.rs @@ -7,7 +7,7 @@ pub(crate) fn opts() -> TargetOptions { // now. When using clang as the linker it will supply these options for us, // so we only list them for ld/lld. // - // https://github.com/llvm/llvm-project/blob/db9322b2066c55254e7691efeab863f43bfcc084/clang/lib/Driver/ToolChains/Fuchsia.cpp#L31 + // https://github.com/llvm/llvm-project/blob/0419db6b95e246fe9dc90b5795beb77c393eb2ce/clang/lib/Driver/ToolChains/Fuchsia.cpp#L32 let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gnu(Cc::No, Lld::No), &[ @@ -18,9 +18,13 @@ pub(crate) fn opts() -> TargetOptions { "-z", "now", "-z", + "start-stop-visibility=hidden", + "-z", "rodynamic", "-z", "separate-loadable-segments", + "-z", + "rel", "--pack-dyn-relocs=relr", ], ); diff --git a/compiler/rustc_target/src/spec/base/linux_wasm.rs b/compiler/rustc_target/src/spec/base/linux_wasm.rs new file mode 100644 index 0000000000000..a8c137c22a97c --- /dev/null +++ b/compiler/rustc_target/src/spec/base/linux_wasm.rs @@ -0,0 +1,159 @@ +//! This target is a confluence of Linux and Wasm models, inheriting most +//! aspects from their respective base targets + +use crate::spec::{ + Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel, + add_link_args, crt_objects, cvs, +}; + +pub(crate) fn opts() -> TargetOptions { + macro_rules! args { + ($prefix:literal) => { + &[ + // By default LLD only gives us one page of stack (64k) which is a + // little small. Default to a larger stack closer to other PC platforms + // (1MB) and users can always inject their own link-args to override this. + concat!($prefix, "-z"), + concat!($prefix, "stack-size=1048576"), + // By default LLD's memory layout is: + // + // 1. First, a blank page + // 2. Next, all static data + // 3. Finally, the main stack (which grows down) + // + // This has the unfortunate consequence that on stack overflows you + // corrupt static data and can cause some exceedingly weird bugs. To + // help detect this a little sooner we instead request that the stack is + // placed before static data. + // + // This means that we'll generate slightly larger binaries as references + // to static data will take more bytes in the ULEB128 encoding, but + // stack overflow will be guaranteed to trap as it underflows instead of + // corrupting static data. + concat!($prefix, "--stack-first"), + // FIXME we probably shouldn't pass this but instead pass an explicit list + // of symbols we'll allow to be undefined. We don't currently have a + // mechanism of knowing, however, which symbols are intended to be imported + // from the environment and which are intended to be imported from other + // objects linked elsewhere. This is a coarse approximation but is sure to + // hide some bugs and frustrate someone at some point, so we should ideally + // work towards a world where we can explicitly list symbols that are + // supposed to be imported and have all other symbols generate errors if + // they remain undefined. + concat!($prefix, "--allow-undefined"), + // LLD only implements C++-like demangling, which doesn't match our own + // mangling scheme. Tell LLD to not demangle anything and leave it up to + // us to demangle these symbols later. Currently rustc does not perform + // further demangling, but tools like twiggy and wasm-bindgen are intended + // to do so. + concat!($prefix, "--no-demangle"), + ] + }; + } + + let mut pre_link_args = TargetOptions::link_args(LinkerFlavor::WasmLld(Cc::No), args!("")); + add_link_args(&mut pre_link_args, LinkerFlavor::WasmLld(Cc::Yes), args!("-Wl,")); + + TargetOptions { + is_like_wasm: true, + families: cvs!["wasm", "unix"], + os: "linux".into(), + env: "musl".into(), + + // we allow dynamic linking, but only cdylibs. Basically we allow a + // final library artifact that exports some symbols (a wasm module) but + // we don't allow intermediate `dylib` crate types + dynamic_linking: true, + only_cdylib: true, + + // relatively self-explanatory! + exe_suffix: ".wasm".into(), + dll_prefix: "".into(), + dll_suffix: ".wasm".into(), + eh_frame_header: false, + + max_atomic_width: Some(64), + + // Unwinding doesn't work right now, so the whole target unconditionally + // defaults to panic=abort. Note that this is guaranteed to change in + // the future once unwinding is implemented. Don't rely on this as we're + // basically guaranteed to change it once WebAssembly supports + // exceptions. + panic_strategy: PanicStrategy::Abort, + + // Symbol visibility takes care of this for the WebAssembly. + // Additionally the only known linker, LLD, doesn't support the script + // arguments just yet + limit_rdylib_exports: false, + + // we use the LLD shipped with the Rust toolchain by default + linker: Some("rust-lld".into()), + linker_flavor: LinkerFlavor::WasmLld(Cc::No), + + pre_link_args, + + // FIXME: Figure out cases in which WASM needs to link with a native toolchain. + // + // rust-lang/rust#104137: cannot blindly remove this without putting in + // some other way to compensate for lack of `-nostartfiles` in linker + // invocation. + link_self_contained: LinkSelfContainedDefault::True, + pre_link_objects_self_contained: crt_objects::pre_wasi_self_contained(), + post_link_objects_self_contained: crt_objects::post_wasi_self_contained(), + + // This has no effect in LLVM 8 or prior, but in LLVM 9 and later when + // PIC code is implemented this has quite a drastic effect if it stays + // at the default, `pic`. In an effort to keep wasm binaries as minimal + // as possible we're defaulting to `static` for now, but the hope is + // that eventually we can ship a `pic`-compatible standard library which + // works with `static` as well (or works with some method of generating + // non-relative calls and such later on). + relocation_model: RelocModel::Static, + + // When the atomics feature is activated then these two keys matter, + // otherwise they're basically ignored by the standard library. In this + // mode, however, the `#[thread_local]` attribute works (i.e. + // `has_thread_local`) and we need to get it to work by specifying + // `local-exec` as that's all that's implemented in LLVM today for wasm. + has_thread_local: true, + tls_model: TlsModel::LocalExec, + + // Supporting Linux requires multithreading supported by Wasm's thread + // proposal + singlethread: false, + + // gdb scripts don't work on wasm blobs + emit_debug_gdb_scripts: false, + + // There's more discussion of this at + // https://bugs.llvm.org/show_bug.cgi?id=52442 but the general result is + // that this isn't useful for wasm and has tricky issues with + // representation, so this is disabled. + generate_arange_section: false, + + // Right now this is a bit of a workaround but we're currently saying that + // the target by default has a static crt which we're taking as a signal + // for "use the bundled crt". If that's turned off then the system's crt + // will be used, but this means that default usage of this target doesn't + // need an external compiler but it's still interoperable with an external + // compiler if configured correctly. + crt_static_default: true, + crt_static_respected: true, + + // Allow `+crt-static` to create a "cdylib" output which is just a wasm file + // without a main function. + crt_static_allows_dylibs: true, + + // Wasm start ignores arguments -- relies on API call from interface. + main_needs_argc_argv: false, + + // Wasm toolchains mangle the name of "main" to distinguish between different + // signatures. + entry_name: "__main_void".into(), + + // Wasm Feature flags for supporting Linux + features: "+atomics,+bulk-memory,+mutable-globals,+sign-ext".into(), + + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index 6f88be5d37f16..e8fdc87178539 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -18,6 +18,7 @@ pub(crate) mod linux_gnu; pub(crate) mod linux_musl; pub(crate) mod linux_ohos; pub(crate) mod linux_uclibc; +pub(crate) mod linux_wasm; pub(crate) mod msvc; pub(crate) mod netbsd; pub(crate) mod nto_qnx; diff --git a/compiler/rustc_target/src/spec/base/msvc.rs b/compiler/rustc_target/src/spec/base/msvc.rs index b0fb2ef4b27f2..486d7158723f8 100644 --- a/compiler/rustc_target/src/spec/base/msvc.rs +++ b/compiler/rustc_target/src/spec/base/msvc.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use crate::spec::{DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions}; +use crate::spec::{BinaryFormat, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions}; pub(crate) fn opts() -> TargetOptions { // Suppress the verbose logo and authorship debugging output, which would needlessly @@ -12,6 +12,7 @@ pub(crate) fn opts() -> TargetOptions { dll_tls_export: false, is_like_windows: true, is_like_msvc: true, + binary_format: BinaryFormat::Coff, pre_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs index 81b96cd39ffac..88e7af5e66978 100644 --- a/compiler/rustc_target/src/spec/base/wasm.rs +++ b/compiler/rustc_target/src/spec/base/wasm.rs @@ -1,6 +1,6 @@ use crate::spec::{ - Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel, TargetOptions, TlsModel, - add_link_args, cvs, + BinaryFormat, Cc, LinkSelfContainedDefault, LinkerFlavor, PanicStrategy, RelocModel, + TargetOptions, TlsModel, add_link_args, cvs, }; pub(crate) fn options() -> TargetOptions { @@ -53,6 +53,7 @@ pub(crate) fn options() -> TargetOptions { TargetOptions { is_like_wasm: true, + binary_format: BinaryFormat::Wasm, families: cvs!["wasm"], // we allow dynamic linking, but only cdylibs. Basically we allow a diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index 024b10f2faad7..4ba1102198847 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; use crate::spec::{ - Cc, DebuginfoKind, LinkSelfContainedDefault, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, - add_link_args, crt_objects, cvs, + BinaryFormat, Cc, DebuginfoKind, LinkSelfContainedDefault, LinkerFlavor, Lld, SplitDebuginfo, + TargetOptions, add_link_args, crt_objects, cvs, }; pub(crate) fn opts() -> TargetOptions { @@ -90,6 +90,7 @@ pub(crate) fn opts() -> TargetOptions { exe_suffix: ".exe".into(), families: cvs!["windows"], is_like_windows: true, + binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, pre_link_objects: crt_objects::pre_mingw(), diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 4a6e7c75200f6..f24ad781e2b81 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; -use crate::spec::{Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs}; +use crate::spec::{ + BinaryFormat, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions, cvs, +}; pub(crate) fn opts() -> TargetOptions { // We cannot use `-nodefaultlibs` because compiler-rt has to be passed @@ -30,6 +32,7 @@ pub(crate) fn opts() -> TargetOptions { exe_suffix: ".exe".into(), families: cvs!["windows"], is_like_windows: true, + binary_format: BinaryFormat::Coff, allows_weak_linkage: false, pre_link_args, late_link_args, diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index f703132e51f0a..134405f3630e7 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -103,6 +103,19 @@ impl Target { base.$key_name = Some(s); } } ); + ($key_name:ident, BinaryFormat) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|f| f.as_str().and_then(|s| { + match s.parse::() { + Ok(binary_format) => base.$key_name = binary_format, + _ => return Some(Err(format!( + "'{s}' is not a valid value for binary_format. \ + Use 'coff', 'elf', 'mach-o', 'wasm' or 'xcoff' " + ))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, MergeFunctions) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -585,6 +598,7 @@ impl Target { key!(is_like_msvc, bool); key!(is_like_wasm, bool); key!(is_like_android, bool); + key!(binary_format, BinaryFormat)?; key!(default_dwarf_version, u32); key!(allows_weak_linkage, bool); key!(has_rpath, bool); @@ -762,6 +776,7 @@ impl ToJson for Target { target_option_val!(is_like_msvc); target_option_val!(is_like_wasm); target_option_val!(is_like_android); + target_option_val!(binary_format); target_option_val!(default_dwarf_version); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 65736770efb8c..1887134c5757d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -43,7 +43,7 @@ use std::str::FromStr; use std::{fmt, io}; use rustc_abi::{Endian, ExternAbi, Integer, Size, TargetDataLayout, TargetDataLayoutErrors}; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_fs_util::try_canonicalize; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; @@ -1644,6 +1644,55 @@ impl fmt::Display for StackProtector { } } +#[derive(PartialEq, Clone, Debug)] +pub enum BinaryFormat { + Coff, + Elf, + MachO, + Wasm, + Xcoff, +} + +impl BinaryFormat { + /// Returns [`object::BinaryFormat`] for given `BinaryFormat` + pub fn to_object(&self) -> object::BinaryFormat { + match self { + Self::Coff => object::BinaryFormat::Coff, + Self::Elf => object::BinaryFormat::Elf, + Self::MachO => object::BinaryFormat::MachO, + Self::Wasm => object::BinaryFormat::Wasm, + Self::Xcoff => object::BinaryFormat::Xcoff, + } + } +} + +impl FromStr for BinaryFormat { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "coff" => Ok(Self::Coff), + "elf" => Ok(Self::Elf), + "mach-o" => Ok(Self::MachO), + "wasm" => Ok(Self::Wasm), + "xcoff" => Ok(Self::Xcoff), + _ => Err(()), + } + } +} + +impl ToJson for BinaryFormat { + fn to_json(&self) -> Json { + match self { + Self::Coff => "coff", + Self::Elf => "elf", + Self::MachO => "mach-o", + Self::Wasm => "wasm", + Self::Xcoff => "xcoff", + } + .to_json() + } +} + macro_rules! supported_targets { ( $(($tuple:literal, $module:ident),)+ ) => { mod targets { @@ -1866,7 +1915,6 @@ supported_targets! { ("i686-pc-windows-msvc", i686_pc_windows_msvc), ("i686-uwp-windows-msvc", i686_uwp_windows_msvc), ("i686-win7-windows-msvc", i686_win7_windows_msvc), - ("i586-pc-windows-msvc", i586_pc_windows_msvc), ("thumbv7a-pc-windows-msvc", thumbv7a_pc_windows_msvc), ("thumbv7a-uwp-windows-msvc", thumbv7a_uwp_windows_msvc), @@ -1876,6 +1924,7 @@ supported_targets! { ("wasm32-wasip1", wasm32_wasip1), ("wasm32-wasip2", wasm32_wasip2), ("wasm32-wasip1-threads", wasm32_wasip1_threads), + ("wasm32-wali-linux-musl", wasm32_wali_linux_musl), ("wasm64-unknown-unknown", wasm64_unknown_unknown), ("thumbv6m-none-eabi", thumbv6m_none_eabi), @@ -2381,6 +2430,8 @@ pub struct TargetOptions { pub is_like_wasm: bool, /// Whether a target toolchain is like Android, implying a Linux kernel and a Bionic libc pub is_like_android: bool, + /// Target's binary file format. Defaults to BinaryFormat::Elf + pub binary_format: BinaryFormat, /// Default supported version of DWARF on this platform. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub default_dwarf_version: u32, @@ -2756,6 +2807,7 @@ impl Default for TargetOptions { is_like_msvc: false, is_like_wasm: false, is_like_android: false, + binary_format: BinaryFormat::Elf, default_dwarf_version: 4, allows_weak_linkage: true, has_rpath: false, @@ -2862,20 +2914,35 @@ impl Target { // On Windows, `extern "system"` behaves like msvc's `__stdcall`. // `__stdcall` only applies on x86 and on non-variadic functions: // https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 - System { unwind } if self.is_like_windows && self.arch == "x86" && !c_variadic => { - Stdcall { unwind } + System { unwind } => { + if self.is_like_windows && self.arch == "x86" && !c_variadic { + Stdcall { unwind } + } else { + C { unwind } + } + } + + EfiApi => { + if self.arch == "arm" { + Aapcs { unwind: false } + } else if self.arch == "x86_64" { + Win64 { unwind: false } + } else { + C { unwind: false } + } } - System { unwind } => C { unwind }, - EfiApi if self.arch == "arm" => Aapcs { unwind: false }, - EfiApi if self.arch == "x86_64" => Win64 { unwind: false }, - EfiApi => C { unwind: false }, // See commentary in `is_abi_supported`. - Stdcall { .. } | Thiscall { .. } if self.arch == "x86" => abi, - Stdcall { unwind } | Thiscall { unwind } => C { unwind }, - Fastcall { .. } if self.arch == "x86" => abi, - Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi, - Fastcall { unwind } | Vectorcall { unwind } => C { unwind }, + Stdcall { unwind } | Thiscall { unwind } | Fastcall { unwind } => { + if self.arch == "x86" { abi } else { C { unwind } } + } + Vectorcall { unwind } => { + if ["x86", "x86_64"].contains(&&*self.arch) { + abi + } else { + C { unwind } + } + } // The Windows x64 calling convention we use for `extern "Rust"` // @@ -3436,7 +3503,15 @@ impl Target { return load_file(&p); } - Err(format!("Could not find specification for target {target_tuple:?}")) + // Leave in a specialized error message for the removed target. + // FIXME: If you see this and it's been a few months after this has been released, + // you can probably remove it. + if target_tuple == "i586-pc-windows-msvc" { + Err("the `i586-pc-windows-msvc` target has been removed. Use the `i686-pc-windows-msvc` target instead.\n\ + Windows 10 (the minimum required OS version) requires a CPU baseline of at least i686 so you can safely switch".into()) + } else { + Err(format!("Could not find specification for target {target_tuple:?}")) + } } TargetTuple::TargetJson { ref contents, .. } => { let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; @@ -3468,6 +3543,59 @@ impl Target { s => s.clone(), } } + + pub fn object_architecture( + &self, + unstable_target_features: &FxIndexSet, + ) -> Option<(object::Architecture, Option)> { + use object::Architecture; + Some(match self.arch.as_ref() { + "arm" => (Architecture::Arm, None), + "aarch64" => ( + if self.pointer_width == 32 { + Architecture::Aarch64_Ilp32 + } else { + Architecture::Aarch64 + }, + None, + ), + "x86" => (Architecture::I386, None), + "s390x" => (Architecture::S390x, None), + "mips" | "mips32r6" => (Architecture::Mips, None), + "mips64" | "mips64r6" => (Architecture::Mips64, None), + "x86_64" => ( + if self.pointer_width == 32 { + Architecture::X86_64_X32 + } else { + Architecture::X86_64 + }, + None, + ), + "powerpc" => (Architecture::PowerPc, None), + "powerpc64" => (Architecture::PowerPc64, None), + "riscv32" => (Architecture::Riscv32, None), + "riscv64" => (Architecture::Riscv64, None), + "sparc" => { + if unstable_target_features.contains(&sym::v8plus) { + // Target uses V8+, aka EM_SPARC32PLUS, aka 64-bit V9 but in 32-bit mode + (Architecture::Sparc32Plus, None) + } else { + // Target uses V7 or V8, aka EM_SPARC + (Architecture::Sparc, None) + } + } + "sparc64" => (Architecture::Sparc64, None), + "avr" => (Architecture::Avr, None), + "msp430" => (Architecture::Msp430, None), + "hexagon" => (Architecture::Hexagon, None), + "bpf" => (Architecture::Bpf, None), + "loongarch64" => (Architecture::LoongArch64, None), + "csky" => (Architecture::Csky, None), + "arm64ec" => (Architecture::Aarch64, Some(object::SubArchitecture::Arm64EC)), + // Unsupported architecture. + _ => return None, + }) + } } /// Either a target tuple string or a path to a JSON file. diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs index 23ed92e62b8e9..8366b6d9bd824 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_fuchsia.rs @@ -1,6 +1,28 @@ -use crate::spec::{SanitizerSet, StackProbeType, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{ + Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target, TargetMetadata, base, +}; pub(crate) fn target() -> Target { + let mut base = base::fuchsia::opts(); + base.cpu = "generic".into(); + base.features = "+v8a,+crc,+aes,+sha2,+neon".into(); + base.max_atomic_width = Some(128); + base.stack_probes = StackProbeType::Inline; + base.supported_sanitizers = SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::LEAK + | SanitizerSet::SHADOWCALLSTACK; + base.supports_xray = true; + + base.add_pre_link_args( + LinkerFlavor::Gnu(Cc::No, Lld::No), + &[ + "--execute-only", + // Enable the Cortex-A53 errata 843419 mitigation by default + "--fix-cortex-a53-843419", + ], + ); + Target { llvm_target: "aarch64-unknown-fuchsia".into(), metadata: TargetMetadata { @@ -12,14 +34,6 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), - options: TargetOptions { - features: "+v8a".into(), - max_atomic_width: Some(128), - stack_probes: StackProbeType::Inline, - supported_sanitizers: SanitizerSet::ADDRESS - | SanitizerSet::CFI - | SanitizerSet::SHADOWCALLSTACK, - ..base::fuchsia::opts() - }, + options: base, } } diff --git a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs deleted file mode 100644 index 394e6f9e6bf65..0000000000000 --- a/compiler/rustc_target/src/spec/targets/i586_pc_windows_msvc.rs +++ /dev/null @@ -1,9 +0,0 @@ -use crate::spec::Target; - -pub(crate) fn target() -> Target { - let mut base = super::i686_pc_windows_msvc::target(); - base.rustc_abi = None; // overwrite the SSE2 ABI set by the base target - base.cpu = "pentium".into(); - base.llvm_target = "i586-pc-windows-msvc".into(); - base -} diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs index 03bae9b597778..3c1d18e077719 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs @@ -24,7 +24,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: "spe".into(), endian: Endian::Big, - features: "+secure-plt".into(), + features: "+secure-plt,+msync".into(), mcount: "_mcount".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs index df4fd75b0bded..30d0d9cb60a77 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_muslspe.rs @@ -26,6 +26,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: "spe".into(), endian: Endian::Big, + features: "+msync".into(), mcount: "_mcount".into(), ..base }, diff --git a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs index 55dc6a70627c9..8a4bc58e546e8 100644 --- a/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv32_wrs_vxworks.rs @@ -2,7 +2,7 @@ use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { - llvm_target: "riscv32".into(), + llvm_target: "riscv32-unknown-linux-gnu".into(), metadata: TargetMetadata { description: None, tier: Some(3), diff --git a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs index 58ded24b9c599..39aa70035e4a7 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64_wrs_vxworks.rs @@ -2,7 +2,7 @@ use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base}; pub(crate) fn target() -> Target { Target { - llvm_target: "riscv64".into(), + llvm_target: "riscv64-unknown-linux-gnu".into(), metadata: TargetMetadata { description: None, tier: Some(3), diff --git a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs index d673936f5f85d..e260237ca7764 100644 --- a/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/riscv64gc_unknown_fuchsia.rs @@ -1,6 +1,16 @@ -use crate::spec::{CodeModel, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; +use crate::spec::{CodeModel, SanitizerSet, StackProbeType, Target, TargetMetadata, base}; pub(crate) fn target() -> Target { + let mut base = base::fuchsia::opts(); + base.code_model = Some(CodeModel::Medium); + base.cpu = "generic-rv64".into(); + base.features = "+m,+a,+f,+d,+c".into(); + base.llvm_abiname = "lp64d".into(); + base.max_atomic_width = Some(64); + base.stack_probes = StackProbeType::Inline; + base.supported_sanitizers = SanitizerSet::SHADOWCALLSTACK; + base.supports_xray = true; + Target { llvm_target: "riscv64-unknown-fuchsia".into(), metadata: TargetMetadata { @@ -12,14 +22,6 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(), arch: "riscv64".into(), - options: TargetOptions { - code_model: Some(CodeModel::Medium), - cpu: "generic-rv64".into(), - features: "+m,+a,+f,+d,+c".into(), - llvm_abiname: "lp64d".into(), - max_atomic_width: Some(64), - supported_sanitizers: SanitizerSet::SHADOWCALLSTACK, - ..base::fuchsia::opts() - }, + options: base, } } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs new file mode 100644 index 0000000000000..a0eb4a254fc0e --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs @@ -0,0 +1,29 @@ +//! The `wasm32-wali-linux-musl` target is a wasm32 target compliant with the +//! [WebAssembly Linux Interface](https://github.com/arjunr2/WALI). + +use crate::spec::{Cc, LinkerFlavor, Target, TargetMetadata, base}; + +pub(crate) fn target() -> Target { + let mut options = base::linux_wasm::opts(); + + options + .add_pre_link_args(LinkerFlavor::WasmLld(Cc::No), &["--export-memory", "--shared-memory"]); + options.add_pre_link_args( + LinkerFlavor::WasmLld(Cc::Yes), + &["--target=wasm32-wasi-threads", "-Wl,--export-memory,", "-Wl,--shared-memory"], + ); + + Target { + llvm_target: "wasm32-wasi".into(), + metadata: TargetMetadata { + description: Some("WebAssembly Linux Interface with musl-libc".into()), + tier: Some(3), + host_tools: Some(false), + std: None, + }, + pointer_width: 32, + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(), + arch: "wasm32".into(), + options, + } +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs index d41c696ac23bf..d7253da7e8d66 100644 --- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_fuchsia.rs @@ -4,7 +4,10 @@ pub(crate) fn target() -> Target { let mut base = base::fuchsia::opts(); base.cpu = "x86-64".into(); base.plt_by_default = false; - base.max_atomic_width = Some(64); + // See https://fuchsia.dev/fuchsia-src/contribute/governance/rfcs/0073_x86_64_platform_requirement, + // which corresponds to x86-64-v2. + base.features = "+cx16,+sahf,+popcnt,+sse3,+sse4.1,+sse4.2,+ssse3".into(); + base.max_atomic_width = Some(128); base.stack_probes = StackProbeType::Inline; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK; base.supports_xray = true; diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs index dd98f34d32399..cffdaa9072738 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { vendor: "espressif".into(), executables: true, - cpu: "esp32-s2".into(), + cpu: "esp32s2".into(), linker: Some("xtensa-esp32s2-elf-gcc".into()), // See https://github.com/espressif/rust-esp32-example/issues/3#issuecomment-861054477 diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs index 29bcf12cbaf6c..7bf5834ab0aa0 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_none_elf.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { vendor: "espressif".into(), - cpu: "esp32-s2".into(), + cpu: "esp32s2".into(), linker: Some("xtensa-esp32s2-elf-gcc".into()), max_atomic_width: Some(32), features: "+forced-atomics".into(), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs index dd6e7b6c3e8c1..2e4afc005414d 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { vendor: "espressif".into(), executables: true, - cpu: "esp32-s3".into(), + cpu: "esp32s3".into(), linker: Some("xtensa-esp32s3-elf-gcc".into()), // The esp32s3 only supports native 32bit atomics. diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs index ddc909f387e9e..d506888d8ee04 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_none_elf.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { vendor: "espressif".into(), - cpu: "esp32-s3".into(), + cpu: "esp32s3".into(), linker: Some("xtensa-esp32s3-elf-gcc".into()), max_atomic_width: Some(32), atomic_cas: true, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b98bca60c9de4..a32b42a6fe333 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -461,6 +461,7 @@ const HEXAGON_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("altivec", Unstable(sym::powerpc_target_feature), &[]), + ("msync", Unstable(sym::powerpc_target_feature), &[]), ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]), @@ -497,9 +498,14 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("relax", Unstable(sym::riscv_target_feature), &[]), ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &[]), + ("za128rs", Unstable(sym::riscv_target_feature), &[]), + ("za64rs", Unstable(sym::riscv_target_feature), &[]), ("zaamo", Unstable(sym::riscv_target_feature), &[]), ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), + ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]), ("zalrsc", Unstable(sym::riscv_target_feature), &[]), + ("zama16b", Unstable(sym::riscv_target_feature), &[]), + ("zawrs", Unstable(sym::riscv_target_feature), &[]), ("zba", Stable, &[]), ("zbb", Stable, &[]), ("zbc", Stable, &[]), @@ -597,13 +603,18 @@ static CSKY_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ static LOONGARCH_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("d", Unstable(sym::loongarch_target_feature), &["f"]), + ("div32", Unstable(sym::loongarch_target_feature), &[]), ("f", Unstable(sym::loongarch_target_feature), &[]), ("frecipe", Unstable(sym::loongarch_target_feature), &[]), + ("lam-bh", Unstable(sym::loongarch_target_feature), &[]), + ("lamcas", Unstable(sym::loongarch_target_feature), &[]), ("lasx", Unstable(sym::loongarch_target_feature), &["lsx"]), ("lbt", Unstable(sym::loongarch_target_feature), &[]), + ("ld-seq-sa", Unstable(sym::loongarch_target_feature), &[]), ("lsx", Unstable(sym::loongarch_target_feature), &["d"]), ("lvz", Unstable(sym::loongarch_target_feature), &[]), ("relax", Unstable(sym::loongarch_target_feature), &[]), + ("scq", Unstable(sym::loongarch_target_feature), &[]), ("ual", Unstable(sym::loongarch_target_feature), &[]), // tidy-alphabetical-end ]; @@ -762,17 +773,15 @@ impl Target { } } - pub fn implied_target_features<'a>( - &self, - base_features: impl Iterator, - ) -> FxHashSet<&'a str> { + // Note: the returned set includes `base_feature`. + pub fn implied_target_features<'a>(&self, base_feature: &'a str) -> FxHashSet<&'a str> { let implied_features = self.rust_target_features().iter().map(|(f, _, i)| (f, i)).collect::>(); - // implied target features have their own implied target features, so we traverse the - // map until there are no more features to add + // Implied target features have their own implied target features, so we traverse the + // map until there are no more features to add. let mut features = FxHashSet::default(); - let mut new_features = base_features.collect::>(); + let mut new_features = vec![base_feature]; while let Some(new_feature) = new_features.pop() { if features.insert(new_feature) { if let Some(implied_features) = implied_features.get(&new_feature) { diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index 2f2361609a26c..1c61e23362a83 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_trait_selection" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 055a3edcc3293..4db9d9915b139 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -225,14 +225,6 @@ trait_selection_mismatched_static_lifetime = incompatible lifetime on type trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute .help = at least one of the `message`, `note` and `label` options are expected -trait_selection_more_targeted = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but calling `{$ident}` introduces an implicit `'static` lifetime requirement - trait_selection_msl_introduces_static = introduces a `'static` lifetime requirement trait_selection_msl_unmet_req = because this has an unmet lifetime requirement diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index a618bae269fa4..6510dbbbe9d9b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -65,7 +65,9 @@ use rustc_middle::bug; use rustc_middle::dep_graph::DepContext; use rustc_middle::traits::PatternOriginExpr; use rustc_middle::ty::error::{ExpectedFound, TypeError, TypeErrorToStringExt}; -use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, with_forced_trimmed_paths}; +use rustc_middle::ty::print::{ + PrintError, PrintTraitRefExt as _, WrapBinderMode, with_forced_trimmed_paths, +}; use rustc_middle::ty::{ self, List, ParamEnv, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -507,7 +509,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::MatchSource::TryDesugar(scrut_hir_id), ) => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { - let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); + let scrut_expr = self.tcx.hir_expect_expr(scrut_hir_id); let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let arg_expr = args.first().expect("try desugaring call w/out arg"); self.typeck_results @@ -546,7 +548,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) => match source { hir::MatchSource::TryDesugar(scrut_hir_id) => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { - let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); + let scrut_expr = self.tcx.hir_expect_expr(scrut_hir_id); let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { let arg_expr = args.first().expect("try desugaring call w/out arg"); self.typeck_results @@ -835,7 +837,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let get_lifetimes = |sig| { use rustc_hir::def::Namespace; let (sig, reg) = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS) - .name_all_regions(sig) + .name_all_regions(sig, WrapBinderMode::ForAll) .unwrap(); let lts: Vec = reg.into_items().map(|(_, kind)| kind.to_string()).into_sorted_stable_ord(); @@ -1464,7 +1466,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - impl<'tcx> ty::visit::TypeVisitor> for OpaqueTypesVisitor<'tcx> { + impl<'tcx> ty::TypeVisitor> for OpaqueTypesVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) { if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) { let span = self.tcx.def_span(def_id); @@ -2418,7 +2420,7 @@ impl<'tcx> ObligationCause<'tcx> { pub struct ObligationCauseAsDiagArg<'tcx>(pub ObligationCause<'tcx>); impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { let kind = match self.0.code() { ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat", ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat", diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 42b8199cb265e..0bcb5f6f3b286 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults, }; use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym}; -use rustc_type_ir::visit::TypeVisitableExt; +use rustc_type_ir::TypeVisitableExt; use tracing::{debug, instrument, warn}; use super::nice_region_error::placeholder_error::Highlighted; @@ -137,7 +137,7 @@ impl InferenceDiagnosticsParentData { } impl IntoDiagArg for UnderspecifiedArgKind { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { let kind = match self { Self::Type { .. } => "type", Self::Const { is_parameter: true } => "const_with_param", @@ -1074,7 +1074,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { &self, path: &'tcx hir::Path<'tcx>, args: GenericArgsRef<'tcx>, - ) -> impl Iterator> + 'a { + ) -> impl Iterator> + 'tcx { let tcx = self.tecx.tcx; let have_turbofish = path.segments.iter().any(|segment| { segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const())) @@ -1351,7 +1351,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { && !has_impl_trait(def_id) // FIXME(fn_delegation): In delegation item argument spans are equal to last path // segment. This leads to ICE's when emitting `multipart_suggestion`. - && tcx.hir().opt_delegation_sig_id(expr.hir_id.owner.def_id).is_none() + && tcx.hir_opt_delegation_sig_id(expr.hir_id.owner.def_id).is_none() { let successor = method_args.get(0).map_or_else(|| (")", span.hi()), |arg| (", ", arg.span.lo())); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs index ad2f7f00fa53d..0904177ea8bb1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs @@ -33,11 +33,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { }; // If we added a "points at argument expression" obligation, we remove it here, we care // about the original obligation only. - let code = match cause.code() { - ObligationCauseCode::FunctionArg { parent_code, .. } => &*parent_code, - code => code, - }; - let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else { + let ObligationCauseCode::MatchImpl(parent, impl_def_id) = cause.code() else { return None; }; let (ObligationCauseCode::WhereClause(_, binding_span) diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index aaaefd81d19bd..5056161e117e6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs @@ -31,7 +31,7 @@ impl<'tcx, T> IntoDiagArg for Highlighted<'tcx, T> where T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>>, { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { rustc_errors::DiagArgValue::Str(self.to_string().into()) } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 3f15a79271d5b..083ce022238a0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -1,27 +1,21 @@ //! Error Reporting for static impl Traits. use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnostic}; +use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty}; use rustc_hir::{ self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind, }; -use rustc_middle::ty::{ - self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor, -}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; use rustc_span::{Ident, Span}; use tracing::debug; use crate::error_reporting::infer::nice_region_error::NiceRegionError; -use crate::errors::{ - ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted, - ReqIntroducedLocations, -}; -use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace}; -use crate::traits::{ObligationCauseCode, UnifyReceiverContext}; +use crate::errors::ButNeedsToSatisfy; +use crate::infer::{RegionResolutionError, SubregionOrigin}; impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { /// Print the error message for lifetime errors when the return type is a static `impl Trait`, @@ -39,52 +33,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sup_r, spans, ) if sub_r.is_static() => (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans), - RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { cause, .. }), - sub_r, - sup_r, - ) if sub_r.is_static() => { - // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. - if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() { - // This may have a closure and it would cause ICE - // through `find_param_with_region` (#78262). - let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?; - let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.scope); - if fn_returns.is_empty() { - return None; - } - - let param = self.find_param_with_region(*sup_r, *sub_r)?; - let simple_ident = param.param.pat.simple_ident(); - - let (has_impl_path, impl_path) = match ctxt.assoc_item.container { - AssocItemContainer::Trait => { - let id = ctxt.assoc_item.container_id(tcx); - (true, tcx.def_path_str(id)) - } - AssocItemContainer::Impl => (false, String::new()), - }; - - let mut err = self.tcx().dcx().create_err(ButCallingIntroduces { - param_ty_span: param.param_ty_span, - cause_span: cause.span, - has_param_name: simple_ident.is_some(), - param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(), - has_lifetime: sup_r.has_name(), - lifetime: sup_r.to_string(), - assoc_item: ctxt.assoc_item.name, - has_impl_path, - impl_path, - }); - if self.find_impl_on_dyn_trait(&mut err, param.param_ty, ctxt) { - let reported = err.emit(); - return Some(reported); - } else { - err.cancel() - } - } - return None; - } _ => return None, }; debug!( @@ -140,39 +88,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { None }; - let mut subdiag = None; - - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { - if let ObligationCauseCode::ReturnValue(hir_id) - | ObligationCauseCode::BlockTailExpression(hir_id, ..) = cause.code() - { - let parent_id = tcx.hir_get_parent_item(*hir_id); - if let Some(fn_decl) = tcx.hir_fn_decl_by_hir_id(parent_id.into()) { - let mut span: MultiSpan = fn_decl.output.span().into(); - let mut spans = Vec::new(); - let mut add_label = true; - if let hir::FnRetTy::Return(ty) = fn_decl.output { - let mut v = StaticLifetimeVisitor(vec![], tcx.hir()); - v.visit_ty_unambig(ty); - if !v.0.is_empty() { - span = v.0.clone().into(); - spans = v.0; - add_label = false; - } - } - let fn_decl_span = fn_decl.output.span(); - - subdiag = Some(ReqIntroducedLocations { - span, - spans, - fn_decl_span, - cause_span: cause.span, - add_label, - }); - } - } - } - let diag = ButNeedsToSatisfy { sp, influencer_point, @@ -183,7 +98,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { require_span_as_note: require_as_note.then_some(require_span), // We don't need a note, it's already at the end, it can be shown as a `span_label`. require_span_as_label: (!require_as_note).then_some(require_span), - req_introduces_loc: subdiag, has_lifetime: sup_r.has_name(), lifetime: lifetime_name.clone(), @@ -197,45 +111,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.scope); - let mut override_error_code = None; - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin - && let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() - // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a - // `'static` lifetime when called as a method on a binding: `bar.qux()`. - && self.find_impl_on_dyn_trait(&mut err, param.param_ty, ctxt) - { - override_error_code = Some(ctxt.assoc_item.name); - } - - if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin - && let code = match cause.code() { - ObligationCauseCode::MatchImpl(parent, ..) => parent.code(), - _ => cause.code(), - } - && let ( - &ObligationCauseCode::WhereClause(item_def_id, _) - | &ObligationCauseCode::WhereClauseInExpr(item_def_id, ..), - None, - ) = (code, override_error_code) - { - // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static` - // lifetime as above, but called using a fully-qualified path to the method: - // `Foo::qux(bar)`. - let mut v = TraitObjectVisitor(FxIndexSet::default()); - v.visit_ty(param.param_ty); - if let Some((ident, self_ty)) = - NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0) - && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) - { - override_error_code = Some(ident.name); - } - } - if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) { - // Provide a more targeted error code and description. - let retarget_subdiag = MoreTargeted { ident }; - retarget_subdiag.add_to_diag(&mut err); - } - let arg = match param.param.pat.simple_ident() { Some(simple_ident) => format!("argument `{simple_ident}`"), None => "the argument".to_string(), @@ -495,8 +370,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { kind: ItemKind::Impl(hir::Impl { self_ty, .. }), .. }) = tcx.hir_node_by_def_id(impl_did) && trait_objects.iter().all(|did| { - // FIXME: we should check `self_ty` against the receiver - // type in the `UnifyReceiver` context, but for now, use + // FIXME: we should check `self_ty`, but for now, use // this imperfect proxy. This will fail if there are // multiple `impl`s for the same trait like // `impl Foo for Box` and `impl Foo for dyn Bar`. @@ -516,62 +390,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _ => None, } } - - /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default - /// `'static` obligation. Suggest relaxing that implicit bound. - fn find_impl_on_dyn_trait( - &self, - err: &mut Diag<'_>, - ty: Ty<'_>, - ctxt: &UnifyReceiverContext<'tcx>, - ) -> bool { - let tcx = self.tcx(); - - // Find the method being called. - let Ok(Some(instance)) = ty::Instance::try_resolve( - tcx, - self.cx.typing_env(ctxt.param_env), - ctxt.assoc_item.def_id, - self.cx.resolve_vars_if_possible(ctxt.args), - ) else { - return false; - }; - - let mut v = TraitObjectVisitor(FxIndexSet::default()); - v.visit_ty(ty); - - // Get the `Ident` of the method being called and the corresponding `impl` (to point at - // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called). - let Some((ident, self_ty)) = - NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) - else { - return false; - }; - - // Find the trait object types in the argument, so we point at *only* the trait object. - self.suggest_constrain_dyn_trait_in_impl(err, &v.0, ident, self_ty) - } - - fn suggest_constrain_dyn_trait_in_impl( - &self, - err: &mut Diag<'_>, - found_dids: &FxIndexSet, - ident: Ident, - self_ty: &hir::Ty<'_>, - ) -> bool { - let mut suggested = false; - for found_did in found_dids { - let mut traits = vec![]; - let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did); - hir_v.visit_ty_unambig(self_ty); - for &span in &traits { - let subdiag = DynTraitConstraintSuggestion { span, ident }; - subdiag.add_to_diag(err); - suggested = true; - } - } - suggested - } } /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index cc2ab1c343289..742059228510d 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs @@ -71,7 +71,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { } } - impl<'tcx> ty::visit::TypeVisitor> for HighlightBuilder<'tcx> { + impl<'tcx> ty::TypeVisitor> for HighlightBuilder<'tcx> { fn visit_region(&mut self, r: ty::Region<'tcx>) { if !r.has_name() && self.counter <= 3 { self.highlight.highlighting_region(r, self.counter); diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 245764c94abf0..00f053fa599e0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs @@ -3,8 +3,7 @@ use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable}; +use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable, fold_regions}; use rustc_span::Span; use tracing::instrument; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index 36726cc6cae0d..5583deda99a49 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -395,11 +395,28 @@ impl Trait for X { let sp = tcx .def_ident_span(body_owner_def_id) .unwrap_or_else(|| tcx.def_span(body_owner_def_id)); - diag.span_note( - sp, - "this item must have the opaque type in its signature in order to \ - be able to register hidden types", - ); + let mut alias_def_id = opaque_ty.def_id; + while let DefKind::OpaqueTy = tcx.def_kind(alias_def_id) { + alias_def_id = tcx.parent(alias_def_id); + } + let opaque_path = tcx.def_path_str(alias_def_id); + // FIXME(type_alias_impl_trait): make this a structured suggestion + match tcx.opaque_ty_origin(opaque_ty.def_id) { + rustc_hir::OpaqueTyOrigin::FnReturn { .. } => {} + rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {} + rustc_hir::OpaqueTyOrigin::TyAlias { + in_assoc_ty: false, .. + } => { + diag.span_note( + sp, + format!("this item must have a `#[define_opaque({opaque_path})]` \ + attribute to be able to define hidden types"), + ); + } + rustc_hir::OpaqueTyOrigin::TyAlias { + in_assoc_ty: true, .. + } => {} + } } // If two if arms can be coerced to a trait object, provide a structured // suggestion. @@ -522,7 +539,8 @@ impl Trait for X { } } TypeError::TargetFeatureCast(def_id) => { - let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span); + let target_spans = + tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span()); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); @@ -725,7 +743,7 @@ fn foo(&self) -> Self::T { String::new() } if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() { let opaque_local_def_id = def_id.as_local(); let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id { - tcx.hir().expect_opaque_ty(opaque_local_def_id) + tcx.hir_expect_opaque_ty(opaque_local_def_id) } else { return false; }; diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index fecb38ab597e4..c7f0a88f951a8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -1023,7 +1023,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!(" for lifetime parameter `{name}`") } infer::UpvarRegion(ref upvar_id, _) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); + let var_name = self.tcx.hir_name(upvar_id.var_path.hir_id); format!(" for capture of `{var_name}` by closure") } infer::Nll(..) => bug!("NLL variable found in lexical phase"), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index a87a449daf1c7..cdbb92f4c7baa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -237,7 +237,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() }) } ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - ref prior_non_diverging_arms, + prior_non_diverging_arms, .. }) => Some({ ConsiderAddingAwait::FutureSuggMultiple { @@ -778,8 +778,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let exp_local_id = exp_def_id.as_local()?; match ( - &self.tcx.hir().expect_opaque_ty(last_local_id), - &self.tcx.hir().expect_opaque_ty(exp_local_id), + &self.tcx.hir_expect_opaque_ty(last_local_id), + &self.tcx.hir_expect_opaque_ty(exp_local_id), ) { ( hir::OpaqueTy { bounds: last_bounds, .. }, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index f15f1b78b5282..d673e5672a00b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -1,8 +1,6 @@ use std::ops::ControlFlow; -use rustc_errors::{ - Applicability, Diag, E0283, E0284, E0790, MultiSpan, StashKey, struct_span_code_err, -}; +use rustc_errors::{Applicability, Diag, E0283, E0284, E0790, MultiSpan, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::LangItem; use rustc_hir::def::{DefKind, Res}; @@ -197,7 +195,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // be ignoring the fact that we don't KNOW the type works // out. Though even that would probably be harmless, given that // we're only talking about builtin traits, which are known to be - // inhabited. We used to check for `self.tcx.sess.has_errors()` to + // inhabited. We used to check for `self.tainted_by_errors()` to // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. @@ -211,7 +209,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { TypeAnnotationNeeded::E0282, false, ); - return err.stash(span, StashKey::MaybeForgetReturn).unwrap(); + return err.emit(); } Some(e) => return e, } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index c92dfa24f85ed..07a67cde3be1c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -18,12 +18,14 @@ use rustc_middle::traits::SignatureMismatchData; use rustc_middle::traits::select::OverflowError; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::print::{ PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _, with_forced_trimmed_paths, }; -use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast}; +use rustc_middle::ty::{ + self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + Upcast, +}; use rustc_middle::{bug, span_bug}; use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -829,7 +831,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) = *typeck_results.node_type(arg_hir_id).kind() { - // Otherwise, extract the closure kind from the obligation. + // Otherwise, extract the closure kind from the obligation, + // but only if we actually have an argument to deduce the + // closure type from... let mut err = self.report_closure_error( &obligation, closure_def_id, @@ -844,63 +848,72 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let self_ty = trait_pred.self_ty().skip_binder(); - if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) { - let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { - ty::Closure(def_id, args) => { - (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) - } - ty::CoroutineClosure(def_id, args) => ( - def_id, - args.as_coroutine_closure() - .coroutine_closure_sig() - .map_bound(|sig| sig.tupled_inputs_ty), - Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), - ), - _ => return None, + let (expected_kind, trait_prefix) = + if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) { + (expected_kind, "") + } else if let Some(expected_kind) = + self.tcx.async_fn_trait_kind_from_def_id(trait_pred.def_id()) + { + (expected_kind, "Async") + } else { + return None; }; - let expected_args = - trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1)); - - // Verify that the arguments are compatible. If the signature is - // mismatched, then we have a totally different error to report. - if self.enter_forall(found_args, |found_args| { - self.enter_forall(expected_args, |expected_args| { - !self.can_eq(obligation.param_env, expected_args, found_args) - }) - }) { - return None; + let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { + ty::Closure(def_id, args) => { + (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) } + ty::CoroutineClosure(def_id, args) => ( + def_id, + args.as_coroutine_closure() + .coroutine_closure_sig() + .map_bound(|sig| sig.tupled_inputs_ty), + Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()), + ), + _ => return None, + }; - if let Some(found_kind) = self.closure_kind(self_ty) - && !found_kind.extends(expected_kind) - { - let mut err = self.report_closure_error( - &obligation, - closure_def_id, - found_kind, - expected_kind, - "", - ); - self.note_obligation_cause(&mut err, &obligation); - return Some(err.emit()); - } + let expected_args = trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1)); - // If the closure has captures, then perhaps the reason that the trait - // is unimplemented is because async closures don't implement `Fn`/`FnMut` - // if they have captures. - if let Some(by_ref_captures) = by_ref_captures - && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind() - && !sig_tys.skip_binder().output().is_unit() - { - let mut err = self.dcx().create_err(AsyncClosureNotFn { - span: self.tcx.def_span(closure_def_id), - kind: expected_kind.as_str(), - }); - self.note_obligation_cause(&mut err, &obligation); - return Some(err.emit()); - } + // Verify that the arguments are compatible. If the signature is + // mismatched, then we have a totally different error to report. + if self.enter_forall(found_args, |found_args| { + self.enter_forall(expected_args, |expected_args| { + !self.can_eq(obligation.param_env, expected_args, found_args) + }) + }) { + return None; + } + + if let Some(found_kind) = self.closure_kind(self_ty) + && !found_kind.extends(expected_kind) + { + let mut err = self.report_closure_error( + &obligation, + closure_def_id, + found_kind, + expected_kind, + trait_prefix, + ); + self.note_obligation_cause(&mut err, &obligation); + return Some(err.emit()); + } + + // If the closure has captures, then perhaps the reason that the trait + // is unimplemented is because async closures don't implement `Fn`/`FnMut` + // if they have captures. + if let Some(by_ref_captures) = by_ref_captures + && let ty::FnPtr(sig_tys, _) = by_ref_captures.kind() + && !sig_tys.skip_binder().output().is_unit() + { + let mut err = self.dcx().create_err(AsyncClosureNotFn { + span: self.tcx.def_span(closure_def_id), + kind: expected_kind.as_str(), + }); + self.note_obligation_cause(&mut err, &obligation); + return Some(err.emit()); } + None } @@ -1189,9 +1202,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let span = obligation.cause.span; let mut diag = match ty.kind() { - _ if ty.has_param() => { - span_bug!(span, "const param tys cannot mention other generic parameters"); - } ty::Float(_) => { struct_span_code_err!( self.dcx(), @@ -2419,6 +2429,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &mut vec![], &mut Default::default(), ); + self.suggest_swapping_lhs_and_rhs( + err, + obligation.predicate, + obligation.param_env, + obligation.cause.code(), + ); self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = @@ -2437,7 +2453,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligated_types: &mut Vec>, cause_code: &ObligationCauseCode<'tcx>, ) -> bool { - if let ObligationCauseCode::BuiltinDerived(ref data) = cause_code { + if let ObligationCauseCode::BuiltinDerived(data) = cause_code { let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred); let self_ty = parent_trait_ref.skip_binder().self_ty(); if obligated_types.iter().any(|ot| ot == &self_ty) { @@ -2530,9 +2546,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return GetSafeTransmuteErrorAndReason::Silent; }; - let Some(assume) = - rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) - else { + let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else { self.dcx().span_delayed_bug( span, "Unable to construct rustc_transmute::Assume where it was previously possible", @@ -2544,11 +2558,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let src = trait_pred.trait_ref.args.type_at(1); let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); - match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( - obligation.cause, - src_and_dst, - assume, - ) { + match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx) + .is_transmutable(src_and_dst, assume) + { Answer::No(reason) => { let safe_transmute_explanation = match reason { rustc_transmute::Reason::SrcIsNotYetSupported => { @@ -3251,7 +3263,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, span: Span, ) -> Result, ErrorGuaranteed> { - if !self.tcx.features().generic_const_exprs() { + if !self.tcx.features().generic_const_exprs() + && !self.tcx.features().min_generic_const_args() + { let guar = self .dcx() .struct_span_err(span, "constant expression depends on a generic parameter") diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 518323f6526a6..f0c6e51f2a4c4 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{AttrArgs, AttrKind, Attribute}; +use rustc_hir::{AttrArgs, Attribute}; use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; @@ -622,7 +622,14 @@ impl<'tcx> OnUnimplementedDirective { item_def_id: DefId, ) -> Result, ErrorGuaranteed> { let result = if let Some(items) = attr.meta_item_list() { - Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant) + Self::parse( + tcx, + item_def_id, + &items, + attr.span(), + true, + is_diagnostic_namespace_variant, + ) } else if let Some(value) = attr.value_str() { if !is_diagnostic_namespace_variant { Ok(Some(OnUnimplementedDirective { @@ -633,7 +640,7 @@ impl<'tcx> OnUnimplementedDirective { tcx, item_def_id, value, - attr.span, + attr.span(), is_diagnostic_namespace_variant, )?), notes: Vec::new(), @@ -659,14 +666,14 @@ impl<'tcx> OnUnimplementedDirective { Ok(None) } } else if is_diagnostic_namespace_variant { - match &attr.kind { - AttrKind::Normal(p) if !matches!(p.args, AttrArgs::Empty) => { + match attr { + Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => { if let Some(item_def_id) = item_def_id.as_local() { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), - attr.span, - MalformedOnUnimplementedAttrLint::new(attr.span), + attr.span(), + MalformedOnUnimplementedAttrLint::new(attr.span()), ); } } @@ -675,7 +682,7 @@ impl<'tcx> OnUnimplementedDirective { tcx.emit_node_span_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, tcx.local_def_id_to_hir_id(item_def_id), - attr.span, + attr.span(), MissingOptionsForOnUnimplementedAttr, ) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 6eeb47a21f8dd..9383b82ff3cde 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -22,12 +22,11 @@ use rustc_hir::{ expr_needs_parens, is_range_literal, }; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk}; -use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::print::{ PrintPolyTraitPredicateExt as _, PrintPolyTraitRefExt, PrintTraitPredicateExt as _, - with_forced_trimmed_paths, with_no_trimmed_paths, + with_forced_trimmed_paths, with_no_trimmed_paths, with_types_for_suggestion, }; use rustc_middle::ty::{ self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder, @@ -93,7 +92,7 @@ impl<'a, 'tcx> CoroutineData<'a, 'tcx> { fn get_from_await_ty( &self, visitor: AwaitsVisitor, - hir: map::Map<'tcx>, + tcx: TyCtxt<'tcx>, ty_matches: F, ) -> Option where @@ -102,7 +101,7 @@ impl<'a, 'tcx> CoroutineData<'a, 'tcx> { visitor .awaits .into_iter() - .map(|id| hir.expect_expr(id)) + .map(|id| tcx.hir_expect_expr(id)) .find(|await_expr| ty_matches(ty::Binder::dummy(self.0.expr_ty_adjusted(await_expr)))) .map(|expr| expr.span) } @@ -111,7 +110,7 @@ impl<'a, 'tcx> CoroutineData<'a, 'tcx> { fn predicate_constraint(generics: &hir::Generics<'_>, pred: ty::Predicate<'_>) -> (Span, String) { ( generics.tail_span_for_predicate_suggestion(), - format!("{} {}", generics.add_where_or_trailing_comma(), pred), + with_types_for_suggestion!(format!("{} {}", generics.add_where_or_trailing_comma(), pred)), ) } @@ -136,7 +135,11 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( ) { if hir_generics.where_clause_span.from_expansion() || hir_generics.where_clause_span.desugaring_kind().is_some() - || projection.is_some_and(|projection| tcx.is_impl_trait_in_trait(projection.def_id)) + || projection.is_some_and(|projection| { + (tcx.is_impl_trait_in_trait(projection.def_id) + && !tcx.features().return_type_notation()) + || tcx.lookup_stability(projection.def_id).is_some_and(|stab| stab.is_unstable()) + }) { return; } @@ -974,7 +977,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { hir::ExprKind::MethodCall( hir::PathSegment { ident, .. }, _receiver, - &[], + [], call_span, ), hir_id, @@ -1995,7 +1998,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .iter() .enumerate() .map(|(i, ident)| { - if ident.name.is_empty() || ident.name == kw::SelfLower { + if ident.name.is_empty() + || ident.name == kw::Underscore + || ident.name == kw::SelfLower + { format!("arg{i}") } else { format!("{ident}") @@ -2177,8 +2183,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err: &mut Diag<'_, G>, obligation: &PredicateObligation<'tcx>, ) -> bool { - let hir = self.tcx.hir(); - // Attempt to detect an async-await error by looking at the obligation causes, looking // for a coroutine to be present. // @@ -2347,7 +2351,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut interior_or_upvar_span = None; - let from_awaited_ty = coroutine_data.get_from_await_ty(visitor, hir, ty_matches); + let from_awaited_ty = coroutine_data.get_from_await_ty(visitor, self.tcx, ty_matches); debug!(?from_awaited_ty); // Avoid disclosing internal information to downstream crates. @@ -2425,7 +2429,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Special case the primary error message when send or sync is the trait that was // not implemented. - let hir = self.tcx.hir(); let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) = self.tcx.get_diagnostic_name(trait_pred.def_id()) { @@ -2452,7 +2455,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .parent(coroutine_did) .as_local() .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id)) .map(|name| { format!("future returned by `{name}` is not {trait_name}") })?, @@ -2476,7 +2479,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .parent(coroutine_did) .as_local() .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id)) .map(|name| { format!("async iterator returned by `{name}` is not {trait_name}") })?, @@ -2499,7 +2502,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .parent(coroutine_did) .as_local() .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) + .and_then(|parent_hir_id| self.tcx.hir_opt_name(parent_hir_id)) .map(|name| { format!("iterator returned by `{name}` is not {trait_name}") })? @@ -2680,7 +2683,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression - | ObligationCauseCode::UnifyReceiver(..) | ObligationCauseCode::Misc | ObligationCauseCode::WellFormed(..) | ObligationCauseCode::MatchImpl(..) @@ -2693,7 +2695,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::LetElse | ObligationCauseCode::BinOp { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) - | ObligationCauseCode::DropImpl + | ObligationCauseCode::AlwaysApplicableImpl | ObligationCauseCode::ConstParam(_) | ObligationCauseCode::ReferenceOutlivesReferent(..) | ObligationCauseCode::ObjectTypeBound(..) => {} @@ -3124,8 +3126,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } - ObligationCauseCode::ConstSized => { - err.note("constant expressions must have a statically known size"); + ObligationCauseCode::SizedConstOrStatic => { + err.note("statics and constants must have a statically known size"); } ObligationCauseCode::InlineAsmSized => { err.note("all inline asm arguments must have a statically known size"); @@ -3189,7 +3191,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false }; - if !is_upvar_tys_infer_tuple { + let is_builtin_async_fn_trait = + tcx.async_fn_trait_kind_from_def_id(data.parent_trait_pred.def_id()).is_some(); + + if !is_upvar_tys_infer_tuple && !is_builtin_async_fn_trait { let ty_str = tcx.short_string(ty, err.long_ty_path()); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { @@ -3564,7 +3569,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ObligationCauseCode::OpaqueReturnType(expr_info) => { let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); - let expr = tcx.hir().expect_expr(hir_id); + let expr = tcx.hir_expect_expr(hir_id); (expr_ty, expr) } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() && let body = tcx.hir_body(body_id) @@ -4912,6 +4917,53 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); true } + pub(crate) fn suggest_swapping_lhs_and_rhs( + &self, + err: &mut Diag<'_>, + predicate: T, + param_env: ty::ParamEnv<'tcx>, + cause_code: &ObligationCauseCode<'tcx>, + ) where + T: Upcast, ty::Predicate<'tcx>>, + { + let tcx = self.tcx; + let predicate = predicate.upcast(tcx); + match *cause_code { + ObligationCauseCode::BinOp { + lhs_hir_id, + rhs_hir_id: Some(rhs_hir_id), + rhs_span: Some(rhs_span), + .. + } if let Some(typeck_results) = &self.typeck_results + && let hir::Node::Expr(lhs) = tcx.hir_node(lhs_hir_id) + && let hir::Node::Expr(rhs) = tcx.hir_node(rhs_hir_id) + && let Some(lhs_ty) = typeck_results.expr_ty_opt(lhs) + && let Some(rhs_ty) = typeck_results.expr_ty_opt(rhs) => + { + if let Some(pred) = predicate.as_trait_clause() + && tcx.is_lang_item(pred.def_id(), LangItem::PartialEq) + && self + .infcx + .type_implements_trait(pred.def_id(), [rhs_ty, lhs_ty], param_env) + .must_apply_modulo_regions() + { + let lhs_span = tcx.hir().span(lhs_hir_id); + let sm = tcx.sess.source_map(); + if let Ok(rhs_snippet) = sm.span_to_snippet(rhs_span) + && let Ok(lhs_snippet) = sm.span_to_snippet(lhs_span) + { + err.note(format!("`{rhs_ty}` implements `PartialEq<{lhs_ty}>`")); + err.multipart_suggestion( + "consider swapping the equality", + vec![(lhs_span, rhs_snippet), (rhs_span, lhs_snippet)], + Applicability::MaybeIncorrect, + ); + } + } + } + _ => {} + } + } } /// Add a hint to add a missing borrow or remove an unnecessary one. diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index e8d30d3ee7996..fe859eb53cd78 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -509,21 +509,18 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { let node = self.tcx.hir_node_by_def_id(anon_reg.scope); let is_impl = matches!(&node, hir::Node::ImplItem(_)); let (generics, parent_generics) = match node { - hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Fn { ref generics, .. }, - .. - }) - | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => ( + hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. }) + | hir::Node::TraitItem(hir::TraitItem { generics, .. }) + | hir::Node::ImplItem(hir::ImplItem { generics, .. }) => ( generics, match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope)) { hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ref generics, ..), + kind: hir::ItemKind::Trait(_, _, generics, ..), .. }) | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }), + kind: hir::ItemKind::Impl(hir::Impl { generics, .. }), .. }) => Some(generics), _ => None, @@ -787,10 +784,10 @@ pub enum TyOrSig<'tcx> { } impl IntoDiagArg for TyOrSig<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, path: &mut Option) -> rustc_errors::DiagArgValue { match self { - TyOrSig::Ty(ty) => ty.into_diag_arg(), - TyOrSig::ClosureSig(sig) => sig.into_diag_arg(), + TyOrSig::Ty(ty) => ty.into_diag_arg(path), + TyOrSig::ClosureSig(sig) => sig.into_diag_arg(path), } } } @@ -1119,22 +1116,6 @@ impl Subdiagnostic for ReqIntroducedLocations { } } -pub struct MoreTargeted { - pub ident: Symbol, -} - -impl Subdiagnostic for MoreTargeted { - fn add_to_diag_with>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.code(E0772); - diag.primary_message(fluent::trait_selection_more_targeted); - diag.arg("ident", self.ident); - } -} - #[derive(Diagnostic)] #[diag(trait_selection_but_needs_to_satisfy, code = E0759)] pub struct ButNeedsToSatisfy { @@ -1151,9 +1132,6 @@ pub struct ButNeedsToSatisfy { #[note(trait_selection_introduced_by_bound)] pub bound: Option, - #[subdiagnostic] - pub req_introduces_loc: Option, - pub has_param_name: bool, pub param_name: String, pub spans_empty: bool, diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index 4601ddf678a01..46622246a178d 100644 --- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -105,7 +105,7 @@ pub enum SuffixKind { } impl IntoDiagArg for PrefixKind { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { let kind = match self { Self::Empty => "empty", Self::RefValidFor => "ref_valid_for", @@ -127,7 +127,7 @@ impl IntoDiagArg for PrefixKind { } impl IntoDiagArg for SuffixKind { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + fn into_diag_arg(self, _: &mut Option) -> rustc_errors::DiagArgValue { let kind = match self { Self::Empty => "empty", Self::Continues => "continues", diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index f373706b2960c..5cf0600ade8b4 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -53,6 +53,16 @@ impl<'tcx> InferCtxt<'tcx> { traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, clone_def_id) } + fn type_is_use_cloned_modulo_regions( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + let ty = self.resolve_vars_if_possible(ty); + let use_cloned_def_id = self.tcx.require_lang_item(LangItem::UseCloned, None); + traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, use_cloned_def_id) + } + fn type_is_sized_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, lang_item) diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 1af383e9200d0..b18fb0fb8fd31 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -20,7 +20,6 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(cfg_version)] -#![feature(extract_if)] #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(iterator_try_reduce)] @@ -32,7 +31,6 @@ #![feature(unwrap_infallible)] #![feature(yeet_expr)] #![recursion_limit = "512"] // For rustdoc -#![warn(unreachable_pub)] // For rustdoc // tidy-alphabetical-end pub mod error_reporting; diff --git a/compiler/rustc_trait_selection/src/regions.rs b/compiler/rustc_trait_selection/src/regions.rs index 5517175461876..068e90b00b8d1 100644 --- a/compiler/rustc_trait_selection/src/regions.rs +++ b/compiler/rustc_trait_selection/src/regions.rs @@ -17,13 +17,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { param_env: ty::ParamEnv<'tcx>, assumed_wf_tys: impl IntoIterator>, ) -> Self { - Self::new_with_implied_bounds_compat( - infcx, - body_id, - param_env, - assumed_wf_tys, - !infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat, - ) + Self::new_with_implied_bounds_compat(infcx, body_id, param_env, assumed_wf_tys, false) } fn new_with_implied_bounds_compat( @@ -31,7 +25,7 @@ impl<'tcx> OutlivesEnvironment<'tcx> { body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, assumed_wf_tys: impl IntoIterator>, - implied_bounds_compat: bool, + disable_implied_bounds_hack: bool, ) -> Self { let mut bounds = vec![]; @@ -59,11 +53,11 @@ impl<'tcx> OutlivesEnvironment<'tcx> { OutlivesEnvironment::from_normalized_bounds( param_env, bounds, - infcx.implied_bounds_tys_with_compat( + infcx.implied_bounds_tys( body_id, param_env, assumed_wf_tys, - implied_bounds_compat, + disable_implied_bounds_hack, ), ) } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 58d8a3a62547e..af5a60027ba4a 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -7,10 +7,8 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues, }; use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt}; -use rustc_infer::traits::ObligationCause; use rustc_infer::traits::solve::Goal; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _}; +use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _}; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; use rustc_type_ir::TypingMode; use rustc_type_ir::solve::{Certainty, NoSolution}; @@ -222,7 +220,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // register candidates. We probably need to register >1 since we may have an OR of ANDs. fn is_transmutable( &self, - param_env: ty::ParamEnv<'tcx>, dst: Ty<'tcx>, src: Ty<'tcx>, assume: ty::Const<'tcx>, @@ -231,16 +228,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< // which will ICE for region vars. let (dst, src) = self.tcx.erase_regions((dst, src)); - let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else { + let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else { return Err(NoSolution); }; // FIXME(transmutability): This really should be returning nested goals for `Answer::If*` - match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable( - ObligationCause::dummy(), - rustc_transmute::Types { src, dst }, - assume, - ) { + match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx) + .is_transmutable(rustc_transmute::Types { src, dst }, assume) + { rustc_transmute::Answer::Yes => Ok(Certainty::Yes), rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution), } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index c238e708ab8fa..704ba6e501d8c 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -67,7 +67,7 @@ impl<'tcx> ObligationStorage<'tcx> { obligations } - fn unstalled_for_select(&mut self) -> impl Iterator> { + fn unstalled_for_select(&mut self) -> impl Iterator> + 'tcx { mem::take(&mut self.pending).into_iter() } diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs index 982782bc57c18..352ac7c1a4e6f 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs @@ -438,7 +438,10 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { let obligation; match (child_mode, nested_goal.source()) { - (ChildMode::Trait(_) | ChildMode::Host(_), GoalSource::Misc) => { + ( + ChildMode::Trait(_) | ChildMode::Host(_), + GoalSource::Misc | GoalSource::TypeRelating | GoalSource::NormalizeGoal(_), + ) => { continue; } (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => { diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index 4b1bc316d5f1d..48a05ad29fbd9 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -15,8 +15,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; -use rustc_middle::ty::visit::{VisitorResult, try_visit}; -use rustc_middle::ty::{TyCtxt, TypeFoldable}; +use rustc_middle::ty::{TyCtxt, TypeFoldable, VisitorResult, try_visit}; use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::EagerResolver; use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 3b40882ef572d..4c7172c32781a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -17,8 +17,9 @@ use rustc_middle::traits::query::NoSolution; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, +}; pub use rustc_next_trait_solver::coherence::*; use rustc_next_trait_solver::solve::SolverDelegateEvalExt; use rustc_span::{DUMMY_SP, Span, sym}; diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index bdee6ca2afe54..39333082acdff 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -2,7 +2,7 @@ //! //! For concrete constants, this is fairly simple as we can just try and evaluate it. //! -//! When dealing with polymorphic constants, for example `std::mem::size_of::() - 1`, +//! When dealing with polymorphic constants, for example `size_of::() - 1`, //! this is not as easy. //! //! In this case we try to build an abstract representation of this constant using @@ -85,6 +85,12 @@ pub fn is_const_evaluatable<'tcx>( } _ => bug!("unexpected constkind in `is_const_evalautable: {unexpanded_ct:?}`"), } + } else if tcx.features().min_generic_const_args() { + // This is a sanity check to make sure that non-generics consts are checked to + // be evaluatable in case they aren't cchecked elsewhere. This will NOT error + // if the const uses generics, as desired. + crate::traits::evaluate_const(infcx, unexpanded_ct, param_env); + Ok(()) } else { let uv = match unexpanded_ct.kind() { ty::ConstKind::Unevaluated(uv) => uv, diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index efe2386d014b3..3fceada251049 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -24,7 +24,9 @@ use super::elaborate; use crate::infer::TyCtxtInferExt; pub use crate::traits::DynCompatibilityViolation; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::{MethodViolationCode, Obligation, ObligationCause, util}; +use crate::traits::{ + MethodViolationCode, Obligation, ObligationCause, normalize_param_env_or_error, util, +}; /// Returns the dyn-compatibility violations that affect HIR ty lowering. /// @@ -538,10 +540,10 @@ fn receiver_for_self_ty<'tcx>( /// a pointer. /// /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in -/// a new check that `Trait` is dyn-compatible, creating a cycle (until dyn_compatible_for_dispatch -/// is stabilized, see tracking issue ). -/// Instead, we fudge a little by introducing a new type parameter `U` such that +/// a new check that `Trait` is dyn-compatible, creating a cycle. +/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that /// `Self: Unsize` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. +/// /// Written as a chalk-style query: /// ```ignore (not-rust) /// forall (U: Trait + ?Sized) { @@ -572,8 +574,6 @@ fn receiver_is_dispatchable<'tcx>( // the type `U` in the query // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now. - // FIXME(mikeyhew) this is a total hack. Once dyn_compatible_for_dispatch is stabilized, we can - // replace this with `dyn Trait` let unsized_self_ty: Ty<'tcx> = Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome); @@ -581,8 +581,8 @@ fn receiver_is_dispatchable<'tcx>( let unsized_receiver_ty = receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id); - // create a modified param env, with `Self: Unsize` and `U: Trait` added to caller bounds - // `U: ?Sized` is already implied here + // create a modified param env, with `Self: Unsize` and `U: Trait` (and all of + // its supertraits) added to caller bounds. `U: ?Sized` is already implied here. let param_env = { let param_env = tcx.param_env(method.def_id); @@ -600,10 +600,13 @@ fn receiver_is_dispatchable<'tcx>( ty::TraitRef::new_from_args(tcx, trait_def_id, args).upcast(tcx) }; - let caller_bounds = - param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]); - - ty::ParamEnv::new(tcx.mk_clauses_from_iter(caller_bounds)) + normalize_param_env_or_error( + tcx, + ty::ParamEnv::new(tcx.mk_clauses_from_iter( + param_env.caller_bounds().iter().chain([unsize_predicate, trait_predicate]), + )), + ObligationCause::dummy_with_span(tcx.def_span(method.def_id)), + ) }; // Receiver: DispatchFromDyn U]> @@ -698,11 +701,11 @@ impl<'tcx> TypeVisitor> for IllegalSelfTypeVisitor<'tcx> { ControlFlow::Continue(()) } } - ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => { + ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => { // We'll deny these later in their own pass ControlFlow::Continue(()) } - ty::Alias(ty::Projection, ref data) => { + ty::Alias(ty::Projection, data) => { match self.allow_self_projections { AllowSelfProjections::Yes => { // This is a projected type `::X`. diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index b32909efe0be7..3c127416cbf7c 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -31,6 +31,8 @@ pub fn evaluate_host_effect_obligation<'tcx>( ); } + let ref obligation = selcx.infcx.resolve_vars_if_possible(obligation.clone()); + // Force ambiguity for infer self ty. if obligation.predicate.self_ty().is_ty_var() { return Err(EvaluationFailure::Ambiguous); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index f2d2dd2f3ce59..e39f8e673dbac 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,6 +1,5 @@ use std::marker::PhantomData; -use rustc_data_structures::captures::Captures; use rustc_data_structures::obligation_forest::{ Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult, }; @@ -900,10 +899,10 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> { } /// Returns the set of inference variables contained in `args`. -fn args_infer_vars<'a, 'tcx>( - selcx: &SelectionContext<'a, 'tcx>, +fn args_infer_vars<'tcx>( + selcx: &SelectionContext<'_, 'tcx>, args: ty::Binder<'tcx, GenericArgsRef<'tcx>>, -) -> impl Iterator + Captures<'tcx> { +) -> impl Iterator { selcx .infcx .resolve_vars_if_possible(args) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 105cb9175717d..de337710b5ef7 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -32,11 +32,9 @@ pub use rustc_infer::traits::*; use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFolder, TypeSuperFoldable, - TypeSuperVisitable, TypingMode, Upcast, + self, GenericArgs, GenericArgsRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypingMode, Upcast, }; use rustc_span::def_id::DefId; use rustc_span::{DUMMY_SP, Span}; diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 189326958078d..68983ef80fa48 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -36,7 +36,7 @@ fn implied_outlives_bounds<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, body_id: LocalDefId, ty: Ty<'tcx>, - compat: bool, + disable_implied_bounds_hack: bool, ) -> Vec> { let ty = infcx.resolve_vars_if_possible(ty); let ty = OpportunisticRegionResolver::new(infcx).fold_ty(ty); @@ -52,11 +52,8 @@ fn implied_outlives_bounds<'a, 'tcx>( let mut canonical_var_values = OriginalQueryValues::default(); let input = ImpliedOutlivesBounds { ty }; let canonical = infcx.canonicalize_query(param_env.and(input), &mut canonical_var_values); - let implied_bounds_result = if compat { - infcx.tcx.implied_outlives_bounds_compat(canonical) - } else { - infcx.tcx.implied_outlives_bounds(canonical) - }; + let implied_bounds_result = + infcx.tcx.implied_outlives_bounds((canonical, disable_implied_bounds_hack)); let Ok(canonical_result) = implied_bounds_result else { return vec![]; }; @@ -110,14 +107,15 @@ fn implied_outlives_bounds<'a, 'tcx>( impl<'tcx> InferCtxt<'tcx> { /// Do *NOT* call this directly. You probably want to construct a `OutlivesEnvironment` /// instead if you're interested in the implied bounds for a given signature. - fn implied_bounds_tys_with_compat>>( + fn implied_bounds_tys>>( &self, body_id: LocalDefId, param_env: ParamEnv<'tcx>, tys: Tys, - compat: bool, + disable_implied_bounds_hack: bool, ) -> impl Iterator> { - tys.into_iter() - .flat_map(move |ty| implied_outlives_bounds(self, param_env, body_id, ty, compat)) + tys.into_iter().flat_map(move |ty| { + implied_outlives_bounds(self, param_env, body_id, ty, disable_implied_bounds_hack) + }) } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index de5aaa5bd9729..be5d6286e2604 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -13,9 +13,9 @@ use rustc_infer::traits::{ObligationCauseCode, PredicateObligations}; use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ImplSourceUserDefinedData}; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::visit::TypeVisitableExt; -use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast}; +use rustc_middle::ty::{ + self, Term, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, TypingMode, Upcast, +}; use rustc_middle::{bug, span_bug}; use rustc_span::sym; use rustc_type_ir::elaborate; @@ -1232,8 +1232,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // why we special case object types. false } - ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) - | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { + ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => { // These traits have no associated types. selcx.tcx().dcx().span_delayed_bug( obligation.cause.span, @@ -1325,8 +1324,7 @@ fn confirm_select_candidate<'cx, 'tcx>( } ImplSource::Builtin(BuiltinImplSource::Object { .. }, _) | ImplSource::Param(..) - | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) - | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => { + | ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => { // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 2ef9d5421ba6c..165c63f3745a2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -7,9 +7,10 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::traits::PredicateObligations; use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; -use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable}; -use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor, TypingMode}; +use rustc_middle::ty::{ + self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, + TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, +}; use rustc_span::DUMMY_SP; use tracing::{debug, info, instrument}; @@ -31,20 +32,19 @@ impl<'a, 'tcx> At<'a, 'tcx> { /// normalized. If you don't care about regions, you should prefer /// `normalize_erasing_regions`, which is more efficient. /// - /// If the normalization succeeds and is unambiguous, returns back - /// the normalized value along with various outlives relations (in - /// the form of obligations that must be discharged). - /// - /// N.B., this will *eventually* be the main means of - /// normalizing, but for now should be used only when we actually - /// know that normalization will succeed, since error reporting - /// and other details are still "under development". + /// If the normalization succeeds, returns back the normalized + /// value along with various outlives relations (in the form of + /// obligations that must be discharged). /// - /// This normalization should *only* be used when the projection does not - /// have possible ambiguity or may not be well-formed. + /// This normalization should *only* be used when the projection is well-formed and + /// does not have possible ambiguity (contains inference variables). /// /// After codegen, when lifetimes do not matter, it is preferable to instead /// use [`TyCtxt::normalize_erasing_regions`], which wraps this procedure. + /// + /// N.B. Once the new solver is stabilized this method of normalization will + /// likely be removed as trait solver operations are already cached by the query + /// system making this redundant. fn query_normalize(self, value: T) -> Result, NoSolution> where T: TypeFoldable>, @@ -210,8 +210,6 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { // See note in `rustc_trait_selection::traits::project` about why we // wait to fold the args. - - // Wrap this in a closure so we don't accidentally return from the outer function let res = match kind { ty::Opaque => { // Only normalize `impl Trait` outside of type inference, usually in codegen. diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index ec0b790339691..f98529860ff81 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -1,15 +1,16 @@ +use std::ops::ControlFlow; + +use rustc_infer::infer::RegionObligation; use rustc_infer::infer::canonical::CanonicalQueryInput; -use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::query::OutlivesBound; use rustc_infer::traits::query::type_op::ImpliedOutlivesBounds; use rustc_middle::infer::canonical::CanonicalQueryResponse; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFolder, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitable, TypeVisitor}; use rustc_span::def_id::CRATE_DEF_ID; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, sym}; use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::{SmallVec, smallvec}; -use tracing::debug; use crate::traits::query::NoSolution; use crate::traits::{ObligationCtxt, wf}; @@ -35,11 +36,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { tcx: TyCtxt<'tcx>, canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>, ) -> Result, NoSolution> { - if tcx.sess.opts.unstable_opts.no_implied_bounds_compat { - tcx.implied_outlives_bounds(canonicalized) - } else { - tcx.implied_outlives_bounds_compat(canonicalized) - } + tcx.implied_outlives_bounds((canonicalized, false)) } fn perform_locally_with_next_solver( @@ -47,11 +44,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { key: ParamEnvAnd<'tcx, Self>, span: Span, ) -> Result { - if ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat { - compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span) - } else { - compute_implied_outlives_bounds_compat_inner(ocx, key.param_env, key.value.ty, span) - } + compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty, span, false) } } @@ -60,18 +53,15 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, span: Span, + disable_implied_bounds_hack: bool, ) -> Result>, NoSolution> { - let normalize_op = |ty| -> Result<_, NoSolution> { + let normalize_ty = |ty| -> Result<_, NoSolution> { // We must normalize the type so we can compute the right outlives components. // for example, if we have some constrained param type like `T: Trait`, // and we know that `&'a T::Out` is WF, then we want to imply `U: 'a`. let ty = ocx .deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty) .map_err(|_| NoSolution)?; - if !ocx.select_all_or_error().is_empty() { - return Err(NoSolution); - } - let ty = OpportunisticRegionResolver::new(&ocx.infcx).fold_ty(ty); Ok(ty) }; @@ -81,7 +71,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( // guaranteed to be a subset of the original type, so we need to store the // WF args we've computed in a set. let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); - let mut wf_args = vec![ty.into(), normalize_op(ty)?.into()]; + let mut wf_args = vec![ty.into(), normalize_ty(ty)?.into()]; let mut outlives_bounds: Vec> = vec![]; @@ -96,8 +86,14 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( .into_iter() .flatten() { - assert!(!obligation.has_escaping_bound_vars()); - let Some(pred) = obligation.predicate.kind().no_bound_vars() else { + let pred = ocx + .deeply_normalize( + &ObligationCause::dummy_with_span(span), + param_env, + obligation.predicate, + ) + .map_err(|_| NoSolution)?; + let Some(pred) = pred.kind().no_bound_vars() else { continue; }; match pred { @@ -130,7 +126,6 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( ty_a, r_b, ))) => { - let ty_a = normalize_op(ty_a)?; let mut components = smallvec![]; push_outlives_components(ocx.infcx.tcx, ty_a, &mut components); outlives_bounds.extend(implied_bounds_from_components(r_b, components)) @@ -139,141 +134,48 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( } } - Ok(outlives_bounds) -} - -pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( - ocx: &ObligationCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, -) -> Result>, NoSolution> { - let tcx = ocx.infcx.tcx; - - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Because the resulting predicates aren't always - // guaranteed to be a subset of the original type, so we need to store the - // WF args we've computed in a set. - let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default(); - let mut wf_args = vec![ty.into()]; - - let mut outlives_bounds: Vec>> = vec![]; - - while let Some(arg) = wf_args.pop() { - if !checked_wf_args.insert(arg) { - continue; + // If we detect `bevy_ecs::*::ParamSet` in the WF args list (and `disable_implied_bounds_hack` + // or `-Zno-implied-bounds-compat` are not set), then use the registered outlives obligations + // as implied bounds. + if !disable_implied_bounds_hack + && !ocx.infcx.tcx.sess.opts.unstable_opts.no_implied_bounds_compat + && ty.visit_with(&mut ContainsBevyParamSet { tcx: ocx.infcx.tcx }).is_break() + { + for RegionObligation { sup_type, sub_region, .. } in + ocx.infcx.take_registered_region_obligations() + { + let mut components = smallvec![]; + push_outlives_components(ocx.infcx.tcx, sup_type, &mut components); + outlives_bounds.extend(implied_bounds_from_components(sub_region, components)); } + } - // Compute the obligations for `arg` to be well-formed. If `arg` is - // an unresolved inference variable, just instantiated an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - // - // FIXME(@lcnr): It's not really "always fine", having fewer implied - // bounds can be backward incompatible, e.g. #101951 was caused by - // us not dealing with inference vars in `TypeOutlives` predicates. - let obligations = - wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, span).unwrap_or_default(); + Ok(outlives_bounds) +} - for obligation in obligations { - debug!(?obligation); - assert!(!obligation.has_escaping_bound_vars()); +struct ContainsBevyParamSet<'tcx> { + tcx: TyCtxt<'tcx>, +} - // While these predicates should all be implied by other parts of - // the program, they are still relevant as they may constrain - // inference variables, which is necessary to add the correct - // implied bounds in some cases, mostly when dealing with projections. - // - // Another important point here: we only register `Projection` - // predicates, since otherwise we might register outlives - // predicates containing inference variables, and we don't - // learn anything new from those. - if obligation.predicate.has_non_region_infer() { - match obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::AliasRelate(..) => { - ocx.register_obligation(obligation.clone()); - } - _ => {} - } - } +impl<'tcx> TypeVisitor> for ContainsBevyParamSet<'tcx> { + type Result = ControlFlow<()>; - let pred = match obligation.predicate.kind().no_bound_vars() { - None => continue, - Some(pred) => pred, - }; - match pred { - // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound - // if we ever support that - ty::PredicateKind::Clause(ty::ClauseKind::Trait(..)) - | ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) - | ty::PredicateKind::Subtype(..) - | ty::PredicateKind::Coerce(..) - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::DynCompatible(..) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::Ambiguous - | ty::PredicateKind::NormalizesTo(..) - | ty::PredicateKind::AliasRelate(..) => {} - - // We need to search through *all* WellFormed predicates - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { - wf_args.push(arg); + fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { + // We only care to match `ParamSet` or `&ParamSet`. + match t.kind() { + ty::Adt(def, _) => { + if self.tcx.item_name(def.did()) == sym::ParamSet + && self.tcx.crate_name(def.did().krate) == sym::bevy_ecs + { + return ControlFlow::Break(()); } - - // We need to register region relationships - ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives( - ty::OutlivesPredicate(r_a, r_b), - )) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)), - - ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate( - ty_a, - r_b, - ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)), } + ty::Ref(_, ty, _) => ty.visit_with(self)?, + _ => {} } - } - // This call to `select_all_or_error` is necessary to constrain inference variables, which we - // use further down when computing the implied bounds. - match ocx.select_all_or_error().as_slice() { - [] => (), - _ => return Err(NoSolution), + ControlFlow::Continue(()) } - - // We lazily compute the outlives components as - // `select_all_or_error` constrains inference variables. - let mut implied_bounds = Vec::new(); - for ty::OutlivesPredicate(a, r_b) in outlives_bounds { - match a.unpack() { - ty::GenericArgKind::Lifetime(r_a) => { - implied_bounds.push(OutlivesBound::RegionSubRegion(r_b, r_a)) - } - ty::GenericArgKind::Type(ty_a) => { - let mut ty_a = ocx.infcx.resolve_vars_if_possible(ty_a); - // Need to manually normalize in the new solver as `wf::obligations` does not. - if ocx.infcx.next_trait_solver() { - ty_a = ocx - .deeply_normalize(&ObligationCause::dummy_with_span(span), param_env, ty_a) - .map_err(|_| NoSolution)?; - } - let mut components = smallvec![]; - push_outlives_components(tcx, ty_a, &mut components); - implied_bounds.extend(implied_bounds_from_components(r_b, components)) - } - ty::GenericArgKind::Const(_) => { - unreachable!("consts do not participate in outlives bounds") - } - } - } - - Ok(implied_bounds) } /// When we have an implied bound that `T: 'a`, we can further break diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 68feb19c55b89..4bdf04311a04f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -3,8 +3,7 @@ use std::fmt; use rustc_errors::ErrorGuaranteed; use rustc_infer::traits::PredicateObligations; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; +use rustc_middle::ty::{ParamEnvAnd, TyCtxt, TypeFoldable}; use rustc_span::Span; use crate::infer::canonical::{ 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 2f6bbd7f4cf48..f2a6ce855b49d 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 @@ -3,8 +3,7 @@ use std::fmt; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::query::NoSolution; pub use rustc_middle::traits::query::type_op::{DeeplyNormalize, Normalize}; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::Span; use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse}; diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 5b362b2356e82..a8d8003ead6ea 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -859,13 +859,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().dyn_compatible_for_dispatch() { - principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_dyn_compatible(principal.def_id()) { - principal.with_self_ty(self.tcx(), self_ty) - } else { - return; - } + principal.with_self_ty(self.tcx(), self_ty) } else { // Only auto trait bounds exist. return; @@ -1023,13 +1017,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { - if tys_a.len() == tys_b.len() { - candidates.vec.push(BuiltinUnsizeCandidate); - } - } - _ => {} }; } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 32cbb97e314d6..4cd6781ab8905 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -7,7 +7,6 @@ //! [rustc dev guide]: //! https://rustc-dev-guide.rust-lang.org/traits/resolution.html#confirmation -use std::iter; use std::ops::ControlFlow; use rustc_ast::Mutability; @@ -410,13 +409,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = obligation.predicate.skip_binder(); let mut assume = predicate.trait_ref.args.const_at(2); - // FIXME(min_generic_const_exprs): We should shallowly normalize this. + // FIXME(mgca): We should shallowly normalize this. if self.tcx().features().generic_const_exprs() { assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) } - let Some(assume) = - rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume) - else { + let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else { return Err(Unimplemented); }; @@ -424,12 +421,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let src = predicate.trait_ref.args.type_at(1); debug!(?src, ?dst); - let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx); - let maybe_transmutable = transmute_env.is_transmutable( - obligation.cause.clone(), - rustc_transmute::Types { dst, src }, - assume, - ); + let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx); + let maybe_transmutable = + transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume); let fully_flattened = match maybe_transmutable { Answer::No(_) => Err(Unimplemented)?, @@ -469,18 +463,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive); - let trait_ref = - self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref; - let trait_obligations = self.impl_or_trait_obligations( - &cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - trait_ref.args, - obligation.predicate, - ); - let mut obligations = self.collect_predicates_for_types( + let obligations = self.collect_predicates_for_types( obligation.param_env, cause, obligation.recursion_depth + 1, @@ -488,10 +472,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested, ); - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); - debug!(?obligations, "vtable_auto_impl"); obligations @@ -989,8 +969,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(SelectionError::Unimplemented); } } else { - nested.push(obligation.with( + nested.push(Obligation::new( self.tcx(), + obligation.derived_cause(ObligationCauseCode::BuiltinDerived), + obligation.param_env, ty::TraitRef::new( self.tcx(), self.tcx().require_lang_item( @@ -1320,34 +1302,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, nested) } - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { - assert_eq!(tys_a.len(), tys_b.len()); - - // The last field of the tuple has to exist. - let (&a_last, a_mid) = tys_a.split_last().ok_or(Unimplemented)?; - let &b_last = tys_b.last().unwrap(); - - // Check that the source tuple with the target's - // last element is equal to the target. - let new_tuple = - Ty::new_tup_from_iter(tcx, a_mid.iter().copied().chain(iter::once(b_last))); - let InferOk { mut obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::Yes, target, new_tuple) - .map_err(|_| Unimplemented)?; - - // Add a nested `T: Unsize` predicate. - let last_unsize_obligation = obligation.with( - tcx, - ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]), - ); - obligations.push(last_unsize_obligation); - - ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, obligations) - } - _ => bug!("source: {source}, target: {target}"), }) } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 436ce3dddd9f0..e1adabbeaa662 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -9,7 +9,7 @@ use std::ops::ControlFlow; use std::{cmp, iter}; use hir::def::DefKind; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{Diag, EmissionGuarantee}; use rustc_hir as hir; @@ -25,7 +25,6 @@ use rustc_middle::dep_graph::{DepNodeIndex, dep_kinds}; pub use rustc_middle::traits::select::*; use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::TypeErrorToStringExt; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{ self, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, @@ -1008,7 +1007,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // depend on its particular value in order to work, so we can clear // out the param env and get better caching. debug!("in global"); - obligation.param_env = obligation.param_env.without_caller_bounds(); + obligation.param_env = ty::ParamEnv::empty(); } let stack = self.push_stack(previous_stack, &obligation); @@ -1225,15 +1224,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// that recursion is ok. This routine returns `true` if the top of the /// stack (`cycle[0]`): /// - /// - is a defaulted trait, + /// - is a coinductive trait: an auto-trait or `Sized`, /// - it also appears in the backtrace at some position `X`, /// - all the predicates at positions `X..` between `X` and the top are - /// also defaulted traits. + /// also coinductive traits. pub(crate) fn coinductive_match(&mut self, mut cycle: I) -> bool where I: Iterator>, { - cycle.all(|predicate| predicate.is_coinductive(self.tcx())) + cycle.all(|p| match p.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { + self.infcx.tcx.trait_is_coinductive(data.def_id()) + } + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => true, + _ => false, + }) } /// Further evaluates `candidate` to decide whether all type parameters match and whether nested @@ -1920,9 +1925,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let mut impl_candidate = None; for c in impls { if let Some(prev) = impl_candidate.replace(c) { - if self.prefer_lhs_over_victim(has_non_region_infer, c, prev) { + if self.prefer_lhs_over_victim(has_non_region_infer, c, prev.0) { // Ok, prefer `c` over the previous entry - } else if self.prefer_lhs_over_victim(has_non_region_infer, prev, c) { + } else if self.prefer_lhs_over_victim(has_non_region_infer, prev, c.0) { // Ok, keep `prev` instead of the new entry impl_candidate = Some(prev); } else { @@ -1981,7 +1986,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { &self, has_non_region_infer: bool, (lhs, lhs_evaluation): (DefId, EvaluationResult), - (victim, victim_evaluation): (DefId, EvaluationResult), + victim: DefId, ) -> bool { let tcx = self.tcx(); // See if we can toss out `victim` based on specialization. @@ -1997,14 +2002,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } match tcx.impls_are_allowed_to_overlap(lhs, victim) { - // For #33140 the impl headers must be exactly equal, the trait must not have - // any associated items and there are no where-clauses. - // - // We can just arbitrarily drop one of the impls. - Some(ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects) => { - assert_eq!(lhs_evaluation, victim_evaluation); - true - } // For candidates which already reference errors it doesn't really // matter what we do 🤷 Some(ty::ImplOverlapKind::Permitted { marker: false }) => { @@ -2199,8 +2196,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::CoroutineWitness(def_id, args) => { - let hidden_types = bind_coroutine_hidden_types_above( - self.infcx, + let hidden_types = rebind_coroutine_witness_types( + self.infcx.tcx, def_id, args, obligation.predicate.bound_vars(), @@ -2234,15 +2231,6 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } - // `Copy` and `Clone` are automatically implemented for an anonymous adt - // if all of its fields are `Copy` and `Clone` - ty::Adt(adt, args) if adt.is_anonymous() => { - // (*) binder moved here - Where(obligation.predicate.rebind( - adt.non_enum_variant().fields.iter().map(|f| f.ty(self.tcx(), args)).collect(), - )) - } - ty::Adt(..) | ty::Alias(..) | ty::Param(..) | ty::Placeholder(..) => { // Fallback to whatever user-defined impls exist in this case. None @@ -2348,7 +2336,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } ty::CoroutineWitness(def_id, args) => { - bind_coroutine_hidden_types_above(self.infcx, def_id, args, t.bound_vars()) + rebind_coroutine_witness_types(self.infcx.tcx, def_id, args, t.bound_vars()) } // For `PhantomData`, we pass `T`. @@ -2843,6 +2831,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } } +fn rebind_coroutine_witness_types<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + args: ty::GenericArgsRef<'tcx>, + bound_vars: &'tcx ty::List, +) -> ty::Binder<'tcx, Vec>> { + let bound_coroutine_types = tcx.coroutine_hidden_types(def_id).skip_binder(); + let shifted_coroutine_types = + tcx.shift_bound_var_indices(bound_vars.len(), bound_coroutine_types.skip_binder()); + ty::Binder::bind_with_vars( + ty::EarlyBinder::bind(shifted_coroutine_types.to_vec()).instantiate(tcx, args), + tcx.mk_bound_variable_kinds_from_iter( + bound_vars.iter().chain(bound_coroutine_types.bound_vars()), + ), + ) +} + impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { TraitObligationStackList::with(self) @@ -3151,56 +3156,3 @@ pub(crate) enum ProjectionMatchesProjection { Ambiguous, No, } - -/// Replace all regions inside the coroutine interior with late bound regions. -/// Note that each region slot in the types gets a new fresh late bound region, which means that -/// none of the regions inside relate to any other, even if typeck had previously found constraints -/// that would cause them to be related. -#[instrument(level = "trace", skip(infcx), ret)] -fn bind_coroutine_hidden_types_above<'tcx>( - infcx: &InferCtxt<'tcx>, - def_id: DefId, - args: ty::GenericArgsRef<'tcx>, - bound_vars: &ty::List, -) -> ty::Binder<'tcx, Vec>> { - let tcx = infcx.tcx; - let mut seen_tys = FxHashSet::default(); - - let considering_regions = infcx.considering_regions; - - let num_bound_variables = bound_vars.len() as u32; - let mut counter = num_bound_variables; - - let hidden_types: Vec<_> = tcx - .coroutine_hidden_types(def_id) - // Deduplicate tys to avoid repeated work. - .filter(|bty| seen_tys.insert(*bty)) - .map(|mut bty| { - // Only remap erased regions if we use them. - if considering_regions { - bty = bty.map_bound(|ty| { - fold_regions(tcx, ty, |r, current_depth| match r.kind() { - ty::ReErased => { - let br = ty::BoundRegion { - var: ty::BoundVar::from_u32(counter), - kind: ty::BoundRegionKind::Anon, - }; - counter += 1; - ty::Region::new_bound(tcx, current_depth, br) - } - r => bug!("unexpected region: {r:?}"), - }) - }) - } - - bty.instantiate(tcx, args) - }) - .collect(); - let bound_vars = tcx.mk_bound_variable_kinds_from_iter( - bound_vars.iter().chain( - (num_bound_variables..counter) - .map(|_| ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)), - ), - ); - ty::Binder::bind_with_vars(hidden_types, bound_vars) -} diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index cb3e81f5477fc..448ac558cad7f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -20,7 +20,7 @@ use rustc_middle::bug; use rustc_middle::query::LocalCrate; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; -use rustc_session::lint::builtin::{COHERENCE_LEAK_CHECK, ORDER_DEPENDENT_TRAIT_OBJECTS}; +use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, sym}; use rustc_type_ir::solve::NoSolution; use specialization_graph::GraphExt; @@ -557,13 +557,9 @@ fn report_conflicting_impls<'tcx>( let msg = || { format!( - "conflicting implementations of trait `{}`{}{}", + "conflicting implementations of trait `{}`{}", overlap.trait_ref.print_trait_sugared(), overlap.self_ty.map_or_else(String::new, |ty| format!(" for type `{ty}`")), - match used_to_be_allowed { - Some(FutureCompatOverlapErrorKind::OrderDepTraitObjects) => ": (E0119)", - _ => "", - } ) }; @@ -588,7 +584,6 @@ fn report_conflicting_impls<'tcx>( } Some(kind) => { let lint = match kind { - FutureCompatOverlapErrorKind::OrderDepTraitObjects => ORDER_DEPENDENT_TRAIT_OBJECTS, FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, }; tcx.node_span_lint(lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, |err| { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index f39c611d19fe0..9452dca9a4f0f 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -12,7 +12,6 @@ use crate::traits; #[derive(Copy, Clone, Debug)] pub enum FutureCompatOverlapErrorKind { - OrderDepTraitObjects, LeakCheck, } @@ -151,12 +150,6 @@ impl<'tcx> Children { { match overlap_kind { ty::ImplOverlapKind::Permitted { marker: _ } => {} - ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects => { - *last_lint_mut = Some(FutureCompatOverlapError { - error: create_overlap_error(overlap), - kind: FutureCompatOverlapErrorKind::OrderDepTraitObjects, - }); - } } return Ok((false, false)); @@ -200,15 +193,12 @@ impl<'tcx> Children { } } -fn iter_children(children: &Children) -> impl Iterator + '_ { +fn iter_children(children: &Children) -> impl Iterator { let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter()); children.blanket_impls.iter().chain(nonblanket).cloned() } -fn filtered_children( - children: &mut Children, - st: SimplifiedType, -) -> impl Iterator + '_ { +fn filtered_children(children: &mut Children, st: SimplifiedType) -> impl Iterator { let nonblanket = children.non_blanket_impls.entry(st).or_default().iter(); children.blanket_impls.iter().chain(nonblanket).cloned() } diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index 0024316b877c5..165174c0bcc15 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -196,7 +196,7 @@ fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[Def fn own_existential_vtable_entries_iter( tcx: TyCtxt<'_>, trait_def_id: DefId, -) -> impl Iterator + '_ { +) -> impl Iterator { let trait_methods = tcx .associated_items(trait_def_id) .in_definition_order() diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 7f3e3ce47816c..54b6c22b2d821 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -708,7 +708,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { ty::Pat(subty, pat) => { self.require_sized(subty, ObligationCauseCode::Misc); match *pat { - ty::PatternKind::Range { start, end, include_end: _ } => { + ty::PatternKind::Range { start, end } => { let mut check = |c| { let cause = self.cause(ObligationCauseCode::Misc); self.out.push(traits::Obligation::with_depth( @@ -738,12 +738,8 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { } } }; - if let Some(start) = start { - check(start) - } - if let Some(end) = end { - check(end) - } + check(start); + check(end); } } } @@ -904,19 +900,14 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { // FIXME(#27579) RFC also considers adding trait // obligations that don't refer to Self and // checking those - - let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch(); - - if !defer_to_coercion { - if let Some(principal) = data.principal_def_id() { - self.out.push(traits::Obligation::with_depth( - tcx, - self.cause(ObligationCauseCode::WellFormed(None)), - self.recursion_depth, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)), - )); - } + if let Some(principal) = data.principal_def_id() { + self.out.push(traits::Obligation::with_depth( + tcx, + self.cause(ObligationCauseCode::WellFormed(None)), + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)), + )); } } diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml index 9c788116d98c3..04aef4e7b9e03 100644 --- a/compiler/rustc_traits/Cargo.toml +++ b/compiler/rustc_traits/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_traits" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index cc329ca33288c..4a889abfc28f1 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -70,7 +70,7 @@ pub(crate) fn codegen_select_candidate<'tcx>( infcx.err_ctxt().report_overflow_obligation_cycle(&cycle); } } - return Err(CodegenObligationError::FulfillmentError); + return Err(CodegenObligationError::Unimplemented); } let impl_source = infcx.resolve_vars_if_possible(impl_source); diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index 5f75e242a50fb..6fb483e6dac93 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -10,38 +10,28 @@ use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtBuilderExt; -use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::{ - compute_implied_outlives_bounds_compat_inner, compute_implied_outlives_bounds_inner, -}; +use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner; use rustc_trait_selection::traits::query::{CanonicalImpliedOutlivesBoundsGoal, NoSolution}; pub(crate) fn provide(p: &mut Providers) { - *p = Providers { implied_outlives_bounds_compat, ..*p }; *p = Providers { implied_outlives_bounds, ..*p }; } -fn implied_outlives_bounds_compat<'tcx>( - tcx: TyCtxt<'tcx>, - goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>, -) -> Result< - &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, - NoSolution, -> { - tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { - let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts(); - compute_implied_outlives_bounds_compat_inner(ocx, param_env, ty, DUMMY_SP) - }) -} - fn implied_outlives_bounds<'tcx>( tcx: TyCtxt<'tcx>, - goal: CanonicalImpliedOutlivesBoundsGoal<'tcx>, + (goal, disable_implied_bounds_hack): (CanonicalImpliedOutlivesBoundsGoal<'tcx>, bool), ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec>>>, NoSolution, > { tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| { let (param_env, ImpliedOutlivesBounds { ty }) = key.into_parts(); - compute_implied_outlives_bounds_inner(ocx, param_env, ty, DUMMY_SP) + compute_implied_outlives_bounds_inner( + ocx, + param_env, + ty, + DUMMY_SP, + disable_implied_bounds_hack, + ) }) } diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index d2f979bd6d9dc..697c839180312 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -2,7 +2,6 @@ // tidy-alphabetical-start #![recursion_limit = "256"] -#![warn(unreachable_pub)] // tidy-alphabetical-end mod codegen; diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml index 94c7695117c63..f0c783b30020e 100644 --- a/compiler/rustc_transmute/Cargo.toml +++ b/compiler/rustc_transmute/Cargo.toml @@ -1,15 +1,13 @@ [package] name = "rustc_transmute" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start rustc_abi = { path = "../rustc_abi", optional = true } rustc_data_structures = { path = "../rustc_data_structures" } rustc_hir = { path = "../rustc_hir", optional = true } -rustc_infer = { path = "../rustc_infer", optional = true } -rustc_macros = { path = "../rustc_macros", optional = true } rustc_middle = { path = "../rustc_middle", optional = true } rustc_span = { path = "../rustc_span", optional = true } tracing = "0.1" @@ -19,8 +17,6 @@ tracing = "0.1" rustc = [ "dep:rustc_abi", "dep:rustc_hir", - "dep:rustc_infer", - "dep:rustc_macros", "dep:rustc_middle", "dep:rustc_span", ] diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index a70dc034e63dd..a29baade42fb7 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -38,7 +38,7 @@ impl Transitions where R: Ref, { - #[allow(dead_code)] + #[cfg(test)] fn insert(&mut self, transition: Transition, state: State) { match transition { Transition::Byte(b) => { @@ -86,15 +86,6 @@ impl Dfa where R: Ref, { - #[allow(dead_code)] - pub(crate) fn unit() -> Self { - let transitions: Map> = Map::default(); - let start = State::new(); - let accepting = start; - - Self { transitions, start, accepting } - } - #[cfg(test)] pub(crate) fn bool() -> Self { let mut transitions: Map> = Map::default(); diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs index 3b49c59fa6867..9c21fd94f03ec 100644 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -159,11 +159,6 @@ where } Self { transitions, start, accepting } } - - #[allow(dead_code)] - pub(crate) fn edges_from(&self, start: State) -> Option<&Map, Set>> { - self.transitions.get(&start) - } } impl State { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index b00585d292212..a21be5dda4ee0 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -237,7 +237,7 @@ pub(crate) mod rustc { ty::Tuple(members) => Self::from_tuple((ty, layout), members, cx), - ty::Array(inner_ty, len) => { + ty::Array(inner_ty, _len) => { let FieldsShape::Array { stride, count } = &layout.fields else { return Err(Err::NotYetSupported); }; @@ -282,7 +282,6 @@ pub(crate) mod rustc { FieldsShape::Primitive => { assert_eq!(members.len(), 1); let inner_ty = members[0]; - let inner_layout = layout_of(cx, inner_ty)?; Self::from_ty(inner_ty, cx) } FieldsShape::Arbitrary { offsets, .. } => { @@ -345,7 +344,7 @@ pub(crate) mod rustc { // the enum delegates its layout to the variant at `index`. layout_of_variant(*index, None) } - Variants::Multiple { tag, tag_encoding, tag_field, .. } => { + Variants::Multiple { tag: _, tag_encoding, tag_field, .. } => { // `Variants::Multiple` denotes an enum with multiple // variants. The layout of such an enum is the disjunction // of the layouts of its tagged variants. @@ -356,7 +355,7 @@ pub(crate) mod rustc { let variants = def.discriminants(cx.tcx()).try_fold( Self::uninhabited(), - |variants, (idx, ref discriminant)| { + |variants, (idx, _discriminant)| { let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?; Result::::Ok(variants.or(variant)) }, @@ -414,7 +413,7 @@ pub(crate) mod rustc { // Append the fields, in memory order, to the layout. let inverse_memory_index = memory_index.invert_bijective_mapping(); - for (memory_idx, &field_idx) in inverse_memory_index.iter_enumerated() { + for &field_idx in inverse_memory_index.iter() { // Add interfield padding. let padding_needed = offsets[field_idx] - size; let padding = Self::padding(padding_needed.bytes_usize()); @@ -468,15 +467,14 @@ pub(crate) mod rustc { // This constructor does not support non-`FieldsShape::Union` // layouts. Fields of this shape are all placed at offset 0. - let FieldsShape::Union(fields) = layout.fields() else { + let FieldsShape::Union(_fields) = layout.fields() else { return Err(Err::NotYetSupported); }; let fields = &def.non_enum_variant().fields; let fields = fields.iter_enumerated().try_fold( Self::uninhabited(), - |fields, (idx, field_def)| { - let field_def = Def::Field(field_def); + |fields, (idx, _field_def)| { let field_ty = ty_field(cx, (ty, layout), idx); let field_layout = layout_of(cx, field_ty)?; let field = Self::from_ty(field_ty, cx)?; diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index f9537f708ef8d..7d800e49ff45f 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,8 +1,6 @@ // tidy-alphabetical-start -#![allow(unused_variables)] -#![feature(alloc_layout_extra)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![feature(never_type)] -#![warn(unreachable_pub)] // tidy-alphabetical-end pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set}; @@ -81,15 +79,12 @@ pub enum Reason { #[cfg(feature = "rustc")] mod rustc { use rustc_hir::lang_items::LangItem; - use rustc_infer::infer::InferCtxt; - use rustc_macros::TypeVisitable; - use rustc_middle::traits::ObligationCause; - use rustc_middle::ty::{Const, ParamEnv, Ty, TyCtxt}; + use rustc_middle::ty::{Const, Ty, TyCtxt}; use super::*; /// The source and destination types of a transmutation. - #[derive(TypeVisitable, Debug, Clone, Copy)] + #[derive(Debug, Clone, Copy)] pub struct Types<'tcx> { /// The source type. pub src: Ty<'tcx>, @@ -97,27 +92,22 @@ mod rustc { pub dst: Ty<'tcx>, } - pub struct TransmuteTypeEnv<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, + pub struct TransmuteTypeEnv<'tcx> { + tcx: TyCtxt<'tcx>, } - impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self { - Self { infcx } + impl<'tcx> TransmuteTypeEnv<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>) -> Self { + Self { tcx } } - #[allow(unused)] pub fn is_transmutable( &mut self, - cause: ObligationCause<'tcx>, types: Types<'tcx>, assume: crate::Assume, ) -> crate::Answer> { crate::maybe_transmutable::MaybeTransmutableQuery::new( - types.src, - types.dst, - assume, - self.infcx.tcx, + types.src, types.dst, assume, self.tcx, ) .answer() } @@ -125,11 +115,7 @@ mod rustc { impl Assume { /// Constructs an `Assume` from a given const-`Assume`. - pub fn from_const<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - ct: Const<'tcx>, - ) -> Option { + pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option { use rustc_middle::ty::ScalarInt; use rustc_span::sym; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 023c8fad781dd..63fabc9c83d93 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -79,12 +79,12 @@ where pub(crate) fn answer(self) -> Answer<::Ref> { let Self { src, dst, assume, context } = self; - // Unconditionally all `Def` nodes from `src`, without pruning away the + // Unconditionally remove all `Def` nodes from `src`, without pruning away the // branches they appear in. This is valid to do for value-to-value // transmutations, but not for `&mut T` to `&mut U`; we will need to be // more sophisticated to handle transmutations between mutable // references. - let src = src.prune(&|def| false); + let src = src.prune(&|_def| false); if src.is_inhabited() && !dst.is_inhabited() { return Answer::No(Reason::DstUninhabited); @@ -96,7 +96,7 @@ where let dst = if assume.safety { // ...if safety is assumed, don't check if they carry safety // invariants; retain all paths. - dst.prune(&|def| false) + dst.prune(&|_def| false) } else { // ...otherwise, prune away all paths with safety invariants from // the `Dst` layout. diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 84af20c773e05..4d81382eba02c 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -92,7 +92,6 @@ mod bool { #[test] fn should_permit_validity_expansion_and_reject_contraction() { - let un = layout::Tree::::uninhabited(); let b0 = layout::Tree::::from_bits(0); let b1 = layout::Tree::::from_bits(1); let b2 = layout::Tree::::from_bits(2); diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml index ab903c6ed73f8..b14ce8a7f21e8 100644 --- a/compiler/rustc_ty_utils/Cargo.toml +++ b/compiler/rustc_ty_utils/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "rustc_ty_utils" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start itertools = "0.12" rustc_abi = { path = "../rustc_abi" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } @@ -20,6 +21,5 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } -rustc_type_ir = { path = "../rustc_type_ir" } tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index ae795ef2214b8..8bc7bf10865f5 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -14,6 +14,8 @@ ty_utils_borrow_not_supported = borrowing is not supported in generic constants ty_utils_box_not_supported = allocations are not allowed in generic constants +ty_utils_by_use_not_supported = .use is not allowed in generic constants + ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants ty_utils_const_block_not_supported = const blocks are not supported in generic constants @@ -42,8 +44,6 @@ ty_utils_logical_op_not_supported = unsupported operation in generic constants, ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants -ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field - ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 0ff82f0c256de..a726ebae6fe1b 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -309,15 +309,11 @@ fn fn_abi_of_fn_ptr<'tcx>( query: ty::PseudoCanonicalInput<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List>)>, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> { let ty::PseudoCanonicalInput { typing_env, value: (sig, extra_args) } = query; - - let cx = LayoutCx::new(tcx, typing_env); fn_abi_new_uncached( - &cx, + &LayoutCx::new(tcx, typing_env), tcx.instantiate_bound_regions_with_erased(sig), extra_args, None, - None, - false, ) } @@ -326,19 +322,11 @@ fn fn_abi_of_instance<'tcx>( query: ty::PseudoCanonicalInput<'tcx, (ty::Instance<'tcx>, &'tcx ty::List>)>, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> { let ty::PseudoCanonicalInput { typing_env, value: (instance, extra_args) } = query; - - let sig = fn_sig_for_fn_abi(tcx, instance, typing_env); - - let caller_location = - instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty()); - fn_abi_new_uncached( &LayoutCx::new(tcx, typing_env), - sig, + fn_sig_for_fn_abi(tcx, instance, typing_env), extra_args, - caller_location, - Some(instance.def_id()), - matches!(instance.def, ty::InstanceKind::Virtual(..)), + Some(instance), ) } @@ -448,10 +436,7 @@ fn fn_abi_sanity_check<'tcx>( ) { let tcx = cx.tcx(); - if spec_abi == ExternAbi::Rust - || spec_abi == ExternAbi::RustCall - || spec_abi == ExternAbi::RustCold - { + if spec_abi.is_rustic_abi() { if arg.layout.is_zst() { // Casting closures to function pointers depends on ZST closure types being // omitted entirely in the calling convention. @@ -472,7 +457,7 @@ fn fn_abi_sanity_check<'tcx>( // `layout.backend_repr` and ignore everything else. We should just reject //`Aggregate` entirely here, but some targets need to be fixed first. match arg.layout.backend_repr { - BackendRepr::Scalar(_) | BackendRepr::Vector { .. } => {} + BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => {} BackendRepr::ScalarPair(..) => { panic!("`PassMode::Direct` used for ScalarPair type {}", arg.layout.ty) } @@ -547,19 +532,25 @@ fn fn_abi_sanity_check<'tcx>( fn_arg_sanity_check(cx, fn_abi, spec_abi, &fn_abi.ret); } -// FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) -// arguments of this method, into a separate `struct`. -#[tracing::instrument(level = "debug", skip(cx, caller_location, fn_def_id, force_thin_self_ptr))] +#[tracing::instrument(level = "debug", skip(cx, instance))] fn fn_abi_new_uncached<'tcx>( cx: &LayoutCx<'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>], - caller_location: Option>, - fn_def_id: Option, - // FIXME(eddyb) replace this with something typed, like an `enum`. - force_thin_self_ptr: bool, + instance: Option>, ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> { let tcx = cx.tcx(); + let (caller_location, determined_fn_def_id, is_virtual_call) = if let Some(instance) = instance + { + let is_virtual_call = matches!(instance.def, ty::InstanceKind::Virtual(..)); + ( + instance.def.requires_caller_location(tcx).then(|| tcx.caller_location_ty()), + if is_virtual_call { None } else { Some(instance.def_id()) }, + is_virtual_call, + ) + } else { + (None, None, false) + }; let sig = tcx.normalize_erasing_regions(cx.typing_env, sig); let conv = conv_from_spec_abi(cx.tcx(), sig.abi, sig.c_variadic); @@ -568,16 +559,11 @@ fn fn_abi_new_uncached<'tcx>( let extra_args = if sig.abi == ExternAbi::RustCall { assert!(!sig.c_variadic && extra_args.is_empty()); - if let Some(input) = sig.inputs().last() { - if let ty::Tuple(tupled_arguments) = input.kind() { - inputs = &sig.inputs()[0..sig.inputs().len() - 1]; - tupled_arguments - } else { - bug!( - "argument to function with \"rust-call\" ABI \ - is not a tuple" - ); - } + if let Some(input) = sig.inputs().last() + && let ty::Tuple(tupled_arguments) = input.kind() + { + inputs = &sig.inputs()[0..sig.inputs().len() - 1]; + tupled_arguments } else { bug!( "argument to function with \"rust-call\" ABI \ @@ -590,7 +576,7 @@ fn fn_abi_new_uncached<'tcx>( }; let is_drop_in_place = - fn_def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::DropInPlace)); + determined_fn_def_id.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::DropInPlace)); let arg_of = |ty: Ty<'tcx>, arg_idx: Option| -> Result<_, &'tcx FnAbiError<'tcx>> { let span = tracing::debug_span!("arg_of"); @@ -603,7 +589,7 @@ fn fn_abi_new_uncached<'tcx>( }); let layout = cx.layout_of(ty).map_err(|err| &*tcx.arena.alloc(FnAbiError::Layout(*err)))?; - let layout = if force_thin_self_ptr && arg_idx == Some(0) { + let layout = if is_virtual_call && arg_idx == Some(0) { // Don't pass the vtable, it's not an argument of the virtual fn. // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait` // or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen @@ -646,9 +632,22 @@ fn fn_abi_new_uncached<'tcx>( c_variadic: sig.c_variadic, fixed_count: inputs.len() as u32, conv, - can_unwind: fn_can_unwind(cx.tcx(), fn_def_id, sig.abi), + can_unwind: fn_can_unwind( + tcx, + // Since `#[rustc_nounwind]` can change unwinding, we cannot infer unwinding by `fn_def_id` for a virtual call. + determined_fn_def_id, + sig.abi, + ), }; - fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id); + fn_abi_adjust_for_abi( + cx, + &mut fn_abi, + sig.abi, + // If this is a virtual call, we cannot pass the `fn_def_id`, as it might call other + // functions from vtable. Internally, `deduced_param_attrs` attempts to infer attributes by + // visit the function body. + determined_fn_def_id, + ); debug!("fn_abi_new_uncached = {:?}", fn_abi); fn_abi_sanity_check(cx, &fn_abi, sig.abi); Ok(tcx.arena.alloc(fn_abi)) @@ -685,7 +684,7 @@ fn fn_abi_adjust_for_abi<'tcx>( let tcx = cx.tcx(); - if abi == ExternAbi::Rust || abi == ExternAbi::RustCall || abi == ExternAbi::RustIntrinsic { + if abi.is_rustic_abi() { fn_abi.adjust_for_rust_abi(cx, abi); // Look up the deduced parameter attributes for this function, if we have its def ID and diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index c8034f4e7b9f6..b7684e85d4128 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -21,7 +21,7 @@ pub(crate) fn provide(providers: &mut Providers) { } fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[DefId] { - let item = tcx.hir().expect_item(def_id); + let item = tcx.hir_expect_item(def_id); match item.kind { hir::ItemKind::Trait(.., trait_item_refs) => { // We collect RPITITs for each trait method's return type and create a @@ -96,7 +96,7 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { let id = tcx.local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir_get_parent_item(id); - let parent_item = tcx.hir().expect_item(parent_def_id.def_id); + let parent_item = tcx.hir_expect_item(parent_def_id.def_id); match parent_item.kind { hir::ItemKind::Impl(impl_) => { if let Some(impl_item_ref) = impl_.items.iter().find(|i| i.id.owner_id.def_id == def_id) @@ -201,7 +201,7 @@ fn associated_types_for_impl_traits_in_associated_fn( let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; - if let Some(output) = tcx.hir().get_fn_output(fn_def_id) { + if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { visitor.visit_fn_ret_ty(output); tcx.arena.alloc_from_iter(visitor.rpits.iter().map(|opaque_ty_def_id| { @@ -252,7 +252,8 @@ fn associated_type_for_impl_trait_in_trait( assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); let span = tcx.def_span(opaque_ty_def_id); - let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, kw::Empty, DefKind::AssocTy); + // No name because this is a synthetic associated type. + let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, None, DefKind::AssocTy); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -304,7 +305,8 @@ fn associated_type_for_impl_trait_in_impl( hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), hir::FnRetTy::Return(ty) => ty.span, }; - let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, kw::Empty, DefKind::AssocTy); + // No name because this is a synthetic associated type. + let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, None, DefKind::AssocTy); let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 2157ab3c4022c..20646cf9a826c 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -10,6 +10,13 @@ fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty is_item_raw(tcx, query, LangItem::Copy) } +fn is_use_cloned_raw<'tcx>( + tcx: TyCtxt<'tcx>, + query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, +) -> bool { + is_item_raw(tcx, query, LangItem::UseCloned) +} + fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { is_item_raw(tcx, query, LangItem::Sized) } @@ -33,5 +40,12 @@ fn is_item_raw<'tcx>( } pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers }; + *providers = Providers { + is_copy_raw, + is_use_cloned_raw, + is_sized_raw, + is_freeze_raw, + is_unpin_raw, + ..*providers + }; } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index ece796b3c71ce..b275cd382ab83 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -230,7 +230,9 @@ fn recurse_build<'tcx>( error(GenericConstantTooComplexSub::LoopNotSupported(node.span))? } ExprKind::Box { .. } => error(GenericConstantTooComplexSub::BoxNotSupported(node.span))?, - + ExprKind::ByUse { .. } => { + error(GenericConstantTooComplexSub::ByUseNotSupported(node.span))? + } ExprKind::Unary { .. } => unreachable!(), // we handle valid unary/binary ops above ExprKind::Binary { .. } => { @@ -317,6 +319,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> { | thir::ExprKind::Box { .. } | thir::ExprKind::If { .. } | thir::ExprKind::Call { .. } + | thir::ExprKind::ByUse { .. } | thir::ExprKind::Deref { .. } | thir::ExprKind::Binary { .. } | thir::ExprKind::LogicalOp { .. } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 5497d7d0bd2a0..0298e7e0e9511 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -55,6 +55,8 @@ pub(crate) enum GenericConstantTooComplexSub { BoxNotSupported(#[primary_span] Span), #[label(ty_utils_binary_not_supported)] BinaryNotSupported(#[primary_span] Span), + #[label(ty_utils_by_use_not_supported)] + ByUseNotSupported(#[primary_span] Span), #[label(ty_utils_logical_op_not_supported)] LogicalOpNotSupported(#[primary_span] Span), #[label(ty_utils_assign_not_supported)] @@ -82,12 +84,6 @@ pub(crate) struct ZeroLengthSimdType<'tcx> { pub ty: Ty<'tcx>, } -#[derive(Diagnostic)] -#[diag(ty_utils_multiple_array_fields_simd_type)] -pub(crate) struct MultipleArrayFieldsSimdType<'tcx> { - pub ty: Ty<'tcx>, -} - #[derive(Diagnostic)] #[diag(ty_utils_oversized_simd_type)] pub(crate) struct OversizedSimdType<'tcx> { diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index cc7baf8daac54..088d5e76b8685 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -6,8 +6,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt, fold_regions}; use rustc_span::Span; pub(crate) fn provide(providers: &mut Providers) { @@ -151,7 +150,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' } } -fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator + '_ { +fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator { let node = tcx.hir_node_by_def_id(def_id); if let Some(decl) = node.fn_decl() { decl.inputs.iter().map(|ty| ty.span).chain(iter::once(decl.output.span())) @@ -160,8 +159,8 @@ fn fn_sig_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator, def_id: LocalDefId) -> impl Iterator + '_ { - let item = tcx.hir().expect_item(def_id); +fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator { + let item = tcx.hir_expect_item(def_id); if let hir::ItemKind::Impl(impl_) = item.kind { let trait_args = impl_ .of_trait diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index d059d6dcd139c..962e1353ebcd7 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -7,11 +7,10 @@ use rustc_middle::query::Providers; use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError}; use rustc_middle::ty::util::AsyncDropGlueMorphology; use rustc_middle::ty::{ - self, GenericArgsRef, Instance, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, + self, ClosureKind, GenericArgsRef, Instance, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, }; use rustc_span::sym; use rustc_trait_selection::traits; -use rustc_type_ir::ClosureKind; use tracing::debug; use traits::translate_args; @@ -107,11 +106,9 @@ fn resolve_associated_item<'tcx>( let input = typing_env.as_query_input(trait_ref); let vtbl = match tcx.codegen_select_candidate(input) { Ok(vtbl) => vtbl, - Err( - CodegenObligationError::Ambiguity - | CodegenObligationError::Unimplemented - | CodegenObligationError::FulfillmentError, - ) => return Ok(None), + Err(CodegenObligationError::Ambiguity | CodegenObligationError::Unimplemented) => { + return Ok(None); + } Err(CodegenObligationError::UnconstrainedParam(guar)) => return Err(guar), }; @@ -381,8 +378,7 @@ fn resolve_associated_item<'tcx>( } } traits::ImplSource::Param(..) - | traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) - | traits::ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => None, + | traits::ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _) => None, }) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index c8b3c8a796f3a..7334beb52c9d5 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -1,36 +1,28 @@ -use std::fmt::Debug; -use std::iter; - use hir::def_id::DefId; use rustc_abi::Integer::{I8, I32}; use rustc_abi::Primitive::{self, Float, Int, Pointer}; use rustc_abi::{ - AbiAndPrefAlign, AddressSpace, Align, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, - HasDataLayout, Layout, LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, - StructKind, TagEncoding, VariantIdx, Variants, WrappingRange, + AddressSpace, BackendRepr, FIRST_VARIANT, FieldIdx, FieldsShape, HasDataLayout, Layout, + LayoutCalculatorError, LayoutData, Niche, ReprOptions, Scalar, Size, StructKind, TagEncoding, + VariantIdx, Variants, WrappingRange, }; use rustc_hashes::Hash64; -use rustc_index::bit_set::DenseBitSet; -use rustc_index::{IndexSlice, IndexVec}; +use rustc_index::IndexVec; use rustc_middle::bug; -use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ - FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, MAX_SIMD_LANES, TyAndLayout, + FloatExt, HasTyCtxt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, AdtDef, CoroutineArgsExt, EarlyBinder, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt, - TypeVisitableExt, + self, AdtDef, CoroutineArgsExt, EarlyBinder, PseudoCanonicalInput, Ty, TyCtxt, TypeVisitableExt, }; use rustc_session::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use rustc_span::{Symbol, sym}; -use tracing::{debug, instrument, trace}; +use tracing::{debug, instrument}; use {rustc_abi as abi, rustc_hir as hir}; -use crate::errors::{ - MultipleArrayFieldsSimdType, NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType, -}; +use crate::errors::{NonPrimitiveSimdType, OversizedSimdType, ZeroLengthSimdType}; mod invariant; @@ -126,20 +118,23 @@ fn map_error<'tcx>( .delayed_bug(format!("computed impossible repr (packed enum?): {ty:?}")); LayoutError::ReferencesError(guar) } + LayoutCalculatorError::ZeroLengthSimdType => { + // Can't be caught in typeck if the array length is generic. + cx.tcx().dcx().emit_fatal(ZeroLengthSimdType { ty }) + } + LayoutCalculatorError::OversizedSimdType { max_lanes } => { + // Can't be caught in typeck if the array length is generic. + cx.tcx().dcx().emit_fatal(OversizedSimdType { ty, max_lanes }) + } + LayoutCalculatorError::NonPrimitiveSimdType(field) => { + // This error isn't caught in typeck, e.g., if + // the element type of the vector is generic. + cx.tcx().dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty: field.ty }) + } }; error(cx, err) } -fn univariant_uninterned<'tcx>( - cx: &LayoutCx<'tcx>, - ty: Ty<'tcx>, - fields: &IndexSlice>, - kind: StructKind, -) -> Result, &'tcx LayoutError<'tcx>> { - let repr = ReprOptions::default(); - cx.calc.univariant(fields, &repr, kind).map_err(|err| map_error(cx, ty, err)) -} - fn extract_const_value<'tcx>( cx: &LayoutCx<'tcx>, ty: Ty<'tcx>, @@ -190,6 +185,10 @@ fn layout_of_uncached<'tcx>( let tcx = cx.tcx(); let dl = cx.data_layout(); + let map_layout = |result: Result<_, _>| match result { + Ok(layout) => Ok(tcx.mk_layout(layout)), + Err(err) => Err(map_error(cx, ty, err)), + }; let scalar_unit = |value: Primitive| { let size = value.size(dl); assert!(size.bits() <= 128); @@ -197,8 +196,10 @@ fn layout_of_uncached<'tcx>( }; let scalar = |value: Primitive| tcx.mk_layout(LayoutData::scalar(cx, scalar_unit(value))); - let univariant = |fields: &IndexSlice>, kind| { - Ok(tcx.mk_layout(univariant_uninterned(cx, ty, fields, kind)?)) + let univariant = |tys: &[Ty<'tcx>], kind| { + let fields = tys.iter().map(|ty| cx.layout_of(*ty)).try_collect::>()?; + let repr = ReprOptions::default(); + map_layout(cx.calc.univariant(&fields, &repr, kind)) }; debug_assert!(!ty.has_non_region_infer()); @@ -207,24 +208,45 @@ fn layout_of_uncached<'tcx>( let layout = cx.layout_of(ty)?.layout; let mut layout = LayoutData::clone(&layout.0); match *pat { - ty::PatternKind::Range { start, end, include_end } => { + ty::PatternKind::Range { start, end } => { if let BackendRepr::Scalar(scalar) | BackendRepr::ScalarPair(scalar, _) = &mut layout.backend_repr { - if let Some(start) = start { - scalar.valid_range_mut().start = extract_const_value(cx, ty, start)? - .try_to_bits(tcx, cx.typing_env) - .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; - } - if let Some(end) = end { - let mut end = extract_const_value(cx, ty, end)? - .try_to_bits(tcx, cx.typing_env) - .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; - if !include_end { - end = end.wrapping_sub(1); + scalar.valid_range_mut().start = extract_const_value(cx, ty, start)? + .try_to_bits(tcx, cx.typing_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + + scalar.valid_range_mut().end = extract_const_value(cx, ty, end)? + .try_to_bits(tcx, cx.typing_env) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; + + // FIXME(pattern_types): create implied bounds from pattern types in signatures + // that require that the range end is >= the range start so that we can't hit + // this error anymore without first having hit a trait solver error. + // Very fuzzy on the details here, but pattern types are an internal impl detail, + // so we can just go with this for now + if scalar.is_signed() { + let range = scalar.valid_range_mut(); + let start = layout.size.sign_extend(range.start); + let end = layout.size.sign_extend(range.end); + if end < start { + let guar = tcx.dcx().err(format!( + "pattern type ranges cannot wrap: {start}..={end}" + )); + + return Err(error(cx, LayoutError::ReferencesError(guar))); } - scalar.valid_range_mut().end = end; - } + } else { + let range = scalar.valid_range_mut(); + if range.end < range.start { + let guar = tcx.dcx().err(format!( + "pattern type ranges cannot wrap: {}..={}", + range.start, range.end + )); + + return Err(error(cx, LayoutError::ReferencesError(guar))); + } + }; let niche = Niche { offset: Size::ZERO, @@ -267,7 +289,7 @@ fn layout_of_uncached<'tcx>( } // The never type. - ty::Never => tcx.mk_layout(cx.calc.layout_of_never_type()), + ty::Never => tcx.mk_layout(LayoutData::never_type(cx)), // Potentially-wide pointers. ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => { @@ -338,7 +360,7 @@ fn layout_of_uncached<'tcx>( }; // Effectively a (ptr, meta) tuple. - tcx.mk_layout(cx.calc.scalar_pair(data_ptr, metadata)) + tcx.mk_layout(LayoutData::scalar_pair(cx, data_ptr, metadata)) } ty::Dynamic(_, _, ty::DynStar) => { @@ -346,7 +368,7 @@ fn layout_of_uncached<'tcx>( data.valid_range_mut().start = 0; let mut vtable = scalar_unit(Pointer(AddressSpace::DATA)); vtable.valid_range_mut().start = 1; - tcx.mk_layout(cx.calc.scalar_pair(data, vtable)) + tcx.mk_layout(LayoutData::scalar_pair(cx, data, vtable)) } // Arrays and slices. @@ -356,225 +378,114 @@ fn layout_of_uncached<'tcx>( .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; let element = cx.layout_of(element)?; - let size = element - .size - .checked_mul(count, dl) - .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; - - let abi = BackendRepr::Memory { sized: true }; - - let largest_niche = if count != 0 { element.largest_niche } else { None }; - let uninhabited = if count != 0 { element.uninhabited } else { false }; - - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields: FieldsShape::Array { stride: element.size, count }, - backend_repr: abi, - largest_niche, - uninhabited, - align: element.align, - size, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - randomization_seed: element.randomization_seed.wrapping_add(Hash64::new(count)), - }) + map_layout(cx.calc.array_like(&element, Some(count)))? } ty::Slice(element) => { let element = cx.layout_of(element)?; - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields: FieldsShape::Array { stride: element.size, count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: element.align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: element.align.abi, - // adding a randomly chosen value to distinguish slices - randomization_seed: element - .randomization_seed - .wrapping_add(Hash64::new(0x2dcba99c39784102)), - }) + map_layout(cx.calc.array_like(&element, None).map(|mut layout| { + // a randomly chosen value to distinguish slices + layout.randomization_seed = Hash64::new(0x2dcba99c39784102); + layout + }))? + } + ty::Str => { + let element = scalar(Int(I8, false)); + map_layout(cx.calc.array_like(&element, None).map(|mut layout| { + // another random value + layout.randomization_seed = Hash64::new(0xc1325f37d127be22); + layout + }))? } - ty::Str => tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, - backend_repr: BackendRepr::Memory { sized: false }, - largest_niche: None, - uninhabited: false, - align: dl.i8_align, - size: Size::ZERO, - max_repr_align: None, - unadjusted_abi_align: dl.i8_align.abi, - // another random value - randomization_seed: Hash64::new(0xc1325f37d127be22), - }), // Odd unit types. - ty::FnDef(..) => univariant(IndexSlice::empty(), StructKind::AlwaysSized)?, - ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { - let mut unit = - univariant_uninterned(cx, ty, IndexSlice::empty(), StructKind::AlwaysSized)?; - match unit.backend_repr { - BackendRepr::Memory { ref mut sized } => *sized = false, - _ => bug!(), - } - tcx.mk_layout(unit) + ty::FnDef(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => { + let sized = matches!(ty.kind(), ty::FnDef(..)); + tcx.mk_layout(LayoutData::unit(cx, sized)) } - ty::Coroutine(def_id, args) => coroutine_layout(cx, ty, def_id, args)?, + ty::Coroutine(def_id, args) => { + use rustc_middle::ty::layout::PrimitiveExt as _; + + let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else { + return Err(error(cx, LayoutError::Unknown(ty))); + }; + + let local_layouts = info + .field_tys + .iter() + .map(|local| { + let field_ty = EarlyBinder::bind(local.ty); + let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty.instantiate(tcx, args)); + cx.spanned_layout_of(uninit_ty, local.source_info.span) + }) + .try_collect::>()?; + + let prefix_layouts = args + .as_coroutine() + .prefix_tys() + .iter() + .map(|ty| cx.layout_of(ty)) + .try_collect::>()?; - ty::Closure(_, args) => { - let tys = args.as_closure().upvar_tys(); - univariant( - &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::>()?, - StructKind::AlwaysSized, - )? + let layout = cx + .calc + .coroutine( + &local_layouts, + prefix_layouts, + &info.variant_fields, + &info.storage_conflicts, + |tag| TyAndLayout { + ty: tag.primitive().to_ty(tcx), + layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), + }, + ) + .map(|mut layout| { + // this is similar to how ReprOptions populates its field_shuffle_seed + layout.randomization_seed = tcx.def_path_hash(def_id).0.to_smaller_hash(); + debug!("coroutine layout ({:?}): {:#?}", ty, layout); + layout + }); + map_layout(layout)? } + ty::Closure(_, args) => univariant(args.as_closure().upvar_tys(), StructKind::AlwaysSized)?, + ty::CoroutineClosure(_, args) => { - let tys = args.as_coroutine_closure().upvar_tys(); - univariant( - &tys.iter().map(|ty| cx.layout_of(ty)).try_collect::>()?, - StructKind::AlwaysSized, - )? + univariant(args.as_coroutine_closure().upvar_tys(), StructKind::AlwaysSized)? } ty::Tuple(tys) => { let kind = if tys.len() == 0 { StructKind::AlwaysSized } else { StructKind::MaybeUnsized }; - univariant(&tys.iter().map(|k| cx.layout_of(k)).try_collect::>()?, kind)? + univariant(tys, kind)? } // SIMD vector types. ty::Adt(def, args) if def.repr().simd() => { - if !def.is_struct() { - // Should have yielded E0517 by now. - let guar = tcx - .dcx() - .delayed_bug("#[repr(simd)] was applied to an ADT that is not a struct"); - return Err(error(cx, LayoutError::ReferencesError(guar))); - } - - let fields = &def.non_enum_variant().fields; - - // Supported SIMD vectors are homogeneous ADTs with at least one field: + // Supported SIMD vectors are ADTs with a single array field: // - // * #[repr(simd)] struct S(T, T, T, T); - // * #[repr(simd)] struct S { x: T, y: T, z: T, w: T } // * #[repr(simd)] struct S([T; 4]) // // where T is a primitive scalar (integer/float/pointer). - - // SIMD vectors with zero fields are not supported. - // (should be caught by typeck) - if fields.is_empty() { - tcx.dcx().emit_fatal(ZeroLengthSimdType { ty }) - } - - // Type of the first ADT field: - let f0_ty = fields[FieldIdx::ZERO].ty(tcx, args); - - // Heterogeneous SIMD vectors are not supported: - // (should be caught by typeck) - for fi in fields { - if fi.ty(tcx, args) != f0_ty { - let guar = tcx.dcx().delayed_bug( - "#[repr(simd)] was applied to an ADT with heterogeneous field type", - ); - return Err(error(cx, LayoutError::ReferencesError(guar))); - } - } - - // The element type and number of elements of the SIMD vector - // are obtained from: - // - // * the element type and length of the single array field, if - // the first field is of array type, or - // - // * the homogeneous field type and the number of fields. - let (e_ty, e_len, is_array) = if let ty::Array(e_ty, _) = f0_ty.kind() { - // First ADT field is an array: - - // SIMD vectors with multiple array fields are not supported: - // Can't be caught by typeck with a generic simd type. - if def.non_enum_variant().fields.len() != 1 { - tcx.dcx().emit_fatal(MultipleArrayFieldsSimdType { ty }); - } - - // Extract the number of elements from the layout of the array field: - let FieldsShape::Array { count, .. } = cx.layout_of(f0_ty)?.layout.fields() else { - return Err(error(cx, LayoutError::Unknown(ty))); - }; - - (*e_ty, *count, true) - } else { - // First ADT field is not an array: - (f0_ty, def.non_enum_variant().fields.len() as _, false) + let Some(ty::Array(e_ty, e_len)) = def + .is_struct() + .then(|| &def.variant(FIRST_VARIANT).fields) + .filter(|fields| fields.len() == 1) + .map(|fields| *fields[FieldIdx::ZERO].ty(tcx, args).kind()) + else { + // Invalid SIMD types should have been caught by typeck by now. + let guar = tcx.dcx().delayed_bug("#[repr(simd)] was applied to an invalid ADT"); + return Err(error(cx, LayoutError::ReferencesError(guar))); }; - // SIMD vectors of zero length are not supported. - // Additionally, lengths are capped at 2^16 as a fixed maximum backends must - // support. - // - // Can't be caught in typeck if the array length is generic. - if e_len == 0 { - tcx.dcx().emit_fatal(ZeroLengthSimdType { ty }); - } else if e_len > MAX_SIMD_LANES { - tcx.dcx().emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES }); - } + let e_len = extract_const_value(cx, ty, e_len)? + .try_to_target_usize(tcx) + .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?; - // Compute the ABI of the element type: let e_ly = cx.layout_of(e_ty)?; - let BackendRepr::Scalar(e_abi) = e_ly.backend_repr else { - // This error isn't caught in typeck, e.g., if - // the element type of the vector is generic. - tcx.dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty }); - }; - - // Compute the size and alignment of the vector: - let size = e_ly - .size - .checked_mul(e_len, dl) - .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?; - - let (abi, align) = if def.repr().packed() && !e_len.is_power_of_two() { - // Non-power-of-two vectors have padding up to the next power-of-two. - // If we're a packed repr, remove the padding while keeping the alignment as close - // to a vector as possible. - ( - BackendRepr::Memory { sized: true }, - AbiAndPrefAlign { - abi: Align::max_for_offset(size), - pref: dl.vector_align(size).pref, - }, - ) - } else { - (BackendRepr::Vector { element: e_abi, count: e_len }, dl.vector_align(size)) - }; - let size = size.align_to(align.abi); - // Compute the placement of the vector fields: - let fields = if is_array { - FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into() } - } else { - FieldsShape::Array { stride: e_ly.size, count: e_len } - }; - - tcx.mk_layout(LayoutData { - variants: Variants::Single { index: FIRST_VARIANT }, - fields, - backend_repr: abi, - largest_niche: e_ly.largest_niche, - uninhabited: false, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: e_ly.randomization_seed.wrapping_add(Hash64::new(e_len)), - }) + map_layout(cx.calc.simd_type(e_ly, e_len, def.repr().packed()))? } // ADTs. @@ -600,11 +511,7 @@ fn layout_of_uncached<'tcx>( return Err(error(cx, LayoutError::ReferencesError(guar))); } - return Ok(tcx.mk_layout( - cx.calc - .layout_of_union(&def.repr(), &variants) - .map_err(|err| map_error(cx, ty, err))?, - )); + return map_layout(cx.calc.layout_of_union(&def.repr(), &variants)); } let get_discriminant_type = @@ -732,335 +639,6 @@ fn layout_of_uncached<'tcx>( }) } -/// Overlap eligibility and variant assignment for each CoroutineSavedLocal. -#[derive(Clone, Debug, PartialEq)] -enum SavedLocalEligibility { - Unassigned, - Assigned(VariantIdx), - Ineligible(Option), -} - -// When laying out coroutines, we divide our saved local fields into two -// categories: overlap-eligible and overlap-ineligible. -// -// Those fields which are ineligible for overlap go in a "prefix" at the -// beginning of the layout, and always have space reserved for them. -// -// Overlap-eligible fields are only assigned to one variant, so we lay -// those fields out for each variant and put them right after the -// prefix. -// -// Finally, in the layout details, we point to the fields from the -// variants they are assigned to. It is possible for some fields to be -// included in multiple variants. No field ever "moves around" in the -// layout; its offset is always the same. -// -// Also included in the layout are the upvars and the discriminant. -// These are included as fields on the "outer" layout; they are not part -// of any variant. - -/// Compute the eligibility and assignment of each local. -fn coroutine_saved_local_eligibility( - info: &CoroutineLayout<'_>, -) -> (DenseBitSet, IndexVec) { - use SavedLocalEligibility::*; - - let mut assignments: IndexVec = - IndexVec::from_elem(Unassigned, &info.field_tys); - - // The saved locals not eligible for overlap. These will get - // "promoted" to the prefix of our coroutine. - let mut ineligible_locals = DenseBitSet::new_empty(info.field_tys.len()); - - // Figure out which of our saved locals are fields in only - // one variant. The rest are deemed ineligible for overlap. - for (variant_index, fields) in info.variant_fields.iter_enumerated() { - for local in fields { - match assignments[*local] { - Unassigned => { - assignments[*local] = Assigned(variant_index); - } - Assigned(idx) => { - // We've already seen this local at another suspension - // point, so it is no longer a candidate. - trace!( - "removing local {:?} in >1 variant ({:?}, {:?})", - local, variant_index, idx - ); - ineligible_locals.insert(*local); - assignments[*local] = Ineligible(None); - } - Ineligible(_) => {} - } - } - } - - // Next, check every pair of eligible locals to see if they - // conflict. - for local_a in info.storage_conflicts.rows() { - let conflicts_a = info.storage_conflicts.count(local_a); - if ineligible_locals.contains(local_a) { - continue; - } - - for local_b in info.storage_conflicts.iter(local_a) { - // local_a and local_b are storage live at the same time, therefore they - // cannot overlap in the coroutine layout. The only way to guarantee - // this is if they are in the same variant, or one is ineligible - // (which means it is stored in every variant). - if ineligible_locals.contains(local_b) || assignments[local_a] == assignments[local_b] { - continue; - } - - // If they conflict, we will choose one to make ineligible. - // This is not always optimal; it's just a greedy heuristic that - // seems to produce good results most of the time. - let conflicts_b = info.storage_conflicts.count(local_b); - let (remove, other) = - if conflicts_a > conflicts_b { (local_a, local_b) } else { (local_b, local_a) }; - ineligible_locals.insert(remove); - assignments[remove] = Ineligible(None); - trace!("removing local {:?} due to conflict with {:?}", remove, other); - } - } - - // Count the number of variants in use. If only one of them, then it is - // impossible to overlap any locals in our layout. In this case it's - // always better to make the remaining locals ineligible, so we can - // lay them out with the other locals in the prefix and eliminate - // unnecessary padding bytes. - { - let mut used_variants = DenseBitSet::new_empty(info.variant_fields.len()); - for assignment in &assignments { - if let Assigned(idx) = assignment { - used_variants.insert(*idx); - } - } - if used_variants.count() < 2 { - for assignment in assignments.iter_mut() { - *assignment = Ineligible(None); - } - ineligible_locals.insert_all(); - } - } - - // Write down the order of our locals that will be promoted to the prefix. - { - for (idx, local) in ineligible_locals.iter().enumerate() { - assignments[local] = Ineligible(Some(FieldIdx::from_usize(idx))); - } - } - debug!("coroutine saved local assignments: {:?}", assignments); - - (ineligible_locals, assignments) -} - -/// Compute the full coroutine layout. -fn coroutine_layout<'tcx>( - cx: &LayoutCx<'tcx>, - ty: Ty<'tcx>, - def_id: hir::def_id::DefId, - args: GenericArgsRef<'tcx>, -) -> Result, &'tcx LayoutError<'tcx>> { - use SavedLocalEligibility::*; - let tcx = cx.tcx(); - let instantiate_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).instantiate(tcx, args); - - let Some(info) = tcx.coroutine_layout(def_id, args.as_coroutine().kind_ty()) else { - return Err(error(cx, LayoutError::Unknown(ty))); - }; - let (ineligible_locals, assignments) = coroutine_saved_local_eligibility(info); - - // Build a prefix layout, including "promoting" all ineligible - // locals as part of the prefix. We compute the layout of all of - // these fields at once to get optimal packing. - let tag_index = args.as_coroutine().prefix_tys().len(); - - // `info.variant_fields` already accounts for the reserved variants, so no need to add them. - let max_discr = (info.variant_fields.len() - 1) as u128; - let discr_int = abi::Integer::fit_unsigned(max_discr); - let tag = Scalar::Initialized { - value: Primitive::Int(discr_int, /* signed = */ false), - valid_range: WrappingRange { start: 0, end: max_discr }, - }; - let tag_layout = TyAndLayout { - ty: discr_int.to_ty(tcx, /* signed = */ false), - layout: tcx.mk_layout(LayoutData::scalar(cx, tag)), - }; - - let promoted_layouts = ineligible_locals.iter().map(|local| { - let field_ty = instantiate_field(info.field_tys[local].ty); - let uninit_ty = Ty::new_maybe_uninit(tcx, field_ty); - cx.spanned_layout_of(uninit_ty, info.field_tys[local].source_info.span) - }); - let prefix_layouts = args - .as_coroutine() - .prefix_tys() - .iter() - .map(|ty| cx.layout_of(ty)) - .chain(iter::once(Ok(tag_layout))) - .chain(promoted_layouts) - .try_collect::>()?; - let prefix = univariant_uninterned(cx, ty, &prefix_layouts, StructKind::AlwaysSized)?; - - let (prefix_size, prefix_align) = (prefix.size, prefix.align); - - // Split the prefix layout into the "outer" fields (upvars and - // discriminant) and the "promoted" fields. Promoted fields will - // get included in each variant that requested them in - // CoroutineLayout. - debug!("prefix = {:#?}", prefix); - let (outer_fields, promoted_offsets, promoted_memory_index) = match prefix.fields { - FieldsShape::Arbitrary { mut offsets, memory_index } => { - let mut inverse_memory_index = memory_index.invert_bijective_mapping(); - - // "a" (`0..b_start`) and "b" (`b_start..`) correspond to - // "outer" and "promoted" fields respectively. - let b_start = FieldIdx::from_usize(tag_index + 1); - let offsets_b = IndexVec::from_raw(offsets.raw.split_off(b_start.as_usize())); - let offsets_a = offsets; - - // Disentangle the "a" and "b" components of `inverse_memory_index` - // by preserving the order but keeping only one disjoint "half" each. - // FIXME(eddyb) build a better abstraction for permutations, if possible. - let inverse_memory_index_b: IndexVec = inverse_memory_index - .iter() - .filter_map(|&i| i.as_u32().checked_sub(b_start.as_u32()).map(FieldIdx::from_u32)) - .collect(); - inverse_memory_index.raw.retain(|&i| i < b_start); - let inverse_memory_index_a = inverse_memory_index; - - // Since `inverse_memory_index_{a,b}` each only refer to their - // respective fields, they can be safely inverted - let memory_index_a = inverse_memory_index_a.invert_bijective_mapping(); - let memory_index_b = inverse_memory_index_b.invert_bijective_mapping(); - - let outer_fields = - FieldsShape::Arbitrary { offsets: offsets_a, memory_index: memory_index_a }; - (outer_fields, offsets_b, memory_index_b) - } - _ => bug!(), - }; - - let mut size = prefix.size; - let mut align = prefix.align; - let variants = info - .variant_fields - .iter_enumerated() - .map(|(index, variant_fields)| { - // Only include overlap-eligible fields when we compute our variant layout. - let variant_only_tys = variant_fields - .iter() - .filter(|local| match assignments[**local] { - Unassigned => bug!(), - Assigned(v) if v == index => true, - Assigned(_) => bug!("assignment does not match variant"), - Ineligible(_) => false, - }) - .map(|local| { - let field_ty = instantiate_field(info.field_tys[*local].ty); - Ty::new_maybe_uninit(tcx, field_ty) - }); - - let mut variant = univariant_uninterned( - cx, - ty, - &variant_only_tys.map(|ty| cx.layout_of(ty)).try_collect::>()?, - StructKind::Prefixed(prefix_size, prefix_align.abi), - )?; - variant.variants = Variants::Single { index }; - - let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { - bug!(); - }; - - // Now, stitch the promoted and variant-only fields back together in - // the order they are mentioned by our CoroutineLayout. - // Because we only use some subset (that can differ between variants) - // of the promoted fields, we can't just pick those elements of the - // `promoted_memory_index` (as we'd end up with gaps). - // So instead, we build an "inverse memory_index", as if all of the - // promoted fields were being used, but leave the elements not in the - // subset as `INVALID_FIELD_IDX`, which we can filter out later to - // obtain a valid (bijective) mapping. - const INVALID_FIELD_IDX: FieldIdx = FieldIdx::MAX; - debug_assert!(variant_fields.next_index() <= INVALID_FIELD_IDX); - - let mut combined_inverse_memory_index = IndexVec::from_elem_n( - INVALID_FIELD_IDX, - promoted_memory_index.len() + memory_index.len(), - ); - let mut offsets_and_memory_index = iter::zip(offsets, memory_index); - let combined_offsets = variant_fields - .iter_enumerated() - .map(|(i, local)| { - let (offset, memory_index) = match assignments[*local] { - Unassigned => bug!(), - Assigned(_) => { - let (offset, memory_index) = offsets_and_memory_index.next().unwrap(); - (offset, promoted_memory_index.len() as u32 + memory_index) - } - Ineligible(field_idx) => { - let field_idx = field_idx.unwrap(); - (promoted_offsets[field_idx], promoted_memory_index[field_idx]) - } - }; - combined_inverse_memory_index[memory_index] = i; - offset - }) - .collect(); - - // Remove the unused slots and invert the mapping to obtain the - // combined `memory_index` (also see previous comment). - combined_inverse_memory_index.raw.retain(|&i| i != INVALID_FIELD_IDX); - let combined_memory_index = combined_inverse_memory_index.invert_bijective_mapping(); - - variant.fields = FieldsShape::Arbitrary { - offsets: combined_offsets, - memory_index: combined_memory_index, - }; - - size = size.max(variant.size); - align = align.max(variant.align); - Ok(variant) - }) - .try_collect::>()?; - - size = size.align_to(align.abi); - - let uninhabited = prefix.uninhabited || variants.iter().all(|v| v.is_uninhabited()); - let abi = BackendRepr::Memory { sized: true }; - - // this is similar to how ReprOptions populates its field_shuffle_seed - let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash(); - - let layout = tcx.mk_layout(LayoutData { - variants: Variants::Multiple { - tag, - tag_encoding: TagEncoding::Direct, - tag_field: tag_index, - variants, - }, - fields: outer_fields, - backend_repr: abi, - // Suppress niches inside coroutines. If the niche is inside a field that is aliased (due to - // self-referentiality), getting the discriminant can cause aliasing violations. - // `UnsafeCell` blocks niches for the same reason, but we don't yet have `UnsafePinned` that - // would do the same for us here. - // See , . - // FIXME: Remove when is implemented and aliased coroutine fields are wrapped in `UnsafePinned`. - largest_niche: None, - uninhabited, - size, - align, - max_repr_align: None, - unadjusted_abi_align: align.abi, - randomization_seed: def_hash, - }); - debug!("coroutine layout ({:?}): {:#?}", ty, layout); - Ok(layout) -} - fn record_layout_for_printing<'tcx>(cx: &LayoutCx<'tcx>, layout: TyAndLayout<'tcx>) { // Ignore layouts that are done with non-empty environments or // non-monomorphic layouts, as the user only wants to see the stuff diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 5ea6716c5ca14..7423a156a217a 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -33,7 +33,7 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou fn non_zst_fields<'tcx, 'a>( cx: &'a LayoutCx<'tcx>, layout: &'a TyAndLayout<'tcx>, - ) -> impl Iterator)> + 'a { + ) -> impl Iterator)> { (0..layout.layout.fields().count()).filter_map(|i| { let field = layout.field(cx, i); // Also checking `align == 1` here leads to test failures in @@ -69,31 +69,30 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou } fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { - // Verify the ABI mandated alignment and size. - let align = layout.backend_repr.inherent_align(cx).map(|align| align.abi); - let size = layout.backend_repr.inherent_size(cx); - let Some((align, size)) = align.zip(size) else { - assert_matches!( - layout.layout.backend_repr(), - BackendRepr::Memory { .. }, - "ABI unexpectedly missing alignment and/or size in {layout:#?}" + // Verify the ABI-mandated alignment and size for scalars. + let align = layout.backend_repr.scalar_align(cx); + let size = layout.backend_repr.scalar_size(cx); + if let Some(align) = align { + assert_eq!( + layout.layout.align().abi, + align, + "alignment mismatch between ABI and layout in {layout:#?}" ); - return; - }; - assert_eq!( - layout.layout.align().abi, - align, - "alignment mismatch between ABI and layout in {layout:#?}" - ); - assert_eq!( - layout.layout.size(), - size, - "size mismatch between ABI and layout in {layout:#?}" - ); + } + if let Some(size) = size { + assert_eq!( + layout.layout.size(), + size, + "size mismatch between ABI and layout in {layout:#?}" + ); + } // Verify per-ABI invariants match layout.layout.backend_repr() { BackendRepr::Scalar(_) => { + // These must always be present for `Scalar` types. + let align = align.unwrap(); + let size = size.unwrap(); // Check that this matches the underlying field. let inner = skip_newtypes(cx, layout); assert!( @@ -235,9 +234,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou "`ScalarPair` second field with bad ABI in {inner:#?}", ); } - BackendRepr::Vector { element, .. } => { - assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`. - // FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair. + BackendRepr::SimdVector { element, count } => { + let align = layout.align.abi; + let size = layout.size; + let element_align = element.align(cx).abi; + let element_size = element.size(cx); + // Currently, vectors must always be aligned to at least their elements: + assert!(align >= element_align); + // And the size has to be element * count plus alignment padding, of course + assert!(size == (element_size * count).align_to(align)); } BackendRepr::Memory { .. } => {} // Nothing to check. } diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 8be1611bb9ac2..143b7d538801b 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -6,6 +6,7 @@ // tidy-alphabetical-start #![allow(internal_features)] +#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] #![feature(assert_matches)] @@ -16,7 +17,6 @@ #![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] -#![warn(unreachable_pub)] // tidy-alphabetical-end use rustc_middle::query::Providers; diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 80de7e20951a7..52955ec59a4a0 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -373,7 +373,7 @@ fn drop_tys_helper<'tcx>( fn adt_consider_insignificant_dtor<'tcx>( tcx: TyCtxt<'tcx>, -) -> impl Fn(ty::AdtDef<'tcx>) -> Option + 'tcx { +) -> impl Fn(ty::AdtDef<'tcx>) -> Option { move |adt_def: ty::AdtDef<'tcx>| { let is_marked_insig = tcx.has_attr(adt_def.did(), sym::rustc_insignificant_dtor); if is_marked_insig { diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 98881905bcf88..3aad97d86cca1 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit; use rustc_hir::intravisit::Visitor; -use rustc_hir::{CRATE_HIR_ID, intravisit}; use rustc_middle::bug; use rustc_middle::query::Providers; use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; @@ -30,14 +30,21 @@ enum CollectionMode { /// For impl trait in assoc types we only permit collecting them from /// associated types of the same impl block. ImplTraitInAssocTypes, - TypeAliasImplTraitTransition, + /// When collecting for an explicit `#[define_opaque]` attribute, find all TAITs + Taits, + /// The default case, only collect RPITs and AsyncFn return types, as these are + /// always defined by the current item. + RpitAndAsyncFnOnly, } impl<'tcx> OpaqueTypeCollector<'tcx> { fn new(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self { - let mode = match tcx.def_kind(tcx.local_parent(item)) { - DefKind::Impl { of_trait: true } => CollectionMode::ImplTraitInAssocTypes, - _ => CollectionMode::TypeAliasImplTraitTransition, + let mode = match tcx.def_kind(item) { + DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy => { + CollectionMode::ImplTraitInAssocTypes + } + DefKind::TyAlias => CollectionMode::Taits, + _ => CollectionMode::RpitAndAsyncFnOnly, }; Self { tcx, opaques: Vec::new(), item, seen: Default::default(), span: None, mode } } @@ -73,40 +80,6 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } } - /// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `self.item`. - /// - /// Example: - /// ```ignore UNSOLVED (is this a bug?) - /// # #![feature(type_alias_impl_trait)] - /// pub mod foo { - /// pub mod bar { - /// pub trait Bar { /* ... */ } - /// pub type Baz = impl Bar; - /// - /// # impl Bar for () {} - /// fn f1() -> Baz { /* ... */ } - /// } - /// fn f2() -> bar::Baz { /* ... */ } - /// } - /// ``` - /// - /// and `opaque_def_id` is the `DefId` of the definition of the opaque type `Baz`. - /// For the above example, this function returns `true` for `f1` and `false` for `f2`. - #[instrument(level = "trace", skip(self), ret)] - fn check_tait_defining_scope(&self, opaque_def_id: LocalDefId) -> bool { - let mut hir_id = self.tcx.local_def_id_to_hir_id(self.item); - let opaque_hir_id = self.tcx.local_def_id_to_hir_id(opaque_def_id); - - // Named opaque types can be defined by any siblings or children of siblings. - let scope = self.tcx.hir_get_defining_scope(opaque_hir_id); - // We walk up the node tree until we hit the root or the scope of the opaque type. - while hir_id != scope && hir_id != CRATE_HIR_ID { - hir_id = self.tcx.hir_get_parent_item(hir_id).into(); - } - // Syntactically, we are allowed to define the concrete type if: - hir_id == scope - } - #[instrument(level = "trace", skip(self))] fn collect_taits_declared_in_body(&mut self) { let body = self.tcx.hir_body_owned_by(self.item).value; @@ -139,18 +112,31 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } // TAITs outside their defining scopes are ignored. - let origin = self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local()); - trace!(?origin); - match origin { + match self.tcx.local_opaque_ty_origin(alias_ty.def_id.expect_local()) { rustc_hir::OpaqueTyOrigin::FnReturn { .. } | rustc_hir::OpaqueTyOrigin::AsyncFn { .. } => {} - rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => { - if !in_assoc_ty && !self.check_tait_defining_scope(alias_ty.def_id.expect_local()) { - return; + rustc_hir::OpaqueTyOrigin::TyAlias { in_assoc_ty, .. } => match self.mode { + // If we are collecting opaques in an assoc method, we are only looking at assoc types + // mentioned in the assoc method and only at opaques defined in there. We do not + // want to collect TAITs + CollectionMode::ImplTraitInAssocTypes => { + if !in_assoc_ty { + return; + } } - } + // If we are collecting opaques referenced from a `define_opaque` attribute, we + // do not want to look at opaques defined in associated types. Those can only be + // defined by methods on the same impl. + CollectionMode::Taits => { + if in_assoc_ty { + return; + } + } + CollectionMode::RpitAndAsyncFnOnly => return, + }, } + trace!(?alias_ty, "adding"); self.opaques.push(alias_ty.def_id.expect_local()); let parent_count = self.tcx.generics_of(alias_ty.def_id).parent_count; @@ -192,6 +178,32 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { } } } + + /// Checks the `#[define_opaque]` attributes on items and collectes opaques to define + /// from the referenced types. + #[instrument(level = "trace", skip(self))] + fn collect_taits_from_defines_attr(&mut self) { + let hir_id = self.tcx.local_def_id_to_hir_id(self.item); + if !hir_id.is_owner() { + return; + } + let Some(defines) = self.tcx.hir_attr_map(hir_id.owner).define_opaque else { + return; + }; + for &(span, define) in defines { + trace!(?define); + let mode = std::mem::replace(&mut self.mode, CollectionMode::Taits); + let n = self.opaques.len(); + super::sig_types::walk_types(self.tcx, define, self); + if n == self.opaques.len() { + self.tcx.dcx().span_err(span, "item does not contain any opaque types"); + } + self.mode = mode; + } + // Allow using `#[define_opaque]` on assoc methods and type aliases to override the default collection mode in + // case it was capturing too much. + self.mode = CollectionMode::RpitAndAsyncFnOnly; + } } impl<'tcx> super::sig_types::SpannedTypeVisitor<'tcx> for OpaqueTypeCollector<'tcx> { @@ -210,6 +222,7 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { self.visit_opaque_ty(alias_ty); } // Skips type aliases, as they are meant to be transparent. + // FIXME(type_alias_impl_trait): can we require mentioning nested type aliases explicitly? ty::Alias(ty::Weak, alias_ty) if alias_ty.def_id.is_local() => { self.tcx .type_of(alias_ty.def_id) @@ -283,28 +296,6 @@ impl<'tcx> TypeVisitor> for OpaqueTypeCollector<'tcx> { self.visit_opaque_ty(alias_ty); } } - ty::Adt(def, _) if def.did().is_local() => { - if let CollectionMode::ImplTraitInAssocTypes = self.mode { - return; - } - if !self.seen.insert(def.did().expect_local()) { - return; - } - for variant in def.variants().iter() { - for field in variant.fields.iter() { - // Don't use the `ty::Adt` args, we either - // * found the opaque in the args - // * will find the opaque in the uninstantiated fields - // The only other situation that can occur is that after instantiating, - // some projection resolves to an opaque that we would have otherwise - // not found. While we could instantiate and walk those, that would mean we - // would have to walk all generic parameters of an Adt, which can quickly - // degenerate into looking at an exponential number of types. - let ty = self.tcx.type_of(field.did).instantiate_identity(); - self.visit_spanned(self.tcx.def_span(field.did), ty); - } - } - } _ => trace!(kind=?t.kind()), } } @@ -317,7 +308,9 @@ fn opaque_types_defined_by<'tcx>( let kind = tcx.def_kind(item); trace!(?kind); let mut collector = OpaqueTypeCollector::new(tcx, item); + collector.collect_taits_from_defines_attr(); super::sig_types::walk_types(tcx, item, &mut collector); + match kind { DefKind::AssocFn | DefKind::Fn @@ -350,8 +343,7 @@ fn opaque_types_defined_by<'tcx>( | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::SyntheticCoroutineBody => {} - // Closures and coroutines are type checked with their parent, so we need to allow all - // opaques from the closure signature *and* from the parent body. + // Closures and coroutines are type checked with their parent DefKind::Closure | DefKind::InlineConst => { collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item))); } diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index d6f9277813d12..5bb96f90029ae 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -4,10 +4,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::span_bug; -use rustc_middle::ty::visit::{VisitorResult, try_visit}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt, TypeVisitable, VisitorResult, try_visit}; use rustc_span::Span; -use rustc_type_ir::visit::TypeVisitable; use tracing::{instrument, trace}; pub trait SpannedTypeVisitor<'tcx> { diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 8ed45b4e5415b..9dc4f11e456e2 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -5,57 +5,59 @@ use rustc_hir::def::DefKind; use rustc_index::bit_set::DenseBitSet; use rustc_middle::bug; use rustc_middle::query::Providers; -use rustc_middle::ty::fold::fold_regions; use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, fold_regions, }; use rustc_span::DUMMY_SP; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_trait_selection::traits; -use tracing::{debug, instrument}; +use tracing::instrument; #[instrument(level = "debug", skip(tcx), ret)] fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option> { - use rustc_type_ir::TyKind::*; - match ty.kind() { // these are always sized - Bool - | Char - | Int(..) - | Uint(..) - | Float(..) - | RawPtr(..) - | Ref(..) - | FnDef(..) - | FnPtr(..) - | Array(..) - | Closure(..) - | CoroutineClosure(..) - | Coroutine(..) - | CoroutineWitness(..) - | Never - | Dynamic(_, _, ty::DynStar) => None, - - UnsafeBinder(_) => todo!(), + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::Array(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Never + | ty::Dynamic(_, _, ty::DynStar) => None, // these are never sized - Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty), + ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => Some(ty), - Pat(ty, _) => sized_constraint_for_ty(tcx, *ty), + ty::Pat(ty, _) => sized_constraint_for_ty(tcx, *ty), - Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)), + ty::Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)), // recursive case - Adt(adt, args) => adt.sized_constraint(tcx).and_then(|intermediate| { + ty::Adt(adt, args) => adt.sized_constraint(tcx).and_then(|intermediate| { let ty = intermediate.instantiate(tcx, args); sized_constraint_for_ty(tcx, ty) }), - // these can be sized or unsized - Param(..) | Alias(..) | Error(_) => Some(ty), + // these can be sized or unsized. + ty::Param(..) | ty::Alias(..) | ty::Error(_) => Some(ty), + + // We cannot instantiate the binder, so just return the *original* type back, + // but only if the inner type has a sized constraint. Thus we skip the binder, + // but don't actually use the result from `sized_constraint_for_ty`. + ty::UnsafeBinder(inner_ty) => { + sized_constraint_for_ty(tcx, inner_ty.skip_binder()).map(|_| ty) + } - Placeholder(..) | Bound(..) | Infer(..) => { + ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => { bug!("unexpected type `{ty:?}` in sized_constraint_for_ty") } } @@ -257,57 +259,6 @@ fn param_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty: typing_env.with_post_analysis_normalized(tcx).param_env } -/// If the given trait impl enables exploiting the former order dependence of trait objects, -/// returns its self type; otherwise, returns `None`. -/// -/// See [`ty::ImplOverlapKind::FutureCompatOrderDepTraitObjects`] for more details. -#[instrument(level = "debug", skip(tcx))] -fn self_ty_of_trait_impl_enabling_order_dep_trait_object_hack( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> Option>> { - let impl_ = - tcx.impl_trait_header(def_id).unwrap_or_else(|| bug!("called on inherent impl {def_id:?}")); - - let trait_ref = impl_.trait_ref.skip_binder(); - debug!(?trait_ref); - - let is_marker_like = impl_.polarity == ty::ImplPolarity::Positive - && tcx.associated_item_def_ids(trait_ref.def_id).is_empty(); - - // Check whether these impls would be ok for a marker trait. - if !is_marker_like { - debug!("not marker-like!"); - return None; - } - - // impl must be `impl Trait for dyn Marker1 + Marker2 + ...` - if trait_ref.args.len() != 1 { - debug!("impl has args!"); - return None; - } - - let predicates = tcx.predicates_of(def_id); - if predicates.parent.is_some() || !predicates.predicates.is_empty() { - debug!(?predicates, "impl has predicates!"); - return None; - } - - let self_ty = trait_ref.self_ty(); - let self_ty_matches = match self_ty.kind() { - ty::Dynamic(data, re, _) if re.is_static() => data.principal().is_none(), - _ => false, - }; - - if self_ty_matches { - debug!("MATCHES!"); - Some(EarlyBinder::bind(self_ty)) - } else { - debug!("non-matching self type"); - None - } -} - /// Check if a function is async. fn asyncness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Asyncness { let node = tcx.hir_node_by_def_id(def_id); @@ -367,7 +318,6 @@ pub(crate) fn provide(providers: &mut Providers) { adt_sized_constraint, param_env, param_env_normalized_for_post_analysis, - self_ty_of_trait_impl_enabling_order_dep_trait_object_hack, defaultness, unsizing_params_for_adt, ..*providers diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml index 8d97ec728304e..4adf715792666 100644 --- a/compiler/rustc_type_ir/Cargo.toml +++ b/compiler/rustc_type_ir/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_type_ir" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] # tidy-alphabetical-start @@ -16,7 +16,7 @@ rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_span = { path = "../rustc_span", optional = true } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } -smallvec = { version = "1.8.1", default-features = false } +smallvec = { version = "1.8.1", default-features = false, features = ["const_generics"] } thin-vec = "0.2.12" tracing = "0.1" # tidy-alphabetical-end @@ -33,6 +33,3 @@ nightly = [ "rustc_index/nightly", "rustc_ast_ir/nightly", ] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 0d0092ea1aa08..c8b71074de7b4 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -5,7 +5,7 @@ use std::ops::{ControlFlow, Deref}; use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use tracing::instrument; use crate::data_structures::SsoHashSet; @@ -57,7 +57,7 @@ where macro_rules! impl_binder_encode_decode { ($($t:ty),+ $(,)?) => { $( - impl> rustc_serialize::Encodable for ty::Binder + impl rustc_serialize::Encodable for ty::Binder where $t: rustc_serialize::Encodable, I::BoundVarKinds: rustc_serialize::Encodable, @@ -67,7 +67,7 @@ macro_rules! impl_binder_encode_decode { self.as_ref().skip_binder().encode(e); } } - impl> rustc_serialize::Decodable for ty::Binder + impl rustc_serialize::Decodable for ty::Binder where $t: TypeVisitable + rustc_serialize::Decodable, I::BoundVarKinds: rustc_serialize::Decodable, @@ -342,7 +342,10 @@ impl TypeVisitor for ValidateBoundVars { #[derive_where(PartialOrd; I: Interner, T: Ord)] #[derive_where(Hash; I: Interner, T: Hash)] #[derive_where(Debug; I: Interner, T: Debug)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub struct EarlyBinder { value: T, #[derive_where(skip(Debug))] @@ -859,7 +862,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> { if self.binders_passed == 0 || !val.has_escaping_bound_vars() { val } else { - ty::fold::shift_vars(self.cx, val, self.binders_passed) + ty::shift_vars(self.cx, val, self.binders_passed) } } @@ -867,7 +870,7 @@ impl<'a, I: Interner> ArgFolder<'a, I> { if self.binders_passed == 0 || !region.has_escaping_bound_vars() { region } else { - ty::fold::shift_region(self.cx, region, self.binders_passed) + ty::shift_region(self.cx, region, self.binders_passed) } } } diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 24b2ebc1fbe79..03d3194f1065d 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -4,7 +4,7 @@ use std::ops::Index; use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; @@ -16,7 +16,10 @@ use crate::{self as ty, Interner, TypingMode, UniverseIndex}; #[derive_where(Eq; I: Interner, V: Eq)] #[derive_where(Debug; I: Interner, V: fmt::Debug)] #[derive_where(Copy; I: Interner, V: Copy)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub struct CanonicalQueryInput { pub canonical: Canonical, pub typing_mode: TypingMode, @@ -32,7 +35,10 @@ pub struct CanonicalQueryInput { #[derive_where(Debug; I: Interner, V: fmt::Debug)] #[derive_where(Copy; I: Interner, V: Copy)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub struct Canonical { pub value: V, pub max_universe: UniverseIndex, @@ -85,7 +91,10 @@ impl fmt::Display for Canonical { /// with fresh inference variables replacing the canonical values. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct CanonicalVarInfo { pub kind: CanonicalVarKind, } @@ -139,7 +148,10 @@ impl CanonicalVarInfo { /// that analyzes type-like values. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum CanonicalVarKind { /// Some kind of type inference variable. Ty(CanonicalTyVarKind), @@ -213,7 +225,10 @@ impl CanonicalVarKind { /// know what set of types a given type variable can be unified with. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum CanonicalTyVarKind { /// General type variable `?T` that can be unified with arbitrary types. General(UniverseIndex), @@ -235,7 +250,10 @@ pub enum CanonicalTyVarKind { /// variables. You will need to supply it later to instantiate the /// canonicalized query response. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CanonicalVarValues { pub var_values: I::GenericArgs, diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs deleted file mode 100644 index f443f596373fb..0000000000000 --- a/compiler/rustc_type_ir/src/codec.rs +++ /dev/null @@ -1,61 +0,0 @@ -use rustc_data_structures::fx::FxHashMap; -use rustc_span::{SpanDecoder, SpanEncoder}; - -use crate::{Interner, PredicateKind}; - -/// The shorthand encoding uses an enum's variant index `usize` -/// and is offset by this value so it never matches a real variant. -/// This offset is also chosen so that the first byte is never < 0x80. -pub const SHORTHAND_OFFSET: usize = 0x80; - -/// Trait for decoding to a reference. -/// -/// This is a separate trait from `Decodable` so that we can implement it for -/// upstream types, such as `FxHashSet`. -/// -/// The `TyDecodable` derive macro will use this trait for fields that are -/// references (and don't use a type alias to hide that). -/// -/// `Decodable` can still be implemented in cases where `Decodable` is required -/// by a trait bound. -pub trait RefDecodable<'tcx, D: TyDecoder> { - fn decode(d: &mut D) -> &'tcx Self; -} - -pub trait TyEncoder: SpanEncoder { - type I: Interner; - const CLEAR_CROSS_CRATE: bool; - - fn position(&self) -> usize; - - fn type_shorthands(&mut self) -> &mut FxHashMap<::Ty, usize>; - - fn predicate_shorthands(&mut self) -> &mut FxHashMap, usize>; - - fn encode_alloc_id(&mut self, alloc_id: &::AllocId); -} - -pub trait TyDecoder: SpanDecoder { - type I: Interner; - const CLEAR_CROSS_CRATE: bool; - - fn interner(&self) -> Self::I; - - fn cached_ty_for_shorthand( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> ::Ty - where - F: FnOnce(&mut Self) -> ::Ty; - - fn with_position(&mut self, pos: usize, f: F) -> R - where - F: FnOnce(&mut Self) -> R; - - fn positioned_at_shorthand(&self) -> bool { - (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0 - } - - fn decode_alloc_id(&mut self) -> ::AllocId; -} diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index aafc0907ae156..70a8509b51339 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -4,14 +4,17 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::{self as ty, DebruijnIndex, Interner}; /// Represents a constant in Rust. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum ConstKind { /// A const generic parameter. Param(I::ParamConst), @@ -62,7 +65,10 @@ impl fmt::Debug for ConstKind { /// An unevaluated (potentially generic) constant used in the type-system. #[derive_where(Clone, Copy, Debug, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct UnevaluatedConst { pub def: I::DefId, pub args: I::GenericArgs, @@ -86,7 +92,7 @@ rustc_index::newtype_index! { /// An inference variable for a const, for use in const generics. #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] +#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))] pub enum InferConst { /// Infer the value of the const. Var(ConstVid), diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 9955e92b55a5c..11ec1f0a9fb0e 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fingerprint::Fingerprint; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use crate::inherent::*; use crate::visit::TypeVisitableExt as _; @@ -17,7 +17,10 @@ use crate::{self as ty, Interner}; /// See `simplify_type`. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum SimplifiedType { Bool, Char, diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs index 008268c3bffad..c18cade0e39bc 100644 --- a/compiler/rustc_type_ir/src/generic_arg.rs +++ b/compiler/rustc_type_ir/src/generic_arg.rs @@ -1,11 +1,14 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use crate::Interner; #[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum GenericArgKind { Lifetime(I::Region), Type(I::Ty), @@ -13,7 +16,10 @@ pub enum GenericArgKind { } #[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum TermKind { Ty(I::Ty), Const(I::Const), diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index c9b636132f807..26c4951069626 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -1,6 +1,6 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::fold::TypeFoldable; @@ -20,7 +20,10 @@ use crate::{self as ty, Interner}; /// t-types for help. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum TypingMode { /// When checking whether impls overlap, we check whether any obligations /// are guaranteed to never hold when unifying the impls. This requires us @@ -151,7 +154,7 @@ pub trait InferCtxtLike: Sized { value: ty::Binder, ) -> T; - fn enter_forall + Copy, U>( + fn enter_forall, U>( &self, value: ty::Binder, f: impl FnOnce(T) -> U, diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 9277226b718b1..d4134bdf3a782 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -462,8 +462,6 @@ pub trait Predicate>: { fn as_clause(self) -> Option; - fn is_coinductive(self, interner: I) -> bool; - // FIXME: Eventually uplift the impl out of rustc and make this defaulted. fn allow_normalization(self) -> bool; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index aae2d2e96b96f..e765cb66d00a3 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -189,10 +189,10 @@ pub trait Interner: type Features: Features; fn features(self) -> Self::Features; - fn bound_coroutine_hidden_types( + fn coroutine_hidden_types( self, def_id: Self::DefId, - ) -> impl IntoIterator>>; + ) -> ty::EarlyBinder>; fn fn_sig( self, @@ -279,6 +279,8 @@ pub trait Interner: fn trait_is_auto(self, trait_def_id: Self::DefId) -> bool; + fn trait_is_coinductive(self, trait_def_id: Self::DefId) -> bool; + fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool; fn trait_is_dyn_compatible(self, trait_def_id: Self::DefId) -> bool; diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 15ef4e7d6c1d2..6291218950917 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -6,7 +6,6 @@ feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] #![cfg_attr(feature = "nightly", allow(internal_features))] -#![warn(unreachable_pub)] // tidy-alphabetical-end extern crate self as rustc_type_ir; @@ -18,15 +17,10 @@ use std::hash::Hash; use rustc_macros::{Decodable, Encodable, HashStable_NoContext}; // These modules are `pub` since they are not glob-imported. -#[macro_use] -pub mod visit; -#[cfg(feature = "nightly")] -pub mod codec; pub mod data_structures; pub mod elaborate; pub mod error; pub mod fast_reject; -pub mod fold; #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_inherent")] pub mod inherent; pub mod ir_print; @@ -44,6 +38,7 @@ mod binder; mod canonical; mod const_kind; mod flags; +mod fold; mod generic_arg; mod infer_ctxt; mod interner; @@ -54,6 +49,7 @@ mod region_kind; mod ty_info; mod ty_kind; mod upcast; +mod visit; pub use AliasTyKind::*; pub use DynKind::*; @@ -63,10 +59,9 @@ pub use TyKind::*; pub use Variance::*; pub use binder::*; pub use canonical::*; -#[cfg(feature = "nightly")] -pub use codec::*; pub use const_kind::*; pub use flags::*; +pub use fold::*; pub use generic_arg::*; pub use infer_ctxt::*; pub use interner::*; @@ -78,6 +73,7 @@ pub use rustc_ast_ir::{Movability, Mutability, Pinnedness}; pub use ty_info::*; pub use ty_kind::*; pub use upcast::*; +pub use visit::*; rustc_index::newtype_index! { /// A [De Bruijn index][dbi] is a standard means of representing diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index 6d61a52723aeb..416d355fd03bd 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -1,6 +1,6 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; @@ -8,7 +8,10 @@ use crate::{self as ty, Interner}; #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub struct OpaqueTypeKey { pub def_id: I::LocalDefId, pub args: I::GenericArgs, diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 51790b13ec776..22d0fa23d0c56 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -3,7 +3,9 @@ use std::hash::Hash; use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{ + Decodable, Decodable_NoContext, Encodable, Encodable_NoContext, HashStable_NoContext, +}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; @@ -20,7 +22,10 @@ use crate::{self as ty, Interner}; #[derive_where(Eq; I: Interner, A: Eq)] #[derive_where(Debug; I: Interner, A: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct OutlivesPredicate(pub A, pub I::Region); // FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't @@ -50,7 +55,10 @@ where /// that case the `Self` parameter is absent from the generic parameters. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct TraitRef { pub def_id: I::DefId, pub args: I::GenericArgs, @@ -122,7 +130,10 @@ impl ty::Binder> { #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct TraitPredicate { pub trait_ref: TraitRef, @@ -131,8 +142,6 @@ pub struct TraitPredicate { /// If polarity is Negative: we are proving that a negative impl of this trait /// exists. (Note that coherence also checks whether negative impls of supertraits /// exist via a series of predicates.) - /// - /// If polarity is Reserved: that's a bug. pub polarity: PredicatePolarity, } @@ -179,7 +188,10 @@ impl fmt::Debug for TraitPredicate { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum ImplPolarity { /// `impl Trait for Type` Positive, @@ -217,7 +229,10 @@ impl ImplPolarity { /// Distinguished from [`ImplPolarity`] since we never compute goals with /// "reservation" level. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum PredicatePolarity { /// `Type: Trait` Positive, @@ -246,7 +261,10 @@ impl fmt::Display for PredicatePolarity { #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum ExistentialPredicate { /// E.g., `Iterator`. Trait(ExistentialTraitRef), @@ -291,7 +309,10 @@ impl ty::Binder> { /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct ExistentialTraitRef { pub def_id: I::DefId, pub args: I::GenericArgs, @@ -355,7 +376,10 @@ impl ty::Binder> { /// A `ProjectionPredicate` for an `ExistentialTraitRef`. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct ExistentialProjection { pub def_id: I::DefId, pub args: I::GenericArgs, @@ -487,7 +511,10 @@ impl From for AliasTermKind { /// * For an opaque type, there is no explicit syntax. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct AliasTerm { /// The parameters of the associated or opaque item. /// @@ -658,7 +685,10 @@ impl From> for AliasTerm { /// instances to normalize the LHS. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct ProjectionPredicate { pub projection_term: AliasTerm, pub term: I::Term, @@ -713,7 +743,10 @@ impl fmt::Debug for ProjectionPredicate { /// be an unconstrained inference variable which is used as the output. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct NormalizesTo { pub alias: AliasTerm, pub term: I::Term, @@ -745,7 +778,10 @@ impl fmt::Debug for NormalizesTo { #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub struct HostEffectPredicate { pub trait_ref: ty::TraitRef, pub constness: BoundConstness, @@ -786,7 +822,10 @@ impl ty::Binder> { /// presenting user diagnostics. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct SubtypePredicate { pub a_is_expected: bool, pub a: I::Ty, @@ -796,14 +835,20 @@ pub struct SubtypePredicate { /// Encodes that we have to coerce *from* the `a` type to the `b` type. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct CoercePredicate { pub a: I::Ty, pub b: I::Ty, } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum BoundConstness { /// `Type: const Trait` /// diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 21f4456abd114..847dff156fe87 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -2,7 +2,7 @@ use std::fmt; use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::{self as ty, Interner}; @@ -11,7 +11,10 @@ use crate::{self as ty, Interner}; /// by implied bounds. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum ClauseKind { /// Corresponds to `where Foo: Bar`. `Foo` here would be /// the `Self` type of the trait reference and `A`, `B`, and `C` @@ -47,7 +50,10 @@ pub enum ClauseKind { #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum PredicateKind { /// Prove a clause Clause(ClauseKind), @@ -97,7 +103,10 @@ pub enum PredicateKind { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] -#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, Encodable, Decodable))] +#[cfg_attr( + feature = "nightly", + derive(HashStable_NoContext, Encodable_NoContext, Decodable_NoContext) +)] pub enum AliasRelationDirection { Equate, Subtype, diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index e0b3973700783..eae3213ead0d0 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -4,7 +4,7 @@ use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use self::RegionKind::*; use crate::{DebruijnIndex, Interner}; @@ -126,7 +126,7 @@ rustc_index::newtype_index! { /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))] +#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))] pub enum RegionKind { /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. /// diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs index 3cc2dcbaca6d3..1acd5d5c2af4b 100644 --- a/compiler/rustc_type_ir/src/search_graph/mod.rs +++ b/compiler/rustc_type_ir/src/search_graph/mod.rs @@ -12,13 +12,16 @@ /// The global cache has to be completely unobservable, while the per-cycle cache may impact /// behavior as long as the resulting behavior is still correct. use std::cmp::Ordering; -use std::collections::BTreeSet; +use std::collections::BTreeMap; +use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; use derive_where::derive_where; use rustc_index::{Idx, IndexVec}; +#[cfg(feature = "nightly")] +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use tracing::debug; use crate::data_structures::HashMap; @@ -104,27 +107,66 @@ pub trait Delegate { for_input: ::Input, from_result: ::Result, ) -> ::Result; - - fn step_is_coinductive(cx: Self::Cx, input: ::Input) -> bool; } /// In the initial iteration of a cycle, we do not yet have a provisional /// result. In the case we return an initial provisional result depending /// on the kind of cycle. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub enum PathKind { - Coinductive, + /// A path consisting of only inductive/unproductive steps. Their initial + /// provisional result is `Err(NoSolution)`. We currently treat them as + /// `PathKind::Unknown` during coherence until we're fully confident in + /// our approach. Inductive, + /// A path which is not be coinductive right now but we may want + /// to change of them to be so in the future. We return an ambiguous + /// result in this case to prevent people from relying on this. + Unknown, + /// A path with at least one coinductive step. Such cycles hold. + Coinductive, } +impl PathKind { + /// Returns the path kind when merging `self` with `rest`. + /// + /// Given an inductive path `self` and a coinductive path `rest`, + /// the path `self -> rest` would be coinductive. + /// + /// This operation represents an ordering and would be equivalent + /// to `max(self, rest)`. + fn extend(self, rest: PathKind) -> PathKind { + match (self, rest) { + (PathKind::Coinductive, _) | (_, PathKind::Coinductive) => PathKind::Coinductive, + (PathKind::Unknown, _) | (_, PathKind::Unknown) => PathKind::Unknown, + (PathKind::Inductive, PathKind::Inductive) => PathKind::Inductive, + } + } +} + +/// The kinds of cycles a cycle head was involved in. +/// +/// This is used to avoid rerunning a cycle if there's +/// just a single usage kind and the final result matches +/// its provisional result. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UsageKind { Single(PathKind), Mixed, } +impl From for UsageKind { + fn from(path: PathKind) -> UsageKind { + UsageKind::Single(path) + } +} impl UsageKind { - fn merge(self, other: Self) -> Self { - match (self, other) { + #[must_use] + fn merge(self, other: impl Into) -> Self { + match (self, other.into()) { (UsageKind::Mixed, _) | (_, UsageKind::Mixed) => UsageKind::Mixed, (UsageKind::Single(lhs), UsageKind::Single(rhs)) => { if lhs == rhs { @@ -135,7 +177,39 @@ impl UsageKind { } } } - fn and_merge(&mut self, other: Self) { +} + +/// For each goal we track whether the paths from this goal +/// to its cycle heads are coinductive. +/// +/// This is a necessary condition to rebase provisional cache +/// entries. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum AllPathsToHeadCoinductive { + Yes, + No, +} +impl From for AllPathsToHeadCoinductive { + fn from(path: PathKind) -> AllPathsToHeadCoinductive { + match path { + PathKind::Coinductive => AllPathsToHeadCoinductive::Yes, + _ => AllPathsToHeadCoinductive::No, + } + } +} +impl AllPathsToHeadCoinductive { + #[must_use] + fn merge(self, other: impl Into) -> Self { + match (self, other.into()) { + (AllPathsToHeadCoinductive::Yes, AllPathsToHeadCoinductive::Yes) => { + AllPathsToHeadCoinductive::Yes + } + (AllPathsToHeadCoinductive::No, _) | (_, AllPathsToHeadCoinductive::No) => { + AllPathsToHeadCoinductive::No + } + } + } + fn and_merge(&mut self, other: impl Into) { *self = self.merge(other); } } @@ -177,10 +251,11 @@ impl AvailableDepth { /// All cycle heads a given goal depends on, ordered by their stack depth. /// -/// We therefore pop the cycle heads from highest to lowest. +/// We also track all paths from this goal to that head. This is necessary +/// when rebasing provisional cache results. #[derive(Clone, Debug, PartialEq, Eq, Default)] struct CycleHeads { - heads: BTreeSet, + heads: BTreeMap, } impl CycleHeads { @@ -189,15 +264,15 @@ impl CycleHeads { } fn highest_cycle_head(&self) -> StackDepth { - *self.heads.last().unwrap() + self.opt_highest_cycle_head().unwrap() } fn opt_highest_cycle_head(&self) -> Option { - self.heads.last().copied() + self.heads.last_key_value().map(|(k, _)| *k) } fn opt_lowest_cycle_head(&self) -> Option { - self.heads.first().copied() + self.heads.first_key_value().map(|(k, _)| *k) } fn remove_highest_cycle_head(&mut self) { @@ -205,29 +280,100 @@ impl CycleHeads { debug_assert_ne!(last, None); } - fn insert(&mut self, head: StackDepth) { - self.heads.insert(head); + fn insert( + &mut self, + head: StackDepth, + path_from_entry: impl Into + Copy, + ) { + self.heads.entry(head).or_insert(path_from_entry.into()).and_merge(path_from_entry); } fn merge(&mut self, heads: &CycleHeads) { - for &head in heads.heads.iter() { - self.insert(head); + for (&head, &path_from_entry) in heads.heads.iter() { + self.insert(head, path_from_entry); + debug_assert!(matches!(self.heads[&head], AllPathsToHeadCoinductive::Yes)); } } + fn iter(&self) -> impl Iterator + '_ { + self.heads.iter().map(|(k, v)| (*k, *v)) + } + /// Update the cycle heads of a goal at depth `this` given the cycle heads /// of a nested goal. This merges the heads after filtering the parent goal /// itself. - fn extend_from_child(&mut self, this: StackDepth, child: &CycleHeads) { - for &head in child.heads.iter() { + fn extend_from_child(&mut self, this: StackDepth, step_kind: PathKind, child: &CycleHeads) { + for (&head, &path_from_entry) in child.heads.iter() { match head.cmp(&this) { Ordering::Less => {} Ordering::Equal => continue, Ordering::Greater => unreachable!(), } - self.insert(head); + let path_from_entry = match step_kind { + PathKind::Coinductive => AllPathsToHeadCoinductive::Yes, + PathKind::Unknown | PathKind::Inductive => path_from_entry, + }; + + self.insert(head, path_from_entry); + } + } +} + +bitflags::bitflags! { + /// Tracks how nested goals have been accessed. This is necessary to disable + /// global cache entries if computing them would otherwise result in a cycle or + /// access a provisional cache entry. + #[derive(Debug, Clone, Copy)] + pub struct PathsToNested: u8 { + /// The initial value when adding a goal to its own nested goals. + const EMPTY = 1 << 0; + const INDUCTIVE = 1 << 1; + const UNKNOWN = 1 << 2; + const COINDUCTIVE = 1 << 3; + } +} +impl From for PathsToNested { + fn from(path: PathKind) -> PathsToNested { + match path { + PathKind::Inductive => PathsToNested::INDUCTIVE, + PathKind::Unknown => PathsToNested::UNKNOWN, + PathKind::Coinductive => PathsToNested::COINDUCTIVE, + } + } +} +impl PathsToNested { + /// The implementation of this function is kind of ugly. We check whether + /// there currently exist 'weaker' paths in the set, if so we upgrade these + /// paths to at least `path`. + #[must_use] + fn extend_with(mut self, path: PathKind) -> Self { + match path { + PathKind::Inductive => { + if self.intersects(PathsToNested::EMPTY) { + self.remove(PathsToNested::EMPTY); + self.insert(PathsToNested::INDUCTIVE); + } + } + PathKind::Unknown => { + if self.intersects(PathsToNested::EMPTY | PathsToNested::INDUCTIVE) { + self.remove(PathsToNested::EMPTY | PathsToNested::INDUCTIVE); + self.insert(PathsToNested::UNKNOWN); + } + } + PathKind::Coinductive => { + if self.intersects( + PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN, + ) { + self.remove( + PathsToNested::EMPTY | PathsToNested::INDUCTIVE | PathsToNested::UNKNOWN, + ); + self.insert(PathsToNested::COINDUCTIVE); + } + } } + + self } } @@ -246,23 +392,19 @@ impl CycleHeads { /// We need to disable the global cache if using it would hide a cycle, as /// cycles can impact behavior. The cycle ABA may have different final /// results from a the cycle BAB depending on the cycle root. -#[derive_where(Debug, Default; X: Cx)] +#[derive_where(Debug, Default, Clone; X: Cx)] struct NestedGoals { - nested_goals: HashMap, + nested_goals: HashMap, } impl NestedGoals { fn is_empty(&self) -> bool { self.nested_goals.is_empty() } - fn insert(&mut self, input: X::Input, path_from_entry: UsageKind) { - self.nested_goals.entry(input).or_insert(path_from_entry).and_merge(path_from_entry); - } - - fn merge(&mut self, nested_goals: &NestedGoals) { - #[allow(rustc::potential_query_instability)] - for (input, path_from_entry) in nested_goals.iter() { - self.insert(input, path_from_entry); + fn insert(&mut self, input: X::Input, paths_to_nested: PathsToNested) { + match self.nested_goals.entry(input) { + Entry::Occupied(mut entry) => *entry.get_mut() |= paths_to_nested, + Entry::Vacant(entry) => drop(entry.insert(paths_to_nested)), } } @@ -274,25 +416,18 @@ impl NestedGoals { /// the same as for the child. fn extend_from_child(&mut self, step_kind: PathKind, nested_goals: &NestedGoals) { #[allow(rustc::potential_query_instability)] - for (input, path_from_entry) in nested_goals.iter() { - let path_from_entry = match step_kind { - PathKind::Coinductive => path_from_entry, - PathKind::Inductive => UsageKind::Single(PathKind::Inductive), - }; - self.insert(input, path_from_entry); + for (input, paths_to_nested) in nested_goals.iter() { + let paths_to_nested = paths_to_nested.extend_with(step_kind); + self.insert(input, paths_to_nested); } } #[cfg_attr(feature = "nightly", rustc_lint_query_instability)] #[allow(rustc::potential_query_instability)] - fn iter(&self) -> impl Iterator + '_ { + fn iter(&self) -> impl Iterator + '_ { self.nested_goals.iter().map(|(i, p)| (*i, *p)) } - fn get(&self, input: X::Input) -> Option { - self.nested_goals.get(&input).copied() - } - fn contains(&self, input: X::Input) -> bool { self.nested_goals.contains_key(&input) } @@ -310,6 +445,12 @@ rustc_index::newtype_index! { struct StackEntry { input: X::Input, + /// Whether proving this goal is a coinductive step. + /// + /// This is used when encountering a trait solver cycle to + /// decide whether the initial provisional result of the cycle. + step_kind_from_parent: PathKind, + /// The available depth of a given goal, immutable. available_depth: AvailableDepth, @@ -346,9 +487,9 @@ struct ProvisionalCacheEntry { encountered_overflow: bool, /// All cycle heads this cache entry depends on. heads: CycleHeads, - /// The path from the highest cycle head to this goal. + /// The path from the highest cycle head to this goal. This differs from + /// `heads` which tracks the path to the cycle head *from* this goal. path_from_head: PathKind, - nested_goals: NestedGoals, result: X::Result, } @@ -367,6 +508,20 @@ pub struct SearchGraph, X: Cx = ::Cx> { _marker: PhantomData, } +/// While [`SearchGraph::update_parent_goal`] can be mostly shared between +/// ordinary nested goals/global cache hits and provisional cache hits, +/// using the provisional cache should not add any nested goals. +/// +/// `nested_goals` are only used when checking whether global cache entries +/// are applicable. This only cares about whether a goal is actually accessed. +/// Given that the usage of the provisional cache is fully determinstic, we +/// don't need to track the nested goals used while computing a provisional +/// cache entry. +enum UpdateParentGoalCtxt<'a, X: Cx> { + Ordinary(&'a NestedGoals), + ProvisionalCacheHit, +} + impl, X: Cx> SearchGraph { pub fn new(root_depth: usize) -> SearchGraph { Self { @@ -382,27 +537,32 @@ impl, X: Cx> SearchGraph { /// and using existing global cache entries to make sure they /// have the same impact on the remaining evaluation. fn update_parent_goal( - cx: X, stack: &mut IndexVec>, + step_kind_from_parent: PathKind, reached_depth: StackDepth, heads: &CycleHeads, encountered_overflow: bool, - nested_goals: &NestedGoals, + context: UpdateParentGoalCtxt<'_, X>, ) { if let Some(parent_index) = stack.last_index() { let parent = &mut stack[parent_index]; parent.reached_depth = parent.reached_depth.max(reached_depth); parent.encountered_overflow |= encountered_overflow; - parent.heads.extend_from_child(parent_index, heads); - let step_kind = Self::step_kind(cx, parent.input); - parent.nested_goals.extend_from_child(step_kind, nested_goals); + parent.heads.extend_from_child(parent_index, step_kind_from_parent, heads); + let parent_depends_on_cycle = match context { + UpdateParentGoalCtxt::Ordinary(nested_goals) => { + parent.nested_goals.extend_from_child(step_kind_from_parent, nested_goals); + !nested_goals.is_empty() + } + UpdateParentGoalCtxt::ProvisionalCacheHit => true, + }; // Once we've got goals which encountered overflow or a cycle, // we track all goals whose behavior may depend depend on these // goals as this change may cause them to now depend on additional // goals, resulting in new cycles. See the dev-guide for examples. - if !nested_goals.is_empty() { - parent.nested_goals.insert(parent.input, UsageKind::Single(PathKind::Coinductive)) + if parent_depends_on_cycle { + parent.nested_goals.insert(parent.input, PathsToNested::EMPTY); } } } @@ -422,21 +582,19 @@ impl, X: Cx> SearchGraph { self.stack.len() } - fn step_kind(cx: X, input: X::Input) -> PathKind { - if D::step_is_coinductive(cx, input) { PathKind::Coinductive } else { PathKind::Inductive } - } - /// Whether the path from `head` to the current stack entry is inductive or coinductive. - fn stack_path_kind( - cx: X, + /// + /// The `step_kind_to_head` is used to add a single additional path segment to the path on + /// the stack which completes the cycle. This given an inductive step AB which then cycles + /// coinductively with A, we need to treat this cycle as coinductive. + fn cycle_path_kind( stack: &IndexVec>, + step_kind_to_head: PathKind, head: StackDepth, ) -> PathKind { - if stack.raw[head.index()..].iter().all(|entry| D::step_is_coinductive(cx, entry.input)) { - PathKind::Coinductive - } else { - PathKind::Inductive - } + stack.raw[head.index() + 1..] + .iter() + .fold(step_kind_to_head, |curr, entry| curr.extend(entry.step_kind_from_parent)) } /// Probably the most involved method of the whole solver. @@ -447,6 +605,7 @@ impl, X: Cx> SearchGraph { &mut self, cx: X, input: X::Input, + step_kind_from_parent: PathKind, inspect: &mut D::ProofTreeBuilder, mut evaluate_goal: impl FnMut(&mut Self, &mut D::ProofTreeBuilder) -> X::Result, ) -> X::Result { @@ -464,7 +623,7 @@ impl, X: Cx> SearchGraph { // - A // - BA cycle // - CB :x: - if let Some(result) = self.lookup_provisional_cache(cx, input) { + if let Some(result) = self.lookup_provisional_cache(input, step_kind_from_parent) { return result; } @@ -477,10 +636,12 @@ impl, X: Cx> SearchGraph { // global cache has been disabled as it may otherwise change the result for // cyclic goals. We don't care about goals which are not on the current stack // so it's fine to drop their scope eagerly. - self.lookup_global_cache_untracked(cx, input, available_depth) + self.lookup_global_cache_untracked(cx, input, step_kind_from_parent, available_depth) .inspect(|expected| debug!(?expected, "validate cache entry")) .map(|r| (scope, r)) - } else if let Some(result) = self.lookup_global_cache(cx, input, available_depth) { + } else if let Some(result) = + self.lookup_global_cache(cx, input, step_kind_from_parent, available_depth) + { return result; } else { None @@ -490,8 +651,8 @@ impl, X: Cx> SearchGraph { // avoid iterating over the stack in case a goal has already been computed. // This may not have an actual performance impact and we could reorder them // as it may reduce the number of `nested_goals` we need to track. - if let Some(result) = self.check_cycle_on_stack(cx, input) { - debug_assert!(validate_cache.is_none(), "global cache and cycle on stack"); + if let Some(result) = self.check_cycle_on_stack(cx, input, step_kind_from_parent) { + debug_assert!(validate_cache.is_none(), "global cache and cycle on stack: {input:?}"); return result; } @@ -499,6 +660,7 @@ impl, X: Cx> SearchGraph { let depth = self.stack.next_index(); let entry = StackEntry { input, + step_kind_from_parent, available_depth, reached_depth: depth, heads: Default::default(), @@ -522,12 +684,12 @@ impl, X: Cx> SearchGraph { // We've finished computing the goal and have popped it from the stack, // lazily update its parent goal. Self::update_parent_goal( - cx, &mut self.stack, + final_entry.step_kind_from_parent, final_entry.reached_depth, &final_entry.heads, final_entry.encountered_overflow, - &final_entry.nested_goals, + UpdateParentGoalCtxt::Ordinary(&final_entry.nested_goals), ); // We're now done with this goal. We only add the root of cycles to the global cache. @@ -541,19 +703,20 @@ impl, X: Cx> SearchGraph { self.insert_global_cache(cx, input, final_entry, result, dep_node) } } else if D::ENABLE_PROVISIONAL_CACHE { - debug_assert!(validate_cache.is_none()); + debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}"); let entry = self.provisional_cache.entry(input).or_default(); - let StackEntry { heads, nested_goals, encountered_overflow, .. } = final_entry; - let path_from_head = Self::stack_path_kind(cx, &self.stack, heads.highest_cycle_head()); - entry.push(ProvisionalCacheEntry { - encountered_overflow, - heads, - path_from_head, - nested_goals, - result, - }); + let StackEntry { heads, encountered_overflow, .. } = final_entry; + let path_from_head = Self::cycle_path_kind( + &self.stack, + step_kind_from_parent, + heads.highest_cycle_head(), + ); + let provisional_cache_entry = + ProvisionalCacheEntry { encountered_overflow, heads, path_from_head, result }; + debug!(?provisional_cache_entry); + entry.push(provisional_cache_entry); } else { - debug_assert!(validate_cache.is_none()); + debug_assert!(validate_cache.is_none(), "unexpected non-root: {input:?}"); } result @@ -575,7 +738,7 @@ impl, X: Cx> SearchGraph { // // We must therefore not use the global cache entry for `B` in that case. // See tests/ui/traits/next-solver/cycles/hidden-by-overflow.rs - last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Coinductive)); + last.nested_goals.insert(last.input, PathsToNested::EMPTY); } debug!("encountered stack overflow"); @@ -607,7 +770,6 @@ impl, X: Cx> SearchGraph { /// This can be thought of rotating the sub-tree of this provisional result and changing /// its entry point while making sure that all paths through this sub-tree stay the same. /// - /// /// In case the popped cycle head failed to reach a fixpoint anything which depends on /// its provisional result is invalid. Actually discarding provisional cache entries in /// this case would cause hangs, so we instead change the result of dependant provisional @@ -616,7 +778,6 @@ impl, X: Cx> SearchGraph { /// to me. fn rebase_provisional_cache_entries( &mut self, - cx: X, stack_entry: &StackEntry, mut mutate_result: impl FnMut(X::Input, X::Result) -> X::Result, ) { @@ -628,25 +789,24 @@ impl, X: Cx> SearchGraph { encountered_overflow: _, heads, path_from_head, - nested_goals, result, } = entry; - if heads.highest_cycle_head() != head { + if heads.highest_cycle_head() == head { + heads.remove_highest_cycle_head() + } else { return true; } - // We don't try rebasing if the path from the current head - // to the cache entry is not coinductive or if the path from - // the cache entry to the current head is not coinductive. - // - // Both of these constraints could be weakened, but by only - // accepting coinductive paths we don't have to worry about - // changing the cycle kind of the remaining cycles. We can - // extend this in the future once there's a known issue - // caused by it. - if *path_from_head != PathKind::Coinductive - || nested_goals.get(stack_entry.input).unwrap() - != UsageKind::Single(PathKind::Coinductive) + // We only try to rebase if all paths from the cache entry + // to its heads are coinductive. In this case these cycle + // kinds won't change, no matter the goals between these + // heads and the provisional cache entry. + if heads.iter().any(|(_, p)| matches!(p, AllPathsToHeadCoinductive::No)) { + return false; + } + + // The same for nested goals of the cycle head. + if stack_entry.heads.iter().any(|(_, p)| matches!(p, AllPathsToHeadCoinductive::No)) { return false; } @@ -654,20 +814,18 @@ impl, X: Cx> SearchGraph { // Merge the cycle heads of the provisional cache entry and the // popped head. If the popped cycle head was a root, discard all // provisional cache entries which depend on it. - heads.remove_highest_cycle_head(); heads.merge(&stack_entry.heads); let Some(head) = heads.opt_highest_cycle_head() else { return false; }; - // As we've made sure that the path from the new highest cycle - // head to the uses of the popped cycle head are fully coinductive, - // we can be sure that the paths to all nested goals of the popped - // cycle head remain the same. We can simply merge them. - nested_goals.merge(&stack_entry.nested_goals); // We now care about the path from the next highest cycle head to the // provisional cache entry. - *path_from_head = Self::stack_path_kind(cx, &self.stack, head); + *path_from_head = path_from_head.extend(Self::cycle_path_kind( + &self.stack, + stack_entry.step_kind_from_parent, + head, + )); // Mutate the result of the provisional cache entry in case we did // not reach a fixpoint. *result = mutate_result(input, *result); @@ -677,19 +835,18 @@ impl, X: Cx> SearchGraph { }); } - fn lookup_provisional_cache(&mut self, cx: X, input: X::Input) -> Option { + fn lookup_provisional_cache( + &mut self, + input: X::Input, + step_kind_from_parent: PathKind, + ) -> Option { if !D::ENABLE_PROVISIONAL_CACHE { return None; } let entries = self.provisional_cache.get(&input)?; - for &ProvisionalCacheEntry { - encountered_overflow, - ref heads, - path_from_head, - ref nested_goals, - result, - } in entries + for &ProvisionalCacheEntry { encountered_overflow, ref heads, path_from_head, result } in + entries { let head = heads.highest_cycle_head(); if encountered_overflow { @@ -710,22 +867,18 @@ impl, X: Cx> SearchGraph { // A provisional cache entry is only valid if the current path from its // highest cycle head to the goal is the same. - if path_from_head == Self::stack_path_kind(cx, &self.stack, head) { + if path_from_head == Self::cycle_path_kind(&self.stack, step_kind_from_parent, head) { // While we don't have to track the full depth of the provisional cache entry, // we do have to increment the required depth by one as we'd have already failed // with overflow otherwise let next_index = self.stack.next_index(); - let last = &mut self.stack.raw.last_mut().unwrap(); - let path_from_entry = Self::step_kind(cx, last.input); - last.nested_goals.insert(input, UsageKind::Single(path_from_entry)); - Self::update_parent_goal( - cx, &mut self.stack, + step_kind_from_parent, next_index, heads, - false, - nested_goals, + encountered_overflow, + UpdateParentGoalCtxt::ProvisionalCacheHit, ); debug_assert!(self.stack[head].has_been_used.is_some()); debug!(?head, ?path_from_head, "provisional cache hit"); @@ -740,8 +893,8 @@ impl, X: Cx> SearchGraph { /// evaluating this entry would not have ended up depending on either a goal /// already on the stack or a provisional cache entry. fn candidate_is_applicable( - cx: X, stack: &IndexVec>, + step_kind_from_parent: PathKind, provisional_cache: &HashMap>>, nested_goals: &NestedGoals, ) -> bool { @@ -772,8 +925,7 @@ impl, X: Cx> SearchGraph { for &ProvisionalCacheEntry { encountered_overflow, ref heads, - path_from_head, - nested_goals: _, + path_from_head: head_to_provisional, result: _, } in entries.iter() { @@ -785,24 +937,19 @@ impl, X: Cx> SearchGraph { // A provisional cache entry only applies if the path from its highest head // matches the path when encountering the goal. + // + // We check if any of the paths taken while computing the global goal + // would end up with an applicable provisional cache entry. let head = heads.highest_cycle_head(); - let full_path = match Self::stack_path_kind(cx, stack, head) { - PathKind::Coinductive => path_from_global_entry, - PathKind::Inductive => UsageKind::Single(PathKind::Inductive), - }; - - match (full_path, path_from_head) { - (UsageKind::Mixed, _) - | (UsageKind::Single(PathKind::Coinductive), PathKind::Coinductive) - | (UsageKind::Single(PathKind::Inductive), PathKind::Inductive) => { - debug!( - ?full_path, - ?path_from_head, - "cache entry not applicable due to matching paths" - ); - return false; - } - _ => debug!(?full_path, ?path_from_head, "paths don't match"), + let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head); + let full_paths = path_from_global_entry.extend_with(head_to_curr); + if full_paths.contains(head_to_provisional.into()) { + debug!( + ?full_paths, + ?head_to_provisional, + "cache entry not applicable due to matching paths" + ); + return false; } } } @@ -816,14 +963,15 @@ impl, X: Cx> SearchGraph { &self, cx: X, input: X::Input, + step_kind_from_parent: PathKind, available_depth: AvailableDepth, ) -> Option { cx.with_global_cache(|cache| { cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( - cx, &self.stack, + step_kind_from_parent, &self.provisional_cache, nested_goals, ) @@ -839,14 +987,15 @@ impl, X: Cx> SearchGraph { &mut self, cx: X, input: X::Input, + step_kind_from_parent: PathKind, available_depth: AvailableDepth, ) -> Option { cx.with_global_cache(|cache| { let CacheData { result, additional_depth, encountered_overflow, nested_goals } = cache .get(cx, input, available_depth, |nested_goals| { Self::candidate_is_applicable( - cx, &self.stack, + step_kind_from_parent, &self.provisional_cache, nested_goals, ) @@ -860,12 +1009,12 @@ impl, X: Cx> SearchGraph { // cycle heads are always empty. let heads = Default::default(); Self::update_parent_goal( - cx, &mut self.stack, + step_kind_from_parent, reached_depth, &heads, encountered_overflow, - nested_goals, + UpdateParentGoalCtxt::Ordinary(nested_goals), ); debug!(?additional_depth, "global cache hit"); @@ -873,16 +1022,21 @@ impl, X: Cx> SearchGraph { }) } - fn check_cycle_on_stack(&mut self, cx: X, input: X::Input) -> Option { + fn check_cycle_on_stack( + &mut self, + cx: X, + input: X::Input, + step_kind_from_parent: PathKind, + ) -> Option { let (head, _stack_entry) = self.stack.iter_enumerated().find(|(_, e)| e.input == input)?; - debug!("encountered cycle with depth {head:?}"); // We have a nested goal which directly relies on a goal deeper in the stack. // // We start by tagging all cycle participants, as that's necessary for caching. // // Finally we can return either the provisional response or the initial response // in case we're in the first fixpoint iteration for this goal. - let path_kind = Self::stack_path_kind(cx, &self.stack, head); + let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head); + debug!(?path_kind, "encountered cycle with depth {head:?}"); let usage_kind = UsageKind::Single(path_kind); self.stack[head].has_been_used = Some(self.stack[head].has_been_used.map_or(usage_kind, |prev| prev.merge(usage_kind))); @@ -894,11 +1048,10 @@ impl, X: Cx> SearchGraph { let last = &mut self.stack[last_index]; last.reached_depth = last.reached_depth.max(next_index); - let path_from_entry = Self::step_kind(cx, last.input); - last.nested_goals.insert(input, UsageKind::Single(path_from_entry)); - last.nested_goals.insert(last.input, UsageKind::Single(PathKind::Coinductive)); + last.nested_goals.insert(input, step_kind_from_parent.into()); + last.nested_goals.insert(last.input, PathsToNested::EMPTY); if last_index != head { - last.heads.insert(head); + last.heads.insert(head, step_kind_from_parent); } // Return the provisional result or, if we're in the first iteration, @@ -964,7 +1117,7 @@ impl, X: Cx> SearchGraph { // this was only the root of either coinductive or inductive cycles, and the // final result is equal to the initial response for that case. if self.reached_fixpoint(cx, &stack_entry, usage_kind, result) { - self.rebase_provisional_cache_entries(cx, &stack_entry, |_, result| result); + self.rebase_provisional_cache_entries(&stack_entry, |_, result| result); return (stack_entry, result); } @@ -981,7 +1134,7 @@ impl, X: Cx> SearchGraph { // we also taint all provisional cache entries which depend on the // current goal. if D::is_ambiguous_result(result) { - self.rebase_provisional_cache_entries(cx, &stack_entry, |input, _| { + self.rebase_provisional_cache_entries(&stack_entry, |input, _| { D::propagate_ambiguity(cx, input, result) }); return (stack_entry, result); @@ -993,7 +1146,7 @@ impl, X: Cx> SearchGraph { if i >= D::FIXPOINT_STEP_LIMIT { debug!("canonical cycle overflow"); let result = D::on_fixpoint_overflow(cx, input); - self.rebase_provisional_cache_entries(cx, &stack_entry, |input, _| { + self.rebase_provisional_cache_entries(&stack_entry, |input, _| { D::on_fixpoint_overflow(cx, input) }); return (stack_entry, result); diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index a562b751d8a9c..3aec4804b2799 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -5,9 +5,10 @@ use std::hash::Hash; use derive_where::derive_where; #[cfg(feature = "nightly")] -use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; +use crate::search_graph::PathKind; use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast}; pub type CanonicalInput::Predicate> = @@ -37,7 +38,10 @@ pub struct NoSolution; #[derive_where(Eq; I: Interner, P: Eq)] #[derive_where(Debug; I: Interner, P: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct Goal { pub param_env: I::ParamEnv, pub predicate: P, @@ -57,20 +61,24 @@ impl Goal { /// Why a specific goal has to be proven. /// /// This is necessary as we treat nested goals different depending on -/// their source. This is currently mostly used by proof tree visitors -/// but will be used by cycle handling in the future. +/// their source. This is used to decide whether a cycle is coinductive. +/// See the documentation of `EvalCtxt::step_kind_for_source` for more details +/// about this. +/// +/// It is also used by proof tree visitors, e.g. for diagnostics purposes. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum GoalSource { Misc, - /// We're proving a where-bound of an impl. + /// A nested goal required to prove that types are equal/subtypes. + /// This is always an unproductive step. /// - /// FIXME(-Znext-solver=coinductive): Explain how and why this - /// changes whether cycles are coinductive. + /// This is also used for all `NormalizesTo` goals as we they are used + /// to relate types in `AliasRelate`. + TypeRelating, + /// We're proving a where-bound of an impl. ImplWhereBound, /// Const conditions that need to hold for `~const` alias bounds to hold. - /// - /// FIXME(-Znext-solver=coinductive): Are these even coinductive? AliasBoundConstCondition, /// Instantiating a higher-ranked goal and re-proving it. InstantiateHigherRanked, @@ -78,6 +86,12 @@ pub enum GoalSource { /// This is used in two places: projecting to an opaque whose hidden type /// is already registered in the opaque type storage, and for rigid projections. AliasWellFormed, + /// In case normalizing aliases in nested goals cycles, eagerly normalizing these + /// aliases in the context of the parent may incorrectly change the cycle kind. + /// Normalizing aliases in goals therefore tracks the original path kind for this + /// nested goal. See the comment of the `ReplaceAliasWithInfer` visitor for more + /// details. + NormalizeGoal(PathKind), } #[derive_where(Clone; I: Interner, Goal: Clone)] @@ -87,7 +101,10 @@ pub enum GoalSource { #[derive_where(Eq; I: Interner, Goal: Eq)] #[derive_where(Debug; I: Interner, Goal: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct QueryInput { pub goal: Goal, pub predefined_opaques_in_body: I::PredefinedOpaques, @@ -96,7 +113,10 @@ pub struct QueryInput { /// Opaques that are defined in the inference context before a query is called. #[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct PredefinedOpaquesData { pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, } @@ -167,7 +187,10 @@ pub enum CandidateSource { } #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] -#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))] +#[cfg_attr( + feature = "nightly", + derive(HashStable_NoContext, Encodable_NoContext, Decodable_NoContext) +)] pub enum BuiltinImplSource { /// A built-in impl that is considered trivial, without any nested requirements. They /// are preferred over where-clauses, and we want to track them explicitly. @@ -181,11 +204,6 @@ pub enum BuiltinImplSource { /// /// The index is only used for winnowing. TraitUpcasting(usize), - /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`. - /// - /// This can be removed when `feature(tuple_unsizing)` is stabilized, since we only - /// use it to detect when unsizing tuples in hir typeck. - TupleUnsizing, } #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 83631f7fe343f..9bea4482b550c 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -8,7 +8,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; #[cfg(feature = "nightly")] use rustc_data_structures::unify::{NoError, UnifyKey, UnifyValue}; #[cfg(feature = "nightly")] -use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use self::TyKind::*; @@ -22,7 +22,10 @@ mod closure; /// Specifies how a trait object is represented. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum DynKind { /// An unsized `dyn Trait` object Dyn, @@ -36,7 +39,10 @@ pub enum DynKind { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum AliasTyKind { /// A projection `::AssocType`. /// Can get normalized away if monomorphic enough. @@ -69,7 +75,10 @@ impl AliasTyKind { /// converted to this representation using `::lower_ty`. #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum TyKind { /// The primitive boolean type. Written as `bool`. Bool, @@ -341,7 +350,10 @@ impl fmt::Debug for TyKind { /// * For an opaque type, there is no explicit syntax. #[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] -#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] pub struct AliasTy { /// The parameters of the associated or opaque type. /// @@ -464,7 +476,10 @@ impl AliasTy { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum IntTy { Isize, I8, @@ -522,7 +537,10 @@ impl IntTy { } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum UintTy { Usize, U8, @@ -580,7 +598,10 @@ impl UintTy { } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] pub enum FloatTy { F16, F32, @@ -680,7 +701,7 @@ rustc_index::newtype_index! { /// type variable for the element type since we won't know until it's /// used what the element type is supposed to be. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))] +#[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))] pub enum InferTy { /// A type variable. TyVar(TyVid), @@ -860,7 +881,10 @@ impl fmt::Debug for InferTy { } #[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct TypeAndMut { pub ty: I::Ty, @@ -868,7 +892,10 @@ pub struct TypeAndMut { } #[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct FnSig { pub inputs_and_output: I::Tys, @@ -1010,7 +1037,8 @@ impl Deref for UnsafeBinderInner { } #[cfg(feature = "nightly")] -impl> rustc_serialize::Encodable for UnsafeBinderInner +impl rustc_serialize::Encodable + for UnsafeBinderInner where I::Ty: rustc_serialize::Encodable, I::BoundVarKinds: rustc_serialize::Encodable, @@ -1022,7 +1050,8 @@ where } #[cfg(feature = "nightly")] -impl> rustc_serialize::Decodable for UnsafeBinderInner +impl rustc_serialize::Decodable + for UnsafeBinderInner where I::Ty: TypeVisitable + rustc_serialize::Decodable, I::BoundVarKinds: rustc_serialize::Decodable, @@ -1038,7 +1067,10 @@ where // This is just a `FnSig` without the `FnHeader` fields. #[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct FnSigTys { pub inputs_and_output: I::Tys, @@ -1087,7 +1119,10 @@ impl ty::Binder> { } #[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)] -#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +#[cfg_attr( + feature = "nightly", + derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) +)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct FnHeader { pub c_variadic: bool, diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml index cb95ca6834623..15a5557509929 100644 --- a/compiler/rustc_type_ir_macros/Cargo.toml +++ b/compiler/rustc_type_ir_macros/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustc_type_ir_macros" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] proc-macro = true diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs index 640299c216796..8eefecdc980e5 100644 --- a/compiler/rustc_type_ir_macros/src/lib.rs +++ b/compiler/rustc_type_ir_macros/src/lib.rs @@ -45,12 +45,12 @@ fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Tok s.add_bounds(synstructure::AddBounds::Fields); let body_visit = s.each(|bind| { quote! { - match ::rustc_type_ir::visit::VisitorResult::branch( - ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor) + match ::rustc_type_ir::VisitorResult::branch( + ::rustc_type_ir::TypeVisitable::visit_with(#bind, __visitor) ) { ::core::ops::ControlFlow::Continue(()) => {}, ::core::ops::ControlFlow::Break(r) => { - return ::rustc_type_ir::visit::VisitorResult::from_residual(r); + return ::rustc_type_ir::VisitorResult::from_residual(r); }, } } @@ -58,14 +58,14 @@ fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Tok s.bind_with(|_| synstructure::BindStyle::Move); s.bound_impl( - quote!(::rustc_type_ir::visit::TypeVisitable), + quote!(::rustc_type_ir::TypeVisitable), quote! { - fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor>( + fn visit_with<__V: ::rustc_type_ir::TypeVisitor>( &self, __visitor: &mut __V ) -> __V::Result { match *self { #body_visit } - <__V::Result as ::rustc_type_ir::visit::VisitorResult>::output() + <__V::Result as ::rustc_type_ir::VisitorResult>::output() } }, ) @@ -93,7 +93,7 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke bind.to_token_stream() } else { quote! { - ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)? + ::rustc_type_ir::TypeFoldable::try_fold_with(#bind, __folder)? } } }) @@ -105,9 +105,9 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke s.filter(|bi| !has_ignore_attr(&bi.ast().attrs, "type_foldable", "identity")); s.add_bounds(synstructure::AddBounds::Fields); s.bound_impl( - quote!(::rustc_type_ir::fold::TypeFoldable), + quote!(::rustc_type_ir::TypeFoldable), quote! { - fn try_fold_with<__F: ::rustc_type_ir::fold::FallibleTypeFolder>( + fn try_fold_with<__F: ::rustc_type_ir::FallibleTypeFolder>( self, __folder: &mut __F ) -> Result { diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index 2edb3f140d7ac..d691a0e4f22f5 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "stable_mir" version = "0.1.0-preview" -edition = "2021" +edition = "2024" [dependencies] scoped-tls = "1.0" diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index a6f7c254583e2..e82c957c34ea6 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -62,14 +62,17 @@ pub trait Context { /// Returns the name of given `DefId` fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol; - /// Return attributes with the given attribute name. + /// Return registered tool attributes with the given attribute name. /// - /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool + /// attributes will simply return an empty list. + /// + /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. - fn get_attrs_by_path(&self, def_id: DefId, attr: &[Symbol]) -> Vec; + fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec; - /// Get all attributes of a definition. - fn get_all_attrs(&self, def_id: DefId) -> Vec; + /// Get all tool attributes of a definition. + fn all_tool_attrs(&self, def_id: DefId) -> Vec; /// Returns printable, human readable form of `Span` fn span_to_string(&self, span: Span) -> String; diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs index cf29176dbbdda..2577c281ca4f2 100644 --- a/compiler/stable_mir/src/crate_def.rs +++ b/compiler/stable_mir/src/crate_def.rs @@ -10,6 +10,27 @@ use crate::{Crate, Symbol, with}; #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize)] pub struct DefId(pub(crate) usize); +impl DefId { + /// Return fully qualified name of this definition + pub fn name(&self) -> Symbol { + with(|cx| cx.def_name(*self, false)) + } + + /// Return a trimmed name of this definition. + /// + /// This can be used to print more user friendly diagnostic messages. + /// + /// If a symbol name can only be imported from one place for a type, and as + /// long as it was not glob-imported anywhere in the current crate, we trim its + /// path and print only the name. + /// + /// For example, this function may shorten `std::vec::Vec` to just `Vec`, + /// as long as there is no other `Vec` importable anywhere. + pub fn trimmed_name(&self) -> Symbol { + with(|cx| cx.def_name(*self, true)) + } +} + /// A trait for retrieving information about a particular definition. /// /// Implementors must provide the implementation of `def_id` which will be used to retrieve @@ -19,24 +40,17 @@ pub trait CrateDef { fn def_id(&self) -> DefId; /// Return the fully qualified name of the current definition. + /// + /// See [`DefId::name`] for more details fn name(&self) -> Symbol { - let def_id = self.def_id(); - with(|cx| cx.def_name(def_id, false)) + self.def_id().name() } /// Return a trimmed name of this definition. /// - /// This can be used to print more user friendly diagnostic messages. - /// - /// If a symbol name can only be imported from one place for a type, and as - /// long as it was not glob-imported anywhere in the current crate, we trim its - /// path and print only the name. - /// - /// For example, this function may shorten `std::vec::Vec` to just `Vec`, - /// as long as there is no other `Vec` importable anywhere. + /// See [`DefId::trimmed_name`] for more details fn trimmed_name(&self) -> Symbol { - let def_id = self.def_id(); - with(|cx| cx.def_name(def_id, true)) + self.def_id().trimmed_name() } /// Return information about the crate where this definition is declared. @@ -53,19 +67,22 @@ pub trait CrateDef { with(|cx| cx.span_of_an_item(def_id)) } - /// Return attributes with the given attribute name. + /// Return registered tool attributes with the given attribute name. + /// + /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool + /// attributes will simply return an empty list. /// - /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`. + /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`. /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`. - fn attrs_by_path(&self, attr: &[Symbol]) -> Vec { + fn tool_attrs(&self, attr: &[Symbol]) -> Vec { let def_id = self.def_id(); - with(|cx| cx.get_attrs_by_path(def_id, attr)) + with(|cx| cx.tool_attrs(def_id, attr)) } - /// Return all attributes of this definition. - fn all_attrs(&self) -> Vec { + /// Return all tool attributes of this definition. + fn all_tool_attrs(&self) -> Vec { let def_id = self.def_id(); - with(|cx| cx.get_all_attrs(def_id)) + with(|cx| cx.all_tool_attrs(def_id)) } } diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index 0b4cebadad1d4..70d42dfbfcb9a 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -48,10 +48,7 @@ pub type CrateNum = usize; impl Debug for DefId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DefId") - .field("id", &self.0) - .field("name", &with(|cx| cx.def_name(*self, false))) - .finish() + f.debug_struct("DefId").field("id", &self.0).field("name", &self.name()).finish() } } @@ -132,13 +129,21 @@ crate_def_with_ty! { } impl CrateItem { - /// This will return the body of an item. - /// - /// This will panic if no body is available. - pub fn body(&self) -> mir::Body { + /// This will return the body of an item or panic if it's not available. + pub fn expect_body(&self) -> mir::Body { with(|cx| cx.mir_body(self.0)) } + /// Return the body of an item if available. + pub fn body(&self) -> Option { + with(|cx| cx.has_body(self.0).then(|| cx.mir_body(self.0))) + } + + /// Check if a body is available for this item. + pub fn has_body(&self) -> bool { + with(|cx| cx.has_body(self.0)) + } + pub fn span(&self) -> Span { with(|cx| cx.span_of_an_item(self.0)) } @@ -159,8 +164,11 @@ impl CrateItem { with(|cx| cx.is_foreign_item(self.0)) } + /// Emit MIR for this item body. pub fn emit_mir(&self, w: &mut W) -> io::Result<()> { - self.body().dump(w, &self.name()) + self.body() + .ok_or_else(|| io::Error::other(format!("No body found for `{}`", self.name())))? + .dump(w, &self.name()) } } diff --git a/compiler/stable_mir/src/mir/alloc.rs b/compiler/stable_mir/src/mir/alloc.rs index 7e0c4a479b8ef..023807b76aec6 100644 --- a/compiler/stable_mir/src/mir/alloc.rs +++ b/compiler/stable_mir/src/mir/alloc.rs @@ -58,7 +58,7 @@ impl IndexedVal for AllocId { /// Utility function used to read an allocation data into a unassigned integer. pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result { - let mut buf = [0u8; std::mem::size_of::()]; + let mut buf = [0u8; size_of::()]; match MachineInfo::target_endianness() { Endian::Little => { bytes.read_exact(&mut buf[..bytes.len()])?; @@ -73,7 +73,7 @@ pub(crate) fn read_target_uint(mut bytes: &[u8]) -> Result { /// Utility function used to read an allocation data into an assigned integer. pub(crate) fn read_target_int(mut bytes: &[u8]) -> Result { - let mut buf = [0u8; std::mem::size_of::()]; + let mut buf = [0u8; size_of::()]; match MachineInfo::target_endianness() { Endian::Little => { bytes.read_exact(&mut buf[..bytes.len()])?; diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index bc2e427f50cb0..f8b46f50a5298 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -864,7 +864,7 @@ impl SwitchTargets { } /// The conditional targets which are only taken if the pattern matches the given value. - pub fn branches(&self) -> impl Iterator + '_ { + pub fn branches(&self) -> impl Iterator { self.branches.iter().copied() } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 9ef80edb82a6e..b857a735b7259 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -809,7 +809,7 @@ impl AdtDef { } /// Iterate over the variants in this ADT. - pub fn variants_iter(&self) -> impl Iterator + '_ { + pub fn variants_iter(&self) -> impl Iterator { (0..self.num_variants()) .map(|idx| VariantDef { idx: VariantIdx::to_val(idx), adt_def: *self }) } diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs index 3533ed2e8511d..8463174f9a468 100644 --- a/compiler/stable_mir/src/visitor.rs +++ b/compiler/stable_mir/src/visitor.rs @@ -161,7 +161,7 @@ impl Visitable for RigidTy { RigidTy::Slice(inner) => inner.visit(visitor), RigidTy::RawPtr(ty, _) => ty.visit(visitor), RigidTy::Ref(reg, ty, _) => { - reg.visit(visitor); + reg.visit(visitor)?; ty.visit(visitor) } RigidTy::Adt(_, args) diff --git a/config.example.toml b/config.example.toml index a17d3ec9f8841..0700a31710995 100644 --- a/config.example.toml +++ b/config.example.toml @@ -163,6 +163,16 @@ # Custom CMake defines to set when building LLVM. #build-config = {} +# ============================================================================= +# Tweaking how GCC is compiled +# ============================================================================= +[gcc] +# Download GCC from CI instead of building it locally. +# Note that this will attempt to download GCC even if there are local +# modifications to the `src/gcc` submodule. +# Currently, this is only supported for the `x86_64-unknown-linux-gnu` target. +# download-ci-gcc = false + # ============================================================================= # General build configuration options # ============================================================================= @@ -189,6 +199,17 @@ # The default stage to use for the `bench` subcommand #bench-stage = 2 +# A descriptive string to be appended to version output (e.g., `rustc --version`), +# which is also used in places like debuginfo `DW_AT_producer`. This may be useful for +# supplementary build information, like distro-specific package versions. +# +# The Rust compiler will differentiate between versions of itself, including +# based on this string, which means that if you wish to be compatible with +# upstream Rust you need to set this to "". However, note that if you set this to "" but +# are not actually compatible -- for example if you've backported patches that change +# behavior -- this may lead to miscompilations or other bugs. +#description = "" + # Build triple for the pre-compiled snapshot compiler. If `rustc` is set, this must match its host # triple (see `rustc --version --verbose`; cross-compiling the rust build system itself is NOT # supported). If `rustc` is unset, this must be a platform with pre-compiled host tools @@ -425,6 +446,10 @@ # a specific version. #ccache = false +# List of paths to exclude from the build and test processes. +# For example, exclude = ["tests/ui", "src/tools/tidy"]. +#exclude = [] + # ============================================================================= # General install configuration options # ============================================================================= @@ -608,22 +633,12 @@ # The "channel" for the Rust build to produce. The stable/beta channels only # allow using stable features, whereas the nightly and dev channels allow using -# nightly features +# nightly features. # -# If using tarball sources, default value for `channel` is taken from the `src/ci/channel` file; -# otherwise, it's "dev". -#channel = if "is a tarball source" { content of `src/ci/channel` file } else { "dev" } - -# A descriptive string to be appended to `rustc --version` output, which is -# also used in places like debuginfo `DW_AT_producer`. This may be useful for -# supplementary build information, like distro-specific package versions. +# You can set the channel to "auto-detect" to load the channel name from `src/ci/channel`. # -# The Rust compiler will differentiate between versions of itself, including -# based on this string, which means that if you wish to be compatible with -# upstream Rust you need to set this to "". However, note that if you are not -# actually compatible -- for example if you've backported patches that change -# behavior -- this may lead to miscompilations or other bugs. -#description = "" +# If using tarball sources, default value is "auto-detect", otherwise, it's "dev". +#channel = if "is a tarball source" { "auto-detect" } else { "dev" } # The root location of the musl installation directory. The library directory # will also need to contain libunwind.a for an unwinding implementation. Note diff --git a/library/Cargo.lock b/library/Cargo.lock index 0be2f9a154939..104e0a3d01079 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -30,8 +30,6 @@ version = "0.0.0" dependencies = [ "compiler_builtins", "core", - "rand", - "rand_xorshift", ] [[package]] @@ -40,6 +38,14 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "alloctests" +version = "0.0.0" +dependencies = [ + "rand", + "rand_xorshift", +] + [[package]] name = "cc" version = "1.2.0" @@ -61,9 +67,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.146" +version = "0.1.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97117b1434b79833f39a5fabdf82f890bd98c1988334dea1cb67f7e627fa311" +checksum = "abc30f1766d387c35f2405e586d3e7a88230dc728ff78cd1d0bc59ae0b63154b" dependencies = [ "cc", "rustc-std-workspace-core", @@ -140,9 +146,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" +checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -151,9 +157,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" dependencies = [ "rustc-std-workspace-core", ] diff --git a/library/Cargo.toml b/library/Cargo.toml index 1205f7c9ed6b5..4d5955593ffcd 100644 --- a/library/Cargo.toml +++ b/library/Cargo.toml @@ -4,6 +4,7 @@ members = [ "std", "sysroot", "coretests", + "alloctests", ] exclude = [ diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index c1d7f324f1770..8d0253bd29aa2 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["public-dependency"] + [package] name = "alloc" version = "0.0.0" @@ -6,33 +8,15 @@ repository = "https://github.com/rust-lang/rust.git" description = "The Rust core allocation and collections library" autotests = false autobenches = false -edition = "2021" - -[dependencies] -core = { path = "../core" } -compiler_builtins = { version = "=0.1.146", features = ['rustc-dep-of-std'] } - -[dev-dependencies] -rand = { version = "0.9.0", default-features = false, features = ["alloc"] } -rand_xorshift = "0.4.0" +edition = "2024" -[[test]] -name = "alloctests" -path = "tests/lib.rs" +[lib] +test = false +bench = false -[[test]] -name = "vec_deque_alloc_error" -path = "tests/vec_deque_alloc_error.rs" - -[[bench]] -name = "allocbenches" -path = "benches/lib.rs" -test = true - -[[bench]] -name = "vec_deque_append_bench" -path = "benches/vec_deque_append.rs" -harness = false +[dependencies] +core = { path = "../core", public = true } +compiler_builtins = { version = "=0.1.151", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index e686a02f29b0c..2f752f6eb3940 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -5,9 +5,7 @@ #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; -#[cfg(not(test))] use core::hint; -#[cfg(not(test))] use core::ptr::{self, NonNull}; unsafe extern "Rust" { @@ -44,14 +42,10 @@ unsafe extern "Rust" { /// accessed through the [free functions in `alloc`](self#functions). #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] -#[cfg(not(test))] // the compiler needs to know when a Box uses the global allocator vs a custom one #[lang = "global_alloc_ty"] pub struct Global; -#[cfg(test)] -pub use std::alloc::Global; - /// Allocates memory with the global allocator. /// /// This function forwards calls to the [`GlobalAlloc::alloc`] method @@ -180,7 +174,6 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { } } -#[cfg(not(test))] impl Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -246,7 +239,6 @@ impl Global { } #[unstable(feature = "allocator_api", issue = "32838")] -#[cfg(not(test))] unsafe impl Allocator for Global { #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -264,8 +256,14 @@ unsafe impl Allocator for Global { #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { - // SAFETY: `layout` is non-zero in size, - // other conditions must be upheld by the caller + // SAFETY: + // * We have checked that `layout` is non-zero in size. + // * The caller is obligated to provide a layout that "fits", and in this case, + // "fit" always means a layout that is equal to the original, because our + // `allocate()`, `grow()`, and `shrink()` implementations never returns a larger + // allocation than requested. + // * Other conditions must be upheld by the caller, as per `Allocator::deallocate()`'s + // safety documentation. unsafe { dealloc(ptr.as_ptr(), layout) } } } @@ -340,7 +338,7 @@ unsafe impl Allocator for Global { } /// The allocator for `Box`. -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[lang = "exchange_malloc"] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -389,7 +387,7 @@ unsafe extern "Rust" { /// [no_std]: https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute #[stable(feature = "global_alloc", since = "1.28.0")] #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")] -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[cold] #[optimize(size)] pub const fn handle_alloc_error(layout: Layout) -> ! { @@ -413,11 +411,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { ct_error(layout) } -// For alloc test `std::alloc::handle_alloc_error` can be used directly. -#[cfg(all(not(no_global_oom_handling), test))] -pub use std::alloc::handle_alloc_error; - -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 17dad3277b95d..07f51b7614ff8 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -32,7 +32,7 @@ where /// implementing the `Clone` trait. But `Clone` works only for going from `&T` /// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data /// from any borrow of a given type. -#[cfg_attr(not(test), rustc_diagnostic_item = "ToOwned")] +#[rustc_diagnostic_item = "ToOwned"] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToOwned { /// The resulting type after obtaining ownership. @@ -54,7 +54,7 @@ pub trait ToOwned { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "cloning is often expensive and is not expected to have side effects"] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_owned_method")] + #[rustc_diagnostic_item = "to_owned_method"] fn to_owned(&self) -> Self::Owned; /// Uses borrowed data to replace owned data, usually by cloning. @@ -175,7 +175,7 @@ where /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Cow")] +#[rustc_diagnostic_item = "Cow"] pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 5a3c1b74dadd5..e77caad65401b 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -237,22 +237,9 @@ pub struct Box< /// the newly allocated memory. This is an intrinsic to avoid unnecessary copies. /// /// This is the surface syntax for `box ` expressions. -#[cfg(not(bootstrap))] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[unstable(feature = "liballoc_internals", issue = "none")] -pub fn box_new(_x: T) -> Box { - unreachable!() -} - -/// Transition function for the next bootstrap bump. -#[cfg(bootstrap)] -#[unstable(feature = "liballoc_internals", issue = "none")] -#[inline(always)] -pub fn box_new(x: T) -> Box { - #[rustc_box] - Box::new(x) -} +pub fn box_new(x: T) -> Box; impl Box { /// Allocates memory on the heap and then places `x` into it. @@ -950,8 +937,6 @@ impl Box, A> { /// # Examples /// /// ``` - /// #![feature(box_uninit_write)] - /// /// let big_box = Box::<[usize; 1024]>::new_uninit(); /// /// let mut array = [0; 1024]; @@ -967,7 +952,7 @@ impl Box, A> { /// assert_eq!(*x, i); /// } /// ``` - #[unstable(feature = "box_uninit_write", issue = "129397")] + #[stable(feature = "box_uninit_write", since = "CURRENT_RUSTC_VERSION")] #[inline] pub fn write(mut boxed: Self, value: T) -> Box { unsafe { diff --git a/library/alloc/src/boxed/convert.rs b/library/alloc/src/boxed/convert.rs index 255cefb1e78fb..8062658020239 100644 --- a/library/alloc/src/boxed/convert.rs +++ b/library/alloc/src/boxed/convert.rs @@ -529,7 +529,6 @@ impl<'a, E: Error + 'a> From for Box { /// ``` /// use std::error::Error; /// use std::fmt; - /// use std::mem; /// /// #[derive(Debug)] /// struct AnError; @@ -543,9 +542,9 @@ impl<'a, E: Error + 'a> From for Box { /// impl Error for AnError {} /// /// let an_error = AnError; - /// assert!(0 == mem::size_of_val(&an_error)); + /// assert!(0 == size_of_val(&an_error)); /// let a_boxed_error = Box::::from(an_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// assert!(size_of::>() == size_of_val(&a_boxed_error)) /// ``` fn from(err: E) -> Box { Box::new(err) @@ -563,7 +562,6 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box From for Box::from(an_error); /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// size_of::>() == size_of_val(&a_boxed_error)) /// ``` fn from(err: E) -> Box { Box::new(err) @@ -600,12 +598,11 @@ impl<'a> From for Box { /// /// ``` /// use std::error::Error; - /// use std::mem; /// /// let a_string_error = "a string error".to_string(); /// let a_boxed_error = Box::::from(a_string_error); /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// size_of::>() == size_of_val(&a_boxed_error)) /// ``` #[inline] fn from(err: String) -> Box { @@ -644,11 +641,10 @@ impl<'a> From for Box { /// /// ``` /// use std::error::Error; - /// use std::mem; /// /// let a_string_error = "a string error".to_string(); /// let a_boxed_error = Box::::from(a_string_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// assert!(size_of::>() == size_of_val(&a_boxed_error)) /// ``` fn from(str_err: String) -> Box { let err1: Box = From::from(str_err); @@ -668,12 +664,11 @@ impl<'a> From<&str> for Box { /// /// ``` /// use std::error::Error; - /// use std::mem; /// /// let a_str_error = "a str error"; /// let a_boxed_error = Box::::from(a_str_error); /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// size_of::>() == size_of_val(&a_boxed_error)) /// ``` #[inline] fn from(err: &str) -> Box { @@ -692,11 +687,10 @@ impl<'a> From<&str> for Box { /// /// ``` /// use std::error::Error; - /// use std::mem; /// /// let a_str_error = "a str error"; /// let a_boxed_error = Box::::from(a_str_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// assert!(size_of::>() == size_of_val(&a_boxed_error)) /// ``` fn from(err: &str) -> Box { From::from(String::from(err)) @@ -712,13 +706,12 @@ impl<'a, 'b> From> for Box { /// /// ``` /// use std::error::Error; - /// use std::mem; /// use std::borrow::Cow; /// /// let a_cow_str_error = Cow::from("a str error"); /// let a_boxed_error = Box::::from(a_cow_str_error); /// assert!( - /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// size_of::>() == size_of_val(&a_boxed_error)) /// ``` fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) @@ -734,12 +727,11 @@ impl<'a, 'b> From> for Box { /// /// ``` /// use std::error::Error; - /// use std::mem; /// use std::borrow::Cow; /// /// let a_cow_str_error = Cow::from("a str error"); /// let a_boxed_error = Box::::from(a_cow_str_error); - /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// assert!(size_of::>() == size_of_val(&a_boxed_error)) /// ``` fn from(err: Cow<'b, str>) -> Box { From::from(String::from(err)) diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 78e5aec09b18d..21425b9846e42 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -9,9 +9,8 @@ use core::intrinsics::const_allocate; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; -use core::mem; #[cfg(not(no_global_oom_handling))] -use core::mem::SizedTypeProperties; +use core::mem::{self, SizedTypeProperties}; use core::ops::{Deref, DerefMut}; use core::ptr::{self, NonNull, Pointee}; @@ -30,7 +29,6 @@ use crate::alloc::{self, Layout, LayoutError}; /// let five = ThinBox::new(5); /// let thin_slice = ThinBox::<[i32]>::new_unsize([1, 2, 3, 4]); /// -/// use std::mem::{size_of, size_of_val}; /// let size_of_ptr = size_of::<*const ()>(); /// assert_eq!(size_of_ptr, size_of_val(&five)); /// assert_eq!(size_of_ptr, size_of_val(&thin_slice)); @@ -114,7 +112,7 @@ impl ThinBox { where T: Unsize, { - if mem::size_of::() == 0 { + if size_of::() == 0 { let ptr = WithOpaqueHeader::new_unsize_zst::(value); ThinBox { ptr, _marker: PhantomData } } else { @@ -283,9 +281,7 @@ impl WithHeader { let ptr = if layout.size() == 0 { // Some paranoia checking, mostly so that the ThinBox tests are // more able to catch issues. - debug_assert!( - value_offset == 0 && mem::size_of::() == 0 && mem::size_of::() == 0 - ); + debug_assert!(value_offset == 0 && size_of::() == 0 && size_of::() == 0); layout.dangling() } else { let ptr = alloc::alloc(layout); @@ -315,7 +311,7 @@ impl WithHeader { Dyn: Pointee + ?Sized, T: Unsize, { - assert!(mem::size_of::() == 0); + assert!(size_of::() == 0); const fn max(a: usize, b: usize) -> usize { if a > b { a } else { b } @@ -329,18 +325,16 @@ impl WithHeader { // FIXME: just call `WithHeader::alloc_layout` with size reset to 0. // Currently that's blocked on `Layout::extend` not being `const fn`. - let alloc_align = - max(mem::align_of::(), mem::align_of::<::Metadata>()); + let alloc_align = max(align_of::(), align_of::<::Metadata>()); - let alloc_size = - max(mem::align_of::(), mem::size_of::<::Metadata>()); + let alloc_size = max(align_of::(), size_of::<::Metadata>()); unsafe { // SAFETY: align is power of two because it is the maximum of two alignments. let alloc: *mut u8 = const_allocate(alloc_size, alloc_align); let metadata_offset = - alloc_size.checked_sub(mem::size_of::<::Metadata>()).unwrap(); + alloc_size.checked_sub(size_of::<::Metadata>()).unwrap(); // SAFETY: adding offset within the allocation. let metadata_ptr: *mut ::Metadata = alloc.add(metadata_offset).cast(); @@ -421,7 +415,7 @@ impl WithHeader { } const fn header_size() -> usize { - mem::size_of::() + size_of::() } fn alloc_layout(value_layout: Layout) -> Result<(Layout, usize), LayoutError> { diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs index 61e61019b508c..338c7ac7f8876 100644 --- a/library/alloc/src/bstr.rs +++ b/library/alloc/src/bstr.rs @@ -12,13 +12,10 @@ use core::ops::{ Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use core::str::FromStr; use core::{fmt, hash}; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 use crate::boxed::Box; #[cfg(not(no_rc))] use crate::rc::Rc; @@ -181,7 +178,6 @@ impl Default for ByteString { // Omitted due to inference failures // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { // #[inline] @@ -190,7 +186,6 @@ impl Default for ByteString { // } // } // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl From<[u8; N]> for ByteString { // #[inline] @@ -199,7 +194,6 @@ impl Default for ByteString { // } // } // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a [u8]> for ByteString { // #[inline] @@ -226,7 +220,6 @@ impl From for Vec { // Omitted due to inference failures // -// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 // #[unstable(feature = "bstr", issue = "134915")] // impl<'a> From<&'a str> for ByteString { // #[inline] @@ -243,7 +236,6 @@ impl From for Vec { // } // } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for ByteString { #[inline] @@ -252,7 +244,6 @@ impl<'a> From<&'a ByteStr> for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From for Cow<'a, ByteStr> { #[inline] @@ -261,7 +252,6 @@ impl<'a> From for Cow<'a, ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { #[inline] @@ -330,7 +320,6 @@ impl FromIterator for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl FromStr for ByteString { type Err = core::convert::Infallible; @@ -488,7 +477,6 @@ impl PartialEq for ByteString { macro_rules! impl_partial_eq_ord_cow { ($lhs:ty, $rhs:ty) => { - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$rhs> for $lhs { @@ -499,7 +487,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialEq<$lhs> for $rhs { @@ -510,7 +497,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$rhs> for $lhs { @@ -521,7 +507,6 @@ macro_rules! impl_partial_eq_ord_cow { } } - #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[allow(unused_lifetimes)] #[unstable(feature = "bstr", issue = "134915")] impl<'a> PartialOrd<$lhs> for $rhs { @@ -572,7 +557,6 @@ impl PartialOrd for ByteString { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl ToOwned for ByteStr { type Owned = ByteString; @@ -605,7 +589,6 @@ impl<'a> TryFrom<&'a ByteString> for &'a str { // Additional impls for `ByteStr` that require types from `alloc`: -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl Clone for Box { #[inline] @@ -614,7 +597,6 @@ impl Clone for Box { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { #[inline] @@ -623,7 +605,6 @@ impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From> for Box { #[inline] @@ -633,7 +614,6 @@ impl From> for Box { } } -#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 #[unstable(feature = "bstr", issue = "134915")] impl From> for Box<[u8]> { #[inline] diff --git a/library/alloc/src/collections/binary_heap/mod.rs b/library/alloc/src/collections/binary_heap/mod.rs index 965fd63a52981..63828b482b9a9 100644 --- a/library/alloc/src/collections/binary_heap/mod.rs +++ b/library/alloc/src/collections/binary_heap/mod.rs @@ -153,7 +153,9 @@ use core::{fmt, ptr}; use crate::alloc::Global; use crate::collections::TryReserveError; use crate::slice; -use crate::vec::{self, AsVecIntoIter, Vec}; +#[cfg(not(test))] +use crate::vec::AsVecIntoIter; +use crate::vec::{self, Vec}; /// A priority queue implemented with a binary heap. /// @@ -359,6 +361,74 @@ impl DerefMut for PeekMut<'_, T, A> { } impl<'a, T: Ord, A: Allocator> PeekMut<'a, T, A> { + /// Sifts the current element to its new position. + /// + /// Afterwards refers to the new element. Returns if the element changed. + /// + /// ## Examples + /// + /// The condition can be used to upper bound all elements in the heap. When only few elements + /// are affected, the heap's sort ensures this is faster than a reconstruction from the raw + /// element list and requires no additional allocation. + /// + /// ``` + /// #![feature(binary_heap_peek_mut_refresh)] + /// use std::collections::BinaryHeap; + /// + /// let mut heap: BinaryHeap = (0..128).collect(); + /// let mut peek = heap.peek_mut().unwrap(); + /// + /// loop { + /// *peek = 99; + /// + /// if !peek.refresh() { + /// break; + /// } + /// } + /// + /// // Post condition, this is now an upper bound. + /// assert!(*peek < 100); + /// ``` + /// + /// When the element remains the maximum after modification, the peek remains unchanged: + /// + /// ``` + /// #![feature(binary_heap_peek_mut_refresh)] + /// use std::collections::BinaryHeap; + /// + /// let mut heap: BinaryHeap = [1, 2, 3].into(); + /// let mut peek = heap.peek_mut().unwrap(); + /// + /// assert_eq!(*peek, 3); + /// *peek = 42; + /// + /// // When we refresh, the peek is updated to the new maximum. + /// assert!(!peek.refresh(), "42 is even larger than 3"); + /// assert_eq!(*peek, 42); + /// ``` + #[unstable(feature = "binary_heap_peek_mut_refresh", issue = "138355")] + #[must_use = "is equivalent to dropping and getting a new PeekMut except for return information"] + pub fn refresh(&mut self) -> bool { + // The length of the underlying heap is unchanged by sifting down. The value stored for leak + // amplification thus remains accurate. We erase the leak amplification firstly because the + // operation is then equivalent to constructing a new PeekMut and secondly this avoids any + // future complication where original_len being non-empty would be interpreted as the heap + // having been leak amplified instead of checking the heap itself. + if let Some(original_len) = self.original_len.take() { + // SAFETY: This is how many elements were in the Vec at the time of + // the BinaryHeap::peek_mut call. + unsafe { self.heap.data.set_len(original_len.get()) }; + + // The length of the heap did not change by sifting, upholding our own invariants. + + // SAFETY: PeekMut is only instantiated for non-empty heaps. + (unsafe { self.heap.sift_down(0) }) != 0 + } else { + // The element was not modified. + false + } + } + /// Removes the peeked value from the heap and returns it. #[stable(feature = "binary_heap_peek_mut_pop", since = "1.18.0")] pub fn pop(mut this: PeekMut<'a, T, A>) -> T { @@ -670,6 +740,8 @@ impl BinaryHeap { /// # Safety /// /// The caller must guarantee that `pos < self.len()`. + /// + /// Returns the new position of the element. unsafe fn sift_up(&mut self, start: usize, pos: usize) -> usize { // Take out the value at `pos` and create a hole. // SAFETY: The caller guarantees that pos < self.len() @@ -696,10 +768,12 @@ impl BinaryHeap { /// Take an element at `pos` and move it down the heap, /// while its children are larger. /// + /// Returns the new position of the element. + /// /// # Safety /// /// The caller must guarantee that `pos < end <= self.len()`. - unsafe fn sift_down_range(&mut self, pos: usize, end: usize) { + unsafe fn sift_down_range(&mut self, pos: usize, end: usize) -> usize { // SAFETY: The caller guarantees that pos < end <= self.len(). let mut hole = unsafe { Hole::new(&mut self.data, pos) }; let mut child = 2 * hole.pos() + 1; @@ -719,7 +793,7 @@ impl BinaryHeap { // SAFETY: child is now either the old child or the old child+1 // We already proven that both are < self.len() and != hole.pos() if hole.element() >= unsafe { hole.get(child) } { - return; + return hole.pos(); } // SAFETY: same as above. @@ -734,16 +808,18 @@ impl BinaryHeap { // child == 2 * hole.pos() + 1 != hole.pos(). unsafe { hole.move_to(child) }; } + + hole.pos() } /// # Safety /// /// The caller must guarantee that `pos < self.len()`. - unsafe fn sift_down(&mut self, pos: usize) { + unsafe fn sift_down(&mut self, pos: usize) -> usize { let len = self.len(); // SAFETY: pos < len is guaranteed by the caller and // obviously len = self.len() <= self.len(). - unsafe { self.sift_down_range(pos, len) }; + unsafe { self.sift_down_range(pos, len) } } /// Take an element at `pos` and move it all the way down the heap, @@ -1600,6 +1676,7 @@ unsafe impl InPlaceIterable for IntoIter { const MERGE_BY: Option> = NonZero::new(1); } +#[cfg(not(test))] unsafe impl AsVecIntoIter for IntoIter { type Item = I; diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 6d305386dbfa0..78b7da9d6b3ee 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -289,7 +289,7 @@ impl Clone for BTreeMap { } } -/// Internal functionality for `BTreeSet`. +// Internal functionality for `BTreeSet`. impl BTreeMap { pub(super) fn replace(&mut self, key: K) -> Option where diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index ecd009f11c71a..7d1a2ea480943 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -92,8 +92,8 @@ fn test_partial_eq() { #[cfg(target_arch = "x86_64")] #[cfg_attr(any(miri, randomized_layouts), ignore)] // We'd like to run Miri with layout randomization fn test_sizes() { - assert_eq!(core::mem::size_of::>(), 16); - assert_eq!(core::mem::size_of::>(), 16 + CAPACITY * 2 * 8); - assert_eq!(core::mem::size_of::>(), 16 + (CAPACITY + 1) * 8); - assert_eq!(core::mem::size_of::>(), 16 + (CAPACITY * 3 + 1) * 8); + assert_eq!(size_of::>(), 16); + assert_eq!(size_of::>(), 16 + CAPACITY * 2 * 8); + assert_eq!(size_of::>(), 16 + (CAPACITY + 1) * 8); + assert_eq!(size_of::>(), 16 + (CAPACITY * 3 + 1) * 8); } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 13168b7a39fe4..3183268b4b32e 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1140,7 +1140,6 @@ impl LinkedList { /// Splitting a list into evens and odds, reusing the original list: /// /// ``` - /// #![feature(extract_if)] /// use std::collections::LinkedList; /// /// let mut numbers: LinkedList = LinkedList::new(); @@ -1152,7 +1151,7 @@ impl LinkedList { /// assert_eq!(evens.into_iter().collect::>(), vec![2, 4, 6, 8, 14]); /// assert_eq!(odds.into_iter().collect::>(), vec![1, 3, 5, 9, 11, 13, 15]); /// ``` - #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] + #[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -1932,7 +1931,7 @@ impl<'a, T, A: Allocator> CursorMut<'a, T, A> { } /// An iterator produced by calling `extract_if` on LinkedList. -#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -1947,7 +1946,7 @@ pub struct ExtractIf< old_len: usize, } -#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -1976,7 +1975,7 @@ where } } -#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] impl fmt::Debug for ExtractIf<'_, T, F> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("ExtractIf").field(&self.list).finish() diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 020cf4d736510..fac4d1a65abcb 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -1,5 +1,8 @@ //! Collection types. +// Note: This module is also included in the alloctests crate using #[path] to +// run the tests. See the comment there for an explanation why this is the case. + #![stable(feature = "rust1", since = "1.0.0")] #[cfg(not(no_global_oom_handling))] @@ -24,41 +27,54 @@ pub mod btree_map { pub mod btree_set { //! An ordered set based on a B-Tree. #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(not(test))] pub use super::btree::set::*; } +#[cfg(not(test))] use core::fmt::Display; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use binary_heap::BinaryHeap; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use btree_map::BTreeMap; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use btree_set::BTreeSet; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use linked_list::LinkedList; #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[doc(no_inline)] +#[cfg(not(test))] pub use vec_deque::VecDeque; +#[cfg(not(test))] use crate::alloc::{Layout, LayoutError}; /// The error type for `try_reserve` methods. #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] pub struct TryReserveError { kind: TryReserveErrorKind, } +#[cfg(test)] +pub use realalloc::collections::TryReserveError; + +#[cfg(not(test))] impl TryReserveError { /// Details about the allocation that caused the error #[inline] @@ -80,6 +96,7 @@ impl TryReserveError { reason = "Uncertain how much info should be exposed", issue = "48043" )] +#[cfg(not(test))] pub enum TryReserveErrorKind { /// Error due to the computed capacity exceeding the collection's maximum /// (usually `isize::MAX` bytes). @@ -103,11 +120,15 @@ pub enum TryReserveErrorKind { }, } +#[cfg(test)] +pub use realalloc::collections::TryReserveErrorKind; + #[unstable( feature = "try_reserve_kind", reason = "Uncertain how much info should be exposed", issue = "48043" )] +#[cfg(not(test))] impl From for TryReserveError { #[inline] fn from(kind: TryReserveErrorKind) -> Self { @@ -116,6 +137,7 @@ impl From for TryReserveError { } #[unstable(feature = "try_reserve_kind", reason = "new API", issue = "48043")] +#[cfg(not(test))] impl From for TryReserveErrorKind { /// Always evaluates to [`TryReserveErrorKind::CapacityOverflow`]. #[inline] @@ -125,6 +147,7 @@ impl From for TryReserveErrorKind { } #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] impl Display for TryReserveError { fn fmt( &self, @@ -152,4 +175,5 @@ trait SpecExtend { } #[stable(feature = "try_reserve", since = "1.57.0")] +#[cfg(not(test))] impl core::error::Error for TryReserveError {} diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 299c8b8679e3d..f8844e2d3a5cb 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -645,6 +645,7 @@ impl VecDeque { /// initialized rather than only supporting `0..len`. Requires that /// `initialized.start` ≤ `initialized.end` ≤ `capacity`. #[inline] + #[cfg(not(test))] pub(crate) unsafe fn from_contiguous_raw_parts_in( ptr: *mut T, initialized: Range, diff --git a/library/alloc/src/collections/vec_deque/spec_extend.rs b/library/alloc/src/collections/vec_deque/spec_extend.rs index d246385ca8419..7c7072c4c3a1b 100644 --- a/library/alloc/src/collections/vec_deque/spec_extend.rs +++ b/library/alloc/src/collections/vec_deque/spec_extend.rs @@ -3,6 +3,7 @@ use core::slice; use super::VecDeque; use crate::alloc::Allocator; +#[cfg(not(test))] use crate::vec; // Specialization trait used for VecDeque::extend @@ -78,6 +79,7 @@ where } } +#[cfg(not(test))] impl SpecExtend> for VecDeque { #[track_caller] fn spec_extend(&mut self, mut iterator: vec::IntoIter) { diff --git a/library/alloc/src/collections/vec_deque/spec_from_iter.rs b/library/alloc/src/collections/vec_deque/spec_from_iter.rs index 1efe84d6d7d7d..c80a30c2103dd 100644 --- a/library/alloc/src/collections/vec_deque/spec_from_iter.rs +++ b/library/alloc/src/collections/vec_deque/spec_from_iter.rs @@ -19,6 +19,7 @@ where } } +#[cfg(not(test))] impl SpecFromIter> for VecDeque { #[inline] fn spec_from_iter(iterator: crate::vec::IntoIter) -> Self { diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index fd93045a5ac4d..f6743c6571095 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -10,7 +10,6 @@ use core::{fmt, mem, ops, ptr, slice}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::Rc; -use crate::slice::hack::into_vec; use crate::string::String; #[cfg(target_has_atomic = "ptr")] use crate::sync::Arc; @@ -103,7 +102,7 @@ use crate::vec::Vec; /// of `CString` instances can lead to invalid memory accesses, memory leaks, /// and other memory errors. #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] -#[cfg_attr(not(test), rustc_diagnostic_item = "cstring_type")] +#[rustc_diagnostic_item = "cstring_type"] #[stable(feature = "alloc_c_string", since = "1.64.0")] pub struct CString { // Invariant 1: the slice ends with a zero byte and has a length of at least one. @@ -491,7 +490,7 @@ impl CString { #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes(self) -> Vec { - let mut vec = into_vec(self.into_inner()); + let mut vec = self.into_inner().into_vec(); let _nul = vec.pop(); debug_assert_eq!(_nul, Some(0u8)); vec @@ -512,7 +511,7 @@ impl CString { #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_bytes_with_nul(self) -> Vec { - into_vec(self.into_inner()) + self.into_inner().into_vec() } /// Returns the contents of this `CString` as a slice of bytes. @@ -573,7 +572,7 @@ impl CString { #[inline] #[must_use] #[stable(feature = "as_c_str", since = "1.20.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "cstring_as_c_str")] + #[rustc_diagnostic_item = "cstring_as_c_str"] pub fn as_c_str(&self) -> &CStr { &*self } @@ -755,7 +754,6 @@ impl<'a> From> for CString { } } -#[cfg(not(test))] #[stable(feature = "box_from_c_str", since = "1.17.0")] impl From<&CStr> for Box { /// Converts a `&CStr` into a `Box`, @@ -766,7 +764,6 @@ impl From<&CStr> for Box { } } -#[cfg(not(test))] #[stable(feature = "box_from_mut_slice", since = "1.84.0")] impl From<&mut CStr> for Box { /// Converts a `&mut CStr` into a `Box`, @@ -845,7 +842,6 @@ impl TryFrom for String { } } -#[cfg(not(test))] #[stable(feature = "more_box_slice_clone", since = "1.29.0")] impl Clone for Box { #[inline] @@ -971,7 +967,6 @@ impl Default for Rc { } } -#[cfg(not(test))] #[stable(feature = "default_box_extra", since = "1.17.0")] impl Default for Box { fn default() -> Box { @@ -1080,7 +1075,7 @@ impl ToOwned for CStr { } fn clone_into(&self, target: &mut CString) { - let mut b = into_vec(mem::take(&mut target.inner)); + let mut b = mem::take(&mut target.inner).into_vec(); self.to_bytes_with_nul().clone_into(&mut b); target.inner = b.into_boxed_slice(); } @@ -1113,7 +1108,6 @@ impl AsRef for CString { } } -#[cfg(not(test))] impl CStr { /// Converts a `CStr` into a [Cow]<[str]>. /// diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b16d40e988e15..f0cdb1e4e0f78 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,6 +56,7 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell +#![allow(incomplete_features)] #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -92,7 +93,6 @@ // // Library features: // tidy-alphabetical-start -#![cfg_attr(test, feature(str_as_str))] #![feature(alloc_layout_extra)] #![feature(allocator_api)] #![feature(array_chunks)] @@ -102,7 +102,6 @@ #![feature(assert_matches)] #![feature(async_fn_traits)] #![feature(async_iterator)] -#![feature(box_uninit_write)] #![feature(bstr)] #![feature(bstr_internals)] #![feature(char_max_len)] @@ -114,6 +113,7 @@ #![feature(deprecated_suggestion)] #![feature(deref_pure_trait)] #![feature(dispatch_from_dyn)] +#![feature(ergonomic_clones)] #![feature(error_generic_member_access)] #![feature(exact_size_is_empty)] #![feature(extend_one)] @@ -137,7 +137,6 @@ #![feature(pointer_like_trait)] #![feature(ptr_internals)] #![feature(ptr_metadata)] -#![feature(ptr_sub_ptr)] #![feature(set_ptr_value)] #![feature(sized_type_properties)] #![feature(slice_from_ptr_range)] @@ -161,13 +160,11 @@ // // Language features: // tidy-alphabetical-start -#![cfg_attr(not(test), feature(coroutine_trait))] -#![cfg_attr(test, feature(panic_update_hook))] -#![cfg_attr(test, feature(test))] #![feature(allocator_internals)] #![feature(allow_internal_unstable)] #![feature(cfg_sanitize)] #![feature(const_precise_live_drops)] +#![feature(coroutine_trait)] #![feature(decl_macro)] #![feature(dropck_eyepatch)] #![feature(fundamental)] @@ -200,15 +197,6 @@ // from other crates, but since this can only appear for lang items, it doesn't seem worth fixing. #![feature(intra_doc_pointers)] -// Allow testing this library -#[cfg(test)] -#[macro_use] -extern crate std; -#[cfg(test)] -extern crate test; -#[cfg(test)] -mod testing; - // Module with internal macros used by other modules (needs to be included before other modules). #[macro_use] mod macros; @@ -216,7 +204,6 @@ mod macros; mod raw_vec; // Heaps provided for low-level allocation strategies - pub mod alloc; // Primitive types using the heaps above @@ -224,13 +211,8 @@ pub mod alloc; // Need to conditionally define the mod from `boxed.rs` to avoid // duplicating the lang-items when building in test cfg; but also need // to allow code to have `use boxed::Box;` declarations. -#[cfg(not(test))] -pub mod boxed; -#[cfg(test)] -mod boxed { - pub(crate) use std::boxed::Box; -} pub mod borrow; +pub mod boxed; #[unstable(feature = "bstr", issue = "134915")] pub mod bstr; pub mod collections; @@ -254,20 +236,3 @@ pub mod __export { pub use core::format_args; pub use core::hint::must_use; } - -#[cfg(test)] -#[allow(dead_code)] // Not used in all configurations -pub(crate) mod test_helpers { - /// Copied from `std::test_helpers::test_rng`, since these tests rely on the - /// seed not being the same for every RNG invocation too. - pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { - use std::hash::{BuildHasher, Hash, Hasher}; - let mut hasher = std::hash::RandomState::new().build_hasher(); - std::panic::Location::caller().hash(&mut hasher); - let hc64 = hasher.finish(); - let seed_vec = - hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); - let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); - rand::SeedableRng::from_seed(seed) - } -} diff --git a/library/alloc/src/macros.rs b/library/alloc/src/macros.rs index c000fd6f4efa7..214192b8c9a9b 100644 --- a/library/alloc/src/macros.rs +++ b/library/alloc/src/macros.rs @@ -34,7 +34,7 @@ /// be mindful of side effects. /// /// [`Vec`]: crate::vec::Vec -#[cfg(all(not(no_global_oom_handling), not(test)))] +#[cfg(not(no_global_oom_handling))] #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "vec_macro"] @@ -55,25 +55,6 @@ macro_rules! vec { ); } -// HACK(japaric): with cfg(test) the inherent `[T]::into_vec` method, which is -// required for this macro definition, is not available. Instead use the -// `slice::into_vec` function which is only available with cfg(test) -// NB see the slice::hack module in slice.rs for more information -#[cfg(all(not(no_global_oom_handling), test))] -#[allow(unused_macro_rules)] -macro_rules! vec { - () => ( - $crate::vec::Vec::new() - ); - ($elem:expr; $n:expr) => ( - $crate::vec::from_elem($elem, $n) - ); - ($($x:expr),*) => ( - $crate::slice::into_vec($crate::boxed::Box::new([$($x),*])) - ); - ($($x:expr,)*) => (vec![$($x),*]) -} - /// Creates a `String` using interpolation of runtime expressions. /// /// The first argument `format!` receives is a format string. This must be a string @@ -120,7 +101,7 @@ macro_rules! vec { #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] #[allow_internal_unstable(hint_must_use, liballoc_internals)] -#[cfg_attr(not(test), rustc_diagnostic_item = "format_macro")] +#[rustc_diagnostic_item = "format_macro"] macro_rules! format { ($($arg:tt)*) => { $crate::__export::must_use({ diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec/mod.rs similarity index 98% rename from library/alloc/src/raw_vec.rs rename to library/alloc/src/raw_vec/mod.rs index b80d1fc788947..99ebc5c4bfca8 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -1,4 +1,8 @@ #![unstable(feature = "raw_vec_internals", reason = "unstable const warnings", issue = "none")] +#![cfg_attr(test, allow(dead_code))] + +// Note: This module is also included in the alloctests crate using #[path] to +// run the tests. See the comment there for an explanation why this is the case. use core::marker::PhantomData; use core::mem::{ManuallyDrop, MaybeUninit, SizedTypeProperties}; @@ -480,7 +484,7 @@ impl RawVecInner { // Allocators currently return a `NonNull<[u8]>` whose length // matches the size requested. If that ever changes, the capacity - // here should change to `ptr.len() / mem::size_of::()`. + // here should change to `ptr.len() / size_of::()`. Ok(Self { ptr: Unique::from(ptr.cast()), cap: unsafe { Cap::new_unchecked(capacity) }, @@ -627,7 +631,7 @@ impl RawVecInner { unsafe fn set_ptr_and_cap(&mut self, ptr: NonNull<[u8]>, cap: usize) { // Allocators currently return a `NonNull<[u8]>` whose length matches // the size requested. If that ever changes, the capacity here should - // change to `ptr.len() / mem::size_of::()`. + // change to `ptr.len() / size_of::()`. self.ptr = Unique::from(ptr.cast()); self.cap = unsafe { Cap::new_unchecked(cap) }; } diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index d78ded104fb09..700fa922739d6 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -1,4 +1,3 @@ -use core::mem::size_of; use std::cell::Cell; use super::*; @@ -93,7 +92,7 @@ fn zst_sanity(v: &RawVec) { fn zst() { let cap_err = Err(crate::collections::TryReserveErrorKind::CapacityOverflow.into()); - assert_eq!(std::mem::size_of::(), 0); + assert_eq!(size_of::(), 0); // All these different ways of creating the RawVec produce the same thing. diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 09206c2f8b290..619d9f258e342 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -245,6 +245,7 @@ use core::any::Any; use core::cell::Cell; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -262,23 +263,17 @@ use core::ptr::{self, NonNull, drop_in_place}; #[cfg(not(no_global_oom_handling))] use core::slice::from_raw_parts_mut; use core::{borrow, fmt, hint}; -#[cfg(test)] -use std::boxed::Box; #[cfg(not(no_global_oom_handling))] use crate::alloc::handle_alloc_error; use crate::alloc::{AllocError, Allocator, Global, Layout}; use crate::borrow::{Cow, ToOwned}; -#[cfg(not(test))] use crate::boxed::Box; #[cfg(not(no_global_oom_handling))] use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; -#[cfg(test)] -mod tests; - // This is repr(C) to future-proof against possible field-reordering, which // would interfere with otherwise safe [into|from]_raw() of transmutable // inner types. @@ -309,7 +304,7 @@ fn rc_inner_layout_for_value_layout(layout: Layout) -> Layout { /// /// [get_mut]: Rc::get_mut #[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Rc")] +#[rustc_diagnostic_item = "Rc"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct Rc< @@ -1332,11 +1327,14 @@ impl Rc { /// /// # Safety /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// The pointer must have been obtained through `Rc::into_raw` and must satisfy the + /// same layout requirements specified in [`Rc::from_raw_in`][from_raw_in]. + /// The associated `Rc` instance must be valid (i.e. the strong count must be at /// least 1) for the duration of this method, and `ptr` must point to a block of memory /// allocated by the global allocator. /// + /// [from_raw_in]: Rc::from_raw_in + /// /// # Examples /// /// ``` @@ -1365,12 +1363,15 @@ impl Rc { /// /// # Safety /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// The pointer must have been obtained through `Rc::into_raw`and must satisfy the + /// same layout requirements specified in [`Rc::from_raw_in`][from_raw_in]. + /// The associated `Rc` instance must be valid (i.e. the strong count must be at /// least 1) when invoking this method, and `ptr` must point to a block of memory /// allocated by the global allocator. This method can be used to release the final `Rc` and /// backing storage, but **should not** be called after the final `Rc` has been released. /// + /// [from_raw_in]: Rc::from_raw_in + /// /// # Examples /// /// ``` @@ -1628,10 +1629,13 @@ impl Rc { /// /// # Safety /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// The pointer must have been obtained through `Rc::into_raw` and must satisfy the + /// same layout requirements specified in [`Rc::from_raw_in`][from_raw_in]. + /// The associated `Rc` instance must be valid (i.e. the strong count must be at /// least 1) for the duration of this method, and `ptr` must point to a block of memory - /// allocated by `alloc` + /// allocated by `alloc`. + /// + /// [from_raw_in]: Rc::from_raw_in /// /// # Examples /// @@ -1670,11 +1674,14 @@ impl Rc { /// /// # Safety /// - /// The pointer must have been obtained through `Rc::into_raw`, the - /// associated `Rc` instance must be valid (i.e. the strong count must be at + /// The pointer must have been obtained through `Rc::into_raw`and must satisfy the + /// same layout requirements specified in [`Rc::from_raw_in`][from_raw_in]. + /// The associated `Rc` instance must be valid (i.e. the strong count must be at /// least 1) when invoking this method, and `ptr` must point to a block of memory - /// allocated by `alloc`. This method can be used to release the final `Rc` and backing storage, - /// but **should not** be called after the final `Rc` has been released. + /// allocated by `alloc`. This method can be used to release the final `Rc` and + /// backing storage, but **should not** be called after the final `Rc` has been released. + /// + /// [from_raw_in]: Rc::from_raw_in /// /// # Examples /// @@ -2333,6 +2340,9 @@ impl Clone for Rc { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Rc {} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Default for Rc { @@ -2984,7 +2994,7 @@ impl> ToRcSlice for I { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "rc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "RcWeak")] +#[rustc_diagnostic_item = "RcWeak"] pub struct Weak< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -3496,6 +3506,9 @@ impl Clone for Weak { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Weak {} + #[stable(feature = "rc_weak", since = "1.4.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index c83b1962eb691..7c5d22e1ee9be 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -8,15 +8,12 @@ //! A few functions are provided to create a slice from a value reference //! or from a raw pointer. #![stable(feature = "rust1", since = "1.0.0")] -// Many of the usings in this module are only used in the test configuration. -// It's cleaner to just turn off the unused_imports warning than to fix them. -#![cfg_attr(test, allow(unused_imports, dead_code))] use core::borrow::{Borrow, BorrowMut}; #[cfg(not(no_global_oom_handling))] use core::cmp::Ordering::{self, Less}; #[cfg(not(no_global_oom_handling))] -use core::mem::{self, MaybeUninit}; +use core::mem::MaybeUninit; #[cfg(not(no_global_oom_handling))] use core::ptr; #[unstable(feature = "array_chunks", issue = "74985")] @@ -27,7 +24,7 @@ pub use core::slice::ArrayChunksMut; pub use core::slice::ArrayWindows; #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use core::slice::EscapeAscii; -#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "get_many_mut", since = "1.86.0")] pub use core::slice::GetDisjointMutError; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; @@ -63,16 +60,6 @@ pub use core::slice::{range, try_range}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods //////////////////////////////////////////////////////////////////////////////// - -// HACK(japaric) needed for the implementation of `vec!` macro during testing -// N.B., see the `hack` module in this file for more details. -#[cfg(test)] -pub use hack::into_vec; -// HACK(japaric) needed for the implementation of `Vec::clone` during testing -// N.B., see the `hack` module in this file for more details. -#[cfg(test)] -pub use hack::to_vec; - use crate::alloc::Allocator; #[cfg(not(no_global_oom_handling))] use crate::alloc::Global; @@ -81,98 +68,6 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; -// HACK(japaric): With cfg(test) `impl [T]` is not available, these three -// functions are actually methods that are in `impl [T]` but not in -// `core::slice::SliceExt` - we need to supply these functions for the -// `test_permutations` test -#[allow(unreachable_pub)] // cfg(test) pub above -pub(crate) mod hack { - use core::alloc::Allocator; - - use crate::boxed::Box; - use crate::vec::Vec; - - // We shouldn't add inline attribute to this since this is used in - // `vec!` macro mostly and causes perf regression. See #71204 for - // discussion and perf results. - #[allow(missing_docs)] - pub fn into_vec(b: Box<[T], A>) -> Vec { - unsafe { - let len = b.len(); - let (b, alloc) = Box::into_raw_with_allocator(b); - Vec::from_raw_parts_in(b as *mut T, len, len, alloc) - } - } - - #[cfg(not(no_global_oom_handling))] - #[allow(missing_docs)] - #[inline] - pub fn to_vec(s: &[T], alloc: A) -> Vec { - T::to_vec(s, alloc) - } - - #[cfg(not(no_global_oom_handling))] - pub trait ConvertVec { - fn to_vec(s: &[Self], alloc: A) -> Vec - where - Self: Sized; - } - - #[cfg(not(no_global_oom_handling))] - impl ConvertVec for T { - #[inline] - default fn to_vec(s: &[Self], alloc: A) -> Vec { - struct DropGuard<'a, T, A: Allocator> { - vec: &'a mut Vec, - num_init: usize, - } - impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { - #[inline] - fn drop(&mut self) { - // SAFETY: - // items were marked initialized in the loop below - unsafe { - self.vec.set_len(self.num_init); - } - } - } - let mut vec = Vec::with_capacity_in(s.len(), alloc); - let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; - let slots = guard.vec.spare_capacity_mut(); - // .take(slots.len()) is necessary for LLVM to remove bounds checks - // and has better codegen than zip. - for (i, b) in s.iter().enumerate().take(slots.len()) { - guard.num_init = i; - slots[i].write(b.clone()); - } - core::mem::forget(guard); - // SAFETY: - // the vec was allocated and initialized above to at least this length. - unsafe { - vec.set_len(s.len()); - } - vec - } - } - - #[cfg(not(no_global_oom_handling))] - impl ConvertVec for T { - #[inline] - fn to_vec(s: &[Self], alloc: A) -> Vec { - let mut v = Vec::with_capacity_in(s.len(), alloc); - // SAFETY: - // allocated above with the capacity of `s`, and initialize to `s.len()` in - // ptr::copy_to_non_overlapping below. - unsafe { - s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); - v.set_len(s.len()); - } - v - } - } -} - -#[cfg(not(test))] impl [T] { /// Sorts the slice, preserving initial order of equal elements. /// @@ -446,7 +341,7 @@ impl [T] { // Avoids binary-size usage in cases where the alignment doesn't work out to make this // beneficial or on 32-bit platforms. let is_using_u32_as_idx_type_helpful = - const { mem::size_of::<(K, u32)>() < mem::size_of::<(K, usize)>() }; + const { size_of::<(K, u32)>() < size_of::<(K, usize)>() }; // It's possible to instantiate this for u8 and u16 but, doing so is very wasteful in terms // of compile-times and binary-size, the peak saved heap memory for u16 is (u8 + u16) -> 4 @@ -501,8 +396,64 @@ impl [T] { where T: Clone, { - // N.B., see the `hack` module in this file for more details. - hack::to_vec(self, alloc) + return T::to_vec(self, alloc); + + trait ConvertVec { + fn to_vec(s: &[Self], alloc: A) -> Vec + where + Self: Sized; + } + + impl ConvertVec for T { + #[inline] + default fn to_vec(s: &[Self], alloc: A) -> Vec { + struct DropGuard<'a, T, A: Allocator> { + vec: &'a mut Vec, + num_init: usize, + } + impl<'a, T, A: Allocator> Drop for DropGuard<'a, T, A> { + #[inline] + fn drop(&mut self) { + // SAFETY: + // items were marked initialized in the loop below + unsafe { + self.vec.set_len(self.num_init); + } + } + } + let mut vec = Vec::with_capacity_in(s.len(), alloc); + let mut guard = DropGuard { vec: &mut vec, num_init: 0 }; + let slots = guard.vec.spare_capacity_mut(); + // .take(slots.len()) is necessary for LLVM to remove bounds checks + // and has better codegen than zip. + for (i, b) in s.iter().enumerate().take(slots.len()) { + guard.num_init = i; + slots[i].write(b.clone()); + } + core::mem::forget(guard); + // SAFETY: + // the vec was allocated and initialized above to at least this length. + unsafe { + vec.set_len(s.len()); + } + vec + } + } + + impl ConvertVec for T { + #[inline] + fn to_vec(s: &[Self], alloc: A) -> Vec { + let mut v = Vec::with_capacity_in(s.len(), alloc); + // SAFETY: + // allocated above with the capacity of `s`, and initialize to `s.len()` in + // ptr::copy_to_non_overlapping below. + unsafe { + s.as_ptr().copy_to_nonoverlapping(v.as_mut_ptr(), s.len()); + v.set_len(s.len()); + } + v + } + } } /// Converts `self` into a vector without clones or allocation. @@ -522,10 +473,13 @@ impl [T] { #[rustc_allow_incoherent_impl] #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[cfg_attr(not(test), rustc_diagnostic_item = "slice_into_vec")] + #[rustc_diagnostic_item = "slice_into_vec"] pub fn into_vec(self: Box) -> Vec { - // N.B., see the `hack` module in this file for more details. - hack::into_vec(self) + unsafe { + let len = self.len(); + let (b, alloc) = Box::into_raw_with_allocator(self); + Vec::from_raw_parts_in(b as *mut T, len, len, alloc) + } } /// Creates a vector by copying a slice `n` times. @@ -666,7 +620,6 @@ impl [T] { } } -#[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte /// is mapped to its ASCII upper case equivalent. @@ -883,14 +836,9 @@ impl SpecCloneIntoVec for [T] { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for [T] { type Owned = Vec; - #[cfg(not(test))] - fn to_owned(&self) -> Vec { - self.to_vec() - } - #[cfg(test)] fn to_owned(&self) -> Vec { - hack::to_vec(self, Global) + self.to_vec() } fn clone_into(&self, target: &mut Vec) { diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 6fee8d3fe3346..0664f2c3cf2c1 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -219,7 +219,6 @@ impl ToOwned for str { } /// Methods for string slices. -#[cfg(not(test))] impl str { /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. /// @@ -631,7 +630,6 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { #[unstable(feature = "str_internals", issue = "none")] #[doc(hidden)] #[inline] -#[cfg(not(test))] #[cfg(not(no_global_oom_handling))] pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { // Process the input in chunks of 16 bytes to enable auto-vectorization. @@ -704,7 +702,6 @@ pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { } } #[inline] -#[cfg(not(test))] #[cfg(not(no_global_oom_handling))] #[allow(dead_code)] /// Faster implementation of string replacement for ASCII to ASCII cases. diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 9446afd4b24b0..9236f5cb8d1f0 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -119,8 +119,6 @@ use crate::vec::{self, Vec}; /// the same `char`s: /// /// ``` -/// use std::mem; -/// /// // `s` is ASCII which represents each `char` as one byte /// let s = "hello"; /// assert_eq!(s.len(), 5); @@ -128,7 +126,7 @@ use crate::vec::{self, Vec}; /// // A `char` array with the same contents would be longer because /// // every `char` is four bytes /// let s = ['h', 'e', 'l', 'l', 'o']; -/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum(); +/// let size: usize = s.into_iter().map(|c| size_of_val(&c)).sum(); /// assert_eq!(size, 20); /// /// // However, for non-ASCII strings, the difference will be smaller @@ -137,7 +135,7 @@ use crate::vec::{self, Vec}; /// assert_eq!(s.len(), 20); /// /// let s = ['💖', '💖', '💖', '💖', '💖']; -/// let size: usize = s.into_iter().map(|c| mem::size_of_val(&c)).sum(); +/// let size: usize = s.into_iter().map(|c| size_of_val(&c)).sum(); /// assert_eq!(size, 20); /// ``` /// @@ -358,7 +356,7 @@ use crate::vec::{self, Vec}; /// [`as_str()`]: String::as_str #[derive(PartialEq, PartialOrd, Eq, Ord)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), lang = "String")] +#[lang = "String"] pub struct String { vec: Vec, } @@ -440,7 +438,7 @@ impl String { /// ``` #[inline] #[rustc_const_stable(feature = "const_string_new", since = "1.39.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_new")] + #[rustc_diagnostic_item = "string_new"] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> String { @@ -503,17 +501,6 @@ impl String { Ok(String { vec: Vec::try_with_capacity(capacity)? }) } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Since we don't - // require this method for testing purposes, I'll just stub it - // NB see the slice::hack module in slice.rs for more information - #[inline] - #[cfg(test)] - #[allow(missing_docs)] - pub fn from_str(_: &str) -> String { - panic!("not available with cfg(test)"); - } - /// Converts a vector of bytes to a `String`. /// /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes @@ -572,7 +559,7 @@ impl String { /// [`into_bytes`]: String::into_bytes #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_from_utf8")] + #[rustc_diagnostic_item = "string_from_utf8"] pub fn from_utf8(vec: Vec) -> Result { match str::from_utf8(&vec) { Ok(..) => Ok(String { vec }), @@ -966,11 +953,8 @@ impl String { /// This is highly unsafe, due to the number of invariants that aren't /// checked: /// - /// * The memory at `buf` needs to have been previously allocated by the - /// same allocator the standard library uses, with a required alignment of exactly 1. - /// * `length` needs to be less than or equal to `capacity`. - /// * `capacity` needs to be the correct value. - /// * The first `length` bytes at `buf` need to be valid UTF-8. + /// * all safety requirements for [`Vec::::from_raw_parts`]. + /// * all safety requirements for [`String::from_utf8_unchecked`]. /// /// Violating these may cause problems like corrupting the allocator's /// internal data structures. For example, it is normally **not** safe to @@ -1059,7 +1043,8 @@ impl String { #[inline] #[must_use = "`self` will be dropped if the result is not used"] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_bytes(self) -> Vec { self.vec } @@ -1076,8 +1061,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_str")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "string_as_str"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_str(&self) -> &str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1099,8 +1084,8 @@ impl String { #[inline] #[must_use] #[stable(feature = "string_as_str", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_as_mut_str")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "string_as_mut_str"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_mut_str(&mut self) -> &mut str { // SAFETY: String contents are stipulated to be valid UTF-8, invalid contents are an error // at construction. @@ -1122,7 +1107,7 @@ impl String { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("append", "push")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_push_str")] + #[rustc_diagnostic_item = "string_push_str"] pub fn push_str(&mut self, string: &str) { self.vec.extend_from_slice(string.as_bytes()) } @@ -1137,7 +1122,6 @@ impl String { /// # Examples /// /// ``` - /// #![feature(string_extend_from_within)] /// let mut string = String::from("abcde"); /// /// string.extend_from_within(2..); @@ -1150,7 +1134,7 @@ impl String { /// assert_eq!(string, "abcdecdeabecde"); /// ``` #[cfg(not(no_global_oom_handling))] - #[unstable(feature = "string_extend_from_within", issue = "103806")] + #[stable(feature = "string_extend_from_within", since = "CURRENT_RUSTC_VERSION")] pub fn extend_from_within(&mut self, src: R) where R: RangeBounds, @@ -1175,7 +1159,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn capacity(&self) -> usize { self.vec.capacity() } @@ -1441,7 +1425,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_bytes(&self) -> &[u8] { self.vec.as_slice() } @@ -1761,7 +1745,7 @@ impl String { #[cfg(not(no_global_oom_handling))] #[inline] #[stable(feature = "insert_str", since = "1.16.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "string_insert_str")] + #[rustc_diagnostic_item = "string_insert_str"] pub fn insert_str(&mut self, idx: usize, string: &str) { assert!(self.is_char_boundary(idx)); @@ -1795,7 +1779,7 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const unsafe fn as_mut_vec(&mut self) -> &mut Vec { &mut self.vec } @@ -1817,7 +1801,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { self.vec.len() @@ -1837,7 +1821,7 @@ impl String { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -2730,7 +2714,7 @@ impl FromStr for String { /// implementation for free. /// /// [`Display`]: fmt::Display -#[cfg_attr(not(test), rustc_diagnostic_item = "ToString")] +#[rustc_diagnostic_item = "ToString"] #[stable(feature = "rust1", since = "1.0.0")] pub trait ToString { /// Converts the given value to a `String`. @@ -2745,7 +2729,7 @@ pub trait ToString { /// ``` #[rustc_conversion_suggestion] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "to_string_method")] + #[rustc_diagnostic_item = "to_string_method"] fn to_string(&self) -> String; } @@ -2985,7 +2969,6 @@ impl From<&String> for String { } // note: test pulls in std, which causes errors here -#[cfg(not(test))] #[stable(feature = "string_from_box", since = "1.18.0")] impl From> for String { /// Converts the given boxed `str` slice to a [`String`]. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index dba1449347ac0..104cb35c23b65 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -11,6 +11,7 @@ use core::any::Any; #[cfg(not(no_global_oom_handling))] use core::clone::CloneToUninit; +use core::clone::UseCloned; use core::cmp::Ordering; use core::hash::{Hash, Hasher}; use core::intrinsics::abort; @@ -234,7 +235,7 @@ macro_rules! acquire { /// /// [rc_examples]: crate::rc#examples #[doc(search_unbox)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] +#[rustc_diagnostic_item = "Arc"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_insignificant_dtor] pub struct Arc< @@ -311,7 +312,7 @@ impl Arc { /// /// [`upgrade`]: Weak::upgrade #[stable(feature = "arc_weak", since = "1.4.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "ArcWeak")] +#[rustc_diagnostic_item = "ArcWeak"] pub struct Weak< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -1452,11 +1453,14 @@ impl Arc { /// /// # Safety /// - /// The pointer must have been obtained through `Arc::into_raw`, and the - /// associated `Arc` instance must be valid (i.e. the strong count must be at + /// The pointer must have been obtained through `Arc::into_raw` and must satisfy the + /// same layout requirements specified in [`Arc::from_raw_in`][from_raw_in]. + /// The associated `Arc` instance must be valid (i.e. the strong count must be at /// least 1) for the duration of this method, and `ptr` must point to a block of memory /// allocated by the global allocator. /// + /// [from_raw_in]: Arc::from_raw_in + /// /// # Examples /// /// ``` @@ -1487,13 +1491,16 @@ impl Arc { /// /// # Safety /// - /// The pointer must have been obtained through `Arc::into_raw`, and the - /// associated `Arc` instance must be valid (i.e. the strong count must be at + /// The pointer must have been obtained through `Arc::into_raw` and must satisfy the + /// same layout requirements specified in [`Arc::from_raw_in`][from_raw_in]. + /// The associated `Arc` instance must be valid (i.e. the strong count must be at /// least 1) when invoking this method, and `ptr` must point to a block of memory /// allocated by the global allocator. This method can be used to release the final /// `Arc` and backing storage, but **should not** be called after the final `Arc` has been /// released. /// + /// [from_raw_in]: Arc::from_raw_in + /// /// # Examples /// /// ``` @@ -1805,11 +1812,14 @@ impl Arc { /// /// # Safety /// - /// The pointer must have been obtained through `Arc::into_raw`, and the - /// associated `Arc` instance must be valid (i.e. the strong count must be at - /// least 1) for the duration of this method,, and `ptr` must point to a block of memory + /// The pointer must have been obtained through `Arc::into_raw` and must satisfy the + /// same layout requirements specified in [`Arc::from_raw_in`][from_raw_in]. + /// The associated `Arc` instance must be valid (i.e. the strong count must be at + /// least 1) for the duration of this method, and `ptr` must point to a block of memory /// allocated by `alloc`. /// + /// [from_raw_in]: Arc::from_raw_in + /// /// # Examples /// /// ``` @@ -1849,13 +1859,16 @@ impl Arc { /// /// # Safety /// - /// The pointer must have been obtained through `Arc::into_raw`, the - /// associated `Arc` instance must be valid (i.e. the strong count must be at + /// The pointer must have been obtained through `Arc::into_raw` and must satisfy the + /// same layout requirements specified in [`Arc::from_raw_in`][from_raw_in]. + /// The associated `Arc` instance must be valid (i.e. the strong count must be at /// least 1) when invoking this method, and `ptr` must point to a block of memory /// allocated by `alloc`. This method can be used to release the final /// `Arc` and backing storage, but **should not** be called after the final `Arc` has been /// released. /// + /// [from_raw_in]: Arc::from_raw_in + /// /// # Examples /// /// ``` @@ -2197,6 +2210,9 @@ impl Clone for Arc { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Arc {} + #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Arc { type Target = T; @@ -2274,7 +2290,7 @@ impl Arc { #[inline] #[stable(feature = "arc_unique", since = "1.4.0")] pub fn make_mut(this: &mut Self) -> &mut T { - let size_of_val = mem::size_of_val::(&**this); + let size_of_val = size_of_val::(&**this); // Note that we hold both a strong reference and a weak reference. // Thus, releasing our strong reference only will not, by itself, cause @@ -3158,6 +3174,9 @@ impl Clone for Weak { } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for Weak {} + #[stable(feature = "downgraded_weak", since = "1.10.0")] impl Default for Weak { /// Constructs a new `Weak`, without allocating memory. @@ -3544,7 +3563,7 @@ impl Default for Arc<[T]> { /// This may or may not share an allocation with other Arcs. #[inline] fn default() -> Self { - if mem::align_of::() <= MAX_STATIC_INNER_SLICE_ALIGNMENT { + if align_of::() <= MAX_STATIC_INNER_SLICE_ALIGNMENT { // We take a reference to the whole struct instead of the ArcInner<[u8; 1]> inside it so // we don't shrink the range of bytes the ptr is allowed to access under Stacked Borrows. // (Miri complains on 32-bit targets with Arc<[Align16]> otherwise.) diff --git a/library/alloc/src/vec/drain.rs b/library/alloc/src/vec/drain.rs index 9362cef2a1b00..8705a9c3d2679 100644 --- a/library/alloc/src/vec/drain.rs +++ b/library/alloc/src/vec/drain.rs @@ -232,7 +232,7 @@ impl Drop for Drain<'_, T, A> { // it from the original vec but also avoid creating a &mut to the front since that could // invalidate raw pointers to it which some unsafe code might rely on. let vec_ptr = vec.as_mut().as_mut_ptr(); - let drop_offset = drop_ptr.sub_ptr(vec_ptr); + let drop_offset = drop_ptr.offset_from_unsigned(vec_ptr); let to_drop = ptr::slice_from_raw_parts_mut(vec_ptr.add(drop_offset), drop_len); ptr::drop_in_place(to_drop); } diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index 4db13981596bc..be869553ef4e1 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -12,12 +12,10 @@ use crate::alloc::{Allocator, Global}; /// # Example /// /// ``` -/// #![feature(extract_if)] -/// /// let mut v = vec![0, 1, 2]; /// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` -#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] #[derive(Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< @@ -59,7 +57,7 @@ impl<'a, T, F, A: Allocator> ExtractIf<'a, T, F, A> { } } -#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -95,7 +93,7 @@ where } } -#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] impl Drop for ExtractIf<'_, T, F, A> { fn drop(&mut self) { unsafe { diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index a7dba16944e7d..b98a118048f2d 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -171,7 +171,7 @@ const fn in_place_collectible( ) -> bool { // Require matching alignments because an alignment-changing realloc is inefficient on many // system allocators and better implementations would require the unstable Allocator trait. - if const { SRC::IS_ZST || DEST::IS_ZST || mem::align_of::() != mem::align_of::() } { + if const { SRC::IS_ZST || DEST::IS_ZST || align_of::() != align_of::() } { return false; } @@ -181,7 +181,7 @@ const fn in_place_collectible( // e.g. // - 1 x [u8; 4] -> 4x u8, via flatten // - 4 x u8 -> 1x [u8; 4], via array_chunks - mem::size_of::() * step_merge.get() >= mem::size_of::() * step_expand.get() + size_of::() * step_merge.get() >= size_of::() * step_expand.get() } // Fall back to other from_iter impls if an overflow occurred in the step merge/expansion // tracking. @@ -190,7 +190,7 @@ const fn in_place_collectible( } const fn needs_realloc(src_cap: usize, dst_cap: usize) -> bool { - if const { mem::align_of::() != mem::align_of::() } { + if const { align_of::() != align_of::() } { // FIXME(const-hack): use unreachable! once that works in const panic!("in_place_collectible() prevents this"); } @@ -199,8 +199,8 @@ const fn needs_realloc(src_cap: usize, dst_cap: usize) -> bool { // the caller will have calculated a `dst_cap` that is an integer multiple of // `src_cap` without remainder. if const { - let src_sz = mem::size_of::(); - let dest_sz = mem::size_of::(); + let src_sz = size_of::(); + let dest_sz = size_of::(); dest_sz != 0 && src_sz % dest_sz == 0 } { return false; @@ -208,7 +208,7 @@ const fn needs_realloc(src_cap: usize, dst_cap: usize) -> bool { // type layouts don't guarantee a fit, so do a runtime check to see if // the allocations happen to match - src_cap > 0 && src_cap * mem::size_of::() != dst_cap * mem::size_of::() + src_cap > 0 && src_cap * size_of::() != dst_cap * size_of::() } /// This provides a shorthand for the source type since local type aliases aren't a thing. @@ -262,7 +262,7 @@ where inner.buf.cast::(), inner.end as *const T, // SAFETY: the multiplication can not overflow, since `inner.cap * size_of::()` is the size of the allocation. - inner.cap.unchecked_mul(mem::size_of::()) / mem::size_of::(), + inner.cap.unchecked_mul(size_of::()) / size_of::(), ) }; @@ -310,14 +310,14 @@ where debug_assert_ne!(dst_cap, 0); unsafe { // The old allocation exists, therefore it must have a valid layout. - let src_align = mem::align_of::(); - let src_size = mem::size_of::().unchecked_mul(src_cap); + let src_align = align_of::(); + let src_size = size_of::().unchecked_mul(src_cap); let old_layout = Layout::from_size_align_unchecked(src_size, src_align); // The allocation must be equal or smaller for in-place iteration to be possible // therefore the new layout must be ≤ the old one and therefore valid. - let dst_align = mem::align_of::(); - let dst_size = mem::size_of::().unchecked_mul(dst_cap); + let dst_align = align_of::(); + let dst_size = size_of::().unchecked_mul(dst_cap); let new_layout = Layout::from_size_align_unchecked(dst_size, dst_align); let result = alloc.shrink(dst_buf.cast(), old_layout, new_layout); @@ -325,7 +325,7 @@ where dst_buf = reallocated.cast::(); } } else { - debug_assert_eq!(src_cap * mem::size_of::(), dst_cap * mem::size_of::()); + debug_assert_eq!(src_cap * size_of::(), dst_cap * size_of::()); } mem::forget(dst_guard); @@ -379,7 +379,7 @@ where let sink = self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).into_ok(); // iteration succeeded, don't drop head - unsafe { ManuallyDrop::new(sink).dst.sub_ptr(dst_buf) } + unsafe { ManuallyDrop::new(sink).dst.offset_from_unsigned(dst_buf) } } } diff --git a/library/alloc/src/vec/in_place_drop.rs b/library/alloc/src/vec/in_place_drop.rs index 4d5b4e47d39e4..997c4c7525b5a 100644 --- a/library/alloc/src/vec/in_place_drop.rs +++ b/library/alloc/src/vec/in_place_drop.rs @@ -14,7 +14,7 @@ pub(super) struct InPlaceDrop { impl InPlaceDrop { fn len(&self) -> usize { - unsafe { self.dst.sub_ptr(self.inner) } + unsafe { self.dst.offset_from_unsigned(self.inner) } } } diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 9a6745fdbc0a3..3eee988b6c9d1 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -179,7 +179,7 @@ impl IntoIter { // say that they're all at the beginning of the "allocation". 0..this.len() } else { - this.ptr.sub_ptr(this.buf)..this.end.sub_ptr(buf) + this.ptr.offset_from_unsigned(this.buf)..this.end.offset_from_unsigned(buf) }; let cap = this.cap; let alloc = ManuallyDrop::take(&mut this.alloc); @@ -230,7 +230,7 @@ impl Iterator for IntoIter { let exact = if T::IS_ZST { self.end.addr().wrapping_sub(self.ptr.as_ptr().addr()) } else { - unsafe { non_null!(self.end, T).sub_ptr(self.ptr) } + unsafe { non_null!(self.end, T).offset_from_unsigned(self.ptr) } }; (exact, Some(exact)) } @@ -472,14 +472,9 @@ where #[cfg(not(no_global_oom_handling))] #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { - #[cfg(not(test))] fn clone(&self) -> Self { self.as_slice().to_vec_in(self.alloc.deref().clone()).into_iter() } - #[cfg(test)] - fn clone(&self) -> Self { - crate::slice::to_vec(self.as_slice(), self.alloc.deref().clone()).into_iter() - } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 7d02a15ed7a51..da9a77154f9b5 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -66,7 +66,7 @@ use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; use core::{fmt, intrinsics}; -#[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] +#[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] pub use self::extract_if::ExtractIf; use crate::alloc::{Allocator, Global}; use crate::borrow::{Cow, ToOwned}; @@ -293,7 +293,7 @@ mod spec_extend; /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized /// types inside a `Vec`, it will not allocate space for them. *Note that in this case /// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only -/// if [mem::size_of::\]\() * [capacity]\() > 0. In general, `Vec`'s allocation +/// if [size_of::\]\() * [capacity]\() > 0. In general, `Vec`'s allocation /// details are very subtle --- if you intend to allocate memory using a `Vec` /// and use it for something else (either to pass to unsafe code, or to build your /// own memory-backed collection), be sure to deallocate this memory by using @@ -355,11 +355,20 @@ mod spec_extend; /// and it may prove desirable to use a non-constant growth factor. Whatever /// strategy is used will of course guarantee *O*(1) amortized [`push`]. /// -/// `vec![x; n]`, `vec![a, b, c, d]`, and -/// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec` -/// with at least the requested capacity. If [len] == [capacity], -/// (as is the case for the [`vec!`] macro), then a `Vec` can be converted to -/// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. +/// It is guaranteed, in order to respect the intentions of the programmer, that +/// all of `vec![e_1, e_2, ..., e_n]`, `vec![x; n]`, and [`Vec::with_capacity(n)`] produce a `Vec` +/// that requests an allocation of the exact size needed for precisely `n` elements from the allocator, +/// and no other size (such as, for example: a size rounded up to the nearest power of 2). +/// The allocator will return an allocation that is at least as large as requested, but it may be larger. +/// +/// It is guaranteed that the [`Vec::capacity`] method returns a value that is at least the requested capacity +/// and not more than the allocated capacity. +/// +/// The method [`Vec::shrink_to_fit`] will attempt to discard excess capacity an allocator has given to a `Vec`. +/// If [len] == [capacity], then a `Vec` can be converted +/// to and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements. +/// `Vec` exploits this fact as much as reasonable when implementing common conversions +/// such as [`into_boxed_slice`]. /// /// `Vec` will not specifically overwrite any data that is removed from it, /// but also won't specifically preserve it. Its uninitialized memory is @@ -383,16 +392,19 @@ mod spec_extend; /// [`shrink_to`]: Vec::shrink_to /// [capacity]: Vec::capacity /// [`capacity`]: Vec::capacity -/// [mem::size_of::\]: core::mem::size_of +/// [`Vec::capacity`]: Vec::capacity +/// [size_of::\]: size_of /// [len]: Vec::len /// [`len`]: Vec::len /// [`push`]: Vec::push /// [`insert`]: Vec::insert /// [`reserve`]: Vec::reserve +/// [`Vec::with_capacity(n)`]: Vec::with_capacity /// [`MaybeUninit`]: core::mem::MaybeUninit /// [owned slice]: Box +/// [`into_boxed_slice`]: Vec::into_boxed_slice #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Vec")] +#[rustc_diagnostic_item = "Vec"] #[rustc_insignificant_dtor] pub struct Vec { buf: RawVec, @@ -416,7 +428,7 @@ impl Vec { /// ``` #[inline] #[rustc_const_stable(feature = "const_vec_new", since = "1.39.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_new")] + #[rustc_diagnostic_item = "vec_new"] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] pub const fn new() -> Self { @@ -477,7 +489,7 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_with_capacity")] + #[rustc_diagnostic_item = "vec_with_capacity"] #[track_caller] pub fn with_capacity(capacity: usize) -> Self { Self::with_capacity_in(capacity, Global) @@ -1242,7 +1254,7 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn capacity(&self) -> usize { self.buf.capacity() } @@ -1267,7 +1279,7 @@ impl Vec { #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] #[track_caller] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_reserve")] + #[rustc_diagnostic_item = "vec_reserve"] pub fn reserve(&mut self, additional: usize) { self.buf.reserve(self.len, additional); } @@ -1556,12 +1568,12 @@ impl Vec { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_slice")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "vec_as_slice"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_slice(&self) -> &[T] { // SAFETY: `slice::from_raw_parts` requires pointee is a contiguous, aligned buffer of size // `len` containing properly-initialized `T`s. Data must not be mutated for the returned - // lifetime. Further, `len * mem::size_of::` <= `ISIZE::MAX`, and allocation does not + // lifetime. Further, `len * size_of::` <= `isize::MAX`, and allocation does not // "wrap" through overflowing memory addresses. // // * Vec API guarantees that self.buf: @@ -1588,12 +1600,12 @@ impl Vec { /// ``` #[inline] #[stable(feature = "vec_as_slice", since = "1.7.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_as_mut_slice")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "vec_as_mut_slice"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn as_mut_slice(&mut self) -> &mut [T] { // SAFETY: `slice::from_raw_parts_mut` requires pointee is a contiguous, aligned buffer of // size `len` containing properly-initialized `T`s. Data must not be accessed through any - // other pointer for the returned lifetime. Further, `len * mem::size_of::` <= + // other pointer for the returned lifetime. Further, `len * size_of::` <= // `ISIZE::MAX` and allocation does not "wrap" through overflowing memory addresses. // // * Vec API guarantees that self.buf: @@ -1661,7 +1673,7 @@ impl Vec { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -1724,7 +1736,7 @@ impl Vec { /// [`as_ptr`]: Vec::as_ptr /// [`as_non_null`]: Vec::as_non_null #[stable(feature = "vec_as_ptr", since = "1.37.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_never_returns_null_ptr] #[rustc_as_ptr] #[inline] @@ -2499,7 +2511,7 @@ impl Vec { /// Takes *O*(1) time. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_pop")] + #[rustc_diagnostic_item = "vec_pop"] pub fn pop(&mut self) -> Option { if self.len == 0 { None @@ -2526,7 +2538,7 @@ impl Vec { /// assert_eq!(vec, [1, 2, 3]); /// assert_eq!(vec.pop_if(pred), None); /// ``` - #[stable(feature = "vec_pop_if", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "vec_pop_if", since = "1.86.0")] pub fn pop_if(&mut self, predicate: impl FnOnce(&mut T) -> bool) -> Option { let last = self.last_mut()?; if predicate(last) { self.pop() } else { None } @@ -2675,13 +2687,13 @@ impl Vec { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] #[rustc_confusables("length", "size")] pub const fn len(&self) -> usize { let len = self.len; // SAFETY: The maximum capacity of `Vec` is `isize::MAX` bytes, so the maximum value can - // be returned is `usize::checked_div(mem::size_of::()).unwrap_or(usize::MAX)`, which + // be returned is `usize::checked_div(size_of::()).unwrap_or(usize::MAX)`, which // matches the definition of `T::MAX_SLICE_LEN`. unsafe { intrinsics::assume(len <= T::MAX_SLICE_LEN) }; @@ -2700,8 +2712,8 @@ impl Vec { /// assert!(!v.is_empty()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "vec_is_empty")] - #[rustc_const_unstable(feature = "const_vec_string_slice", issue = "129041")] + #[rustc_diagnostic_item = "vec_is_empty"] + #[rustc_const_stable(feature = "const_vec_string_slice", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(&self) -> bool { self.len() == 0 } @@ -3181,7 +3193,7 @@ impl Vec { #[doc(hidden)] #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "vec_from_elem")] +#[rustc_diagnostic_item = "vec_from_elem"] #[track_caller] pub fn from_elem(elem: T, n: usize) -> Vec { ::from_elem(elem, n, Global) @@ -3281,23 +3293,12 @@ unsafe impl ops::DerefPure for Vec {} #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Vec { - #[cfg(not(test))] #[track_caller] fn clone(&self) -> Self { let alloc = self.allocator().clone(); <[T]>::to_vec_in(&**self, alloc) } - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Instead use the - // `slice::to_vec` function which is only available with cfg(test) - // NB see the slice::hack module in slice.rs for more information - #[cfg(test)] - fn clone(&self) -> Self { - let alloc = self.allocator().clone(); - crate::slice::to_vec(&**self, alloc) - } - /// Overwrites the contents of `self` with a clone of the contents of `source`. /// /// This method is preferred over simply assigning `source.clone()` to `self`, @@ -3684,7 +3685,6 @@ impl Vec { /// Splitting an array into evens and odds, reusing the original allocation: /// /// ``` - /// #![feature(extract_if)] /// let mut numbers = vec![1, 2, 3, 4, 5, 6, 8, 9, 11, 13, 14, 15]; /// /// let evens = numbers.extract_if(.., |x| *x % 2 == 0).collect::>(); @@ -3697,13 +3697,12 @@ impl Vec { /// Using the range argument to only process a part of the vector: /// /// ``` - /// #![feature(extract_if)] /// let mut items = vec![0, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2]; /// let ones = items.extract_if(7.., |x| *x == 1).collect::>(); /// assert_eq!(items, vec![0, 0, 0, 0, 0, 0, 0, 2, 2, 2]); /// assert_eq!(ones.len(), 3); /// ``` - #[unstable(feature = "extract_if", reason = "recently added", issue = "43244")] + #[stable(feature = "extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, range: R, filter: F) -> ExtractIf<'_, T, F, A> where F: FnMut(&mut T) -> bool, @@ -3844,15 +3843,10 @@ impl From<&[T]> for Vec { /// ``` /// assert_eq!(Vec::from(&[1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: &[T]) -> Vec { s.to_vec() } - #[cfg(test)] - fn from(s: &[T]) -> Vec { - crate::slice::to_vec(s, Global) - } } #[cfg(not(no_global_oom_handling))] @@ -3865,15 +3859,10 @@ impl From<&mut [T]> for Vec { /// ``` /// assert_eq!(Vec::from(&mut [1, 2, 3][..]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: &mut [T]) -> Vec { s.to_vec() } - #[cfg(test)] - fn from(s: &mut [T]) -> Vec { - crate::slice::to_vec(s, Global) - } } #[cfg(not(no_global_oom_handling))] @@ -3918,16 +3907,10 @@ impl From<[T; N]> for Vec { /// ``` /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]); /// ``` - #[cfg(not(test))] #[track_caller] fn from(s: [T; N]) -> Vec { <[T]>::into_vec(Box::new(s)) } - - #[cfg(test)] - fn from(s: [T; N]) -> Vec { - crate::slice::into_vec(Box::new(s)) - } } #[stable(feature = "vec_from_cow_slice", since = "1.14.0")] @@ -3956,7 +3939,6 @@ where } // note: test pulls in std, which causes errors here -#[cfg(not(test))] #[stable(feature = "vec_from_box", since = "1.18.0")] impl From> for Vec { /// Converts a boxed slice into a vector by transferring ownership of @@ -3975,7 +3957,6 @@ impl From> for Vec { // note: test pulls in std, which causes errors here #[cfg(not(no_global_oom_handling))] -#[cfg(not(test))] #[stable(feature = "box_from_vec", since = "1.20.0")] impl From> for Box<[T], A> { /// Converts a vector into a boxed slice. diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs deleted file mode 100644 index 451765d724283..0000000000000 --- a/library/alloc/tests/rc.rs +++ /dev/null @@ -1,260 +0,0 @@ -use std::any::Any; -use std::cell::{Cell, RefCell}; -use std::iter::TrustedLen; -use std::mem; -use std::rc::{Rc, Weak}; - -#[test] -fn uninhabited() { - enum Void {} - let mut a = Weak::::new(); - a = a.clone(); - assert!(a.upgrade().is_none()); - - let mut a: Weak = a; // Unsizing - a = a.clone(); - assert!(a.upgrade().is_none()); -} - -#[test] -fn slice() { - let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]); - let a: Rc<[u32]> = a; // Unsizing - let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion - assert_eq!(a, b); - - // Exercise is_dangling() with a DST - let mut a = Rc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); -} - -#[test] -fn trait_object() { - let a: Rc = Rc::new(4); - let a: Rc = a; // Unsizing - - // Exercise is_dangling() with a DST - let mut a = Rc::downgrade(&a); - a = a.clone(); - assert!(a.upgrade().is_some()); - - let mut b = Weak::::new(); - b = b.clone(); - assert!(b.upgrade().is_none()); - let mut b: Weak = b; // Unsizing - b = b.clone(); - assert!(b.upgrade().is_none()); -} - -#[test] -fn float_nan_ne() { - let x = Rc::new(f32::NAN); - assert!(x != x); - assert!(!(x == x)); -} - -#[test] -fn partial_eq() { - struct TestPEq(RefCell); - impl PartialEq for TestPEq { - fn eq(&self, other: &TestPEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Rc::new(TestPEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 4); -} - -#[test] -fn eq() { - #[derive(Eq)] - struct TestEq(RefCell); - impl PartialEq for TestEq { - fn eq(&self, other: &TestEq) -> bool { - *self.0.borrow_mut() += 1; - *other.0.borrow_mut() += 1; - true - } - } - let x = Rc::new(TestEq(RefCell::new(0))); - assert!(x == x); - assert!(!(x != x)); - assert_eq!(*x.0.borrow(), 0); -} - -const SHARED_ITER_MAX: u16 = 100; - -fn assert_trusted_len(_: &I) {} - -#[test] -fn shared_from_iter_normal() { - // Exercise the base implementation for non-`TrustedLen` iterators. - { - // `Filter` is never `TrustedLen` since we don't - // know statically how many elements will be kept: - let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); - - // Collecting into a `Vec` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. -} - -#[test] -fn shared_from_iter_trustedlen_normal() { - // Exercise the `TrustedLen` implementation under normal circumstances - // where `size_hint()` matches `(_, Some(exact_len))`. - { - let iter = (0..SHARED_ITER_MAX).map(Box::new); - assert_trusted_len(&iter); - - // Collecting into a `Vec` or `Rc<[T]>` should make no difference: - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - assert_eq!(mem::size_of::>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc)); - - // Clone a bit and let these get dropped. - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } // Drop what hasn't been here. - - // Try a ZST to make sure it is handled well. - { - let iter = (0..SHARED_ITER_MAX).map(drop); - let vec = iter.clone().collect::>(); - let rc = iter.collect::>(); - assert_eq!(&*vec, &*rc); - assert_eq!(0, mem::size_of_val(&*rc)); - { - let _rc_2 = rc.clone(); - let _rc_3 = rc.clone(); - let _rc_4 = Rc::downgrade(&_rc_3); - } - } -} - -#[test] -#[should_panic = "I've almost got 99 problems."] -fn shared_from_iter_trustedlen_panic() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. - let iter = (0..SHARED_ITER_MAX).map(|val| match val { - 98 => panic!("I've almost got 99 problems."), - _ => Box::new(val), - }); - assert_trusted_len(&iter); - let _ = iter.collect::>(); - - panic!("I am unreachable."); -} - -#[test] -fn shared_from_iter_trustedlen_no_fuse() { - // Exercise the `TrustedLen` implementation when `size_hint()` matches - // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. - struct Iter(std::vec::IntoIter>>); - - unsafe impl TrustedLen for Iter {} - - impl Iterator for Iter { - fn size_hint(&self) -> (usize, Option) { - (2, Some(2)) - } - - type Item = Box; - - fn next(&mut self) -> Option { - self.0.next().flatten() - } - } - - let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; - let iter = Iter(vec.into_iter()); - assert_trusted_len(&iter); - assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); -} - -#[test] -fn weak_may_dangle() { - fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { - val.clone() - } - - // Without #[may_dangle] we get: - let mut val = Weak::new(); - hmm(&mut val); - // ~~~~~~~~ borrowed value does not live long enough - // - // `val` dropped here while still borrowed - // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` -} - -/// Test that a panic from a destructor does not leak the allocation. -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn panic_no_leak() { - use std::alloc::{AllocError, Allocator, Global, Layout}; - use std::panic::{AssertUnwindSafe, catch_unwind}; - use std::ptr::NonNull; - - struct AllocCount(Cell); - unsafe impl Allocator for AllocCount { - fn allocate(&self, layout: Layout) -> Result, AllocError> { - self.0.set(self.0.get() + 1); - Global.allocate(layout) - } - unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { - self.0.set(self.0.get() - 1); - unsafe { Global.deallocate(ptr, layout) } - } - } - - struct PanicOnDrop; - impl Drop for PanicOnDrop { - fn drop(&mut self) { - panic!("PanicOnDrop"); - } - } - - let alloc = AllocCount(Cell::new(0)); - let rc = Rc::new_in(PanicOnDrop, &alloc); - assert_eq!(alloc.0.get(), 1); - - let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); - assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); - assert_eq!(alloc.0.get(), 0); -} - -#[allow(unused)] -mod pin_coerce_unsized { - use alloc::rc::{Rc, UniqueRc}; - use core::pin::Pin; - - pub trait MyTrait {} - impl MyTrait for String {} - - // Pin coercion should work for Rc - pub fn pin_rc(arg: Pin>) -> Pin> { - arg - } - pub fn pin_unique_rc(arg: Pin>) -> Pin> { - arg - } -} diff --git a/library/alloctests/Cargo.toml b/library/alloctests/Cargo.toml new file mode 100644 index 0000000000000..306375f5f01cc --- /dev/null +++ b/library/alloctests/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "alloctests" +version = "0.0.0" +license = "MIT OR Apache-2.0" +repository = "https://github.com/rust-lang/rust.git" +description = "Tests for the Rust Allocation Library" +autotests = false +autobenches = false +edition = "2021" + +[lib] +path = "lib.rs" +test = true +bench = true +doc = false + +[dev-dependencies] +rand = { version = "0.9.0", default-features = false, features = ["alloc"] } +rand_xorshift = "0.4.0" + +[[test]] +name = "alloctests" +path = "tests/lib.rs" + +[[test]] +name = "vec_deque_alloc_error" +path = "tests/vec_deque_alloc_error.rs" + +[[bench]] +name = "allocbenches" +path = "benches/lib.rs" +test = true + +[[bench]] +name = "vec_deque_append_bench" +path = "benches/vec_deque_append.rs" +harness = false + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = [ + 'cfg(bootstrap)', + 'cfg(no_global_oom_handling)', + 'cfg(no_rc)', + 'cfg(no_sync)', + 'cfg(randomized_layouts)', +] diff --git a/library/alloc/benches/binary_heap.rs b/library/alloctests/benches/binary_heap.rs similarity index 100% rename from library/alloc/benches/binary_heap.rs rename to library/alloctests/benches/binary_heap.rs diff --git a/library/alloc/benches/btree/map.rs b/library/alloctests/benches/btree/map.rs similarity index 100% rename from library/alloc/benches/btree/map.rs rename to library/alloctests/benches/btree/map.rs diff --git a/library/alloc/benches/btree/mod.rs b/library/alloctests/benches/btree/mod.rs similarity index 100% rename from library/alloc/benches/btree/mod.rs rename to library/alloctests/benches/btree/mod.rs diff --git a/library/alloc/benches/btree/set.rs b/library/alloctests/benches/btree/set.rs similarity index 100% rename from library/alloc/benches/btree/set.rs rename to library/alloctests/benches/btree/set.rs diff --git a/library/alloc/benches/lib.rs b/library/alloctests/benches/lib.rs similarity index 100% rename from library/alloc/benches/lib.rs rename to library/alloctests/benches/lib.rs diff --git a/library/alloc/benches/linked_list.rs b/library/alloctests/benches/linked_list.rs similarity index 100% rename from library/alloc/benches/linked_list.rs rename to library/alloctests/benches/linked_list.rs diff --git a/library/alloc/benches/slice.rs b/library/alloctests/benches/slice.rs similarity index 96% rename from library/alloc/benches/slice.rs rename to library/alloctests/benches/slice.rs index c6b46e6a2a188..27b0e6fac0adb 100644 --- a/library/alloc/benches/slice.rs +++ b/library/alloctests/benches/slice.rs @@ -1,4 +1,4 @@ -use std::{mem, ptr}; +use std::ptr; use rand::Rng; use rand::distr::{Alphanumeric, SampleString, StandardUniform}; @@ -234,7 +234,7 @@ macro_rules! sort { fn $name(b: &mut Bencher) { let v = $gen($len); b.iter(|| v.clone().$f()); - b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64; + b.bytes = $len * size_of_val(&$gen(1)[0]) as u64; } }; } @@ -246,7 +246,7 @@ macro_rules! sort_strings { let v = $gen($len); let v = v.iter().map(|s| &**s).collect::>(); b.iter(|| v.clone().$f()); - b.bytes = $len * mem::size_of::<&str>() as u64; + b.bytes = $len * size_of::<&str>() as u64; } }; } @@ -268,7 +268,7 @@ macro_rules! sort_expensive { }); black_box(count); }); - b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64; + b.bytes = $len * size_of_val(&$gen(1)[0]) as u64; } }; } @@ -279,7 +279,7 @@ macro_rules! sort_lexicographic { fn $name(b: &mut Bencher) { let v = $gen($len); b.iter(|| v.clone().$f(|x| x.to_string())); - b.bytes = $len * mem::size_of_val(&$gen(1)[0]) as u64; + b.bytes = $len * size_of_val(&$gen(1)[0]) as u64; } }; } @@ -322,7 +322,7 @@ macro_rules! reverse { fn $name(b: &mut Bencher) { // odd length and offset by 1 to be as unaligned as possible let n = 0xFFFFF; - let mut v: Vec<_> = (0..1 + (n / mem::size_of::<$ty>() as u64)).map($f).collect(); + let mut v: Vec<_> = (0..1 + (n / size_of::<$ty>() as u64)).map($f).collect(); b.iter(|| black_box(&mut v[1..]).reverse()); b.bytes = n; } @@ -346,7 +346,7 @@ macro_rules! rotate { ($name:ident, $gen:expr, $len:expr, $mid:expr) => { #[bench] fn $name(b: &mut Bencher) { - let size = mem::size_of_val(&$gen(1)[0]); + let size = size_of_val(&$gen(1)[0]); let mut v = $gen($len * 8 / size); b.iter(|| black_box(&mut v).rotate_left(($mid * 8 + size - 1) / size)); b.bytes = (v.len() * size) as u64; diff --git a/library/alloc/benches/str.rs b/library/alloctests/benches/str.rs similarity index 100% rename from library/alloc/benches/str.rs rename to library/alloctests/benches/str.rs diff --git a/library/alloc/benches/string.rs b/library/alloctests/benches/string.rs similarity index 100% rename from library/alloc/benches/string.rs rename to library/alloctests/benches/string.rs diff --git a/library/alloc/benches/vec.rs b/library/alloctests/benches/vec.rs similarity index 98% rename from library/alloc/benches/vec.rs rename to library/alloctests/benches/vec.rs index a725ad6894b9c..1dab71fa1f4f4 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloctests/benches/vec.rs @@ -669,7 +669,7 @@ fn random_sorted_fill(mut seed: u32, buf: &mut [u32]) { // This algorithm was used for Vecs prior to Rust 1.52. fn bench_dedup_slice_truncate(b: &mut Bencher, sz: usize) { let mut template = vec![0u32; sz]; - b.bytes = std::mem::size_of_val(template.as_slice()) as u64; + b.bytes = size_of_val(template.as_slice()) as u64; random_sorted_fill(0x43, &mut template); let mut vec = template.clone(); @@ -691,7 +691,7 @@ fn bench_dedup_slice_truncate(b: &mut Bencher, sz: usize) { // Measures performance of Vec::dedup on random data. fn bench_vec_dedup_random(b: &mut Bencher, sz: usize) { let mut template = vec![0u32; sz]; - b.bytes = std::mem::size_of_val(template.as_slice()) as u64; + b.bytes = size_of_val(template.as_slice()) as u64; random_sorted_fill(0x43, &mut template); let mut vec = template.clone(); @@ -708,7 +708,7 @@ fn bench_vec_dedup_random(b: &mut Bencher, sz: usize) { // Measures performance of Vec::dedup when there is no items removed fn bench_vec_dedup_none(b: &mut Bencher, sz: usize) { let mut template = vec![0u32; sz]; - b.bytes = std::mem::size_of_val(template.as_slice()) as u64; + b.bytes = size_of_val(template.as_slice()) as u64; template.chunks_exact_mut(2).for_each(|w| { w[0] = black_box(0); w[1] = black_box(5); @@ -729,7 +729,7 @@ fn bench_vec_dedup_none(b: &mut Bencher, sz: usize) { // Measures performance of Vec::dedup when there is all items removed fn bench_vec_dedup_all(b: &mut Bencher, sz: usize) { let mut template = vec![0u32; sz]; - b.bytes = std::mem::size_of_val(template.as_slice()) as u64; + b.bytes = size_of_val(template.as_slice()) as u64; template.iter_mut().for_each(|w| { *w = black_box(0); }); diff --git a/library/alloc/benches/vec_deque.rs b/library/alloctests/benches/vec_deque.rs similarity index 100% rename from library/alloc/benches/vec_deque.rs rename to library/alloctests/benches/vec_deque.rs diff --git a/library/alloc/benches/vec_deque_append.rs b/library/alloctests/benches/vec_deque_append.rs similarity index 100% rename from library/alloc/benches/vec_deque_append.rs rename to library/alloctests/benches/vec_deque_append.rs diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs new file mode 100644 index 0000000000000..6ce8a6d9ca174 --- /dev/null +++ b/library/alloctests/lib.rs @@ -0,0 +1,93 @@ +#![cfg(test)] +#![allow(unused_attributes)] +#![unstable(feature = "alloctests", issue = "none")] +#![no_std] +// Lints: +#![deny(unsafe_op_in_unsafe_fn)] +#![warn(deprecated_in_future)] +#![warn(missing_debug_implementations)] +#![allow(explicit_outlives_requirements)] +#![allow(internal_features)] +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +#![deny(ffi_unwind_calls)] +// +// Library features: +// tidy-alphabetical-start +#![feature(alloc_layout_extra)] +#![feature(allocator_api)] +#![feature(array_into_iter_constructors)] +#![feature(assert_matches)] +#![feature(core_intrinsics)] +#![feature(exact_size_is_empty)] +#![feature(extend_one)] +#![feature(extend_one_unchecked)] +#![feature(hasher_prefixfree_extras)] +#![feature(inplace_iteration)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] +#![feature(maybe_uninit_slice)] +#![feature(maybe_uninit_uninit_array_transpose)] +#![feature(ptr_internals)] +#![feature(sized_type_properties)] +#![feature(slice_iter_mut_as_mut_slice)] +#![feature(slice_ptr_get)] +#![feature(slice_range)] +#![feature(std_internals)] +#![feature(temporary_niche_types)] +#![feature(trusted_fused)] +#![feature(trusted_len)] +#![feature(trusted_random_access)] +#![feature(try_reserve_kind)] +#![feature(try_trait_v2)] +// tidy-alphabetical-end +// +// Language features: +// tidy-alphabetical-start +#![feature(cfg_sanitize)] +#![feature(dropck_eyepatch)] +#![feature(lang_items)] +#![feature(min_specialization)] +#![feature(negative_impls)] +#![feature(never_type)] +#![feature(optimize_attribute)] +#![feature(rustc_allow_const_fn_unstable)] +#![feature(rustc_attrs)] +#![feature(staged_api)] +#![feature(test)] +#![rustc_preserve_ub_checks] +// tidy-alphabetical-end + +// Allow testing this library +extern crate alloc as realalloc; +#[macro_use] +extern crate std; +#[cfg(test)] +extern crate test; +mod testing; +use realalloc::*; + +// We are directly including collections and raw_vec here as both use non-public +// methods and fields in tests and as such need to have the types to test in the +// same crate as the tests themself. +#[path = "../alloc/src/collections/mod.rs"] +mod collections; + +#[path = "../alloc/src/raw_vec/mod.rs"] +mod raw_vec; + +#[allow(dead_code)] // Not used in all configurations +pub(crate) mod test_helpers { + /// Copied from `std::test_helpers::test_rng`, since these tests rely on the + /// seed not being the same for every RNG invocation too. + pub(crate) fn test_rng() -> rand_xorshift::XorShiftRng { + use std::hash::{BuildHasher, Hash, Hasher}; + let mut hasher = std::hash::RandomState::new().build_hasher(); + std::panic::Location::caller().hash(&mut hasher); + let hc64 = hasher.finish(); + let seed_vec = + hc64.to_le_bytes().into_iter().chain(0u8..8).collect::>(); + let seed: [u8; 16] = seed_vec.as_slice().try_into().unwrap(); + rand::SeedableRng::from_seed(seed) + } +} diff --git a/library/alloc/src/testing/crash_test.rs b/library/alloctests/testing/crash_test.rs similarity index 100% rename from library/alloc/src/testing/crash_test.rs rename to library/alloctests/testing/crash_test.rs diff --git a/library/alloc/src/testing/mod.rs b/library/alloctests/testing/mod.rs similarity index 100% rename from library/alloc/src/testing/mod.rs rename to library/alloctests/testing/mod.rs diff --git a/library/alloc/src/testing/ord_chaos.rs b/library/alloctests/testing/ord_chaos.rs similarity index 100% rename from library/alloc/src/testing/ord_chaos.rs rename to library/alloctests/testing/ord_chaos.rs diff --git a/library/alloc/src/testing/rng.rs b/library/alloctests/testing/rng.rs similarity index 100% rename from library/alloc/src/testing/rng.rs rename to library/alloctests/testing/rng.rs diff --git a/library/alloc/tests/alloc.rs b/library/alloctests/tests/alloc_test.rs similarity index 100% rename from library/alloc/tests/alloc.rs rename to library/alloctests/tests/alloc_test.rs diff --git a/library/alloc/tests/arc.rs b/library/alloctests/tests/arc.rs similarity index 98% rename from library/alloc/tests/arc.rs rename to library/alloctests/tests/arc.rs index a259c0131ecdf..0baa50f439b37 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloctests/tests/arc.rs @@ -1,7 +1,6 @@ use std::any::Any; use std::cell::{Cell, RefCell}; use std::iter::TrustedLen; -use std::mem; use std::sync::{Arc, Weak}; #[test] @@ -129,7 +128,7 @@ fn shared_from_iter_trustedlen_normal() { let vec = iter.clone().collect::>(); let rc = iter.collect::>(); assert_eq!(&*vec, &*rc); - assert_eq!(mem::size_of::>() * SHARED_ITER_MAX as usize, mem::size_of_val(&*rc)); + assert_eq!(size_of::>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); // Clone a bit and let these get dropped. { @@ -145,7 +144,7 @@ fn shared_from_iter_trustedlen_normal() { let vec = iter.clone().collect::>(); let rc = iter.collect::>(); assert_eq!(&*vec, &*rc); - assert_eq!(0, mem::size_of_val(&*rc)); + assert_eq!(0, size_of_val(&*rc)); { let _rc_2 = rc.clone(); let _rc_3 = rc.clone(); diff --git a/library/alloc/tests/autotraits.rs b/library/alloctests/tests/autotraits.rs similarity index 100% rename from library/alloc/tests/autotraits.rs rename to library/alloctests/tests/autotraits.rs diff --git a/library/alloc/tests/borrow.rs b/library/alloctests/tests/borrow.rs similarity index 100% rename from library/alloc/tests/borrow.rs rename to library/alloctests/tests/borrow.rs diff --git a/library/alloc/tests/boxed.rs b/library/alloctests/tests/boxed.rs similarity index 100% rename from library/alloc/tests/boxed.rs rename to library/alloctests/tests/boxed.rs diff --git a/library/alloc/tests/btree_set_hash.rs b/library/alloctests/tests/btree_set_hash.rs similarity index 100% rename from library/alloc/tests/btree_set_hash.rs rename to library/alloctests/tests/btree_set_hash.rs diff --git a/library/alloc/tests/c_str.rs b/library/alloctests/tests/c_str.rs similarity index 100% rename from library/alloc/tests/c_str.rs rename to library/alloctests/tests/c_str.rs diff --git a/library/alloc/tests/c_str2.rs b/library/alloctests/tests/c_str2.rs similarity index 100% rename from library/alloc/tests/c_str2.rs rename to library/alloctests/tests/c_str2.rs diff --git a/library/alloc/tests/collections/binary_heap.rs b/library/alloctests/tests/collections/binary_heap.rs similarity index 100% rename from library/alloc/tests/collections/binary_heap.rs rename to library/alloctests/tests/collections/binary_heap.rs diff --git a/library/alloc/tests/collections/mod.rs b/library/alloctests/tests/collections/mod.rs similarity index 100% rename from library/alloc/tests/collections/mod.rs rename to library/alloctests/tests/collections/mod.rs diff --git a/library/alloc/tests/const_fns.rs b/library/alloctests/tests/const_fns.rs similarity index 100% rename from library/alloc/tests/const_fns.rs rename to library/alloctests/tests/const_fns.rs diff --git a/library/alloc/tests/cow_str.rs b/library/alloctests/tests/cow_str.rs similarity index 100% rename from library/alloc/tests/cow_str.rs rename to library/alloctests/tests/cow_str.rs diff --git a/library/alloc/tests/fmt.rs b/library/alloctests/tests/fmt.rs similarity index 100% rename from library/alloc/tests/fmt.rs rename to library/alloctests/tests/fmt.rs diff --git a/library/alloc/tests/heap.rs b/library/alloctests/tests/heap.rs similarity index 100% rename from library/alloc/tests/heap.rs rename to library/alloctests/tests/heap.rs diff --git a/library/alloc/tests/lib.rs b/library/alloctests/tests/lib.rs similarity index 97% rename from library/alloc/tests/lib.rs rename to library/alloctests/tests/lib.rs index f95be6a6df0b3..46c11ea150bf8 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -7,7 +7,6 @@ #![feature(cow_is_borrowed)] #![feature(core_intrinsics)] #![feature(downcast_unchecked)] -#![feature(extract_if)] #![feature(exact_size_is_empty)] #![feature(hashmap_internals)] #![feature(linked_list_cursors)] @@ -29,7 +28,6 @@ #![feature(string_remove_matches)] #![feature(const_btree_len)] #![feature(const_trait_impl)] -#![feature(const_str_from_utf8)] #![feature(panic_update_hook)] #![feature(pointer_is_aligned_to)] #![feature(test)] @@ -45,11 +43,12 @@ #![deny(fuzzy_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +extern crate alloc; extern crate test; use std::hash::{DefaultHasher, Hash, Hasher}; -mod alloc; +mod alloc_test; mod arc; mod autotraits; mod borrow; diff --git a/library/alloc/tests/linked_list.rs b/library/alloctests/tests/linked_list.rs similarity index 100% rename from library/alloc/tests/linked_list.rs rename to library/alloctests/tests/linked_list.rs diff --git a/library/alloc/tests/misc_tests.rs b/library/alloctests/tests/misc_tests.rs similarity index 100% rename from library/alloc/tests/misc_tests.rs rename to library/alloctests/tests/misc_tests.rs diff --git a/library/alloc/src/rc/tests.rs b/library/alloctests/tests/rc.rs similarity index 66% rename from library/alloc/src/rc/tests.rs rename to library/alloctests/tests/rc.rs index 2210a7c24c06a..bb68eb4ac9e3d 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloctests/tests/rc.rs @@ -1,7 +1,263 @@ -use std::cell::RefCell; -use std::clone::Clone; +use std::any::Any; +use std::cell::{Cell, RefCell}; +use std::iter::TrustedLen; +use std::mem; +use std::rc::{Rc, UniqueRc, Weak}; -use super::*; +#[test] +fn uninhabited() { + enum Void {} + let mut a = Weak::::new(); + a = a.clone(); + assert!(a.upgrade().is_none()); + + let mut a: Weak = a; // Unsizing + a = a.clone(); + assert!(a.upgrade().is_none()); +} + +#[test] +fn slice() { + let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]); + let a: Rc<[u32]> = a; // Unsizing + let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion + assert_eq!(a, b); + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); +} + +#[test] +fn trait_object() { + let a: Rc = Rc::new(4); + let a: Rc = a; // Unsizing + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); + + let mut b = Weak::::new(); + b = b.clone(); + assert!(b.upgrade().is_none()); + let mut b: Weak = b; // Unsizing + b = b.clone(); + assert!(b.upgrade().is_none()); +} + +#[test] +fn float_nan_ne() { + let x = Rc::new(f32::NAN); + assert!(x != x); + assert!(!(x == x)); +} + +#[test] +fn partial_eq() { + struct TestPEq(RefCell); + impl PartialEq for TestPEq { + fn eq(&self, other: &TestPEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestPEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 4); +} + +#[test] +fn eq() { + #[derive(Eq)] + struct TestEq(RefCell); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::new(TestEq(RefCell::new(0))); + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +} + +const SHARED_ITER_MAX: u16 = 100; + +fn assert_trusted_len(_: &I) {} + +#[test] +fn shared_from_iter_normal() { + // Exercise the base implementation for non-`TrustedLen` iterators. + { + // `Filter` is never `TrustedLen` since we don't + // know statically how many elements will be kept: + let iter = (0..SHARED_ITER_MAX).filter(|x| x % 2 == 0).map(Box::new); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. +} + +#[test] +fn shared_from_iter_trustedlen_normal() { + // Exercise the `TrustedLen` implementation under normal circumstances + // where `size_hint()` matches `(_, Some(exact_len))`. + { + let iter = (0..SHARED_ITER_MAX).map(Box::new); + assert_trusted_len(&iter); + + // Collecting into a `Vec` or `Rc<[T]>` should make no difference: + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(size_of::>() * SHARED_ITER_MAX as usize, size_of_val(&*rc)); + + // Clone a bit and let these get dropped. + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } // Drop what hasn't been here. + + // Try a ZST to make sure it is handled well. + { + let iter = (0..SHARED_ITER_MAX).map(drop); + let vec = iter.clone().collect::>(); + let rc = iter.collect::>(); + assert_eq!(&*vec, &*rc); + assert_eq!(0, size_of_val(&*rc)); + { + let _rc_2 = rc.clone(); + let _rc_3 = rc.clone(); + let _rc_4 = Rc::downgrade(&_rc_3); + } + } +} + +#[test] +#[should_panic = "I've almost got 99 problems."] +fn shared_from_iter_trustedlen_panic() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where `.next()` drops before the last iteration. + let iter = (0..SHARED_ITER_MAX).map(|val| match val { + 98 => panic!("I've almost got 99 problems."), + _ => Box::new(val), + }); + assert_trusted_len(&iter); + let _ = iter.collect::>(); + + panic!("I am unreachable."); +} + +#[test] +fn shared_from_iter_trustedlen_no_fuse() { + // Exercise the `TrustedLen` implementation when `size_hint()` matches + // `(_, Some(exact_len))` but where the iterator does not behave in a fused manner. + struct Iter(std::vec::IntoIter>>); + + unsafe impl TrustedLen for Iter {} + + impl Iterator for Iter { + fn size_hint(&self) -> (usize, Option) { + (2, Some(2)) + } + + type Item = Box; + + fn next(&mut self) -> Option { + self.0.next().flatten() + } + } + + let vec = vec![Some(Box::new(42)), Some(Box::new(24)), None, Some(Box::new(12))]; + let iter = Iter(vec.into_iter()); + assert_trusted_len(&iter); + assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::>()); +} + +#[test] +fn weak_may_dangle() { + fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { + val.clone() + } + + // Without #[may_dangle] we get: + let mut val = Weak::new(); + hmm(&mut val); + // ~~~~~~~~ borrowed value does not live long enough + // + // `val` dropped here while still borrowed + // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` +} + +/// Test that a panic from a destructor does not leak the allocation. +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn panic_no_leak() { + use std::alloc::{AllocError, Allocator, Global, Layout}; + use std::panic::{AssertUnwindSafe, catch_unwind}; + use std::ptr::NonNull; + + struct AllocCount(Cell); + unsafe impl Allocator for AllocCount { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.0.set(self.0.get() + 1); + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + self.0.set(self.0.get() - 1); + unsafe { Global.deallocate(ptr, layout) } + } + } + + struct PanicOnDrop; + impl Drop for PanicOnDrop { + fn drop(&mut self) { + panic!("PanicOnDrop"); + } + } + + let alloc = AllocCount(Cell::new(0)); + let rc = Rc::new_in(PanicOnDrop, &alloc); + assert_eq!(alloc.0.get(), 1); + + let panic_message = catch_unwind(AssertUnwindSafe(|| drop(rc))).unwrap_err(); + assert_eq!(*panic_message.downcast_ref::<&'static str>().unwrap(), "PanicOnDrop"); + assert_eq!(alloc.0.get(), 0); +} + +#[allow(unused)] +mod pin_coerce_unsized { + use alloc::rc::{Rc, UniqueRc}; + use core::pin::Pin; + + pub trait MyTrait {} + impl MyTrait for String {} + + // Pin coercion should work for Rc + pub fn pin_rc(arg: Pin>) -> Pin> { + arg + } + pub fn pin_unique_rc(arg: Pin>) -> Pin> { + arg + } +} #[test] fn test_clone() { @@ -61,16 +317,20 @@ fn weak_self_cyclic() { #[test] fn is_unique() { + fn is_unique(this: &Rc) -> bool { + Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1 + } + let x = Rc::new(3); - assert!(Rc::is_unique(&x)); + assert!(is_unique(&x)); let y = x.clone(); - assert!(!Rc::is_unique(&x)); + assert!(!is_unique(&x)); drop(y); - assert!(Rc::is_unique(&x)); + assert!(is_unique(&x)); let w = Rc::downgrade(&x); - assert!(!Rc::is_unique(&x)); + assert!(!is_unique(&x)); drop(w); - assert!(Rc::is_unique(&x)); + assert!(is_unique(&x)); } #[test] diff --git a/library/alloc/tests/slice.rs b/library/alloctests/tests/slice.rs similarity index 99% rename from library/alloc/tests/slice.rs rename to library/alloctests/tests/slice.rs index f990a41b679fa..2516563187f2d 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloctests/tests/slice.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering::{Equal, Greater, Less}; use std::convert::identity; use std::rc::Rc; -use std::{fmt, mem, panic}; +use std::{fmt, panic}; fn square(n: usize) -> usize { n * n @@ -73,7 +73,7 @@ fn test_len_divzero() { let v0: &[Z] = &[]; let v1: &[Z] = &[[]]; let v2: &[Z] = &[[], []]; - assert_eq!(mem::size_of::(), 0); + assert_eq!(size_of::(), 0); assert_eq!(v0.len(), 0); assert_eq!(v1.len(), 1); assert_eq!(v2.len(), 2); diff --git a/library/alloc/tests/sort/ffi_types.rs b/library/alloctests/tests/sort/ffi_types.rs similarity index 100% rename from library/alloc/tests/sort/ffi_types.rs rename to library/alloctests/tests/sort/ffi_types.rs diff --git a/library/alloc/tests/sort/known_good_stable_sort.rs b/library/alloctests/tests/sort/known_good_stable_sort.rs similarity index 98% rename from library/alloc/tests/sort/known_good_stable_sort.rs rename to library/alloctests/tests/sort/known_good_stable_sort.rs index f8615435fc2a7..2df891462538d 100644 --- a/library/alloc/tests/sort/known_good_stable_sort.rs +++ b/library/alloctests/tests/sort/known_good_stable_sort.rs @@ -5,7 +5,7 @@ // Based on https://github.com/voultapher/tiny-sort-rs. use alloc::alloc::{Layout, alloc, dealloc}; -use std::{mem, ptr}; +use std::ptr; /// Sort `v` preserving initial order of equal elements. /// @@ -26,7 +26,7 @@ pub fn sort(v: &mut [T]) { #[inline(always)] fn stable_sort bool>(v: &mut [T], mut is_less: F) { - if mem::size_of::() == 0 { + if size_of::() == 0 { return; } @@ -166,7 +166,7 @@ struct BufGuard { impl BufGuard { // SAFETY: The caller has to ensure that len is not 0 and that T is not a ZST. unsafe fn new(len: usize) -> Self { - debug_assert!(len > 0 && mem::size_of::() > 0); + debug_assert!(len > 0 && size_of::() > 0); // SAFETY: See function safety description. let layout = unsafe { unwrap_unchecked(Layout::array::(len).ok()) }; diff --git a/library/alloc/tests/sort/mod.rs b/library/alloctests/tests/sort/mod.rs similarity index 100% rename from library/alloc/tests/sort/mod.rs rename to library/alloctests/tests/sort/mod.rs diff --git a/library/alloc/tests/sort/patterns.rs b/library/alloctests/tests/sort/patterns.rs similarity index 100% rename from library/alloc/tests/sort/patterns.rs rename to library/alloctests/tests/sort/patterns.rs diff --git a/library/alloc/tests/sort/tests.rs b/library/alloctests/tests/sort/tests.rs similarity index 100% rename from library/alloc/tests/sort/tests.rs rename to library/alloctests/tests/sort/tests.rs diff --git a/library/alloc/tests/sort/zipf.rs b/library/alloctests/tests/sort/zipf.rs similarity index 100% rename from library/alloc/tests/sort/zipf.rs rename to library/alloctests/tests/sort/zipf.rs diff --git a/library/alloc/tests/str.rs b/library/alloctests/tests/str.rs similarity index 100% rename from library/alloc/tests/str.rs rename to library/alloctests/tests/str.rs diff --git a/library/alloc/tests/string.rs b/library/alloctests/tests/string.rs similarity index 100% rename from library/alloc/tests/string.rs rename to library/alloctests/tests/string.rs diff --git a/library/alloc/tests/sync.rs b/library/alloctests/tests/sync.rs similarity index 100% rename from library/alloc/tests/sync.rs rename to library/alloctests/tests/sync.rs diff --git a/library/alloc/tests/task.rs b/library/alloctests/tests/task.rs similarity index 100% rename from library/alloc/tests/task.rs rename to library/alloctests/tests/task.rs diff --git a/library/alloc/tests/testing/crash_test.rs b/library/alloctests/tests/testing/crash_test.rs similarity index 100% rename from library/alloc/tests/testing/crash_test.rs rename to library/alloctests/tests/testing/crash_test.rs diff --git a/library/alloc/tests/testing/mod.rs b/library/alloctests/tests/testing/mod.rs similarity index 100% rename from library/alloc/tests/testing/mod.rs rename to library/alloctests/tests/testing/mod.rs diff --git a/library/alloc/tests/thin_box.rs b/library/alloctests/tests/thin_box.rs similarity index 99% rename from library/alloc/tests/thin_box.rs rename to library/alloctests/tests/thin_box.rs index e008b0cc35718..4c46b61412796 100644 --- a/library/alloc/tests/thin_box.rs +++ b/library/alloctests/tests/thin_box.rs @@ -1,5 +1,4 @@ use core::fmt::Debug; -use core::mem::size_of; use std::boxed::ThinBox; #[test] @@ -52,7 +51,7 @@ fn verify_aligned(ptr: *const T) { ptr.is_aligned() && !ptr.is_null(), "misaligned ThinBox data; valid pointers to `{ty}` should be aligned to {align}: {ptr:p}", ty = core::any::type_name::(), - align = core::mem::align_of::(), + align = align_of::(), ); } diff --git a/library/alloc/tests/vec.rs b/library/alloctests/tests/vec.rs similarity index 99% rename from library/alloc/tests/vec.rs rename to library/alloctests/tests/vec.rs index fe1db56414e0c..f430d979fa848 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -11,14 +11,14 @@ use std::borrow::Cow; use std::cell::Cell; use std::collections::TryReserveErrorKind::*; use std::fmt::Debug; +use std::hint; use std::iter::InPlaceIterable; -use std::mem::{size_of, swap}; +use std::mem::swap; use std::ops::Bound::*; use std::panic::{AssertUnwindSafe, catch_unwind}; use std::rc::Rc; use std::sync::atomic::{AtomicU32, Ordering}; use std::vec::{Drain, IntoIter}; -use std::{hint, mem}; struct DropCounter<'a> { count: &'a mut u32, @@ -1134,7 +1134,7 @@ fn test_into_iter_zst() { impl Drop for AlignedZstWithDrop { fn drop(&mut self) { let addr = self as *mut _ as usize; - assert!(hint::black_box(addr) % mem::align_of::() == 0); + assert!(hint::black_box(addr) % align_of::() == 0); } } diff --git a/library/alloc/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs similarity index 100% rename from library/alloc/tests/vec_deque.rs rename to library/alloctests/tests/vec_deque.rs diff --git a/library/alloc/tests/vec_deque_alloc_error.rs b/library/alloctests/tests/vec_deque_alloc_error.rs similarity index 100% rename from library/alloc/tests/vec_deque_alloc_error.rs rename to library/alloctests/tests/vec_deque_alloc_error.rs diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index e49d978a36787..b60826ee4e6c7 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -9,7 +9,7 @@ autobenches = false # If you update this, be sure to update it in a bunch of other places too! # As of 2024, it was src/tools/opt-dist, the core-no-fp-fmt-parse test and # the version of the prelude imported in core/lib.rs. -edition = "2021" +edition = "2024" [lib] test = false @@ -32,7 +32,8 @@ check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', 'cfg(stdarch_intel_sde)', - 'cfg(target_arch, values("xtensa"))', + # #[cfg(bootstrap)] + 'cfg(target_feature, values("vector-enhancements-1"))', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 17f4d68867e1e..1595a3af883d1 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -17,7 +17,7 @@ use crate::{assert_unsafe_precondition, fmt, mem}; // * https://github.com/rust-lang/rust/pull/72189 // * https://github.com/rust-lang/rust/pull/79827 const fn size_align() -> (usize, usize) { - (mem::size_of::(), mem::align_of::()) + (size_of::(), align_of::()) } /// Layout of a block of memory. @@ -182,7 +182,7 @@ impl Layout { #[must_use] #[inline] pub const fn for_value(t: &T) -> Self { - let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); + let (size, align) = (size_of_val(t), align_of_val(t)); // SAFETY: see rationale in `new` for why this is using the unsafe variant unsafe { Layout::from_size_align_unchecked(size, align) } } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index 9ed2c8e9f3ad1..10f2a11d558be 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -109,7 +109,7 @@ use crate::{fmt, hash, intrinsics}; // unsafe traits and unsafe methods (i.e., `type_id` would still be safe to call, // but we would likely want to indicate as such in documentation). #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Any")] +#[rustc_diagnostic_item = "Any"] pub trait Any: 'static { /// Gets the `TypeId` of `self`. /// diff --git a/library/core/src/array/ascii.rs b/library/core/src/array/ascii.rs index e2faef855bc2c..792a57e3fa25c 100644 --- a/library/core/src/array/ascii.rs +++ b/library/core/src/array/ascii.rs @@ -1,6 +1,5 @@ use crate::ascii; -#[cfg(not(test))] impl [u8; N] { /// Converts this array of bytes into an array of ASCII characters, /// or returns `None` if any of the characters is non-ASCII. diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index 3c589ca5dfa7e..d525ab425e60d 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -56,7 +56,7 @@ impl bool { /// ``` #[doc(alias = "then_with")] #[stable(feature = "lazy_bool_to_option", since = "1.50.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "bool_then")] + #[rustc_diagnostic_item = "bool_then"] #[inline] pub fn then T>(self, f: F) -> Option { if self { Some(f()) } else { None } diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs index 74e07f3d242cd..ae84fd8adb61c 100644 --- a/library/core/src/bstr.rs +++ b/library/core/src/bstr.rs @@ -151,7 +151,9 @@ impl fmt::Display for ByteStr { }; let nchars: usize = self .utf8_chunks() - .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 }) + .map(|chunk| { + chunk.valid().chars().count() + if chunk.invalid().is_empty() { 0 } else { 1 } + }) .sum(); let padding = f.width().unwrap_or(0).saturating_sub(nchars); let fill = f.fill(); diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index cbf00106c5173..1a320b316a41a 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -304,7 +304,7 @@ pub use once::OnceCell; /// ``` /// /// See the [module-level documentation](self) for more. -#[cfg_attr(not(test), rustc_diagnostic_item = "Cell")] +#[rustc_diagnostic_item = "Cell"] #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] #[rustc_pub_transparent] @@ -725,7 +725,7 @@ impl Cell<[T; N]> { /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](self) for more. -#[cfg_attr(not(test), rustc_diagnostic_item = "RefCell")] +#[rustc_diagnostic_item = "RefCell"] #[stable(feature = "rust1", since = "1.0.0")] pub struct RefCell { borrow: Cell, diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 73ab4f1e52ade..ac808038f8900 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -40,11 +40,9 @@ impl From for u32 { /// # Examples /// /// ``` - /// use std::mem; - /// /// let c = 'c'; /// let u = u32::from(c); - /// assert!(4 == mem::size_of_val(&u)) + /// assert!(4 == size_of_val(&u)) /// ``` #[inline] fn from(c: char) -> Self { @@ -59,11 +57,9 @@ impl From for u64 { /// # Examples /// /// ``` - /// use std::mem; - /// /// let c = '👤'; /// let u = u64::from(c); - /// assert!(8 == mem::size_of_val(&u)) + /// assert!(8 == size_of_val(&u)) /// ``` #[inline] fn from(c: char) -> Self { @@ -80,11 +76,9 @@ impl From for u128 { /// # Examples /// /// ``` - /// use std::mem; - /// /// let c = '⚙'; /// let u = u128::from(c); - /// assert!(16 == mem::size_of_val(&u)) + /// assert!(16 == size_of_val(&u)) /// ``` #[inline] fn from(c: char) -> Self { @@ -167,11 +161,9 @@ impl From for char { /// # Examples /// /// ``` - /// use std::mem; - /// /// let u = 32 as u8; /// let c = char::from(u); - /// assert!(4 == mem::size_of_val(&c)) + /// assert!(4 == size_of_val(&c)) /// ``` #[inline] fn from(i: u8) -> Self { diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 85cc315626d4b..fa584953bed5c 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -337,7 +337,7 @@ impl char { /// '1'.is_digit(1); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")] + #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_digit(self, radix: u32) -> bool { self.to_digit(radix).is_some() @@ -886,7 +886,7 @@ impl char { /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_char_classify", issue = "132241")] + #[rustc_const_stable(feature = "const_char_classify", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn is_whitespace(self) -> bool { match self { @@ -1178,7 +1178,7 @@ impl char { #[must_use] #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[rustc_const_stable(feature = "const_char_is_ascii", since = "1.32.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "char_is_ascii")] + #[rustc_diagnostic_item = "char_is_ascii"] #[inline] pub const fn is_ascii(&self) -> bool { *self as u32 <= 0x7F diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 00300328b64c1..e0ac0bfc5289f 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -184,6 +184,59 @@ pub macro Clone($item:item) { /* compiler built-in */ } +/// Trait for objects whose [`Clone`] impl is lightweight (e.g. reference-counted) +/// +/// Cloning an object implementing this trait should in general: +/// - be O(1) (constant) time regardless of the amount of data managed by the object, +/// - not require a memory allocation, +/// - not require copying more than roughly 64 bytes (a typical cache line size), +/// - not block the current thread, +/// - not have any semantic side effects (e.g. allocating a file descriptor), and +/// - not have overhead larger than a couple of atomic operations. +/// +/// The `UseCloned` trait does not provide a method; instead, it indicates that +/// `Clone::clone` is lightweight, and allows the use of the `.use` syntax. +/// +/// ## .use postfix syntax +/// +/// Values can be `.use`d by adding `.use` postfix to the value you want to use. +/// +/// ```ignore (this won't work until we land use) +/// fn foo(f: Foo) { +/// // if `Foo` implements `Copy` f would be copied into x. +/// // if `Foo` implements `UseCloned` f would be cloned into x. +/// // otherwise f would be moved into x. +/// let x = f.use; +/// // ... +/// } +/// ``` +/// +/// ## use closures +/// +/// Use closures allow captured values to be automatically used. +/// This is similar to have a closure that you would call `.use` over each captured value. +#[unstable(feature = "ergonomic_clones", issue = "132290")] +#[cfg_attr(not(bootstrap), lang = "use_cloned")] +pub trait UseCloned: Clone { + // Empty. +} + +macro_rules! impl_use_cloned { + ($($t:ty)*) => { + $( + #[unstable(feature = "ergonomic_clones", issue = "132290")] + impl UseCloned for $t {} + )* + } +} + +impl_use_cloned! { + usize u8 u16 u32 u64 u128 + isize i8 i16 i32 i64 i128 + f16 f32 f64 f128 + bool char +} + // FIXME(aburka): these structs are used solely by #[derive] to // assert that every component of a type implements Clone or Copy. // @@ -209,34 +262,150 @@ pub struct AssertParamIsCopy { _field: crate::marker::PhantomData, } -/// A generalization of [`Clone`] to dynamically-sized types stored in arbitrary containers. +/// A generalization of [`Clone`] to [dynamically-sized types][DST] stored in arbitrary containers. +/// +/// This trait is implemented for all types implementing [`Clone`], [slices](slice) of all +/// such types, and other dynamically-sized types in the standard library. +/// You may also implement this trait to enable cloning custom DSTs +/// (structures containing dynamically-sized fields), or use it as a supertrait to enable +/// cloning a [trait object]. /// -/// This trait is implemented for all types implementing [`Clone`], and also [slices](slice) of all -/// such types. You may also implement this trait to enable cloning trait objects and custom DSTs -/// (structures containing dynamically-sized fields). +/// This trait is normally used via operations on container types which support DSTs, +/// so you should not typically need to call `.clone_to_uninit()` explicitly except when +/// implementing such a container or otherwise performing explicit management of an allocation, +/// or when implementing `CloneToUninit` itself. /// /// # Safety /// -/// Implementations must ensure that when `.clone_to_uninit(dst)` returns normally rather than -/// panicking, it always leaves `*dst` initialized as a valid value of type `Self`. +/// Implementations must ensure that when `.clone_to_uninit(dest)` returns normally rather than +/// panicking, it always leaves `*dest` initialized as a valid value of type `Self`. /// -/// # See also +/// # Examples +/// +// FIXME(#126799): when `Box::clone` allows use of `CloneToUninit`, rewrite these examples with it +// since `Rc` is a distraction. +/// +/// If you are defining a trait, you can add `CloneToUninit` as a supertrait to enable cloning of +/// `dyn` values of your trait: +/// +/// ``` +/// #![feature(clone_to_uninit)] +/// use std::rc::Rc; +/// +/// trait Foo: std::fmt::Debug + std::clone::CloneToUninit { +/// fn modify(&mut self); +/// fn value(&self) -> i32; +/// } +/// +/// impl Foo for i32 { +/// fn modify(&mut self) { +/// *self *= 10; +/// } +/// fn value(&self) -> i32 { +/// *self +/// } +/// } /// -/// * [`Clone::clone_from`] is a safe function which may be used instead when `Self` is a [`Sized`] +/// let first: Rc = Rc::new(1234); +/// +/// let mut second = first.clone(); +/// Rc::make_mut(&mut second).modify(); // make_mut() will call clone_to_uninit() +/// +/// assert_eq!(first.value(), 1234); +/// assert_eq!(second.value(), 12340); +/// ``` +/// +/// The following is an example of implementing `CloneToUninit` for a custom DST. +/// (It is essentially a limited form of what `derive(CloneToUninit)` would do, +/// if such a derive macro existed.) +/// +/// ``` +/// #![feature(clone_to_uninit)] +/// use std::clone::CloneToUninit; +/// use std::mem::offset_of; +/// use std::rc::Rc; +/// +/// #[derive(PartialEq)] +/// struct MyDst { +/// label: String, +/// contents: T, +/// } +/// +/// unsafe impl CloneToUninit for MyDst { +/// unsafe fn clone_to_uninit(&self, dest: *mut u8) { +/// // The offset of `self.contents` is dynamic because it depends on the alignment of T +/// // which can be dynamic (if `T = dyn SomeTrait`). Therefore, we have to obtain it +/// // dynamically by examining `self`, rather than using `offset_of!`. +/// // +/// // SAFETY: `self` by definition points somewhere before `&self.contents` in the same +/// // allocation. +/// let offset_of_contents = unsafe { +/// (&raw const self.contents).byte_offset_from_unsigned(self) +/// }; +/// +/// // Clone the *sized* fields of `self` (just one, in this example). +/// // (By cloning this first and storing it temporarily in a local variable, we avoid +/// // leaking it in case of any panic, using the ordinary automatic cleanup of local +/// // variables. Such a leak would be sound, but undesirable.) +/// let label = self.label.clone(); +/// +/// // SAFETY: The caller must provide a `dest` such that these field offsets are valid +/// // to write to. +/// unsafe { +/// // Clone the unsized field directly from `self` to `dest`. +/// self.contents.clone_to_uninit(dest.add(offset_of_contents)); +/// +/// // Now write all the sized fields. +/// // +/// // Note that we only do this once all of the clone() and clone_to_uninit() calls +/// // have completed, and therefore we know that there are no more possible panics; +/// // this ensures no memory leaks in case of panic. +/// dest.add(offset_of!(Self, label)).cast::().write(label); +/// } +/// // All fields of the struct have been initialized; therefore, the struct is initialized, +/// // and we have satisfied our `unsafe impl CloneToUninit` obligations. +/// } +/// } +/// +/// fn main() { +/// // Construct MyDst<[u8; 4]>, then coerce to MyDst<[u8]>. +/// let first: Rc> = Rc::new(MyDst { +/// label: String::from("hello"), +/// contents: [1, 2, 3, 4], +/// }); +/// +/// let mut second = first.clone(); +/// // make_mut() will call clone_to_uninit(). +/// for elem in Rc::make_mut(&mut second).contents.iter_mut() { +/// *elem *= 10; +/// } +/// +/// assert_eq!(first.contents, [1, 2, 3, 4]); +/// assert_eq!(second.contents, [10, 20, 30, 40]); +/// assert_eq!(second.label, "hello"); +/// } +/// ``` +/// +/// # See Also +/// +/// * [`Clone::clone_from`] is a safe function which may be used instead when [`Self: Sized`](Sized) /// and the destination is already initialized; it may be able to reuse allocations owned by -/// the destination. +/// the destination, whereas `clone_to_uninit` cannot, since its destination is assumed to be +/// uninitialized. /// * [`ToOwned`], which allocates a new destination container. /// /// [`ToOwned`]: ../../std/borrow/trait.ToOwned.html +/// [DST]: https://doc.rust-lang.org/reference/dynamically-sized-types.html +/// [trait object]: https://doc.rust-lang.org/reference/types/trait-object.html #[unstable(feature = "clone_to_uninit", issue = "126799")] pub unsafe trait CloneToUninit { - /// Performs copy-assignment from `self` to `dst`. + /// Performs copy-assignment from `self` to `dest`. /// - /// This is analogous to `std::ptr::write(dst.cast(), self.clone())`, - /// except that `self` may be a dynamically-sized type ([`!Sized`](Sized)). + /// This is analogous to `std::ptr::write(dest.cast(), self.clone())`, + /// except that `Self` may be a dynamically-sized type ([`!Sized`](Sized)). /// - /// Before this function is called, `dst` may point to uninitialized memory. - /// After this function is called, `dst` will point to initialized memory; it will be + /// Before this function is called, `dest` may point to uninitialized memory. + /// After this function is called, `dest` will point to initialized memory; it will be /// sound to create a `&Self` reference from the pointer with the [pointer metadata] /// from `self`. /// @@ -244,8 +413,8 @@ pub unsafe trait CloneToUninit { /// /// Behavior is undefined if any of the following conditions are violated: /// - /// * `dst` must be [valid] for writes for `std::mem::size_of_val(self)` bytes. - /// * `dst` must be properly aligned to `std::mem::align_of_val(self)`. + /// * `dest` must be [valid] for writes for `size_of_val(self)` bytes. + /// * `dest` must be properly aligned to `align_of_val(self)`. /// /// [valid]: crate::ptr#safety /// [pointer metadata]: crate::ptr::metadata() @@ -254,27 +423,26 @@ pub unsafe trait CloneToUninit { /// /// This function may panic. (For example, it might panic if memory allocation for a clone /// of a value owned by `self` fails.) - /// If the call panics, then `*dst` should be treated as uninitialized memory; it must not be + /// If the call panics, then `*dest` should be treated as uninitialized memory; it must not be /// read or dropped, because even if it was previously valid, it may have been partially /// overwritten. /// - /// The caller may also need to take care to deallocate the allocation pointed to by `dst`, - /// if applicable, to avoid a memory leak, and may need to take other precautions to ensure - /// soundness in the presence of unwinding. + /// The caller may wish to to take care to deallocate the allocation pointed to by `dest`, + /// if applicable, to avoid a memory leak (but this is not a requirement). /// /// Implementors should avoid leaking values by, upon unwinding, dropping all component values /// that might have already been created. (For example, if a `[Foo]` of length 3 is being /// cloned, and the second of the three calls to `Foo::clone()` unwinds, then the first `Foo` /// cloned should be dropped.) - unsafe fn clone_to_uninit(&self, dst: *mut u8); + unsafe fn clone_to_uninit(&self, dest: *mut u8); } #[unstable(feature = "clone_to_uninit", issue = "126799")] unsafe impl CloneToUninit for T { #[inline] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { + unsafe fn clone_to_uninit(&self, dest: *mut u8) { // SAFETY: we're calling a specialization with the same contract - unsafe { ::clone_one(self, dst.cast::()) } + unsafe { ::clone_one(self, dest.cast::()) } } } @@ -282,10 +450,10 @@ unsafe impl CloneToUninit for T { unsafe impl CloneToUninit for [T] { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { - let dst: *mut [T] = dst.with_metadata_of(self); + unsafe fn clone_to_uninit(&self, dest: *mut u8) { + let dest: *mut [T] = dest.with_metadata_of(self); // SAFETY: we're calling a specialization with the same contract - unsafe { ::clone_slice(self, dst) } + unsafe { ::clone_slice(self, dest) } } } @@ -293,21 +461,21 @@ unsafe impl CloneToUninit for [T] { unsafe impl CloneToUninit for str { #[inline] #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { + unsafe fn clone_to_uninit(&self, dest: *mut u8) { // SAFETY: str is just a [u8] with UTF-8 invariant - unsafe { self.as_bytes().clone_to_uninit(dst) } + unsafe { self.as_bytes().clone_to_uninit(dest) } } } #[unstable(feature = "clone_to_uninit", issue = "126799")] unsafe impl CloneToUninit for crate::ffi::CStr { #[cfg_attr(debug_assertions, track_caller)] - unsafe fn clone_to_uninit(&self, dst: *mut u8) { + unsafe fn clone_to_uninit(&self, dest: *mut u8) { // SAFETY: For now, CStr is just a #[repr(trasnsparent)] [c_char] with some invariants. // And we can cast [c_char] to [u8] on all supported platforms (see: to_bytes_with_nul). // The pointer metadata properly preserves the length (so NUL is also copied). // See: `cstr_metadata_is_length_with_nul` in tests. - unsafe { self.to_bytes_with_nul().clone_to_uninit(dst) } + unsafe { self.to_bytes_with_nul().clone_to_uninit(dest) } } } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 594236cf1d96f..25bd17d5802fd 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -397,6 +397,12 @@ pub enum Ordering { } impl Ordering { + #[inline] + const fn as_raw(self) -> i8 { + // FIXME(const-hack): just use `PartialOrd` against `Equal` once that's const + crate::intrinsics::discriminant_value(&self) + } + /// Returns `true` if the ordering is the `Equal` variant. /// /// # Examples @@ -413,7 +419,11 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_eq(self) -> bool { - matches!(self, Equal) + // All the `is_*` methods are implemented as comparisons against zero + // to follow how clang's libcxx implements their equivalents in + // + + self.as_raw() == 0 } /// Returns `true` if the ordering is not the `Equal` variant. @@ -432,7 +442,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ne(self) -> bool { - !matches!(self, Equal) + self.as_raw() != 0 } /// Returns `true` if the ordering is the `Less` variant. @@ -451,7 +461,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_lt(self) -> bool { - matches!(self, Less) + self.as_raw() < 0 } /// Returns `true` if the ordering is the `Greater` variant. @@ -470,7 +480,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_gt(self) -> bool { - matches!(self, Greater) + self.as_raw() > 0 } /// Returns `true` if the ordering is either the `Less` or `Equal` variant. @@ -489,7 +499,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_le(self) -> bool { - !matches!(self, Greater) + self.as_raw() <= 0 } /// Returns `true` if the ordering is either the `Greater` or `Equal` variant. @@ -508,7 +518,7 @@ impl Ordering { #[rustc_const_stable(feature = "ordering_helpers", since = "1.53.0")] #[stable(feature = "ordering_helpers", since = "1.53.0")] pub const fn is_ge(self) -> bool { - !matches!(self, Less) + self.as_raw() >= 0 } /// Reverses the `Ordering`. @@ -1369,7 +1379,7 @@ pub trait PartialOrd: PartialEq { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_partialord_lt"] fn lt(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Less)) + self.partial_cmp(other).is_some_and(Ordering::is_lt) } /// Tests less than or equal to (for `self` and `other`) and is used by the @@ -1387,7 +1397,7 @@ pub trait PartialOrd: PartialEq { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_partialord_le"] fn le(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Less | Equal)) + self.partial_cmp(other).is_some_and(Ordering::is_le) } /// Tests greater than (for `self` and `other`) and is used by the `>` @@ -1405,7 +1415,7 @@ pub trait PartialOrd: PartialEq { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_partialord_gt"] fn gt(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Greater)) + self.partial_cmp(other).is_some_and(Ordering::is_gt) } /// Tests greater than or equal to (for `self` and `other`) and is used by @@ -1423,7 +1433,7 @@ pub trait PartialOrd: PartialEq { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "cmp_partialord_ge"] fn ge(&self, other: &Rhs) -> bool { - matches!(self.partial_cmp(other), Some(Greater | Equal)) + self.partial_cmp(other).is_some_and(Ordering::is_ge) } } @@ -1471,7 +1481,7 @@ pub macro PartialOrd($item:item) { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_min")] +#[rustc_diagnostic_item = "cmp_min"] pub fn min(v1: T, v2: T) -> T { v1.min(v2) } @@ -1563,7 +1573,7 @@ pub fn min_by_key K, K: Ord>(v1: T, v2: T, mut f: F) -> T { #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "cmp_max")] +#[rustc_diagnostic_item = "cmp_max"] pub fn max(v1: T, v2: T) -> T { v1.max(v2) } diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs index c769e219e4d49..8b79a3a7eba86 100644 --- a/library/core/src/contracts.rs +++ b/library/core/src/contracts.rs @@ -1,5 +1,4 @@ //! Unstable module containing the unstable contracts lang items and attribute macros. -#![cfg(not(bootstrap))] pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires}; diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index e468f4f0f7e66..e1b10e1074d27 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -214,7 +214,7 @@ pub const fn identity(x: T) -> T { /// is_hello(s); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "AsRef")] +#[rustc_diagnostic_item = "AsRef"] pub trait AsRef { /// Converts this type into a shared reference of the (usually inferred) input type. #[stable(feature = "rust1", since = "1.0.0")] @@ -365,7 +365,7 @@ pub trait AsRef { /// Note, however, that APIs don't need to be generic. In many cases taking a `&mut [u8]` or /// `&mut Vec`, for example, is the better choice (callers need to pass the correct type then). #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "AsMut")] +#[rustc_diagnostic_item = "AsMut"] pub trait AsMut { /// Converts this type into a mutable reference of the (usually inferred) input type. #[stable(feature = "rust1", since = "1.0.0")] @@ -778,7 +778,6 @@ impl From for T { /// /// [#64715]: https://github.com/rust-lang/rust/issues/64715 #[stable(feature = "convert_infallible", since = "1.34.0")] -#[allow(unused_attributes)] // FIXME(#58633): do a principled fix instead. #[rustc_reservation_impl = "permitting this impl would forbid us from adding \ `impl From for T` later; see rust-lang/rust#64715 for details"] impl From for T { diff --git a/library/core/src/default.rs b/library/core/src/default.rs index 4c30290ff263b..044997a81a9a2 100644 --- a/library/core/src/default.rs +++ b/library/core/src/default.rs @@ -101,7 +101,7 @@ use crate::ascii::Char as AsciiChar; /// bar: f32, /// } /// ``` -#[cfg_attr(not(test), rustc_diagnostic_item = "Default")] +#[rustc_diagnostic_item = "Default"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_trivial_field_reads] pub trait Default: Sized { diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 69ad7239954ac..bfa392003b91b 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -47,7 +47,7 @@ use crate::fmt::{self, Debug, Display, Formatter}; /// impl Error for ReadConfigError {} /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[rustc_diagnostic_item = "Error"] #[rustc_has_incoherent_inherent_impls] #[allow(multiple_supertrait_upcastable)] pub trait Error: Debug + Display { @@ -1099,5 +1099,5 @@ impl Error for crate::time::TryFromFloatSecsError {} #[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] impl Error for crate::ffi::FromBytesUntilNulError {} -#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "get_many_mut", since = "1.86.0")] impl Error for crate::slice::GetDisjointMutError {} diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 75338e492ee0a..080c0cef53304 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -55,18 +55,15 @@ use crate::{fmt, ops, slice, str}; /// Passing a Rust-originating C string: /// /// ``` -/// use std::ffi::{CString, CStr}; +/// use std::ffi::CStr; /// use std::os::raw::c_char; /// /// fn work(data: &CStr) { -/// # /* Extern functions are awkward in doc comments - fake it instead -/// extern "C" { fn work_with(data: *const c_char); } -/// # */ unsafe extern "C" fn work_with(s: *const c_char) {} -/// +/// unsafe extern "C" fn work_with(s: *const c_char) {} /// unsafe { work_with(data.as_ptr()) } /// } /// -/// let s = CString::new("data data data data").expect("CString::new failed"); +/// let s = c"Hello world!"; /// work(&s); /// ``` /// @@ -384,13 +381,12 @@ impl CStr { /// # Examples /// /// ``` - /// use std::ffi::{CStr, CString}; + /// use std::ffi::CStr; /// - /// unsafe { - /// let cstring = CString::new("hello").expect("CString::new failed"); - /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); - /// assert_eq!(cstr, &*cstring); - /// } + /// let bytes = b"Hello world!\0"; + /// + /// let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }; + /// assert_eq!(cstr.to_bytes_with_nul(), bytes); /// ``` #[inline] #[must_use] @@ -449,38 +445,43 @@ impl CStr { /// behavior when `ptr` is used inside the `unsafe` block: /// /// ```no_run - /// # #![allow(unused_must_use)] /// # #![expect(dangling_pointers_from_temporaries)] - /// use std::ffi::CString; + /// use std::ffi::{CStr, CString}; /// - /// // Do not do this: - /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr(); - /// unsafe { - /// // `ptr` is dangling - /// *ptr; - /// } + /// // 💀 The meaning of this entire program is undefined, + /// // 💀 and nothing about its behavior is guaranteed, + /// // 💀 not even that its behavior resembles the code as written, + /// // 💀 just because it contains a single instance of undefined behavior! + /// + /// // 🚨 creates a dangling pointer to a temporary `CString` + /// // 🚨 that is deallocated at the end of the statement + /// let ptr = CString::new("Hi!".to_uppercase()).unwrap().as_ptr(); + /// + /// // without undefined behavior, you would expect that `ptr` equals: + /// dbg!(CStr::from_bytes_with_nul(b"HI!\0").unwrap()); + /// + /// // 🙏 Possibly the program behaved as expected so far, + /// // 🙏 and this just shows `ptr` is now garbage..., but + /// // 💀 this violates `CStr::from_ptr`'s safety contract + /// // 💀 leading to a dereference of a dangling pointer, + /// // 💀 which is immediate undefined behavior. + /// // 💀 *BOOM*, you're dead, you're entire program has no meaning. + /// dbg!(unsafe { CStr::from_ptr(ptr) }); /// ``` /// - /// This happens because the pointer returned by `as_ptr` does not carry any - /// lifetime information and the `CString` is deallocated immediately after - /// the `CString::new("Hello").expect("CString::new failed").as_ptr()` - /// expression is evaluated. + /// This happens because, the pointer returned by `as_ptr` does not carry any + /// lifetime information, and the `CString` is deallocated immediately after + /// the expression that it is part of has been evaluated. /// To fix the problem, bind the `CString` to a local variable: /// - /// ```no_run - /// # #![allow(unused_must_use)] - /// use std::ffi::CString; - /// - /// let hello = CString::new("Hello").expect("CString::new failed"); - /// let ptr = hello.as_ptr(); - /// unsafe { - /// // `ptr` is valid because `hello` is in scope - /// *ptr; - /// } /// ``` + /// use std::ffi::{CStr, CString}; /// - /// This way, the lifetime of the `CString` in `hello` encompasses - /// the lifetime of `ptr` and the `unsafe` block. + /// let c_str = CString::new("Hi!".to_uppercase()).unwrap(); + /// let ptr = c_str.as_ptr(); + /// + /// assert_eq!(unsafe { CStr::from_ptr(ptr) }, c"HI!"); + /// ``` #[inline] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/ffi/primitives.rs b/library/core/src/ffi/primitives.rs index ece3c7538dabb..0a70eb4da5522 100644 --- a/library/core/src/ffi/primitives.rs +++ b/library/core/src/ffi/primitives.rs @@ -39,7 +39,6 @@ mod c_char_definition { // These are the targets on which c_char is unsigned. Usually the // signedness is the same for all target_os values on a given architecture // but there are some exceptions (see isSignedCharDefault() in clang). - // // aarch64: // Section 10 "Arm C and C++ language mappings" in Procedure Call Standard for the Arm® // 64-bit Architecture (AArch64) says C/C++ char is unsigned byte. @@ -97,14 +96,19 @@ mod c_char_definition { // are promoted to int as if from type signed char by default, unless the /J compilation // option is used." // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types + // Vita: + // Chars are signed by default on the Vita, and VITASDK follows that convention. + // https://github.com/vitasdk/buildscripts/blob/09c533b771591ecde88864b6acad28ffb688dbd4/patches/gcc/0001-gcc-10.patch#L33-L34 + // // L4Re: - // The kernel builds with -funsigned-char on all targets (but useserspace follows the + // The kernel builds with -funsigned-char on all targets (but userspace follows the // architecture defaults). As we only have a target for userspace apps so there are no // special cases for L4Re below. // https://github.com/rust-lang/rust/pull/132975#issuecomment-2484645240 if #[cfg(all( not(windows), not(target_vendor = "apple"), + not(target_os = "vita"), any( target_arch = "aarch64", target_arch = "arm", @@ -129,7 +133,10 @@ mod c_char_definition { mod c_long_definition { cfg_if! { - if #[cfg(all(target_pointer_width = "64", not(windows)))] { + if #[cfg(any( + all(target_pointer_width = "64", not(windows)), + // wasm32 Linux ABI uses 64-bit long + all(target_arch = "wasm32", target_os = "linux")))] { pub(super) type c_long = i64; pub(super) type c_ulong = u64; } else { diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs index cceb186b31e79..1ad8038cbf6eb 100644 --- a/library/core/src/ffi/va_list.rs +++ b/library/core/src/ffi/va_list.rs @@ -305,25 +305,16 @@ impl<'f> Drop for VaListImpl<'f> { /// Destroy the arglist `ap` after initialization with `va_start` or /// `va_copy`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -unsafe fn va_end(_ap: &mut VaListImpl<'_>) { - unreachable!() -} +unsafe fn va_end(ap: &mut VaListImpl<'_>); /// Copies the current location of arglist `src` to the arglist `dst`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -unsafe fn va_copy<'f>(_dest: *mut VaListImpl<'f>, _src: &VaListImpl<'f>) { - unreachable!() -} +unsafe fn va_copy<'f>(dest: *mut VaListImpl<'f>, src: &VaListImpl<'f>); /// Loads an argument of type `T` from the `va_list` `ap` and increment the /// argument `ap` points to. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -unsafe fn va_arg(_ap: &mut VaListImpl<'_>) -> T { - unreachable!() -} +unsafe fn va_arg(ap: &mut VaListImpl<'_>) -> T; diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 3f10158193d76..4a43c12be9aaa 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -29,7 +29,7 @@ fn float_to_decimal_common_exact( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, ) -> Result where T: flt2dec::DecodableFloat, @@ -40,7 +40,7 @@ where flt2dec::strategy::grisu::format_exact, *num, sign, - precision, + precision.into(), &mut buf, &mut parts, ); @@ -55,7 +55,7 @@ fn float_to_decimal_common_shortest( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, ) -> Result where T: flt2dec::DecodableFloat, @@ -68,7 +68,7 @@ where flt2dec::strategy::grisu::format_shortest, *num, sign, - precision, + precision.into(), &mut buf, &mut parts, ); @@ -101,7 +101,7 @@ fn float_to_exponential_common_exact( fmt: &mut Formatter<'_>, num: &T, sign: flt2dec::Sign, - precision: usize, + precision: u16, upper: bool, ) -> Result where @@ -113,7 +113,7 @@ where flt2dec::strategy::grisu::format_exact, *num, sign, - precision, + precision.into(), upper, &mut buf, &mut parts, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 764e7fff33ec7..a0f5b00cd2dc4 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -18,7 +18,7 @@ mod num; mod rt; #[stable(feature = "fmt_flags_align", since = "1.28.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Alignment")] +#[rustc_diagnostic_item = "Alignment"] /// Possible alignments returned by `Formatter::align` #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Alignment { @@ -294,8 +294,8 @@ pub struct FormattingOptions { flags: u32, fill: char, align: Option, - width: Option, - precision: Option, + width: Option, + precision: Option, } impl FormattingOptions { @@ -389,7 +389,7 @@ impl FormattingOptions { /// the padding specified by [`FormattingOptions::fill`]/[`FormattingOptions::align`] /// will be used to take up the required space. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn width(&mut self, width: Option) -> &mut Self { + pub fn width(&mut self, width: Option) -> &mut Self { self.width = width; self } @@ -403,7 +403,7 @@ impl FormattingOptions { /// - For floating-point types, this indicates how many digits after the /// decimal point should be printed. #[unstable(feature = "formatting_options", issue = "118117")] - pub fn precision(&mut self, precision: Option) -> &mut Self { + pub fn precision(&mut self, precision: Option) -> &mut Self { self.precision = precision; self } @@ -455,12 +455,12 @@ impl FormattingOptions { } /// Returns the current width. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn get_width(&self) -> Option { + pub const fn get_width(&self) -> Option { self.width } /// Returns the current precision. #[unstable(feature = "formatting_options", issue = "118117")] - pub const fn get_precision(&self) -> Option { + pub const fn get_precision(&self) -> Option { self.precision } /// Returns the current precision. @@ -1499,15 +1499,18 @@ unsafe fn run(fmt: &mut Formatter<'_>, arg: &rt::Placeholder, args: &[rt::Argume unsafe { value.fmt(fmt) } } -unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { +unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option { match *cnt { + #[cfg(bootstrap)] + rt::Count::Is(n) => Some(n as u16), + #[cfg(not(bootstrap))] rt::Count::Is(n) => Some(n), rt::Count::Implied => None, rt::Count::Param(i) => { debug_assert!(i < args.len()); // SAFETY: cnt and args come from the same Arguments, // which guarantees this index is always within bounds. - unsafe { args.get_unchecked(i).as_usize() } + unsafe { args.get_unchecked(i).as_u16() } } } } @@ -1516,11 +1519,11 @@ unsafe fn getcount(args: &[rt::Argument<'_>], cnt: &rt::Count) -> Option #[must_use = "don't forget to write the post padding"] pub(crate) struct PostPadding { fill: char, - padding: usize, + padding: u16, } impl PostPadding { - fn new(fill: char, padding: usize) -> PostPadding { + fn new(fill: char, padding: u16) -> PostPadding { PostPadding { fill, padding } } @@ -1634,7 +1637,7 @@ impl<'a> Formatter<'a> { } // Check if we're over the minimum width, if so then we can also // just write the bytes. - Some(min) if width >= min => { + Some(min) if width >= usize::from(min) => { write_prefix(self, sign, prefix)?; self.buf.write_str(buf) } @@ -1645,7 +1648,7 @@ impl<'a> Formatter<'a> { let old_align = crate::mem::replace(&mut self.options.align, Some(Alignment::Right)); write_prefix(self, sign, prefix)?; - let post_padding = self.padding(min - width, Alignment::Right)?; + let post_padding = self.padding(min - width as u16, Alignment::Right)?; self.buf.write_str(buf)?; post_padding.write(self)?; self.options.fill = old_fill; @@ -1654,7 +1657,7 @@ impl<'a> Formatter<'a> { } // Otherwise, the sign and prefix goes after the padding Some(min) => { - let post_padding = self.padding(min - width, Alignment::Right)?; + let post_padding = self.padding(min - width as u16, Alignment::Right)?; write_prefix(self, sign, prefix)?; self.buf.write_str(buf)?; post_padding.write(self) @@ -1693,49 +1696,41 @@ impl<'a> Formatter<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { - // Make sure there's a fast path up front + // Make sure there's a fast path up front. if self.options.width.is_none() && self.options.precision.is_none() { return self.buf.write_str(s); } - // The `precision` field can be interpreted as a `max-width` for the + + // The `precision` field can be interpreted as a maximum width for the // string being formatted. - let s = if let Some(max) = self.options.precision { - // If our string is longer that the precision, then we must have - // truncation. However other flags like `fill`, `width` and `align` - // must act as always. - if let Some((i, _)) = s.char_indices().nth(max) { - // LLVM here can't prove that `..i` won't panic `&s[..i]`, but - // we know that it can't panic. Use `get` + `unwrap_or` to avoid - // `unsafe` and otherwise don't emit any panic-related code - // here. - s.get(..i).unwrap_or(s) - } else { - &s - } + let (s, char_count) = if let Some(max_char_count) = self.options.precision { + let mut iter = s.char_indices(); + let remaining = match iter.advance_by(usize::from(max_char_count)) { + Ok(()) => 0, + Err(remaining) => remaining.get(), + }; + // SAFETY: The offset of `.char_indices()` is guaranteed to be + // in-bounds and between character boundaries. + let truncated = unsafe { s.get_unchecked(..iter.offset()) }; + (truncated, usize::from(max_char_count) - remaining) } else { - &s + // Use the optimized char counting algorithm for the full string. + (s, s.chars().count()) }; - // The `width` field is more of a `min-width` parameter at this point. - match self.options.width { - // If we're under the maximum length, and there's no minimum length - // requirements, then we can just emit the string - None => self.buf.write_str(s), - Some(width) => { - let chars_count = s.chars().count(); - // If we're under the maximum width, check if we're over the minimum - // width, if so it's as easy as just emitting the string. - if chars_count >= width { - self.buf.write_str(s) - } - // If we're under both the maximum and the minimum width, then fill - // up the minimum width with the specified string + some alignment. - else { - let align = Alignment::Left; - let post_padding = self.padding(width - chars_count, align)?; - self.buf.write_str(s)?; - post_padding.write(self) - } - } + + // The `width` field is more of a minimum width parameter at this point. + if let Some(width) = self.options.width + && char_count < usize::from(width) + { + // If we're under the minimum width, then fill up the minimum width + // with the specified string + some alignment. + let post_padding = self.padding(width - char_count as u16, Alignment::Left)?; + self.buf.write_str(s)?; + post_padding.write(self) + } else { + // If we're over the minimum width or there is no minimum width, we + // can just emit the string. + self.buf.write_str(s) } } @@ -1745,7 +1740,7 @@ impl<'a> Formatter<'a> { /// thing that is being padded. pub(crate) fn padding( &mut self, - padding: usize, + padding: u16, default: Alignment, ) -> result::Result { let align = self.align().unwrap_or(default); @@ -1785,19 +1780,19 @@ impl<'a> Formatter<'a> { // remove the sign from the formatted parts formatted.sign = ""; - width = width.saturating_sub(sign.len()); + width = width.saturating_sub(sign.len() as u16); self.options.fill = '0'; self.options.align = Some(Alignment::Right); } // remaining parts go through the ordinary padding process. let len = formatted.len(); - let ret = if width <= len { + let ret = if usize::from(width) <= len { // no padding // SAFETY: Per the precondition. unsafe { self.write_formatted_parts(&formatted) } } else { - let post_padding = self.padding(width - len, Alignment::Right)?; + let post_padding = self.padding(width - len as u16, Alignment::Right)?; // SAFETY: Per the precondition. unsafe { self.write_formatted_parts(&formatted)?; @@ -2029,7 +2024,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn width(&self) -> Option { - self.options.width + self.options.width.map(|x| x as usize) } /// Returns the optionally specified precision for numeric types. @@ -2060,7 +2055,7 @@ impl<'a> Formatter<'a> { #[must_use] #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn precision(&self) -> Option { - self.options.precision + self.options.precision.map(|x| x as usize) } /// Determines if the `+` flag was specified. @@ -2800,7 +2795,7 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul f.options.flags |= 1 << (rt::Flag::SignAwareZeroPad as u32); if f.options.width.is_none() { - f.options.width = Some((usize::BITS / 4) as usize + 2); + f.options.width = Some((usize::BITS / 4) as u16 + 2); } } f.options.flags |= 1 << (rt::Flag::Alternate as u32); diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index 85d089a079082..080fc6ddfc9b8 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -47,7 +47,11 @@ pub enum Alignment { #[derive(Copy, Clone)] pub enum Count { /// Specified with a literal number, stores the value + #[cfg(bootstrap)] Is(usize), + /// Specified with a literal number, stores the value + #[cfg(not(bootstrap))] + Is(u16), /// Specified using `$` and `*` syntaxes, stores the index into `args` Param(usize), /// Not specified @@ -74,7 +78,7 @@ enum ArgumentType<'a> { formatter: unsafe fn(NonNull<()>, &mut Formatter<'_>) -> Result, _lifetime: PhantomData<&'a ()>, }, - Count(usize), + Count(u16), } /// This struct represents a generic "argument" which is taken by format_args!(). @@ -150,8 +154,12 @@ impl Argument<'_> { Self::new(x, UpperExp::fmt) } #[inline] + #[track_caller] pub const fn from_usize(x: &usize) -> Argument<'_> { - Argument { ty: ArgumentType::Count(*x) } + if *x > u16::MAX as usize { + panic!("Formatting argument out of range"); + } + Argument { ty: ArgumentType::Count(*x as u16) } } /// Format this placeholder argument. @@ -181,7 +189,7 @@ impl Argument<'_> { } #[inline] - pub(super) const fn as_usize(&self) -> Option { + pub(super) const fn as_u16(&self) -> Option { match self.ty { ArgumentType::Count(count) => Some(count), ArgumentType::Placeholder { .. } => None, diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index e5a368796ec93..65c0171c88d5b 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -46,19 +46,19 @@ pub use self::join::join; /// It also simplifies the HIR lowering of `.await`. #[lang = "ResumeTy"] #[doc(hidden)] -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] #[derive(Debug, Copy, Clone)] pub struct ResumeTy(NonNull>); -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] unsafe impl Send for ResumeTy {} -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] unsafe impl Sync for ResumeTy {} #[lang = "get_context"] #[doc(hidden)] -#[unstable(feature = "gen_future", issue = "50547")] +#[unstable(feature = "gen_future", issue = "none")] #[must_use] #[inline] pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> { diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 7a6630c82d0da..f7b874b26bb74 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -801,7 +801,7 @@ impl Eq for BuildHasherDefault {} mod impls { use super::*; - use crate::{mem, slice}; + use crate::slice; macro_rules! impl_write { ($(($ty:ident, $meth:ident),)*) => {$( @@ -814,7 +814,7 @@ mod impls { #[inline] fn hash_slice(data: &[$ty], state: &mut H) { - let newlen = mem::size_of_val(data); + let newlen = size_of_val(data); let ptr = data.as_ptr() as *const u8; // SAFETY: `ptr` is valid and aligned, as this macro is only used // for numeric primitives which have no padding. The new slice only diff --git a/library/core/src/hash/sip.rs b/library/core/src/hash/sip.rs index 6ea3241c59354..780e522c48ebf 100644 --- a/library/core/src/hash/sip.rs +++ b/library/core/src/hash/sip.rs @@ -3,7 +3,7 @@ #![allow(deprecated)] // the types in this module are deprecated use crate::marker::PhantomData; -use crate::{cmp, mem, ptr}; +use crate::{cmp, ptr}; /// An implementation of SipHash 1-3. /// @@ -99,12 +99,12 @@ macro_rules! compress { /// `$i..$i+size_of::<$int_ty>()`, so that must be in-bounds. macro_rules! load_int_le { ($buf:expr, $i:expr, $int_ty:ident) => {{ - debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len()); + debug_assert!($i + size_of::<$int_ty>() <= $buf.len()); let mut data = 0 as $int_ty; ptr::copy_nonoverlapping( $buf.as_ptr().add($i), &mut data as *mut _ as *mut u8, - mem::size_of::<$int_ty>(), + size_of::<$int_ty>(), ); data.to_le() }}; diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 76afb3b8e20c0..5ce282b05de73 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -472,7 +472,7 @@ pub fn spin_loop() { /// During constant evaluation, `black_box` is treated as a no-op. #[inline] #[stable(feature = "bench_black_box", since = "1.66.0")] -#[rustc_const_stable(feature = "const_black_box", since = "CURRENT_RUSTC_VERSION")] +#[rustc_const_stable(feature = "const_black_box", since = "1.86.0")] pub const fn black_box(dummy: T) -> T { crate::intrinsics::black_box(dummy) } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 99c42f3626e7c..078f7552c8744 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -10,7 +10,7 @@ //! //! In order to make an intrinsic usable at compile-time, it needs to be declared in the "new" //! style, i.e. as a `#[rustc_intrinsic]` function, not inside an `extern` block. Then copy the -//! implementation from to +//! implementation from to //! //! and make the intrinsic declaration a `const fn`. //! @@ -78,11 +78,7 @@ pub mod simd; use crate::sync::atomic::{self, AtomicBool, AtomicI32, AtomicIsize, AtomicU32, Ordering}; #[stable(feature = "drop_in_place", since = "1.8.0")] -#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] -#[cfg_attr( - not(bootstrap), - rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead" -)] +#[rustc_allowed_through_unstable_modules = "import this function via `std::ptr` instead"] #[deprecated(note = "no longer an intrinsic - use `ptr::drop_in_place` directly", since = "1.52.0")] #[inline] pub unsafe fn drop_in_place(to_drop: *mut T) { @@ -94,1120 +90,964 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { // memory, which is not valid for either `&` or `&mut`. /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_relaxed_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_relaxed_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_relaxed_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_relaxed_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_relaxed_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_acquire_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_acquire_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Acquire`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_acquire_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_acquire_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_acquire_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_release_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_release_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_release_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_release_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_release_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_acqrel_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_acqrel_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_acqrel_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_seqcst_relaxed(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_seqcst_acquire(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange` method by passing /// [`Ordering::SeqCst`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchg_seqcst_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchg_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] pub unsafe fn atomic_cxchgweak_relaxed_relaxed( _dst: *mut T, _old: T, _src: T, -) -> (T, bool) { - unreachable!() -} +) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] pub unsafe fn atomic_cxchgweak_relaxed_acquire( _dst: *mut T, _old: T, _src: T, -) -> (T, bool) { - unreachable!() -} +) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_relaxed_seqcst( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_relaxed_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] pub unsafe fn atomic_cxchgweak_acquire_relaxed( _dst: *mut T, _old: T, _src: T, -) -> (T, bool) { - unreachable!() -} +) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] pub unsafe fn atomic_cxchgweak_acquire_acquire( _dst: *mut T, _old: T, _src: T, -) -> (T, bool) { - unreachable!() -} +) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acquire_seqcst( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_acquire_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] pub unsafe fn atomic_cxchgweak_release_relaxed( _dst: *mut T, _old: T, _src: T, -) -> (T, bool) { - unreachable!() -} +) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] pub unsafe fn atomic_cxchgweak_release_acquire( _dst: *mut T, _old: T, _src: T, -) -> (T, bool) { - unreachable!() -} +) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_release_seqcst( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_release_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acqrel_relaxed( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_acqrel_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acqrel_acquire( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_acqrel_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_acqrel_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_acqrel_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_seqcst_relaxed( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_seqcst_relaxed(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_seqcst_acquire( - _dst: *mut T, - _old: T, - _src: T, -) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_seqcst_acquire(dst: *mut T, old: T, src: T) -> (T, bool); /// Stores a value if the current value is the same as the `old` value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `compare_exchange_weak` method by passing /// [`Ordering::SeqCst`] as both the success and failure parameters. /// For example, [`AtomicBool::compare_exchange_weak`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_cxchgweak_seqcst_seqcst(_dst: *mut T, _old: T, _src: T) -> (T, bool) { - unreachable!() -} +pub unsafe fn atomic_cxchgweak_seqcst_seqcst(dst: *mut T, old: T, src: T) -> (T, bool); /// Loads the current value of the pointer. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_load_seqcst(_src: *const T) -> T { - unreachable!() -} +pub unsafe fn atomic_load_seqcst(src: *const T) -> T; /// Loads the current value of the pointer. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_load_acquire(_src: *const T) -> T { - unreachable!() -} +pub unsafe fn atomic_load_acquire(src: *const T) -> T; /// Loads the current value of the pointer. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `load` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_load_relaxed(_src: *const T) -> T { - unreachable!() -} +pub unsafe fn atomic_load_relaxed(src: *const T) -> T; /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! /// In terms of the Rust Abstract Machine, this operation is equivalent to `src.read()`, /// i.e., it performs a non-atomic read. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_load_unordered(_src: *const T) -> T { - unreachable!() -} +pub unsafe fn atomic_load_unordered(src: *const T) -> T; /// Stores the value at the specified memory location. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_store_seqcst(_dst: *mut T, _val: T) { - unreachable!() -} +pub unsafe fn atomic_store_seqcst(dst: *mut T, val: T); /// Stores the value at the specified memory location. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_store_release(_dst: *mut T, _val: T) { - unreachable!() -} +pub unsafe fn atomic_store_release(dst: *mut T, val: T); /// Stores the value at the specified memory location. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `store` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_store_relaxed(_dst: *mut T, _val: T) { - unreachable!() -} +pub unsafe fn atomic_store_relaxed(dst: *mut T, val: T); /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model! /// In terms of the Rust Abstract Machine, this operation is equivalent to `dst.write(val)`, /// i.e., it performs a non-atomic write. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_store_unordered(_dst: *mut T, _val: T) { - unreachable!() -} +pub unsafe fn atomic_store_unordered(dst: *mut T, val: T); /// Stores the value at the specified memory location, returning the old value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xchg_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xchg_seqcst(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xchg_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xchg_acquire(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xchg_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xchg_release(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::swap`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xchg_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xchg_acqrel(dst: *mut T, src: T) -> T; /// Stores the value at the specified memory location, returning the old value. +/// `T` must be an integer or pointer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `swap` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::swap`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xchg_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xchg_relaxed(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xadd_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xadd_seqcst(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xadd_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xadd_acquire(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xadd_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xadd_release(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_add`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xadd_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xadd_acqrel(dst: *mut T, src: T) -> T; /// Adds to the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_add` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_add`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xadd_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xadd_relaxed(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xsub_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xsub_seqcst(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xsub_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xsub_acquire(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xsub_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xsub_release(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xsub_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xsub_acqrel(dst: *mut T, src: T) -> T; /// Subtract from the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_sub` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_sub`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xsub_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xsub_relaxed(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_and_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_and_seqcst(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_and_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_and_acquire(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_and_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_and_release(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_and`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_and_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_and_acqrel(dst: *mut T, src: T) -> T; /// Bitwise and with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_and` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_and`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_and_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_and_relaxed(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_nand_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_nand_seqcst(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_nand_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_nand_acquire(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_nand_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_nand_release(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_nand`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_nand_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_nand_acqrel(dst: *mut T, src: T) -> T; /// Bitwise nand with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`AtomicBool`] type via the `fetch_nand` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_nand`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_nand_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_nand_relaxed(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_or_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_or_seqcst(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_or_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_or_acquire(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_or_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_or_release(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_or`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_or_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_or_acqrel(dst: *mut T, src: T) -> T; /// Bitwise or with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_or` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_or`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_or_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_or_relaxed(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xor_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xor_seqcst(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xor_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xor_acquire(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xor_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xor_release(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_xor`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xor_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xor_acqrel(dst: *mut T, src: T) -> T; /// Bitwise xor with the current value, returning the previous value. +/// `T` must be an integer or pointer type. +/// If `T` is a pointer type, the provenance of `src` is ignored: both the return value and the new +/// value stored at `*dst` will have the provenance of the old value stored there. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] types via the `fetch_xor` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_xor`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_xor_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_xor_relaxed(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_max_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_max_seqcst(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_max_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_max_acquire(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_max_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_max_release(dst: *mut T, src: T) -> T; /// Maximum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_max_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} -/// Maximum with the current value. +pub unsafe fn atomic_max_acqrel(dst: *mut T, src: T) -> T; +/// Maximum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_max` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_max_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_max_relaxed(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_min_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_min_seqcst(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_min_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_min_acquire(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_min_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_min_release(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_min_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_min_acqrel(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. +/// `T` must be a signed integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_min_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_min_relaxed(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umin_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umin_seqcst(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umin_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umin_acquire(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umin_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umin_release(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umin_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umin_acqrel(dst: *mut T, src: T) -> T; /// Minimum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_min` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_min`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umin_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umin_relaxed(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umax_seqcst(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umax_seqcst(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umax_acquire(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umax_acquire(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umax_release(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umax_release(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umax_acqrel(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umax_acqrel(dst: *mut T, src: T) -> T; /// Maximum with the current value using an unsigned comparison. +/// `T` must be an unsigned integer type. /// /// The stabilized version of this intrinsic is available on the /// [`atomic`] unsigned integer types via the `fetch_max` method by passing /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_umax_relaxed(_dst: *mut T, _src: T) -> T { - unreachable!() -} +pub unsafe fn atomic_umax_relaxed(dst: *mut T, src: T) -> T; /// An atomic fence. /// @@ -1215,44 +1055,32 @@ pub unsafe fn atomic_umax_relaxed(_dst: *mut T, _src: T) -> T { /// [`atomic::fence`] by passing [`Ordering::SeqCst`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_fence_seqcst() { - unreachable!() -} +pub unsafe fn atomic_fence_seqcst(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::Acquire`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_fence_acquire() { - unreachable!() -} +pub unsafe fn atomic_fence_acquire(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::Release`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_fence_release() { - unreachable!() -} +pub unsafe fn atomic_fence_release(); /// An atomic fence. /// /// The stabilized version of this intrinsic is available in /// [`atomic::fence`] by passing [`Ordering::AcqRel`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_fence_acqrel() { - unreachable!() -} +pub unsafe fn atomic_fence_acqrel(); /// A compiler-only memory barrier. /// @@ -1265,11 +1093,8 @@ pub unsafe fn atomic_fence_acqrel() { /// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_seqcst() { - unreachable!() -} +pub unsafe fn atomic_singlethreadfence_seqcst(); /// A compiler-only memory barrier. /// /// Memory accesses will never be reordered across this barrier by the @@ -1281,11 +1106,8 @@ pub unsafe fn atomic_singlethreadfence_seqcst() { /// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_acquire() { - unreachable!() -} +pub unsafe fn atomic_singlethreadfence_acquire(); /// A compiler-only memory barrier. /// /// Memory accesses will never be reordered across this barrier by the @@ -1297,11 +1119,8 @@ pub unsafe fn atomic_singlethreadfence_acquire() { /// [`atomic::compiler_fence`] by passing [`Ordering::Release`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_release() { - unreachable!() -} +pub unsafe fn atomic_singlethreadfence_release(); /// A compiler-only memory barrier. /// /// Memory accesses will never be reordered across this barrier by the @@ -1313,11 +1132,8 @@ pub unsafe fn atomic_singlethreadfence_release() { /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`] /// as the `order`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn atomic_singlethreadfence_acqrel() { - unreachable!() -} +pub unsafe fn atomic_singlethreadfence_acqrel(); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. @@ -1329,11 +1145,8 @@ pub unsafe fn atomic_singlethreadfence_acqrel() { /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn prefetch_read_data(_data: *const T, _locality: i32) { - unreachable!() -} +pub unsafe fn prefetch_read_data(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance @@ -1344,11 +1157,8 @@ pub unsafe fn prefetch_read_data(_data: *const T, _locality: i32) { /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn prefetch_write_data(_data: *const T, _locality: i32) { - unreachable!() -} +pub unsafe fn prefetch_write_data(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance @@ -1359,11 +1169,8 @@ pub unsafe fn prefetch_write_data(_data: *const T, _locality: i32) { /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn prefetch_read_instruction(_data: *const T, _locality: i32) { - unreachable!() -} +pub unsafe fn prefetch_read_instruction(data: *const T, locality: i32); /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction /// if supported; otherwise, it is a no-op. /// Prefetches have no effect on the behavior of the program but can change its performance @@ -1374,21 +1181,15 @@ pub unsafe fn prefetch_read_instruction(_data: *const T, _locality: i32) { /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn prefetch_write_instruction(_data: *const T, _locality: i32) { - unreachable!() -} +pub unsafe fn prefetch_write_instruction(data: *const T, locality: i32); /// Executes a breakpoint trap, for inspection by a debugger. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub fn breakpoint() { - unreachable!() -} +pub fn breakpoint(); /// Magic intrinsic that derives its meaning from attributes /// attached to the function. @@ -1401,10 +1202,7 @@ pub fn breakpoint() { /// This intrinsic should not be used outside of the compiler. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn rustc_peek(_: T) -> T { - unreachable!() -} +pub fn rustc_peek(_: T) -> T; /// Aborts the execution of the process. /// @@ -1423,10 +1221,7 @@ pub fn rustc_peek(_: T) -> T { /// `SIGBUS`. The precise behavior is not guaranteed and not stable. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn abort() -> ! { - unreachable!() -} +pub fn abort() -> !; /// Informs the optimizer that this point in the code is not reachable, /// enabling further optimizations. @@ -1439,10 +1234,7 @@ pub fn abort() -> ! { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unreachable() -> ! { - unreachable!() -} +pub const unsafe fn unreachable() -> !; /// Informs the optimizer that a condition is always true. /// If the condition is false, the behavior is undefined. @@ -1554,10 +1346,7 @@ pub fn select_unpredictable(b: bool, true_val: T, false_val: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn assert_inhabited() { - unreachable!() -} +pub const fn assert_inhabited(); /// A guard for unsafe functions that cannot ever be executed if `T` does not permit /// zero-initialization: This will statically either panic, or do nothing. @@ -1566,10 +1355,7 @@ pub const fn assert_inhabited() { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn assert_zero_valid() { - unreachable!() -} +pub const fn assert_zero_valid(); /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing. /// @@ -1577,10 +1363,7 @@ pub const fn assert_zero_valid() { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn assert_mem_uninitialized_valid() { - unreachable!() -} +pub const fn assert_mem_uninitialized_valid(); /// Gets a reference to a static `Location` indicating where it was called. /// @@ -1593,10 +1376,7 @@ pub const fn assert_mem_uninitialized_valid() { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn caller_location() -> &'static crate::panic::Location<'static> { - unreachable!() -} +pub const fn caller_location() -> &'static crate::panic::Location<'static>; /// Moves a value out of scope without running drop glue. /// @@ -1610,10 +1390,7 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn forget(_: T) { - unreachable!() -} +pub const fn forget(_: T); /// Reinterprets the bits of a value of one type as another type. /// @@ -1901,19 +1678,12 @@ pub const fn forget(_: T) { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] -#[cfg_attr( - not(bootstrap), - rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" -)] +#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")] #[rustc_diagnostic_item = "transmute"] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn transmute(_src: Src) -> Dst { - unreachable!() -} +pub const unsafe fn transmute(src: Src) -> Dst; /// Like [`transmute`], but even less checked at compile-time: rather than /// giving an error for `size_of::() != size_of::()`, it's @@ -1927,10 +1697,7 @@ pub const unsafe fn transmute(_src: Src) -> Dst { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { - unreachable!() -} +pub const unsafe fn transmute_unchecked(src: Src) -> Dst; /// Returns `true` if the actual type given as `T` requires drop /// glue; returns `false` if the actual type provided for `T` @@ -1948,10 +1715,7 @@ pub const unsafe fn transmute_unchecked(_src: Src) -> Dst { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn needs_drop() -> bool { - unreachable!() -} +pub const fn needs_drop() -> bool; /// Calculates the offset from a pointer. /// @@ -1973,10 +1737,7 @@ pub const fn needs_drop() -> bool { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { - unreachable!() -} +pub const unsafe fn offset(dst: Ptr, offset: Delta) -> Ptr; /// Calculates the offset from a pointer, potentially wrapping. /// @@ -1995,10 +1756,7 @@ pub const unsafe fn offset(_dst: Ptr, _offset: Delta) -> Ptr { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn arith_offset(_dst: *const T, _offset: isize) -> *const T { - unreachable!() -} +pub const unsafe fn arith_offset(dst: *const T, offset: isize) -> *const T; /// Masks out bits of the pointer according to a mask. /// @@ -2010,25 +1768,23 @@ pub const unsafe fn arith_offset(_dst: *const T, _offset: isize) -> *const T /// Consider using [`pointer::mask`] instead. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn ptr_mask(_ptr: *const T, _mask: usize) -> *const T { - unreachable!() -} +pub fn ptr_mask(ptr: *const T, mask: usize) -> *const T; /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` /// -/// The volatile parameter is set to `true`, so it will not be optimized out -/// unless size is equal to zero. -/// /// This intrinsic does not have a stable counterpart. +/// # Safety +/// +/// The safety requirements are consistent with [`copy_nonoverlapping`] +/// while the read and write behaviors are volatile, +/// which means it will not be optimized out unless `_count` or `size_of::()` is equal to zero. +/// +/// [`copy_nonoverlapping`]: ptr::copy_nonoverlapping #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn volatile_copy_nonoverlapping_memory(_dst: *mut T, _src: *const T, _count: usize) { - unreachable!() -} +pub unsafe fn volatile_copy_nonoverlapping_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with /// a size of `count * size_of::()` and an alignment of /// `min_align_of::()` @@ -2038,518 +1794,371 @@ pub unsafe fn volatile_copy_nonoverlapping_memory(_dst: *mut T, _src: *const /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn volatile_copy_memory(_dst: *mut T, _src: *const T, _count: usize) { - unreachable!() -} +pub unsafe fn volatile_copy_memory(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a /// size of `count * size_of::()` and an alignment of /// `min_align_of::()`. /// -/// The volatile parameter is set to `true`, so it will not be optimized out -/// unless size is equal to zero. -/// /// This intrinsic does not have a stable counterpart. +/// # Safety +/// +/// The safety requirements are consistent with [`write_bytes`] while the write behavior is volatile, +/// which means it will not be optimized out unless `_count` or `size_of::()` is equal to zero. +/// +/// [`write_bytes`]: ptr::write_bytes #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn volatile_set_memory(_dst: *mut T, _val: u8, _count: usize) { - unreachable!() -} +pub unsafe fn volatile_set_memory(dst: *mut T, val: u8, count: usize); /// Performs a volatile load from the `src` pointer. /// /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn volatile_load(_src: *const T) -> T { - unreachable!() -} +pub unsafe fn volatile_load(src: *const T) -> T; /// Performs a volatile store to the `dst` pointer. /// /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn volatile_store(_dst: *mut T, _val: T) { - unreachable!() -} +pub unsafe fn volatile_store(dst: *mut T, val: T); /// Performs a volatile load from the `src` pointer /// The pointer is not required to be aligned. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_load"] -pub unsafe fn unaligned_volatile_load(_src: *const T) -> T { - unreachable!() -} +pub unsafe fn unaligned_volatile_load(src: *const T) -> T; /// Performs a volatile store to the `dst` pointer. /// The pointer is not required to be aligned. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"] -pub unsafe fn unaligned_volatile_store(_dst: *mut T, _val: T) { - unreachable!() -} +pub unsafe fn unaligned_volatile_store(dst: *mut T, val: T); /// Returns the square root of an `f16` /// /// The stabilized version of this intrinsic is /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sqrtf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn sqrtf16(x: f16) -> f16; /// Returns the square root of an `f32` /// /// The stabilized version of this intrinsic is /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sqrtf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn sqrtf32(x: f32) -> f32; /// Returns the square root of an `f64` /// /// The stabilized version of this intrinsic is /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sqrtf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn sqrtf64(x: f64) -> f64; /// Returns the square root of an `f128` /// /// The stabilized version of this intrinsic is /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sqrtf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn sqrtf128(x: f128) -> f128; /// Raises an `f16` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f16::powi`](../../std/primitive.f16.html#method.powi) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powif16(_a: f16, _x: i32) -> f16 { - unreachable!() -} +pub unsafe fn powif16(a: f16, x: i32) -> f16; /// Raises an `f32` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f32::powi`](../../std/primitive.f32.html#method.powi) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powif32(_a: f32, _x: i32) -> f32 { - unreachable!() -} +pub unsafe fn powif32(a: f32, x: i32) -> f32; /// Raises an `f64` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f64::powi`](../../std/primitive.f64.html#method.powi) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powif64(_a: f64, _x: i32) -> f64 { - unreachable!() -} +pub unsafe fn powif64(a: f64, x: i32) -> f64; /// Raises an `f128` to an integer power. /// /// The stabilized version of this intrinsic is /// [`f128::powi`](../../std/primitive.f128.html#method.powi) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powif128(_a: f128, _x: i32) -> f128 { - unreachable!() -} +pub unsafe fn powif128(a: f128, x: i32) -> f128; /// Returns the sine of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::sin`](../../std/primitive.f16.html#method.sin) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sinf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn sinf16(x: f16) -> f16; /// Returns the sine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::sin`](../../std/primitive.f32.html#method.sin) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sinf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn sinf32(x: f32) -> f32; /// Returns the sine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::sin`](../../std/primitive.f64.html#method.sin) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sinf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn sinf64(x: f64) -> f64; /// Returns the sine of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::sin`](../../std/primitive.f128.html#method.sin) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn sinf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn sinf128(x: f128) -> f128; /// Returns the cosine of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::cos`](../../std/primitive.f16.html#method.cos) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn cosf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn cosf16(x: f16) -> f16; /// Returns the cosine of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::cos`](../../std/primitive.f32.html#method.cos) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn cosf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn cosf32(x: f32) -> f32; /// Returns the cosine of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::cos`](../../std/primitive.f64.html#method.cos) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn cosf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn cosf64(x: f64) -> f64; /// Returns the cosine of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::cos`](../../std/primitive.f128.html#method.cos) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn cosf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn cosf128(x: f128) -> f128; /// Raises an `f16` to an `f16` power. /// /// The stabilized version of this intrinsic is /// [`f16::powf`](../../std/primitive.f16.html#method.powf) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powf16(_a: f16, _x: f16) -> f16 { - unreachable!() -} +pub unsafe fn powf16(a: f16, x: f16) -> f16; /// Raises an `f32` to an `f32` power. /// /// The stabilized version of this intrinsic is /// [`f32::powf`](../../std/primitive.f32.html#method.powf) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powf32(_a: f32, _x: f32) -> f32 { - unreachable!() -} +pub unsafe fn powf32(a: f32, x: f32) -> f32; /// Raises an `f64` to an `f64` power. /// /// The stabilized version of this intrinsic is /// [`f64::powf`](../../std/primitive.f64.html#method.powf) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powf64(_a: f64, _x: f64) -> f64 { - unreachable!() -} +pub unsafe fn powf64(a: f64, x: f64) -> f64; /// Raises an `f128` to an `f128` power. /// /// The stabilized version of this intrinsic is /// [`f128::powf`](../../std/primitive.f128.html#method.powf) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn powf128(_a: f128, _x: f128) -> f128 { - unreachable!() -} +pub unsafe fn powf128(a: f128, x: f128) -> f128; /// Returns the exponential of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::exp`](../../std/primitive.f16.html#method.exp) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn expf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn expf16(x: f16) -> f16; /// Returns the exponential of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp`](../../std/primitive.f32.html#method.exp) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn expf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn expf32(x: f32) -> f32; /// Returns the exponential of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp`](../../std/primitive.f64.html#method.exp) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn expf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn expf64(x: f64) -> f64; /// Returns the exponential of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::exp`](../../std/primitive.f128.html#method.exp) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn expf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn expf128(x: f128) -> f128; /// Returns 2 raised to the power of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn exp2f16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn exp2f16(x: f16) -> f16; /// Returns 2 raised to the power of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn exp2f32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn exp2f32(x: f32) -> f32; /// Returns 2 raised to the power of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn exp2f64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn exp2f64(x: f64) -> f64; /// Returns 2 raised to the power of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn exp2f128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn exp2f128(x: f128) -> f128; /// Returns the natural logarithm of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::ln`](../../std/primitive.f16.html#method.ln) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn logf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn logf16(x: f16) -> f16; /// Returns the natural logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::ln`](../../std/primitive.f32.html#method.ln) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn logf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn logf32(x: f32) -> f32; /// Returns the natural logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::ln`](../../std/primitive.f64.html#method.ln) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn logf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn logf64(x: f64) -> f64; /// Returns the natural logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::ln`](../../std/primitive.f128.html#method.ln) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn logf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn logf128(x: f128) -> f128; /// Returns the base 10 logarithm of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::log10`](../../std/primitive.f16.html#method.log10) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log10f16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn log10f16(x: f16) -> f16; /// Returns the base 10 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log10`](../../std/primitive.f32.html#method.log10) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log10f32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn log10f32(x: f32) -> f32; /// Returns the base 10 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log10`](../../std/primitive.f64.html#method.log10) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log10f64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn log10f64(x: f64) -> f64; /// Returns the base 10 logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::log10`](../../std/primitive.f128.html#method.log10) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log10f128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn log10f128(x: f128) -> f128; /// Returns the base 2 logarithm of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::log2`](../../std/primitive.f16.html#method.log2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log2f16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn log2f16(x: f16) -> f16; /// Returns the base 2 logarithm of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::log2`](../../std/primitive.f32.html#method.log2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log2f32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn log2f32(x: f32) -> f32; /// Returns the base 2 logarithm of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::log2`](../../std/primitive.f64.html#method.log2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log2f64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn log2f64(x: f64) -> f64; /// Returns the base 2 logarithm of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::log2`](../../std/primitive.f128.html#method.log2) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn log2f128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn log2f128(x: f128) -> f128; /// Returns `a * b + c` for `f16` values. /// /// The stabilized version of this intrinsic is /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmaf16(_a: f16, _b: f16, _c: f16) -> f16 { - unreachable!() -} +pub unsafe fn fmaf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values. /// /// The stabilized version of this intrinsic is /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmaf32(_a: f32, _b: f32, _c: f32) -> f32 { - unreachable!() -} +pub unsafe fn fmaf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values. /// /// The stabilized version of this intrinsic is /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmaf64(_a: f64, _b: f64, _c: f64) -> f64 { - unreachable!() -} +pub unsafe fn fmaf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values. /// /// The stabilized version of this intrinsic is /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmaf128(_a: f128, _b: f128, _c: f128) -> f128 { - unreachable!() -} +pub unsafe fn fmaf128(a: f128, b: f128, c: f128) -> f128; /// Returns `a * b + c` for `f16` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the @@ -2562,11 +2171,8 @@ pub unsafe fn fmaf128(_a: f128, _b: f128, _c: f128) -> f128 { /// is selected, and that may depend on optimization level and context, for /// example. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmuladdf16(_a: f16, _b: f16, _c: f16) -> f16 { - unreachable!() -} +pub unsafe fn fmuladdf16(a: f16, b: f16, c: f16) -> f16; /// Returns `a * b + c` for `f32` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -2578,11 +2184,8 @@ pub unsafe fn fmuladdf16(_a: f16, _b: f16, _c: f16) -> f16 { /// is selected, and that may depend on optimization level and context, for /// example. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmuladdf32(_a: f32, _b: f32, _c: f32) -> f32 { - unreachable!() -} +pub unsafe fn fmuladdf32(a: f32, b: f32, c: f32) -> f32; /// Returns `a * b + c` for `f64` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -2594,11 +2197,8 @@ pub unsafe fn fmuladdf32(_a: f32, _b: f32, _c: f32) -> f32 { /// is selected, and that may depend on optimization level and context, for /// example. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmuladdf64(_a: f64, _b: f64, _c: f64) -> f64 { - unreachable!() -} +pub unsafe fn fmuladdf64(a: f64, b: f64, c: f64) -> f64; /// Returns `a * b + c` for `f128` values, non-deterministically executing /// either a fused multiply-add or two operations with rounding of the /// intermediate result. @@ -2610,239 +2210,190 @@ pub unsafe fn fmuladdf64(_a: f64, _b: f64, _c: f64) -> f64 { /// is selected, and that may depend on optimization level and context, for /// example. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmuladdf128(_a: f128, _b: f128, _c: f128) -> f128 { - unreachable!() -} +pub unsafe fn fmuladdf128(a: f128, b: f128, c: f128) -> f128; /// Returns the largest integer less than or equal to an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::floor`](../../std/primitive.f16.html#method.floor) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn floorf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn floorf16(x: f16) -> f16; /// Returns the largest integer less than or equal to an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::floor`](../../std/primitive.f32.html#method.floor) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn floorf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn floorf32(x: f32) -> f32; /// Returns the largest integer less than or equal to an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::floor`](../../std/primitive.f64.html#method.floor) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn floorf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn floorf64(x: f64) -> f64; /// Returns the largest integer less than or equal to an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::floor`](../../std/primitive.f128.html#method.floor) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn floorf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn floorf128(x: f128) -> f128; /// Returns the smallest integer greater than or equal to an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn ceilf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn ceilf16(x: f16) -> f16; /// Returns the smallest integer greater than or equal to an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn ceilf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn ceilf32(x: f32) -> f32; /// Returns the smallest integer greater than or equal to an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn ceilf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn ceilf64(x: f64) -> f64; /// Returns the smallest integer greater than or equal to an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn ceilf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn ceilf128(x: f128) -> f128; /// Returns the integer part of an `f16`. /// /// The stabilized version of this intrinsic is /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn truncf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn truncf16(x: f16) -> f16; /// Returns the integer part of an `f32`. /// /// The stabilized version of this intrinsic is /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn truncf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn truncf32(x: f32) -> f32; /// Returns the integer part of an `f64`. /// /// The stabilized version of this intrinsic is /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn truncf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn truncf64(x: f64) -> f64; /// Returns the integer part of an `f128`. /// /// The stabilized version of this intrinsic is /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn truncf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn truncf128(x: f128) -> f128; -/// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// May raise an inexact floating-point exception if the argument is not an integer. -/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions -/// cannot actually be utilized from Rust code. -/// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`. +/// Returns the nearest integer to an `f16`. Rounds half-way cases to the number with an even +/// least significant digit. /// /// The stabilized version of this intrinsic is /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn rintf16(_x: f16) -> f16 { - unreachable!() +#[cfg(not(bootstrap))] +pub fn round_ties_even_f16(x: f16) -> f16; + +/// To be removed on next bootstrap bump. +#[cfg(bootstrap)] +pub fn round_ties_even_f16(x: f16) -> f16 { + #[rustc_intrinsic] + #[rustc_nounwind] + unsafe fn rintf16(x: f16) -> f16; + + // SAFETY: this intrinsic isn't actually unsafe + unsafe { rintf16(x) } } -/// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// May raise an inexact floating-point exception if the argument is not an integer. -/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions -/// cannot actually be utilized from Rust code. -/// In other words, this intrinsic is equivalent in behavior to `nearbyintf32` and `roundevenf32`. + +/// Returns the nearest integer to an `f32`. Rounds half-way cases to the number with an even +/// least significant digit. /// /// The stabilized version of this intrinsic is /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn rintf32(_x: f32) -> f32 { - unreachable!() +#[cfg(not(bootstrap))] +pub fn round_ties_even_f32(x: f32) -> f32; + +/// To be removed on next bootstrap bump. +#[cfg(bootstrap)] +pub fn round_ties_even_f32(x: f32) -> f32 { + #[rustc_intrinsic] + #[rustc_nounwind] + unsafe fn rintf32(x: f32) -> f32; + + // SAFETY: this intrinsic isn't actually unsafe + unsafe { rintf32(x) } } -/// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// May raise an inexact floating-point exception if the argument is not an integer. -/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions -/// cannot actually be utilized from Rust code. -/// In other words, this intrinsic is equivalent in behavior to `nearbyintf64` and `roundevenf64`. + +/// Provided for compatibility with stdarch. DO NOT USE. +#[inline(always)] +pub unsafe fn rintf32(x: f32) -> f32 { + round_ties_even_f32(x) +} + +/// Returns the nearest integer to an `f64`. Rounds half-way cases to the number with an even +/// least significant digit. /// /// The stabilized version of this intrinsic is /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn rintf64(_x: f64) -> f64 { - unreachable!() +#[cfg(not(bootstrap))] +pub fn round_ties_even_f64(x: f64) -> f64; + +/// To be removed on next bootstrap bump. +#[cfg(bootstrap)] +pub fn round_ties_even_f64(x: f64) -> f64 { + #[rustc_intrinsic] + #[rustc_nounwind] + unsafe fn rintf64(x: f64) -> f64; + + // SAFETY: this intrinsic isn't actually unsafe + unsafe { rintf64(x) } } -/// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// May raise an inexact floating-point exception if the argument is not an integer. -/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions -/// cannot actually be utilized from Rust code. -/// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`. + +/// Provided for compatibility with stdarch. DO NOT USE. +#[inline(always)] +pub unsafe fn rintf64(x: f64) -> f64 { + round_ties_even_f64(x) +} + +/// Returns the nearest integer to an `f128`. Rounds half-way cases to the number with an even +/// least significant digit. /// /// The stabilized version of this intrinsic is /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn rintf128(_x: f128) -> f128 { - unreachable!() -} +#[cfg(not(bootstrap))] +pub fn round_ties_even_f128(x: f128) -> f128; -/// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn nearbyintf16(_x: f16) -> f16 { - unreachable!() -} -/// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn nearbyintf32(_x: f32) -> f32 { - unreachable!() -} -/// Returns the nearest integer to an `f64`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn nearbyintf64(_x: f64) -> f64 { - unreachable!() -} -/// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust, -/// so this rounds half-way cases to the number with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn nearbyintf128(_x: f128) -> f128 { - unreachable!() +/// To be removed on next bootstrap bump. +#[cfg(bootstrap)] +pub fn round_ties_even_f128(x: f128) -> f128 { + #[rustc_intrinsic] + #[rustc_nounwind] + unsafe fn rintf128(x: f128) -> f128; + + // SAFETY: this intrinsic isn't actually unsafe + unsafe { rintf128(x) } } /// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero. @@ -2850,198 +2401,112 @@ pub unsafe fn nearbyintf128(_x: f128) -> f128 { /// The stabilized version of this intrinsic is /// [`f16::round`](../../std/primitive.f16.html#method.round) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn roundf16(_x: f16) -> f16 { - unreachable!() -} +pub unsafe fn roundf16(x: f16) -> f16; /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f32::round`](../../std/primitive.f32.html#method.round) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn roundf32(_x: f32) -> f32 { - unreachable!() -} +pub unsafe fn roundf32(x: f32) -> f32; /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f64::round`](../../std/primitive.f64.html#method.round) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn roundf64(_x: f64) -> f64 { - unreachable!() -} +pub unsafe fn roundf64(x: f64) -> f64; /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero. /// /// The stabilized version of this intrinsic is /// [`f128::round`](../../std/primitive.f128.html#method.round) #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn roundf128(_x: f128) -> f128 { - unreachable!() -} - -/// Returns the nearest integer to an `f16`. Rounds half-way cases to the number -/// with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn roundevenf16(_x: f16) -> f16 { - unreachable!() -} -/// Returns the nearest integer to an `f32`. Rounds half-way cases to the number -/// with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn roundevenf32(_x: f32) -> f32 { - unreachable!() -} -/// Returns the nearest integer to an `f64`. Rounds half-way cases to the number -/// with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -#[rustc_nounwind] -pub unsafe fn roundevenf64(_x: f64) -> f64 { - unreachable!() -} -/// Returns the nearest integer to an `f128`. Rounds half-way cases to the number -/// with an even least significant digit. -/// -/// This intrinsic does not have a stable counterpart. -#[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn roundevenf128(_x: f128) -> f128 { - unreachable!() -} +pub unsafe fn roundf128(x: f128) -> f128; /// Float addition that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fadd_fast(_a: T, _b: T) -> T { - unreachable!() -} +pub unsafe fn fadd_fast(a: T, b: T) -> T; /// Float subtraction that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fsub_fast(_a: T, _b: T) -> T { - unreachable!() -} +pub unsafe fn fsub_fast(a: T, b: T) -> T; /// Float multiplication that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fmul_fast(_a: T, _b: T) -> T { - unreachable!() -} +pub unsafe fn fmul_fast(a: T, b: T) -> T; /// Float division that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn fdiv_fast(_a: T, _b: T) -> T { - unreachable!() -} +pub unsafe fn fdiv_fast(a: T, b: T) -> T; /// Float remainder that allows optimizations based on algebraic rules. /// May assume inputs are finite. /// /// This intrinsic does not have a stable counterpart. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn frem_fast(_a: T, _b: T) -> T { - unreachable!() -} +pub unsafe fn frem_fast(a: T, b: T) -> T; /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range /// () /// /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn float_to_int_unchecked(_value: Float) -> Int { - unreachable!() -} +pub unsafe fn float_to_int_unchecked(value: Float) -> Int; /// Float addition that allows optimizations based on algebraic rules. /// /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn fadd_algebraic(_a: T, _b: T) -> T { - unimplemented!() -} +pub fn fadd_algebraic(a: T, b: T) -> T; /// Float subtraction that allows optimizations based on algebraic rules. /// /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn fsub_algebraic(_a: T, _b: T) -> T { - unimplemented!() -} +pub fn fsub_algebraic(a: T, b: T) -> T; /// Float multiplication that allows optimizations based on algebraic rules. /// /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn fmul_algebraic(_a: T, _b: T) -> T { - unimplemented!() -} +pub fn fmul_algebraic(a: T, b: T) -> T; /// Float division that allows optimizations based on algebraic rules. /// /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn fdiv_algebraic(_a: T, _b: T) -> T { - unimplemented!() -} +pub fn fdiv_algebraic(a: T, b: T) -> T; /// Float remainder that allows optimizations based on algebraic rules. /// /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub fn frem_algebraic(_a: T, _b: T) -> T { - unimplemented!() -} +pub fn frem_algebraic(a: T, b: T) -> T; /// Returns the number of bits set in an integer type `T` /// @@ -3056,10 +2521,7 @@ pub fn frem_algebraic(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn ctpop(_x: T) -> u32 { - unimplemented!() -} +pub const fn ctpop(x: T) -> u32; /// Returns the number of leading unset bits (zeroes) in an integer type `T`. /// @@ -3100,10 +2562,7 @@ pub const fn ctpop(_x: T) -> u32 { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn ctlz(_x: T) -> u32 { - unimplemented!() -} +pub const fn ctlz(x: T) -> u32; /// Like `ctlz`, but extra-unsafe as it returns `undef` when /// given an `x` with value `0`. @@ -3125,10 +2584,7 @@ pub const fn ctlz(_x: T) -> u32 { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { - unimplemented!() -} +pub const unsafe fn ctlz_nonzero(x: T) -> u32; /// Returns the number of trailing unset bits (zeroes) in an integer type `T`. /// @@ -3169,10 +2625,7 @@ pub const unsafe fn ctlz_nonzero(_x: T) -> u32 { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn cttz(_x: T) -> u32 { - unimplemented!() -} +pub const fn cttz(x: T) -> u32; /// Like `cttz`, but extra-unsafe as it returns `undef` when /// given an `x` with value `0`. @@ -3194,10 +2647,7 @@ pub const fn cttz(_x: T) -> u32 { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn cttz_nonzero(_x: T) -> u32 { - unimplemented!() -} +pub const unsafe fn cttz_nonzero(x: T) -> u32; /// Reverses the bytes in an integer type `T`. /// @@ -3212,10 +2662,7 @@ pub const unsafe fn cttz_nonzero(_x: T) -> u32 { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn bswap(_x: T) -> T { - unimplemented!() -} +pub const fn bswap(x: T) -> T; /// Reverses the bits in an integer type `T`. /// @@ -3230,10 +2677,7 @@ pub const fn bswap(_x: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn bitreverse(_x: T) -> T { - unimplemented!() -} +pub const fn bitreverse(x: T) -> T; /// Does a three-way comparison between the two integer arguments. /// @@ -3243,10 +2687,7 @@ pub const fn bitreverse(_x: T) -> T { /// /// The stabilized version of this intrinsic is [`Ord::cmp`]. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Ordering { - unimplemented!() -} +pub const fn three_way_compare(lhs: T, rhss: T) -> crate::cmp::Ordering; /// Combine two values which have no bits in common. /// @@ -3260,7 +2701,7 @@ pub const fn three_way_compare(_lhs: T, _rhss: T) -> crate::cmp::Orderi /// Otherwise it's immediate UB. #[rustc_const_unstable(feature = "disjoint_bitor", issue = "135758")] #[rustc_nounwind] -#[cfg_attr(not(bootstrap), rustc_intrinsic)] +#[rustc_intrinsic] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[miri::intrinsic_fallback_is_spec] // the fallbacks all `assume` to tell Miri pub const unsafe fn disjoint_bitor(a: T, b: T) -> T { @@ -3281,10 +2722,7 @@ pub const unsafe fn disjoint_bitor(a: T, b: T #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { - unimplemented!() -} +pub const fn add_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer subtraction /// @@ -3299,10 +2737,7 @@ pub const fn add_with_overflow(_x: T, _y: T) -> (T, bool) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { - unimplemented!() -} +pub const fn sub_with_overflow(x: T, y: T) -> (T, bool); /// Performs checked integer multiplication /// @@ -3317,10 +2752,7 @@ pub const fn sub_with_overflow(_x: T, _y: T) -> (T, bool) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn mul_with_overflow(_x: T, _y: T) -> (T, bool) { - unimplemented!() -} +pub const fn mul_with_overflow(x: T, y: T) -> (T, bool); /// Performs full-width multiplication and addition with a carry: /// `multiplier * multiplicand + addend + carry`. @@ -3356,10 +2788,7 @@ pub const fn carrying_mul_add, /// This intrinsic does not have a stable counterpart. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn exact_div(_x: T, _y: T) -> T { - unimplemented!() -} +pub const unsafe fn exact_div(x: T, y: T) -> T; /// Performs an unchecked division, resulting in undefined behavior /// where `y == 0` or `x == T::MIN && y == -1` @@ -3370,10 +2799,7 @@ pub const unsafe fn exact_div(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { - unimplemented!() -} +pub const unsafe fn unchecked_div(x: T, y: T) -> T; /// Returns the remainder of an unchecked division, resulting in /// undefined behavior when `y == 0` or `x == T::MIN && y == -1` /// @@ -3383,10 +2809,7 @@ pub const unsafe fn unchecked_div(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { - unimplemented!() -} +pub const unsafe fn unchecked_rem(x: T, y: T) -> T; /// Performs an unchecked left shift, resulting in undefined behavior when /// `y < 0` or `y >= N`, where N is the width of T in bits. @@ -3397,10 +2820,7 @@ pub const unsafe fn unchecked_rem(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { - unimplemented!() -} +pub const unsafe fn unchecked_shl(x: T, y: U) -> T; /// Performs an unchecked right shift, resulting in undefined behavior when /// `y < 0` or `y >= N`, where N is the width of T in bits. /// @@ -3410,10 +2830,7 @@ pub const unsafe fn unchecked_shl(_x: T, _y: U) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { - unimplemented!() -} +pub const unsafe fn unchecked_shr(x: T, y: U) -> T; /// Returns the result of an unchecked addition, resulting in /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. @@ -3423,10 +2840,7 @@ pub const unsafe fn unchecked_shr(_x: T, _y: U) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { - unimplemented!() -} +pub const unsafe fn unchecked_add(x: T, y: T) -> T; /// Returns the result of an unchecked subtraction, resulting in /// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. @@ -3436,10 +2850,7 @@ pub const unsafe fn unchecked_add(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { - unimplemented!() -} +pub const unsafe fn unchecked_sub(x: T, y: T) -> T; /// Returns the result of an unchecked multiplication, resulting in /// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. @@ -3449,10 +2860,7 @@ pub const unsafe fn unchecked_sub(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { - unimplemented!() -} +pub const unsafe fn unchecked_mul(x: T, y: T) -> T; /// Performs rotate left. /// @@ -3467,10 +2875,7 @@ pub const unsafe fn unchecked_mul(_x: T, _y: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn rotate_left(_x: T, _shift: u32) -> T { - unimplemented!() -} +pub const fn rotate_left(x: T, shift: u32) -> T; /// Performs rotate right. /// @@ -3485,10 +2890,7 @@ pub const fn rotate_left(_x: T, _shift: u32) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn rotate_right(_x: T, _shift: u32) -> T { - unimplemented!() -} +pub const fn rotate_right(x: T, shift: u32) -> T; /// Returns (a + b) mod 2N, where N is the width of T in bits. /// @@ -3503,10 +2905,7 @@ pub const fn rotate_right(_x: T, _shift: u32) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn wrapping_add(_a: T, _b: T) -> T { - unimplemented!() -} +pub const fn wrapping_add(a: T, b: T) -> T; /// Returns (a - b) mod 2N, where N is the width of T in bits. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -3520,10 +2919,7 @@ pub const fn wrapping_add(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn wrapping_sub(_a: T, _b: T) -> T { - unimplemented!() -} +pub const fn wrapping_sub(a: T, b: T) -> T; /// Returns (a * b) mod 2N, where N is the width of T in bits. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -3537,10 +2933,7 @@ pub const fn wrapping_sub(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn wrapping_mul(_a: T, _b: T) -> T { - unimplemented!() -} +pub const fn wrapping_mul(a: T, b: T) -> T; /// Computes `a + b`, saturating at numeric bounds. /// @@ -3555,10 +2948,7 @@ pub const fn wrapping_mul(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn saturating_add(_a: T, _b: T) -> T { - unimplemented!() -} +pub const fn saturating_add(a: T, b: T) -> T; /// Computes `a - b`, saturating at numeric bounds. /// /// Note that, unlike most intrinsics, this is safe to call; @@ -3572,10 +2962,7 @@ pub const fn saturating_add(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn saturating_sub(_a: T, _b: T) -> T { - unimplemented!() -} +pub const fn saturating_sub(a: T, b: T) -> T; /// This is an implementation detail of [`crate::ptr::read`] and should /// not be used anywhere else. See its comments for why this exists. @@ -3586,10 +2973,7 @@ pub const fn saturating_sub(_a: T, _b: T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn read_via_copy(_ptr: *const T) -> T { - unimplemented!() -} +pub const unsafe fn read_via_copy(ptr: *const T) -> T; /// This is an implementation detail of [`crate::ptr::write`] and should /// not be used anywhere else. See its comments for why this exists. @@ -3600,10 +2984,7 @@ pub const unsafe fn read_via_copy(_ptr: *const T) -> T { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { - unimplemented!() -} +pub const unsafe fn write_via_move(ptr: *mut T, value: T); /// Returns the value of the discriminant for the variant in 'v'; /// if `T` has no discriminant, returns `0`. @@ -3617,10 +2998,7 @@ pub const unsafe fn write_via_move(_ptr: *mut T, _value: T) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn discriminant_value(_v: &T) -> ::Discriminant { - unimplemented!() -} +pub const fn discriminant_value(v: &T) -> ::Discriminant; /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs. @@ -3639,15 +3017,12 @@ pub const fn discriminant_value(_v: &T) -> ::Discrimin /// For more information, see the compiler's source, as well as the documentation for the stable /// version of this intrinsic, `std::panic::catch_unwind`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] pub unsafe fn catch_unwind( _try_fn: fn(*mut u8), _data: *mut u8, _catch_fn: fn(*mut u8, *mut u8), -) -> i32 { - unreachable!() -} +) -> i32; /// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held /// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`. @@ -3656,28 +3031,20 @@ pub unsafe fn catch_unwind( /// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered /// in ways that are not allowed for regular writes). #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn nontemporal_store(_ptr: *mut T, _val: T) { - unreachable!() -} +pub unsafe fn nontemporal_store(ptr: *mut T, val: T); /// See documentation of `<*const T>::offset_from` for details. #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn ptr_offset_from(_ptr: *const T, _base: *const T) -> isize { - unimplemented!() -} +pub const unsafe fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; /// See documentation of `<*const T>::sub_ptr` for details. #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn ptr_offset_from_unsigned(_ptr: *const T, _base: *const T) -> usize { - unimplemented!() -} +#[rustc_intrinsic_const_stable_indirect] +pub const unsafe fn ptr_offset_from_unsigned(ptr: *const T, base: *const T) -> usize; /// See documentation of `<*const T>::guaranteed_eq` for details. /// Returns `2` if the result is unknown. @@ -3717,10 +3084,7 @@ pub const fn ptr_guaranteed_cmp(ptr: *const T, other: *const T) -> u8 { /// which is UB if any of their inputs are `undef`.) #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { - unimplemented!() -} +pub const unsafe fn raw_eq(a: &T, b: &T) -> bool; /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)` /// as unsigned bytes, returning negative if `left` is less, zero if all the @@ -3738,21 +3102,15 @@ pub const unsafe fn raw_eq(_a: &T, _b: &T) -> bool { /// [valid]: crate::ptr#safety #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: usize) -> i32 { - unimplemented!() -} +pub const unsafe fn compare_bytes(left: *const u8, right: *const u8, bytes: usize) -> i32; /// See documentation of [`std::hint::black_box`] for details. /// /// [`std::hint::black_box`]: crate::hint::black_box #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_intrinsic_const_stable_indirect] -pub const fn black_box(_dummy: T) -> T { - unimplemented!() -} +pub const fn black_box(dummy: T) -> T; /// Selects which function to call depending on the context. /// @@ -3808,7 +3166,6 @@ pub const fn black_box(_dummy: T) -> T { /// otherwise, that principle should not be violated. #[rustc_const_unstable(feature = "const_eval_select", issue = "124625")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] pub const fn const_eval_select( _arg: ARG, _called_in_const: F, @@ -3816,10 +3173,7 @@ pub const fn const_eval_select( ) -> RET where G: FnOnce, - F: FnOnce, -{ - unreachable!() -} + F: FnOnce; /// A macro to make it easier to invoke const_eval_select. Use as follows: /// ```rust,ignore (just a macro example) @@ -3994,8 +3348,18 @@ pub const fn is_val_statically_known(_arg: T) -> bool { /// The stabilized form of this intrinsic is [`crate::mem::swap`]. /// /// # Safety +/// Behavior is undefined if any of the following conditions are violated: /// -/// `x` and `y` are readable and writable as `T`, and non-overlapping. +/// * Both `x` and `y` must be [valid] for both reads and writes. +/// +/// * Both `x` and `y` must be properly aligned. +/// +/// * The region of memory beginning at `x` must *not* overlap with the region of memory +/// beginning at `y`. +/// +/// * The memory pointed by `x` and `y` must both contain values of type `T`. +/// +/// [valid]: crate::ptr#safety #[rustc_nounwind] #[inline] #[rustc_intrinsic] @@ -4070,7 +3434,6 @@ pub const unsafe fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) /// of not prematurely commiting at compile-time to whether contract /// checking is turned on, so that we can specify contracts in libstd /// and let an end user opt into turning them on. -#[cfg(not(bootstrap))] #[rustc_const_unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[inline(always)] @@ -4086,7 +3449,6 @@ pub const fn contract_checks() -> bool { /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. -#[cfg(not(bootstrap))] #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[lang = "contract_check_requires"] #[rustc_intrinsic] @@ -4101,7 +3463,6 @@ pub fn contract_check_requires bool>(cond: C) { /// /// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition /// returns false. -#[cfg(not(bootstrap))] #[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)] #[rustc_intrinsic] pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) { @@ -4118,10 +3479,7 @@ pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, con #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub unsafe fn vtable_size(_ptr: *const ()) -> usize { - unreachable!() -} +pub unsafe fn vtable_size(ptr: *const ()) -> usize; /// The intrinsic will return the alignment stored in that vtable. /// @@ -4131,10 +3489,7 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub unsafe fn vtable_align(_ptr: *const ()) -> usize { - unreachable!() -} +pub unsafe fn vtable_align(ptr: *const ()) -> usize; /// The size of a type in bytes. /// @@ -4146,15 +3501,12 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize { /// More specifically, this is the offset in bytes between successive /// items of the same type, including alignment padding. /// -/// The stabilized version of this intrinsic is [`core::mem::size_of`]. +/// The stabilized version of this intrinsic is [`size_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn size_of() -> usize { - unreachable!() -} +pub const fn size_of() -> usize; /// The minimum alignment of a type. /// @@ -4163,15 +3515,12 @@ pub const fn size_of() -> usize { /// Therefore, implementations must not require the user to uphold /// any safety invariants. /// -/// The stabilized version of this intrinsic is [`core::mem::align_of`]. +/// The stabilized version of this intrinsic is [`align_of`]. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn min_align_of() -> usize { - unreachable!() -} +pub const fn min_align_of() -> usize; /// The preferred alignment of a type. /// @@ -4180,10 +3529,7 @@ pub const fn min_align_of() -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn pref_align_of() -> usize { - unreachable!() -} +pub const unsafe fn pref_align_of() -> usize; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. @@ -4197,14 +3543,11 @@ pub const unsafe fn pref_align_of() -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn variant_count() -> usize { - unreachable!() -} +pub const fn variant_count() -> usize; /// The size of the referenced value in bytes. /// -/// The stabilized version of this intrinsic is [`crate::mem::size_of_val`]. +/// The stabilized version of this intrinsic is [`size_of_val`]. /// /// # Safety /// @@ -4212,15 +3555,12 @@ pub const fn variant_count() -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_intrinsic_const_stable_indirect] -pub const unsafe fn size_of_val(_ptr: *const T) -> usize { - unreachable!() -} +pub const unsafe fn size_of_val(ptr: *const T) -> usize; /// The required alignment of the referenced value. /// -/// The stabilized version of this intrinsic is [`core::mem::align_of_val`]. +/// The stabilized version of this intrinsic is [`align_of_val`]. /// /// # Safety /// @@ -4228,11 +3568,8 @@ pub const unsafe fn size_of_val(_ptr: *const T) -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_intrinsic_const_stable_indirect] -pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { - unreachable!() -} +pub const unsafe fn min_align_of_val(ptr: *const T) -> usize; /// Gets a static string slice containing the name of a type. /// @@ -4245,10 +3582,7 @@ pub const unsafe fn min_align_of_val(_ptr: *const T) -> usize { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn type_name() -> &'static str { - unreachable!() -} +pub const fn type_name() -> &'static str; /// Gets an identifier which is globally unique to the specified type. This /// function will return the same value for a type regardless of whichever @@ -4263,10 +3597,7 @@ pub const fn type_name() -> &'static str { #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn type_id() -> u128 { - unreachable!() -} +pub const fn type_id() -> u128; /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`. /// @@ -4277,12 +3608,7 @@ pub const fn type_id() -> u128 { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { - // To implement a fallback we'd have to assume the layout of the pointer, - // but the whole point of this intrinsic is that we shouldn't do that. - unreachable!() -} +pub const fn aggregate_raw_ptr, D, M>(data: D, meta: M) -> P; #[unstable(feature = "core_intrinsics", issue = "none")] pub trait AggregateRawPtr { @@ -4302,12 +3628,7 @@ impl AggregateRawPtr<*mut T> for *mut P { #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { - // To implement a fallback we'd have to assume the layout of the pointer, - // but the whole point of this intrinsic is that we shouldn't do that. - unreachable!() -} +pub const fn ptr_metadata + ?Sized, M>(ptr: *const P) -> M; // Some functions are defined here because they accidentally got made // available in this module on stable. See . @@ -4400,11 +3721,7 @@ pub const fn ptr_metadata + ?Sized, M>(_ptr: *cons /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append #[doc(alias = "memcpy")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] -#[cfg_attr( - not(bootstrap), - rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" -)] +#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4413,10 +3730,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - const unsafe fn copy_nonoverlapping(_src: *const T, _dst: *mut T, _count: usize) { - unreachable!() - } + const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); ub_checks::assert_unsafe_precondition!( check_language_ub, @@ -4508,11 +3822,7 @@ pub const unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: us /// ``` #[doc(alias = "memmove")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] -#[cfg_attr( - not(bootstrap), - rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" -)] +#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4521,10 +3831,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - const unsafe fn copy(_src: *const T, _dst: *mut T, _count: usize) { - unreachable!() - } + const unsafe fn copy(src: *const T, dst: *mut T, count: usize); // SAFETY: the safety contract for `copy` must be upheld by the caller. unsafe { @@ -4595,11 +3902,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// ``` #[doc(alias = "memset")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(bootstrap, rustc_allowed_through_unstable_modules)] -#[cfg_attr( - not(bootstrap), - rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead" -)] +#[rustc_allowed_through_unstable_modules = "import this function via `std::mem` instead"] #[rustc_const_stable(feature = "const_ptr_write", since = "1.83.0")] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces @@ -4608,10 +3911,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { #[rustc_intrinsic_const_stable_indirect] #[rustc_nounwind] #[rustc_intrinsic] - #[rustc_intrinsic_must_be_overridden] - const unsafe fn write_bytes(_dst: *mut T, _val: u8, _count: usize) { - unreachable!() - } + const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize); // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. unsafe { @@ -4639,10 +3939,7 @@ pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { /// [`f16::min`] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf16(_x: f16, _y: f16) -> f16 { - unimplemented!(); -} +pub const fn minnumf16(x: f16, y: f16) -> f16; /// Returns the minimum of two `f32` values. /// @@ -4656,10 +3953,7 @@ pub const fn minnumf16(_x: f16, _y: f16) -> f16 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf32(_x: f32, _y: f32) -> f32 { - unimplemented!(); -} +pub const fn minnumf32(x: f32, y: f32) -> f32; /// Returns the minimum of two `f64` values. /// @@ -4673,10 +3967,7 @@ pub const fn minnumf32(_x: f32, _y: f32) -> f32 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf64(_x: f64, _y: f64) -> f64 { - unimplemented!(); -} +pub const fn minnumf64(x: f64, y: f64) -> f64; /// Returns the minimum of two `f128` values. /// @@ -4689,10 +3980,7 @@ pub const fn minnumf64(_x: f64, _y: f64) -> f64 { /// [`f128::min`] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn minnumf128(_x: f128, _y: f128) -> f128 { - unimplemented!(); -} +pub const fn minnumf128(x: f128, y: f128) -> f128; /// Returns the maximum of two `f16` values. /// @@ -4705,10 +3993,7 @@ pub const fn minnumf128(_x: f128, _y: f128) -> f128 { /// [`f16::max`] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { - unimplemented!(); -} +pub const fn maxnumf16(x: f16, y: f16) -> f16; /// Returns the maximum of two `f32` values. /// @@ -4722,10 +4007,7 @@ pub const fn maxnumf16(_x: f16, _y: f16) -> f16 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { - unimplemented!(); -} +pub const fn maxnumf32(x: f32, y: f32) -> f32; /// Returns the maximum of two `f64` values. /// @@ -4739,10 +4021,7 @@ pub const fn maxnumf32(_x: f32, _y: f32) -> f32 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { - unimplemented!(); -} +pub const fn maxnumf64(x: f64, y: f64) -> f64; /// Returns the maximum of two `f128` values. /// @@ -4755,10 +4034,7 @@ pub const fn maxnumf64(_x: f64, _y: f64) -> f64 { /// [`f128::max`] #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { - unimplemented!(); -} +pub const fn maxnumf128(x: f128, y: f128) -> f128; /// Returns the absolute value of an `f16`. /// @@ -4766,10 +4042,7 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 { /// [`f16::abs`](../../std/primitive.f16.html#method.abs) #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf16(_x: f16) -> f16 { - unimplemented!(); -} +pub const unsafe fn fabsf16(x: f16) -> f16; /// Returns the absolute value of an `f32`. /// @@ -4778,10 +4051,7 @@ pub const unsafe fn fabsf16(_x: f16) -> f16 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf32(_x: f32) -> f32 { - unimplemented!(); -} +pub const unsafe fn fabsf32(x: f32) -> f32; /// Returns the absolute value of an `f64`. /// @@ -4790,10 +4060,7 @@ pub const unsafe fn fabsf32(_x: f32) -> f32 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf64(_x: f64) -> f64 { - unimplemented!(); -} +pub const unsafe fn fabsf64(x: f64) -> f64; /// Returns the absolute value of an `f128`. /// @@ -4801,10 +4068,7 @@ pub const unsafe fn fabsf64(_x: f64) -> f64 { /// [`f128::abs`](../../std/primitive.f128.html#method.abs) #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn fabsf128(_x: f128) -> f128 { - unimplemented!(); -} +pub const unsafe fn fabsf128(x: f128) -> f128; /// Copies the sign from `y` to `x` for `f16` values. /// @@ -4812,10 +4076,7 @@ pub const unsafe fn fabsf128(_x: f128) -> f128 { /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign) #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { - unimplemented!(); -} +pub const unsafe fn copysignf16(x: f16, y: f16) -> f16; /// Copies the sign from `y` to `x` for `f32` values. /// @@ -4824,10 +4085,7 @@ pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { - unimplemented!(); -} +pub const unsafe fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. /// /// The stabilized version of this intrinsic is @@ -4835,10 +4093,7 @@ pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 { #[rustc_nounwind] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { - unimplemented!(); -} +pub const unsafe fn copysignf64(x: f64, y: f64) -> f64; /// Copies the sign from `y` to `x` for `f128` values. /// @@ -4846,10 +4101,7 @@ pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 { /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign) #[rustc_nounwind] #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] -pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 { - unimplemented!(); -} +pub const unsafe fn copysignf128(x: f128, y: f128) -> f128; /// Inform Miri that a given pointer definitely has a certain alignment. #[cfg(miri)] diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index e59d3aff37999..ae6e1a779ed58 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -10,11 +10,8 @@ /// /// `idx` must be in-bounds of the vector. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_insert(_x: T, _idx: u32, _val: U) -> T { - unreachable!() -} +pub const unsafe fn simd_insert(x: T, idx: u32, val: U) -> T; /// Extracts an element from a vector. /// @@ -24,89 +21,68 @@ pub unsafe fn simd_insert(_x: T, _idx: u32, _val: U) -> T { /// /// `idx` must be in-bounds of the vector. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_extract(_x: T, _idx: u32) -> U { - unreachable!() -} +pub const unsafe fn simd_extract(x: T, idx: u32) -> U; /// Adds two simd vectors elementwise. /// -/// `T` must be a vector of integer or floating point primitive types. +/// `T` must be a vector of integers or floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_add(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_add(x: T, y: T) -> T; /// Subtracts `rhs` from `lhs` elementwise. /// -/// `T` must be a vector of integer or floating point primitive types. +/// `T` must be a vector of integers or floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_sub(_lhs: T, _rhs: T) -> T { - unreachable!() -} +pub unsafe fn simd_sub(lhs: T, rhs: T) -> T; /// Multiplies two simd vectors elementwise. /// -/// `T` must be a vector of integer or floating point primitive types. +/// `T` must be a vector of integers or floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_mul(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_mul(x: T, y: T) -> T; /// Divides `lhs` by `rhs` elementwise. /// -/// `T` must be a vector of integer or floating point primitive types. +/// `T` must be a vector of integers or floats. /// /// # Safety /// For integers, `rhs` must not contain any zero elements. /// Additionally for signed integers, `::MIN / -1` is undefined behavior. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_div(_lhs: T, _rhs: T) -> T { - unreachable!() -} +pub unsafe fn simd_div(lhs: T, rhs: T) -> T; /// Returns remainder of two vectors elementwise. /// -/// `T` must be a vector of integer or floating point primitive types. +/// `T` must be a vector of integers or floats. /// /// # Safety /// For integers, `rhs` must not contain any zero elements. /// Additionally for signed integers, `::MIN / -1` is undefined behavior. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_rem(_lhs: T, _rhs: T) -> T { - unreachable!() -} +pub unsafe fn simd_rem(lhs: T, rhs: T) -> T; /// Shifts vector left elementwise, with UB on overflow. /// /// Shifts `lhs` left by `rhs`, shifting in sign bits for signed types. /// -/// `T` must be a vector of integer primitive types. +/// `T` must be a vector of integers. /// /// # Safety /// /// Each element of `rhs` must be less than `::BITS`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_shl(_lhs: T, _rhs: T) -> T { - unreachable!() -} +pub unsafe fn simd_shl(lhs: T, rhs: T) -> T; /// Shifts vector right elementwise, with UB on overflow. /// -/// `T` must be a vector of integer primitive types. +/// `T` must be a vector of integers. /// /// Shifts `lhs` right by `rhs`, shifting in sign bits for signed types. /// @@ -114,46 +90,33 @@ pub unsafe fn simd_shl(_lhs: T, _rhs: T) -> T { /// /// Each element of `rhs` must be less than `::BITS`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_shr(_lhs: T, _rhs: T) -> T { - unreachable!() -} +pub unsafe fn simd_shr(lhs: T, rhs: T) -> T; /// "Ands" vectors elementwise. /// -/// `T` must be a vector of integer primitive types. +/// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_and(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_and(x: T, y: T) -> T; /// "Ors" vectors elementwise. /// -/// `T` must be a vector of integer primitive types. +/// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_or(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_or(x: T, y: T) -> T; /// "Exclusive ors" vectors elementwise. /// -/// `T` must be a vector of integer primitive types. +/// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_xor(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_xor(x: T, y: T) -> T; /// Numerically casts a vector, elementwise. /// -/// `T` and `U` must be vectors of integer or floating point primitive types, and must have the -/// same length. +/// `T` and `U` must be vectors of integers or floats, and must have the same length. /// /// When casting floats to integers, the result is truncated. Out-of-bounds result lead to UB. /// When casting integers to floats, the result is rounded. @@ -169,16 +132,12 @@ pub unsafe fn simd_xor(_x: T, _y: T) -> T { /// * Not be infinite /// * Be representable in the return type, after truncating off its fractional part #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_cast(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_cast(x: T) -> U; /// Numerically casts a vector, elementwise. /// -/// `T` and `U` be a vectors of integer or floating point primitive types, and must have the -/// same length. +/// `T` and `U` be a vectors of integers or floats, and must have the same length. /// /// Like `simd_cast`, but saturates float-to-integer conversions (NaN becomes 0). /// This matches regular `as` and is always safe. @@ -187,33 +146,24 @@ pub unsafe fn simd_cast(_x: T) -> U { /// When casting integers to floats, the result is rounded. /// Otherwise, truncates or extends the value, maintaining the sign for signed integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_as(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_as(x: T) -> U; /// Negates a vector elementwise. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// Rust panics for `-::Min` due to overflow, but it is not UB with this intrinsic. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_neg(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_neg(x: T) -> T; /// Returns absolute value of a vector, elementwise. /// /// `T` must be a vector of floating-point primitive types. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fabs(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_fabs(x: T) -> T; /// Returns the minimum of two vectors, elementwise. /// @@ -221,11 +171,8 @@ pub unsafe fn simd_fabs(_x: T) -> T { /// /// Follows IEEE-754 `minNum` semantics. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fmin(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_fmin(x: T, y: T) -> T; /// Returns the maximum of two vectors, elementwise. /// @@ -233,95 +180,74 @@ pub unsafe fn simd_fmin(_x: T, _y: T) -> T { /// /// Follows IEEE-754 `maxNum` semantics. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fmax(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_fmax(x: T, y: T) -> T; /// Tests elementwise equality of two vectors. /// -/// `T` must be a vector of floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_eq(_x: T, _y: T) -> U { - unreachable!() -} +pub unsafe fn simd_eq(x: T, y: T) -> U; /// Tests elementwise inequality equality of two vectors. /// -/// `T` must be a vector of floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_ne(_x: T, _y: T) -> U { - unreachable!() -} +pub unsafe fn simd_ne(x: T, y: T) -> U; /// Tests if `x` is less than `y`, elementwise. /// -/// `T` must be a vector of floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_lt(_x: T, _y: T) -> U { - unreachable!() -} +pub unsafe fn simd_lt(x: T, y: T) -> U; /// Tests if `x` is less than or equal to `y`, elementwise. /// -/// `T` must be a vector of floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_le(_x: T, _y: T) -> U { - unreachable!() -} +pub unsafe fn simd_le(x: T, y: T) -> U; /// Tests if `x` is greater than `y`, elementwise. /// -/// `T` must be a vector of floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_gt(_x: T, _y: T) -> U { - unreachable!() -} +pub unsafe fn simd_gt(x: T, y: T) -> U; /// Tests if `x` is greater than or equal to `y`, elementwise. /// -/// `T` must be a vector of floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be a vector of integers with the same number of elements and element size as `T`. /// /// Returns `0` for false and `!0` for true. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_ge(_x: T, _y: T) -> U { - unreachable!() -} +pub unsafe fn simd_ge(x: T, y: T) -> U; /// Shuffles two vectors by const indices. /// @@ -336,11 +262,8 @@ pub unsafe fn simd_ge(_x: T, _y: T) -> U { /// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds /// of `xy`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_shuffle(_x: T, _y: T, _idx: U) -> V { - unreachable!() -} +pub unsafe fn simd_shuffle(x: T, y: T, idx: U) -> V; /// Reads a vector of pointers. /// @@ -348,7 +271,7 @@ pub unsafe fn simd_shuffle(_x: T, _y: T, _idx: U) -> V { /// /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. /// -/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// `V` must be a vector of signed integers with the same length as `T` (but any element size). /// /// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer. /// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from @@ -360,11 +283,8 @@ pub unsafe fn simd_shuffle(_x: T, _y: T, _idx: U) -> V { /// /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_gather(_val: T, _ptr: U, _mask: V) -> T { - unreachable!() -} +pub unsafe fn simd_gather(val: T, ptr: U, mask: V) -> T; /// Writes to a vector of pointers. /// @@ -372,7 +292,7 @@ pub unsafe fn simd_gather(_val: T, _ptr: U, _mask: V) -> T { /// /// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`. /// -/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// `V` must be a vector of signed integers with the same length as `T` (but any element size). /// /// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, write the /// corresponding value in `val` to the pointer. @@ -387,11 +307,8 @@ pub unsafe fn simd_gather(_val: T, _ptr: U, _mask: V) -> T { /// /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_scatter(_val: T, _ptr: U, _mask: V) { - unreachable!() -} +pub unsafe fn simd_scatter(val: T, ptr: U, mask: V); /// Reads a vector of pointers. /// @@ -399,7 +316,7 @@ pub unsafe fn simd_scatter(_val: T, _ptr: U, _mask: V) { /// /// `U` must be a pointer to the element type of `T` /// -/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// `V` must be a vector of signed integers with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, read the corresponding /// pointer offset from `ptr`. @@ -413,11 +330,8 @@ pub unsafe fn simd_scatter(_val: T, _ptr: U, _mask: V) { /// /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_masked_load(_mask: V, _ptr: U, _val: T) -> T { - unreachable!() -} +pub unsafe fn simd_masked_load(mask: V, ptr: U, val: T) -> T; /// Writes to a vector of pointers. /// @@ -425,7 +339,7 @@ pub unsafe fn simd_masked_load(_mask: V, _ptr: U, _val: T) -> T { /// /// `U` must be a pointer to the element type of `T` /// -/// `V` must be a vector of integers with the same length as `T` (but any element size). +/// `V` must be a vector of signed integers with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, write the corresponding /// value in `val` to the pointer offset from `ptr`. @@ -438,21 +352,15 @@ pub unsafe fn simd_masked_load(_mask: V, _ptr: U, _val: T) -> T { /// /// `mask` must only contain `0` or `!0` values. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_masked_store(_mask: V, _ptr: U, _val: T) { - unreachable!() -} +pub unsafe fn simd_masked_store(mask: V, ptr: U, val: T); /// Adds two simd vectors elementwise, with saturation. /// /// `T` must be a vector of integer primitive types. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_saturating_add(_x: T, _y: T) -> T { - unreachable!() -} +pub unsafe fn simd_saturating_add(x: T, y: T) -> T; /// Subtracts two simd vectors elementwise, with saturation. /// @@ -460,65 +368,50 @@ pub unsafe fn simd_saturating_add(_x: T, _y: T) -> T { /// /// Subtract `rhs` from `lhs`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_saturating_sub(_lhs: T, _rhs: T) -> T { - unreachable!() -} +pub unsafe fn simd_saturating_sub(lhs: T, rhs: T) -> T; /// Adds elements within a vector from left to right. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. /// /// Starting with the value `y`, add the elements of `x` and accumulate. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_add_ordered(_x: T, _y: U) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_add_ordered(x: T, y: U) -> U; /// Adds elements within a vector in arbitrary order. May also be re-associated with /// unordered additions on the inputs/outputs. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_add_unordered(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_add_unordered(x: T) -> U; /// Multiplies elements within a vector from left to right. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. /// /// Starting with the value `y`, multiply the elements of `x` and accumulate. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_mul_ordered(_x: T, _y: U) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_mul_ordered(x: T, y: U) -> U; /// Multiplies elements within a vector in arbitrary order. May also be re-associated with /// unordered additions on the inputs/outputs. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_mul_unordered(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_mul_unordered(x: T) -> U; /// Checks if all mask values are true. /// @@ -527,11 +420,8 @@ pub unsafe fn simd_reduce_mul_unordered(_x: T) -> U { /// # Safety /// `x` must contain only `0` or `!0`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_all(_x: T) -> bool { - unreachable!() -} +pub unsafe fn simd_reduce_all(x: T) -> bool; /// Checks if any mask value is true. /// @@ -540,75 +430,57 @@ pub unsafe fn simd_reduce_all(_x: T) -> bool { /// # Safety /// `x` must contain only `0` or `!0`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_any(_x: T) -> bool { - unreachable!() -} +pub unsafe fn simd_reduce_any(x: T) -> bool; /// Returns the maximum element of a vector. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. /// /// For floating-point values, uses IEEE-754 `maxNum`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_max(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_max(x: T) -> U; /// Returns the minimum element of a vector. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. /// /// For floating-point values, uses IEEE-754 `minNum`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_min(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_min(x: T) -> U; /// Logical "ands" all elements together. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_and(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_and(x: T) -> U; /// Logical "ors" all elements together. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_or(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_or(x: T) -> U; /// Logical "exclusive ors" all elements together. /// -/// `T` must be a vector of integer or floating-point primitive types. +/// `T` must be a vector of integers or floats. /// /// `U` must be the element type of `T`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_reduce_xor(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_reduce_xor(x: T) -> U; /// Truncates an integer vector to a bitmask. /// @@ -644,17 +516,14 @@ pub unsafe fn simd_reduce_xor(_x: T) -> U { /// # Safety /// `x` must contain only `0` and `!0`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_bitmask(_x: T) -> U { - unreachable!() -} +pub unsafe fn simd_bitmask(x: T) -> U; /// Selects elements from a mask. /// -/// `M` must be an integer vector. +/// `T` must be a vector. /// -/// `T` must be a vector with the same number of elements as `M`. +/// `M` must be a signed integer vector with the same length as `T` (but any element size). /// /// For each element, if the corresponding value in `mask` is `!0`, select the element from /// `if_true`. If the corresponding value in `mask` is `0`, select the element from @@ -663,11 +532,8 @@ pub unsafe fn simd_bitmask(_x: T) -> U { /// # Safety /// `mask` must only contain `0` and `!0`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_select(_mask: M, _if_true: T, _if_false: T) -> T { - unreachable!() -} +pub unsafe fn simd_select(mask: M, if_true: T, if_false: T) -> T; /// Selects elements from a bitmask. /// @@ -684,11 +550,8 @@ pub unsafe fn simd_select(_mask: M, _if_true: T, _if_false: T) -> T { /// # Safety /// Padding bits must be all zero. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_select_bitmask(_m: M, _yes: T, _no: T) -> T { - unreachable!() -} +pub unsafe fn simd_select_bitmask(m: M, yes: T, no: T) -> T; /// Calculates the offset from a pointer vector elementwise, potentially /// wrapping. @@ -699,21 +562,15 @@ pub unsafe fn simd_select_bitmask(_m: M, _yes: T, _no: T) -> T { /// /// Operates as if by `::wrapping_offset`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_arith_offset(_ptr: T, _offset: U) -> T { - unreachable!() -} +pub unsafe fn simd_arith_offset(ptr: T, offset: U) -> T; /// Casts a vector of pointers. /// /// `T` and `U` must be vectors of pointers with the same number of elements. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_cast_ptr(_ptr: T) -> U { - unreachable!() -} +pub unsafe fn simd_cast_ptr(ptr: T) -> U; /// Exposes a vector of pointers as a vector of addresses. /// @@ -721,11 +578,8 @@ pub unsafe fn simd_cast_ptr(_ptr: T) -> U { /// /// `U` must be a vector of `usize` with the same length as `T`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_expose_provenance(_ptr: T) -> U { - unreachable!() -} +pub unsafe fn simd_expose_provenance(ptr: T) -> U; /// Creates a vector of pointers from a vector of addresses. /// @@ -733,123 +587,87 @@ pub unsafe fn simd_expose_provenance(_ptr: T) -> U { /// /// `U` must be a vector of pointers, with the same length as `T`. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_with_exposed_provenance(_addr: T) -> U { - unreachable!() -} +pub unsafe fn simd_with_exposed_provenance(addr: T) -> U; /// Swaps bytes of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_bswap(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_bswap(x: T) -> T; /// Reverses bits of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_bitreverse(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_bitreverse(x: T) -> T; /// Counts the leading zeros of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_ctlz(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_ctlz(x: T) -> T; /// Counts the number of ones in each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_ctpop(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_ctpop(x: T) -> T; /// Counts the trailing zeros of each element. /// /// `T` must be a vector of integers. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_cttz(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_cttz(x: T) -> T; /// Rounds up each element to the next highest integer-valued float. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_ceil(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_ceil(x: T) -> T; /// Rounds down each element to the next lowest integer-valued float. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_floor(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_floor(x: T) -> T; /// Rounds each element to the closest integer-valued float. /// Ties are resolved by rounding away from 0. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_round(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_round(x: T) -> T; /// Returns the integer part of each element as an integer-valued float. /// In other words, non-integer values are truncated towards zero. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_trunc(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_trunc(x: T) -> T; /// Takes the square root of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fsqrt(_x: T) -> T { - unreachable!() -} +pub unsafe fn simd_fsqrt(x: T) -> T; /// Computes `(x*y) + z` for each element, but without any intermediate rounding. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fma(_x: T, _y: T, _z: T) -> T { - unreachable!() -} +pub unsafe fn simd_fma(x: T, y: T, z: T) -> T; /// Computes `(x*y) + z` for each element, non-deterministically executing either /// a fused multiply-add or two operations with rounding of the intermediate result. @@ -863,78 +681,54 @@ pub unsafe fn simd_fma(_x: T, _y: T, _z: T) -> T { /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_relaxed_fma(_x: T, _y: T, _z: T) -> T { - unreachable!() -} +pub unsafe fn simd_relaxed_fma(x: T, y: T, z: T) -> T; // Computes the sine of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fsin(_a: T) -> T { - unreachable!() -} +pub unsafe fn simd_fsin(a: T) -> T; // Computes the cosine of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fcos(_a: T) -> T { - unreachable!() -} +pub unsafe fn simd_fcos(a: T) -> T; // Computes the exponential function of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fexp(_a: T) -> T { - unreachable!() -} +pub unsafe fn simd_fexp(a: T) -> T; // Computes 2 raised to the power of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_fexp2(_a: T) -> T { - unreachable!() -} +pub unsafe fn simd_fexp2(a: T) -> T; // Computes the base 10 logarithm of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_flog10(_a: T) -> T { - unreachable!() -} +pub unsafe fn simd_flog10(a: T) -> T; // Computes the base 2 logarithm of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_flog2(_a: T) -> T { - unreachable!() -} +pub unsafe fn simd_flog2(a: T) -> T; // Computes the natural logarithm of each element. /// /// `T` must be a vector of floats. #[rustc_intrinsic] -#[rustc_intrinsic_must_be_overridden] #[rustc_nounwind] -pub unsafe fn simd_flog(_a: T) -> T { - unreachable!() -} +pub unsafe fn simd_flog(a: T) -> T; diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index ac15e3767fc09..f9c388e8564d3 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -14,7 +14,7 @@ use crate::ops::Try; #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Enumerate")] +#[rustc_diagnostic_item = "Enumerate"] pub struct Enumerate { iter: I, count: usize, diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs index cb13023c85c41..a9c07fee2a91e 100644 --- a/library/core/src/iter/adapters/map_windows.rs +++ b/library/core/src/iter/adapters/map_windows.rs @@ -1,5 +1,5 @@ use crate::iter::FusedIterator; -use crate::mem::{self, MaybeUninit}; +use crate::mem::MaybeUninit; use crate::{fmt, ptr}; /// An iterator over the mapped windows of another iterator. @@ -50,7 +50,7 @@ impl MapWindows { assert!(N != 0, "array in `Iterator::map_windows` must contain more than 0 elements"); // Only ZST arrays' length can be so large. - if mem::size_of::() == 0 { + if size_of::() == 0 { assert!( N.checked_mul(2).is_some(), "array size of `Iterator::map_windows` is too large" diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index 243f938bce2af..c4f5a483e5c2a 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -56,7 +56,7 @@ use crate::num::NonZero; /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "iter_repeat")] +#[rustc_diagnostic_item = "iter_repeat"] pub fn repeat(elt: T) -> Repeat { Repeat { element: elt } } diff --git a/library/core/src/iter/sources/successors.rs b/library/core/src/iter/sources/successors.rs index e14c9235e5562..5466131903f85 100644 --- a/library/core/src/iter/sources/successors.rs +++ b/library/core/src/iter/sources/successors.rs @@ -1,11 +1,16 @@ use crate::fmt; use crate::iter::FusedIterator; -/// Creates a new iterator where each successive item is computed based on the preceding one. +/// Creates an iterator which, starting from an initial item, +/// computes each successive item from the preceding one. /// -/// The iterator starts with the given first item (if any) -/// and calls the given `FnMut(&T) -> Option` closure to compute each item’s successor. -/// The iterator will yield the `T`s returned from the closure. +/// This iterator stores an optional item (`Option`) and a successor closure (`impl FnMut(&T) -> Option`). +/// Its `next` method returns the stored optional item and +/// if it is `Some(val)` calls the stored closure on `&val` to compute and store its successor. +/// The iterator will apply the closure successively to the stored option's value until the option is `None`. +/// This also means that once the stored option is `None` it will remain `None`, +/// as the closure will not be called again, so the created iterator is a [`FusedIterator`]. +/// The iterator's items will be the initial item and all of its successors as calculated by the successor closure. /// /// ``` /// use std::iter::successors; @@ -24,7 +29,8 @@ where Successors { next: first, succ } } -/// A new iterator where each successive item is computed based on the preceding one. +/// An iterator which, starting from an initial item, +/// computes each successive item from the preceding one. /// /// This `struct` is created by the [`iter::successors()`] function. /// See its documentation for more. diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 3b12678572841..7dabaece95561 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -37,7 +37,7 @@ use crate::ops::{ControlFlow, Try}; /// assert_eq!(None, iter.next_back()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "DoubleEndedIterator")] +#[rustc_diagnostic_item = "DoubleEndedIterator"] pub trait DoubleEndedIterator: Iterator { /// Removes and returns an element from the end of the iterator. /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 42886e90f997d..075da02285449 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -862,7 +862,7 @@ pub trait Iterator { /// Note that `iter.filter(f).next()` is equivalent to `iter.find(f)`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "iter_filter")] + #[rustc_diagnostic_item = "iter_filter"] fn filter
() <= MIN_ALIGN); - assert!(mem::align_of::
() <= MIN_ALIGN); + assert!(size_of::
() <= MIN_ALIGN); + assert!(align_of::
() <= MIN_ALIGN); } diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys/fs/common.rs similarity index 100% rename from library/std/src/sys_common/fs.rs rename to library/std/src/sys/fs/common.rs diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/fs/hermit.rs similarity index 98% rename from library/std/src/sys/pal/hermit/fs.rs rename to library/std/src/sys/fs/hermit.rs index d4bf84dc1854c..1191e335daadd 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,18 +1,18 @@ -use super::fd::FileDesc; -use super::hermit_abi::{ - self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, - O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct, -}; use crate::ffi::{CStr, OsStr, OsString, c_char}; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; use crate::os::hermit::ffi::OsStringExt; +use crate::os::hermit::hermit_abi::{ + self, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, O_DIRECTORY, O_EXCL, O_RDONLY, + O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, dirent64, stat as stat_struct, +}; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; +pub use crate::sys::fs::common::{copy, exists}; +use crate::sys::pal::fd::FileDesc; use crate::sys::time::SystemTime; use crate::sys::{cvt, unsupported}; -pub use crate::sys_common::fs::{copy, exists}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{fmt, mem}; @@ -417,12 +417,12 @@ impl File { Ok(()) } - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - Err(Error::from_raw_os_error(22)) + pub fn seek(&self, pos: SeekFrom) -> io::Result { + self.0.seek(pos) } pub fn tell(&self) -> io::Result { - self.seek(SeekFrom::Current(0)) + self.0.tell() } pub fn duplicate(&self) -> io::Result { diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs new file mode 100644 index 0000000000000..c2e19eb393a16 --- /dev/null +++ b/library/std/src/sys/fs/mod.rs @@ -0,0 +1,28 @@ +#![deny(unsafe_op_in_unsafe_fn)] + +pub mod common; + +cfg_if::cfg_if! { + if #[cfg(target_family = "unix")] { + mod unix; + pub use unix::*; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(target_os = "hermit")] { + mod hermit; + pub use hermit::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/fs/solid.rs similarity index 99% rename from library/std/src/sys/pal/solid/fs.rs rename to library/std/src/sys/fs/solid.rs index 4e741943283d0..39de933b7248b 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/fs/solid.rs @@ -1,4 +1,5 @@ -use super::{abi, error}; +#![allow(dead_code)] + use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; @@ -7,9 +8,10 @@ use crate::os::raw::{c_int, c_short}; use crate::os::solid::ffi::OsStrExt; use crate::path::{Path, PathBuf}; use crate::sync::Arc; +pub use crate::sys::fs::common::exists; +use crate::sys::pal::{abi, error}; use crate::sys::time::SystemTime; use crate::sys::unsupported; -pub use crate::sys_common::fs::exists; use crate::sys_common::ignore_notfound; type CIntNotMinusOne = core::num::niche_types::NotAllOnes; diff --git a/library/std/src/sys/pal/unsupported/fs.rs b/library/std/src/sys/fs/uefi.rs similarity index 80% rename from library/std/src/sys/pal/unsupported/fs.rs rename to library/std/src/sys/fs/uefi.rs index 45e93deffa3a4..56aed7dfd8e82 100644 --- a/library/std/src/sys/pal/unsupported/fs.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -1,14 +1,21 @@ use crate::ffi::OsString; use crate::fmt; -use crate::hash::{Hash, Hasher}; +use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; use crate::sys::time::SystemTime; use crate::sys::unsupported; +#[expect(dead_code)] +const FILE_PERMISSIONS_MASK: u64 = r_efi::protocols::file::READ_ONLY; + pub struct File(!); -pub struct FileAttr(!); +#[derive(Clone)] +pub struct FileAttr { + attr: u64, + size: u64, +} pub struct ReadDir(!); @@ -20,42 +27,40 @@ pub struct OpenOptions {} #[derive(Copy, Clone, Debug, Default)] pub struct FileTimes {} -pub struct FilePermissions(!); +#[derive(Clone, PartialEq, Eq, Debug)] +// Bool indicates if file is readonly +pub struct FilePermissions(bool); -pub struct FileType(!); +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +// Bool indicates if directory +pub struct FileType(bool); #[derive(Debug)] pub struct DirBuilder {} impl FileAttr { pub fn size(&self) -> u64 { - self.0 + self.size } pub fn perm(&self) -> FilePermissions { - self.0 + FilePermissions::from_attr(self.attr) } pub fn file_type(&self) -> FileType { - self.0 + FileType::from_attr(self.attr) } pub fn modified(&self) -> io::Result { - self.0 + unsupported() } pub fn accessed(&self) -> io::Result { - self.0 + unsupported() } pub fn created(&self) -> io::Result { - self.0 - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - self.0 + unsupported() } } @@ -64,28 +69,17 @@ impl FilePermissions { self.0 } - pub fn set_readonly(&mut self, _readonly: bool) { - self.0 + pub fn set_readonly(&mut self, readonly: bool) { + self.0 = readonly } -} -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - self.0 + const fn from_attr(attr: u64) -> Self { + Self(attr & r_efi::protocols::file::READ_ONLY != 0) } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - self.0 - } -} -impl Eq for FilePermissions {} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + #[expect(dead_code)] + const fn to_attr(&self) -> u64 { + if self.0 { r_efi::protocols::file::READ_ONLY } else { 0 } } } @@ -100,39 +94,16 @@ impl FileType { } pub fn is_file(&self) -> bool { - self.0 + !self.is_dir() } + // Symlinks are not supported in UEFI pub fn is_symlink(&self) -> bool { - self.0 - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - self.0 + false } -} - -impl Copy for FileType {} -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - self.0 - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - self.0 - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + const fn from_attr(attr: u64) -> Self { + Self(attr & r_efi::protocols::file::DIRECTORY != 0) } } @@ -303,8 +274,8 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { unsupported() } -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + unsupported() } pub fn rmdir(_p: &Path) -> io::Result<()> { diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/fs/unix.rs similarity index 98% rename from library/std/src/sys/pal/unix/fs.rs rename to library/std/src/sys/fs/unix.rs index 3df460e38b72e..d944bc9c9a2a0 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/fs/unix.rs @@ -1,3 +1,5 @@ +#![allow(nonstandard_style)] +#![allow(unsafe_op_in_unsafe_fn)] // miri has some special hacks here that make things unused. #![cfg_attr(miri, allow(unused))] @@ -79,13 +81,13 @@ use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::fd::FileDesc; +pub use crate::sys::fs::common::exists; use crate::sys::time::SystemTime; #[cfg(all(target_os = "linux", target_env = "gnu"))] use crate::sys::weak::syscall; #[cfg(target_os = "android")] use crate::sys::weak::weak; use crate::sys::{cvt, cvt_r}; -pub use crate::sys_common::fs::exists; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{mem, ptr}; @@ -699,6 +701,8 @@ impl Iterator for ReadDir { target_os = "hurd", ))] fn next(&mut self) -> Option> { + use crate::sys::os::{errno, set_errno}; + if self.end_of_stream { return None; } @@ -710,7 +714,7 @@ impl Iterator for ReadDir { // with unlimited or variable NAME_MAX. Many modern platforms guarantee // thread safety for readdir() as long an individual DIR* is not accessed // concurrently, which is sufficient for Rust. - super::os::set_errno(0); + set_errno(0); let entry_ptr: *const dirent64 = readdir64(self.inner.dirp.0); if entry_ptr.is_null() { // We either encountered an error, or reached the end. Either way, @@ -719,7 +723,7 @@ impl Iterator for ReadDir { // To distinguish between errors and end-of-directory, we had to clear // errno beforehand to check for an error now. - return match super::os::errno() { + return match errno() { 0 => None, e => Some(Err(Error::from_raw_os_error(e))), }; @@ -1450,6 +1454,20 @@ impl File { Ok(()) } + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. + #[cfg_attr( + any( + target_os = "android", + all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ) + ), + no_sanitize(cfi) + )] pub fn set_times(&self, times: FileTimes) -> io::Result<()> { #[cfg(not(any( target_os = "redox", @@ -1505,7 +1523,7 @@ impl File { self.as_raw_fd(), (&raw const attrlist).cast::().cast_mut(), buf.as_ptr().cast::().cast_mut(), - num_times * mem::size_of::(), + num_times * size_of::(), 0 ) })?; Ok(()) @@ -1660,7 +1678,7 @@ impl fmt::Debug for File { fn get_path(fd: c_int) -> Option { let info = Box::::new_zeroed(); let mut info = unsafe { info.assume_init() }; - info.kf_structsize = mem::size_of::() as libc::c_int; + info.kf_structsize = size_of::() as libc::c_int; let n = unsafe { libc::fcntl(fd, libc::F_KINFO, &mut *info) }; if n == -1 { return None; @@ -1932,7 +1950,7 @@ pub fn canonicalize(p: &Path) -> io::Result { fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> { use crate::fs::File; - use crate::sys_common::fs::NOT_FILE_ERROR; + use crate::sys::fs::common::NOT_FILE_ERROR; let reader = File::open(from)?; let metadata = reader.metadata()?; @@ -2151,7 +2169,7 @@ pub use remove_dir_impl::remove_dir_all; miri ))] mod remove_dir_impl { - pub use crate::sys_common::fs::remove_dir_all; + pub use crate::sys::fs::common::remove_dir_all; } // Modern implementation using openat(), unlinkat() and fdopendir() diff --git a/library/std/src/sys/pal/unix/fs/tests.rs b/library/std/src/sys/fs/unix/tests.rs similarity index 98% rename from library/std/src/sys/pal/unix/fs/tests.rs rename to library/std/src/sys/fs/unix/tests.rs index 71be3472148b0..8875a318db7d2 100644 --- a/library/std/src/sys/pal/unix/fs/tests.rs +++ b/library/std/src/sys/fs/unix/tests.rs @@ -1,4 +1,4 @@ -use crate::sys::pal::unix::fs::FilePermissions; +use crate::sys::fs::FilePermissions; #[test] fn test_debug_permissions() { diff --git a/library/std/src/sys/pal/uefi/fs.rs b/library/std/src/sys/fs/unsupported.rs similarity index 100% rename from library/std/src/sys/pal/uefi/fs.rs rename to library/std/src/sys/fs/unsupported.rs diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/fs/wasi.rs similarity index 99% rename from library/std/src/sys/pal/wasi/fs.rs rename to library/std/src/sys/fs/wasi.rs index 39978346d7382..773040571bc97 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -1,6 +1,3 @@ -#![forbid(unsafe_op_in_unsafe_fn)] - -use super::fd::WasiFd; use crate::ffi::{CStr, OsStr, OsString}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, ManuallyDrop}; @@ -10,9 +7,10 @@ use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; +use crate::sys::fd::WasiFd; +pub use crate::sys::fs::common::exists; use crate::sys::time::SystemTime; use crate::sys::unsupported; -pub use crate::sys_common::fs::exists; use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound}; use crate::{fmt, iter, ptr}; @@ -209,7 +207,7 @@ impl Iterator for ReadDir { } ReadDirState::ProcessEntry { buf, next_read_offset, offset } => { let contents = &buf[*offset..]; - const DIRENT_SIZE: usize = crate::mem::size_of::(); + const DIRENT_SIZE: usize = size_of::(); if contents.len() >= DIRENT_SIZE { let (dirent, data) = contents.split_at(DIRENT_SIZE); let dirent = diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/fs/windows.rs similarity index 87% rename from library/std/src/sys/pal/windows/fs.rs rename to library/std/src/sys/fs/windows.rs index 0ddce30cf8e44..362e64abf1ac3 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/fs/windows.rs @@ -1,15 +1,17 @@ -use super::api::{self, WinError}; -use super::{IoResult, to_u16s}; -use crate::alloc::{alloc, handle_alloc_error}; +#![allow(nonstandard_style)] + +use crate::alloc::{Layout, alloc, dealloc}; use crate::borrow::Cow; use crate::ffi::{OsStr, OsString, c_void}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem::{self, MaybeUninit}; +use crate::mem::{self, MaybeUninit, offset_of}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; use crate::os::windows::prelude::*; use crate::path::{Path, PathBuf}; use crate::sync::Arc; use crate::sys::handle::Handle; +use crate::sys::pal::api::{self, WinError, set_file_information_by_handle}; +use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul}; use crate::sys::path::maybe_verbatim; use crate::sys::time::SystemTime; use crate::sys::{Align8, c, cvt}; @@ -167,7 +169,7 @@ impl DirEntry { } pub fn file_name(&self) -> OsString { - let filename = super::truncate_utf16_at_nul(&self.data.cFileName); + let filename = truncate_utf16_at_nul(&self.data.cFileName); OsString::from_wide(filename) } @@ -319,31 +321,17 @@ impl File { && creation == c::OPEN_ALWAYS && api::get_last_error() == WinError::ALREADY_EXISTS { - unsafe { - // This first tries `FileAllocationInfo` but falls back to - // `FileEndOfFileInfo` in order to support WINE. - // If WINE gains support for FileAllocationInfo, we should - // remove the fallback. - let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; - let result = c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileAllocationInfo, - (&raw const alloc).cast::(), - mem::size_of::() as u32, - ); - if result == 0 { + // This first tries `FileAllocationInfo` but falls back to + // `FileEndOfFileInfo` in order to support WINE. + // If WINE gains support for FileAllocationInfo, we should + // remove the fallback. + let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 }; + set_file_information_by_handle(handle.as_raw_handle(), &alloc) + .or_else(|_| { let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; - let result = c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileEndOfFileInfo, - (&raw const eof).cast::(), - mem::size_of::() as u32, - ); - if result == 0 { - return Err(io::Error::last_os_error()); - } - } - } + set_file_information_by_handle(handle.as_raw_handle(), &eof) + }) + .io_result()?; } Ok(File { handle: Handle::from_inner(handle) }) } else { @@ -491,7 +479,7 @@ impl File { self.handle.as_raw_handle(), c::FileAttributeTagInfo, (&raw mut attr_tag).cast(), - mem::size_of::().try_into().unwrap(), + size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { reparse_tag = attr_tag.ReparseTag; @@ -518,7 +506,7 @@ impl File { pub fn file_attr(&self) -> io::Result { unsafe { let mut info: c::FILE_BASIC_INFO = mem::zeroed(); - let size = mem::size_of_val(&info); + let size = size_of_val(&info); cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, @@ -550,7 +538,7 @@ impl File { file_index: None, }; let mut info: c::FILE_STANDARD_INFO = mem::zeroed(); - let size = mem::size_of_val(&info); + let size = size_of_val(&info); cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileStandardInfo, @@ -565,7 +553,7 @@ impl File { self.handle.as_raw_handle(), c::FileAttributeTagInfo, (&raw mut attr_tag).cast(), - mem::size_of::().try_into().unwrap(), + size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { attr.reparse_tag = attr_tag.ReparseTag; @@ -663,7 +651,7 @@ impl File { ptr::null_mut(), ) })?; - const _: () = assert!(core::mem::align_of::() <= 8); + const _: () = assert!(align_of::() <= 8); Ok((bytes, space.0.as_mut_ptr().cast::())) } } @@ -709,7 +697,7 @@ impl File { // Turn `\??\` into `\\?\` (a verbatim path). subst[1] = b'\\' as u16; // Attempt to convert to a more user-friendly path. - let user = super::args::from_wide_to_user_path( + let user = crate::sys::args::from_wide_to_user_path( subst.iter().copied().chain([0]).collect(), )?; Ok(PathBuf::from(OsString::from_wide(user.strip_suffix(&[0]).unwrap_or(&user)))) @@ -738,7 +726,7 @@ impl File { { return Err(io::const_error!( io::ErrorKind::InvalidInput, - "Cannot set file timestamp to 0", + "cannot set file timestamp to 0", )); } let is_max = |t: c::FILETIME| t.dwLowDateTime == u32::MAX && t.dwHighDateTime == u32::MAX; @@ -748,7 +736,7 @@ impl File { { return Err(io::const_error!( io::ErrorKind::InvalidInput, - "Cannot set file timestamp to 0xFFFF_FFFF_FFFF_FFFF", + "cannot set file timestamp to 0xFFFF_FFFF_FFFF_FFFF", )); } cvt(unsafe { @@ -767,7 +755,7 @@ impl File { fn basic_info(&self) -> io::Result { unsafe { let mut info: c::FILE_BASIC_INFO = mem::zeroed(); - let size = mem::size_of_val(&info); + let size = size_of_val(&info); cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, @@ -900,7 +888,6 @@ impl<'a> DirBuffIter<'a> { impl<'a> Iterator for DirBuffIter<'a> { type Item = (Cow<'a, [u16]>, bool); fn next(&mut self) -> Option { - use crate::mem::size_of; let buffer = &self.buffer?[self.cursor..]; // Get the name and next entry from the buffer. @@ -1256,141 +1243,72 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> { let old = maybe_verbatim(old)?; let new = maybe_verbatim(new)?; - let new_len_without_nul_in_bytes = (new.len() - 1).try_into().unwrap(); - - // The last field of FILE_RENAME_INFO, the file name, is unsized, - // and FILE_RENAME_INFO has two padding bytes. - // Therefore we need to make sure to not allocate less than - // size_of::() bytes, which would be the case with - // 0 or 1 character paths + a null byte. - let struct_size = mem::size_of::() - .max(mem::offset_of!(c::FILE_RENAME_INFO, FileName) + new.len() * mem::size_of::()); - - let struct_size: u32 = struct_size.try_into().unwrap(); - - let create_file = |extra_access, extra_flags| { - let handle = unsafe { - HandleOrInvalid::from_raw_handle(c::CreateFileW( - old.as_ptr(), - c::SYNCHRONIZE | c::DELETE | extra_access, - c::FILE_SHARE_READ | c::FILE_SHARE_WRITE | c::FILE_SHARE_DELETE, - ptr::null(), - c::OPEN_EXISTING, - c::FILE_ATTRIBUTE_NORMAL | c::FILE_FLAG_BACKUP_SEMANTICS | extra_flags, - ptr::null_mut(), - )) - }; - - OwnedHandle::try_from(handle).map_err(|_| io::Error::last_os_error()) - }; - - // The following code replicates `MoveFileEx`'s behavior as reverse-engineered from its disassembly. - // If `old` refers to a mount point, we move it instead of the target. - let handle = match create_file(c::FILE_READ_ATTRIBUTES, c::FILE_FLAG_OPEN_REPARSE_POINT) { - Ok(handle) => { - let mut file_attribute_tag_info: MaybeUninit = - MaybeUninit::uninit(); - - let result = unsafe { - cvt(c::GetFileInformationByHandleEx( - handle.as_raw_handle(), - c::FileAttributeTagInfo, - file_attribute_tag_info.as_mut_ptr().cast(), - mem::size_of::().try_into().unwrap(), - )) + if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 { + let err = api::get_last_error(); + // if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move + // the file while ignoring the readonly attribute. + // This is accomplished by calling `SetFileInformationByHandle` with `FileRenameInfoEx`. + if err == WinError::ACCESS_DENIED { + let mut opts = OpenOptions::new(); + opts.access_mode(c::DELETE); + opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS); + let Ok(f) = File::open_native(&old, &opts) else { return Err(err).io_result() }; + + // Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation` + // This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size. + let Ok(new_len_without_nul_in_bytes): Result = ((new.len() - 1) * 2).try_into() + else { + return Err(err).io_result(); }; - - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) - || err.raw_os_error() == Some(c::ERROR_INVALID_FUNCTION as _) - { - // `GetFileInformationByHandleEx` documents that not all underlying drivers support all file information classes. - // Since we know we passed the correct arguments, this means the underlying driver didn't understand our request; - // `MoveFileEx` proceeds by reopening the file without inhibiting reparse point behavior. - None - } else { - Some(Err(err)) + let offset: u32 = offset_of!(c::FILE_RENAME_INFO, FileName).try_into().unwrap(); + let struct_size = offset + new_len_without_nul_in_bytes + 2; + let layout = + Layout::from_size_align(struct_size as usize, align_of::()) + .unwrap(); + + // SAFETY: We allocate enough memory for a full FILE_RENAME_INFO struct and a filename. + let file_rename_info; + unsafe { + file_rename_info = alloc(layout).cast::(); + if file_rename_info.is_null() { + return Err(io::ErrorKind::OutOfMemory.into()); } - } else { - // SAFETY: The struct has been initialized by GetFileInformationByHandleEx - let file_attribute_tag_info = unsafe { file_attribute_tag_info.assume_init() }; - let file_type = FileType::new( - file_attribute_tag_info.FileAttributes, - file_attribute_tag_info.ReparseTag, - ); - if file_type.is_symlink() { - // The file is a mount point, junction point or symlink so - // don't reopen the file so that the link gets renamed. - Some(Ok(handle)) - } else { - // Otherwise reopen the file without inhibiting reparse point behavior. - None - } - } - } - // The underlying driver may not support `FILE_FLAG_OPEN_REPARSE_POINT`: Retry without it. - Err(err) if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) => None, - Err(err) => Some(Err(err)), - } - .unwrap_or_else(|| create_file(0, 0))?; - - let layout = core::alloc::Layout::from_size_align( - struct_size as _, - mem::align_of::(), - ) - .unwrap(); + (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { + Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS + | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, + }); - let file_rename_info = unsafe { alloc(layout) } as *mut c::FILE_RENAME_INFO; + (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); + // Don't include the NULL in the size + (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes); - if file_rename_info.is_null() { - handle_alloc_error(layout); - } - - // SAFETY: file_rename_info is a non-null pointer pointing to memory allocated by the global allocator. - let mut file_rename_info = unsafe { Box::from_raw(file_rename_info) }; - - // SAFETY: We have allocated enough memory for a full FILE_RENAME_INFO struct and a filename. - unsafe { - (&raw mut (*file_rename_info).Anonymous).write(c::FILE_RENAME_INFO_0 { - Flags: c::FILE_RENAME_FLAG_REPLACE_IF_EXISTS | c::FILE_RENAME_FLAG_POSIX_SEMANTICS, - }); - - (&raw mut (*file_rename_info).RootDirectory).write(ptr::null_mut()); - (&raw mut (*file_rename_info).FileNameLength).write(new_len_without_nul_in_bytes); - - new.as_ptr() - .copy_to_nonoverlapping((&raw mut (*file_rename_info).FileName) as *mut u16, new.len()); - } - - // We don't use `set_file_information_by_handle` here as `FILE_RENAME_INFO` is used for both `FileRenameInfo` and `FileRenameInfoEx`. - let result = unsafe { - cvt(c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileRenameInfoEx, - (&raw const *file_rename_info).cast::(), - struct_size, - )) - }; - - if let Err(err) = result { - if err.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as _) { - // FileRenameInfoEx and FILE_RENAME_FLAG_POSIX_SEMANTICS were added in Windows 10 1607; retry with FileRenameInfo. - file_rename_info.Anonymous.ReplaceIfExists = true; + new.as_ptr().copy_to_nonoverlapping( + (&raw mut (*file_rename_info).FileName).cast::(), + new.len(), + ); + } - cvt(unsafe { + let result = unsafe { c::SetFileInformationByHandle( - handle.as_raw_handle(), - c::FileRenameInfo, - (&raw const *file_rename_info).cast::(), + f.as_raw_handle(), + c::FileRenameInfoEx, + file_rename_info.cast::(), struct_size, ) - })?; + }; + unsafe { dealloc(file_rename_info.cast::(), layout) }; + if result == 0 { + if api::get_last_error() == WinError::DIR_NOT_EMPTY { + return Err(WinError::DIR_NOT_EMPTY).io_result(); + } else { + return Err(err).io_result(); + } + } } else { - return Err(err); + return Err(err).io_result(); } } - Ok(()) } @@ -1576,7 +1494,7 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { } fn get_path(f: &File) -> io::Result { - super::fill_utf16_buf( + fill_utf16_buf( |buf, sz| unsafe { c::GetFinalPathNameByHandleW(f.handle.as_raw_handle(), buf, sz, c::VOLUME_NAME_DOS) }, diff --git a/library/std/src/sys/pal/windows/fs/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs similarity index 99% rename from library/std/src/sys/pal/windows/fs/remove_dir_all.rs rename to library/std/src/sys/fs/windows/remove_dir_all.rs index 9416049da78f8..f51eced84164f 100644 --- a/library/std/src/sys/pal/windows/fs/remove_dir_all.rs +++ b/library/std/src/sys/fs/windows/remove_dir_all.rs @@ -33,7 +33,7 @@ use core::sync::atomic::{AtomicU32, Ordering}; use super::{AsRawHandle, DirBuff, File, FromRawHandle}; use crate::sys::c; -use crate::sys::pal::windows::api::WinError; +use crate::sys::pal::api::WinError; use crate::thread; // The maximum number of times to spin when waiting for deletes to complete. diff --git a/library/std/src/sys/io/is_terminal/windows.rs b/library/std/src/sys/io/is_terminal/windows.rs index 3ec18fb47b9de..b0c718d71f9f3 100644 --- a/library/std/src/sys/io/is_terminal/windows.rs +++ b/library/std/src/sys/io/is_terminal/windows.rs @@ -1,5 +1,4 @@ use crate::ffi::c_void; -use crate::mem::size_of; use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle}; use crate::sys::c; diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index 1032fcba5e2e1..09677b9d64282 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -12,11 +12,13 @@ pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; pub mod exit_guard; +pub mod fs; pub mod io; pub mod net; pub mod os_str; pub mod path; pub mod random; +pub mod stdio; pub mod sync; pub mod thread_local; diff --git a/library/std/src/sys/net/connection/socket.rs b/library/std/src/sys/net/connection/socket.rs index b4f0a7836803e..e154cf039cad1 100644 --- a/library/std/src/sys/net/connection/socket.rs +++ b/library/std/src/sys/net/connection/socket.rs @@ -154,11 +154,11 @@ fn socket_addr_to_c(addr: &SocketAddr) -> (SocketAddrCRepr, c::socklen_t) { match addr { SocketAddr::V4(a) => { let sockaddr = SocketAddrCRepr { v4: socket_addr_v4_to_c(a) }; - (sockaddr, mem::size_of::() as c::socklen_t) + (sockaddr, size_of::() as c::socklen_t) } SocketAddr::V6(a) => { let sockaddr = SocketAddrCRepr { v6: socket_addr_v6_to_c(a) }; - (sockaddr, mem::size_of::() as c::socklen_t) + (sockaddr, size_of::() as c::socklen_t) } } } @@ -169,13 +169,13 @@ unsafe fn socket_addr_from_c( ) -> io::Result { match (*storage).ss_family as c_int { c::AF_INET => { - assert!(len >= mem::size_of::()); + assert!(len >= size_of::()); Ok(SocketAddr::V4(socket_addr_v4_from_c(unsafe { *(storage as *const _ as *const c::sockaddr_in) }))) } c::AF_INET6 => { - assert!(len >= mem::size_of::()); + assert!(len >= size_of::()); Ok(SocketAddr::V6(socket_addr_v6_from_c(unsafe { *(storage as *const _ as *const c::sockaddr_in6) }))) @@ -200,7 +200,7 @@ pub fn setsockopt( level, option_name, (&raw const option_value) as *const _, - mem::size_of::() as c::socklen_t, + size_of::() as c::socklen_t, ))?; Ok(()) } @@ -209,7 +209,7 @@ pub fn setsockopt( pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> io::Result { unsafe { let mut option_value: T = mem::zeroed(); - let mut option_len = mem::size_of::() as c::socklen_t; + let mut option_len = size_of::() as c::socklen_t; cvt(c::getsockopt( sock.as_raw(), level, @@ -227,7 +227,7 @@ where { unsafe { let mut storage: c::sockaddr_storage = mem::zeroed(); - let mut len = mem::size_of_val(&storage) as c::socklen_t; + let mut len = size_of_val(&storage) as c::socklen_t; cvt(f((&raw mut storage) as *mut _, &mut len))?; socket_addr_from_c(&storage, len as usize) } @@ -557,10 +557,13 @@ impl TcpListener { } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as c::socklen_t; - let sock = self.inner.accept((&raw mut storage) as *mut _, &mut len)?; - let addr = unsafe { socket_addr_from_c(&storage, len as usize)? }; + // The `accept` function will fill in the storage with the address, + // so we don't need to zero it here. + // reference: https://linux.die.net/man/2/accept4 + let mut storage: mem::MaybeUninit = mem::MaybeUninit::uninit(); + let mut len = size_of_val(&storage) as c::socklen_t; + let sock = self.inner.accept(storage.as_mut_ptr() as *mut _, &mut len)?; + let addr = unsafe { socket_addr_from_c(storage.as_ptr(), len as usize)? }; Ok((TcpStream { inner: sock }, addr)) } diff --git a/library/std/src/sys/net/connection/socket/hermit.rs b/library/std/src/sys/net/connection/socket/hermit.rs index e393342ced9da..f49821657d940 100644 --- a/library/std/src/sys/net/connection/socket/hermit.rs +++ b/library/std/src/sys/net/connection/socket/hermit.rs @@ -183,7 +183,7 @@ impl Socket { fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> { let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + let mut addrlen = size_of_val(&storage) as netc::socklen_t; let n = cvt(unsafe { netc::recvfrom( diff --git a/library/std/src/sys/net/connection/socket/solid.rs b/library/std/src/sys/net/connection/socket/solid.rs index 906bef267b6f0..94bb605c1007c 100644 --- a/library/std/src/sys/net/connection/socket/solid.rs +++ b/library/std/src/sys/net/connection/socket/solid.rs @@ -244,7 +244,7 @@ impl Socket { flags: c_int, ) -> io::Result<(usize, SocketAddr)> { let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + let mut addrlen = size_of_val(&storage) as netc::socklen_t; let n = cvt(unsafe { netc::recvfrom( diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs index 34ab26bc117af..e633cf772c528 100644 --- a/library/std/src/sys/net/connection/socket/unix.rs +++ b/library/std/src/sys/net/connection/socket/unix.rs @@ -322,8 +322,11 @@ impl Socket { buf: &mut [u8], flags: c_int, ) -> io::Result<(usize, SocketAddr)> { - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; + // The `recvfrom` function will fill in the storage with the address, + // so we don't need to zero it here. + // reference: https://linux.die.net/man/2/recvfrom + let mut storage: mem::MaybeUninit = mem::MaybeUninit::uninit(); + let mut addrlen = size_of_val(&storage) as libc::socklen_t; let n = cvt(unsafe { libc::recvfrom( @@ -335,7 +338,7 @@ impl Socket { &mut addrlen, ) })?; - Ok((n as usize, unsafe { socket_addr_from_c(&storage, addrlen as usize)? })) + Ok((n as usize, unsafe { socket_addr_from_c(storage.as_ptr(), addrlen as usize)? })) } pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { diff --git a/library/std/src/sys/net/connection/socket/wasip2.rs b/library/std/src/sys/net/connection/socket/wasip2.rs index c5034e73dd704..73c2583187207 100644 --- a/library/std/src/sys/net/connection/socket/wasip2.rs +++ b/library/std/src/sys/net/connection/socket/wasip2.rs @@ -211,7 +211,7 @@ impl Socket { flags: c_int, ) -> io::Result<(usize, SocketAddr)> { let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + let mut addrlen = size_of_val(&storage) as netc::socklen_t; let n = cvt(unsafe { netc::recvfrom( diff --git a/library/std/src/sys/net/connection/socket/windows.rs b/library/std/src/sys/net/connection/socket/windows.rs index 428f142dabe20..ce975bb2289c2 100644 --- a/library/std/src/sys/net/connection/socket/windows.rs +++ b/library/std/src/sys/net/connection/socket/windows.rs @@ -381,7 +381,7 @@ impl Socket { flags: c_int, ) -> io::Result<(usize, SocketAddr)> { let mut storage = unsafe { mem::zeroed::() }; - let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + let mut addrlen = size_of_val(&storage) as netc::socklen_t; let length = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; // On unix when a socket is shut down all further reads return 0, so we @@ -514,13 +514,13 @@ impl Socket { // This is used by sys_common code to abstract over Windows and Unix. pub fn as_raw(&self) -> c::SOCKET { - debug_assert_eq!(mem::size_of::(), mem::size_of::()); - debug_assert_eq!(mem::align_of::(), mem::align_of::()); + debug_assert_eq!(size_of::(), size_of::()); + debug_assert_eq!(align_of::(), align_of::()); self.as_inner().as_raw_socket() as c::SOCKET } pub unsafe fn from_raw(raw: c::SOCKET) -> Self { - debug_assert_eq!(mem::size_of::(), mem::size_of::()); - debug_assert_eq!(mem::align_of::(), mem::align_of::()); + debug_assert_eq!(size_of::(), size_of::()); + debug_assert_eq!(align_of::(), align_of::()); unsafe { Self::from_raw_socket(raw as RawSocket) } } } diff --git a/library/std/src/sys/net/connection/xous/tcplistener.rs b/library/std/src/sys/net/connection/xous/tcplistener.rs index 851d2eb8178d4..7f13ca5592040 100644 --- a/library/std/src/sys/net/connection/xous/tcplistener.rs +++ b/library/std/src/sys/net/connection/xous/tcplistener.rs @@ -11,7 +11,7 @@ macro_rules! unimpl { () => { return Err(io::const_error!( io::ErrorKind::Unsupported, - "This function is not yet implemented", + "this function is not yet implemented", )); }; } @@ -71,7 +71,7 @@ impl TcpListener { 0, 4096, ) else { - return Err(io::const_error!(io::ErrorKind::InvalidInput, "Invalid response")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response")); }; // The first four bytes should be zero upon success, and will be nonzero @@ -80,15 +80,15 @@ impl TcpListener { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_error!(io::ErrorKind::ResourceBusy, "Socket in use")); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, "socket in use")); } else if errcode == NetError::Invalid as u8 { - return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, "Invalid address")); + return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, "invalid address")); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_error!(io::ErrorKind::Other, "Library error")); + return Err(io::const_error!(io::ErrorKind::Other, "library error")); } else { return Err(io::const_error!( io::ErrorKind::Other, - "Unable to connect or internal error", + "unable to connect or internal error", )); } } @@ -131,7 +131,7 @@ impl TcpListener { } else if receive_request.raw[1] == NetError::WouldBlock as u8 { return Err(io::const_error!(io::ErrorKind::WouldBlock, "accept would block")); } else if receive_request.raw[1] == NetError::LibraryError as u8 { - return Err(io::const_error!(io::ErrorKind::Other, "Library error")); + return Err(io::const_error!(io::ErrorKind::Other, "library error")); } else { return Err(io::const_error!(io::ErrorKind::Other, "library error")); } @@ -169,7 +169,7 @@ impl TcpListener { Ok((TcpStream::from_listener(stream_fd, self.local.port(), port, addr), addr)) } } else { - Err(io::const_error!(io::ErrorKind::InvalidInput, "Unable to accept")) + Err(io::const_error!(io::ErrorKind::InvalidInput, "unable to accept")) } } @@ -186,7 +186,7 @@ impl TcpListener { services::net_server(), services::NetBlockingScalar::StdSetTtlTcp(self.fd.load(Ordering::Relaxed), ttl).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|_| ()) } @@ -195,7 +195,7 @@ impl TcpListener { services::net_server(), services::NetBlockingScalar::StdGetTtlTcp(self.fd.load(Ordering::Relaxed)).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/library/std/src/sys/net/connection/xous/tcpstream.rs b/library/std/src/sys/net/connection/xous/tcpstream.rs index 7f7bbfb7fed34..283b1fe9a33b9 100644 --- a/library/std/src/sys/net/connection/xous/tcpstream.rs +++ b/library/std/src/sys/net/connection/xous/tcpstream.rs @@ -12,7 +12,7 @@ macro_rules! unimpl { () => { return Err(io::const_error!( io::ErrorKind::Unsupported, - "This function is not yet implemented", + "this function is not yet implemented", )); }; } @@ -96,7 +96,7 @@ impl TcpStream { 0, 4096, ) else { - return Err(io::const_error!(io::ErrorKind::InvalidInput, "Invalid response")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response")); }; // The first four bytes should be zero upon success, and will be nonzero @@ -106,13 +106,13 @@ impl TcpStream { // errcode is a u8 but stuck in a u16 where the upper byte is invalid. Mask & decode accordingly. let errcode = response[0]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_error!(io::ErrorKind::ResourceBusy, "Socket in use")); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, "socket in use")); } else if errcode == NetError::Unaddressable as u8 { - return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, "Invalid address")); + return Err(io::const_error!(io::ErrorKind::AddrNotAvailable, "invalid address")); } else { return Err(io::const_error!( io::ErrorKind::InvalidInput, - "Unable to connect or internal error", + "unable to connect or internal error", )); } } @@ -198,7 +198,7 @@ impl TcpStream { ) else { return Err(io::const_error!( io::ErrorKind::InvalidInput, - "Library failure: wrong message type or messaging error", + "library failure: wrong message type or messaging error", )); }; @@ -212,11 +212,11 @@ impl TcpStream { if result[0] != 0 { if result[1] == 8 { // timed out - return Err(io::const_error!(io::ErrorKind::TimedOut, "Timeout")); + return Err(io::const_error!(io::ErrorKind::TimedOut, "timeout")); } if result[1] == 9 { // would block - return Err(io::const_error!(io::ErrorKind::WouldBlock, "Would block")); + return Err(io::const_error!(io::ErrorKind::WouldBlock, "would block")); } } Err(io::const_error!(io::ErrorKind::Other, "recv_slice failure")) @@ -258,20 +258,20 @@ impl TcpStream { self.write_timeout.load(Ordering::Relaxed) as usize, buf_len, ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Internal error")))?; + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "internal error")))?; if send_request.raw[0] != 0 { if send_request.raw[4] == 8 { // timed out return Err(io::const_error!( io::ErrorKind::BrokenPipe, - "Timeout or connection closed", + "timeout or connection closed", )); } else if send_request.raw[4] == 9 { // would block - return Err(io::const_error!(io::ErrorKind::WouldBlock, "Would block")); + return Err(io::const_error!(io::ErrorKind::WouldBlock, "would block")); } else { - return Err(io::const_error!(io::ErrorKind::InvalidInput, "Error when sending")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "error when sending")); } } Ok(u32::from_le_bytes([ @@ -304,7 +304,7 @@ impl TcpStream { 0, 0, ) else { - return Err(io::const_error!(io::ErrorKind::InvalidInput, "Internal error")); + return Err(io::const_error!(io::ErrorKind::InvalidInput, "internal error")); }; let mut i = get_addr.raw.iter(); match *i.next().unwrap() { @@ -324,7 +324,7 @@ impl TcpStream { } Ok(SocketAddr::V6(SocketAddrV6::new(new_addr.into(), self.local_port, 0, 0))) } - _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "Internal error")), + _ => Err(io::const_error!(io::ErrorKind::InvalidInput, "tnternal error")), } } @@ -333,7 +333,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdTcpStreamShutdown(self.fd, how).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|_| ()) } @@ -355,7 +355,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdSetNodelay(self.fd, enabled).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|_| ()) } @@ -364,7 +364,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdGetNodelay(self.fd).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|res| res[0] != 0)?) } @@ -376,7 +376,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdSetTtlTcp(self.fd, ttl).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|_| ()) } @@ -385,7 +385,7 @@ impl TcpStream { services::net_server(), services::NetBlockingScalar::StdGetTtlTcp(self.fd).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/library/std/src/sys/net/connection/xous/udp.rs b/library/std/src/sys/net/connection/xous/udp.rs index ab5bd357b6123..c112c04ce94bc 100644 --- a/library/std/src/sys/net/connection/xous/udp.rs +++ b/library/std/src/sys/net/connection/xous/udp.rs @@ -13,7 +13,7 @@ macro_rules! unimpl { () => { return Err(io::const_error!( io::ErrorKind::Unsupported, - "This function is not yet implemented", + "this function is not yet implemented", )); }; } @@ -72,18 +72,18 @@ impl UdpSocket { if response[0] != 0 || valid == 0 { let errcode = response[1]; if errcode == NetError::SocketInUse as u8 { - return Err(io::const_error!(io::ErrorKind::ResourceBusy, "Socket in use")); + return Err(io::const_error!(io::ErrorKind::ResourceBusy, "socket in use")); } else if errcode == NetError::Invalid as u8 { return Err(io::const_error!( io::ErrorKind::InvalidInput, - "Port can't be 0 or invalid address", + "port can't be 0 or invalid address", )); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_error!(io::ErrorKind::Other, "Library error")); + return Err(io::const_error!(io::ErrorKind::Other, "library error")); } else { return Err(io::const_error!( io::ErrorKind::Other, - "Unable to connect or internal error", + "unable to connect or internal error", )); } } @@ -98,13 +98,13 @@ impl UdpSocket { nonblocking: Cell::new(false), }); } - Err(io::const_error!(io::ErrorKind::InvalidInput, "Invalid response")) + Err(io::const_error!(io::ErrorKind::InvalidInput, "invalid response")) } pub fn peer_addr(&self) -> io::Result { match self.remote.get() { Some(dest) => Ok(dest), - None => Err(io::const_error!(io::ErrorKind::NotConnected, "No peer specified")), + None => Err(io::const_error!(io::ErrorKind::NotConnected, "no peer specified")), } } @@ -145,7 +145,7 @@ impl UdpSocket { } else if receive_request.raw[1] == NetError::WouldBlock as u8 { return Err(io::const_error!(io::ErrorKind::WouldBlock, "recv would block")); } else if receive_request.raw[1] == NetError::LibraryError as u8 { - return Err(io::const_error!(io::ErrorKind::Other, "Library error")); + return Err(io::const_error!(io::ErrorKind::Other, "library error")); } else { return Err(io::const_error!(io::ErrorKind::Other, "library error")); } @@ -178,7 +178,7 @@ impl UdpSocket { Ok((rxlen as usize, addr)) } } else { - Err(io::const_error!(io::ErrorKind::InvalidInput, "Unable to recv")) + Err(io::const_error!(io::ErrorKind::InvalidInput, "unable to recv")) } } @@ -244,7 +244,7 @@ impl UdpSocket { // let buf = unsafe { // xous::MemoryRange::new( // &mut tx_req as *mut SendData as usize, - // core::mem::size_of::(), + // size_of::(), // ) // .unwrap() // }; @@ -281,19 +281,19 @@ impl UdpSocket { if errcode == NetError::SocketInUse as u8 { return Err(io::const_error!( io::ErrorKind::ResourceBusy, - "Socket in use", + "socket in use", )); } else if errcode == NetError::Invalid as u8 { return Err(io::const_error!( io::ErrorKind::InvalidInput, - "Socket not valid", + "socket not valid", )); } else if errcode == NetError::LibraryError as u8 { - return Err(io::const_error!(io::ErrorKind::Other, "Library error")); + return Err(io::const_error!(io::ErrorKind::Other, "library error")); } else { return Err(io::const_error!( io::ErrorKind::Other, - "Unable to connect", + "unable to connect", )); } } else { @@ -303,13 +303,13 @@ impl UdpSocket { } Err(crate::os::xous::ffi::Error::ServerQueueFull) => { if now.elapsed() >= write_timeout { - return Err(io::const_error!(io::ErrorKind::WouldBlock, "Write timed out")); + return Err(io::const_error!(io::ErrorKind::WouldBlock, "write timed out")); } else { // question: do we want to do something a bit more gentle than immediately retrying? crate::thread::yield_now(); } } - _ => return Err(io::const_error!(io::ErrorKind::Other, "Library error")), + _ => return Err(io::const_error!(io::ErrorKind::Other, "library error")), } } } @@ -363,7 +363,7 @@ impl UdpSocket { services::net_server(), services::NetBlockingScalar::StdSetTtlUdp(self.fd, ttl).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|_| ()) } @@ -372,7 +372,7 @@ impl UdpSocket { services::net_server(), services::NetBlockingScalar::StdGetTtlUdp(self.fd).into(), ) - .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "Unexpected return value"))) + .or(Err(io::const_error!(io::ErrorKind::InvalidInput, "unexpected return value"))) .map(|res| res[0] as _)?) } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 1d337694944bc..dfff2d3e5d31d 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -139,6 +139,11 @@ impl Buf { self.inner.extend_from_slice(&s.inner) } + #[inline] + pub fn push_str(&mut self, s: &str) { + self.inner.extend_from_slice(s.as_bytes()); + } + #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 19728d33990ac..a32f5d40f6a9c 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -41,13 +41,13 @@ impl AsInner for Buf { impl fmt::Debug for Buf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(self.as_slice(), f) + fmt::Debug::fmt(&self.inner, f) } } impl fmt::Display for Buf { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self.as_slice(), f) + fmt::Display::fmt(&self.inner, f) } } @@ -116,6 +116,11 @@ impl Buf { self.inner.push_wtf8(&s.inner) } + #[inline] + pub fn push_str(&mut self, s: &str) { + self.inner.push_str(s); + } + #[inline] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs index 79fc13bd4a87f..3d6b99cd77b54 100644 --- a/library/std/src/sys/pal/hermit/fd.rs +++ b/library/std/src/sys/pal/hermit/fd.rs @@ -2,8 +2,8 @@ use super::hermit_abi; use crate::cmp; -use crate::io::{self, IoSlice, IoSliceMut, Read}; -use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd, *}; +use crate::io::{self, IoSlice, IoSliceMut, Read, SeekFrom}; +use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; use crate::sys::{cvt, unsupported}; use crate::sys_common::{AsInner, FromInner, IntoInner}; @@ -66,9 +66,26 @@ impl FileDesc { true } + pub fn seek(&self, pos: SeekFrom) -> io::Result { + let (whence, pos) = match pos { + // Casting to `i64` is fine, too large values will end up as + // negative which will cause an error in `lseek`. + SeekFrom::Start(off) => (hermit_abi::SEEK_SET, off as i64), + SeekFrom::End(off) => (hermit_abi::SEEK_END, off), + SeekFrom::Current(off) => (hermit_abi::SEEK_CUR, off), + }; + let n = cvt(unsafe { hermit_abi::lseek(self.as_raw_fd(), pos as isize, whence) })?; + Ok(n as u64) + } + + pub fn tell(&self) -> io::Result { + self.seek(SeekFrom::Current(0)) + } + pub fn duplicate(&self) -> io::Result { self.duplicate_path(&[]) } + pub fn duplicate_path(&self, _path: &[u8]) -> io::Result { unsupported() } diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs index 21cbac643bbec..608245bd430bc 100644 --- a/library/std/src/sys/pal/hermit/mod.rs +++ b/library/std/src/sys/pal/hermit/mod.rs @@ -21,14 +21,12 @@ use crate::os::raw::c_char; pub mod args; pub mod env; pub mod fd; -pub mod fs; pub mod futex; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/hermit/stdio.rs b/library/std/src/sys/pal/hermit/stdio.rs deleted file mode 100644 index 3ea00f5cc5ec9..0000000000000 --- a/library/std/src/sys/pal/hermit/stdio.rs +++ /dev/null @@ -1,97 +0,0 @@ -use super::hermit_abi; -use crate::io; -use crate::io::{IoSlice, IoSliceMut}; -use crate::mem::ManuallyDrop; -use crate::os::hermit::io::FromRawFd; -use crate::sys::fd::FileDesc; - -pub struct Stdin; -pub struct Stdout; -pub struct Stderr; - -impl Stdin { - pub const fn new() -> Stdin { - Stdin - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read(buf) } - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDIN_FILENO)).read_vectored(bufs) - } - } - - #[inline] - fn is_read_vectored(&self) -> bool { - true - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write(buf) } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDOUT_FILENO)).write_vectored(bufs) - } - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write(buf) } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(hermit_abi::STDERR_FILENO)).write_vectored(bufs) - } - } - - #[inline] - fn is_write_vectored(&self) -> bool { - true - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub const STDIN_BUF_SIZE: usize = 128; - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(hermit_abi::EBADF) -} - -pub fn panic_output() -> Option { - Some(Stderr::new()) -} diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs index 4a7afddbec107..bb68a824fc313 100644 --- a/library/std/src/sys/pal/hermit/thread.rs +++ b/library/std/src/sys/pal/hermit/thread.rs @@ -41,7 +41,7 @@ impl Thread { unsafe { drop(Box::from_raw(p)); } - Err(io::const_error!(io::ErrorKind::Uncategorized, "Unable to create thread!")) + Err(io::const_error!(io::ErrorKind::Uncategorized, "unable to create thread!")) } else { Ok(Thread { tid }) }; diff --git a/library/std/src/sys/pal/itron/thread.rs b/library/std/src/sys/pal/itron/thread.rs index 04095e1a7cf99..d1481f827e1e1 100644 --- a/library/std/src/sys/pal/itron/thread.rs +++ b/library/std/src/sys/pal/itron/thread.rs @@ -80,7 +80,7 @@ const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX; // there's no single value for `JOINING` // 64KiB for 32-bit ISAs, 128KiB for 64-bit ISAs. -pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * crate::mem::size_of::(); +pub const DEFAULT_MIN_STACK_SIZE: usize = 0x4000 * size_of::(); impl Thread { /// # Safety diff --git a/library/std/src/sys/pal/mod.rs b/library/std/src/sys/pal/mod.rs index 9be018c8a5312..fbefc62ac88eb 100644 --- a/library/std/src/sys/pal/mod.rs +++ b/library/std/src/sys/pal/mod.rs @@ -37,6 +37,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "hermit")] { mod hermit; pub use self::hermit::*; + } else if #[cfg(target_os = "trusty")] { + mod trusty; + pub use self::trusty::*; } else if #[cfg(all(target_os = "wasi", target_env = "p2"))] { mod wasip2; pub use self::wasip2::*; diff --git a/library/std/src/sys/pal/sgx/abi/mod.rs b/library/std/src/sys/pal/sgx/abi/mod.rs index 90981bd6a6a04..2c805a4d0af01 100644 --- a/library/std/src/sys/pal/sgx/abi/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/mod.rs @@ -6,7 +6,7 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use crate::io::Write; // runtime features -pub(super) mod panic; +pub mod panic; mod reloc; // library features diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs index 5069ab82ccc90..3fe6dee3d6f4f 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/alloc.rs @@ -6,7 +6,7 @@ use super::super::mem::{is_enclave_range, is_user_range}; use crate::arch::asm; use crate::cell::UnsafeCell; use crate::convert::TryInto; -use crate::mem::{self, ManuallyDrop}; +use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::ops::{CoerceUnsized, Deref, DerefMut, Index, IndexMut}; use crate::pin::PinCoerceUnsized; use crate::ptr::{self, NonNull}; @@ -63,7 +63,7 @@ unsafe impl UserSafeSized for [T; 2] {} /// A type that can be represented in memory as one or more `UserSafeSized`s. #[unstable(feature = "sgx_platform", issue = "56975")] pub unsafe trait UserSafe { - /// Equivalent to `mem::align_of::`. + /// Equivalent to `align_of::`. fn align_of() -> usize; /// Constructs a pointer to `Self` given a memory range in user space. @@ -120,7 +120,7 @@ pub unsafe trait UserSafe { let is_aligned = |p: *const u8| -> bool { p.is_aligned_to(Self::align_of()) }; assert!(is_aligned(ptr as *const u8)); - assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); + assert!(is_user_range(ptr as _, size_of_val(unsafe { &*ptr }))); assert!(!ptr.is_null()); } } @@ -128,11 +128,11 @@ pub unsafe trait UserSafe { #[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafe for T { fn align_of() -> usize { - mem::align_of::() + align_of::() } unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self { - assert_eq!(size, mem::size_of::()); + assert_eq!(size, size_of::()); ptr as _ } } @@ -140,7 +140,7 @@ unsafe impl UserSafe for T { #[unstable(feature = "sgx_platform", issue = "56975")] unsafe impl UserSafe for [T] { fn align_of() -> usize { - mem::align_of::() + align_of::() } /// # Safety @@ -155,7 +155,7 @@ unsafe impl UserSafe for [T] { /// /// * the element size is not a factor of the size unsafe fn from_raw_sized_unchecked(ptr: *mut u8, size: usize) -> *mut Self { - let elem_size = mem::size_of::(); + let elem_size = size_of::(); assert_eq!(size % elem_size, 0); let len = size / elem_size; // SAFETY: The caller must uphold the safety contract for `from_raw_sized_unchecked` @@ -209,6 +209,45 @@ impl NewUserRef> for NonNull> { } } +/// A type which can a destination for safely copying from userspace. +/// +/// # Safety +/// +/// Requires that `T` and `Self` have identical layouts. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub unsafe trait UserSafeCopyDestination { + /// Returns a pointer for writing to the value. + fn as_mut_ptr(&mut self) -> *mut T; +} + +#[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl UserSafeCopyDestination for T { + fn as_mut_ptr(&mut self) -> *mut T { + self as _ + } +} + +#[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl UserSafeCopyDestination<[T]> for [T] { + fn as_mut_ptr(&mut self) -> *mut [T] { + self as _ + } +} + +#[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl UserSafeCopyDestination for MaybeUninit { + fn as_mut_ptr(&mut self) -> *mut T { + self as *mut Self as _ + } +} + +#[unstable(feature = "sgx_platform", issue = "56975")] +unsafe impl UserSafeCopyDestination<[T]> for [MaybeUninit] { + fn as_mut_ptr(&mut self) -> *mut [T] { + self as *mut Self as _ + } +} + #[unstable(feature = "sgx_platform", issue = "56975")] impl User where @@ -239,7 +278,7 @@ where /// Copies `val` into freshly allocated space in user memory. pub fn new_from_enclave(val: &T) -> Self { unsafe { - let mut user = Self::new_uninit_bytes(mem::size_of_val(val)); + let mut user = Self::new_uninit_bytes(size_of_val(val)); user.copy_from_enclave(val); user } @@ -277,7 +316,7 @@ where { /// Allocates space for `T` in user memory. pub fn uninitialized() -> Self { - Self::new_uninit_bytes(mem::size_of::()) + Self::new_uninit_bytes(size_of::()) } } @@ -288,7 +327,7 @@ where { /// Allocates space for a `[T]` of `n` elements in user memory. pub fn uninitialized(n: usize) -> Self { - Self::new_uninit_bytes(n * mem::size_of::()) + Self::new_uninit_bytes(n * size_of::()) } /// Creates an owned `User<[T]>` from a raw thin pointer and a slice length. @@ -306,9 +345,7 @@ where /// * The pointed-to range does not fit in the address space /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self { - User(unsafe { - NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::())) - }) + User(unsafe { NonNull::new_userref(<[T]>::from_raw_sized(ptr as _, len * size_of::())) }) } } @@ -326,7 +363,7 @@ where // `<*const u8>::align_offset` aren't _guaranteed_ to compute the largest // possible middle region, and as such can't be used. fn u64_align_to_guaranteed(ptr: *const u8, mut len: usize) -> (usize, usize, usize) { - const QWORD_SIZE: usize = mem::size_of::(); + const QWORD_SIZE: usize = size_of::(); let offset = ptr as usize % QWORD_SIZE; @@ -532,11 +569,11 @@ where /// the source. This can happen for dynamically-sized types such as slices. pub fn copy_from_enclave(&mut self, val: &T) { unsafe { - assert_eq!(mem::size_of_val(val), mem::size_of_val(&*self.0.get())); + assert_eq!(size_of_val(val), size_of_val(&*self.0.get())); copy_to_userspace( val as *const T as *const u8, self.0.get() as *mut T as *mut u8, - mem::size_of_val(val), + size_of_val(val), ); } } @@ -546,13 +583,13 @@ where /// # Panics /// This function panics if the destination doesn't have the same size as /// the source. This can happen for dynamically-sized types such as slices. - pub fn copy_to_enclave(&self, dest: &mut T) { + pub fn copy_to_enclave>(&self, dest: &mut U) { unsafe { - assert_eq!(mem::size_of_val(dest), mem::size_of_val(&*self.0.get())); + assert_eq!(size_of_val(dest), size_of_val(&*self.0.get())); copy_from_userspace( self.0.get() as *const T as *const u8, - dest as *mut T as *mut u8, - mem::size_of_val(dest), + dest.as_mut_ptr() as *mut u8, + size_of_val(dest), ); } } @@ -577,7 +614,7 @@ where pub fn to_enclave(&self) -> T { unsafe { let mut data = mem::MaybeUninit::uninit(); - copy_from_userspace(self.0.get() as _, data.as_mut_ptr() as _, mem::size_of::()); + copy_from_userspace(self.0.get() as _, data.as_mut_ptr() as _, size_of::()); data.assume_init() } } @@ -602,9 +639,7 @@ where /// * The pointed-to range is not in user memory pub unsafe fn from_raw_parts<'a>(ptr: *const T, len: usize) -> &'a Self { // SAFETY: The caller must uphold the safety contract for `from_raw_parts`. - unsafe { - &*(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *const Self) - } + unsafe { &*(<[T]>::from_raw_sized(ptr as _, len * size_of::()).as_ptr() as *const Self) } } /// Creates a `&mut UserRef<[T]>` from a raw thin pointer and a slice length. @@ -624,7 +659,7 @@ where pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut T, len: usize) -> &'a mut Self { // SAFETY: The caller must uphold the safety contract for `from_raw_parts_mut`. unsafe { - &mut *(<[T]>::from_raw_sized(ptr as _, len * mem::size_of::()).as_ptr() as *mut Self) + &mut *(<[T]>::from_raw_sized(ptr as _, len * size_of::()).as_ptr() as *mut Self) } } @@ -643,25 +678,18 @@ where unsafe { (*self.0.get()).len() } } - /// Copies the value from user memory and place it into `dest`. Afterwards, - /// `dest` will contain exactly `self.len()` elements. - /// - /// # Panics - /// This function panics if the destination doesn't have the same size as - /// the source. This can happen for dynamically-sized types such as slices. - pub fn copy_to_enclave_vec(&self, dest: &mut Vec) { - if let Some(missing) = self.len().checked_sub(dest.capacity()) { - dest.reserve(missing) - } + /// Copies the value from user memory and appends it to `dest`. + pub fn append_to_enclave_vec(&self, dest: &mut Vec) { + dest.reserve(self.len()); + self.copy_to_enclave(&mut dest.spare_capacity_mut()[..self.len()]); // SAFETY: We reserve enough space above. - unsafe { dest.set_len(self.len()) }; - self.copy_to_enclave(&mut dest[..]); + unsafe { dest.set_len(dest.len() + self.len()) }; } /// Copies the value from user memory into a vector in enclave memory. pub fn to_enclave(&self) -> Vec { let mut ret = Vec::with_capacity(self.len()); - self.copy_to_enclave_vec(&mut ret); + self.append_to_enclave_vec(&mut ret); ret } @@ -744,7 +772,7 @@ where fn drop(&mut self) { unsafe { let ptr = (*self.0.as_ptr()).0.get(); - super::free(ptr as _, mem::size_of_val(&mut *ptr), T::align_of()); + super::free(ptr as _, size_of_val(&mut *ptr), T::align_of()); } } } diff --git a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs index 90b9b59471a52..cbdaf439b2847 100644 --- a/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/usercalls/mod.rs @@ -1,5 +1,7 @@ use crate::cmp; -use crate::io::{Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult}; +use crate::io::{ + BorrowedCursor, Error as IoError, ErrorKind, IoSlice, IoSliceMut, Result as IoResult, +}; use crate::random::{DefaultRandomSource, Random}; use crate::time::{Duration, Instant}; @@ -36,6 +38,19 @@ pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult { } } +/// Usercall `read` with an uninitialized buffer. See the ABI documentation for +/// more information. +#[unstable(feature = "sgx_platform", issue = "56975")] +pub fn read_buf(fd: Fd, mut buf: BorrowedCursor<'_>) -> IoResult<()> { + unsafe { + let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.capacity()); + let len = raw::read(fd, userbuf.as_mut_ptr().cast(), userbuf.len()).from_sgx_result()?; + userbuf[..len].copy_to_enclave(&mut buf.as_mut()[..len]); + buf.advance_unchecked(len); + Ok(()) + } +} + /// Usercall `read_alloc`. See the ABI documentation for more information. #[unstable(feature = "sgx_platform", issue = "56975")] pub fn read_alloc(fd: Fd) -> IoResult> { diff --git a/library/std/src/sys/pal/sgx/fd.rs b/library/std/src/sys/pal/sgx/fd.rs index 3bb3189a1d127..399f6a1648984 100644 --- a/library/std/src/sys/pal/sgx/fd.rs +++ b/library/std/src/sys/pal/sgx/fd.rs @@ -29,7 +29,7 @@ impl FileDesc { } pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { - crate::io::default_read_buf(|b| self.read(b), buf) + usercalls::read_buf(self.fd, buf) } pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { diff --git a/library/std/src/sys/pal/sgx/libunwind_integration.rs b/library/std/src/sys/pal/sgx/libunwind_integration.rs index 6d0d78d1eb9b5..b5419ad05decd 100644 --- a/library/std/src/sys/pal/sgx/libunwind_integration.rs +++ b/library/std/src/sys/pal/sgx/libunwind_integration.rs @@ -4,6 +4,7 @@ #![cfg(not(test))] use crate::sys::sync::RwLock; +use crate::{slice, str}; // Verify that the byte pattern libunwind uses to initialize an RwLock is // equivalent to the value of RwLock::new(). If the value changes, @@ -44,3 +45,14 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 { unsafe { (*p).write_unlock() }; return 0; } + +#[unsafe(no_mangle)] +pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { + if s < 0 { + return; + } + let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) }; + if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { + eprint!("{s}"); + } +} diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs index 37ca6b08c950b..bb419c2530ec1 100644 --- a/library/std/src/sys/pal/sgx/mod.rs +++ b/library/std/src/sys/pal/sgx/mod.rs @@ -12,15 +12,12 @@ pub mod abi; pub mod args; pub mod env; pub mod fd; -#[path = "../unsupported/fs.rs"] -pub mod fs; mod libunwind_integration; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod thread_parking; pub mod time; diff --git a/library/std/src/sys/pal/sgx/stdio.rs b/library/std/src/sys/pal/sgx/stdio.rs deleted file mode 100644 index 726a93acae44b..0000000000000 --- a/library/std/src/sys/pal/sgx/stdio.rs +++ /dev/null @@ -1,88 +0,0 @@ -use fortanix_sgx_abi as abi; - -use crate::io; -#[cfg(not(test))] -use crate::slice; -#[cfg(not(test))] -use crate::str; -use crate::sys::fd::FileDesc; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -fn with_std_fd R, R>(fd: abi::Fd, f: F) -> R { - let fd = FileDesc::new(fd); - let ret = f(&fd); - fd.into_raw(); - ret -} - -impl Stdin { - pub const fn new() -> Stdin { - Stdin(()) - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - with_std_fd(abi::FD_STDIN, |fd| fd.read(buf)) - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout(()) - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result { - with_std_fd(abi::FD_STDOUT, |fd| fd.write(buf)) - } - - fn flush(&mut self) -> io::Result<()> { - with_std_fd(abi::FD_STDOUT, |fd| fd.flush()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr(()) - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result { - with_std_fd(abi::FD_STDERR, |fd| fd.write(buf)) - } - - fn flush(&mut self) -> io::Result<()> { - with_std_fd(abi::FD_STDERR, |fd| fd.flush()) - } -} - -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; - -pub fn is_ebadf(err: &io::Error) -> bool { - // FIXME: Rust normally maps Unix EBADF to `Uncategorized` - err.raw_os_error() == Some(abi::Error::BrokenPipe as _) -} - -pub fn panic_output() -> Option { - super::abi::panic::SgxPanicOutput::new() -} - -// This function is needed by libunwind. The symbol is named in pre-link args -// for the target specification, so keep that in sync. -#[cfg(not(test))] -#[unsafe(no_mangle)] -pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) { - if s < 0 { - return; - } - let buf = unsafe { slice::from_raw_parts(m as *const u8, s as _) }; - if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) { - eprint!("{s}"); - } -} diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 06af7bfade059..e4a61fdcfe3e7 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -22,13 +22,11 @@ pub mod env; // `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as // `crate::sys::error` pub(crate) mod error; -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub use self::itron::{thread, thread_parking}; pub mod time; diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs index 3f9bbb0b63cdb..c39d715c6a6f6 100644 --- a/library/std/src/sys/pal/solid/time.rs +++ b/library/std/src/sys/pal/solid/time.rs @@ -35,7 +35,7 @@ impl SystemTime { SystemTime(t) } - pub(super) fn from_time_t(t: abi::time_t) -> Self { + pub fn from_time_t(t: abi::time_t) -> Self { Self(t) } diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs index 3632524157db9..41b2512159289 100644 --- a/library/std/src/sys/pal/teeos/mod.rs +++ b/library/std/src/sys/pal/teeos/mod.rs @@ -11,14 +11,11 @@ pub mod args; #[path = "../unsupported/env.rs"] pub mod env; //pub mod fd; -#[path = "../unsupported/fs.rs"] -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; #[allow(non_upper_case_globals)] #[path = "../unix/time.rs"] diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs new file mode 100644 index 0000000000000..7034b643d8e8e --- /dev/null +++ b/library/std/src/sys/pal/trusty/mod.rs @@ -0,0 +1,21 @@ +//! System bindings for the Trusty OS. + +#[path = "../unsupported/args.rs"] +pub mod args; +#[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] +mod common; +#[path = "../unsupported/env.rs"] +pub mod env; +#[path = "../unsupported/os.rs"] +pub mod os; +#[path = "../unsupported/pipe.rs"] +pub mod pipe; +#[path = "../unsupported/process.rs"] +pub mod process; +#[path = "../unsupported/thread.rs"] +pub mod thread; +#[path = "../unsupported/time.rs"] +pub mod time; + +pub use common::*; diff --git a/library/std/src/sys/pal/uefi/args.rs b/library/std/src/sys/pal/uefi/args.rs index bdf6f5a0c1c34..0c29caf2db676 100644 --- a/library/std/src/sys/pal/uefi/args.rs +++ b/library/std/src/sys/pal/uefi/args.rs @@ -4,7 +4,6 @@ use super::helpers; use crate::env::current_exe; use crate::ffi::OsString; use crate::iter::Iterator; -use crate::mem::size_of; use crate::{fmt, vec}; pub struct Args { diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index ec2da4e4ee7a4..60c33c637d762 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -10,12 +10,12 @@ //! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles) use r_efi::efi::{self, Guid}; -use r_efi::protocols::{device_path, device_path_to_text, shell}; +use r_efi::protocols::{device_path, device_path_to_text, service_binding, shell}; use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_error}; use crate::marker::PhantomData; -use crate::mem::{MaybeUninit, size_of}; +use crate::mem::MaybeUninit; use crate::os::uefi::env::boot_services; use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::os::uefi::{self}; @@ -158,7 +158,7 @@ pub(crate) unsafe fn close_event(evt: NonNull) -> io::Result /// Note: Some protocols need to be manually freed. It is the caller's responsibility to do so. pub(crate) fn image_handle_protocol(protocol_guid: Guid) -> io::Result> { let system_handle = uefi::env::try_image_handle() - .ok_or(io::const_error!(io::ErrorKind::NotFound, "Protocol not found in Image handle"))?; + .ok_or(io::const_error!(io::ErrorKind::NotFound, "protocol not found in Image handle"))?; open_protocol(system_handle, protocol_guid) } @@ -178,7 +178,7 @@ pub(crate) fn device_path_to_text(path: NonNull) -> io::R }; let path = os_string_from_raw(path_ptr) - .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "invalid path"))?; if let Some(boot_services) = crate::os::uefi::env::boot_services() { let boot_services: NonNull = boot_services.cast(); @@ -213,6 +213,60 @@ pub(crate) fn device_path_to_text(path: NonNull) -> io::R } } + Err(io::const_error!(io::ErrorKind::NotFound, "no device path to text protocol found")) +} + +fn device_node_to_text(path: NonNull) -> io::Result { + fn node_to_text( + protocol: NonNull, + path: NonNull, + ) -> io::Result { + let path_ptr: *mut r_efi::efi::Char16 = unsafe { + ((*protocol.as_ptr()).convert_device_node_to_text)( + path.as_ptr(), + // DisplayOnly + r_efi::efi::Boolean::FALSE, + // AllowShortcuts + r_efi::efi::Boolean::FALSE, + ) + }; + + let path = os_string_from_raw(path_ptr) + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + + if let Some(boot_services) = crate::os::uefi::env::boot_services() { + let boot_services: NonNull = boot_services.cast(); + unsafe { + ((*boot_services.as_ptr()).free_pool)(path_ptr.cast()); + } + } + + Ok(path) + } + + static LAST_VALID_HANDLE: AtomicPtr = + AtomicPtr::new(crate::ptr::null_mut()); + + if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) { + if let Ok(protocol) = open_protocol::( + handle, + device_path_to_text::PROTOCOL_GUID, + ) { + return node_to_text(protocol, path); + } + } + + let device_path_to_text_handles = locate_handles(device_path_to_text::PROTOCOL_GUID)?; + for handle in device_path_to_text_handles { + if let Ok(protocol) = open_protocol::( + handle, + device_path_to_text::PROTOCOL_GUID, + ) { + LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release); + return node_to_text(protocol, path); + } + } + Err(io::const_error!(io::ErrorKind::NotFound, "No device path to text protocol found")) } @@ -245,7 +299,7 @@ impl OwnedDevicePath { NonNull::new(path) .map(OwnedDevicePath) - .ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")) + .ok_or_else(|| const_error!(io::ErrorKind::InvalidFilename, "invalid Device Path")) } static LAST_VALID_HANDLE: AtomicPtr = @@ -319,6 +373,11 @@ impl<'a> BorrowedDevicePath<'a> { pub(crate) fn to_text(&self) -> io::Result { device_path_to_text(self.protocol) } + + #[expect(dead_code)] + pub(crate) const fn iter(&'a self) -> DevicePathIterator<'a> { + DevicePathIterator::new(DevicePathNode::new(self.protocol)) + } } impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> { @@ -330,6 +389,126 @@ impl<'a> crate::fmt::Debug for BorrowedDevicePath<'a> { } } +pub(crate) struct DevicePathIterator<'a>(Option>); + +impl<'a> DevicePathIterator<'a> { + const fn new(node: DevicePathNode<'a>) -> Self { + if node.is_end() { Self(None) } else { Self(Some(node)) } + } +} + +impl<'a> Iterator for DevicePathIterator<'a> { + type Item = DevicePathNode<'a>; + + fn next(&mut self) -> Option { + let cur_node = self.0?; + + let next_node = unsafe { cur_node.next_node() }; + self.0 = if next_node.is_end() { None } else { Some(next_node) }; + + Some(cur_node) + } +} + +#[derive(Copy, Clone)] +pub(crate) struct DevicePathNode<'a> { + protocol: NonNull, + phantom: PhantomData<&'a r_efi::protocols::device_path::Protocol>, +} + +impl<'a> DevicePathNode<'a> { + pub(crate) const fn new(protocol: NonNull) -> Self { + Self { protocol, phantom: PhantomData } + } + + pub(crate) const fn length(&self) -> u16 { + let len = unsafe { (*self.protocol.as_ptr()).length }; + u16::from_le_bytes(len) + } + + pub(crate) const fn node_type(&self) -> u8 { + unsafe { (*self.protocol.as_ptr()).r#type } + } + + pub(crate) const fn sub_type(&self) -> u8 { + unsafe { (*self.protocol.as_ptr()).sub_type } + } + + pub(crate) fn data(&self) -> &[u8] { + let length: usize = self.length().into(); + + // Some nodes do not have any special data + if length > 4 { + let raw_ptr: *const u8 = self.protocol.as_ptr().cast(); + let data = unsafe { raw_ptr.add(4) }; + unsafe { crate::slice::from_raw_parts(data, length - 4) } + } else { + &[] + } + } + + pub(crate) const fn is_end(&self) -> bool { + self.node_type() == r_efi::protocols::device_path::TYPE_END + && self.sub_type() == r_efi::protocols::device_path::End::SUBTYPE_ENTIRE + } + + #[expect(dead_code)] + pub(crate) const fn is_end_instance(&self) -> bool { + self.node_type() == r_efi::protocols::device_path::TYPE_END + && self.sub_type() == r_efi::protocols::device_path::End::SUBTYPE_INSTANCE + } + + pub(crate) unsafe fn next_node(&self) -> Self { + let node = unsafe { + self.protocol + .cast::() + .add(self.length().into()) + .cast::() + }; + Self::new(node) + } + + #[expect(dead_code)] + pub(crate) fn to_path(&'a self) -> BorrowedDevicePath<'a> { + BorrowedDevicePath::new(self.protocol) + } + + pub(crate) fn to_text(&self) -> io::Result { + device_node_to_text(self.protocol) + } +} + +impl<'a> PartialEq for DevicePathNode<'a> { + fn eq(&self, other: &Self) -> bool { + let self_len = self.length(); + let other_len = other.length(); + + self_len == other_len + && unsafe { + compiler_builtins::mem::memcmp( + self.protocol.as_ptr().cast(), + other.protocol.as_ptr().cast(), + usize::from(self_len), + ) == 0 + } + } +} + +impl<'a> crate::fmt::Debug for DevicePathNode<'a> { + fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { + match self.to_text() { + Ok(p) => p.fmt(f), + Err(_) => f + .debug_struct("DevicePathNode") + .field("type", &self.node_type()) + .field("sub_type", &self.sub_type()) + .field("length", &self.length()) + .field("specific_device_path_data", &self.data()) + .finish(), + } + } +} + pub(crate) struct OwnedProtocol { guid: r_efi::efi::Guid, handle: NonNull, @@ -490,7 +669,7 @@ pub(crate) fn get_device_path_from_map(map: &Path) -> io::Result io::Result, + child_handle: NonNull, +} + +impl ServiceProtocol { + #[expect(dead_code)] + pub(crate) fn open(service_guid: r_efi::efi::Guid) -> io::Result { + let handles = locate_handles(service_guid)?; + + for handle in handles { + if let Ok(protocol) = open_protocol::(handle, service_guid) { + let Ok(child_handle) = Self::create_child(protocol) else { + continue; + }; + + return Ok(Self { service_guid, handle, child_handle }); + } + } + + Err(io::const_error!(io::ErrorKind::NotFound, "no service binding protocol found")) + } + + #[expect(dead_code)] + pub(crate) fn child_handle(&self) -> NonNull { + self.child_handle + } + + fn create_child( + sbp: NonNull, + ) -> io::Result> { + let mut child_handle: r_efi::efi::Handle = crate::ptr::null_mut(); + // SAFETY: A new handle is allocated if a pointer to NULL is passed. + let r = unsafe { ((*sbp.as_ptr()).create_child)(sbp.as_ptr(), &mut child_handle) }; + + if r.is_error() { + Err(crate::io::Error::from_raw_os_error(r.as_usize())) + } else { + NonNull::new(child_handle) + .ok_or(const_error!(io::ErrorKind::Other, "null child handle")) + } + } +} + +impl Drop for ServiceProtocol { + fn drop(&mut self) { + if let Ok(sbp) = open_protocol::(self.handle, self.service_guid) + { + // SAFETY: Child handle must be allocated by the current service binding protocol. + let _ = unsafe { + ((*sbp.as_ptr()).destroy_child)(sbp.as_ptr(), self.child_handle.as_ptr()) + }; + } + } +} diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 6a03e240c6bd4..714dc392688fb 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -15,13 +15,11 @@ pub mod args; pub mod env; -pub mod fs; pub mod helpers; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/uefi/os.rs b/library/std/src/sys/pal/uefi/os.rs index e305b8610c9f8..d26d61890c19e 100644 --- a/library/std/src/sys/pal/uefi/os.rs +++ b/library/std/src/sys/pal/uefi/os.rs @@ -70,7 +70,7 @@ pub fn getcwd() -> io::Result { let path_ptr = unsafe { ((*shell.as_ptr()).get_cur_dir)(crate::ptr::null_mut()) }; helpers::os_string_from_raw(path_ptr) .map(PathBuf::from) - .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path")) + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "invalid path")) } None => { let mut t = current_exe()?; @@ -86,7 +86,7 @@ pub fn chdir(p: &path::Path) -> io::Result<()> { let shell = helpers::open_shell().ok_or(unsupported_err())?; let mut p = helpers::os_string_to_raw(p.as_os_str()) - .ok_or(io::const_error!(io::ErrorKind::InvalidData, "Invalid path"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidData, "invalid path"))?; let r = unsafe { ((*shell.as_ptr()).set_cur_dir)(crate::ptr::null_mut(), p.as_mut_ptr()) }; if r.is_error() { Err(io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } @@ -229,15 +229,15 @@ mod uefi_env { pub(crate) fn set(key: &OsStr, val: &OsStr) -> io::Result<()> { let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; let mut val_ptr = helpers::os_string_to_raw(val) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; unsafe { set_raw(key_ptr.as_mut_ptr(), val_ptr.as_mut_ptr()) } } pub(crate) fn unset(key: &OsStr) -> io::Result<()> { let mut key_ptr = helpers::os_string_to_raw(key) - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Key"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid key"))?; unsafe { set_raw(key_ptr.as_mut_ptr(), crate::ptr::null_mut()) } } @@ -267,7 +267,7 @@ mod uefi_env { }); // SAFETY: val.add(start) is always NULL terminated let val = unsafe { get_raw(shell, val.add(start)) } - .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "Invalid Value"))?; + .ok_or(io::const_error!(io::ErrorKind::InvalidInput, "invalid value"))?; vars.push((key, val)); start = i + 1; diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 9efe9a314f2e9..1203d51e5312a 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -388,7 +388,7 @@ mod uefi_command_internal { } } - pub fn start_image(&mut self) -> io::Result { + pub(crate) fn start_image(&mut self) -> io::Result { self.update_st_crc32()?; // Use our system table instead of the default one @@ -490,7 +490,7 @@ mod uefi_command_internal { helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); let len = args.len(); - let args_size: u32 = (len * crate::mem::size_of::()).try_into().unwrap(); + let args_size: u32 = (len * size_of::()).try_into().unwrap(); let ptr = Box::into_raw(args).as_mut_ptr(); unsafe { @@ -613,7 +613,7 @@ mod uefi_command_internal { OsString::from_wide(&self._buffer) .into_string() .map(Into::into) - .map_err(|_| const_error!(io::ErrorKind::Other, "utf8 conversion failed")) + .map_err(|_| const_error!(io::ErrorKind::Other, "UTF-8 conversion failed")) } extern "efiapi" fn reset( @@ -757,7 +757,7 @@ mod uefi_command_internal { } /// Create a map of environment variable changes. Allows efficient setting and rolling back of -/// enviroment variable changes. +/// environment variable changes. /// /// Entry: (Old Value, New Value) fn env_changes(env: &CommandEnv) -> Option, Option)>> { diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs index 5eb36da922b54..38658cc4e9ac4 100644 --- a/library/std/src/sys/pal/uefi/tests.rs +++ b/library/std/src/sys/pal/uefi/tests.rs @@ -16,7 +16,7 @@ fn align() { if *j <= 8 { assert_eq!(align_size(i, *j), i); } else { - assert!(align_size(i, *j) > i + std::mem::size_of::<*mut ()>()); + assert!(align_size(i, *j) > i + size_of::<*mut ()>()); } } } diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs index 495ff2dc930ed..c4ff3015ac60d 100644 --- a/library/std/src/sys/pal/uefi/time.rs +++ b/library/std/src/sys/pal/uefi/time.rs @@ -84,7 +84,7 @@ pub(crate) mod system_time_internal { // This algorithm is based on the one described in the post // https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html - pub const fn uefi_time_to_duration(t: r_efi::system::Time) -> Duration { + pub(crate) const fn uefi_time_to_duration(t: r_efi::system::Time) -> Duration { assert!(t.month <= 12); assert!(t.month != 0); diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index 2fc33bdfefbf5..a08c7ccec2da3 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -251,6 +251,9 @@ impl FileDesc { } #[cfg(all(target_os = "android", target_pointer_width = "32"))] + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. + #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index d4551dd6a38bb..87ba13ca9321d 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -58,7 +58,7 @@ pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option) - _clockid: libc::CLOCK_MONOTONIC as u32, }); let umtx_timeout_ptr = umtx_timeout.as_ref().map_or(null(), |t| t as *const _); - let umtx_timeout_size = umtx_timeout.as_ref().map_or(0, |t| crate::mem::size_of_val(t)); + let umtx_timeout_size = umtx_timeout.as_ref().map_or(0, |t| size_of_val(t)); libc::_umtx_op( futex as *const AtomicU32 as *mut _, libc::UMTX_OP_WAIT_UINT_PRIVATE, diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index c0b56d8d2b28a..419abe732ac3f 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -9,7 +9,6 @@ pub mod weak; pub mod args; pub mod env; pub mod fd; -pub mod fs; pub mod futex; #[cfg(any(target_os = "linux", target_os = "android"))] pub mod kernel_copy; @@ -19,7 +18,6 @@ pub mod os; pub mod pipe; pub mod process; pub mod stack_overflow; -pub mod stdio; pub mod sync; pub mod thread; pub mod thread_parking; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 78404b4afa790..91f55fcd32bb5 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -475,7 +475,7 @@ pub fn current_exe() -> io::Result { ); if result != libc::B_OK { use crate::io::ErrorKind; - Err(io::const_error!(ErrorKind::Uncategorized, "Error getting executable path")) + Err(io::const_error!(ErrorKind::Uncategorized, "error getting executable path")) } else { // find_path adds the null terminator. let name = CStr::from_ptr(name.as_ptr()).to_bytes(); @@ -484,7 +484,12 @@ pub fn current_exe() -> io::Result { } } -#[cfg(any(target_os = "redox", target_os = "rtems"))] +#[cfg(target_os = "redox")] +pub fn current_exe() -> io::Result { + crate::fs::read_to_string("/scheme/sys/exe").map(PathBuf::from) +} + +#[cfg(target_os = "rtems")] pub fn current_exe() -> io::Result { crate::fs::read_to_string("sys:exe").map(PathBuf::from) } @@ -492,7 +497,7 @@ pub fn current_exe() -> io::Result { #[cfg(target_os = "l4re")] pub fn current_exe() -> io::Result { use crate::io::ErrorKind; - Err(io::const_error!(ErrorKind::Unsupported, "Not yet implemented!")) + Err(io::const_error!(ErrorKind::Unsupported, "not yet implemented!")) } #[cfg(target_os = "vxworks")] diff --git a/library/std/src/sys/pal/unix/process/process_common.rs b/library/std/src/sys/pal/unix/process/process_common.rs index 342818ac91183..dd41921f263e6 100644 --- a/library/std/src/sys/pal/unix/process/process_common.rs +++ b/library/std/src/sys/pal/unix/process/process_common.rs @@ -19,8 +19,6 @@ use crate::{fmt, io, ptr}; cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { // fuchsia doesn't have /dev/null - } else if #[cfg(target_os = "redox")] { - const DEV_NULL: &CStr = c"null:"; } else if #[cfg(target_os = "vxworks")] { const DEV_NULL: &CStr = c"/null"; } else { @@ -43,10 +41,7 @@ cfg_if::cfg_if! { #[allow(dead_code)] pub unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { - use crate::{ - mem::{align_of, size_of}, - slice, - }; + use crate::slice; use libc::{c_ulong, sigset_t}; // The implementations from bionic (android libc) type pun `sigset_t` as an diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index b7a35718757ae..05c9ace470e3e 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -179,7 +179,7 @@ impl Process { self.handle.raw(), ZX_INFO_PROCESS, (&raw mut proc_info) as *mut libc::c_void, - mem::size_of::(), + size_of::(), &mut actual, &mut avail, ))?; @@ -187,7 +187,7 @@ impl Process { if actual != 1 { return Err(io::const_error!( io::ErrorKind::InvalidData, - "Failed to get exit status of process", + "failed to get exit status of process", )); } Ok(ExitStatus(proc_info.return_code)) @@ -216,7 +216,7 @@ impl Process { self.handle.raw(), ZX_INFO_PROCESS, (&raw mut proc_info) as *mut libc::c_void, - mem::size_of::(), + size_of::(), &mut actual, &mut avail, ))?; @@ -224,7 +224,7 @@ impl Process { if actual != 1 { return Err(io::const_error!( io::ErrorKind::InvalidData, - "Failed to get exit status of process", + "failed to get exit status of process", )); } Ok(Some(ExitStatus(proc_info.return_code))) 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 aa7406dd54874..be9a7e919905f 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -410,6 +410,7 @@ impl Command { #[cfg(not(any( target_os = "freebsd", + target_os = "illumos", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), target_os = "nto", @@ -427,11 +428,15 @@ impl Command { // directly. #[cfg(any( target_os = "freebsd", + target_os = "illumos", all(target_os = "linux", target_env = "gnu"), all(target_os = "linux", target_env = "musl"), target_os = "nto", target_vendor = "apple", ))] + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. + #[cfg_attr(target_os = "linux", no_sanitize(cfi))] fn posix_spawn( &mut self, stdio: &ChildPipes, @@ -584,6 +589,10 @@ impl Command { fn get_posix_spawn_addchdir() -> Option { use crate::sys::weak::weak; + // POSIX.1-2024 standardizes this function: + // https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html. + // The _np version is more widely available, though, so try that first. + weak! { fn posix_spawn_file_actions_addchdir_np( *mut libc::posix_spawn_file_actions_t, @@ -591,7 +600,16 @@ impl Command { ) -> libc::c_int } - posix_spawn_file_actions_addchdir_np.get() + weak! { + fn posix_spawn_file_actions_addchdir( + *mut libc::posix_spawn_file_actions_t, + *const libc::c_char + ) -> libc::c_int + } + + posix_spawn_file_actions_addchdir_np + .get() + .or_else(|| posix_spawn_file_actions_addchdir.get()) } /// Get the function pointer for adding a chdir action to a @@ -799,7 +817,7 @@ impl Command { let fds: [c_int; 1] = [pidfd as RawFd]; - const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>(); + const SCM_MSG_LEN: usize = size_of::<[c_int; 1]>(); #[repr(C)] union Cmsg { @@ -818,7 +836,7 @@ impl Command { // only attach cmsg if we successfully acquired the pidfd if pidfd >= 0 { - msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _; + msg.msg_controllen = size_of_val(&cmsg.buf) as _; msg.msg_control = (&raw mut cmsg.buf) as *mut _; let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); @@ -850,7 +868,7 @@ impl Command { use crate::sys::cvt_r; unsafe { - const SCM_MSG_LEN: usize = mem::size_of::<[c_int; 1]>(); + const SCM_MSG_LEN: usize = size_of::<[c_int; 1]>(); #[repr(C)] union Cmsg { @@ -865,7 +883,7 @@ impl Command { msg.msg_iov = (&raw mut iov) as *mut _; msg.msg_iovlen = 1; - msg.msg_controllen = mem::size_of::() as _; + msg.msg_controllen = size_of::() as _; msg.msg_control = (&raw mut cmsg) as *mut _; match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) { @@ -1228,7 +1246,7 @@ mod linux_child_ext { .as_ref() // SAFETY: The os type is a transparent wrapper, therefore we can transmute references .map(|fd| unsafe { mem::transmute::<&imp::PidFd, &os::PidFd>(fd) }) - .ok_or_else(|| io::const_error!(ErrorKind::Uncategorized, "No pidfd was created.")) + .ok_or_else(|| io::const_error!(ErrorKind::Uncategorized, "no pidfd was created.")) } fn into_pidfd(mut self) -> Result { diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index db5c6bd3a1c32..0ecccdc8812dd 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -319,21 +319,27 @@ mod imp { ))] unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; - let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); + if !cfg!(target_os = "freebsd") { + attr = mem::MaybeUninit::zeroed(); + } #[cfg(target_os = "freebsd")] - assert_eq!(libc::pthread_attr_init(&mut attr), 0); + assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); #[cfg(target_os = "freebsd")] - let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); + let e = libc::pthread_attr_get_np(libc::pthread_self(), attr.as_mut_ptr()); #[cfg(not(target_os = "freebsd"))] - let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); + let e = libc::pthread_getattr_np(libc::pthread_self(), attr.as_mut_ptr()); if e == 0 { let mut stackaddr = crate::ptr::null_mut(); let mut stacksize = 0; - assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); + assert_eq!( + libc::pthread_attr_getstack(attr.as_ptr(), &mut stackaddr, &mut stacksize), + 0 + ); ret = Some(stackaddr); } if e == 0 || cfg!(target_os = "freebsd") { - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); } ret } @@ -420,7 +426,7 @@ mod imp { use crate::sys::weak::dlsym; dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int); let mut guard: usize = 0; - let mut size = mem::size_of_val(&guard); + let mut size = size_of_val(&guard); let oid = c"security.bsd.stack_guard_page"; match sysctlbyname.get() { Some(fcn) if unsafe { @@ -509,16 +515,20 @@ mod imp { // FIXME: I am probably not unsafe. unsafe fn current_guard() -> Option> { let mut ret = None; - let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + + let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); + if !cfg!(target_os = "freebsd") { + attr = mem::MaybeUninit::zeroed(); + } #[cfg(target_os = "freebsd")] - assert_eq!(libc::pthread_attr_init(&mut attr), 0); + assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); #[cfg(target_os = "freebsd")] - let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); + let e = libc::pthread_attr_get_np(libc::pthread_self(), attr.as_mut_ptr()); #[cfg(not(target_os = "freebsd"))] - let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr); + let e = libc::pthread_getattr_np(libc::pthread_self(), attr.as_mut_ptr()); if e == 0 { let mut guardsize = 0; - assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0); + assert_eq!(libc::pthread_attr_getguardsize(attr.as_ptr(), &mut guardsize), 0); if guardsize == 0 { if cfg!(all(target_os = "linux", target_env = "musl")) { // musl versions before 1.1.19 always reported guard @@ -531,7 +541,7 @@ mod imp { } let mut stackptr = crate::ptr::null_mut::(); let mut size = 0; - assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0); + assert_eq!(libc::pthread_attr_getstack(attr.as_ptr(), &mut stackptr, &mut size), 0); let stackaddr = stackptr.addr(); ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) { @@ -552,7 +562,7 @@ mod imp { }; } if e == 0 || cfg!(target_os = "freebsd") { - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); } ret } diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 69c99782f0bf6..abe8d3fbf681e 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -49,24 +49,27 @@ impl Thread { pub unsafe fn new(stack: usize, p: Box) -> io::Result { let p = Box::into_raw(Box::new(p)); let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); + let mut attr: mem::MaybeUninit = mem::MaybeUninit::uninit(); + assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0); #[cfg(target_os = "espidf")] if stack > 0 { // Only set the stack if a non-zero value is passed // 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used assert_eq!( - libc::pthread_attr_setstacksize(&mut attr, cmp::max(stack, min_stack_size(&attr))), + libc::pthread_attr_setstacksize( + attr.as_mut_ptr(), + cmp::max(stack, min_stack_size(attr.as_ptr())) + ), 0 ); } #[cfg(not(target_os = "espidf"))] { - let stack_size = cmp::max(stack, min_stack_size(&attr)); + let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr())); - match libc::pthread_attr_setstacksize(&mut attr, stack_size) { + match libc::pthread_attr_setstacksize(attr.as_mut_ptr(), stack_size) { 0 => {} n => { assert_eq!(n, libc::EINVAL); @@ -77,16 +80,16 @@ impl Thread { let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); + assert_eq!(libc::pthread_attr_setstacksize(attr.as_mut_ptr(), stack_size), 0); } }; } - let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); + let ret = libc::pthread_create(&mut native, attr.as_ptr(), thread_start, p as *mut _); // Note: if the thread creation fails and this assert fails, then p will // be leaked. However, an alternative design could cause double-free // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + assert_eq!(libc::pthread_attr_destroy(attr.as_mut_ptr()), 0); return if ret != 0 { // The thread failed to start and as a result p was not consumed. Therefore, it is @@ -185,6 +188,9 @@ impl Thread { } #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))] + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. + #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { weak! { fn pthread_setname_np( @@ -369,7 +375,7 @@ pub fn available_parallelism() -> io::Result> { quota = cgroups::quota().max(1); let mut set: libc::cpu_set_t = unsafe { mem::zeroed() }; unsafe { - if libc::sched_getaffinity(0, mem::size_of::(), &mut set) == 0 { + if libc::sched_getaffinity(0, size_of::(), &mut set) == 0 { let count = libc::CPU_COUNT(&set) as usize; let count = count.min(quota); @@ -409,7 +415,7 @@ pub fn available_parallelism() -> io::Result> { libc::CPU_LEVEL_WHICH, libc::CPU_WHICH_PID, -1, - mem::size_of::(), + size_of::(), &mut set, ) == 0 { let count = libc::CPU_COUNT(&set) as usize; @@ -444,7 +450,7 @@ pub fn available_parallelism() -> io::Result> { } let mut cpus: libc::c_uint = 0; - let mut cpus_size = crate::mem::size_of_val(&cpus); + let mut cpus_size = size_of_val(&cpus); unsafe { cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint; @@ -477,7 +483,7 @@ pub fn available_parallelism() -> io::Result> { unsafe { use libc::_syspage_ptr; if _syspage_ptr.is_null() { - Err(io::const_error!(io::ErrorKind::NotFound, "No syspage available")) + Err(io::const_error!(io::ErrorKind::NotFound, "no syspage available")) } else { let cpus = (*_syspage_ptr).num_cpu; NonZero::new(cpus as usize) @@ -517,7 +523,7 @@ pub fn available_parallelism() -> io::Result> { } } else { // FIXME: implement on Redox, l4re - Err(io::const_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform")) + Err(io::const_error!(io::ErrorKind::Unsupported, "getting the number of hardware threads is not supported on the target platform")) } } } diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index e224980e95f31..c0a3044660b7e 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -92,10 +92,21 @@ impl Timespec { if tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64 { Ok(unsafe { Self::new_unchecked(tv_sec, tv_nsec) }) } else { - Err(io::const_error!(io::ErrorKind::InvalidData, "Invalid timestamp")) + Err(io::const_error!(io::ErrorKind::InvalidData, "invalid timestamp")) } } + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. + #[cfg_attr( + all( + target_os = "linux", + target_env = "gnu", + target_pointer_width = "32", + not(target_arch = "riscv32") + ), + no_sanitize(cfi) + )] pub fn now(clock: libc::clockid_t) -> Timespec { use crate::mem::MaybeUninit; use crate::sys::cvt; diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index 5a37598f43827..ce3f66a83748b 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -123,7 +123,7 @@ impl DlsymWeak { // Cold because it should only happen during first-time initialization. #[cold] unsafe fn initialize(&self) -> Option { - assert_eq!(mem::size_of::(), mem::size_of::<*mut libc::c_void>()); + assert_eq!(size_of::(), size_of::<*mut libc::c_void>()); let val = fetch(self.name); // This synchronizes with the acquire fence in `get`. @@ -144,6 +144,9 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + // FIXME(#115199): Rust currently omits weak function definitions + // and its metadata from LLVM IR. + #[no_sanitize(cfi)] unsafe fn $name($($arg_name: $t),*) -> $ret { weak! { fn $name($($t),*) -> $ret } diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs index b1aaeb1b4c814..bcea699f3b2ad 100644 --- a/library/std/src/sys/pal/unsupported/mod.rs +++ b/library/std/src/sys/pal/unsupported/mod.rs @@ -2,11 +2,9 @@ pub mod args; pub mod env; -pub mod fs; pub mod os; pub mod pipe; pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/wasi/fd.rs b/library/std/src/sys/pal/wasi/fd.rs index 19b60157e2e00..4b3dd1ce49ef6 100644 --- a/library/std/src/sys/pal/wasi/fd.rs +++ b/library/std/src/sys/pal/wasi/fd.rs @@ -14,8 +14,8 @@ pub struct WasiFd { } fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { - assert_eq!(mem::size_of::>(), mem::size_of::()); - assert_eq!(mem::align_of::>(), mem::align_of::()); + assert_eq!(size_of::>(), size_of::()); + assert_eq!(align_of::>(), align_of::()); // SAFETY: `IoSliceMut` and `IoVec` have exactly the same memory layout. // We decorate our `IoSliceMut` with `repr(transparent)` (see `io.rs`), and // `crate::io::IoSliceMut` is a `repr(transparent)` wrapper around our type, so this is @@ -24,8 +24,8 @@ fn iovec<'a>(a: &'a mut [IoSliceMut<'_>]) -> &'a [wasi::Iovec] { } fn ciovec<'a>(a: &'a [IoSlice<'_>]) -> &'a [wasi::Ciovec] { - assert_eq!(mem::size_of::>(), mem::size_of::()); - assert_eq!(mem::align_of::>(), mem::align_of::()); + assert_eq!(size_of::>(), size_of::()); + assert_eq!(align_of::>(), align_of::()); // SAFETY: `IoSlice` and `CIoVec` have exactly the same memory layout. // We decorate our `IoSlice` with `repr(transparent)` (see `io.rs`), and // `crate::io::IoSlice` is a `repr(transparent)` wrapper around our type, so this is diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs index f4588a60ea9a4..c89832857dd72 100644 --- a/library/std/src/sys/pal/wasi/mod.rs +++ b/library/std/src/sys/pal/wasi/mod.rs @@ -16,7 +16,6 @@ pub mod args; pub mod env; pub mod fd; -pub mod fs; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; @@ -26,7 +25,6 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index 0ae0236941061..c85b03d4a8918 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -13,16 +13,15 @@ cfg_if::cfg_if! { // Add a few symbols not in upstream `libc` just yet. mod libc { pub use crate::ffi; - pub use crate::mem; pub use libc::*; // defined in wasi-libc // https://github.com/WebAssembly/wasi-libc/blob/a6f871343313220b76009827ed0153586361c0d5/libc-top-half/musl/include/alltypes.h.in#L108 #[repr(C)] union pthread_attr_union { - __i: [ffi::c_int; if mem::size_of::() == 8 { 14 } else { 9 }], - __vi: [ffi::c_int; if mem::size_of::() == 8 { 14 } else { 9 }], - __s: [ffi::c_ulong; if mem::size_of::() == 8 { 7 } else { 9 }], + __i: [ffi::c_int; if size_of::() == 8 { 14 } else { 9 }], + __vi: [ffi::c_int; if size_of::() == 8 { 14 } else { 9 }], + __s: [ffi::c_ulong; if size_of::() == 8 { 7 } else { 9 }], } #[repr(C)] diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 72c9742b2e549..3008ba887535c 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -12,8 +12,6 @@ pub mod args; pub mod env; #[path = "../wasi/fd.rs"] pub mod fd; -#[path = "../wasi/fs.rs"] -pub mod fs; #[allow(unused)] #[path = "../wasm/atomics/futex.rs"] pub mod futex; @@ -24,8 +22,6 @@ pub mod os; pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../wasi/stdio.rs"] -pub mod stdio; #[path = "../wasi/thread.rs"] pub mod thread; #[path = "../wasi/time.rs"] diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs index 32d59c4d0f7c4..175fe75357fb5 100644 --- a/library/std/src/sys/pal/wasm/mod.rs +++ b/library/std/src/sys/pal/wasm/mod.rs @@ -19,16 +19,12 @@ #[path = "../unsupported/args.rs"] pub mod args; pub mod env; -#[path = "../unsupported/fs.rs"] -pub mod fs; #[path = "../unsupported/os.rs"] pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -#[path = "../unsupported/stdio.rs"] -pub mod stdio; #[path = "../unsupported/time.rs"] pub mod time; diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index ebe207fde935c..6b5f9aeace28a 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -137,7 +137,7 @@ pub const fn to_utf16(s: &str) -> [u16; UTF16_LEN] { /// use frequent `as` casts. This is risky because they are too powerful. /// For example, the following will compile today: /// -/// `std::mem::size_of:: as u32` +/// `size_of:: as u32` /// /// Note that `size_of` is never actually called, instead a function pointer is /// converted to a `u32`. Clippy would warn about this but, alas, it's not run @@ -147,7 +147,7 @@ const fn win32_size_of() -> u32 { // Uses a trait to workaround restriction on using generic types in inner items. trait Win32SizeOf: Sized { const WIN32_SIZE_OF: u32 = { - let size = core::mem::size_of::(); + let size = size_of::(); assert!(size <= u32::MAX as usize); size as u32 }; diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 4fbdc839939c9..004cbee52f62a 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -6,7 +6,7 @@ #![allow(clippy::style)] use core::ffi::{CStr, c_uint, c_ulong, c_ushort, c_void}; -use core::{mem, ptr}; +use core::ptr; mod windows_sys; pub use windows_sys::*; @@ -39,7 +39,7 @@ pub fn nt_success(status: NTSTATUS) -> bool { impl UNICODE_STRING { pub fn from_ref(slice: &[u16]) -> Self { - let len = mem::size_of_val(slice); + let len = size_of_val(slice); Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ } } } @@ -47,7 +47,7 @@ impl UNICODE_STRING { impl Default for OBJECT_ATTRIBUTES { fn default() -> Self { Self { - Length: mem::size_of::() as _, + Length: size_of::() as _, RootDirectory: ptr::null_mut(), ObjectName: ptr::null_mut(), Attributes: 0, @@ -237,6 +237,17 @@ compat_fn_with_fallback! { STATUS_NOT_IMPLEMENTED } #[cfg(target_vendor = "uwp")] + pub fn NtOpenFile( + filehandle: *mut HANDLE, + desiredaccess: u32, + objectattributes: *const OBJECT_ATTRIBUTES, + iostatusblock: *mut IO_STATUS_BLOCK, + shareaccess: u32, + openoptions: u32 + ) -> NTSTATUS { + STATUS_NOT_IMPLEMENTED + } + #[cfg(target_vendor = "uwp")] pub fn NtReadFile( filehandle: HANDLE, event: HANDLE, diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index 38afb8c043b3b..aebf638239ca9 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -1,10 +1,10 @@ use core::ffi::c_void; +use core::ptr; use core::sync::atomic::{ AtomicBool, AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize, AtomicPtr, AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize, }; use core::time::Duration; -use core::{mem, ptr}; use super::api::{self, WinError}; use crate::sys::{c, dur2timeout}; @@ -61,7 +61,7 @@ pub fn wait_on_address( ) -> bool { unsafe { let addr = ptr::from_ref(address).cast::(); - let size = mem::size_of::(); + let size = size_of::(); let compare_addr = (&raw const compare).cast::(); let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE); c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 1eca346b76c2b..6eb68f3a3bc41 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -17,14 +17,12 @@ pub mod api; pub mod args; pub mod c; pub mod env; -pub mod fs; #[cfg(not(target_vendor = "win7"))] pub mod futex; pub mod handle; pub mod os; pub mod pipe; pub mod process; -pub mod stdio; pub mod thread; pub mod time; cfg_if::cfg_if! { @@ -37,7 +35,7 @@ cfg_if::cfg_if! { } /// Map a [`Result`] to [`io::Result`](crate::io::Result). -trait IoResult { +pub trait IoResult { fn io_result(self) -> crate::io::Result; } impl IoResult for Result { diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index a8f6617c9dc8f..8521cf4162f5c 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -151,7 +151,7 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res opts.write(ours_readable); opts.read(!ours_readable); opts.share_mode(0); - let size = mem::size_of::(); + let size = size_of::(); let mut sa = c::SECURITY_ATTRIBUTES { nLength: size as u32, lpSecurityDescriptor: ptr::null_mut(), diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index a41dfbfe6014d..c57ff355d124d 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -24,7 +24,7 @@ use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; use crate::sys_common::IntoInner; use crate::sys_common::process::{CommandEnv, CommandEnvs}; -use crate::{cmp, env, fmt, mem, ptr}; +use crate::{cmp, env, fmt, ptr}; //////////////////////////////////////////////////////////////////////////////// // Command @@ -260,9 +260,10 @@ impl Command { needs_stdin: bool, proc_thread_attribute_list: Option<&ProcThreadAttributeList<'_>>, ) -> io::Result<(Process, StdioPipes)> { + let env_saw_path = self.env.have_changed_path(); let maybe_env = self.env.capture_if_changed(); - let child_paths = if let Some(env) = maybe_env.as_ref() { + let child_paths = if env_saw_path && let Some(env) = maybe_env.as_ref() { env.get(&EnvKey::new("PATH")).map(|s| s.as_os_str()) } else { None @@ -354,7 +355,7 @@ impl Command { let mut si_ex; if let Some(proc_thread_attribute_list) = proc_thread_attribute_list { - si.cb = mem::size_of::() as u32; + si.cb = size_of::() as u32; flags |= c::EXTENDED_STARTUPINFO_PRESENT; si_ex = c::STARTUPINFOEXW { @@ -366,7 +367,7 @@ impl Command { }; si_ptr = (&raw mut si_ex) as _; } else { - si.cb = mem::size_of::() as u32; + si.cb = size_of::() as u32; si_ptr = (&raw mut si) as _; } @@ -598,7 +599,7 @@ impl Stdio { // permissions as well as the ability to be inherited to child // processes (as this is about to be inherited). Stdio::Null => { - let size = mem::size_of::(); + let size = size_of::(); let mut sa = c::SECURITY_ATTRIBUTES { nLength: size as u32, lpSecurityDescriptor: ptr::null_mut(), diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs index 1bd0e67f37162..7d823012ad145 100644 --- a/library/std/src/sys/pal/xous/mod.rs +++ b/library/std/src/sys/pal/xous/mod.rs @@ -3,14 +3,11 @@ pub mod args; #[path = "../unsupported/env.rs"] pub mod env; -#[path = "../unsupported/fs.rs"] -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; pub mod thread; pub mod time; diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs index 054c867f90d8e..499e27872015f 100644 --- a/library/std/src/sys/pal/zkvm/mod.rs +++ b/library/std/src/sys/pal/zkvm/mod.rs @@ -8,20 +8,17 @@ //! will likely change over time. #![forbid(unsafe_op_in_unsafe_fn)] -const WORD_SIZE: usize = core::mem::size_of::(); +const WORD_SIZE: usize = size_of::(); pub mod abi; #[path = "../zkvm/args.rs"] pub mod args; pub mod env; -#[path = "../unsupported/fs.rs"] -pub mod fs; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; #[path = "../unsupported/process.rs"] pub mod process; -pub mod stdio; #[path = "../unsupported/thread.rs"] pub mod thread; #[path = "../unsupported/time.rs"] diff --git a/library/std/src/sys/path/unix.rs b/library/std/src/sys/path/unix.rs index 361e99964f18c..faa2616a6320d 100644 --- a/library/std/src/sys/path/unix.rs +++ b/library/std/src/sys/path/unix.rs @@ -62,10 +62,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result { } pub(crate) fn is_absolute(path: &Path) -> bool { - if cfg!(target_os = "redox") { - // FIXME: Allow Redox prefixes - path.has_root() || crate::path::has_redox_scheme(path.as_u8_slice()) - } else if cfg!(any(unix, target_os = "hermit", target_os = "wasi")) { + if cfg!(any(unix, target_os = "hermit", target_os = "wasi")) { path.has_root() } else { path.has_root() && path.prefix().is_some() diff --git a/library/std/src/sys/personality/dwarf/eh.rs b/library/std/src/sys/personality/dwarf/eh.rs index 778d8686f023e..ef5112ad74f13 100644 --- a/library/std/src/sys/personality/dwarf/eh.rs +++ b/library/std/src/sys/personality/dwarf/eh.rs @@ -12,7 +12,7 @@ #![allow(non_upper_case_globals)] #![allow(unused)] -use core::{mem, ptr}; +use core::ptr; use super::DwarfReader; @@ -245,8 +245,7 @@ unsafe fn read_encoded_pointer( DW_EH_PE_datarel => (*context.get_data_start)(), // aligned means the value is aligned to the size of a pointer DW_EH_PE_aligned => { - reader.ptr = - reader.ptr.with_addr(round_up(reader.ptr.addr(), mem::size_of::<*const u8>())?); + reader.ptr = reader.ptr.with_addr(round_up(reader.ptr.addr(), size_of::<*const u8>())?); core::ptr::null() } _ => return Err(()), diff --git a/library/std/src/sys/personality/dwarf/mod.rs b/library/std/src/sys/personality/dwarf/mod.rs index 5c52d96c4cad4..2bc91951b49fd 100644 --- a/library/std/src/sys/personality/dwarf/mod.rs +++ b/library/std/src/sys/personality/dwarf/mod.rs @@ -12,8 +12,6 @@ mod tests; pub mod eh; -use core::mem; - pub struct DwarfReader { pub ptr: *const u8, } @@ -29,7 +27,7 @@ impl DwarfReader { pub unsafe fn read(&mut self) -> T { unsafe { let result = self.ptr.cast::().read_unaligned(); - self.ptr = self.ptr.byte_add(mem::size_of::()); + self.ptr = self.ptr.byte_add(size_of::()); result } } diff --git a/library/std/src/sys/random/mod.rs b/library/std/src/sys/random/mod.rs index f42351deb92c0..870039602bcf0 100644 --- a/library/std/src/sys/random/mod.rs +++ b/library/std/src/sys/random/mod.rs @@ -60,6 +60,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_os = "teeos")] { mod teeos; pub use teeos::fill_bytes; + } else if #[cfg(target_os = "trusty")] { + mod trusty; + pub use trusty::fill_bytes; } else if #[cfg(target_os = "uefi")] { mod uefi; pub use uefi::fill_bytes; diff --git a/library/std/src/sys/random/trusty.rs b/library/std/src/sys/random/trusty.rs new file mode 100644 index 0000000000000..da6ca3eea2426 --- /dev/null +++ b/library/std/src/sys/random/trusty.rs @@ -0,0 +1,7 @@ +extern "C" { + fn trusty_rng_secure_rand(randomBuffer: *mut core::ffi::c_void, randomBufferLen: libc::size_t); +} + +pub fn fill_bytes(bytes: &mut [u8]) { + unsafe { trusty_rng_secure_rand(bytes.as_mut_ptr().cast(), bytes.len()) } +} diff --git a/library/std/src/sys/stdio/mod.rs b/library/std/src/sys/stdio/mod.rs new file mode 100644 index 0000000000000..336d4c8527db3 --- /dev/null +++ b/library/std/src/sys/stdio/mod.rs @@ -0,0 +1,41 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +cfg_if::cfg_if! { + if #[cfg(any( + target_family = "unix", + target_os = "hermit" + ))] { + mod unix; + pub use unix::*; + } else if #[cfg(target_os = "windows")] { + mod windows; + pub use windows::*; + } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { + mod sgx; + pub use sgx::*; + } else if #[cfg(target_os = "solid_asp3")] { + mod solid; + pub use solid::*; + } else if #[cfg(target_os = "teeos")] { + mod teeos; + pub use teeos::*; + } else if #[cfg(target_os = "trusty")] { + mod trusty; + pub use trusty::*; + } else if #[cfg(target_os = "uefi")] { + mod uefi; + pub use uefi::*; + } else if #[cfg(target_os = "wasi")] { + mod wasi; + pub use wasi::*; + } else if #[cfg(target_os = "xous")] { + mod xous; + pub use xous::*; + } else if #[cfg(target_os = "zkvm")] { + mod zkvm; + pub use zkvm::*; + } else { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/library/std/src/sys/pal/unix/stdio.rs b/library/std/src/sys/stdio/sgx.rs similarity index 62% rename from library/std/src/sys/pal/unix/stdio.rs rename to library/std/src/sys/stdio/sgx.rs index 8c2f61a40de3b..1894c098d1851 100644 --- a/library/std/src/sys/pal/unix/stdio.rs +++ b/library/std/src/sys/stdio/sgx.rs @@ -1,12 +1,19 @@ +use fortanix_sgx_abi as abi; + use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; -use crate::mem::ManuallyDrop; -use crate::os::unix::io::FromRawFd; use crate::sys::fd::FileDesc; pub struct Stdin(()); pub struct Stdout(()); pub struct Stderr(()); +fn with_std_fd R, R>(fd: abi::Fd, f: F) -> R { + let fd = FileDesc::new(fd); + let ret = f(&fd); + fd.into_raw(); + ret +} + impl Stdin { pub const fn new() -> Stdin { Stdin(()) @@ -15,15 +22,15 @@ impl Stdin { impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read(buf) } + with_std_fd(abi::FD_STDIN, |fd| fd.read(buf)) } fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_buf(buf) } + with_std_fd(abi::FD_STDIN, |fd| fd.read_buf(buf)) } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDIN_FILENO)).read_vectored(bufs) } + with_std_fd(abi::FD_STDIN, |fd| fd.read_vectored(bufs)) } #[inline] @@ -40,24 +47,21 @@ impl Stdout { impl io::Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write(buf) } + with_std_fd(abi::FD_STDOUT, |fd| fd.write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + with_std_fd(abi::FD_STDOUT, |fd| fd.flush()) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDOUT_FILENO)).write_vectored(bufs) - } + with_std_fd(abi::FD_STDOUT, |fd| fd.write_vectored(bufs)) } #[inline] fn is_write_vectored(&self) -> bool { true } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } } impl Stderr { @@ -68,32 +72,30 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { - unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write(buf) } + with_std_fd(abi::FD_STDERR, |fd| fd.write(buf)) + } + + fn flush(&mut self) -> io::Result<()> { + with_std_fd(abi::FD_STDERR, |fd| fd.flush()) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - unsafe { - ManuallyDrop::new(FileDesc::from_raw_fd(libc::STDERR_FILENO)).write_vectored(bufs) - } + with_std_fd(abi::FD_STDERR, |fd| fd.write_vectored(bufs)) } #[inline] fn is_write_vectored(&self) -> bool { true } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } } +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; + pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::EBADF as i32) + // FIXME: Rust normally maps Unix EBADF to `Uncategorized` + err.raw_os_error() == Some(abi::Error::BrokenPipe as _) } -pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; - pub fn panic_output() -> Option { - Some(Stderr::new()) + crate::sys::pal::abi::panic::SgxPanicOutput::new() } diff --git a/library/std/src/sys/pal/solid/stdio.rs b/library/std/src/sys/stdio/solid.rs similarity index 98% rename from library/std/src/sys/pal/solid/stdio.rs rename to library/std/src/sys/stdio/solid.rs index 50f0176967b2d..a2ff4bb212ff5 100644 --- a/library/std/src/sys/pal/solid/stdio.rs +++ b/library/std/src/sys/stdio/solid.rs @@ -1,5 +1,5 @@ -use super::abi; use crate::io; +use crate::sys::pal::abi; pub struct Stdin; pub struct Stdout; diff --git a/library/std/src/sys/pal/teeos/stdio.rs b/library/std/src/sys/stdio/teeos.rs similarity index 100% rename from library/std/src/sys/pal/teeos/stdio.rs rename to library/std/src/sys/stdio/teeos.rs diff --git a/library/std/src/sys/stdio/trusty.rs b/library/std/src/sys/stdio/trusty.rs new file mode 100644 index 0000000000000..d393e95394d1a --- /dev/null +++ b/library/std/src/sys/stdio/trusty.rs @@ -0,0 +1,81 @@ +use crate::io; + +pub struct Stdin; +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub const fn new() -> Stdin { + Stdin + } +} + +impl io::Read for Stdin { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Ok(0) + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + _write(libc::STDOUT_FILENO, buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + _write(libc::STDERR_FILENO, buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} + +pub fn panic_output() -> Option { + Some(Stderr) +} + +fn _write(fd: i32, message: &[u8]) -> io::Result { + let mut iov = libc::iovec { iov_base: message.as_ptr() as *mut _, iov_len: message.len() }; + loop { + // SAFETY: syscall, safe arguments. + let ret = unsafe { libc::writev(fd, &iov, 1) }; + if ret < 0 { + return Err(io::Error::last_os_error()); + } + let ret = ret as usize; + if ret > iov.iov_len { + return Err(io::Error::last_os_error()); + } + if ret == iov.iov_len { + return Ok(message.len()); + } + // SAFETY: ret has been checked to be less than the length of + // the buffer + iov.iov_base = unsafe { iov.iov_base.add(ret) }; + iov.iov_len -= ret; + } +} diff --git a/library/std/src/sys/pal/uefi/stdio.rs b/library/std/src/sys/stdio/uefi.rs similarity index 99% rename from library/std/src/sys/pal/uefi/stdio.rs rename to library/std/src/sys/stdio/uefi.rs index d049d19bc83ee..257e321dd03d7 100644 --- a/library/std/src/sys/pal/uefi/stdio.rs +++ b/library/std/src/sys/stdio/uefi.rs @@ -71,7 +71,7 @@ impl io::Read for Stdin { }; if ch.len() > 1 { - return Err(io::const_error!(io::ErrorKind::InvalidData, "invalid utf-16 sequence")); + return Err(io::const_error!(io::ErrorKind::InvalidData, "invalid UTF-16 sequence")); } match ch.pop().unwrap() { diff --git a/library/std/src/sys/stdio/unix.rs b/library/std/src/sys/stdio/unix.rs new file mode 100644 index 0000000000000..8d133857c596d --- /dev/null +++ b/library/std/src/sys/stdio/unix.rs @@ -0,0 +1,106 @@ +#[cfg(target_os = "hermit")] +use hermit_abi::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; +#[cfg(target_family = "unix")] +use libc::{EBADF, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; + +#[cfg(target_family = "unix")] +use crate::io::BorrowedCursor; +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::mem::ManuallyDrop; +#[cfg(target_os = "hermit")] +use crate::os::hermit::io::FromRawFd; +#[cfg(target_family = "unix")] +use crate::os::unix::io::FromRawFd; +use crate::sys::fd::FileDesc; + +pub struct Stdin(()); +pub struct Stdout(()); +pub struct Stderr(()); + +impl Stdin { + pub const fn new() -> Stdin { + Stdin(()) + } +} + +impl io::Read for Stdin { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read(buf) } + } + + #[cfg(not(target_os = "hermit"))] + fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_buf(buf) } + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDIN_FILENO)).read_vectored(bufs) } + } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } +} + +impl Stdout { + pub const fn new() -> Stdout { + Stdout(()) + } +} + +impl io::Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDOUT_FILENO)).write(buf) } + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDOUT_FILENO)).write_vectored(bufs) } + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +impl Stderr { + pub const fn new() -> Stderr { + Stderr(()) + } +} + +impl io::Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDERR_FILENO)).write(buf) } + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + unsafe { ManuallyDrop::new(FileDesc::from_raw_fd(STDERR_FILENO)).write_vectored(bufs) } + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(EBADF as i32) +} + +pub const STDIN_BUF_SIZE: usize = crate::sys::io::DEFAULT_BUF_SIZE; + +pub fn panic_output() -> Option { + Some(Stderr::new()) +} diff --git a/library/std/src/sys/pal/unsupported/stdio.rs b/library/std/src/sys/stdio/unsupported.rs similarity index 100% rename from library/std/src/sys/pal/unsupported/stdio.rs rename to library/std/src/sys/stdio/unsupported.rs diff --git a/library/std/src/sys/pal/wasi/stdio.rs b/library/std/src/sys/stdio/wasi.rs similarity index 98% rename from library/std/src/sys/pal/wasi/stdio.rs rename to library/std/src/sys/stdio/wasi.rs index fb21cb4d393d0..8105b0cfa2f15 100644 --- a/library/std/src/sys/pal/wasi/stdio.rs +++ b/library/std/src/sys/stdio/wasi.rs @@ -1,10 +1,10 @@ #![forbid(unsafe_op_in_unsafe_fn)] -use super::fd::WasiFd; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::os::raw; use crate::os::wasi::io::{AsRawFd, FromRawFd}; +use crate::sys::pal::fd::WasiFd; pub struct Stdin; pub struct Stdout; diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/stdio/windows.rs similarity index 99% rename from library/std/src/sys/pal/windows/stdio.rs rename to library/std/src/sys/stdio/windows.rs index 1b245991aa797..9b27f76b9dd1a 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/stdio/windows.rs @@ -3,10 +3,10 @@ use core::char::MAX_LEN_UTF8; use core::str::utf8_char_width; -use super::api::{self, WinError}; use crate::mem::MaybeUninit; use crate::os::windows::io::{FromRawHandle, IntoRawHandle}; use crate::sys::handle::Handle; +use crate::sys::pal::api::{self, WinError}; use crate::sys::{c, cvt}; use crate::{cmp, io, ptr, str}; @@ -359,7 +359,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit]) -> io::Result() as u32, + nLength: size_of::() as u32, nInitialChars: 0, dwCtrlWakeupMask: CTRL_Z_MASK, dwControlKeyState: 0, diff --git a/library/std/src/sys/pal/windows/stdio/tests.rs b/library/std/src/sys/stdio/windows/tests.rs similarity index 100% rename from library/std/src/sys/pal/windows/stdio/tests.rs rename to library/std/src/sys/stdio/windows/tests.rs diff --git a/library/std/src/sys/pal/xous/stdio.rs b/library/std/src/sys/stdio/xous.rs similarity index 98% rename from library/std/src/sys/pal/xous/stdio.rs rename to library/std/src/sys/stdio/xous.rs index dfd47a1775ae2..717361452213b 100644 --- a/library/std/src/sys/pal/xous/stdio.rs +++ b/library/std/src/sys/stdio/xous.rs @@ -87,7 +87,7 @@ pub struct PanicWriter { impl io::Write for PanicWriter { fn write(&mut self, s: &[u8]) -> core::result::Result { - for c in s.chunks(core::mem::size_of::() * 4) { + for c in s.chunks(size_of::() * 4) { // Text is grouped into 4x `usize` words. The id is 1100 plus // the number of characters in this message. // Ignore errors since we're already panicking. diff --git a/library/std/src/sys/pal/zkvm/stdio.rs b/library/std/src/sys/stdio/zkvm.rs similarity index 77% rename from library/std/src/sys/pal/zkvm/stdio.rs rename to library/std/src/sys/stdio/zkvm.rs index 5f1d06dd1d78d..f31c6c26e87cd 100644 --- a/library/std/src/sys/pal/zkvm/stdio.rs +++ b/library/std/src/sys/stdio/zkvm.rs @@ -1,6 +1,5 @@ -use super::abi; -use super::abi::fileno; -use crate::io; +use crate::io::{self, BorrowedCursor}; +use crate::sys::pal::abi::{self, fileno}; pub struct Stdin; pub struct Stdout; @@ -16,6 +15,14 @@ impl io::Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { Ok(unsafe { abi::sys_read(fileno::STDIN, buf.as_mut_ptr(), buf.len()) }) } + + fn read_buf(&mut self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { + unsafe { + let n = abi::sys_read(fileno::STDIN, buf.as_mut().as_mut_ptr().cast(), buf.capacity()); + buf.advance_unchecked(n); + } + Ok(()) + } } impl Stdout { diff --git a/library/std/src/sys/thread_local/key/xous.rs b/library/std/src/sys/thread_local/key/xous.rs index 55ac5b20e1ab0..48dfe17ab3261 100644 --- a/library/std/src/sys/thread_local/key/xous.rs +++ b/library/std/src/sys/thread_local/key/xous.rs @@ -85,7 +85,7 @@ fn tls_table() -> &'static mut [*mut u8] { if !tp.is_null() { return unsafe { - core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / core::mem::size_of::<*mut u8>()) + core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / size_of::<*mut u8>()) }; } // If the TP register is `0`, then this thread hasn't initialized @@ -94,7 +94,7 @@ fn tls_table() -> &'static mut [*mut u8] { map_memory( None, None, - TLS_MEMORY_SIZE / core::mem::size_of::<*mut u8>(), + TLS_MEMORY_SIZE / size_of::<*mut u8>(), MemoryFlags::R | MemoryFlags::W, ) .expect("Unable to allocate memory for thread local storage") @@ -177,11 +177,8 @@ pub unsafe fn destroy_tls() { // Finally, free the TLS array unsafe { - unmap_memory(core::slice::from_raw_parts_mut( - tp, - TLS_MEMORY_SIZE / core::mem::size_of::(), - )) - .unwrap() + unmap_memory(core::slice::from_raw_parts_mut(tp, TLS_MEMORY_SIZE / size_of::())) + .unwrap() }; } diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index f0a13323ec93f..1ff13154b7b3c 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -28,6 +28,7 @@ cfg_if::cfg_if! { all(target_family = "wasm", not(target_feature = "atomics")), target_os = "uefi", target_os = "zkvm", + target_os = "trusty", ))] { mod statik; pub use statik::{EagerStorage, LazyStorage, thread_local_inner}; @@ -91,6 +92,7 @@ pub(crate) mod guard { )), target_os = "uefi", target_os = "zkvm", + target_os = "trusty", ))] { pub(crate) fn enable() { // FIXME: Right now there is no concept of "thread exit" on diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 4dc67d26bd8ff..2a5de7f66661c 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -20,7 +20,6 @@ #[cfg(test)] mod tests; -pub mod fs; pub mod process; pub mod wstr; pub mod wtf8; diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 952c39132b056..f9ec112b19747 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -169,6 +169,18 @@ impl fmt::Debug for Wtf8Buf { } } +/// Formats the string with unpaired surrogates substituted with the replacement +/// character, U+FFFD. +impl fmt::Display for Wtf8Buf { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(s) = self.as_known_utf8() { + fmt::Display::fmt(s, formatter) + } else { + fmt::Display::fmt(&**self, formatter) + } + } +} + impl Wtf8Buf { /// Creates a new, empty WTF-8 string. #[inline] @@ -262,6 +274,18 @@ impl Wtf8Buf { unsafe { Wtf8::from_mut_bytes_unchecked(&mut self.bytes) } } + /// Converts the string to UTF-8 without validation, if it was created from + /// valid UTF-8. + #[inline] + fn as_known_utf8(&self) -> Option<&str> { + if self.is_known_utf8 { + // SAFETY: The buffer is known to be valid UTF-8. + Some(unsafe { str::from_utf8_unchecked(self.as_bytes()) }) + } else { + None + } + } + /// Reserves capacity for at least `additional` more bytes to be inserted /// in the given `Wtf8Buf`. /// The collection may reserve more space to avoid frequent reallocations. @@ -364,7 +388,7 @@ impl Wtf8Buf { _ => { // If we'll be pushing a string containing a surrogate, we may // no longer have UTF-8. - if other.next_surrogate(0).is_some() { + if self.is_known_utf8 && other.next_surrogate(0).is_some() { self.is_known_utf8 = false; } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index ca04aa4ada497..d5a5d10205dd8 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -50,7 +50,8 @@ use crate::fmt; /// use std::cell::Cell; /// use std::thread; /// -/// thread_local!(static FOO: Cell = Cell::new(1)); +/// // explicit `const {}` block enables more efficient initialization +/// thread_local!(static FOO: Cell = const { Cell::new(1) }); /// /// assert_eq!(FOO.get(), 1); /// FOO.set(2); @@ -138,7 +139,7 @@ impl fmt::Debug for LocalKey { /// use std::cell::{Cell, RefCell}; /// /// thread_local! { -/// pub static FOO: Cell = Cell::new(1); +/// pub static FOO: Cell = const { Cell::new(1) }; /// /// static BAR: RefCell> = RefCell::new(vec![1.0, 2.0]); /// } @@ -394,7 +395,7 @@ impl LocalKey> { /// use std::cell::Cell; /// /// thread_local! { - /// static X: Cell = Cell::new(1); + /// static X: Cell = const { Cell::new(1) }; /// } /// /// assert_eq!(X.get(), 1); @@ -423,7 +424,7 @@ impl LocalKey> { /// use std::cell::Cell; /// /// thread_local! { - /// static X: Cell> = Cell::new(Some(1)); + /// static X: Cell> = const { Cell::new(Some(1)) }; /// } /// /// assert_eq!(X.take(), Some(1)); @@ -453,7 +454,7 @@ impl LocalKey> { /// use std::cell::Cell; /// /// thread_local! { - /// static X: Cell = Cell::new(1); + /// static X: Cell = const { Cell::new(1) }; /// } /// /// assert_eq!(X.replace(2), 1); diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 59b395336f2e3..3f3ba02361cc8 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -1739,7 +1739,16 @@ struct JoinInner<'scope, T> { impl<'scope, T> JoinInner<'scope, T> { fn join(mut self) -> Result { self.native.join(); - Arc::get_mut(&mut self.packet).unwrap().result.get_mut().take().unwrap() + Arc::get_mut(&mut self.packet) + // FIXME(fuzzypixelz): returning an error instead of panicking here + // would require updating the documentation of + // `std::thread::Result`; currently we can return `Err` if and only + // if the thread had panicked. + .expect("threads should not terminate unexpectedly") + .result + .get_mut() + .take() + .unwrap() } } diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index ff45e82bd9c71..06c347af1819f 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -1,12 +1,12 @@ use super::Builder; use crate::any::Any; use crate::panic::panic_any; +use crate::result; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::mpsc::{Sender, channel}; use crate::sync::{Arc, Barrier}; use crate::thread::{self, Scope, ThreadId}; use crate::time::{Duration, Instant}; -use crate::{mem, result}; // !!! These tests are dangerous. If something is buggy, they will hang, !!! // !!! instead of exiting cleanly. This might wedge the buildbots. !!! @@ -327,7 +327,7 @@ fn sleep_ms_smoke() { #[test] fn test_size_of_option_thread_id() { - assert_eq!(mem::size_of::>(), mem::size_of::()); + assert_eq!(size_of::>(), size_of::()); } #[test] diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs index 5180f3d40f3a7..19389a9178e91 100644 --- a/library/std/tests/floats/f16.rs +++ b/library/std/tests/floats/f16.rs @@ -461,18 +461,16 @@ fn test_recip() { #[test] #[cfg(reliable_f16_math)] fn test_powi() { - // FIXME(llvm19): LLVM misoptimizes `powi.f16` - // - // let nan: f16 = f16::NAN; - // let inf: f16 = f16::INFINITY; - // let neg_inf: f16 = f16::NEG_INFINITY; - // assert_eq!(1.0f16.powi(1), 1.0); - // assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); - // assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); - // assert_eq!(8.3f16.powi(0), 1.0); - // assert!(nan.powi(2).is_nan()); - // assert_eq!(inf.powi(3), inf); - // assert_eq!(neg_inf.powi(2), inf); + let nan: f16 = f16::NAN; + let inf: f16 = f16::INFINITY; + let neg_inf: f16 = f16::NEG_INFINITY; + assert_eq!(1.0f16.powi(1), 1.0); + assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0); + assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2); + assert_eq!(8.3f16.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); } #[test] @@ -813,6 +811,7 @@ fn test_clamp_max_is_nan() { } #[test] +#[cfg(reliable_f16_math)] fn test_total_cmp() { use core::cmp::Ordering; @@ -820,14 +819,13 @@ fn test_total_cmp() { 1 << (f16::MANTISSA_DIGITS - 2) } - // FIXME(f16_f128): test subnormals when powf is available - // fn min_subnorm() -> f16 { - // f16::MIN_POSITIVE / f16::powf(2.0, f16::MANTISSA_DIGITS as f16 - 1.0) - // } + fn min_subnorm() -> f16 { + f16::MIN_POSITIVE / f16::powf(2.0, f16::MANTISSA_DIGITS as f16 - 1.0) + } - // fn max_subnorm() -> f16 { - // f16::MIN_POSITIVE - min_subnorm() - // } + fn max_subnorm() -> f16 { + f16::MIN_POSITIVE - min_subnorm() + } fn q_nan() -> f16 { f16::from_bits(f16::NAN.to_bits() | quiet_bit_mask()) @@ -846,12 +844,12 @@ fn test_total_cmp() { assert_eq!(Ordering::Equal, (-1.5_f16).total_cmp(&-1.5)); assert_eq!(Ordering::Equal, (-0.5_f16).total_cmp(&-0.5)); assert_eq!(Ordering::Equal, (-f16::MIN_POSITIVE).total_cmp(&-f16::MIN_POSITIVE)); - // assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); assert_eq!(Ordering::Equal, (-0.0_f16).total_cmp(&-0.0)); assert_eq!(Ordering::Equal, 0.0_f16.total_cmp(&0.0)); - // assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); assert_eq!(Ordering::Equal, f16::MIN_POSITIVE.total_cmp(&f16::MIN_POSITIVE)); assert_eq!(Ordering::Equal, 0.5_f16.total_cmp(&0.5)); assert_eq!(Ordering::Equal, 1.0_f16.total_cmp(&1.0)); @@ -870,13 +868,13 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-1.5_f16).total_cmp(&-1.0)); assert_eq!(Ordering::Less, (-1.0_f16).total_cmp(&-0.5)); assert_eq!(Ordering::Less, (-0.5_f16).total_cmp(&-f16::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-f16::MIN_POSITIVE).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - // assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-f16::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); assert_eq!(Ordering::Less, (-0.0_f16).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, 0.0_f16.total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - // assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f16::MIN_POSITIVE)); + assert_eq!(Ordering::Less, 0.0_f16.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f16::MIN_POSITIVE)); assert_eq!(Ordering::Less, f16::MIN_POSITIVE.total_cmp(&0.5)); assert_eq!(Ordering::Less, 0.5_f16.total_cmp(&1.0)); assert_eq!(Ordering::Less, 1.0_f16.total_cmp(&1.5)); @@ -894,13 +892,13 @@ fn test_total_cmp() { assert_eq!(Ordering::Greater, (-1.0_f16).total_cmp(&-1.5)); assert_eq!(Ordering::Greater, (-0.5_f16).total_cmp(&-1.0)); assert_eq!(Ordering::Greater, (-f16::MIN_POSITIVE).total_cmp(&-0.5)); - // assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f16::MIN_POSITIVE)); - // assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Greater, (-0.0_f16).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f16::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f16).total_cmp(&-min_subnorm())); assert_eq!(Ordering::Greater, 0.0_f16.total_cmp(&-0.0)); - // assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - // assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Greater, f16::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f16::MIN_POSITIVE.total_cmp(&max_subnorm())); assert_eq!(Ordering::Greater, 0.5_f16.total_cmp(&f16::MIN_POSITIVE)); assert_eq!(Ordering::Greater, 1.0_f16.total_cmp(&0.5)); assert_eq!(Ordering::Greater, 1.5_f16.total_cmp(&1.0)); @@ -918,12 +916,12 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f16::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f16::MIN_POSITIVE)); assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); @@ -940,12 +938,12 @@ fn test_total_cmp() { assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f16::MIN_POSITIVE)); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - // assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f16::MIN_POSITIVE)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index dd14c0266aa4d..e59ae2f3d7f18 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -8,6 +8,10 @@ all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")), feature(stdarch_aarch64_feature_detection) )] +#![cfg_attr( + all(target_arch = "s390x", target_os = "linux"), + feature(stdarch_s390x_feature_detection) +)] #![cfg_attr( all(target_arch = "powerpc", target_os = "linux"), feature(stdarch_powerpc_feature_detection) @@ -132,6 +136,32 @@ fn powerpc64_linux() { // tidy-alphabetical-end } +#[test] +#[cfg(all(target_arch = "s390x", target_os = "linux"))] +fn s390x_linux() { + use std::arch::is_s390x_feature_detected; + // tidy-alphabetical-start + println!("deflate-conversion: {}", is_s390x_feature_detected!("deflate-conversion")); + println!("enhanced-sort: {}", is_s390x_feature_detected!("enhanced-sort")); + println!("guarded-storage: {}", is_s390x_feature_detected!("guarded-storage")); + println!("high-word: {}", is_s390x_feature_detected!("high-word")); + println!("nnp-assist: {}", is_s390x_feature_detected!("nnp-assist")); + println!("transactional-execution: {}", is_s390x_feature_detected!("transactional-execution")); + println!("vector-enhancements-1: {}", is_s390x_feature_detected!("vector-enhancements-1")); + println!("vector-enhancements-2: {}", is_s390x_feature_detected!("vector-enhancements-2")); + println!( + "vector-packed-decimal-enhancement-2: {}", + is_s390x_feature_detected!("vector-packed-decimal-enhancement-2") + ); + println!( + "vector-packed-decimal-enhancement: {}", + is_s390x_feature_detected!("vector-packed-decimal-enhancement") + ); + println!("vector-packed-decimal: {}", is_s390x_feature_detected!("vector-packed-decimal")); + println!("vector: {}", is_s390x_feature_detected!("vector")); + // tidy-alphabetical-end +} + #[test] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn x86_all() { diff --git a/library/stdarch b/library/stdarch index 684de0d6fef70..9426bb56586c6 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 684de0d6fef708cae08214fef9643dd9ec7296e1 +Subproject commit 9426bb56586c6ae4095a2dcbd66c570253e6fb32 diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 6ed2756e526d6..ec6ae31507e05 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -1,14 +1,16 @@ +cargo-features = ["public-dependency"] + [package] name = "sysroot" version = "0.0.0" -edition = "2021" +edition = "2024" # this is a dummy crate to ensure that all required crates appear in the sysroot [dependencies] -proc_macro = { path = "../proc_macro" } +proc_macro = { path = "../proc_macro", public = true } profiler_builtins = { path = "../profiler_builtins", optional = true } -std = { path = "../std" } -test = { path = "../test" } +std = { path = "../std", public = true } +test = { path = "../test", public = true } # Forward features to the `std` crate as necessary [features] diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 75cc7c00e389c..2a32a7dd76eed 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -1,12 +1,14 @@ +cargo-features = ["public-dependency"] + [package] name = "test" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] getopts = { version = "0.2.21", features = ['rustc-dep-of-std'] } -std = { path = "../std" } -core = { path = "../core" } +std = { path = "../std", public = true } +core = { path = "../core", public = true } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.150", default-features = false } diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs index 36158b0258a6f..84153a9d05b59 100644 --- a/library/test/src/formatters/junit.rs +++ b/library/test/src/formatters/junit.rs @@ -39,15 +39,15 @@ fn str_to_cdata(s: &str) -> String { impl OutputFormatter for JunitFormatter { fn write_discovery_start(&mut self) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::NotFound, "Not yet implemented!")) + Err(io::const_error!(io::ErrorKind::NotFound, "not yet implemented!")) } fn write_test_discovered(&mut self, _desc: &TestDesc, _test_type: &str) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::NotFound, "Not yet implemented!")) + Err(io::const_error!(io::ErrorKind::NotFound, "not yet implemented!")) } fn write_discovery_finish(&mut self, _state: &ConsoleTestDiscoveryState) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::NotFound, "Not yet implemented!")) + Err(io::const_error!(io::ErrorKind::NotFound, "not yet implemented!")) } fn write_run_start( diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index 66e8d1a3ffe5f..da60924c2b419 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -3,7 +3,7 @@ name = "unwind" version = "0.0.0" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" -edition = "2021" +edition = "2024" include = [ '/libunwind/*', ] diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 761f924844620..5451a38a674ca 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] +#![feature(cfg_emscripten_wasm_eh)] #![feature(link_cfg)] #![feature(staged_api)] #![cfg_attr(not(target_env = "msvc"), feature(libc))] @@ -8,7 +9,6 @@ feature(simd_wasm64, wasm_exception_handling_intrinsics) )] #![allow(internal_features)] -#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] #![deny(unsafe_op_in_unsafe_fn)] // Force libc to be included even if unused. This is required by many platforms. diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 1a640bbde71d7..ced8e82b8ebe8 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -72,9 +72,12 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_os = "emscripten")] +#[cfg(all(target_arch = "wasm32", target_os = "emscripten"))] pub const unwinder_private_data_size: usize = 20; +#[cfg(all(target_arch = "wasm32", target_os = "linux"))] +pub const unwinder_private_data_size: usize = 2; + #[cfg(all(target_arch = "hexagon", target_os = "linux"))] pub const unwinder_private_data_size: usize = 35; diff --git a/library/unwind/src/unwinding.rs b/library/unwind/src/unwinding.rs index 1b94005ab6cd0..fa8a8c385839b 100644 --- a/library/unwind/src/unwinding.rs +++ b/library/unwind/src/unwinding.rs @@ -39,9 +39,9 @@ pub type _Unwind_Exception_Class = u64; pub type _Unwind_Word = *const u8; pub type _Unwind_Ptr = *const u8; -pub const unwinder_private_data_size: usize = core::mem::size_of::() - - core::mem::size_of::<_Unwind_Exception_Class>() - - core::mem::size_of::<_Unwind_Exception_Cleanup_Fn>(); +pub const unwinder_private_data_size: usize = size_of::() + - size_of::<_Unwind_Exception_Class>() + - size_of::<_Unwind_Exception_Cleanup_Fn>(); pub type _Unwind_Exception_Cleanup_Fn = Option; diff --git a/library/windows_targets/Cargo.toml b/library/windows_targets/Cargo.toml index 94d7c8210647c..705c9e0438119 100644 --- a/library/windows_targets/Cargo.toml +++ b/library/windows_targets/Cargo.toml @@ -2,7 +2,7 @@ name = "windows-targets" description = "A drop-in replacement for the real windows-targets crate for use in std only." version = "0.0.0" -edition = "2021" +edition = "2024" [features] # Enable using raw-dylib for Windows imports. diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index e89bde8b1abf4..c7d158584ebd8 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -12,7 +12,7 @@ pub macro link { ($library:literal $abi:literal $($link_name:literal)? $(#[$doc:meta])? fn $($function:tt)*) => ( #[cfg_attr(not(target_arch = "x86"), link(name = $library, kind = "raw-dylib", modifiers = "+verbatim"))] #[cfg_attr(target_arch = "x86", link(name = $library, kind = "raw-dylib", modifiers = "+verbatim", import_name_type = "undecorated"))] - extern $abi { + unsafe extern $abi { $(#[link_name=$link_name])? pub fn $($function)*; } @@ -26,7 +26,7 @@ pub macro link { // libraries below by using an empty extern block. This works because extern blocks are not // connected to the library given in the #[link] attribute. #[link(name = "kernel32")] - extern $abi { + unsafe extern $abi { $(#[link_name=$link_name])? pub fn $($function)*; } @@ -34,7 +34,7 @@ pub macro link { } #[cfg(not(feature = "windows_raw_dylib"))] -#[link(name = "advapi32")] +#[cfg_attr(target_vendor = "win7", link(name = "advapi32"))] #[link(name = "ntdll")] #[link(name = "userenv")] #[link(name = "ws2_32")] diff --git a/license-metadata.json b/license-metadata.json index 4cf9bea2861d4..4fb59210854e9 100644 --- a/license-metadata.json +++ b/license-metadata.json @@ -13,7 +13,8 @@ "directories": [], "files": [ "analyzer-decls.h", - "malloc-macro.h" + "malloc-macro.h", + "sarif-path-role.h" ], "license": { "copyright": [ diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index a47f3af60cbd5..890e64e2babbc 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -88,9 +88,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.0" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aeb932158bd710538c73702db6945cb68a8fb08c519e6e12706b94263b36db8" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "shlex", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index ed51862390d40..d3e2b9e05e99c 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bootstrap" version = "0.0.0" -edition = "2021" +edition = "2024" build = "build.rs" default-run = "bootstrap" @@ -28,16 +28,13 @@ name = "rustdoc" path = "src/bin/rustdoc.rs" test = false -[[bin]] -name = "sccache-plus-cl" -path = "src/bin/sccache-plus-cl.rs" -test = false - [dependencies] # Most of the time updating these dependencies requires modifications to the # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565); # otherwise, some targets will fail. That's why these dependencies are explicitly pinned. -cc = "=1.2.0" +# +# Do not upgrade this crate unless https://github.com/rust-lang/cc-rs/issues/1317 is fixed. +cc = "=1.1.22" cmake = "=0.1.48" build_helper = { path = "../build_helper" } diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index ac971a64d7c22..77151edd240b9 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -269,6 +269,11 @@ def v(*args): "target.loongarch64-unknown-linux-musl.musl-root", "loongarch64-unknown-linux-musl install directory", ) +v( + "musl-root-wali-wasm32", + "target.wasm32-wali-linux-musl.musl-root", + "wasm32-wali-linux-musl install directory", +) v( "qemu-armhf-rootfs", "target.arm-unknown-linux-gnueabihf.qemu-rootfs", @@ -292,7 +297,7 @@ def v(*args): v("release-channel", "rust.channel", "the name of the release channel to build") v( "release-description", - "rust.description", + "build.description", "optional descriptive string for version output", ) v("dist-compression-formats", None, "List of compression formats to use") @@ -776,6 +781,6 @@ def quit_if_file_exists(file): f.write(contents) p("") - p("run `python {}/x.py --help`".format(rust_dir)) + p("run `{} {}/x.py --help`".format(os.path.basename(sys.executable), rust_dir)) if "GITHUB_ACTIONS" in os.environ: print("::endgroup::") diff --git a/src/bootstrap/defaults/config.tools.toml b/src/bootstrap/defaults/config.tools.toml index 64097320caba7..57c2706f60a56 100644 --- a/src/bootstrap/defaults/config.tools.toml +++ b/src/bootstrap/defaults/config.tools.toml @@ -8,6 +8,8 @@ incremental = true download-rustc = "if-unchanged" [build] +# cargo and clippy tests don't pass on stage 1 +test-stage = 2 # Document with the in-tree rustdoc by default, since `download-rustc` makes it quick to compile. doc-stage = 2 # Contributors working on tools will probably expect compiler docs to be generated, so they can figure out how to use the API. diff --git a/src/bootstrap/download-ci-gcc-stamp b/src/bootstrap/download-ci-gcc-stamp new file mode 100644 index 0000000000000..bbe26afc95269 --- /dev/null +++ b/src/bootstrap/download-ci-gcc-stamp @@ -0,0 +1,4 @@ +Change this file to make users of the `download-ci-gcc` configuration download +a new version of GCC from CI, even if the GCC submodule hasn’t changed. + +Last change is for: https://github.com/rust-lang/rust/pull/138051 diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 88aa70d4f2f83..6cb0b19d7632a 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -56,6 +56,7 @@ check-aux: # Run standard library tests in Miri. $(Q)$(BOOTSTRAP) miri --stage 2 \ library/coretests \ + library/alloctests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --no-doc @@ -63,6 +64,7 @@ check-aux: $(Q)MIRIFLAGS="-Zmiri-disable-isolation" \ $(BOOTSTRAP) miri --stage 2 \ library/coretests \ + library/alloctests \ library/alloc \ $(BOOTSTRAP_ARGS) \ --doc diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 38b380e3db824..6f6aaa878ef6f 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -70,11 +70,12 @@ fn main() { } // check_version warnings are not printed during setup, or during CI - let changelog_suggestion = if matches!(config.cmd, Subcommand::Setup { .. }) || CiEnv::is_ci() { - None - } else { - check_version(&config) - }; + let changelog_suggestion = + if matches!(config.cmd, Subcommand::Setup { .. }) || CiEnv::is_ci() || config.dry_run() { + None + } else { + check_version(&config) + }; // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the // changelog warning, not the `x.py setup` message. @@ -187,7 +188,7 @@ fn check_version(config: &Config) -> Option { "update `config.toml` to use `change-id = {latest_change_id}` instead" )); - if io::stdout().is_terminal() && !config.dry_run() { + if io::stdout().is_terminal() { t!(fs::write(warned_id_path, latest_change_id.to_string())); } } else { diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 6104506759282..d8cae02456c0e 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -349,7 +349,7 @@ fn format_rusage_data(child: Child) -> Option { let mut kernel_filetime = Default::default(); let mut kernel_time = Default::default(); let mut memory_counters = PROCESS_MEMORY_COUNTERS::default(); - let memory_counters_size = std::mem::size_of_val(&memory_counters); + let memory_counters_size = size_of_val(&memory_counters); unsafe { GetProcessTimes( diff --git a/src/bootstrap/src/bin/sccache-plus-cl.rs b/src/bootstrap/src/bin/sccache-plus-cl.rs deleted file mode 100644 index 6e87d4222e863..0000000000000 --- a/src/bootstrap/src/bin/sccache-plus-cl.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::env; -use std::process::{self, Command}; - -fn main() { - let target = env::var("SCCACHE_TARGET").unwrap(); - // Locate the actual compiler that we're invoking - env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); - env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); - let mut cfg = cc::Build::new(); - cfg.cargo_metadata(false) - .out_dir("/") - .target(&target) - .host(&target) - .opt_level(0) - .warnings(false) - .debug(false); - let compiler = cfg.get_compiler(); - - // Invoke sccache with said compiler - let sccache_path = env::var_os("SCCACHE_PATH").unwrap(); - let mut cmd = Command::new(sccache_path); - cmd.arg(compiler.path()); - for (k, v) in compiler.env() { - cmd.env(k, v); - } - for arg in env::args().skip(1) { - cmd.arg(arg); - } - - if let Ok(s) = env::var("SCCACHE_EXTRA_ARGS") { - for s in s.split_whitespace() { - cmd.arg(s); - } - } - - let status = cmd.status().expect("failed to spawn"); - process::exit(status.code().unwrap_or(2)) -} diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 21afb0312033a..e67bc62a60352 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -45,7 +45,10 @@ impl Step for Std { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").crate_or_deps("coretests").path("library") + run.crate_or_deps("sysroot") + .crate_or_deps("coretests") + .crate_or_deps("alloctests") + .path("library") } fn make_run(run: RunConfig<'_>) { @@ -69,7 +72,7 @@ impl Step for Std { ); std_cargo(builder, target, compiler.stage, &mut cargo); - if matches!(builder.config.cmd, Subcommand::Fix { .. }) { + if matches!(builder.config.cmd, Subcommand::Fix) { // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot. cargo.arg("--lib"); } @@ -451,7 +454,6 @@ tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc" tool_check_step!(Clippy { path: "src/tools/clippy" }); tool_check_step!(Miri { path: "src/tools/miri" }); tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri" }); -tool_check_step!(Rls { path: "src/tools/rls" }); tool_check_step!(Rustfmt { path: "src/tools/rustfmt" }); tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools" }); tool_check_step!(TestFloatParse { path: "src/etc/test-float-parse" }); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index fe8c89f7a5394..d3ab215d1b527 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -346,7 +346,6 @@ lint_any!( OptDist, "src/tools/opt-dist", "opt-dist"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; RemoteTestServer, "src/tools/remote-test-server", "remote-test-server"; - Rls, "src/tools/rls", "rls"; RustAnalyzer, "src/tools/rust-analyzer", "rust-analyzer"; Rustdoc, "src/librustdoc", "clippy"; Rustfmt, "src/tools/rustfmt", "rustfmt"; diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 8e9b5856096ae..7c83c53d2c2c2 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -19,6 +19,7 @@ use serde_derive::Deserialize; #[cfg(feature = "tracing")] use tracing::{instrument, span}; +use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::tool::SourceType; use crate::core::build_steps::{dist, llvm}; use crate::core::builder; @@ -66,7 +67,7 @@ impl Std { self } - #[allow(clippy::wrong_self_convention)] + #[expect(clippy::wrong_self_convention)] pub fn is_for_mir_opt_tests(mut self, is_for_mir_opt_tests: bool) -> Self { self.is_for_mir_opt_tests = is_for_mir_opt_tests; self @@ -193,11 +194,7 @@ impl Step for Std { trace!(?compiler_to_use); if compiler_to_use != compiler { - trace!( - ?compiler_to_use, - ?compiler, - "compiler != compiler_to_use, handling cross-compile scenario" - ); + trace!(?compiler_to_use, ?compiler, "compiler != compiler_to_use, uplifting library"); builder.ensure(Std::new(compiler_to_use, target)); let msg = if compiler_to_use.host == target { @@ -389,24 +386,38 @@ fn copy_self_contained_objects( let srcdir = builder.musl_libdir(target).unwrap_or_else(|| { panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple) }); - for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { - copy_and_stamp( - builder, - &libdir_self_contained, - &srcdir, - obj, - &mut target_deps, - DependencyType::TargetSelfContained, - ); - } - let crt_path = builder.ensure(llvm::CrtBeginEnd { target }); - for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] { - let src = crt_path.join(obj); - let target = libdir_self_contained.join(obj); - builder.copy_link(&src, &target); - target_deps.push((target, DependencyType::TargetSelfContained)); + if !target.starts_with("wasm32") { + for &obj in &["libc.a", "crt1.o", "Scrt1.o", "rcrt1.o", "crti.o", "crtn.o"] { + copy_and_stamp( + builder, + &libdir_self_contained, + &srcdir, + obj, + &mut target_deps, + DependencyType::TargetSelfContained, + ); + } + let crt_path = builder.ensure(llvm::CrtBeginEnd { target }); + for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] { + let src = crt_path.join(obj); + let target = libdir_self_contained.join(obj); + builder.copy_link(&src, &target); + target_deps.push((target, DependencyType::TargetSelfContained)); + } + } else { + // For wasm32 targets, we need to copy the libc.a and crt1-command.o files from the + // musl-libdir, but we don't need the other files. + for &obj in &["libc.a", "crt1-command.o"] { + copy_and_stamp( + builder, + &libdir_self_contained, + &srcdir, + obj, + &mut target_deps, + DependencyType::TargetSelfContained, + ); + } } - if !target.starts_with("s390x") { let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained); target_deps.push((libunwind_path, DependencyType::TargetSelfContained)); @@ -993,7 +1004,9 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { let crates = run.cargo_crates_in_set(); run.builder.ensure(Rustc { - compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), + compiler: run + .builder + .compiler(run.builder.top_stage.saturating_sub(1), run.build_triple()), target: run.target, crates, }); @@ -1614,6 +1627,14 @@ impl Step for CodegenBackend { .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml"))); rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + // Ideally, we'd have a separate step for the individual codegen backends, + // like we have in tests (test::CodegenGCC) but that would require a lot of restructuring. + // If the logic gets more complicated, it should probably be done. + if backend == "gcc" { + let gcc = builder.ensure(Gcc { target }); + add_cg_gcc_cargo_flags(&mut cargo, &gcc); + } + let tmp_stamp = BuildStamp::new(&out_dir).with_prefix("tmp"); let _guard = builder.msg_build(compiler, format_args!("codegen backend {backend}"), target); @@ -1902,7 +1923,7 @@ impl Step for Assemble { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Assemble { - target_compiler: run.builder.compiler(run.builder.top_stage + 1, run.target), + target_compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } @@ -1983,13 +2004,14 @@ impl Step for Assemble { let maybe_install_llvm_bitcode_linker = |compiler| { if builder.config.llvm_bitcode_linker_enabled { trace!("llvm-bitcode-linker enabled, installing"); - let src_path = builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { - compiler, - target: target_compiler.host, - extra_features: vec![], - }); + let llvm_bitcode_linker = + builder.ensure(crate::core::build_steps::tool::LlvmBitcodeLinker { + compiler, + target: target_compiler.host, + extra_features: vec![], + }); let tool_exe = exe("llvm-bitcode-linker", target_compiler.host); - builder.copy_link(&src_path, &libdir_bin.join(tool_exe)); + builder.copy_link(&llvm_bitcode_linker.tool_path, &libdir_bin.join(tool_exe)); } }; @@ -2008,7 +2030,9 @@ impl Step for Assemble { builder.info(&format!("Creating a sysroot for stage{stage} compiler (use `rustup toolchain link 'name' build/host/stage{stage}`)", stage=target_compiler.stage)); } - maybe_install_llvm_bitcode_linker(target_compiler); + let mut precompiled_compiler = target_compiler; + precompiled_compiler.forced_compiler(true); + maybe_install_llvm_bitcode_linker(precompiled_compiler); return target_compiler; } @@ -2181,18 +2205,17 @@ impl Step for Assemble { // logic to create the final binary. This is used by the // `wasm32-wasip2` target of Rust. if builder.tool_enabled("wasm-component-ld") { - let wasm_component_ld_exe = - builder.ensure(crate::core::build_steps::tool::WasmComponentLd { - compiler: build_compiler, - target: target_compiler.host, - }); + let wasm_component = builder.ensure(crate::core::build_steps::tool::WasmComponentLd { + compiler: build_compiler, + target: target_compiler.host, + }); builder.copy_link( - &wasm_component_ld_exe, - &libdir_bin.join(wasm_component_ld_exe.file_name().unwrap()), + &wasm_component.tool_path, + &libdir_bin.join(wasm_component.tool_path.file_name().unwrap()), ); } - maybe_install_llvm_bitcode_linker(build_compiler); + maybe_install_llvm_bitcode_linker(target_compiler); // Ensure that `libLLVM.so` ends up in the newly build compiler directory, // so that it can be found when the newly built `rustc` is run. diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 795f9506a259b..ffb60bd5634cb 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -230,8 +230,10 @@ fn make_win_dist( "libiconv.a", "libmoldname.a", "libpthread.a", - //Windows import libs - //This should contain only the set of libraries necessary to link the standard library. + // Windows import libs + // This *should* contain only the set of libraries necessary to link the standard library, + // however we've had problems with people accidentally depending on extra libs being here, + // so we can't easily remove entries. "libadvapi32.a", "libbcrypt.a", "libcomctl32.a", @@ -430,7 +432,7 @@ impl Step for Rustc { }, builder.kind, ) { - builder.install(&ra_proc_macro_srv, &image.join("libexec"), 0o755); + builder.install(&ra_proc_macro_srv.tool_path, &image.join("libexec"), 0o755); } let libdir_relative = builder.libdir_relative(compiler); @@ -1145,7 +1147,7 @@ impl Step for Cargo { let mut tarball = Tarball::new(builder, "cargo", &target.triple); tarball.set_overlay(OverlayKind::Cargo); - tarball.add_file(cargo, "bin", 0o755); + tarball.add_file(cargo.tool_path, "bin", 0o755); tarball.add_file(etc.join("_cargo"), "share/zsh/site-functions", 0o644); tarball.add_renamed_file(etc.join("cargo.bashcomp.sh"), "etc/bash_completion.d", "cargo"); tarball.add_dir(etc.join("man"), "share/man/man1"); @@ -1155,48 +1157,6 @@ impl Step for Cargo { } } -#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] -pub struct Rls { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for Rls { - type Output = Option; - const ONLY_HOSTS: bool = true; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - let default = should_build_extended_tool(run.builder, "rls"); - run.alias("rls").default_condition(default) - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rls { - compiler: run.builder.compiler_for( - run.builder.top_stage, - run.builder.config.build, - run.target, - ), - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) -> Option { - let compiler = self.compiler; - let target = self.target; - - let rls = builder.ensure(tool::Rls { compiler, target }); - - let mut tarball = Tarball::new(builder, "rls", &target.triple); - tarball.set_overlay(OverlayKind::Rls); - tarball.is_preview(true); - tarball.add_file(rls, "bin", 0o755); - tarball.add_legal_and_readme_to("share/doc/rls"); - Some(tarball.generate()) - } -} - #[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] pub struct RustAnalyzer { pub compiler: Compiler, @@ -1233,7 +1193,7 @@ impl Step for RustAnalyzer { let mut tarball = Tarball::new(builder, "rust-analyzer", &target.triple); tarball.set_overlay(OverlayKind::RustAnalyzer); tarball.is_preview(true); - tarball.add_file(rust_analyzer, "bin", 0o755); + tarball.add_file(rust_analyzer.tool_path, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/rust-analyzer"); Some(tarball.generate()) } @@ -1279,8 +1239,8 @@ impl Step for Clippy { let mut tarball = Tarball::new(builder, "clippy", &target.triple); tarball.set_overlay(OverlayKind::Clippy); tarball.is_preview(true); - tarball.add_file(clippy, "bin", 0o755); - tarball.add_file(cargoclippy, "bin", 0o755); + tarball.add_file(clippy.tool_path, "bin", 0o755); + tarball.add_file(cargoclippy.tool_path, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/clippy"); Some(tarball.generate()) } @@ -1329,8 +1289,8 @@ impl Step for Miri { let mut tarball = Tarball::new(builder, "miri", &target.triple); tarball.set_overlay(OverlayKind::Miri); tarball.is_preview(true); - tarball.add_file(miri, "bin", 0o755); - tarball.add_file(cargomiri, "bin", 0o755); + tarball.add_file(miri.tool_path, "bin", 0o755); + tarball.add_file(cargomiri.tool_path, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/miri"); Some(tarball.generate()) } @@ -1460,8 +1420,8 @@ impl Step for Rustfmt { let mut tarball = Tarball::new(builder, "rustfmt", &target.triple); tarball.set_overlay(OverlayKind::Rustfmt); tarball.is_preview(true); - tarball.add_file(rustfmt, "bin", 0o755); - tarball.add_file(cargofmt, "bin", 0o755); + tarball.add_file(rustfmt.tool_path, "bin", 0o755); + tarball.add_file(cargofmt.tool_path, "bin", 0o755); tarball.add_legal_and_readme_to("share/doc/rustfmt"); Some(tarball.generate()) } @@ -1526,7 +1486,6 @@ impl Step for Extended { add_component!("rust-json-docs" => JsonDocs { host: target }); add_component!("cargo" => Cargo { compiler, target }); add_component!("rustfmt" => Rustfmt { compiler, target }); - add_component!("rls" => Rls { compiler, target }); add_component!("rust-analyzer" => RustAnalyzer { compiler, target }); add_component!("llvm-components" => LlvmTools { target }); add_component!("clippy" => Clippy { compiler, target }); @@ -2144,8 +2103,7 @@ pub fn maybe_install_llvm_target(builder: &Builder<'_>, target: TargetSelection, ), )] pub fn maybe_install_llvm_runtime(builder: &Builder<'_>, target: TargetSelection, sysroot: &Path) { - let dst_libdir = - sysroot.join(builder.sysroot_libdir_relative(Compiler { stage: 1, host: target })); + let dst_libdir = sysroot.join(builder.sysroot_libdir_relative(Compiler::new(1, target))); // We do not need to copy LLVM files into the sysroot if it is not // dynamically linked; it is already included into librustc_llvm // statically. @@ -2283,7 +2241,7 @@ impl Step for LlvmBitcodeLinker { tarball.set_overlay(OverlayKind::LlvmBitcodeLinker); tarball.is_preview(true); - tarball.add_file(llbc_linker, self_contained_bin_dir, 0o755); + tarball.add_file(llbc_linker.tool_path, self_contained_bin_dir, 0o755); Some(tarball.generate()) } @@ -2420,7 +2378,7 @@ impl Step for Bootstrap { let tarball = Tarball::new(builder, "bootstrap", &target.triple); let bootstrap_outdir = &builder.bootstrap_out; - for file in &["bootstrap", "rustc", "rustdoc", "sccache-plus-cl"] { + for file in &["bootstrap", "rustc", "rustdoc"] { tarball.add_file(bootstrap_outdir.join(exe(file, target)), "bootstrap/bin", 0o755); } @@ -2500,3 +2458,30 @@ impl Step for ReproducibleArtifacts { if added_anything { Some(tarball.generate()) } else { None } } } + +/// Tarball containing a prebuilt version of the libgccjit library, +/// needed as a dependency for the GCC codegen backend (similarly to the LLVM +/// backend needing a prebuilt libLLVM). +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Gcc { + pub target: TargetSelection, +} + +impl Step for Gcc { + type Output = GeneratedTarball; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("gcc") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Gcc { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + let tarball = Tarball::new(builder, "gcc", &self.target.triple); + let output = builder.ensure(super::gcc::Gcc { target: self.target }); + tarball.add_file(output.libgccjit, "lib", 0o644); + tarball.generate() + } +} diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index aee56fe78e21f..8e913f6818423 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -987,9 +987,7 @@ macro_rules! tool_doc { cargo.rustdocflag("-Arustdoc::private-intra-doc-links"); cargo.rustdocflag("--enable-index-page"); cargo.rustdocflag("--show-type-layout"); - // FIXME: `--generate-link-to-definition` tries to resolve cfged out code - // see https://github.com/rust-lang/rust/pull/122066#issuecomment-1983049222 - // cargo.rustdocflag("--generate-link-to-definition"); + cargo.rustdocflag("--generate-link-to-definition"); let out_dir = builder.stage_out(compiler, Mode::ToolRustc).join(target).join("doc"); $(for krate in $crates { diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index c7eafadee2df3..9817e47baa101 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -27,7 +27,7 @@ fn rustfmt( rustfmt: &Path, paths: &[PathBuf], check: bool, -) -> impl FnMut(bool) -> RustfmtStatus { +) -> impl FnMut(bool) -> RustfmtStatus + use<> { let mut cmd = Command::new(rustfmt); // Avoid the submodule config paths from coming into play. We only allow a single global config // for the workspace for now. diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index 98b8635132b0d..0aa2a3325313f 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -9,18 +9,77 @@ //! ensure that they're always in place if needed. use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::OnceLock; use build_helper::ci::CiEnv; -use crate::Kind; -use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step}; use crate::core::config::TargetSelection; use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash}; use crate::utils::exec::command; use crate::utils::helpers::{self, t}; +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Gcc { + pub target: TargetSelection, +} + +#[derive(Clone)] +pub struct GccOutput { + pub libgccjit: PathBuf, +} + +impl Step for Gcc { + type Output = GccOutput; + + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/gcc").alias("gcc") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Gcc { target: run.target }); + } + + /// Compile GCC (specifically `libgccjit`) for `target`. + fn run(self, builder: &Builder<'_>) -> Self::Output { + let target = self.target; + + // If GCC has already been built, we avoid building it again. + let metadata = match get_gcc_build_status(builder, target) { + GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path }, + GccBuildStatus::ShouldBuild(m) => m, + }; + + let _guard = builder.msg_unstaged(Kind::Build, "GCC", target); + t!(metadata.stamp.remove()); + let _time = helpers::timeit(builder); + + let libgccjit_path = libgccjit_built_path(&metadata.install_dir); + if builder.config.dry_run() { + return GccOutput { libgccjit: libgccjit_path }; + } + + build_gcc(&metadata, builder, target); + create_lib_alias(builder, &libgccjit_path); + + t!(metadata.stamp.write()); + + GccOutput { libgccjit: libgccjit_path } + } +} + +/// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not +/// already exist +fn create_lib_alias(builder: &Builder<'_>, libgccjit: &PathBuf) { + let lib_alias = libgccjit.parent().unwrap().join("libgccjit.so.0"); + if !lib_alias.exists() { + t!(builder.symlink_file(libgccjit, lib_alias)); + } +} + pub struct Meta { stamp: BuildStamp, out_dir: PathBuf, @@ -29,24 +88,52 @@ pub struct Meta { } pub enum GccBuildStatus { - AlreadyBuilt, + /// libgccjit is already built at this path + AlreadyBuilt(PathBuf), ShouldBuild(Meta), } -/// This returns whether we've already previously built GCC. +/// Tries to download GCC from CI if it is enabled and GCC artifacts +/// are available for the given target. +/// Returns a path to the libgccjit.so file. +#[cfg(not(test))] +fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option { + // Try to download GCC from CI if configured and available + if !matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::DownloadFromCi) { + return None; + } + if target != "x86_64-unknown-linux-gnu" { + eprintln!("GCC CI download is only available for the `x86_64-unknown-linux-gnu` target"); + return None; + } + let sha = + detect_gcc_sha(&builder.config, builder.config.rust_info.is_managed_git_subrepository()); + let root = ci_gcc_root(&builder.config); + let gcc_stamp = BuildStamp::new(&root).with_prefix("gcc").add_stamp(&sha); + if !gcc_stamp.is_up_to_date() && !builder.config.dry_run() { + builder.config.download_ci_gcc(&sha, &root); + t!(gcc_stamp.write()); + } + + let libgccjit = root.join("lib").join("libgccjit.so"); + create_lib_alias(builder, &libgccjit); + Some(libgccjit) +} + +#[cfg(test)] +fn try_download_gcc(_builder: &Builder<'_>, _target: TargetSelection) -> Option { + None +} + +/// This returns information about whether GCC should be built or if it's already built. +/// It transparently handles downloading GCC from CI if needed. /// /// It's used to avoid busting caches during x.py check -- if we've already built /// GCC, it's fine for us to not try to avoid doing so. -pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus { - // Initialize the gcc submodule if not initialized already. - builder.config.update_submodule("src/gcc"); - - // FIXME (GuillaumeGomez): To be done once gccjit has been built in the CI. - // builder.config.maybe_download_ci_gcc(); - - let root = builder.src.join("src/gcc"); - let out_dir = builder.gcc_out(target).join("build"); - let install_dir = builder.gcc_out(target).join("install"); +pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus { + if let Some(path) = try_download_gcc(builder, target) { + return GccBuildStatus::AlreadyBuilt(path); + } static STAMP_HASH_MEMO: OnceLock = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { @@ -57,6 +144,13 @@ pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> Gc ) }); + // Initialize the gcc submodule if not initialized already. + builder.config.update_submodule("src/gcc"); + + let root = builder.src.join("src/gcc"); + let out_dir = builder.gcc_out(target).join("build"); + let install_dir = builder.gcc_out(target).join("install"); + let stamp = BuildStamp::new(&out_dir).with_prefix("gcc").add_stamp(smart_stamp_hash); if stamp.is_up_to_date() { @@ -70,114 +164,133 @@ pub fn prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> Gc stamp.path().display() )); } - return GccBuildStatus::AlreadyBuilt; + let path = libgccjit_built_path(&install_dir); + if path.is_file() { + return GccBuildStatus::AlreadyBuilt(path); + } else { + builder.info(&format!( + "GCC stamp is up-to-date, but the libgccjit.so file was not found at `{}`", + path.display(), + )); + } } GccBuildStatus::ShouldBuild(Meta { stamp, out_dir, install_dir, root }) } -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct Gcc { - pub target: TargetSelection, +/// Returns the path to a libgccjit.so file in the install directory of GCC. +fn libgccjit_built_path(install_dir: &Path) -> PathBuf { + install_dir.join("lib/libgccjit.so") } -impl Step for Gcc { - type Output = bool; - - const ONLY_HOSTS: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/gcc").alias("gcc") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Gcc { target: run.target }); +fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) { + if builder.build.cc_tool(target).is_like_clang() + || builder.build.cxx_tool(target).is_like_clang() + { + panic!( + "Attempting to build GCC using Clang, which is known to misbehave. Please use GCC as the host C/C++ compiler. " + ); } - /// Compile GCC for `target`. - fn run(self, builder: &Builder<'_>) -> bool { - let target = self.target; + let Meta { stamp: _, out_dir, install_dir, root } = metadata; - // If GCC has already been built, we avoid building it again. - let Meta { stamp, out_dir, install_dir, root } = match prebuilt_gcc_config(builder, target) - { - GccBuildStatus::AlreadyBuilt => return true, - GccBuildStatus::ShouldBuild(m) => m, - }; - - let _guard = builder.msg_unstaged(Kind::Build, "GCC", target); - t!(stamp.remove()); - let _time = helpers::timeit(builder); - t!(fs::create_dir_all(&out_dir)); + t!(fs::create_dir_all(out_dir)); + t!(fs::create_dir_all(install_dir)); - if builder.config.dry_run() { - return true; + // GCC creates files (e.g. symlinks to the downloaded dependencies) + // in the source directory, which does not work with our CI setup, where we mount + // source directories as read-only on Linux. + // Therefore, as a part of the build in CI, we first copy the whole source directory + // to the build directory, and perform the build from there. + let src_dir = if CiEnv::is_ci() { + let src_dir = builder.gcc_out(target).join("src"); + if src_dir.exists() { + builder.remove_dir(&src_dir); } + builder.create_dir(&src_dir); + builder.cp_link_r(root, &src_dir); + src_dir + } else { + root.clone() + }; - // GCC creates files (e.g. symlinks to the downloaded dependencies) - // in the source directory, which does not work with our CI setup, where we mount - // source directories as read-only on Linux. - // Therefore, as a part of the build in CI, we first copy the whole source directory - // to the build directory, and perform the build from there. - let src_dir = if CiEnv::is_ci() { - let src_dir = builder.gcc_out(target).join("src"); - if src_dir.exists() { - builder.remove_dir(&src_dir); - } - builder.create_dir(&src_dir); - builder.cp_link_r(&root, &src_dir); - src_dir - } else { - root - }; + command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder); + let mut configure_cmd = command(src_dir.join("configure")); + configure_cmd + .current_dir(out_dir) + .arg("--enable-host-shared") + .arg("--enable-languages=c,jit,lto") + .arg("--enable-checking=release") + .arg("--disable-bootstrap") + .arg("--disable-multilib") + .arg(format!("--prefix={}", install_dir.display())); + + let cc = builder.build.cc(target).display().to_string(); + let cc = builder + .build + .config + .ccache + .as_ref() + .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}")); + configure_cmd.env("CC", cc); - command(src_dir.join("contrib/download_prerequisites")).current_dir(&src_dir).run(builder); - let mut configure_cmd = command(src_dir.join("configure")); - configure_cmd - .current_dir(&out_dir) - // On CI, we compile GCC with Clang. - // The -Wno-everything flag is needed to make GCC compile with Clang 19. - // `-g -O2` are the default flags that are otherwise used by Make. - // FIXME(kobzol): change the flags once we have [gcc] configuration in config.toml. - .env("CXXFLAGS", "-Wno-everything -g -O2") - .env("CFLAGS", "-Wno-everything -g -O2") - .arg("--enable-host-shared") - .arg("--enable-languages=jit") - .arg("--enable-checking=release") - .arg("--disable-bootstrap") - .arg("--disable-multilib") - .arg(format!("--prefix={}", install_dir.display())); - let cc = builder.build.cc(target).display().to_string(); - let cc = builder + if let Ok(ref cxx) = builder.build.cxx(target) { + let cxx = cxx.display().to_string(); + let cxx = builder .build .config .ccache .as_ref() - .map_or_else(|| cc.clone(), |ccache| format!("{ccache} {cc}")); - configure_cmd.env("CC", cc); - - if let Ok(ref cxx) = builder.build.cxx(target) { - let cxx = cxx.display().to_string(); - let cxx = builder - .build - .config - .ccache - .as_ref() - .map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}")); - configure_cmd.env("CXX", cxx); - } - configure_cmd.run(builder); + .map_or_else(|| cxx.clone(), |ccache| format!("{ccache} {cxx}")); + configure_cmd.env("CXX", cxx); + } + configure_cmd.run(builder); - command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())).run(builder); - command("make").current_dir(&out_dir).arg("install").run(builder); + command("make") + .current_dir(out_dir) + .arg("--silent") + .arg(format!("-j{}", builder.jobs())) + .run_capture_stdout(builder); + command("make").current_dir(out_dir).arg("--silent").arg("install").run_capture_stdout(builder); +} - let lib_alias = install_dir.join("lib/libgccjit.so.0"); - if !lib_alias.exists() { - t!(builder.symlink_file(install_dir.join("lib/libgccjit.so"), lib_alias,)); - } +/// Configures a Cargo invocation so that it can build the GCC codegen backend. +pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) { + // Add the path to libgccjit.so to the linker search paths. + cargo.rustflag(&format!("-L{}", gcc.libgccjit.parent().unwrap().to_str().unwrap())); +} + +/// The absolute path to the downloaded GCC artifacts. +#[cfg(not(test))] +fn ci_gcc_root(config: &crate::Config) -> PathBuf { + config.out.join(config.build).join("ci-gcc") +} - t!(stamp.write()); +/// This retrieves the GCC sha we *want* to use, according to git history. +#[cfg(not(test))] +fn detect_gcc_sha(config: &crate::Config, is_git: bool) -> String { + use build_helper::git::get_closest_merge_commit; - true + let gcc_sha = if is_git { + get_closest_merge_commit( + Some(&config.src), + &config.git_config(), + &[config.src.join("src/gcc"), config.src.join("src/bootstrap/download-ci-gcc-stamp")], + ) + .unwrap() + } else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) { + info.sha.trim().to_owned() + } else { + "".to_owned() + }; + + if gcc_sha.is_empty() { + eprintln!("error: could not find commit hash for downloading GCC"); + eprintln!("HELP: maybe your repository history is too shallow?"); + eprintln!("HELP: consider disabling `download-ci-gcc`"); + eprintln!("HELP: or fetch enough history to include one upstream commit"); + panic!(); } + + gcc_sha } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 40d701f22c137..e324cf745ffb4 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -735,57 +735,17 @@ fn configure_cmake( None => (builder.cc(target), builder.cxx(target).unwrap()), }; - // Handle msvc + ninja + ccache specially (this is what the bots use) - if target.is_msvc() && builder.ninja() && builder.config.ccache.is_some() { - let mut wrap_cc = env::current_exe().expect("failed to get cwd"); - wrap_cc.set_file_name("sccache-plus-cl.exe"); - - cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc)) - .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc)); - cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap()) - .env("SCCACHE_TARGET", target.triple) - .env("SCCACHE_CC", &cc) - .env("SCCACHE_CXX", &cxx); - - // Building LLVM on MSVC can be a little ludicrous at times. We're so far - // off the beaten path here that I'm not really sure this is even half - // supported any more. Here we're trying to: - // - // * Build LLVM on MSVC - // * Build LLVM with `clang-cl` instead of `cl.exe` - // * Build a project with `sccache` - // * Build for 32-bit as well - // * Build with Ninja - // - // For `cl.exe` there are different binaries to compile 32/64 bit which - // we use but for `clang-cl` there's only one which internally - // multiplexes via flags. As a result it appears that CMake's detection - // of a compiler's architecture and such on MSVC **doesn't** pass any - // custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we - // use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which - // definitely causes problems since all the env vars are pointing to - // 32-bit libraries. - // - // To hack around this... again... we pass an argument that's - // unconditionally passed in the sccache shim. This'll get CMake to - // correctly diagnose it's doing a 32-bit compilation and LLVM will - // internally configure itself appropriately. - if builder.config.llvm_clang_cl.is_some() && target.contains("i686") { - cfg.env("SCCACHE_EXTRA_ARGS", "-m32"); - } - } else { - // If ccache is configured we inform the build a little differently how - // to invoke ccache while also invoking our compilers. - if use_compiler_launcher { - if let Some(ref ccache) = builder.config.ccache { - cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache) - .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache); - } + // If ccache is configured we inform the build a little differently how + // to invoke ccache while also invoking our compilers. + if use_compiler_launcher { + if let Some(ref ccache) = builder.config.ccache { + cfg.define("CMAKE_C_COMPILER_LAUNCHER", ccache) + .define("CMAKE_CXX_COMPILER_LAUNCHER", ccache); } - cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) - .define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx)) - .define("CMAKE_ASM_COMPILER", sanitize_cc(&cc)); } + cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) + .define("CMAKE_CXX_COMPILER", sanitize_cc(&cxx)) + .define("CMAKE_ASM_COMPILER", sanitize_cc(&cc)); cfg.build_arg("-j").build_arg(builder.jobs().to_string()); // FIXME(madsmtm): Allow `cmake-rs` to select flags by itself by passing diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 98c63a41e768b..6962001fdc240 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -166,7 +166,7 @@ Consider setting `rust.debuginfo-level = 1` in `config.toml`."#); let results_dir = rustc_perf_dir.join("results"); builder.create_dir(&results_dir); - let mut cmd = command(collector); + let mut cmd = command(collector.tool_path); // We need to set the working directory to `src/tools/rustc-perf`, so that it can find the directory // with compile-time benchmarks. diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 2b17e02cae5a4..1ef86e674f099 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -126,11 +126,7 @@ impl Step for Miri { // This compiler runs on the host, we'll just use it for the target. let target_compiler = builder.compiler(stage, host); - // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise - // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage - // compilers, which isn't what we want. Rustdoc should be linked in the same way as the - // rustc compiler it's paired with, so it must be built with the previous stage compiler. - let host_compiler = builder.compiler(stage - 1, host); + let host_compiler = tool::get_tool_rustc_compiler(builder, target_compiler); // Get a target sysroot for Miri. let miri_sysroot = test::Miri::build_miri_sysroot(builder, target_compiler, target); @@ -371,3 +367,28 @@ impl Step for FeaturesStatusDump { cmd.run(builder); } } + +/// Dummy step that can be used to deliberately trigger bootstrap's step cycle +/// detector, for automated and manual testing. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct CyclicStep { + n: u32, +} + +impl Step for CyclicStep { + type Output = (); + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("cyclic-step") + } + + fn make_run(run: RunConfig<'_>) { + // Start with n=2, so that we build up a few stack entries before panicking. + run.builder.ensure(CyclicStep { n: 2 }) + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + // When n=0, the step will try to ensure itself, causing a step cycle. + builder.ensure(CyclicStep { n: self.n.saturating_sub(1) }) + } +} diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index f25dfaab0f115..45f9f52cb824e 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -85,9 +85,7 @@ impl FromStr for Profile { "lib" | "library" => Ok(Profile::Library), "compiler" => Ok(Profile::Compiler), "maintainer" | "dist" | "user" => Ok(Profile::Dist), - "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" | "rls" => { - Ok(Profile::Tools) - } + "tools" | "tool" | "rustdoc" | "clippy" | "miri" | "rustfmt" => Ok(Profile::Tools), "none" => Ok(Profile::None), "llvm" | "codegen" => Err("the \"llvm\" and \"codegen\" profiles have been removed,\ use \"compiler\" instead which has the same functionality" @@ -584,10 +582,12 @@ Select which editor you would like to set up [default: None]: "; EditorKind::Emacs => &[ "51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0", "d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45", + "b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088", ], EditorKind::Helix => &[ "2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233", "6736d61409fbebba0933afd2e4c44ff2f97c1cb36cf0299a7f4a7819b8775040", + "f252dcc30ca85a193a699581e5e929d5bd6c19d40d7a7ade5e257a9517a124a5", ], EditorKind::Vim | EditorKind::VsCode => &[ "ea67e259dedf60d4429b6c349a564ffcd1563cf41c920a856d1f5b16b4701ac8", @@ -600,10 +600,12 @@ Select which editor you would like to set up [default: None]: "; "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", "4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4", "c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d", + "e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717", + ], + EditorKind::Zed => &[ + "bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c", + "a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909", ], - EditorKind::Zed => { - &["bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c"] - } } } diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index ba9b1b2fc3317..6a6731cafc54a 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -1,7 +1,5 @@ //! Attempt to magically identify good tests to run -#![cfg_attr(feature = "build-metrics", allow(unused))] - use std::path::PathBuf; use std::str::FromStr; diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 5fc3e8469bb75..cff286e99face 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -12,6 +12,7 @@ use clap_complete::shells; use crate::core::build_steps::compile::run_cargo; use crate::core::build_steps::doc::DocumentationFormat; +use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags}; use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{self, SourceType, Tool}; @@ -89,7 +90,7 @@ impl Step for CrateBootstrap { ); let crate_name = path.rsplit_once('/').unwrap().1; - run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], crate_name, bootstrap_host, builder); } } @@ -139,15 +140,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" SourceType::InTree, &[], ); - run_cargo_test( - cargo, - &[], - &[], - "linkchecker", - "linkchecker self tests", - bootstrap_host, - builder, - ); + run_cargo_test(cargo, &[], &[], "linkchecker self tests", bootstrap_host, builder); if builder.doc_tests == DocTests::No { return; @@ -263,12 +256,18 @@ impl Step for Cargotest { let _time = helpers::timeit(builder); let mut cmd = builder.tool_cmd(Tool::CargoTest); - cmd.arg(&cargo) + cmd.arg(&cargo.tool_path) .arg(&out_dir) .args(builder.config.test_args()) .env("RUSTC", builder.rustc(compiler)) .env("RUSTDOC", builder.rustdoc(compiler)); - add_rustdoc_cargo_linker_args(&mut cmd, builder, compiler.host, LldThreads::No); + add_rustdoc_cargo_linker_args( + &mut cmd, + builder, + compiler.host, + LldThreads::No, + compiler.stage, + ); cmd.delay_failure().run(builder); } } @@ -293,14 +292,31 @@ impl Step for Cargo { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Cargo { stage: run.builder.top_stage, host: run.target }); + // If stage is explicitly set or not lower than 2, keep it. Otherwise, make sure it's at least 2 + // as tests for this step don't work with a lower stage. + let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 { + run.builder.top_stage + } else { + 2 + }; + + run.builder.ensure(Cargo { stage, host: run.target }); } /// Runs `cargo test` for `cargo` packaged with Rust. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(self.stage, self.host); + let stage = self.stage; + + if stage < 2 { + eprintln!("WARNING: cargo tests on stage {stage} may not behave well."); + eprintln!("HELP: consider using stage 2"); + } + + let compiler = builder.compiler(stage, self.host); + + let cargo = builder.ensure(tool::Cargo { compiler, target: self.host }); + let compiler = cargo.build_compiler; - builder.ensure(tool::Cargo { compiler, target: self.host }); let cargo = tool::prepare_tool_cargo( builder, compiler, @@ -313,7 +329,7 @@ impl Step for Cargo { ); // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH` - let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", self.host, builder); + let mut cargo = prepare_cargo_test(cargo, &[], &[], self.host, builder); // Don't run cross-compile tests, we may not have cross-compiled libstd libs // available. @@ -333,7 +349,7 @@ impl Step for Cargo { crates: vec!["cargo".into()], target: self.host.triple.to_string(), host: self.host.triple.to_string(), - stage: self.stage, + stage, }, builder, ); @@ -367,6 +383,7 @@ impl Step for RustAnalyzer { let stage = self.stage; let host = self.host; let compiler = builder.compiler(stage, host); + let compiler = tool::get_tool_rustc_compiler(builder, compiler); // We don't need to build the whole Rust Analyzer for the proc-macro-srv test suite, // but we do need the standard library to be present. @@ -398,7 +415,7 @@ impl Step for RustAnalyzer { cargo.env("SKIP_SLOW_TESTS", "1"); cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", host, builder); + run_cargo_test(cargo, &[], &[], "rust-analyzer", host, builder); } } @@ -427,7 +444,8 @@ impl Step for Rustfmt { let host = self.host; let compiler = builder.compiler(stage, host); - builder.ensure(tool::Rustfmt { compiler, target: self.host }); + let tool_result = builder.ensure(tool::Rustfmt { compiler, target: self.host }); + let compiler = tool_result.build_compiler; let mut cargo = tool::prepare_tool_cargo( builder, @@ -446,7 +464,7 @@ impl Step for Rustfmt { cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", host, builder); + run_cargo_test(cargo, &[], &[], "rustfmt", host, builder); } } @@ -522,16 +540,11 @@ impl Step for Miri { // This compiler runs on the host, we'll just use it for the target. let target_compiler = builder.compiler(stage, host); - // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise - // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage - // compilers, which isn't what we want. Rustdoc should be linked in the same way as the - // rustc compiler it's paired with, so it must be built with the previous stage compiler. - let host_compiler = builder.compiler(stage - 1, host); // Build our tools. - let miri = builder.ensure(tool::Miri { compiler: host_compiler, target: host }); + let miri = builder.ensure(tool::Miri { compiler: target_compiler, target: host }); // the ui tests also assume cargo-miri has been built - builder.ensure(tool::CargoMiri { compiler: host_compiler, target: host }); + builder.ensure(tool::CargoMiri { compiler: target_compiler, target: host }); // We also need sysroots, for Miri and for the host (the latter for build scripts). // This is for the tests so everything is done with the target compiler. @@ -542,7 +555,8 @@ impl Step for Miri { // Miri has its own "target dir" for ui test dependencies. Make sure it gets cleared when // the sysroot gets rebuilt, to avoid "found possibly newer version of crate `std`" errors. if !builder.config.dry_run() { - let ui_test_dep_dir = builder.stage_out(host_compiler, Mode::ToolStd).join("miri_ui"); + let ui_test_dep_dir = + builder.stage_out(miri.build_compiler, Mode::ToolStd).join("miri_ui"); // The mtime of `miri_sysroot` changes when the sysroot gets rebuilt (also see // ). // We can hence use that directly as a signal to clear the ui test dir. @@ -553,7 +567,7 @@ impl Step for Miri { // This is with the Miri crate, so it uses the host compiler. let mut cargo = tool::prepare_tool_cargo( builder, - host_compiler, + miri.build_compiler, Mode::ToolRustc, host, Kind::Test, @@ -566,12 +580,12 @@ impl Step for Miri { // We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test // harness and therefore do not understand the flags added by `add_flags_and_try_run_test`. - let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host, builder); + let mut cargo = prepare_cargo_test(cargo, &[], &[], host, builder); // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", &miri_sysroot); cargo.env("MIRI_HOST_SYSROOT", &host_sysroot); - cargo.env("MIRI", &miri); + cargo.env("MIRI", &miri.tool_path); // Set the target. cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg()); @@ -714,7 +728,7 @@ impl Step for CompiletestTest { &[], ); cargo.allow_features("test"); - run_cargo_test(cargo, &[], &[], "compiletest", "compiletest self test", host, builder); + run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder); } } @@ -734,7 +748,15 @@ impl Step for Clippy { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Clippy { stage: run.builder.top_stage, host: run.target }); + // If stage is explicitly set or not lower than 2, keep it. Otherwise, make sure it's at least 2 + // as tests for this step don't work with a lower stage. + let stage = if run.builder.config.is_explicit_stage() || run.builder.top_stage >= 2 { + run.builder.top_stage + } else { + 2 + }; + + run.builder.ensure(Clippy { stage, host: run.target }); } /// Runs `cargo test` for clippy. @@ -743,7 +765,13 @@ impl Step for Clippy { let host = self.host; let compiler = builder.compiler(stage, host); - builder.ensure(tool::Clippy { compiler, target: self.host }); + if stage < 2 { + eprintln!("WARNING: clippy tests on stage {stage} may not behave well."); + eprintln!("HELP: consider using stage 2"); + } + + let tool_result = builder.ensure(tool::Clippy { compiler, target: self.host }); + let compiler = tool_result.build_compiler; let mut cargo = tool::prepare_tool_cargo( builder, compiler, @@ -761,7 +789,7 @@ impl Step for Clippy { cargo.env("HOST_LIBS", host_libs); cargo.add_rustc_lib_path(builder); - let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", host, builder); + let cargo = prepare_cargo_test(cargo, &[], &[], host, builder); let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); @@ -817,7 +845,7 @@ impl Step for RustdocTheme { .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTC_BOOTSTRAP", "1"); - cmd.args(linker_args(builder, self.compiler.host, LldThreads::No)); + cmd.args(linker_args(builder, self.compiler.host, LldThreads::No, self.compiler.stage)); cmd.delay_failure().run(builder); } @@ -993,7 +1021,13 @@ impl Step for RustdocGUI { cmd.env("RUSTDOC", builder.rustdoc(self.compiler)) .env("RUSTC", builder.rustc(self.compiler)); - add_rustdoc_cargo_linker_args(&mut cmd, builder, self.compiler.host, LldThreads::No); + add_rustdoc_cargo_linker_args( + &mut cmd, + builder, + self.compiler.host, + LldThreads::No, + self.compiler.stage, + ); for path in &builder.paths { if let Some(p) = helpers::is_valid_test_suite_arg(path, "tests/rustdoc-gui", builder) { @@ -1200,51 +1234,6 @@ macro_rules! test { }; } -#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] -pub struct RunMakeSupport { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for RunMakeSupport { - type Output = PathBuf; - const DEFAULT: bool = true; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.never() - } - - fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); - run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() }); - } - - /// Builds run-make-support and returns the path to the resulting rlib. - fn run(self, builder: &Builder<'_>) -> PathBuf { - builder.ensure(compile::Std::new(self.compiler, self.target)); - - let cargo = tool::prepare_tool_cargo( - builder, - self.compiler, - Mode::ToolStd, - self.target, - Kind::Build, - "src/tools/run-make-support", - SourceType::InTree, - &[], - ); - - cargo.into_cmd().run(builder); - - let lib_name = "librun_make_support.rlib"; - let lib = builder.tools_dir(self.compiler).join(lib_name); - - let cargo_out = builder.cargo_out(self.compiler, Mode::ToolStd, self.target).join(lib_name); - builder.copy_link(&cargo_out, &lib); - lib - } -} - /// Runs `cargo test` on the `src/tools/run-make-support` crate. /// That crate is used by run-make tests. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1280,15 +1269,7 @@ impl Step for CrateRunMakeSupport { &[], ); cargo.allow_features("test"); - run_cargo_test( - cargo, - &[], - &[], - "run-make-support", - "run-make-support self test", - host, - builder, - ); + run_cargo_test(cargo, &[], &[], "run-make-support self test", host, builder); } } @@ -1325,7 +1306,7 @@ impl Step for CrateBuildHelper { &[], ); cargo.allow_features("test"); - run_cargo_test(cargo, &[], &[], "build_helper", "build_helper self test", host, builder); + run_cargo_test(cargo, &[], &[], "build_helper self test", host, builder); } } @@ -1396,40 +1377,7 @@ test!(Pretty { only_hosts: true, }); -/// Special-handling is needed for `run-make`, so don't use `test!` for defining `RunMake` -/// tests. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct RunMake { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for RunMake { - type Output = (); - const DEFAULT: bool = true; - const ONLY_HOSTS: bool = false; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.suite_path("tests/run-make") - } - - fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); - run.builder.ensure(RunMakeSupport { compiler, target: run.build_triple() }); - run.builder.ensure(RunMake { compiler, target: run.target }); - } - - fn run(self, builder: &Builder<'_>) { - builder.ensure(Compiletest { - compiler: self.compiler, - target: self.target, - mode: "run-make", - suite: "run-make", - path: "tests/run-make", - compare_mode: None, - }); - } -} +test!(RunMake { path: "tests/run-make", mode: "run-make", suite: "run-make", default: true }); test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly", default: true }); @@ -1672,6 +1620,9 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the host: target, }); } + if suite == "run-make" { + builder.tool_exe(Tool::RunMakeSupport); + } // Also provide `rust_test_helpers` for the host. builder.ensure(TestHelpers { target: compiler.host }); @@ -1720,21 +1671,15 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // If we're using `--stage 0`, we should provide the bootstrap cargo. builder.initial_cargo.clone() } else { - // We need to properly build cargo using the suitable stage compiler. - - let compiler = builder.download_rustc().then_some(compiler).unwrap_or_else(|| - // HACK: currently tool stages are off-by-one compared to compiler stages, i.e. if - // you give `tool::Cargo` a stage 1 rustc, it will cause stage 2 rustc to be built - // and produce a cargo built with stage 2 rustc. To fix this, we need to chop off - // the compiler stage by 1 to align with expected `./x test run-make --stage N` - // behavior, i.e. we need to pass `N - 1` compiler stage to cargo. See also Miri - // which does a similar hack. - builder.compiler(builder.top_stage - 1, compiler.host)); - - builder.ensure(tool::Cargo { compiler, target: compiler.host }) + builder.ensure(tool::Cargo { compiler, target: compiler.host }).tool_path }; cmd.arg("--cargo-path").arg(cargo_path); + + // We need to pass the compiler that was used to compile run-make-support, + // because we have to use the same compiler to compile rmake.rs recipes. + let stage0_rustc_path = builder.compiler(0, compiler.host); + cmd.arg("--stage0-rustc-path").arg(builder.rustc(stage0_rustc_path)); } // Avoid depending on rustdoc when we don't need it. @@ -1752,9 +1697,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // Use the beta compiler for jsondocck let json_compiler = compiler.with_stage(0); cmd.arg("--jsondocck-path") - .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target })); - cmd.arg("--jsondoclint-path") - .arg(builder.ensure(tool::JsonDocLint { compiler: json_compiler, target })); + .arg(builder.ensure(tool::JsonDocCk { compiler: json_compiler, target }).tool_path); + cmd.arg("--jsondoclint-path").arg( + builder.ensure(tool::JsonDocLint { compiler: json_compiler, target }).tool_path, + ); } if matches!(mode, "coverage-map" | "coverage-run") { @@ -1765,14 +1711,18 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--src-root").arg(&builder.src); cmd.arg("--src-test-suite-root").arg(builder.src.join("tests").join(suite)); - cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite)); + // N.B. it's important to distinguish between the *root* build directory, the *host* build + // directory immediately under the root build directory, and the test-suite-specific build + // directory. + cmd.arg("--build-root").arg(&builder.out); + cmd.arg("--build-test-suite-root").arg(testdir(builder, compiler.host).join(suite)); // When top stage is 0, that means that we're testing an externally provided compiler. // In that case we need to use its specific sysroot for tests to pass. let sysroot = if builder.top_stage == 0 { builder.initial_sysroot.clone() } else { - builder.sysroot(compiler).to_path_buf() + builder.sysroot(compiler) }; cmd.arg("--sysroot-base").arg(sysroot); @@ -1849,16 +1799,13 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the } // FIXME(136096): on macOS, we get linker warnings about duplicate `-lm` flags. - // NOTE: `stage > 1` here because `test --stage 1 ui-fulldeps` is a hack that compiles - // with stage 0, but links the tests against stage 1. - // cfg(bootstrap) - remove only the `stage > 1` check, leave everything else. - if suite == "ui-fulldeps" && compiler.stage > 1 && target.ends_with("darwin") { + if suite == "ui-fulldeps" && target.ends_with("darwin") { flags.push("-Alinker_messages".into()); } let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); - hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No)); + hostflags.extend(linker_flags(builder, compiler.host, LldThreads::No, compiler.stage)); let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); @@ -1961,8 +1908,6 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the llvm_components_passed = true; } if !builder.is_rust_llvm(target) { - // FIXME: missing Rust patches is not the same as being system llvm; we should rename the flag at some point. - // Inspecting the tests with `// no-system-llvm` in src/test *looks* like this is doing the right thing, though. cmd.arg("--system-llvm"); } @@ -2544,13 +2489,12 @@ fn run_cargo_test<'a>( cargo: builder::Cargo, libtest_args: &[&str], crates: &[String], - primary_crate: &str, description: impl Into>, target: TargetSelection, builder: &Builder<'_>, ) -> bool { let compiler = cargo.compiler(); - let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, target, builder); + let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder); let _time = helpers::timeit(builder); let _group = description.into().and_then(|what| { builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target) @@ -2574,7 +2518,6 @@ fn prepare_cargo_test( cargo: builder::Cargo, libtest_args: &[&str], crates: &[String], - primary_crate: &str, target: TargetSelection, builder: &Builder<'_>, ) -> BootstrapCommand { @@ -2604,13 +2547,6 @@ fn prepare_cargo_test( cargo.arg("--doc"); } DocTests::No => { - let krate = &builder - .crates - .get(primary_crate) - .unwrap_or_else(|| panic!("missing crate {primary_crate}")); - if krate.has_lib { - cargo.arg("--lib"); - } cargo.args(["--bins", "--examples", "--tests", "--benches"]); } DocTests::Yes => {} @@ -2671,7 +2607,7 @@ impl Step for Crate { const DEFAULT: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.crate_or_deps("sysroot").crate_or_deps("coretests") + run.crate_or_deps("sysroot").crate_or_deps("coretests").crate_or_deps("alloctests") } fn make_run(run: RunConfig<'_>) { @@ -2785,15 +2721,19 @@ impl Step for Crate { _ => panic!("can only test libraries"), }; - run_cargo_test( - cargo, - &[], - &self.crates, - &self.crates[0], - &*crate_description(&self.crates), - target, - builder, - ); + let mut crates = self.crates.clone(); + // The core and alloc crates can't directly be tested. We + // could silently ignore them, but adding their own test + // crates is less confusing for users. We still keep core and + // alloc themself for doctests + if crates.iter().any(|crate_| crate_ == "core") { + crates.push("coretests".to_owned()); + } + if crates.iter().any(|crate_| crate_ == "alloc") { + crates.push("alloctests".to_owned()); + } + + run_cargo_test(cargo, &[], &crates, &*crate_description(&self.crates), target, builder); } } @@ -2886,15 +2826,7 @@ impl Step for CrateRustdoc { dylib_path.insert(0, PathBuf::from(&*libdir)); cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); - run_cargo_test( - cargo, - &[], - &["rustdoc:0.0.0".to_string()], - "rustdoc", - "rustdoc", - target, - builder, - ); + run_cargo_test(cargo, &[], &["rustdoc:0.0.0".to_string()], "rustdoc", target, builder); } } @@ -2951,7 +2883,6 @@ impl Step for CrateRustdocJsonTypes { libtest_args, &["rustdoc-json-types".to_string()], "rustdoc-json-types", - "rustdoc-json-types", target, builder, ); @@ -2991,12 +2922,15 @@ impl Step for RemoteCopyLibs { builder.info(&format!("REMOTE copy libs to emulator ({target})")); - let server = builder.ensure(tool::RemoteTestServer { compiler, target }); + let remote_test_server = builder.ensure(tool::RemoteTestServer { compiler, target }); // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); let mut cmd = command(&tool); - cmd.arg("spawn-emulator").arg(target.triple).arg(&server).arg(builder.tempdir()); + cmd.arg("spawn-emulator") + .arg(target.triple) + .arg(&remote_test_server.tool_path) + .arg(builder.tempdir()); if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } @@ -3128,7 +3062,7 @@ impl Step for Bootstrap { // bootstrap tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. - run_cargo_test(cargo, &["--test-threads=1"], &[], "bootstrap", None, host, builder); + run_cargo_test(cargo, &["--test-threads=1"], &[], None, host, builder); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -3253,7 +3187,7 @@ impl Step for RustInstaller { bootstrap_host, bootstrap_host, ); - run_cargo_test(cargo, &[], &[], "installer", None, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder); // We currently don't support running the test.sh script outside linux(?) environments. // Eventually this should likely migrate to #[test]s in rust-installer proper rather than a @@ -3441,7 +3375,7 @@ impl Step for CodegenCranelift { /* let mut prepare_cargo = build_cargo(); prepare_cargo.arg("--").arg("prepare").arg("--download-dir").arg(&download_dir); - #[allow(deprecated)] + #[expect(deprecated)] builder.config.try_run(&mut prepare_cargo.into()).unwrap(); */ @@ -3522,6 +3456,8 @@ impl Step for CodegenGCC { let compiler = self.compiler; let target = self.target; + let gcc = builder.ensure(Gcc { target }); + builder.ensure( compile::Std::new(compiler, target) .extra_rust_args(&["-Csymbol-mangling-version=v0", "-Cpanic=abort"]), @@ -3548,6 +3484,7 @@ impl Step for CodegenGCC { .arg("--manifest-path") .arg(builder.src.join("compiler/rustc_codegen_gcc/build_system/Cargo.toml")); compile::rustc_cargo_env(builder, &mut cargo, target, compiler.stage); + add_cg_gcc_cargo_flags(&mut cargo, &gcc); // Avoid incremental cache issues when changing rustc cargo.env("CARGO_BUILD_INCREMENTAL", "false"); @@ -3569,7 +3506,7 @@ impl Step for CodegenGCC { /* let mut prepare_cargo = build_cargo(); prepare_cargo.arg("--").arg("prepare"); - #[allow(deprecated)] + #[expect(deprecated)] builder.config.try_run(&mut prepare_cargo.into()).unwrap(); */ @@ -3580,9 +3517,10 @@ impl Step for CodegenGCC { .env("CG_RUSTFLAGS", "-Alinker-messages") .arg("--") .arg("test") - .arg("--use-system-gcc") .arg("--use-backend") .arg("gcc") + .arg("--gcc-path") + .arg(gcc.libgccjit.parent().unwrap()) .arg("--out-dir") .arg(builder.stage_out(compiler, Mode::ToolRustc).join("cg_gcc")) .arg("--release") @@ -3624,7 +3562,7 @@ impl Step for TestFloatParse { let bootstrap_host = builder.config.build; let compiler = builder.compiler(builder.top_stage, bootstrap_host); let path = self.path.to_str().unwrap(); - let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap(); + let crate_name = self.path.iter().next_back().unwrap().to_str().unwrap(); builder.ensure(tool::TestFloatParse { host: self.host }); @@ -3640,7 +3578,7 @@ impl Step for TestFloatParse { &[], ); - run_cargo_test(cargo_test, &[], &[], crate_name, crate_name, bootstrap_host, builder); + run_cargo_test(cargo_test, &[], &[], crate_name, bootstrap_host, builder); // Run the actual parse tests. let mut cargo_run = tool::prepare_tool_cargo( diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 75bfff340862a..aaf6712102cfc 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -1,3 +1,14 @@ +//! This module handles building and managing various tools in bootstrap +//! build system. +//! +//! **What It Does** +//! - Defines how tools are built, configured and installed. +//! - Manages tool dependencies and build steps. +//! - Copies built tool binaries to the correct locations. +//! +//! Each Rust tool **MUST** utilize `ToolBuild` inside their `Step` logic, +//! return `ToolBuildResult` and should never prepare `cargo` invocations manually. + use std::path::PathBuf; use std::{env, fs}; @@ -23,6 +34,12 @@ pub enum SourceType { Submodule, } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub enum ToolArtifactKind { + Binary, + Library, +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct ToolBuild { compiler: Compiler, @@ -36,6 +53,8 @@ struct ToolBuild { allow_features: &'static str, /// Additional arguments to pass to the `cargo` invocation. cargo_args: Vec, + /// Whether the tool builds a binary or a library. + artifact_kind: ToolArtifactKind, } impl Builder<'_> { @@ -64,8 +83,21 @@ impl Builder<'_> { } } +/// Result of the tool build process. Each `Step` in this module is responsible +/// for using this type as `type Output = ToolBuildResult;` +#[derive(Clone)] +pub struct ToolBuildResult { + /// Artifact path of the corresponding tool that was built. + pub tool_path: PathBuf, + /// Compiler used to build the tool. For non-`ToolRustc` tools this is equal to `target_compiler`. + /// For `ToolRustc` this is one stage before of the `target_compiler`. + pub build_compiler: Compiler, + /// Target compiler passed to `Step`. + pub target_compiler: Compiler, +} + impl Step for ToolBuild { - type Output = PathBuf; + type Output = ToolBuildResult; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() @@ -75,25 +107,39 @@ impl Step for ToolBuild { /// /// This will build the specified tool with the specified `host` compiler in /// `stage` into the normal cargo output directory. - fn run(self, builder: &Builder<'_>) -> PathBuf { - let compiler = self.compiler; + fn run(mut self, builder: &Builder<'_>) -> ToolBuildResult { let target = self.target; let mut tool = self.tool; let path = self.path; + let target_compiler = self.compiler; + self.compiler = if self.mode == Mode::ToolRustc { + get_tool_rustc_compiler(builder, self.compiler) + } else { + self.compiler + }; + match self.mode { Mode::ToolRustc => { - builder.ensure(compile::Std::new(compiler, compiler.host)); - builder.ensure(compile::Rustc::new(compiler, target)); + // If compiler was forced, its artifacts should be prepared earlier. + if !self.compiler.is_forced_compiler() { + builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); + builder.ensure(compile::Rustc::new(self.compiler, target)); + } + } + Mode::ToolStd => { + // If compiler was forced, its artifacts should be prepared earlier. + if !self.compiler.is_forced_compiler() { + builder.ensure(compile::Std::new(self.compiler, target)) + } } - Mode::ToolStd => builder.ensure(compile::Std::new(compiler, target)), Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs _ => panic!("unexpected Mode for tool build"), } let mut cargo = prepare_tool_cargo( builder, - compiler, + self.compiler, self.mode, target, Kind::Build, @@ -101,10 +147,28 @@ impl Step for ToolBuild { self.source_type, &self.extra_features, ); + + if path.ends_with("/rustdoc") && + // rustdoc is performance sensitive, so apply LTO to it. + is_lto_stage(&self.compiler) + { + let lto = match builder.config.rust_lto { + RustcLto::Off => Some("off"), + RustcLto::Thin => Some("thin"), + RustcLto::Fat => Some("fat"), + RustcLto::ThinLocal => None, + }; + if let Some(lto) = lto { + cargo.env(cargo_profile_var("LTO", &builder.config), lto); + } + } + if !self.allow_features.is_empty() { cargo.allow_features(self.allow_features); } + cargo.args(self.cargo_args); + let _guard = builder.msg_tool( Kind::Build, self.mode, @@ -131,12 +195,21 @@ impl Step for ToolBuild { if tool == "tidy" { tool = "rust-tidy"; } - copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool) + let tool_path = match self.artifact_kind { + ToolArtifactKind::Binary => { + copy_link_tool_bin(builder, self.compiler, self.target, self.mode, tool) + } + ToolArtifactKind::Library => builder + .cargo_out(self.compiler, self.mode, self.target) + .join(format!("lib{tool}.rlib")), + }; + + ToolBuildResult { tool_path, build_compiler: self.compiler, target_compiler } } } } -#[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this. +#[expect(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this. pub fn prepare_tool_cargo( builder: &Builder<'_>, compiler: Compiler, @@ -155,7 +228,6 @@ pub fn prepare_tool_cargo( let mut features = extra_features.to_vec(); if builder.build.config.cargo_native_static { if path.ends_with("cargo") - || path.ends_with("rls") || path.ends_with("clippy") || path.ends_with("miri") || path.ends_with("rustfmt") @@ -183,23 +255,32 @@ pub fn prepare_tool_cargo( cargo.env("CFG_VERSION", builder.rust_version()); cargo.env("CFG_RELEASE_NUM", &builder.version); cargo.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel()); + if let Some(ref ver_date) = builder.rust_info().commit_date() { cargo.env("CFG_VER_DATE", ver_date); } + if let Some(ref ver_hash) = builder.rust_info().sha() { cargo.env("CFG_VER_HASH", ver_hash); } + if let Some(description) = &builder.config.description { + cargo.env("CFG_VER_DESCRIPTION", description); + } + let info = GitInfo::new(builder.config.omit_git_hash, &dir); if let Some(sha) = info.sha() { cargo.env("CFG_COMMIT_HASH", sha); } + if let Some(sha_short) = info.sha_short() { cargo.env("CFG_SHORT_COMMIT_HASH", sha_short); } + if let Some(date) = info.commit_date() { cargo.env("CFG_COMMIT_DATE", date); } + if !features.is_empty() { cargo.arg("--features").arg(features.join(", ")); } @@ -240,6 +321,27 @@ pub fn prepare_tool_cargo( cargo } +/// Handle stage-off logic for `ToolRustc` tools when necessary. +pub(crate) fn get_tool_rustc_compiler( + builder: &Builder<'_>, + target_compiler: Compiler, +) -> Compiler { + if target_compiler.is_forced_compiler() { + return target_compiler; + } + + if builder.download_rustc() && target_compiler.stage > 0 { + // We already have the stage N compiler, we don't need to cut the stage. + return builder.compiler(target_compiler.stage, builder.config.build); + } + + // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise + // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage + // compilers, which isn't what we want. Rustc tools should be linked in the same way as the + // compiler it's paired with, so it must be built with the previous stage compiler. + builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build) +} + /// Links a built tool binary with the given `name` from the build directory to the /// tools directory. fn copy_link_tool_bin( @@ -262,6 +364,7 @@ macro_rules! bootstrap_tool { $(,is_unstable_tool = $unstable:expr)* $(,allow_features = $allow_features:expr)? $(,submodules = $submodules:expr)? + $(,artifact_kind = $artifact_kind:expr)? ; )+) => { #[derive(PartialEq, Eq, Clone)] @@ -279,7 +382,7 @@ macro_rules! bootstrap_tool { self.ensure($name { compiler: self.compiler(0, self.config.build), target: self.config.build, - }), + }).tool_path, )+ } } @@ -293,7 +396,7 @@ macro_rules! bootstrap_tool { } impl Step for $name { - type Output = PathBuf; + type Output = ToolBuildResult; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path($path) @@ -315,12 +418,13 @@ macro_rules! bootstrap_tool { skip_all, ), )] - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { $( for submodule in $submodules { builder.require_submodule(submodule, None); } )* + builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -339,7 +443,12 @@ macro_rules! bootstrap_tool { }, extra_features: vec![], allow_features: concat!($($allow_features)*), - cargo_args: vec![] + cargo_args: vec![], + artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* { + ToolArtifactKind::Library + } else { + ToolArtifactKind::Binary + } }) } } @@ -377,51 +486,14 @@ bootstrap_tool!( WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization"; UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator"; FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump"; + OptimizedDist, "src/tools/opt-dist", "opt-dist", submodules = &["src/tools/rustc-perf"]; + RunMakeSupport, "src/tools/run-make-support", "run_make_support", artifact_kind = ToolArtifactKind::Library; ); /// These are the submodules that are required for rustbook to work due to /// depending on mdbook plugins. pub static SUBMODULES_FOR_RUSTBOOK: &[&str] = &["src/doc/book", "src/doc/reference"]; -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct OptimizedDist { - pub compiler: Compiler, - pub target: TargetSelection, -} - -impl Step for OptimizedDist { - type Output = PathBuf; - - fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/opt-dist") - } - - fn make_run(run: RunConfig<'_>) { - run.builder.ensure(OptimizedDist { - compiler: run.builder.compiler(0, run.builder.config.build), - target: run.target, - }); - } - - fn run(self, builder: &Builder<'_>) -> PathBuf { - // We need to ensure the rustc-perf submodule is initialized when building opt-dist since - // the tool requires it to be in place to run. - builder.require_submodule("src/tools/rustc-perf", None); - - builder.ensure(ToolBuild { - compiler: self.compiler, - target: self.target, - tool: "opt-dist", - mode: Mode::ToolBootstrap, - path: "src/tools/opt-dist", - source_type: SourceType::InTree, - extra_features: Vec::new(), - allow_features: "", - cargo_args: Vec::new(), - }) - } -} - /// The [rustc-perf](https://github.com/rust-lang/rustc-perf) benchmark suite, which is added /// as a submodule at `src/tools/rustc-perf`. #[derive(Debug, Clone, Hash, PartialEq, Eq)] @@ -432,7 +504,7 @@ pub struct RustcPerf { impl Step for RustcPerf { /// Path to the built `collector` binary. - type Output = PathBuf; + type Output = ToolBuildResult; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/rustc-perf") @@ -445,7 +517,7 @@ impl Step for RustcPerf { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { // We need to ensure the rustc-perf submodule is initialized. builder.require_submodule("src/tools/rustc-perf", None); @@ -461,13 +533,14 @@ impl Step for RustcPerf { // Only build the collector package, which is used for benchmarking through // a CLI. cargo_args: vec!["-p".to_string(), "collector".to_string()], + artifact_kind: ToolArtifactKind::Binary, }; - let collector_bin = builder.ensure(tool.clone()); + let res = builder.ensure(tool.clone()); // We also need to symlink the `rustc-fake` binary to the corresponding directory, // because `collector` expects it in the same directory. copy_link_tool_bin(builder, tool.compiler, tool.target, tool.mode, "rustc-fake"); - collector_bin + res } } @@ -482,7 +555,7 @@ impl ErrorIndex { // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc. let host = builder.config.build; let compiler = builder.compiler_for(builder.top_stage, host, host); - let mut cmd = command(builder.ensure(ErrorIndex { compiler })); + let mut cmd = command(builder.ensure(ErrorIndex { compiler }).tool_path); let mut dylib_paths = builder.rustc_lib_paths(compiler); dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, compiler.host))); add_dylib_path(dylib_paths, &mut cmd); @@ -491,27 +564,23 @@ impl ErrorIndex { } impl Step for ErrorIndex { - type Output = PathBuf; + type Output = ToolBuildResult; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/error_index_generator") } fn make_run(run: RunConfig<'_>) { - // Compile the error-index in the same stage as rustdoc to avoid - // recompiling rustdoc twice if we can. - // // NOTE: This `make_run` isn't used in normal situations, only if you // manually build the tool with `x.py build // src/tools/error-index-generator` which almost nobody does. // Normally, `x.py test` or `x.py doc` will use the // `ErrorIndex::command` function instead. - let compiler = - run.builder.compiler(run.builder.top_stage.saturating_sub(1), run.builder.config.build); + let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build); run.builder.ensure(ErrorIndex { compiler }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { compiler: self.compiler, target: self.compiler.host, @@ -522,6 +591,7 @@ impl Step for ErrorIndex { extra_features: Vec::new(), allow_features: "", cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, }) } } @@ -533,7 +603,7 @@ pub struct RemoteTestServer { } impl Step for RemoteTestServer { - type Output = PathBuf; + type Output = ToolBuildResult; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.path("src/tools/remote-test-server") @@ -546,7 +616,7 @@ impl Step for RemoteTestServer { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -557,6 +627,7 @@ impl Step for RemoteTestServer { extra_features: Vec::new(), allow_features: "", cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, }) } } @@ -569,7 +640,7 @@ pub struct Rustdoc { } impl Step for Rustdoc { - type Output = PathBuf; + type Output = ToolBuildResult; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -578,24 +649,25 @@ impl Step for Rustdoc { } fn make_run(run: RunConfig<'_>) { - run.builder.ensure(Rustdoc { - // NOTE: this is somewhat unique in that we actually want a *target* - // compiler here, because rustdoc *is* a compiler. We won't be using - // this as the compiler to build with, but rather this is "what - // compiler are we producing"? - compiler: run.builder.compiler(run.builder.top_stage, run.target), - }); + run.builder + .ensure(Rustdoc { compiler: run.builder.compiler(run.builder.top_stage, run.target) }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { let target_compiler = self.compiler; + let target = target_compiler.host; + if target_compiler.stage == 0 { if !target_compiler.is_snapshot(builder) { panic!("rustdoc in stage 0 must be snapshot rustdoc"); } - return builder.initial_rustdoc.clone(); + + return ToolBuildResult { + tool_path: builder.initial_rustdoc.clone(), + build_compiler: target_compiler, + target_compiler, + }; } - let target = target_compiler.host; let bin_rustdoc = || { let sysroot = builder.sysroot(target_compiler); @@ -625,27 +697,15 @@ impl Step for Rustdoc { let bin_rustdoc = bin_rustdoc(); builder.copy_link(&precompiled_rustdoc, &bin_rustdoc); - return bin_rustdoc; + + return ToolBuildResult { + tool_path: bin_rustdoc, + build_compiler: target_compiler, + target_compiler, + }; } } - let build_compiler = if builder.download_rustc() && target_compiler.stage == 1 { - // We already have the stage 1 compiler, we don't need to cut the stage. - builder.compiler(target_compiler.stage, builder.config.build) - } else { - // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise - // we'd have stageN/bin/rustc and stageN/bin/rustdoc be effectively different stage - // compilers, which isn't what we want. Rustdoc should be linked in the same way as the - // rustc compiler it's paired with, so it must be built with the previous stage compiler. - builder.compiler(target_compiler.stage - 1, builder.config.build) - }; - - // When using `download-rustc` and a stage0 build_compiler, copying rustc doesn't actually - // build stage0 libstd (because the libstd in sysroot has the wrong ABI). Explicitly build - // it. - builder.ensure(compile::Std::new(build_compiler, target_compiler.host)); - builder.ensure(compile::Rustc::new(build_compiler, target_compiler.host)); - // The presence of `target_compiler` ensures that the necessary libraries (codegen backends, // compiler libraries, ...) are built. Rustdoc does not require the presence of any // libraries within sysroot_libdir (i.e., rustlib), though doctests may want it (since @@ -653,65 +713,40 @@ impl Step for Rustdoc { // libraries here. The intuition here is that If we've built a compiler, we should be able // to build rustdoc. // - let mut features = Vec::new(); + let mut extra_features = Vec::new(); if builder.config.jemalloc(target) { - features.push("jemalloc".to_string()); + extra_features.push("jemalloc".to_string()); } - // NOTE: Never modify the rustflags here, it breaks the build cache for other tools! - let mut cargo = prepare_tool_cargo( - builder, - build_compiler, - Mode::ToolRustc, - target, - Kind::Build, - "src/tools/rustdoc", - SourceType::InTree, - features.as_slice(), - ); - - // rustdoc is performance sensitive, so apply LTO to it. - if is_lto_stage(&build_compiler) { - let lto = match builder.config.rust_lto { - RustcLto::Off => Some("off"), - RustcLto::Thin => Some("thin"), - RustcLto::Fat => Some("fat"), - RustcLto::ThinLocal => None, - }; - if let Some(lto) = lto { - cargo.env(cargo_profile_var("LTO", &builder.config), lto); - } - } - - let _guard = builder.msg_tool( - Kind::Build, - Mode::ToolRustc, - "rustdoc", - build_compiler.stage, - &self.compiler.host, - &target, - ); - cargo.into_cmd().run(builder); - - // Cargo adds a number of paths to the dylib search path on windows, which results in - // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" - // rustdoc a different name. - let tool_rustdoc = builder - .cargo_out(build_compiler, Mode::ToolRustc, target) - .join(exe("rustdoc_tool_binary", target_compiler.host)); + let ToolBuildResult { tool_path, build_compiler, target_compiler } = + builder.ensure(ToolBuild { + compiler: target_compiler, + target, + // Cargo adds a number of paths to the dylib search path on windows, which results in + // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" + // rustdoc a different name. + tool: "rustdoc_tool_binary", + mode: Mode::ToolRustc, + path: "src/tools/rustdoc", + source_type: SourceType::InTree, + extra_features, + allow_features: "", + cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, + }); // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { if builder.config.rust_debuginfo_level_tools == DebuginfoLevel::None { // Due to LTO a lot of debug info from C++ dependencies such as jemalloc can make it into // our final binaries - compile::strip_debug(builder, target, &tool_rustdoc); + compile::strip_debug(builder, target, &tool_path); } let bin_rustdoc = bin_rustdoc(); - builder.copy_link(&tool_rustdoc, &bin_rustdoc); - bin_rustdoc + builder.copy_link(&tool_path, &bin_rustdoc); + ToolBuildResult { tool_path: bin_rustdoc, build_compiler, target_compiler } } else { - tool_rustdoc + ToolBuildResult { tool_path, build_compiler, target_compiler } } } } @@ -723,7 +758,7 @@ pub struct Cargo { } impl Step for Cargo { - type Output = PathBuf; + type Output = ToolBuildResult; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -739,7 +774,7 @@ impl Step for Cargo { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.build.require_submodule("src/tools/cargo", None); builder.ensure(ToolBuild { @@ -752,6 +787,7 @@ impl Step for Cargo { extra_features: Vec::new(), allow_features: "", cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, }) } } @@ -763,7 +799,7 @@ pub struct LldWrapper { } impl Step for LldWrapper { - type Output = (); + type Output = ToolBuildResult; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { run.never() @@ -778,14 +814,19 @@ impl Step for LldWrapper { fields(build_compiler = ?self.build_compiler, target_compiler = ?self.target_compiler), ), )] - fn run(self, builder: &Builder<'_>) { + + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { if builder.config.dry_run() { - return; + return ToolBuildResult { + tool_path: Default::default(), + build_compiler: self.build_compiler, + target_compiler: self.target_compiler, + }; } let target = self.target_compiler.host; - let executable = builder.ensure(ToolBuild { + let tool_result = builder.ensure(ToolBuild { compiler: self.build_compiler, target, tool: "lld-wrapper", @@ -795,6 +836,7 @@ impl Step for LldWrapper { extra_features: Vec::new(), allow_features: "", cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, }); let libdir_bin = builder.sysroot_target_bindir(self.target_compiler, target); @@ -809,8 +851,11 @@ impl Step for LldWrapper { t!(fs::create_dir_all(&self_contained_lld_dir)); for name in crate::LLD_FILE_NAMES { - builder.copy_link(&executable, &self_contained_lld_dir.join(exe(name, target))); + builder + .copy_link(&tool_result.tool_path, &self_contained_lld_dir.join(exe(name, target))); } + + tool_result } } @@ -825,7 +870,7 @@ impl RustAnalyzer { } impl Step for RustAnalyzer { - type Output = PathBuf; + type Output = ToolBuildResult; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -841,7 +886,7 @@ impl Step for RustAnalyzer { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, @@ -852,6 +897,7 @@ impl Step for RustAnalyzer { source_type: SourceType::InTree, allow_features: RustAnalyzer::ALLOW_FEATURES, cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, }) } } @@ -863,7 +909,7 @@ pub struct RustAnalyzerProcMacroSrv { } impl Step for RustAnalyzerProcMacroSrv { - type Output = Option; + type Output = Option; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -885,8 +931,8 @@ impl Step for RustAnalyzerProcMacroSrv { }); } - fn run(self, builder: &Builder<'_>) -> Option { - let path = builder.ensure(ToolBuild { + fn run(self, builder: &Builder<'_>) -> Option { + let tool_result = builder.ensure(ToolBuild { compiler: self.compiler, target: self.target, tool: "rust-analyzer-proc-macro-srv", @@ -896,15 +942,17 @@ impl Step for RustAnalyzerProcMacroSrv { source_type: SourceType::InTree, allow_features: RustAnalyzer::ALLOW_FEATURES, cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, }); // Copy `rust-analyzer-proc-macro-srv` to `/libexec/` // so that r-a can use it. let libexec_path = builder.sysroot(self.compiler).join("libexec"); t!(fs::create_dir_all(&libexec_path)); - builder.copy_link(&path, &libexec_path.join("rust-analyzer-proc-macro-srv")); + builder + .copy_link(&tool_result.tool_path, &libexec_path.join("rust-analyzer-proc-macro-srv")); - Some(path) + Some(tool_result) } } @@ -916,7 +964,7 @@ pub struct LlvmBitcodeLinker { } impl Step for LlvmBitcodeLinker { - type Output = PathBuf; + type Output = ToolBuildResult; const DEFAULT: bool = true; const ONLY_HOSTS: bool = true; @@ -938,51 +986,35 @@ impl Step for LlvmBitcodeLinker { feature = "tracing", instrument(level = "debug", name = "LlvmBitcodeLinker::run", skip_all) )] - fn run(self, builder: &Builder<'_>) -> PathBuf { - let bin_name = "llvm-bitcode-linker"; - - // If enabled, use ci-rustc and skip building the in-tree compiler. - if !builder.download_rustc() { - builder.ensure(compile::Std::new(self.compiler, self.compiler.host)); - builder.ensure(compile::Rustc::new(self.compiler, self.target)); - } - - let cargo = prepare_tool_cargo( - builder, - self.compiler, - Mode::ToolRustc, - self.target, - Kind::Build, - "src/tools/llvm-bitcode-linker", - SourceType::InTree, - &self.extra_features, - ); - - let _guard = builder.msg_tool( - Kind::Build, - Mode::ToolRustc, - bin_name, - self.compiler.stage, - &self.compiler.host, - &self.target, - ); - - cargo.into_cmd().run(builder); - - let tool_out = builder - .cargo_out(self.compiler, Mode::ToolRustc, self.target) - .join(exe(bin_name, self.compiler.host)); + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { + let tool_result = builder.ensure(ToolBuild { + compiler: self.compiler, + target: self.target, + tool: "llvm-bitcode-linker", + mode: Mode::ToolRustc, + path: "src/tools/llvm-bitcode-linker", + source_type: SourceType::InTree, + extra_features: self.extra_features, + allow_features: "", + cargo_args: Vec::new(), + artifact_kind: ToolArtifactKind::Binary, + }); - if self.compiler.stage > 0 { + if tool_result.target_compiler.stage > 0 { let bindir_self_contained = builder - .sysroot(self.compiler) + .sysroot(tool_result.target_compiler) .join(format!("lib/rustlib/{}/bin/self-contained", self.target.triple)); t!(fs::create_dir_all(&bindir_self_contained)); - let bin_destination = bindir_self_contained.join(exe(bin_name, self.compiler.host)); - builder.copy_link(&tool_out, &bin_destination); - bin_destination + let bin_destination = bindir_self_contained + .join(exe("llvm-bitcode-linker", tool_result.target_compiler.host)); + builder.copy_link(&tool_result.tool_path, &bin_destination); + ToolBuildResult { + tool_path: bin_destination, + build_compiler: tool_result.build_compiler, + target_compiler: tool_result.target_compiler, + } } else { - tool_out + tool_result } } } @@ -992,7 +1024,7 @@ pub struct LibcxxVersionTool { pub target: TargetSelection, } -#[allow(dead_code)] +#[expect(dead_code)] #[derive(Debug, Clone)] pub enum LibcxxVersion { Gnu(usize), @@ -1067,7 +1099,7 @@ macro_rules! tool_extended { } impl Step for $name { - type Output = PathBuf; + type Output = ToolBuildResult; const DEFAULT: bool = true; // Overridden by `should_run_tool_build_step` const ONLY_HOSTS: bool = true; @@ -1087,7 +1119,7 @@ macro_rules! tool_extended { }); } - fn run(self, builder: &Builder<'_>) -> PathBuf { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { let Self { compiler, target } = self; run_tool_build_step( builder, @@ -1133,48 +1165,58 @@ fn run_tool_build_step( tool_name: &'static str, path: &'static str, add_bins_to_sysroot: Option<&[&str]>, -) -> PathBuf { - let tool = builder.ensure(ToolBuild { - compiler, - target, - tool: tool_name, - mode: Mode::ToolRustc, - path, - extra_features: vec![], - source_type: SourceType::InTree, - allow_features: "", - cargo_args: vec![], - }); +) -> ToolBuildResult { + let ToolBuildResult { tool_path, build_compiler, target_compiler } = + builder.ensure(ToolBuild { + compiler, + target, + tool: tool_name, + mode: Mode::ToolRustc, + path, + extra_features: vec![], + source_type: SourceType::InTree, + allow_features: "", + cargo_args: vec![], + artifact_kind: ToolArtifactKind::Binary, + }); // FIXME: This should just be an if-let-chain, but those are unstable. if let Some(add_bins_to_sysroot) = - add_bins_to_sysroot.filter(|bins| !bins.is_empty() && compiler.stage > 0) + add_bins_to_sysroot.filter(|bins| !bins.is_empty() && target_compiler.stage > 0) { - let bindir = builder.sysroot(compiler).join("bin"); + let bindir = builder.sysroot(target_compiler).join("bin"); t!(fs::create_dir_all(&bindir)); - let tools_out = builder.cargo_out(compiler, Mode::ToolRustc, target); - for add_bin in add_bins_to_sysroot { - let bin_source = tools_out.join(exe(add_bin, target)); - let bin_destination = bindir.join(exe(add_bin, compiler.host)); - builder.copy_link(&bin_source, &bin_destination); + let bin_destination = bindir.join(exe(add_bin, target_compiler.host)); + builder.copy_link(&tool_path, &bin_destination); } // Return a path into the bin dir. - bindir.join(exe(tool_name, compiler.host)) + let path = bindir.join(exe(tool_name, target_compiler.host)); + ToolBuildResult { tool_path: path, build_compiler, target_compiler } } else { - tool + ToolBuildResult { tool_path, build_compiler, target_compiler } } } -tool_extended!(Cargofmt { path: "src/tools/rustfmt", tool_name: "cargo-fmt", stable: true }); -tool_extended!(CargoClippy { path: "src/tools/clippy", tool_name: "cargo-clippy", stable: true }); +tool_extended!(Cargofmt { + path: "src/tools/rustfmt", + tool_name: "cargo-fmt", + stable: true, + add_bins_to_sysroot: ["cargo-fmt"] +}); +tool_extended!(CargoClippy { + path: "src/tools/clippy", + tool_name: "cargo-clippy", + stable: true, + add_bins_to_sysroot: ["cargo-clippy"] +}); tool_extended!(Clippy { path: "src/tools/clippy", tool_name: "clippy-driver", stable: true, - add_bins_to_sysroot: ["clippy-driver", "cargo-clippy"] + add_bins_to_sysroot: ["clippy-driver"] }); tool_extended!(Miri { path: "src/tools/miri", @@ -1188,12 +1230,11 @@ tool_extended!(CargoMiri { stable: false, add_bins_to_sysroot: ["cargo-miri"] }); -tool_extended!(Rls { path: "src/tools/rls", tool_name: "rls", stable: true }); tool_extended!(Rustfmt { path: "src/tools/rustfmt", tool_name: "rustfmt", stable: true, - add_bins_to_sysroot: ["rustfmt", "cargo-fmt"] + add_bins_to_sysroot: ["rustfmt"] }); #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -1202,7 +1243,7 @@ pub struct TestFloatParse { } impl Step for TestFloatParse { - type Output = (); + type Output = ToolBuildResult; const ONLY_HOSTS: bool = true; const DEFAULT: bool = false; @@ -1210,7 +1251,7 @@ impl Step for TestFloatParse { run.path("src/etc/test-float-parse") } - fn run(self, builder: &Builder<'_>) { + fn run(self, builder: &Builder<'_>) -> ToolBuildResult { let bootstrap_host = builder.config.build; let compiler = builder.compiler(builder.top_stage, bootstrap_host); @@ -1224,7 +1265,8 @@ impl Step for TestFloatParse { extra_features: Vec::new(), allow_features: "", cargo_args: Vec::new(), - }); + artifact_kind: ToolArtifactKind::Binary, + }) } } diff --git a/src/bootstrap/src/core/build_steps/toolstate.rs b/src/bootstrap/src/core/build_steps/toolstate.rs index 668133f05cb35..a65623de95a3f 100644 --- a/src/bootstrap/src/core/build_steps/toolstate.rs +++ b/src/bootstrap/src/core/build_steps/toolstate.rs @@ -354,12 +354,12 @@ fn read_old_toolstate() -> Vec { /// 1. Generate a new Personal access token: /// /// * Login to the bot account, and go to Settings -> Developer settings -> -/// Personal access tokens +/// Personal access tokens /// * Click "Generate new token" /// * Enable the "public_repo" permission, then click "Generate token" /// * Copy the generated token (should be a 40-digit hexadecimal number). -/// Save it somewhere secure, as the token would be gone once you leave -/// the page. +/// Save it somewhere secure, as the token would be gone once you leave +/// the page. /// /// 2. Update the variable group in Azure Pipelines /// @@ -368,7 +368,7 @@ fn read_old_toolstate() -> Vec { /// 4. Replace the email address below if the bot account identity is changed /// /// * See -/// if a private email by GitHub is wanted. +/// if a private email by GitHub is wanted. fn commit_toolstate_change(builder: &Builder<'_>, current_toolstate: &ToolstateData) { let message = format!("({} CI update)", OS.expect("linux/windows only")); let mut success = false; diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 410dbc04f0306..0caeb328811aa 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -1,9 +1,14 @@ +//! Handles the vendoring process for the bootstrap system. +//! +//! This module ensures that all required Cargo dependencies are gathered +//! and stored in the `/` directory. use std::path::PathBuf; use crate::core::build_steps::tool::SUBMODULES_FOR_RUSTBOOK; use crate::core::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::utils::exec::command; +/// The name of the directory where vendored dependencies are stored. pub const VENDOR_DIR: &str = "vendor"; /// Returns the cargo workspaces to vendor for `x vendor` and dist tarballs. @@ -29,11 +34,19 @@ pub fn default_paths_to_vendor(builder: &Builder<'_>) -> Vec<(PathBuf, Vec<&'sta .collect() } +/// Defines the vendoring step in the bootstrap process. +/// +/// This step executes `cargo vendor` to collect all dependencies +/// and store them in the `/` directory. #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub(crate) struct Vendor { + /// Additional paths to synchronize during vendoring. pub(crate) sync_args: Vec, + /// Determines whether vendored dependencies use versioned directories. pub(crate) versioned_dirs: bool, + /// The root directory of the source code. pub(crate) root_dir: PathBuf, + /// The target directory for storing vendored dependencies. pub(crate) output_dir: PathBuf, } @@ -55,6 +68,10 @@ impl Step for Vendor { }); } + /// Executes the vendoring process. + /// + /// This function runs `cargo vendor` and ensures all required submodules + /// are initialized before vendoring begins. fn run(self, builder: &Builder<'_>) -> Self::Output { builder.info(&format!("Vendoring sources to {:?}", self.root_dir)); @@ -86,6 +103,7 @@ impl Step for Vendor { // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. cmd.env("RUSTC_BOOTSTRAP", "1"); + cmd.env("RUSTC", &builder.initial_rustc); cmd.current_dir(self.root_dir).arg(&self.output_dir); @@ -94,6 +112,7 @@ impl Step for Vendor { } } +/// Stores the result of the vendoring step. #[derive(Debug, Clone)] pub(crate) struct VendorOutput { pub(crate) config: String, diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 1ec3e601cad19..62d23c4ae6b23 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -260,7 +260,7 @@ impl Cargo { } } - for arg in linker_args(builder, compiler.host, LldThreads::Yes) { + for arg in linker_args(builder, compiler.host, LldThreads::Yes, 0) { self.hostflags.arg(&arg); } @@ -270,10 +270,10 @@ impl Cargo { } // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not // `linker_args` here. - for flag in linker_flags(builder, target, LldThreads::Yes) { + for flag in linker_flags(builder, target, LldThreads::Yes, compiler.stage) { self.rustflags.arg(&flag); } - for arg in linker_args(builder, target, LldThreads::Yes) { + for arg in linker_args(builder, target, LldThreads::Yes, compiler.stage) { self.rustdocflags.arg(&arg); } @@ -285,10 +285,7 @@ impl Cargo { // Ignore linker warnings for now. These are complicated to fix and don't affect the build. // FIXME: we should really investigate these... - // cfg(bootstrap) - if compiler.stage != 0 { - self.rustflags.arg("-Alinker-messages"); - } + self.rustflags.arg("-Alinker-messages"); // Throughout the build Cargo can execute a number of build scripts // compiling C/C++ code and we need to pass compilers, archivers, flags, etc @@ -600,7 +597,7 @@ impl Builder<'_> { // sysroot. Passing this cfg enables raw-dylib support instead, which makes the native // library unnecessary. This can be removed when windows-rs enables raw-dylib // unconditionally. - if let Mode::Rustc | Mode::ToolRustc = mode { + if let Mode::Rustc | Mode::ToolRustc | Mode::ToolBootstrap = mode { rustflags.arg("--cfg=windows_raw_dylib"); } @@ -611,11 +608,10 @@ impl Builder<'_> { } // FIXME: the following components don't build with `-Zrandomize-layout` yet: - // - wasm-component-ld, due to the `wast`crate // - rust-analyzer, due to the rowan crate - // so we exclude entire categories of steps here due to lack of fine-grained control over + // so we exclude an entire category of steps here due to lack of fine-grained control over // rustflags. - if self.config.rust_randomize_layout && mode != Mode::ToolStd && mode != Mode::ToolRustc { + if self.config.rust_randomize_layout && mode != Mode::ToolRustc { rustflags.arg("-Zrandomize-layout"); } @@ -779,6 +775,12 @@ impl Builder<'_> { Mode::Codegen => metadata.push_str("codegen"), _ => {} } + // `rustc_driver`'s version number is always `0.0.0`, which can cause linker search path + // problems on side-by-side installs because we don't include the version number of the + // `rustc_driver` being built. This can cause builds of different version numbers to produce + // `librustc_driver*.so` artifacts that end up with identical filename hashes. + metadata.push_str(&self.version); + cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata); if cmd_kind == Kind::Clippy { @@ -1043,8 +1045,11 @@ impl Builder<'_> { // so this line allows the use of custom libcs. cargo.env("LIBC_CHECK_CFG", "1"); + let mut lint_flags = Vec::new(); + + // Lints for all in-tree code: compiler, rustdoc, cranelift, gcc, + // clippy, rustfmt, rust-analyzer, etc. if source_type == SourceType::InTree { - let mut lint_flags = Vec::new(); // When extending this list, add the new lints to the RUSTFLAGS of the // build_bootstrap function of src/bootstrap/bootstrap.py as well as // some code doesn't go through this `rustc` wrapper. @@ -1056,30 +1061,32 @@ impl Builder<'_> { rustdocflags.arg("-Dwarnings"); } - // This does not use RUSTFLAGS due to caching issues with Cargo. - // Clippy is treated as an "in tree" tool, but shares the same - // cache as other "submodule" tools. With these options set in - // RUSTFLAGS, that causes *every* shared dependency to be rebuilt. - // By injecting this into the rustc wrapper, this circumvents - // Cargo's fingerprint detection. This is fine because lint flags - // are always ignored in dependencies. Eventually this should be - // fixed via better support from Cargo. - cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" ")); - rustdocflags.arg("-Wrustdoc::invalid_codeblock_attributes"); } + // Lints just for `compiler/` crates. if mode == Mode::Rustc { - rustflags.arg("-Wrustc::internal"); - // cfg(bootstrap) - remove this check when lint is in bootstrap compiler - if stage != 0 { - rustflags.arg("-Drustc::symbol_intern_string_literal"); - } + lint_flags.push("-Wrustc::internal"); + lint_flags.push("-Drustc::symbol_intern_string_literal"); // FIXME(edition_2024): Change this to `-Wrust_2024_idioms` when all // of the individual lints are satisfied. - rustflags.arg("-Wkeyword_idents_2024"); - rustflags.arg("-Wunsafe_op_in_unsafe_fn"); - } + lint_flags.push("-Wkeyword_idents_2024"); + lint_flags.push("-Wunreachable_pub"); + lint_flags.push("-Wunsafe_op_in_unsafe_fn"); + } + + // This does not use RUSTFLAGS for two reasons. + // - Due to caching issues with Cargo. Clippy is treated as an "in + // tree" tool, but shares the same cache as other "submodule" tools. + // With these options set in RUSTFLAGS, that causes *every* shared + // dependency to be rebuilt. By injecting this into the rustc + // wrapper, this circumvents Cargo's fingerprint detection. This is + // fine because lint flags are always ignored in dependencies. + // Eventually this should be fixed via better support from Cargo. + // - RUSTFLAGS is ignored for proc macro crates that are being built on + // the host (because `--target` is given). But we want the lint flags + // to be applied to proc macro crates. + cargo.env("RUSTC_LINT_FLAGS", lint_flags.join(" ")); if self.config.rust_frame_pointers { rustflags.arg("-Cforce-frame-pointers=true"); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index daef8fa3c8a34..0b6b8513cc3a7 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -50,7 +50,7 @@ pub struct Builder<'a> { /// A stack of [`Step`]s to run before we can run this builder. The output /// of steps is cached in [`Self::cache`]. - stack: RefCell>>, + stack: RefCell>>, /// The total amount of time we spent running [`Step`]s in [`Self::stack`]. time_spent_on_dependencies: Cell, @@ -69,6 +69,21 @@ impl Deref for Builder<'_> { } } +/// This trait is similar to `Any`, except that it also exposes the underlying +/// type's [`Debug`] implementation. +/// +/// (Trying to debug-print `dyn Any` results in the unhelpful `"Any { .. }"`.) +trait AnyDebug: Any + Debug {} +impl AnyDebug for T {} +impl dyn AnyDebug { + /// Equivalent to `::downcast_ref`. + fn downcast_ref(&self) -> Option<&T> { + (self as &dyn Any).downcast_ref() + } + + // Feel free to add other `dyn Any` methods as necessary. +} + pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { /// Result type of `Step::run`. type Output: Clone; @@ -880,7 +895,6 @@ impl<'a> Builder<'a> { tool::RemoteTestClient, tool::RustInstaller, tool::Cargo, - tool::Rls, tool::RustAnalyzer, tool::RustAnalyzerProcMacroSrv, tool::Rustdoc, @@ -890,6 +904,7 @@ impl<'a> Builder<'a> { gcc::Gcc, llvm::Sanitizers, tool::Rustfmt, + tool::Cargofmt, tool::Miri, tool::CargoMiri, llvm::Lld, @@ -922,7 +937,6 @@ impl<'a> Builder<'a> { clippy::OptDist, clippy::RemoteTestClient, clippy::RemoteTestServer, - clippy::Rls, clippy::RustAnalyzer, clippy::Rustdoc, clippy::Rustfmt, @@ -940,7 +954,6 @@ impl<'a> Builder<'a> { check::Miri, check::CargoMiri, check::MiroptTestTools, - check::Rls, check::Rustfmt, check::RustAnalyzer, check::TestFloatParse, @@ -1055,7 +1068,6 @@ impl<'a> Builder<'a> { dist::Analysis, dist::Src, dist::Cargo, - dist::Rls, dist::RustAnalyzer, dist::Rustfmt, dist::Clippy, @@ -1072,6 +1084,7 @@ impl<'a> Builder<'a> { dist::PlainSourceTarball, dist::BuildManifest, dist::ReproducibleArtifacts, + dist::Gcc ), Kind::Install => describe!( install::Docs, @@ -1100,6 +1113,7 @@ impl<'a> Builder<'a> { run::GenerateCompletions, run::UnicodeTableGenerator, run::FeaturesStatusDump, + run::CyclicStep, ), Kind::Setup => { describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor) @@ -1234,7 +1248,7 @@ impl<'a> Builder<'a> { ), )] pub fn compiler(&self, stage: u32, host: TargetSelection) -> Compiler { - self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } }) + self.ensure(compile::Assemble { target_compiler: Compiler::new(stage, host) }) } /// Similar to `compiler`, except handles the full-bootstrap option to @@ -1262,14 +1276,16 @@ impl<'a> Builder<'a> { ), ), )] + + /// FIXME: This function is unnecessary (and dangerous, see ). + /// We already have uplifting logic for the compiler, so remove this. pub fn compiler_for( &self, stage: u32, host: TargetSelection, target: TargetSelection, ) -> Compiler { - #![allow(clippy::let_and_return)] - let resolved_compiler = if self.build.force_use_stage2(stage) { + let mut resolved_compiler = if self.build.force_use_stage2(stage) { trace!(target: "COMPILER_FOR", ?stage, "force_use_stage2"); self.compiler(2, self.config.build) } else if self.build.force_use_stage1(stage, target) { @@ -1279,6 +1295,11 @@ impl<'a> Builder<'a> { trace!(target: "COMPILER_FOR", ?stage, ?host, "no force, fallback to `compiler()`"); self.compiler(stage, host) }; + + if stage != resolved_compiler.stage { + resolved_compiler.forced_compiler(true); + } + trace!(target: "COMPILER_FOR", ?resolved_compiler); resolved_compiler } @@ -1392,7 +1413,7 @@ impl<'a> Builder<'a> { } pub fn rustdoc(&self, compiler: Compiler) -> PathBuf { - self.ensure(tool::Rustdoc { compiler }) + self.ensure(tool::Rustdoc { compiler }).tool_path } pub fn cargo_clippy_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { @@ -1408,14 +1429,13 @@ impl<'a> Builder<'a> { return cmd; } - let build_compiler = self.compiler(run_compiler.stage - 1, self.build.build); - self.ensure(tool::Clippy { compiler: build_compiler, target: self.build.build }); + let _ = self.ensure(tool::Clippy { compiler: run_compiler, target: self.build.build }); let cargo_clippy = - self.ensure(tool::CargoClippy { compiler: build_compiler, target: self.build.build }); + self.ensure(tool::CargoClippy { compiler: run_compiler, target: self.build.build }); let mut dylib_path = helpers::dylib_path(); dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); - let mut cmd = command(cargo_clippy); + let mut cmd = command(cargo_clippy.tool_path); cmd.env(helpers::dylib_path_var(), env::join_paths(&dylib_path).unwrap()); cmd.env("CARGO", &self.initial_cargo); cmd @@ -1423,23 +1443,21 @@ impl<'a> Builder<'a> { pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { 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 }); + let miri = self.ensure(tool::Miri { compiler: run_compiler, target: self.build.build }); let cargo_miri = - self.ensure(tool::CargoMiri { compiler: build_compiler, target: self.build.build }); + self.ensure(tool::CargoMiri { compiler: run_compiler, target: self.build.build }); // Invoke cargo-miri, make sure it can find miri and cargo. - let mut cmd = command(cargo_miri); - cmd.env("MIRI", &miri); + let mut cmd = command(cargo_miri.tool_path); + cmd.env("MIRI", &miri.tool_path); cmd.env("CARGO", &self.initial_cargo); - // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`, - // so they match the Miri we just built. However this means they are actually living one - // stage up, i.e. we are running `stage0-tools-bin/miri` with the libraries in `stage1/lib`. - // This is an unfortunate off-by-1 caused (possibly) by the fact that Miri doesn't have an - // "assemble" step like rustc does that would cross the stage boundary. We can't use - // `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries added to - // the PATH due to the stage mismatch. + // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler` + // in `tool::ToolBuild` step, so they match the Miri we just built. However this means they + // are actually living one stage up, i.e. we are running `stage0-tools-bin/miri` with the + // libraries in `stage1/lib`. This is an unfortunate off-by-1 caused (possibly) by the fact + // that Miri doesn't have an "assemble" step like rustc does that would cross the stage boundary. + // We can't use `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries + // added to the PATH due to the stage mismatch. // Also see https://github.com/rust-lang/rust/pull/123192#issuecomment-2028901503. add_dylib_path(self.rustc_lib_paths(run_compiler), &mut cmd); cmd @@ -1462,7 +1480,7 @@ impl<'a> Builder<'a> { cmd.arg("-Dwarnings"); } cmd.arg("-Znormalize-docs"); - cmd.args(linker_args(self, compiler.host, LldThreads::Yes)); + cmd.args(linker_args(self, compiler.host, LldThreads::Yes, compiler.stage)); cmd } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 445b5dfbeab22..b062781e68a71 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1,4 +1,4 @@ -use std::thread; +use std::{panic, thread}; use llvm::prebuilt_llvm_config; @@ -71,7 +71,7 @@ fn check_cli(paths: [&str; N]) { macro_rules! std { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Std::new( - Compiler { host: TargetSelection::from_user($host), stage: $stage }, + Compiler::new($stage, TargetSelection::from_user($host)), TargetSelection::from_user($target), ) }; @@ -84,7 +84,7 @@ macro_rules! doc_std { macro_rules! rustc { ($host:ident => $target:ident, stage = $stage:literal) => { compile::Rustc::new( - Compiler { host: TargetSelection::from_user($host), stage: $stage }, + Compiler::new($stage, TargetSelection::from_user($host)), TargetSelection::from_user($target), ) }; @@ -261,8 +261,14 @@ fn ci_rustc_if_unchanged_logic() { // Make sure "if-unchanged" logic doesn't try to use CI rustc while there are changes // in compiler and/or library. if config.download_rustc_commit.is_some() { - let has_changes = - config.last_modified_commit(&["compiler", "library"], "download-rustc", true).is_none(); + let mut paths = vec!["compiler"]; + + // Handle library tree the same way as in `Config::download_ci_rustc_commit`. + if build_helper::ci::CiEnv::is_ci() { + paths.push("library"); + } + + let has_changes = config.last_modified_commit(&paths, "download-rustc", true).is_none(); assert!( !has_changes, @@ -296,7 +302,7 @@ mod defaults { first(cache.all::()), // Recall that rustdoc stages are off-by-one // - this is the compiler it's _linked_ to, not built with. - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }], + &[tool::Rustdoc { compiler: Compiler::new(1, a) }], ); assert_eq!( first(cache.all::()), @@ -319,7 +325,7 @@ mod defaults { first(cache.all::()), // This is the beta rustdoc. // Add an assert here to make sure this is the only rustdoc built. - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }], + &[tool::Rustdoc { compiler: Compiler::new(0, a) }], ); assert!(cache.all::().is_empty()); } @@ -352,16 +358,16 @@ mod defaults { assert_eq!( first(cache.all::()), &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + compile::Assemble { target_compiler: Compiler::new(0, a) }, + compile::Assemble { target_compiler: Compiler::new(1, a) }, + compile::Assemble { target_compiler: Compiler::new(1, b) }, ] ); assert_eq!( first(cache.all::()), &[ - tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, - tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + tool::Rustdoc { compiler: Compiler::new(1, a) }, + tool::Rustdoc { compiler: Compiler::new(1, b) }, ], ); assert_eq!( @@ -386,14 +392,14 @@ mod defaults { assert_eq!(first(cache.all::()), &[doc::ErrorIndex { target: a },]); assert_eq!( first(cache.all::()), - &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 0 } }] + &[tool::ErrorIndex { compiler: Compiler::new(0, a) }] ); // docs should be built with the beta compiler, not with the stage0 artifacts. // recall that rustdoc is off-by-one: `stage` is the compiler rustdoc is _linked_ to, // not the one it was built by. assert_eq!( first(cache.all::()), - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } },] + &[tool::Rustdoc { compiler: Compiler::new(0, a) },] ); } } @@ -418,17 +424,17 @@ mod dist { assert_eq!(first(cache.all::()), &[dist::Mingw { host: a },]); assert_eq!( first(cache.all::()), - &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },] + &[dist::Rustc { compiler: Compiler::new(2, a) },] ); assert_eq!( first(cache.all::()), - &[dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a },] + &[dist::Std { compiler: Compiler::new(1, a), target: a },] ); assert_eq!(first(cache.all::()), &[dist::Src]); // Make sure rustdoc is only built once. assert_eq!( first(cache.all::()), - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },] + &[tool::Rustdoc { compiler: Compiler::new(2, a) },] ); } @@ -450,13 +456,13 @@ mod dist { ); assert_eq!( first(cache.all::()), - &[dist::Rustc { compiler: Compiler { host: a, stage: 2 } },] + &[dist::Rustc { compiler: Compiler::new(2, a) },] ); assert_eq!( first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(2, a), target: b }, ] ); assert_eq!(first(cache.all::()), &[dist::Src]); @@ -483,15 +489,15 @@ mod dist { assert_eq!( first(cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + dist::Rustc { compiler: Compiler::new(2, a) }, + dist::Rustc { compiler: Compiler::new(2, b) }, ] ); assert_eq!( first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(1, a), target: b }, ] ); assert_eq!( @@ -519,7 +525,7 @@ mod dist { assert_eq!( first(cache.all::()), - &[dist::Rustc { compiler: Compiler { host: b, stage: 2 } },] + &[dist::Rustc { compiler: Compiler::new(2, b) },] ); assert_eq!( first(cache.all::()), @@ -555,16 +561,16 @@ mod dist { assert_eq!( first(cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + dist::Rustc { compiler: Compiler::new(2, a) }, + dist::Rustc { compiler: Compiler::new(2, b) }, ] ); assert_eq!( first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(1, a), target: b }, + dist::Std { compiler: Compiler::new(2, a), target: c }, ] ); assert_eq!(first(cache.all::()), &[dist::Src]); @@ -582,7 +588,7 @@ mod dist { assert_eq!(first(cache.all::()), &[dist::Mingw { host: c },]); assert_eq!( first(cache.all::()), - &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },] + &[dist::Std { compiler: Compiler::new(2, a), target: c },] ); } @@ -607,15 +613,15 @@ mod dist { assert_eq!( first(cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, + dist::Rustc { compiler: Compiler::new(2, a) }, + dist::Rustc { compiler: Compiler::new(2, b) }, ] ); assert_eq!( first(cache.all::()), &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + dist::Std { compiler: Compiler::new(1, a), target: a }, + dist::Std { compiler: Compiler::new(1, a), target: b }, ] ); assert_eq!(first(cache.all::()), &[dist::Src]); @@ -632,10 +638,10 @@ mod dist { assert_eq!( first(cache.all::()), &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, + compile::Assemble { target_compiler: Compiler::new(0, a) }, + compile::Assemble { target_compiler: Compiler::new(1, a) }, + compile::Assemble { target_compiler: Compiler::new(2, a) }, + compile::Assemble { target_compiler: Compiler::new(2, b) }, ] ); } @@ -652,6 +658,20 @@ mod dist { &["compiler/rustc".into(), "library".into()], ); + assert_eq!(builder.config.stage, 2); + + // `compile::Rustc` includes one-stage-off compiler information as the target compiler + // artifacts get copied from there to the target stage sysroot. + // For example, `stage2/bin/rustc` gets copied from the `stage1-rustc` build directory. + assert_eq!( + first(builder.cache.all::()), + &[ + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), + rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), + ] + ); + assert_eq!( first(builder.cache.all::()), &[ @@ -663,15 +683,22 @@ mod dist { std!(TEST_TRIPLE_1 => TEST_TRIPLE_3, stage = 2), ] ); - assert_eq!(builder.cache.all::().len(), 5); + assert_eq!( - first(builder.cache.all::()), + first(builder.cache.all::()), &[ - rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 0), - rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 1), - rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_1, stage = 2), - rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 1), - rustc!(TEST_TRIPLE_1 => TEST_TRIPLE_2, stage = 2), + compile::Assemble { + target_compiler: Compiler::new(0, TargetSelection::from_user(TEST_TRIPLE_1),) + }, + compile::Assemble { + target_compiler: Compiler::new(1, TargetSelection::from_user(TEST_TRIPLE_1),) + }, + compile::Assemble { + target_compiler: Compiler::new(2, TargetSelection::from_user(TEST_TRIPLE_1),) + }, + compile::Assemble { + target_compiler: Compiler::new(2, TargetSelection::from_user(TEST_TRIPLE_2),) + }, ] ); } @@ -713,9 +740,9 @@ mod dist { assert_eq!( first(builder.cache.all::()), &[ - compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, - compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, + compile::Assemble { target_compiler: Compiler::new(0, a) }, + compile::Assemble { target_compiler: Compiler::new(1, a) }, + compile::Assemble { target_compiler: Compiler::new(2, a) }, ] ); assert_eq!( @@ -764,7 +791,7 @@ mod dist { assert_eq!( first(builder.cache.all::()), &[test::Crate { - compiler: Compiler { host, stage: 0 }, + compiler: Compiler::new(0, host), target: host, mode: crate::Mode::Std, crates: vec!["std".to_owned()], @@ -790,13 +817,13 @@ mod dist { ); assert_eq!( first(builder.cache.all::()), - &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }] + &[tool::ErrorIndex { compiler: Compiler::new(1, a) }] ); // This is actually stage 1, but Rustdoc::run swaps out the compiler with // stage minus 1 if --stage is not 0. Very confusing! assert_eq!( first(builder.cache.all::()), - &[tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } },] + &[tool::Rustdoc { compiler: Compiler::new(2, a) },] ); } @@ -836,7 +863,7 @@ mod dist { ); assert_eq!( first(builder.cache.all::()), - &[tool::ErrorIndex { compiler: Compiler { host: a, stage: 1 } }] + &[tool::ErrorIndex { compiler: Compiler::new(1, a) }] ); // Unfortunately rustdoc is built twice. Once from stage1 for compiletest // (and other things), and once from stage0 for std crates. Ideally it @@ -852,9 +879,9 @@ mod dist { assert_eq!( first(builder.cache.all::()), &[ - tool::Rustdoc { compiler: Compiler { host: a, stage: 0 } }, - tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, - tool::Rustdoc { compiler: Compiler { host: a, stage: 2 } }, + tool::Rustdoc { compiler: Compiler::new(0, a) }, + tool::Rustdoc { compiler: Compiler::new(1, a) }, + tool::Rustdoc { compiler: Compiler::new(2, a) }, ] ); } @@ -870,7 +897,7 @@ mod sysroot_target_dirs { let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); let builder = Builder::new(&build); let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); - let compiler = Compiler { stage: 1, host: target_triple_1 }; + let compiler = Compiler::new(1, target_triple_1); let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); let actual = builder.sysroot_target_libdir(compiler, target_triple_2); @@ -890,7 +917,7 @@ mod sysroot_target_dirs { let build = Build::new(configure("build", &[TEST_TRIPLE_1], &[TEST_TRIPLE_1])); let builder = Builder::new(&build); let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); - let compiler = Compiler { stage: 1, host: target_triple_1 }; + let compiler = Compiler::new(1, target_triple_1); let target_triple_2 = TargetSelection::from_user(TEST_TRIPLE_2); let actual = builder.sysroot_target_bindir(compiler, target_triple_2); @@ -1084,3 +1111,65 @@ fn test_is_builder_target() { assert!(!builder.is_builder_target(target2)); } } + +#[test] +fn test_get_tool_rustc_compiler() { + let mut config = configure("build", &[], &[]); + config.download_rustc_commit = None; + let build = Build::new(config); + let builder = Builder::new(&build); + + let target_triple_1 = TargetSelection::from_user(TEST_TRIPLE_1); + + let compiler = Compiler::new(2, target_triple_1); + let expected = Compiler::new(1, target_triple_1); + let actual = tool::get_tool_rustc_compiler(&builder, compiler); + assert_eq!(expected, actual); + + let compiler = Compiler::new(1, target_triple_1); + let expected = Compiler::new(0, target_triple_1); + let actual = tool::get_tool_rustc_compiler(&builder, compiler); + assert_eq!(expected, actual); + + let mut config = configure("build", &[], &[]); + config.download_rustc_commit = Some("".to_owned()); + let build = Build::new(config); + let builder = Builder::new(&build); + + let compiler = Compiler::new(1, target_triple_1); + let expected = Compiler::new(1, target_triple_1); + let actual = tool::get_tool_rustc_compiler(&builder, compiler); + assert_eq!(expected, actual); +} + +/// When bootstrap detects a step dependency cycle (which is a bug), its panic +/// message should show the actual steps on the stack, not just several copies +/// of `Any { .. }`. +#[test] +fn step_cycle_debug() { + let cmd = ["run", "cyclic-step"].map(str::to_owned); + let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]); + + let err = panic::catch_unwind(|| run_build(&config.paths.clone(), config)).unwrap_err(); + let err = err.downcast_ref::().unwrap().as_str(); + + assert!(!err.contains("Any")); + assert!(err.contains("CyclicStep { n: 1 }")); +} + +/// The `AnyDebug` trait should delegate to the underlying type's `Debug`, and +/// should also allow downcasting as expected. +#[test] +fn any_debug() { + #[derive(Debug, PartialEq, Eq)] + struct MyStruct { + x: u32, + } + + let x: &dyn AnyDebug = &MyStruct { x: 7 }; + + // Debug-formatting should delegate to the underlying type. + assert_eq!(format!("{x:?}"), format!("{:?}", MyStruct { x: 7 })); + // Downcasting to the underlying type should succeed. + assert_eq!(x.downcast_ref::(), Some(&MyStruct { x: 7 })); +} diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 172b8d787640d..18624a7c78f15 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -171,6 +171,17 @@ impl LldMode { } } +/// Determines how will GCC be provided. +#[derive(Default, Clone)] +pub enum GccCiMode { + /// Build GCC from the local `src/gcc` submodule. + #[default] + BuildLocally, + /// Try to download GCC from CI. + /// If it is not available on CI, it will be built locally instead. + DownloadFromCi, +} + /// Global configuration for the entire build and/or bootstrap. /// /// This structure is parsed from `config.toml`, and some of the fields are inferred from `git` or build-time parameters. @@ -218,6 +229,8 @@ pub struct Config { pub stderr_is_tty: bool, pub on_fail: Option, + pub explicit_stage_from_cli: bool, + pub explicit_stage_from_config: bool, pub stage: u32, pub keep_stage: Vec, pub keep_stage_std: Vec, @@ -281,6 +294,9 @@ pub struct Config { pub llvm_ldflags: Option, pub llvm_use_libcxx: bool, + // gcc codegen options + pub gcc_ci_mode: GccCiMode, + // rust codegen options pub rust_optimize: RustOptimize, pub rust_codegen_units: Option, @@ -674,6 +690,7 @@ pub(crate) struct TomlConfig { build: Option, install: Option, llvm: Option, + gcc: Option, rust: Option, target: Option>, dist: Option, @@ -708,7 +725,7 @@ trait Merge { impl Merge for TomlConfig { fn merge( &mut self, - TomlConfig { build, install, llvm, rust, dist, target, profile, change_id }: Self, + TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id }: Self, replace: ReplaceOpt, ) { fn do_merge(x: &mut Option, y: Option, replace: ReplaceOpt) { @@ -727,6 +744,7 @@ impl Merge for TomlConfig { do_merge(&mut self.build, build, replace); do_merge(&mut self.install, install, replace); do_merge(&mut self.llvm, llvm, replace); + do_merge(&mut self.gcc, gcc, replace); do_merge(&mut self.rust, rust, replace); do_merge(&mut self.dist, dist, replace); @@ -892,6 +910,7 @@ define_config! { #[derive(Default)] struct Build { build: Option = "build", + description: Option = "description", host: Option> = "host", target: Option> = "target", build_dir: Option = "build-dir", @@ -940,6 +959,7 @@ define_config! { jobs: Option = "jobs", compiletest_diff_tool: Option = "compiletest-diff-tool", ccache: Option = "ccache", + exclude: Option> = "exclude", } } @@ -992,6 +1012,13 @@ define_config! { } } +define_config! { + /// TOML representation of how the GCC build is configured. + struct Gcc { + download_ci_gcc: Option = "download-ci-gcc", + } +} + define_config! { struct Dist { sign_folder: Option = "sign-folder", @@ -1174,6 +1201,7 @@ define_config! { incremental: Option = "incremental", default_linker: Option = "default-linker", channel: Option = "channel", + // FIXME: Remove this field at Q2 2025, it has been replaced by build.description description: Option = "description", musl_root: Option = "musl-root", rpath: Option = "rpath", @@ -1370,22 +1398,6 @@ impl Config { "flags.exclude" = ?flags.exclude ); - config.skip = flags - .skip - .into_iter() - .chain(flags.exclude) - .map(|p| { - // Never return top-level path here as it would break `--skip` - // logic on rustc's internal test framework which is utilized - // by compiletest. - if cfg!(windows) { - PathBuf::from(p.to_str().unwrap().replace('/', "\\")) - } else { - p - } - }) - .collect(); - #[cfg(feature = "tracing")] span!( target: "CONFIG_HANDLING", @@ -1581,6 +1593,7 @@ impl Config { config.change_id = toml.change_id.inner; let Build { + mut description, build, host, target, @@ -1630,8 +1643,29 @@ impl Config { jobs, compiletest_diff_tool, mut ccache, + exclude, } = toml.build.unwrap_or_default(); + let mut paths: Vec = flags.skip.into_iter().chain(flags.exclude).collect(); + + if let Some(exclude) = exclude { + paths.extend(exclude); + } + + config.skip = paths + .into_iter() + .map(|p| { + // Never return top-level path here as it would break `--skip` + // logic on rustc's internal test framework which is utilized + // by compiletest. + if cfg!(windows) { + PathBuf::from(p.to_str().unwrap().replace('/', "\\")) + } else { + p + } + }) + .collect(); + config.jobs = Some(threads_from_config(flags.jobs.unwrap_or(jobs.unwrap_or(0)))); if let Some(file_build) = build { @@ -1775,7 +1809,11 @@ impl Config { let is_user_configured_rust_channel = if let Some(channel) = toml.rust.as_ref().and_then(|r| r.channel.clone()) { - config.channel = channel; + if channel == "auto-detect" { + config.channel = ci_channel.into(); + } else { + config.channel = channel; + } true } else { false @@ -1825,7 +1863,7 @@ impl Config { randomize_layout, default_linker, channel: _, // already handled above - description, + description: rust_description, musl_root, rpath, verbose_tests, @@ -1918,7 +1956,12 @@ impl Config { set(&mut config.jemalloc, jemalloc); set(&mut config.test_compare_mode, test_compare_mode); set(&mut config.backtrace, backtrace); - config.description = description; + if rust_description.is_some() { + eprintln!( + "Warning: rust.description is deprecated. Use build.description instead." + ); + } + description = description.or(rust_description); set(&mut config.rust_dist_src, dist_src); set(&mut config.verbose_tests, verbose_tests); // in the case "false" is set explicitly, do not overwrite the command line args @@ -1984,6 +2027,7 @@ impl Config { } config.reproducible_artifacts = flags.reproducible_artifact; + config.description = description; // We need to override `rust.channel` if it's manually specified when using the CI rustc. // This is because if the compiler uses a different channel than the one specified in config.toml, @@ -2121,6 +2165,16 @@ impl Config { config.llvm_from_ci = config.parse_download_ci_llvm(None, false); } + if let Some(gcc) = toml.gcc { + config.gcc_ci_mode = match gcc.download_ci_gcc { + Some(value) => match value { + true => GccCiMode::DownloadFromCi, + false => GccCiMode::BuildLocally, + }, + None => GccCiMode::default(), + }; + } + if let Some(t) = toml.target { for (triple, cfg) in t { let mut target = Target::from_triple(&triple); @@ -2323,6 +2377,14 @@ impl Config { config.compiletest_diff_tool = compiletest_diff_tool; let download_rustc = config.download_rustc_commit.is_some(); + config.explicit_stage_from_cli = flags.stage.is_some(); + config.explicit_stage_from_config = test_stage.is_some() + || build_stage.is_some() + || doc_stage.is_some() + || dist_stage.is_some() + || install_stage.is_some() + || check_stage.is_some() + || bench_stage.is_some(); // See https://github.com/rust-lang/compiler-team/issues/326 config.stage = match config.cmd { Subcommand::Check { .. } => flags.stage.or(check_stage).unwrap_or(0), @@ -2330,21 +2392,21 @@ impl Config { Subcommand::Doc { .. } => { flags.stage.or(doc_stage).unwrap_or(if download_rustc { 2 } else { 0 }) } - Subcommand::Build { .. } => { + Subcommand::Build => { flags.stage.or(build_stage).unwrap_or(if download_rustc { 2 } else { 1 }) } 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), - Subcommand::Dist { .. } => flags.stage.or(dist_stage).unwrap_or(2), - Subcommand::Install { .. } => flags.stage.or(install_stage).unwrap_or(2), + Subcommand::Dist => flags.stage.or(dist_stage).unwrap_or(2), + Subcommand::Install => flags.stage.or(install_stage).unwrap_or(2), Subcommand::Perf { .. } => flags.stage.unwrap_or(1), // These are all bootstrap tools, which don't depend on the compiler. // The stage we pass shouldn't matter, but use 0 just in case. Subcommand::Clean { .. } | Subcommand::Clippy { .. } - | Subcommand::Fix { .. } + | Subcommand::Fix | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } @@ -2359,10 +2421,10 @@ impl Config { Subcommand::Test { .. } | Subcommand::Miri { .. } | Subcommand::Doc { .. } - | Subcommand::Build { .. } + | Subcommand::Build | Subcommand::Bench { .. } - | Subcommand::Dist { .. } - | Subcommand::Install { .. } => { + | Subcommand::Dist + | Subcommand::Install => { assert_eq!( config.stage, 2, "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`", @@ -2372,7 +2434,7 @@ impl Config { Subcommand::Clean { .. } | Subcommand::Check { .. } | Subcommand::Clippy { .. } - | Subcommand::Fix { .. } + | Subcommand::Fix | Subcommand::Run { .. } | Subcommand::Setup { .. } | Subcommand::Format { .. } @@ -2392,6 +2454,10 @@ impl Config { } } + pub fn is_explicit_stage(&self) -> bool { + self.explicit_stage_from_cli || self.explicit_stage_from_config + } + /// Runs a command, printing out nice contextual information if it fails. /// Exits if the command failed to execute at all, otherwise returns its /// `status.success()`. @@ -2958,6 +3024,9 @@ impl Config { // these changes to speed up the build process for library developers. This provides consistent // functionality for library developers between `download-rustc=true` and `download-rustc="if-unchanged"` // options. + // + // If you update "library" logic here, update `builder::tests::ci_rustc_if_unchanged_logic` test + // logic accordingly. if !CiEnv::is_ci() { allowed_paths.push(":!library"); } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index c08a041ebcd3f..3bb62bbe38082 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -490,17 +490,17 @@ impl Subcommand { pub fn kind(&self) -> Kind { match self { Subcommand::Bench { .. } => Kind::Bench, - Subcommand::Build { .. } => Kind::Build, + Subcommand::Build => Kind::Build, Subcommand::Check { .. } => Kind::Check, Subcommand::Clippy { .. } => Kind::Clippy, Subcommand::Doc { .. } => Kind::Doc, - Subcommand::Fix { .. } => Kind::Fix, + 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, + Subcommand::Dist => Kind::Dist, + Subcommand::Install => Kind::Install, Subcommand::Run { .. } => Kind::Run, Subcommand::Setup { .. } => Kind::Setup, Subcommand::Suggest { .. } => Kind::Suggest, diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 9f09dd13f2985..179e15e778bff 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -1,4 +1,4 @@ -#[allow(clippy::module_inception)] +#[expect(clippy::module_inception)] mod config; pub mod flags; #[cfg(test)] diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index f0a185ee3a7eb..c7b6f3681b891 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -454,3 +454,79 @@ fn check_rustc_if_unchanged_paths() { assert!(config.src.join(p).exists(), "{p} doesn't exist."); } } + +#[test] +fn test_explicit_stage() { + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]), + |&_| { + toml::from_str( + r#" + [build] + test-stage = 1 + "#, + ) + }, + ); + + assert!(!config.explicit_stage_from_cli); + assert!(config.explicit_stage_from_config); + assert!(config.is_explicit_stage()); + + let config = Config::parse_inner( + Flags::parse(&[ + "check".to_owned(), + "--stage=2".to_owned(), + "--config=/does/not/exist".to_owned(), + ]), + |&_| toml::from_str(""), + ); + + assert!(config.explicit_stage_from_cli); + assert!(!config.explicit_stage_from_config); + assert!(config.is_explicit_stage()); + + let config = Config::parse_inner( + Flags::parse(&[ + "check".to_owned(), + "--stage=2".to_owned(), + "--config=/does/not/exist".to_owned(), + ]), + |&_| { + toml::from_str( + r#" + [build] + test-stage = 1 + "#, + ) + }, + ); + + assert!(config.explicit_stage_from_cli); + assert!(config.explicit_stage_from_config); + assert!(config.is_explicit_stage()); + + let config = Config::parse_inner( + Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]), + |&_| toml::from_str(""), + ); + + assert!(!config.explicit_stage_from_cli); + assert!(!config.explicit_stage_from_config); + assert!(!config.is_explicit_stage()); +} + +#[test] +fn test_exclude() { + let exclude_path = "compiler"; + let config = parse(&format!("build.exclude=[\"{}\"]", exclude_path)); + + let first_excluded = config + .skip + .first() + .expect("Expected at least one excluded path") + .to_str() + .expect("Failed to convert excluded path to string"); + + assert_eq!(first_excluded, exclude_path); +} diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index c477bdb829a91..98eff664a5b11 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -19,7 +19,7 @@ static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock = OnceLock::new(); /// `Config::try_run` wrapper for this module to avoid warnings on `try_run`, since we don't have access to a `builder` yet. fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> { - #[allow(deprecated)] + #[expect(deprecated)] config.try_run(cmd) } @@ -826,6 +826,34 @@ download-rustc = false let llvm_root = self.ci_llvm_root(); self.unpack(&tarball, &llvm_root, "rust-dev"); } + + pub fn download_ci_gcc(&self, gcc_sha: &str, root_dir: &Path) { + let cache_prefix = format!("gcc-{gcc_sha}"); + let cache_dst = + self.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| self.out.join("cache")); + + let gcc_cache = cache_dst.join(cache_prefix); + if !gcc_cache.exists() { + t!(fs::create_dir_all(&gcc_cache)); + } + let base = &self.stage0_metadata.config.artifacts_server; + let filename = format!("gcc-nightly-{}.tar.xz", self.build.triple); + let tarball = gcc_cache.join(&filename); + if !tarball.exists() { + let help_on_error = "ERROR: failed to download gcc from ci + + HELP: There could be two reasons behind this: + 1) The host triple is not supported for `download-ci-gcc`. + 2) Old builds get deleted after a certain time. + HELP: In either case, disable `download-ci-gcc` in your config.toml: + + [gcc] + download-ci-gcc = false + "; + self.download_file(&format!("{base}/{gcc_sha}/{filename}"), &tarball, help_on_error); + } + self.unpack(&tarball, root_dir, "gcc"); + } } fn path_is_dylib(path: &Path) -> bool { diff --git a/src/bootstrap/src/core/metadata.rs b/src/bootstrap/src/core/metadata.rs index 983674d2c6835..2706aba5ffc8d 100644 --- a/src/bootstrap/src/core/metadata.rs +++ b/src/bootstrap/src/core/metadata.rs @@ -1,3 +1,10 @@ +//! This module interacts with Cargo metadata to collect and store information about +//! the packages in the Rust workspace. +//! +//! It runs `cargo metadata` to gather details about each package, including its name, +//! source, dependencies, targets, and available features. The collected metadata is then +//! used to update the `Build` structure, ensuring proper dependency resolution and +//! compilation flow. use std::collections::BTreeMap; use std::path::PathBuf; @@ -21,7 +28,6 @@ struct Package { source: Option, manifest_path: String, dependencies: Vec, - targets: Vec, features: BTreeMap>, } @@ -33,11 +39,6 @@ struct Dependency { source: Option, } -#[derive(Debug, Deserialize)] -struct Target { - kind: Vec, -} - /// Collects and stores package metadata of each workspace members into `build`, /// by executing `cargo metadata` commands. pub fn build(build: &mut Build) { @@ -52,12 +53,10 @@ pub fn build(build: &mut Build) { .filter(|dep| dep.source.is_none()) .map(|dep| dep.name) .collect(); - let has_lib = package.targets.iter().any(|t| t.kind.iter().any(|k| k == "lib")); let krate = Crate { name: name.clone(), deps, path, - has_lib, features: package.features.keys().cloned().collect(), }; let relative_path = krate.local_path(build); diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 241b7386d18c5..583b8e1198ae3 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -34,10 +34,7 @@ pub struct Finder { // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined - "aarch64-unknown-nto-qnx710_iosock", - "x86_64-pc-nto-qnx710_iosock", - "x86_64-pc-nto-qnx800", - "aarch64-unknown-nto-qnx800", + "wasm32-wali-linux-musl", ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index da48b924ce4df..91574f8bf5d99 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -27,6 +27,7 @@ use std::{env, fs, io, str}; use build_helper::ci::gha; use build_helper::exit; +use cc::Tool; use termcolor::{ColorChoice, StandardStream, WriteColor}; use utils::build_stamp::BuildStamp; use utils::channel::GitInfo; @@ -74,7 +75,7 @@ const LLD_FILE_NAMES: &[&str] = &["ld.lld", "ld64.lld", "lld-link", "wasm-ld"]; /// Extra `--check-cfg` to add when building the compiler or tools /// (Mode restriction, config name, config values (if any)) -#[allow(clippy::type_complexity)] // It's fine for hard-coded list and type is explained above. +#[expect(clippy::type_complexity)] // It's fine for hard-coded list and type is explained above. const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ (None, "bootstrap", None), (Some(Mode::Rustc), "llvm_enzyme", None), @@ -92,10 +93,27 @@ const EXTRA_CHECK_CFGS: &[(Option, &str, Option<&[&'static str]>)] = &[ /// Each compiler has a `stage` that it is associated with and a `host` that /// corresponds to the platform the compiler runs on. This structure is used as /// a parameter to many methods below. -#[derive(Eq, PartialOrd, Ord, PartialEq, Clone, Copy, Hash, Debug)] +#[derive(Eq, PartialOrd, Ord, Clone, Copy, Debug)] pub struct Compiler { stage: u32, host: TargetSelection, + /// Indicates whether the compiler was forced to use a specific stage. + /// This field is ignored in `Hash` and `PartialEq` implementations as only the `stage` + /// and `host` fields are relevant for those. + forced_compiler: bool, +} + +impl std::hash::Hash for Compiler { + fn hash(&self, state: &mut H) { + self.stage.hash(state); + self.host.hash(state); + } +} + +impl PartialEq for Compiler { + fn eq(&self, other: &Self) -> bool { + self.stage == other.stage && self.host == other.host + } } #[derive(PartialEq, Eq, Copy, Clone, Debug)] @@ -185,7 +203,6 @@ struct Crate { name: String, deps: HashSet, path: PathBuf, - has_lib: bool, features: Vec, } @@ -237,7 +254,7 @@ pub enum Mode { /// Build a tool which uses the locally built rustc and the target std, /// placing the output in the "stageN-tools" directory. This is used for /// anything that needs a fully functional rustc, such as rustdoc, clippy, - /// cargo, rls, rustfmt, miri, etc. + /// cargo, rustfmt, miri, etc. ToolRustc, } @@ -637,7 +654,7 @@ impl Build { // Check for postponed failures from `test --no-fail-fast`. let failures = self.delayed_failures.borrow(); - if failures.len() > 0 { + if !failures.is_empty() { eprintln!("\n{} command(s) did not execute successfully:\n", failures.len()); for failure in failures.iter() { eprintln!(" - {failure}\n"); @@ -1202,6 +1219,16 @@ Executed at: {executed_at}"#, self.cc.borrow()[&target].path().into() } + /// Returns the internal `cc::Tool` for the C compiler. + fn cc_tool(&self, target: TargetSelection) -> Tool { + self.cc.borrow()[&target].clone() + } + + /// Returns the internal `cc::Tool` for the C++ compiler. + fn cxx_tool(&self, target: TargetSelection) -> Tool { + self.cxx.borrow()[&target].clone() + } + /// Returns C flags that `cc-rs` thinks should be enabled for the /// specified target by default. fn cc_handled_clags(&self, target: TargetSelection, c: CLang) -> Vec { @@ -1964,6 +1991,14 @@ fn chmod(path: &Path, perms: u32) { fn chmod(_path: &Path, _perms: u32) {} impl Compiler { + pub fn new(stage: u32, host: TargetSelection) -> Self { + Self { stage, host, forced_compiler: false } + } + + pub fn forced_compiler(&mut self, forced_compiler: bool) { + self.forced_compiler = forced_compiler; + } + pub fn with_stage(mut self, stage: u32) -> Compiler { self.stage = stage; self @@ -1973,6 +2008,11 @@ impl Compiler { pub fn is_snapshot(&self, build: &Build) -> bool { self.stage == 0 && self.host == build.build } + + /// Indicates whether the compiler was forced to use a specific stage. + pub fn is_forced_compiler(&self) -> bool { + self.forced_compiler + } } fn envify(s: &str) -> String { diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 006dfe7e5d7b3..c97529cbe9eb4 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -9,20 +9,24 @@ use crate::{Build, Config, Flags}; fn test_cc2ar_env_specific() { let triple = "x86_64-unknown-linux-gnu"; let key = "AR_x86_64_unknown_linux_gnu"; - env::set_var(key, "custom-ar"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var(key, "custom-ar") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); let result = cc2ar(cc, target, default_ar); - env::remove_var(key); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var(key) }; assert_eq!(result, Some(PathBuf::from("custom-ar"))); } #[test] fn test_cc2ar_musl() { let triple = "x86_64-unknown-linux-musl"; - env::remove_var("AR_x86_64_unknown_linux_musl"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_linux_musl") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -33,8 +37,10 @@ fn test_cc2ar_musl() { #[test] fn test_cc2ar_openbsd() { let triple = "x86_64-unknown-openbsd"; - env::remove_var("AR_x86_64_unknown_openbsd"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_openbsd") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/cc"); let default_ar = PathBuf::from("default-ar"); @@ -45,8 +51,10 @@ fn test_cc2ar_openbsd() { #[test] fn test_cc2ar_vxworks() { let triple = "armv7-wrs-vxworks"; - env::remove_var("AR_armv7_wrs_vxworks"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_armv7_wrs_vxworks") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -57,8 +65,10 @@ fn test_cc2ar_vxworks() { #[test] fn test_cc2ar_nto_i586() { let triple = "i586-unknown-nto-something"; - env::remove_var("AR_i586_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_i586_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -69,8 +79,10 @@ fn test_cc2ar_nto_i586() { #[test] fn test_cc2ar_nto_aarch64() { let triple = "aarch64-unknown-nto-something"; - env::remove_var("AR_aarch64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_aarch64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -81,8 +93,10 @@ fn test_cc2ar_nto_aarch64() { #[test] fn test_cc2ar_nto_x86_64() { let triple = "x86_64-unknown-nto-something"; - env::remove_var("AR_x86_64_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_x86_64_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -94,8 +108,10 @@ fn test_cc2ar_nto_x86_64() { #[should_panic(expected = "Unknown architecture, cannot determine archiver for Neutrino QNX")] fn test_cc2ar_nto_unknown() { let triple = "powerpc-unknown-nto-something"; - env::remove_var("AR_powerpc_unknown_nto_something"); - env::remove_var("AR"); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR_powerpc_unknown_nto_something") }; + // SAFETY: bootstrap tests run on a single thread + unsafe { env::remove_var("AR") }; let target = TargetSelection::from_user(triple); let cc = Path::new("/usr/bin/clang"); let default_ar = PathBuf::from("default-ar"); @@ -177,7 +193,8 @@ fn test_default_compiler_wasi() { let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); - env::set_var("WASI_SDK_PATH", &wasi_sdk); + // SAFETY: bootstrap tests run on a single thread + unsafe { env::set_var("WASI_SDK_PATH", &wasi_sdk) }; let mut cfg = cc::Build::new(); if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) { let expected = { @@ -190,7 +207,10 @@ fn test_default_compiler_wasi() { "default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set" ); } - env::remove_var("WASI_SDK_PATH"); + // SAFETY: bootstrap tests run on a single thread + unsafe { + env::remove_var("WASI_SDK_PATH"); + } } #[test] diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index f215c3f6d0b39..f8478725c4cd0 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -355,4 +355,34 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "It is now possible to configure `jemalloc` for each target", }, + ChangeInfo { + change_id: 137215, + severity: ChangeSeverity::Info, + summary: "Added `build.test-stage = 2` to 'tools' profile defaults", + }, + ChangeInfo { + change_id: 137220, + severity: ChangeSeverity::Info, + summary: "`rust.channel` now supports \"auto-detect\" to load the channel from `src/ci/channel`", + }, + ChangeInfo { + change_id: 137723, + severity: ChangeSeverity::Info, + summary: "The rust.description option has moved to build.description and rust.description is now deprecated.", + }, + ChangeInfo { + change_id: 138051, + severity: ChangeSeverity::Info, + summary: "There is now a new `gcc` config section that can be used to download GCC from CI using `gcc.download-ci-gcc = true`", + }, + ChangeInfo { + change_id: 126856, + severity: ChangeSeverity::Warning, + summary: "Removed `src/tools/rls` tool as it was deprecated long time ago.", + }, + ChangeInfo { + change_id: 137147, + severity: ChangeSeverity::Info, + summary: "New option `build.exclude` that adds support for excluding test.", + }, ]; diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 7eb9ab96c8a4a..d07300e21d003 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -125,7 +125,7 @@ impl BootstrapCommand { Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self } } - #[allow(dead_code)] + #[expect(dead_code)] pub fn fail_fast(self) -> Self { Self { failure_behavior: BehaviorOnFailure::Exit, ..self } } @@ -280,7 +280,7 @@ impl CommandOutput { !self.is_success() } - #[allow(dead_code)] + #[expect(dead_code)] pub fn status(&self) -> Option { match self.status { CommandStatus::Finished(status) => Some(status), @@ -332,7 +332,6 @@ impl Default for CommandOutput { /// Helper trait to format both Command and BootstrapCommand as a short execution line, /// without all the other details (e.g. environment variables). -#[allow(unused)] pub trait FormatShortCmd { fn format_short_cmd(&self) -> String; } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 3fee397da091d..89d93a29acbca 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -286,7 +286,7 @@ pub fn output(cmd: &mut Command) -> String { /// to finish and then return its output. This allows the spawned process /// to do work without immediately blocking bootstrap. #[track_caller] -pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String { +pub fn start_process(cmd: &mut Command) -> impl FnOnce() -> String + use<> { let child = match cmd.stderr(Stdio::inherit()).stdout(Stdio::piped()).spawn() { Ok(child) => child, Err(e) => fail(&format!("failed to execute command: {cmd:?}\nERROR: {e}")), @@ -430,8 +430,9 @@ pub fn linker_args( builder: &Builder<'_>, target: TargetSelection, lld_threads: LldThreads, + stage: u32, ) -> Vec { - let mut args = linker_flags(builder, target, lld_threads); + let mut args = linker_flags(builder, target, lld_threads, stage); if let Some(linker) = builder.linker(target) { args.push(format!("-Clinker={}", linker.display())); @@ -446,12 +447,18 @@ pub fn linker_flags( builder: &Builder<'_>, target: TargetSelection, lld_threads: LldThreads, + stage: u32, ) -> Vec { let mut args = vec![]; if !builder.is_lld_direct_linker(target) && builder.config.lld_mode.is_used() { match builder.config.lld_mode { LldMode::External => { - args.push("-Clinker-flavor=gnu-lld-cc".to_string()); + // cfg(bootstrap) - remove after updating bootstrap compiler (#137498) + if stage == 0 && target.is_windows() { + args.push("-Clink-arg=-fuse-ld=lld".to_string()); + } else { + args.push("-Clinker-flavor=gnu-lld-cc".to_string()); + } // FIXME(kobzol): remove this flag once MCP510 gets stabilized args.push("-Zunstable-options".to_string()); } @@ -479,8 +486,9 @@ pub fn add_rustdoc_cargo_linker_args( builder: &Builder<'_>, target: TargetSelection, lld_threads: LldThreads, + stage: u32, ) { - let args = linker_args(builder, target, lld_threads); + let args = linker_args(builder, target, lld_threads, stage); let mut flags = cmd .get_envs() .find_map(|(k, v)| if k == OsStr::new("RUSTDOCFLAGS") { v } else { None }) diff --git a/src/bootstrap/src/utils/job.rs b/src/bootstrap/src/utils/job.rs index 10efed130d624..4949518de79b0 100644 --- a/src/bootstrap/src/utils/job.rs +++ b/src/bootstrap/src/utils/job.rs @@ -7,7 +7,9 @@ pub unsafe fn setup(_build: &mut crate::Build) {} #[cfg(all(unix, not(target_os = "haiku")))] pub unsafe fn setup(build: &mut crate::Build) { if build.config.low_priority { - libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + unsafe { + libc::setpriority(libc::PRIO_PGRP as _, 0, 10); + } } } @@ -42,7 +44,7 @@ pub unsafe fn setup(build: &mut crate::Build) { #[cfg(windows)] mod for_windows { use std::ffi::c_void; - use std::{io, mem}; + use std::io; use windows::Win32::Foundation::CloseHandle; use windows::Win32::System::Diagnostics::Debug::{ @@ -59,38 +61,41 @@ mod for_windows { use crate::Build; pub unsafe fn setup(build: &mut Build) { - // Enable the Windows Error Reporting dialog which msys disables, - // so we can JIT debug rustc - let mode = SetErrorMode(THREAD_ERROR_MODE::default()); - let mode = THREAD_ERROR_MODE(mode); - SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); + // SAFETY: pretty much everything below is unsafe + unsafe { + // Enable the Windows Error Reporting dialog which msys disables, + // so we can JIT debug rustc + let mode = SetErrorMode(THREAD_ERROR_MODE::default()); + let mode = THREAD_ERROR_MODE(mode); + SetErrorMode(mode & !SEM_NOGPFAULTERRORBOX); - // Create a new job object for us to use - let job = CreateJobObjectW(None, PCWSTR::null()).unwrap(); + // Create a new job object for us to use + let job = CreateJobObjectW(None, PCWSTR::null()).unwrap(); - // Indicate that when all handles to the job object are gone that all - // process in the object should be killed. Note that this includes our - // entire process tree by default because we've added ourselves and our - // children will reside in the job by default. - let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default(); - info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - if build.config.low_priority { - info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS; - info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0; - } - let r = SetInformationJobObject( - job, - JobObjectExtendedLimitInformation, - &info as *const _ as *const c_void, - mem::size_of_val(&info) as u32, - ); - assert!(r.is_ok(), "{}", io::Error::last_os_error()); + // Indicate that when all handles to the job object are gone that all + // process in the object should be killed. Note that this includes our + // entire process tree by default because we've added ourselves and our + // children will reside in the job by default. + let mut info = JOBOBJECT_EXTENDED_LIMIT_INFORMATION::default(); + info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if build.config.low_priority { + info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_PRIORITY_CLASS; + info.BasicLimitInformation.PriorityClass = BELOW_NORMAL_PRIORITY_CLASS.0; + } + let r = SetInformationJobObject( + job, + JobObjectExtendedLimitInformation, + &info as *const _ as *const c_void, + size_of_val(&info) as u32, + ); + assert!(r.is_ok(), "{}", io::Error::last_os_error()); - // Assign our process to this job object. - let r = AssignProcessToJobObject(job, GetCurrentProcess()); - if r.is_err() { - CloseHandle(job).ok(); - return; + // Assign our process to this job object. + let r = AssignProcessToJobObject(job, GetCurrentProcess()); + if r.is_err() { + CloseHandle(job).ok(); + return; + } } // Note: we intentionally leak the job object handle. When our process exits diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index b51fd490535a3..885fff9c32c5a 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -76,7 +76,7 @@ impl BuildMetrics { // Consider all the stats gathered so far as the parent's. if !state.running_steps.is_empty() { - self.collect_stats(&mut *state); + self.collect_stats(&mut state); } state.system_info.refresh_cpu_usage(); @@ -102,7 +102,7 @@ impl BuildMetrics { let mut state = self.state.borrow_mut(); - self.collect_stats(&mut *state); + self.collect_stats(&mut state); let step = state.running_steps.pop().unwrap(); if state.running_steps.is_empty() { @@ -200,6 +200,14 @@ impl BuildMetrics { } }; invocations.push(JsonInvocation { + // The command-line invocation with which bootstrap was invoked. + // Skip the first argument, as it is a potentially long absolute + // path that is not interesting. + cmdline: std::env::args_os() + .skip(1) + .map(|arg| arg.to_string_lossy().to_string()) + .collect::>() + .join(" "), start_time: state .invocation_start .duration_since(SystemTime::UNIX_EPOCH) @@ -216,6 +224,7 @@ impl BuildMetrics { t!(serde_json::to_writer(&mut file, &json)); } + #[expect(clippy::only_used_in_recursion)] fn prepare_json_step(&self, step: StepMetrics) -> JsonNode { let mut children = Vec::new(); children.extend(step.children.into_iter().map(|child| self.prepare_json_step(child))); diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 843ea65e83862..f1678bacc9769 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -22,7 +22,6 @@ pub(crate) enum OverlayKind { Clippy, Miri, Rustfmt, - Rls, RustAnalyzer, RustcCodegenCranelift, LlvmBitcodeLinker, @@ -56,7 +55,6 @@ impl OverlayKind { "src/tools/rustfmt/LICENSE-APACHE", "src/tools/rustfmt/LICENSE-MIT", ], - OverlayKind::Rls => &["src/tools/rls/README.md", "LICENSE-APACHE", "LICENSE-MIT"], OverlayKind::RustAnalyzer => &[ "src/tools/rust-analyzer/README.md", "src/tools/rust-analyzer/LICENSE-APACHE", @@ -90,7 +88,6 @@ impl OverlayKind { OverlayKind::Rustfmt => { builder.rustfmt_info.version(builder, &builder.release_num("rustfmt")) } - OverlayKind::Rls => builder.release(&builder.release_num("rls")), OverlayKind::RustAnalyzer => builder .rust_analyzer_info .version(builder, &builder.release_num("rust-analyzer/crates/rust-analyzer")), diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs index 3ef9c7ac35e9d..9f778a2fd7742 100644 --- a/src/build_helper/src/git.rs +++ b/src/build_helper/src/git.rs @@ -129,7 +129,7 @@ pub fn get_closest_merge_commit( git.current_dir(git_dir); } - let channel = include_str!("../../ci/channel"); + let channel = include_str!("../../ci/channel").trim(); let merge_base = { if CiEnv::is_ci() && diff --git a/src/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs index 538c33e9b1591..b6daac32a4412 100644 --- a/src/build_helper/src/metrics.rs +++ b/src/build_helper/src/metrics.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + use serde_derive::{Deserialize, Serialize}; #[derive(Serialize, Deserialize)] @@ -12,6 +14,8 @@ pub struct JsonRoot { #[derive(Serialize, Deserialize)] #[serde(rename_all = "snake_case")] pub struct JsonInvocation { + // Remembers the command-line invocation with which bootstrap was invoked. + pub cmdline: String, // Unix timestamp in seconds // // This is necessary to easily correlate this invocation with logs or other data. @@ -70,7 +74,7 @@ pub struct Test { pub outcome: TestOutcome, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)] #[serde(tag = "outcome", rename_all = "snake_case")] pub enum TestOutcome { Passed, @@ -98,3 +102,87 @@ fn null_as_f64_nan<'de, D: serde::Deserializer<'de>>(d: D) -> Result::deserialize(d).map(|f| f.unwrap_or(f64::NAN)) } + +/// Represents a single bootstrap step, with the accumulated duration of all its children. +#[derive(Clone, Debug)] +pub struct BuildStep { + pub r#type: String, + pub children: Vec, + pub duration: Duration, +} + +impl BuildStep { + /// Create a `BuildStep` representing a single invocation of bootstrap. + /// The most important thing is that the build step aggregates the + /// durations of all children, so that it can be easily accessed. + pub fn from_invocation(invocation: &JsonInvocation) -> Self { + fn parse(node: &JsonNode) -> Option { + match node { + JsonNode::RustbuildStep { + type_: kind, + children, + duration_excluding_children_sec, + .. + } => { + let children: Vec<_> = children.into_iter().filter_map(parse).collect(); + let children_duration = children.iter().map(|c| c.duration).sum::(); + Some(BuildStep { + r#type: kind.to_string(), + children, + duration: children_duration + + Duration::from_secs_f64(*duration_excluding_children_sec), + }) + } + JsonNode::TestSuite(_) => None, + } + } + + let duration = Duration::from_secs_f64(invocation.duration_including_children_sec); + let children: Vec<_> = invocation.children.iter().filter_map(parse).collect(); + Self { r#type: "total".to_string(), children, duration } + } + + pub fn find_all_by_type(&self, r#type: &str) -> Vec<&Self> { + let mut result = Vec::new(); + self.find_by_type(r#type, &mut result); + result + } + + fn find_by_type<'a>(&'a self, r#type: &str, result: &mut Vec<&'a Self>) { + if self.r#type == r#type { + result.push(self); + } + for child in &self.children { + child.find_by_type(r#type, result); + } + } +} + +/// Writes build steps into a nice indented table. +pub fn format_build_steps(root: &BuildStep) -> String { + use std::fmt::Write; + + let mut substeps: Vec<(u32, &BuildStep)> = Vec::new(); + + fn visit<'a>(step: &'a BuildStep, level: u32, substeps: &mut Vec<(u32, &'a BuildStep)>) { + substeps.push((level, step)); + for child in &step.children { + visit(child, level + 1, substeps); + } + } + + visit(root, 0, &mut substeps); + + let mut output = String::new(); + for (level, step) in substeps { + let label = format!( + "{}{}", + ".".repeat(level as usize), + // Bootstrap steps can be generic and thus contain angle brackets (<...>). + // However, Markdown interprets these as HTML, so we need to escap ethem. + step.r#type.replace('<', "<").replace('>', ">") + ); + writeln!(output, "{label:.<65}{:>8.2}s", step.duration.as_secs_f64()).unwrap(); + } + output +} diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock new file mode 100644 index 0000000000000..c061ec6ebdcee --- /dev/null +++ b/src/ci/citool/Cargo.lock @@ -0,0 +1,1105 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "build_helper" +version = "0.1.0" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "bytes" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" + +[[package]] +name = "cc" +version = "1.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "citool" +version = "0.1.0" +dependencies = [ + "anyhow", + "build_helper", + "clap", + "csv", + "glob-match", + "insta", + "serde", + "serde_json", + "serde_yaml", + "ureq", +] + +[[package]] +name = "clap" +version = "4.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "console" +version = "0.15.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "flate2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glob-match" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985c9503b412198aa4197559e9a318524ebc4519c229bfa05a535828c950b9d" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "insta" +version = "1.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1b125e30d93896b365e156c33dadfffab45ee8400afcbba4752f59de08a86" +dependencies = [ + "console", + "linked-hash-map", + "once_cell", + "pin-project", + "similar", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +dependencies = [ + "adler2", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "once_cell" +version = "1.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfe2e71e1471fe07709406bf725f710b02927c9c54b2b5b2ec0e8087d97c327d" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e859e6e5bd50440ab63c47e3ebabc90f26251f7c73c3d3e837b74a1cc3fa67" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ring" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + +[[package]] +name = "smallvec" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "2.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb041120f25f8fbe8fd2dbe4671c7c2ed74d83be2e7a77529bf7e0790ae3f472" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" + +[[package]] +name = "time-macros" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "3.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06f78313c985f2fba11100dd06d60dd402d0cabb458af4d94791b8e09c025323" +dependencies = [ + "base64", + "cookie_store", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "ureq-proto", + "utf-8", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64adb55464bad1ab1aa9229133d0d59d2f679180f4d15f0d9debe616f541f25e" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "webpki-roots" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml new file mode 100644 index 0000000000000..dde09224afe84 --- /dev/null +++ b/src/ci/citool/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "citool" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1" +clap = { version = "4.5", features = ["derive"] } +csv = "1" +glob-match = "0.2" +serde = { version = "1", features = ["derive"] } +serde_yaml = "0.9" +serde_json = "1" +ureq = { version = "3", features = ["json"] } + +build_helper = { path = "../../build_helper" } + +[dev-dependencies] +insta = "1" + +# Tell cargo that citool is its own workspace. +# If this is omitted, cargo will look for a workspace elsewhere. +# We want to avoid this, since citool is independent of the other crates. +[workspace] + +# Make compilation faster +[profile.dev] +debug = 0 diff --git a/src/ci/citool/README.md b/src/ci/citool/README.md new file mode 100644 index 0000000000000..685a255f15251 --- /dev/null +++ b/src/ci/citool/README.md @@ -0,0 +1,2 @@ +# CI tooling +This is a simple Rust script that determines which jobs should be executed on CI based on the situation (pull request, try job, merge attempt). It also provides a simple way of executing (some) CI jobs locally. diff --git a/src/ci/citool/src/cpu_usage.rs b/src/ci/citool/src/cpu_usage.rs new file mode 100644 index 0000000000000..fa9a1203f4191 --- /dev/null +++ b/src/ci/citool/src/cpu_usage.rs @@ -0,0 +1,24 @@ +use std::path::Path; + +/// Loads CPU usage records from a CSV generated by the `src/ci/scripts/collect-cpu-stats.sh` +/// script. +pub fn load_cpu_usage(path: &Path) -> anyhow::Result> { + let reader = csv::ReaderBuilder::new().flexible(true).from_path(path)?; + + let mut entries = vec![]; + for row in reader.into_records() { + let row = row?; + let cols = row.into_iter().collect::>(); + + // The log might contain incomplete rows or some Python exception + if cols.len() == 2 { + if let Ok(idle) = cols[1].parse::() { + entries.push(100.0 - idle); + } else { + eprintln!("Warning: cannot parse CPU CSV entry {}", cols[1]); + } + } + } + + Ok(entries) +} diff --git a/src/ci/citool/src/datadog.rs b/src/ci/citool/src/datadog.rs new file mode 100644 index 0000000000000..837257420d6a2 --- /dev/null +++ b/src/ci/citool/src/datadog.rs @@ -0,0 +1,43 @@ +use anyhow::Context; + +use crate::utils::load_env_var; + +/// Uploads a custom CI pipeline metric to Datadog. +/// Expects to be executed from within the context of a GitHub Actions job. +pub fn upload_datadog_metric(name: &str, value: f64) -> anyhow::Result<()> { + let datadog_api_key = load_env_var("DATADOG_API_KEY")?; + let github_server_url = load_env_var("GITHUB_SERVER_URL")?; + let github_repository = load_env_var("GITHUB_REPOSITORY")?; + let github_run_id = load_env_var("GITHUB_RUN_ID")?; + let github_run_attempt = load_env_var("GITHUB_RUN_ATTEMPT")?; + let github_job = load_env_var("GITHUB_JOB")?; + let dd_github_job_name = load_env_var("DD_GITHUB_JOB_NAME")?; + + // This API endpoint is not documented in Datadog's API reference currently. + // It was reverse-engineered from the `datadog-ci measure` npm command. + ureq::post("https://api.datadoghq.com/api/v2/ci/pipeline/metrics") + .header("DD-API-KEY", datadog_api_key) + .send_json(serde_json::json!({ + "data": { + "attributes": { + "ci_env": { + "GITHUB_SERVER_URL": github_server_url, + "GITHUB_REPOSITORY": github_repository, + "GITHUB_RUN_ID": github_run_id, + "GITHUB_RUN_ATTEMPT": github_run_attempt, + "GITHUB_JOB": github_job, + "DD_GITHUB_JOB_NAME": dd_github_job_name + }, + // Job level + "ci_level": 1, + "metrics": { + name: value + }, + "provider": "github" + }, + "type": "ci_custom_metric" + } + })) + .context("cannot send metric to DataDog")?; + Ok(()) +} diff --git a/src/ci/citool/src/jobs.rs b/src/ci/citool/src/jobs.rs new file mode 100644 index 0000000000000..0de8b740227d7 --- /dev/null +++ b/src/ci/citool/src/jobs.rs @@ -0,0 +1,249 @@ +#[cfg(test)] +mod tests; + +use std::collections::BTreeMap; + +use serde_yaml::Value; + +use crate::GitHubContext; + +/// Representation of a job loaded from the `src/ci/github-actions/jobs.yml` file. +#[derive(serde::Deserialize, Debug, Clone)] +pub struct Job { + /// Name of the job, e.g. mingw-check + pub name: String, + /// GitHub runner on which the job should be executed + pub os: String, + pub env: BTreeMap, + /// Should the job be only executed on a specific channel? + #[serde(default)] + pub only_on_channel: Option, + /// Do not cancel the whole workflow if this job fails. + #[serde(default)] + pub continue_on_error: Option, + /// Free additional disk space in the job, by removing unused packages. + #[serde(default)] + pub free_disk: Option, + /// Documentation link to a resource that could help people debug this CI job. + pub doc_url: Option, +} + +impl Job { + /// By default, the Docker image of a job is based on its name. + /// However, it can be overridden by its IMAGE environment variable. + pub fn image(&self) -> String { + self.env + .get("IMAGE") + .map(|v| v.as_str().expect("IMAGE value should be a string").to_string()) + .unwrap_or_else(|| self.name.clone()) + } + + fn is_linux(&self) -> bool { + self.os.contains("ubuntu") + } +} + +#[derive(serde::Deserialize, Debug)] +struct JobEnvironments { + #[serde(rename = "pr")] + pr_env: BTreeMap, + #[serde(rename = "try")] + try_env: BTreeMap, + #[serde(rename = "auto")] + auto_env: BTreeMap, +} + +#[derive(serde::Deserialize, Debug)] +pub struct JobDatabase { + #[serde(rename = "pr")] + pub pr_jobs: Vec, + #[serde(rename = "try")] + pub try_jobs: Vec, + #[serde(rename = "auto")] + pub auto_jobs: Vec, + + /// Shared environments for the individual run types. + envs: JobEnvironments, +} + +impl JobDatabase { + /// Find `auto` jobs that correspond to the passed `pattern`. + /// Patterns are matched using the glob syntax. + /// For example `dist-*` matches all jobs starting with `dist-`. + fn find_auto_jobs_by_pattern(&self, pattern: &str) -> Vec { + self.auto_jobs + .iter() + .filter(|j| glob_match::glob_match(pattern, &j.name)) + .cloned() + .collect() + } +} + +pub fn load_job_db(db: &str) -> anyhow::Result { + let mut db: Value = serde_yaml::from_str(&db)?; + + // We need to expand merge keys (<<), because serde_yaml can't deal with them + // `apply_merge` only applies the merge once, so do it a few times to unwrap nested merges. + db.apply_merge()?; + db.apply_merge()?; + + let db: JobDatabase = serde_yaml::from_value(db)?; + Ok(db) +} + +/// Representation of a job outputted to a GitHub Actions workflow. +#[derive(serde::Serialize, Debug)] +struct GithubActionsJob { + /// The main identifier of the job, used by CI scripts to determine what should be executed. + name: String, + /// Helper label displayed in GitHub Actions interface, containing the job name and a run type + /// prefix (PR/try/auto). + full_name: String, + os: String, + env: BTreeMap, + #[serde(skip_serializing_if = "Option::is_none")] + continue_on_error: Option, + #[serde(skip_serializing_if = "Option::is_none")] + free_disk: Option, + #[serde(skip_serializing_if = "Option::is_none")] + doc_url: Option, +} + +/// Skip CI jobs that are not supposed to be executed on the given `channel`. +fn skip_jobs(jobs: Vec, channel: &str) -> Vec { + jobs.into_iter() + .filter(|job| { + job.only_on_channel.is_none() || job.only_on_channel.as_deref() == Some(channel) + }) + .collect() +} + +/// Type of workflow that is being executed on CI +#[derive(Debug)] +pub enum RunType { + /// Workflows that run after a push to a PR branch + PullRequest, + /// Try run started with @bors try + TryJob { job_patterns: Option> }, + /// Merge attempt workflow + AutoJob, +} + +/// Maximum number of custom try jobs that can be requested in a single +/// `@bors try` request. +const MAX_TRY_JOBS_COUNT: usize = 20; + +fn calculate_jobs( + run_type: &RunType, + db: &JobDatabase, + channel: &str, +) -> anyhow::Result> { + let (jobs, prefix, base_env) = match run_type { + RunType::PullRequest => (db.pr_jobs.clone(), "PR", &db.envs.pr_env), + RunType::TryJob { job_patterns } => { + let jobs = if let Some(patterns) = job_patterns { + let mut jobs: Vec = vec![]; + let mut unknown_patterns = vec![]; + for pattern in patterns { + let matched_jobs = db.find_auto_jobs_by_pattern(pattern); + if matched_jobs.is_empty() { + unknown_patterns.push(pattern.clone()); + } else { + for job in matched_jobs { + if !jobs.iter().any(|j| j.name == job.name) { + jobs.push(job); + } + } + } + } + if !unknown_patterns.is_empty() { + return Err(anyhow::anyhow!( + "Patterns `{}` did not match any auto jobs", + unknown_patterns.join(", ") + )); + } + if jobs.len() > MAX_TRY_JOBS_COUNT { + return Err(anyhow::anyhow!( + "It is only possible to schedule up to {MAX_TRY_JOBS_COUNT} custom jobs, received {} custom jobs expanded from {} pattern(s)", + jobs.len(), + patterns.len() + )); + } + jobs + } else { + db.try_jobs.clone() + }; + (jobs, "try", &db.envs.try_env) + } + RunType::AutoJob => (db.auto_jobs.clone(), "auto", &db.envs.auto_env), + }; + let jobs = skip_jobs(jobs, channel); + let jobs = jobs + .into_iter() + .map(|job| { + let mut env: BTreeMap = crate::yaml_map_to_json(base_env); + env.extend(crate::yaml_map_to_json(&job.env)); + let full_name = format!("{prefix} - {}", job.name); + + GithubActionsJob { + name: job.name, + full_name, + os: job.os, + env, + continue_on_error: job.continue_on_error, + free_disk: job.free_disk, + doc_url: job.doc_url, + } + }) + .collect(); + + Ok(jobs) +} + +pub fn calculate_job_matrix( + db: JobDatabase, + gh_ctx: GitHubContext, + channel: &str, +) -> anyhow::Result<()> { + let run_type = gh_ctx.get_run_type().ok_or_else(|| { + anyhow::anyhow!("Cannot determine the type of workflow that is being executed") + })?; + eprintln!("Run type: {run_type:?}"); + + let jobs = calculate_jobs(&run_type, &db, channel)?; + if jobs.is_empty() { + return Err(anyhow::anyhow!("Computed job list is empty")); + } + + let run_type = match run_type { + RunType::PullRequest => "pr", + RunType::TryJob { .. } => "try", + RunType::AutoJob => "auto", + }; + + eprintln!("Output"); + eprintln!("jobs={jobs:?}"); + eprintln!("run_type={run_type}"); + println!("jobs={}", serde_json::to_string(&jobs)?); + println!("run_type={run_type}"); + + Ok(()) +} + +pub fn find_linux_job<'a>(jobs: &'a [Job], name: &str) -> anyhow::Result<&'a Job> { + let Some(job) = jobs.iter().find(|j| j.name == name) else { + let available_jobs: Vec<&Job> = jobs.iter().filter(|j| j.is_linux()).collect(); + let mut available_jobs = + available_jobs.iter().map(|j| j.name.to_string()).collect::>(); + available_jobs.sort(); + return Err(anyhow::anyhow!( + "Job {name} not found. The following jobs are available:\n{}", + available_jobs.join(", ") + )); + }; + if !job.is_linux() { + return Err(anyhow::anyhow!("Only Linux jobs can be executed locally")); + } + + Ok(job) +} diff --git a/src/ci/citool/src/jobs/tests.rs b/src/ci/citool/src/jobs/tests.rs new file mode 100644 index 0000000000000..a489656fa5dc7 --- /dev/null +++ b/src/ci/citool/src/jobs/tests.rs @@ -0,0 +1,64 @@ +use crate::jobs::{JobDatabase, load_job_db}; + +#[test] +fn lookup_job_pattern() { + let db = load_job_db( + r#" +envs: + pr: + try: + auto: + +pr: +try: +auto: + - name: dist-a + os: ubuntu + env: {} + - name: dist-a-alt + os: ubuntu + env: {} + - name: dist-b + os: ubuntu + env: {} + - name: dist-b-alt + os: ubuntu + env: {} + - name: test-a + os: ubuntu + env: {} + - name: test-a-alt + os: ubuntu + env: {} + - name: test-i686 + os: ubuntu + env: {} + - name: dist-i686 + os: ubuntu + env: {} + - name: test-msvc-i686-1 + os: ubuntu + env: {} + - name: test-msvc-i686-2 + os: ubuntu + env: {} +"#, + ) + .unwrap(); + check_pattern(&db, "dist-*", &["dist-a", "dist-a-alt", "dist-b", "dist-b-alt", "dist-i686"]); + check_pattern(&db, "*-alt", &["dist-a-alt", "dist-b-alt", "test-a-alt"]); + check_pattern(&db, "dist*-alt", &["dist-a-alt", "dist-b-alt"]); + check_pattern( + &db, + "*i686*", + &["test-i686", "dist-i686", "test-msvc-i686-1", "test-msvc-i686-2"], + ); +} + +#[track_caller] +fn check_pattern(db: &JobDatabase, pattern: &str, expected: &[&str]) { + let jobs = + db.find_auto_jobs_by_pattern(pattern).into_iter().map(|j| j.name).collect::>(); + + assert_eq!(jobs, expected); +} diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs new file mode 100644 index 0000000000000..cd690ebeb0625 --- /dev/null +++ b/src/ci/citool/src/main.rs @@ -0,0 +1,223 @@ +mod cpu_usage; +mod datadog; +mod jobs; +mod merge_report; +mod metrics; +mod utils; + +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use anyhow::Context; +use clap::Parser; +use jobs::JobDatabase; +use serde_yaml::Value; + +use crate::cpu_usage::load_cpu_usage; +use crate::datadog::upload_datadog_metric; +use crate::jobs::RunType; +use crate::merge_report::post_merge_report; +use crate::metrics::postprocess_metrics; +use crate::utils::load_env_var; + +const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/.."); +const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker"); +const JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../github-actions/jobs.yml"); + +struct GitHubContext { + event_name: String, + branch_ref: String, + commit_message: Option, +} + +impl GitHubContext { + fn get_run_type(&self) -> Option { + match (self.event_name.as_str(), self.branch_ref.as_str()) { + ("pull_request", _) => Some(RunType::PullRequest), + ("push", "refs/heads/try-perf") => Some(RunType::TryJob { job_patterns: None }), + ("push", "refs/heads/try" | "refs/heads/automation/bors/try") => { + let patterns = self.get_try_job_patterns(); + let patterns = if !patterns.is_empty() { Some(patterns) } else { None }; + Some(RunType::TryJob { job_patterns: patterns }) + } + ("push", "refs/heads/auto") => Some(RunType::AutoJob), + _ => None, + } + } + + /// Tries to parse patterns of CI jobs that should be executed + /// from the commit message of the passed GitHub context + /// + /// They can be specified in the form of + /// try-job: + /// or + /// try-job: `` + /// (to avoid GitHub rendering the glob patterns as Markdown) + fn get_try_job_patterns(&self) -> Vec { + if let Some(ref msg) = self.commit_message { + msg.lines() + .filter_map(|line| line.trim().strip_prefix("try-job: ")) + // Strip backticks if present + .map(|l| l.trim_matches('`')) + .map(|l| l.trim().to_string()) + .collect() + } else { + vec![] + } + } +} + +fn load_github_ctx() -> anyhow::Result { + let event_name = load_env_var("GITHUB_EVENT_NAME")?; + let commit_message = + if event_name == "push" { Some(load_env_var("COMMIT_MESSAGE")?) } else { None }; + + Ok(GitHubContext { event_name, branch_ref: load_env_var("GITHUB_REF")?, commit_message }) +} + +fn yaml_map_to_json(map: &BTreeMap) -> BTreeMap { + map.into_iter() + .map(|(key, value)| { + ( + key.clone(), + serde_json::to_value(&value).expect("Cannot convert map value from YAML to JSON"), + ) + }) + .collect() +} + +fn run_workflow_locally(db: JobDatabase, job_type: JobType, name: String) -> anyhow::Result<()> { + let jobs = match job_type { + JobType::Auto => &db.auto_jobs, + JobType::PR => &db.pr_jobs, + }; + let job = + jobs::find_linux_job(jobs, &name).with_context(|| format!("Cannot find job {name}"))?; + + let mut custom_env: BTreeMap = BTreeMap::new(); + // Replicate src/ci/scripts/setup-environment.sh + // Adds custom environment variables to the job + if name.starts_with("dist-") { + if name.ends_with("-alt") { + custom_env.insert("DEPLOY_ALT".to_string(), "1".to_string()); + } else { + custom_env.insert("DEPLOY".to_string(), "1".to_string()); + } + } + custom_env.extend(job.env.iter().map(|(key, value)| { + let value = match value { + Value::Bool(value) => value.to_string(), + Value::Number(value) => value.to_string(), + Value::String(value) => value.clone(), + _ => panic!("Unexpected type for environment variable {key} Only bool/number/string is supported.") + }; + (key.clone(), value) + })); + + let mut cmd = Command::new(Path::new(DOCKER_DIRECTORY).join("run.sh")); + cmd.arg(job.image()); + cmd.envs(custom_env); + + eprintln!("Executing {cmd:?}"); + + let result = cmd.spawn()?.wait()?; + if !result.success() { Err(anyhow::anyhow!("Job failed")) } else { Ok(()) } +} + +fn upload_ci_metrics(cpu_usage_csv: &Path) -> anyhow::Result<()> { + let usage = load_cpu_usage(cpu_usage_csv).context("Cannot load CPU usage from input CSV")?; + eprintln!("CPU usage\n{usage:?}"); + + let avg = if !usage.is_empty() { usage.iter().sum::() / usage.len() as f64 } else { 0.0 }; + eprintln!("CPU usage average: {avg}"); + + upload_datadog_metric("avg-cpu-usage", avg).context("Cannot upload Datadog metric")?; + + Ok(()) +} + +#[derive(clap::Parser)] +enum Args { + /// Calculate a list of jobs that should be executed on CI. + /// Should only be used on CI inside GitHub actions. + CalculateJobMatrix { + #[clap(long)] + jobs_file: Option, + }, + /// Execute a given CI job locally. + #[clap(name = "run-local")] + RunJobLocally { + /// Name of the job that should be executed. + name: String, + /// Type of the job that should be executed. + #[clap(long = "type", default_value = "auto")] + job_type: JobType, + }, + /// Postprocess the metrics.json file generated by bootstrap. + PostprocessMetrics { + /// Path to the metrics.json file + metrics_path: PathBuf, + /// Path to a file where the postprocessed metrics summary will be stored. + /// Usually, this will be GITHUB_STEP_SUMMARY on CI. + summary_path: PathBuf, + }, + /// Upload CI metrics to Datadog. + UploadBuildMetrics { + /// Path to a CSV containing the CI job CPU usage. + cpu_usage_csv: PathBuf, + }, + /// Generate a report of test execution changes between two rustc commits. + PostMergeReport { + /// Parent commit to use as a base of the comparison. + parent: String, + /// Current commit that will be compared to `parent`. + current: String, + }, +} + +#[derive(clap::ValueEnum, Clone)] +pub enum JobType { + /// Merge attempt ("auto") job + Auto, + /// Pull request job + PR, +} + +fn main() -> anyhow::Result<()> { + let args = Args::parse(); + let default_jobs_file = Path::new(JOBS_YML_PATH); + let load_db = |jobs_path| { + let db = utils::read_to_string(jobs_path)?; + Ok::<_, anyhow::Error>(jobs::load_job_db(&db).context("Cannot load jobs.yml")?) + }; + + match args { + Args::CalculateJobMatrix { jobs_file } => { + let jobs_path = jobs_file.as_deref().unwrap_or(default_jobs_file); + let gh_ctx = load_github_ctx() + .context("Cannot load environment variables from GitHub Actions")?; + let channel = utils::read_to_string(Path::new(CI_DIRECTORY).join("channel")) + .context("Cannot read channel file")? + .trim() + .to_string(); + + jobs::calculate_job_matrix(load_db(jobs_path)?, gh_ctx, &channel) + .context("Failed to calculate job matrix")?; + } + Args::RunJobLocally { job_type, name } => { + run_workflow_locally(load_db(default_jobs_file)?, job_type, name)?; + } + Args::UploadBuildMetrics { cpu_usage_csv } => { + upload_ci_metrics(&cpu_usage_csv)?; + } + Args::PostprocessMetrics { metrics_path, summary_path } => { + postprocess_metrics(&metrics_path, &summary_path)?; + } + Args::PostMergeReport { current: commit, parent } => { + post_merge_report(load_db(default_jobs_file)?, parent, commit)?; + } + } + + Ok(()) +} diff --git a/src/ci/citool/src/merge_report.rs b/src/ci/citool/src/merge_report.rs new file mode 100644 index 0000000000000..62daa2e68530a --- /dev/null +++ b/src/ci/citool/src/merge_report.rs @@ -0,0 +1,318 @@ +use std::collections::{HashMap, HashSet}; +use std::path::PathBuf; + +use anyhow::Context; +use build_helper::metrics::{JsonRoot, TestOutcome, TestSuiteMetadata}; + +use crate::jobs::JobDatabase; +use crate::metrics::get_test_suites; + +type Sha = String; +type JobName = String; + +/// Computes a post merge CI analysis report between the `parent` and `current` commits. +pub fn post_merge_report(job_db: JobDatabase, parent: Sha, current: Sha) -> anyhow::Result<()> { + let jobs = download_all_metrics(&job_db, &parent, ¤t)?; + let aggregated_test_diffs = aggregate_test_diffs(&jobs)?; + + println!("Comparing {parent} (base) -> {current} (this PR)\n"); + report_test_diffs(aggregated_test_diffs); + + Ok(()) +} + +struct JobMetrics { + parent: Option, + current: JsonRoot, +} + +/// Download before/after metrics for all auto jobs in the job database. +fn download_all_metrics( + job_db: &JobDatabase, + parent: &str, + current: &str, +) -> anyhow::Result> { + let mut jobs = HashMap::default(); + + for job in &job_db.auto_jobs { + eprintln!("Downloading metrics of job {}", job.name); + let metrics_parent = match download_job_metrics(&job.name, parent) { + Ok(metrics) => Some(metrics), + Err(error) => { + eprintln!( + r#"Did not find metrics for job `{}` at `{}`: {error:?}. +Maybe it was newly added?"#, + job.name, parent + ); + None + } + }; + let metrics_current = download_job_metrics(&job.name, current)?; + jobs.insert( + job.name.clone(), + JobMetrics { parent: metrics_parent, current: metrics_current }, + ); + } + Ok(jobs) +} + +/// Downloads job metrics of the given job for the given commit. +/// Caches the result on the local disk. +fn download_job_metrics(job_name: &str, sha: &str) -> anyhow::Result { + let cache_path = PathBuf::from(".citool-cache").join(sha).join(job_name).join("metrics.json"); + if let Some(cache_entry) = + std::fs::read_to_string(&cache_path).ok().and_then(|data| serde_json::from_str(&data).ok()) + { + return Ok(cache_entry); + } + + let url = get_metrics_url(job_name, sha); + let mut response = ureq::get(&url).call()?; + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "Cannot fetch metrics from {url}: {}\n{}", + response.status(), + response.body_mut().read_to_string()? + )); + } + let data: JsonRoot = response + .body_mut() + .read_json() + .with_context(|| anyhow::anyhow!("cannot deserialize metrics from {url}"))?; + + // Ignore errors if cache cannot be created + if std::fs::create_dir_all(cache_path.parent().unwrap()).is_ok() { + if let Ok(serialized) = serde_json::to_string(&data) { + let _ = std::fs::write(&cache_path, &serialized); + } + } + Ok(data) +} + +fn get_metrics_url(job_name: &str, sha: &str) -> String { + let suffix = if job_name.ends_with("-alt") { "-alt" } else { "" }; + format!("https://ci-artifacts.rust-lang.org/rustc-builds{suffix}/{sha}/metrics-{job_name}.json") +} + +/// Represents a difference in the outcome of tests between a base and a current commit. +/// Maps test diffs to jobs that contained them. +#[derive(Debug)] +struct AggregatedTestDiffs { + diffs: HashMap>, +} + +fn aggregate_test_diffs( + jobs: &HashMap, +) -> anyhow::Result { + let mut diffs: HashMap> = HashMap::new(); + + // Aggregate test suites + for (name, metrics) in jobs { + if let Some(parent) = &metrics.parent { + let tests_parent = aggregate_tests(parent); + let tests_current = aggregate_tests(&metrics.current); + for diff in calculate_test_diffs(tests_parent, tests_current) { + diffs.entry(diff).or_default().push(name.to_string()); + } + } + } + + Ok(AggregatedTestDiffs { diffs }) +} + +#[derive(Eq, PartialEq, Hash, Debug)] +enum TestOutcomeDiff { + ChangeOutcome { before: TestOutcome, after: TestOutcome }, + Missing { before: TestOutcome }, + Added(TestOutcome), +} + +#[derive(Eq, PartialEq, Hash, Debug)] +struct TestDiff { + test: Test, + diff: TestOutcomeDiff, +} + +fn calculate_test_diffs(parent: TestSuiteData, current: TestSuiteData) -> HashSet { + let mut diffs = HashSet::new(); + for (test, outcome) in ¤t.tests { + match parent.tests.get(test) { + Some(before) => { + if before != outcome { + diffs.insert(TestDiff { + test: test.clone(), + diff: TestOutcomeDiff::ChangeOutcome { + before: before.clone(), + after: outcome.clone(), + }, + }); + } + } + None => { + diffs.insert(TestDiff { + test: test.clone(), + diff: TestOutcomeDiff::Added(outcome.clone()), + }); + } + } + } + for (test, outcome) in &parent.tests { + if !current.tests.contains_key(test) { + diffs.insert(TestDiff { + test: test.clone(), + diff: TestOutcomeDiff::Missing { before: outcome.clone() }, + }); + } + } + + diffs +} + +/// Aggregates test suite executions from all bootstrap invocations in a given CI job. +#[derive(Default)] +struct TestSuiteData { + tests: HashMap, +} + +#[derive(Hash, PartialEq, Eq, Debug, Clone)] +struct Test { + name: String, + is_doctest: bool, +} + +/// Extracts all tests from the passed metrics and map them to their outcomes. +fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData { + let mut tests = HashMap::new(); + let test_suites = get_test_suites(&metrics); + for suite in test_suites { + for test in &suite.tests { + // Poor man's detection of doctests based on the "(line XYZ)" suffix + let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. }) + && test.name.contains("(line"); + let test_entry = Test { name: normalize_test_name(&test.name), is_doctest }; + tests.insert(test_entry, test.outcome.clone()); + } + } + TestSuiteData { tests } +} + +/// Normalizes Windows-style path delimiters to Unix-style paths. +fn normalize_test_name(name: &str) -> String { + name.replace('\\', "/") +} + +/// Prints test changes in Markdown format to stdout. +fn report_test_diffs(diff: AggregatedTestDiffs) { + println!("## Test differences"); + if diff.diffs.is_empty() { + println!("No test diffs found"); + return; + } + + fn format_outcome(outcome: &TestOutcome) -> String { + match outcome { + TestOutcome::Passed => "pass".to_string(), + TestOutcome::Failed => "fail".to_string(), + TestOutcome::Ignored { ignore_reason } => { + let reason = match ignore_reason { + Some(reason) => format!(" ({reason})"), + None => String::new(), + }; + format!("ignore{reason}") + } + } + } + + fn format_diff(diff: &TestOutcomeDiff) -> String { + match diff { + TestOutcomeDiff::ChangeOutcome { before, after } => { + format!("{} -> {}", format_outcome(before), format_outcome(after)) + } + TestOutcomeDiff::Missing { before } => { + format!("{} -> [missing]", format_outcome(before)) + } + TestOutcomeDiff::Added(outcome) => { + format!("[missing] -> {}", format_outcome(outcome)) + } + } + } + + fn format_job_group(group: u64) -> String { + format!("**J{group}**") + } + + // It would be quite noisy to repeat the jobs that contained the test changes after/next to + // every test diff. At the same time, grouping the test diffs by + // [unique set of jobs that contained them] also doesn't work well, because the test diffs + // would have to be duplicated several times. + // Instead, we create a set of unique job groups, and then print a job group after each test. + // We then print the job groups at the end, as a sort of index. + let mut grouped_diffs: Vec<(&TestDiff, u64)> = vec![]; + let mut job_list_to_group: HashMap<&[JobName], u64> = HashMap::new(); + let mut job_index: Vec<&[JobName]> = vec![]; + + let original_diff_count = diff.diffs.len(); + let diffs = diff + .diffs + .into_iter() + .filter(|(diff, _)| !diff.test.is_doctest) + .map(|(diff, mut jobs)| { + jobs.sort(); + (diff, jobs) + }) + .collect::>(); + let doctest_count = original_diff_count.saturating_sub(diffs.len()); + + let max_diff_count = 100; + for (diff, jobs) in diffs.iter().take(max_diff_count) { + let jobs = &*jobs; + let job_group = match job_list_to_group.get(jobs.as_slice()) { + Some(id) => *id, + None => { + let id = job_index.len() as u64; + job_index.push(jobs); + job_list_to_group.insert(jobs, id); + id + } + }; + grouped_diffs.push((diff, job_group)); + } + + // Sort diffs by job group and test name + grouped_diffs.sort_by(|(d1, g1), (d2, g2)| g1.cmp(&g2).then(d1.test.name.cmp(&d2.test.name))); + + for (diff, job_group) in grouped_diffs { + println!( + "- `{}`: {} ({})", + diff.test.name, + format_diff(&diff.diff), + format_job_group(job_group) + ); + } + + let extra_diffs = diffs.len().saturating_sub(max_diff_count); + if extra_diffs > 0 { + println!("\n(and {extra_diffs} additional {})", pluralize("test diff", extra_diffs)); + } + + if doctest_count > 0 { + println!( + "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.", + pluralize("diff", doctest_count) + ); + } + + // Now print the job group index + println!("\n**Job group index**\n"); + for (group, jobs) in job_index.into_iter().enumerate() { + println!( + "- {}: {}", + format_job_group(group as u64), + jobs.iter().map(|j| format!("`{j}`")).collect::>().join(", ") + ); + } +} + +fn pluralize(text: &str, count: usize) -> String { + if count == 1 { text.to_string() } else { format!("{text}s") } +} diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs new file mode 100644 index 0000000000000..83b3d5ceed05a --- /dev/null +++ b/src/ci/citool/src/metrics.rs @@ -0,0 +1,172 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::io::Write; +use std::path::Path; + +use anyhow::Context; +use build_helper::metrics::{ + BuildStep, JsonNode, JsonRoot, TestOutcome, TestSuite, TestSuiteMetadata, format_build_steps, +}; + +pub fn postprocess_metrics(metrics_path: &Path, summary_path: &Path) -> anyhow::Result<()> { + let metrics = load_metrics(metrics_path)?; + + let mut file = File::options() + .append(true) + .create(true) + .open(summary_path) + .with_context(|| format!("Cannot open summary file at {summary_path:?}"))?; + + if !metrics.invocations.is_empty() { + writeln!(file, "# Bootstrap steps")?; + record_bootstrap_step_durations(&metrics, &mut file)?; + record_test_suites(&metrics, &mut file)?; + } + + Ok(()) +} + +fn record_bootstrap_step_durations(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> { + for invocation in &metrics.invocations { + let step = BuildStep::from_invocation(invocation); + let table = format_build_steps(&step); + eprintln!("Step `{}`\n{table}\n", invocation.cmdline); + writeln!( + file, + r"
+{} +
{table}
+
+", + invocation.cmdline + )?; + } + eprintln!("Recorded {} bootstrap invocation(s)", metrics.invocations.len()); + + Ok(()) +} + +fn record_test_suites(metrics: &JsonRoot, file: &mut File) -> anyhow::Result<()> { + let suites = get_test_suites(&metrics); + + if !suites.is_empty() { + let aggregated = aggregate_test_suites(&suites); + let table = render_table(aggregated); + writeln!(file, "\n# Test results\n")?; + writeln!(file, "{table}")?; + } else { + eprintln!("No test suites found in metrics"); + } + + Ok(()) +} + +fn render_table(suites: BTreeMap) -> String { + use std::fmt::Write; + + let mut table = "| Test suite | Passed ✅ | Ignored 🚫 | Failed ❌ |\n".to_string(); + writeln!(table, "|:------|------:|------:|------:|").unwrap(); + + fn compute_pct(value: f64, total: f64) -> f64 { + if total == 0.0 { 0.0 } else { value / total } + } + + fn write_row( + buffer: &mut String, + name: &str, + record: &TestSuiteRecord, + surround: &str, + ) -> std::fmt::Result { + let TestSuiteRecord { passed, ignored, failed } = record; + let total = (record.passed + record.ignored + record.failed) as f64; + let passed_pct = compute_pct(*passed as f64, total) * 100.0; + let ignored_pct = compute_pct(*ignored as f64, total) * 100.0; + let failed_pct = compute_pct(*failed as f64, total) * 100.0; + + write!(buffer, "| {surround}{name}{surround} |")?; + write!(buffer, " {surround}{passed} ({passed_pct:.0}%){surround} |")?; + write!(buffer, " {surround}{ignored} ({ignored_pct:.0}%){surround} |")?; + writeln!(buffer, " {surround}{failed} ({failed_pct:.0}%){surround} |")?; + + Ok(()) + } + + let mut total = TestSuiteRecord::default(); + for (name, record) in suites { + write_row(&mut table, &name, &record, "").unwrap(); + total.passed += record.passed; + total.ignored += record.ignored; + total.failed += record.failed; + } + write_row(&mut table, "Total", &total, "**").unwrap(); + table +} + +#[derive(Default)] +struct TestSuiteRecord { + passed: u64, + ignored: u64, + failed: u64, +} + +fn test_metadata_name(metadata: &TestSuiteMetadata) -> String { + match metadata { + TestSuiteMetadata::CargoPackage { crates, stage, .. } => { + format!("{} (stage {stage})", crates.join(", ")) + } + TestSuiteMetadata::Compiletest { suite, stage, .. } => { + format!("{suite} (stage {stage})") + } + } +} + +fn aggregate_test_suites(suites: &[&TestSuite]) -> BTreeMap { + let mut records: BTreeMap = BTreeMap::new(); + for suite in suites { + let name = test_metadata_name(&suite.metadata); + let record = records.entry(name).or_default(); + for test in &suite.tests { + match test.outcome { + TestOutcome::Passed => { + record.passed += 1; + } + TestOutcome::Failed => { + record.failed += 1; + } + TestOutcome::Ignored { .. } => { + record.ignored += 1; + } + } + } + } + records +} + +pub fn get_test_suites(metrics: &JsonRoot) -> Vec<&TestSuite> { + fn visit_test_suites<'a>(nodes: &'a [JsonNode], suites: &mut Vec<&'a TestSuite>) { + for node in nodes { + match node { + JsonNode::RustbuildStep { children, .. } => { + visit_test_suites(&children, suites); + } + JsonNode::TestSuite(suite) => { + suites.push(&suite); + } + } + } + } + + let mut suites = vec![]; + for invocation in &metrics.invocations { + visit_test_suites(&invocation.children, &mut suites); + } + suites +} + +fn load_metrics(path: &Path) -> anyhow::Result { + let metrics = std::fs::read_to_string(path) + .with_context(|| format!("Cannot read JSON metrics from {path:?}"))?; + let metrics: JsonRoot = serde_json::from_str(&metrics) + .with_context(|| format!("Cannot deserialize JSON metrics from {path:?}"))?; + Ok(metrics) +} diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs new file mode 100644 index 0000000000000..9cc220987bdfd --- /dev/null +++ b/src/ci/citool/src/utils.rs @@ -0,0 +1,11 @@ +use std::path::Path; + +use anyhow::Context; + +pub fn load_env_var(name: &str) -> anyhow::Result { + std::env::var(name).with_context(|| format!("Cannot find environment variable `{name}`")) +} + +pub fn read_to_string>(path: P) -> anyhow::Result { + std::fs::read_to_string(&path).with_context(|| format!("Cannot read file {:?}", path.as_ref())) +} diff --git a/src/ci/citool/tests/jobs.rs b/src/ci/citool/tests/jobs.rs new file mode 100644 index 0000000000000..788f5e7e4f661 --- /dev/null +++ b/src/ci/citool/tests/jobs.rs @@ -0,0 +1,64 @@ +use std::process::{Command, Stdio}; + +const TEST_JOBS_YML_PATH: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/test-jobs.yml"); + +#[test] +fn auto_jobs() { + let stdout = get_matrix("push", "commit", "refs/heads/auto"); + insta::assert_snapshot!(stdout, @r#" + jobs=[{"name":"aarch64-gnu","full_name":"auto - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"x86_64-gnu-llvm-18-1","full_name":"auto - x86_64-gnu-llvm-18-1","os":"ubuntu-24.04","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","DOCKER_SCRIPT":"stage_2_test_set1.sh","IMAGE":"x86_64-gnu-llvm-18","READ_ONLY_SRC":"0","RUST_BACKTRACE":1,"TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"aarch64-apple","full_name":"auto - aarch64-apple","os":"macos-14","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","MACOSX_DEPLOYMENT_TARGET":11.0,"MACOSX_STD_DEPLOYMENT_TARGET":11.0,"NO_DEBUG_ASSERTIONS":1,"NO_LLVM_ASSERTIONS":1,"NO_OVERFLOW_CHECKS":1,"RUSTC_RETRY_LINKER_ON_SEGFAULT":1,"RUST_CONFIGURE_ARGS":"--enable-sanitizers --enable-profiler --set rust.jemalloc","SCRIPT":"./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin","SELECT_XCODE":"/Applications/Xcode_15.4.app","TOOLSTATE_PUBLISH":1,"USE_XCODE_CLANG":1}},{"name":"dist-i686-msvc","full_name":"auto - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}] + run_type=auto + "#); +} + +#[test] +fn try_jobs() { + let stdout = get_matrix("push", "commit", "refs/heads/try"); + insta::assert_snapshot!(stdout, @r#" + jobs=[{"name":"dist-x86_64-linux","full_name":"try - dist-x86_64-linux","os":"ubuntu-22.04-16core-64gb","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1}}] + run_type=try + "#); +} + +#[test] +fn try_custom_jobs() { + let stdout = get_matrix( + "push", + r#"This is a test PR + +try-job: aarch64-gnu +try-job: dist-i686-msvc"#, + "refs/heads/try", + ); + insta::assert_snapshot!(stdout, @r#" + jobs=[{"name":"aarch64-gnu","full_name":"try - aarch64-gnu","os":"ubuntu-22.04-arm","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","DEPLOY_BUCKET":"rust-lang-ci2","DIST_TRY_BUILD":1,"TOOLSTATE_PUBLISH":1},"free_disk":true},{"name":"dist-i686-msvc","full_name":"try - dist-i686-msvc","os":"windows-2022","env":{"ARTIFACTS_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZN24CBO55","AWS_REGION":"us-west-1","CACHES_AWS_ACCESS_KEY_ID":"AKIA46X5W6CZI5DHEBFL","CODEGEN_BACKENDS":"llvm,cranelift","DEPLOY_BUCKET":"rust-lang-ci2","DIST_REQUIRE_ALL_TOOLS":1,"DIST_TRY_BUILD":1,"RUST_CONFIGURE_ARGS":"--build=i686-pc-windows-msvc --host=i686-pc-windows-msvc --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler","SCRIPT":"python x.py dist bootstrap --include-default-paths","TOOLSTATE_PUBLISH":1}}] + run_type=try + "#); +} + +#[test] +fn pr_jobs() { + let stdout = get_matrix("pull_request", "commit", "refs/heads/pr/1234"); + insta::assert_snapshot!(stdout, @r#" + jobs=[{"name":"mingw-check","full_name":"PR - mingw-check","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"free_disk":true},{"name":"mingw-check-tidy","full_name":"PR - mingw-check-tidy","os":"ubuntu-24.04","env":{"PR_CI_JOB":1},"continue_on_error":true,"free_disk":true,"doc_url":"https://foo.bar"}] + run_type=pr + "#); +} + +fn get_matrix(event_name: &str, commit_msg: &str, branch_ref: &str) -> String { + let output = Command::new("cargo") + .args(["run", "-q", "calculate-job-matrix", "--jobs-file", TEST_JOBS_YML_PATH]) + .env("GITHUB_EVENT_NAME", event_name) + .env("COMMIT_MESSAGE", commit_msg) + .env("GITHUB_REF", branch_ref) + .stdout(Stdio::piped()) + .output() + .expect("Failed to execute command"); + + let stdout = String::from_utf8(output.stdout).unwrap(); + let stderr = String::from_utf8(output.stderr).unwrap(); + if !output.status.success() { + panic!("cargo run failed: {}\n{}", stdout, stderr); + } + stdout +} diff --git a/src/ci/citool/tests/test-jobs.yml b/src/ci/citool/tests/test-jobs.yml new file mode 100644 index 0000000000000..ff4d1772f59b9 --- /dev/null +++ b/src/ci/citool/tests/test-jobs.yml @@ -0,0 +1,146 @@ +runners: + - &base-job + env: { } + + - &job-linux-4c + os: ubuntu-24.04 + # Free some disk space to avoid running out of space during the build. + free_disk: true + <<: *base-job + + - &job-linux-16c + os: ubuntu-22.04-16core-64gb + <<: *base-job + + - &job-macos-m1 + os: macos-14 + <<: *base-job + + - &job-windows + os: windows-2022 + <<: *base-job + + - &job-aarch64-linux + # Free some disk space to avoid running out of space during the build. + free_disk: true + os: ubuntu-22.04-arm + <<: *base-job +envs: + env-x86_64-apple-tests: &env-x86_64-apple-tests + SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + # Ensure that host tooling is tested on our minimum supported macOS version. + MACOSX_DEPLOYMENT_TARGET: 10.12 + MACOSX_STD_DEPLOYMENT_TARGET: 10.12 + SELECT_XCODE: /Applications/Xcode_15.2.app + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + + production: + &production + DEPLOY_BUCKET: rust-lang-ci2 + # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named + # AWS_SECRET_ACCESS_KEY_. Including the key id in the name allows to + # rotate them in a single branch while keeping the old key in another + # branch, which wouldn't be possible if the key was named with the kind + # (caches, artifacts...). + CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZI5DHEBFL + ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZN24CBO55 + AWS_REGION: us-west-1 + TOOLSTATE_PUBLISH: 1 + + try: + <<: *production + # The following env var activates faster `try` builds in `opt-dist` by, e.g. + # - building only the more commonly useful components (we rarely need e.g. rust-docs in try + # builds) + # - not running `opt-dist`'s post-optimization smoke tests on the resulting toolchain + # + # If you *want* these to happen however, temporarily comment it before triggering a try build. + DIST_TRY_BUILD: 1 + + auto: + <<: *production + + pr: + PR_CI_JOB: 1 + +# Jobs that run on each push to a pull request (PR) +# These jobs automatically inherit envs.pr, to avoid repeating +# it in each job definition. +pr: + - name: mingw-check + <<: *job-linux-4c + - name: mingw-check-tidy + continue_on_error: true + doc_url: https://foo.bar + <<: *job-linux-4c + +# Jobs that run when you perform a try build (@bors try) +# These jobs automatically inherit envs.try, to avoid repeating +# it in each job definition. +try: + - name: dist-x86_64-linux + env: + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-linux-16c + +# Main CI jobs that have to be green to merge a commit into master +# These jobs automatically inherit envs.auto, to avoid repeating +# it in each job definition. +auto: + - name: aarch64-gnu + <<: *job-aarch64-linux + + # The x86_64-gnu-llvm-18 job is split into multiple jobs to run tests in parallel. + # x86_64-gnu-llvm-18-1 skips tests that run in x86_64-gnu-llvm-18-{2,3}. + - name: x86_64-gnu-llvm-18-1 + env: + RUST_BACKTRACE: 1 + READ_ONLY_SRC: "0" + IMAGE: x86_64-gnu-llvm-18 + DOCKER_SCRIPT: stage_2_test_set1.sh + <<: *job-linux-4c + + + #################### + # macOS Builders # + #################### + + - name: aarch64-apple + env: + SCRIPT: ./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin + RUST_CONFIGURE_ARGS: >- + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_15.4.app + USE_XCODE_CLANG: 1 + # Aarch64 tooling only needs to support macOS 11.0 and up as nothing else + # supports the hardware, so only need to test it there. + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + NO_OVERFLOW_CHECKS: 1 + <<: *job-macos-m1 + + ###################### + # Windows Builders # + ###################### + + - name: dist-i686-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-msvc + --host=i686-pc-windows-msvc + --target=i686-pc-windows-msvc,i586-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist bootstrap --include-default-paths + DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift + <<: *job-windows diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 2b1de43c2f68c..20b6f7d10ef56 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -8,15 +8,15 @@ Note that a single Docker image can be used by multiple CI jobs, so the job name is the important thing that you should know. You can examine the existing CI jobs in the [`jobs.yml`](../github-actions/jobs.yml) file. -To run a specific CI job locally, you can use the following script: +To run a specific CI job locally, you can use the `citool` Rust crate: ``` -python3 ./src/ci/github-actions/ci.py run-local +cargo run --manifest-path src/ci/citool/Cargo.toml run-local ``` For example, to run the `x86_64-gnu-llvm-18-1` job: ``` -python3 ./src/ci/github-actions/ci.py run-local x86_64-gnu-llvm-18-1 +cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-18-1 ``` The job will output artifacts in an `obj/` dir at the root of a repository. Note diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile index eb39861d8c703..cf030f6830e5b 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-debug/Dockerfile @@ -30,7 +30,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 -ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 # llvm.use-linker conflicts with downloading CI LLVM ENV NO_DOWNLOAD_CI_LLVM 1 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 0b4682ac32ba0..ae5bf8946dd94 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -101,7 +101,9 @@ ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \ ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \ --host $HOSTS --target $HOSTS \ --include-default-paths \ - build-manifest bootstrap + build-manifest bootstrap && \ + # Use GCC for building GCC, as it seems to behave badly when built with Clang + CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh index 4a42f5da29fcc..ad21836253b9e 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/build-netbsd-toolchain.sh @@ -41,8 +41,6 @@ cd netbsd mkdir -p /x-tools/x86_64-unknown-netbsd/sysroot -# URL=https://ci-mirrors.rust-lang.org/rustc - # Hashes come from https://cdn.netbsd.org/pub/NetBSD/security/hashes/NetBSD-9.0_hashes.asc SRC_SHA=2c791ae009a6929c6fc893ec5df7e62910ee8207e0b2159d6937309c03efe175b6ae1e445829a13d041b6851334ad35c521f2fa03c97675d4a05f1fafe58ede0 GNUSRC_SHA=3710085a73feecf6a843415271ec794c90146b03f6bbd30f07c9e0c79febf8995d557e40194f1e05db655e4f5ef2fae97563f8456fceaae65d4ea98857a83b1c @@ -51,22 +49,16 @@ SYSSRC_SHA=60b9ddf4cc6402256473e2e1eefeabd9001aa4e205208715ecc6d6fc3f5b400e46994 BASE_SHA=b5926b107cebf40c3c19b4f6cd039b610987dd7f819e7cdde3bd1e5230a856906e7930b15ab242d52ced9f0bda01d574be59488b8dbb95fa5df2987d0a70995f COMP_SHA=38ea54f30d5fc2afea87e5096f06873e00182789e8ad9cec0cb3e9f7c538c1aa4779e63fd401a36ba02676158e83fa5c95e8e87898db59c1914fb206aecd82d2 -# FIXME: the archive URL is being used temporarily while the CDN is down. -# We should serve this from our own CDN -# SOURCE_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/source/sets -SOURCE_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/source/sets -download src.tgz "$SOURCE_URL/src.tgz" "$SRC_SHA" tar xzf src.tgz -download gnusrc.tgz "$SOURCE_URL/gnusrc.tgz" "$GNUSRC_SHA" tar xzf gnusrc.tgz -download sharesrc.tgz "$SOURCE_URL/sharesrc.tgz" "$SHARESRC_SHA" tar xzf sharesrc.tgz -download syssrc.tgz "$SOURCE_URL/syssrc.tgz" "$SYSSRC_SHA" tar xzf syssrc.tgz - -# FIXME: the archive URL is being used temporarily while the CDN is down. -# We should serve this from our own CDN -# BINARY_URL=https://cdn.netbsd.org/pub/NetBSD/NetBSD-9.0/amd64/binary/sets -BINARY_URL=http://archive.netbsd.org/pub/NetBSD-archive/NetBSD-9.0/amd64/binary/sets -download base.tar.xz "$BINARY_URL/base.tar.xz" "$BASE_SHA" \ +SOURCE_URL=https://ci-mirrors.rust-lang.org/rustc/2025-03-14-netbsd-9.0-src +download src.tgz "$SOURCE_URL-src.tgz" "$SRC_SHA" tar xzf src.tgz +download gnusrc.tgz "$SOURCE_URL-gnusrc.tgz" "$GNUSRC_SHA" tar xzf gnusrc.tgz +download sharesrc.tgz "$SOURCE_URL-sharesrc.tgz" "$SHARESRC_SHA" tar xzf sharesrc.tgz +download syssrc.tgz "$SOURCE_URL-syssrc.tgz" "$SYSSRC_SHA" tar xzf syssrc.tgz + +BINARY_URL=https://ci-mirrors.rust-lang.org/rustc/2025-03-14-netbsd-9.0-amd64-binary +download base.tar.xz "$BINARY_URL-base.tar.xz" "$BASE_SHA" \ tar xJf base.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib ./lib -download comp.tar.xz "$BINARY_URL/comp.tar.xz" "$COMP_SHA" \ +download comp.tar.xz "$BINARY_URL-comp.tar.xz" "$COMP_SHA" \ tar xJf comp.tar.xz -C /x-tools/x86_64-unknown-netbsd/sysroot ./usr/include ./usr/lib cd usr/src diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index 9234c6dc921ee..b32fa6c8e4eef 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -41,8 +41,6 @@ COPY host-x86_64/mingw-check/check-default-config-profiles.sh /scripts/ COPY host-x86_64/mingw-check/validate-toolstate.sh /scripts/ COPY host-x86_64/mingw-check/validate-error-codes.sh /scripts/ -ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 - # Check library crates on all tier 1 targets. # We disable optimized compiler built-ins because that requires a C toolchain for the target. # We also skip the x86_64-unknown-linux-gnu target as it is well-tested by other jobs. diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index 292dbfd20a509..b97568b081980 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -30,7 +30,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUSTBUILD_FORCE_CLANG_BASED_TESTS 1 -ENV RUN_CHECK_WITH_PARALLEL_QUERIES 1 # llvm.use-linker conflicts with downloading CI LLVM ENV NO_DOWNLOAD_CI_LLVM 1 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile index 0a58f337d9ddb..aefc0f376f689 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-18/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:24.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ + bzip2 \ g++ \ gcc-multilib \ make \ @@ -55,9 +56,6 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.thin-lto-import-instr-limit=10 COPY scripts/shared.sh /scripts/ -COPY scripts/build-gccjit.sh /scripts/ - -RUN /scripts/build-gccjit.sh /scripts ARG SCRIPT_ARG diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile index 092847cdfe04c..e0ed2e227f810 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile @@ -55,9 +55,6 @@ ENV RUST_CONFIGURE_ARGS \ --set rust.thin-lto-import-instr-limit=10 COPY scripts/shared.sh /scripts/ -COPY scripts/build-gccjit.sh /scripts/ - -RUN /scripts/build-gccjit.sh /scripts ARG SCRIPT_ARG diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index ab749b3fdd5a6..89806634c6c26 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -90,9 +90,6 @@ ENV HOST_TARGET x86_64-unknown-linux-gnu #ENV FORCE_CI_RUSTC 1 COPY scripts/shared.sh /scripts/ -COPY scripts/build-gccjit.sh /scripts/ - -RUN /scripts/build-gccjit.sh /scripts # For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries # to create a new folder. For reference: 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 a158e5b6253cd..3428dd4826a73 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.20.2 \ No newline at end of file +0.20.3 \ No newline at end of file diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index 6658b83efc8d2..2805bb1118d82 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -361,6 +361,7 @@ docker \ --env TOOLSTATE_PUBLISH \ --env RUST_CI_OVERRIDE_RELEASE_CHANNEL \ --env CI_JOB_NAME="${CI_JOB_NAME-$IMAGE}" \ + --env CI_JOB_DOC_URL="${CI_JOB_DOC_URL}" \ --env BASE_COMMIT="$BASE_COMMIT" \ --env DIST_TRY_BUILD \ --env PR_CI_JOB \ diff --git a/src/ci/docker/scripts/build-clang.sh b/src/ci/docker/scripts/build-clang.sh index 841a0adb2ab8c..536991cc06b7d 100755 --- a/src/ci/docker/scripts/build-clang.sh +++ b/src/ci/docker/scripts/build-clang.sh @@ -5,7 +5,7 @@ set -ex source shared.sh # Try to keep the LLVM version here in sync with src/ci/scripts/install-clang.sh -LLVM=llvmorg-19.1.0-rc3 +LLVM=llvmorg-20.1.0-rc2 mkdir llvm-project cd llvm-project diff --git a/src/ci/docker/scripts/build-gccjit.sh b/src/ci/docker/scripts/build-gccjit.sh deleted file mode 100755 index 43ed2270d313f..0000000000000 --- a/src/ci/docker/scripts/build-gccjit.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -GIT_REPO="https://github.com/rust-lang/gcc" - -# This commit hash needs to be updated to use a more recent gcc fork version. -GIT_COMMIT="45648c2edd4ecd862d9f08196d3d6c6ccba79f07" - -set -ex - -cd $1 - -source shared.sh - -# Setting up folders for GCC -curl -L "$GIT_REPO/archive/$GIT_COMMIT.tar.gz" | - tar -xz --transform "s/gcc-$GIT_COMMIT/gcc-src/" - -mkdir gcc-build gcc-install -pushd gcc-build - -# Building GCC. -hide_output \ - ../gcc-src/configure \ - --enable-host-shared \ - --enable-languages=jit \ - --enable-checking=release \ - --disable-bootstrap \ - --disable-multilib \ - --prefix=$(pwd)/../gcc-install \ - -hide_output make -j$(nproc) -hide_output make install - -popd -rm -rf gcc-src gcc-build -ln -s /scripts/gcc-install/lib/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so -ln -s /scripts/gcc-install/lib/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so.0 diff --git a/src/ci/docker/scripts/rfl-build.sh b/src/ci/docker/scripts/rfl-build.sh index 573821c3e59cd..ea8066d95e028 100755 --- a/src/ci/docker/scripts/rfl-build.sh +++ b/src/ci/docker/scripts/rfl-build.sh @@ -8,16 +8,10 @@ LINUX_VERSION=v6.14-rc3 ../x.py build --stage 2 library rustdoc clippy rustfmt ../x.py build --stage 0 cargo -# Install rustup so that we can use the built toolchain easily, and also -# install bindgen in an easy way. -curl --proto '=https' --tlsv1.2 -sSf -o rustup.sh https://sh.rustup.rs -sh rustup.sh -y --default-toolchain none +BUILD_DIR=$(realpath ./build/x86_64-unknown-linux-gnu) -source /cargo/env - -BUILD_DIR=$(realpath ./build) -rustup toolchain link local "${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage2 -rustup default local +# Provide path to rustc, rustdoc, clippy-driver and rustfmt to RfL +export PATH=${PATH}:${BUILD_DIR}/stage2/bin mkdir -p rfl cd rfl @@ -33,10 +27,14 @@ git -C linux fetch --depth 1 origin ${LINUX_VERSION} git -C linux checkout FETCH_HEAD # Install bindgen -"${BUILD_DIR}"/x86_64-unknown-linux-gnu/stage0/bin/cargo install \ +"${BUILD_DIR}"/stage0/bin/cargo install \ --version $(linux/scripts/min-tool-version.sh bindgen) \ + --root ${BUILD_DIR}/bindgen \ bindgen-cli +# Provide path to bindgen to RfL +export PATH=${PATH}:${BUILD_DIR}/bindgen/bin + # Configure Rust for Linux cat < linux/kernel/configs/rfl-for-rust-ci.config # CONFIG_WERROR is not set diff --git a/src/ci/docker/scripts/sccache.sh b/src/ci/docker/scripts/sccache.sh index f66671c64d25c..dba617d8bc80d 100644 --- a/src/ci/docker/scripts/sccache.sh +++ b/src/ci/docker/scripts/sccache.sh @@ -6,10 +6,10 @@ set -ex case "$(uname -m)" in x86_64) - url="https://ci-mirrors.rust-lang.org/rustc/2025-01-07-sccache-v0.9.1-x86_64-unknown-linux-musl" + url="https://ci-mirrors.rust-lang.org/rustc/2025-02-24-sccache-v0.10.0-x86_64-unknown-linux-musl" ;; aarch64) - url="https://ci-mirrors.rust-lang.org/rustc/2025-01-07-sccache-v0.9.1-aarch64-unknown-linux-musl" + url="https://ci-mirrors.rust-lang.org/rustc/2025-02-24-sccache-v0.10.0-aarch64-unknown-linux-musl" ;; *) echo "unsupported architecture: $(uname -m)" diff --git a/src/ci/github-actions/ci.py b/src/ci/github-actions/ci.py deleted file mode 100755 index c93766ef33a0d..0000000000000 --- a/src/ci/github-actions/ci.py +++ /dev/null @@ -1,318 +0,0 @@ -#!/usr/bin/env python3 - -""" -This script contains CI functionality. -It can be used to generate a matrix of jobs that should -be executed on CI, or run a specific CI job locally. - -It reads job definitions from `src/ci/github-actions/jobs.yml`. -""" - -import argparse -import dataclasses -import json -import logging -import os -import re -import subprocess -import typing -from pathlib import Path -from typing import List, Dict, Any, Optional - -import yaml - -CI_DIR = Path(__file__).absolute().parent.parent -JOBS_YAML_PATH = Path(__file__).absolute().parent / "jobs.yml" - -Job = Dict[str, Any] - - -def add_job_properties(jobs: List[Dict], prefix: str) -> List[Job]: - """ - Modify the `name` attribute of each job, based on its base name and the given `prefix`. - Add an `image` attribute to each job, based on its image. - """ - modified_jobs = [] - for job in jobs: - # Create a copy of the `job` dictionary to avoid modifying `jobs` - new_job = dict(job) - new_job["image"] = get_job_image(new_job) - new_job["full_name"] = f"{prefix} - {new_job['name']}" - modified_jobs.append(new_job) - return modified_jobs - - -def add_base_env(jobs: List[Job], environment: Dict[str, str]) -> List[Job]: - """ - Prepends `environment` to the `env` attribute of each job. - The `env` of each job has higher precedence than `environment`. - """ - modified_jobs = [] - for job in jobs: - env = environment.copy() - env.update(job.get("env", {})) - - new_job = dict(job) - new_job["env"] = env - modified_jobs.append(new_job) - return modified_jobs - - -@dataclasses.dataclass -class PRRunType: - pass - - -@dataclasses.dataclass -class TryRunType: - custom_jobs: List[str] - - -@dataclasses.dataclass -class AutoRunType: - pass - - -WorkflowRunType = typing.Union[PRRunType, TryRunType, AutoRunType] - - -@dataclasses.dataclass -class GitHubCtx: - event_name: str - ref: str - repository: str - commit_message: Optional[str] - - -def get_custom_jobs(ctx: GitHubCtx) -> List[str]: - """ - Tries to parse names of specific CI jobs that should be executed in the form of - try-job: - from the commit message of the passed GitHub context. - """ - if ctx.commit_message is None: - return [] - - regex = re.compile(r"^try-job: (.*)", re.MULTILINE) - jobs = [] - for match in regex.finditer(ctx.commit_message): - jobs.append(match.group(1)) - return jobs - - -def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]: - if ctx.event_name == "pull_request": - return PRRunType() - elif ctx.event_name == "push": - try_build = ctx.ref in ( - "refs/heads/try", - "refs/heads/try-perf", - "refs/heads/automation/bors/try", - ) - - # Unrolled branch from a rollup for testing perf - # This should **not** allow custom try jobs - is_unrolled_perf_build = ctx.ref == "refs/heads/try-perf" - - if try_build: - custom_jobs = [] - if not is_unrolled_perf_build: - custom_jobs = get_custom_jobs(ctx) - return TryRunType(custom_jobs=custom_jobs) - - if ctx.ref == "refs/heads/auto": - return AutoRunType() - - return None - - -def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]: - if isinstance(run_type, PRRunType): - return add_base_env( - add_job_properties(job_data["pr"], "PR"), job_data["envs"]["pr"] - ) - elif isinstance(run_type, TryRunType): - jobs = job_data["try"] - custom_jobs = run_type.custom_jobs - if custom_jobs: - if len(custom_jobs) > 10: - raise Exception( - f"It is only possible to schedule up to 10 custom jobs, " - f"received {len(custom_jobs)} jobs" - ) - - jobs = [] - unknown_jobs = [] - for custom_job in custom_jobs: - job = [j for j in job_data["auto"] if j["name"] == custom_job] - if not job: - unknown_jobs.append(custom_job) - continue - jobs.append(job[0]) - if unknown_jobs: - raise Exception( - f"Custom job(s) `{unknown_jobs}` not found in auto jobs" - ) - - return add_base_env(add_job_properties(jobs, "try"), job_data["envs"]["try"]) - elif isinstance(run_type, AutoRunType): - return add_base_env( - add_job_properties(job_data["auto"], "auto"), job_data["envs"]["auto"] - ) - - return [] - - -def skip_jobs(jobs: List[Dict[str, Any]], channel: str) -> List[Job]: - """ - Skip CI jobs that are not supposed to be executed on the given `channel`. - """ - return [j for j in jobs if j.get("only_on_channel", channel) == channel] - - -def get_github_ctx() -> GitHubCtx: - event_name = os.environ["GITHUB_EVENT_NAME"] - - commit_message = None - if event_name == "push": - commit_message = os.environ["COMMIT_MESSAGE"] - return GitHubCtx( - event_name=event_name, - ref=os.environ["GITHUB_REF"], - repository=os.environ["GITHUB_REPOSITORY"], - commit_message=commit_message, - ) - - -def format_run_type(run_type: WorkflowRunType) -> str: - if isinstance(run_type, PRRunType): - return "pr" - elif isinstance(run_type, AutoRunType): - return "auto" - elif isinstance(run_type, TryRunType): - return "try" - else: - raise AssertionError() - - -def get_job_image(job: Job) -> str: - """ - By default, the Docker image of a job is based on its name. - However, it can be overridden by its IMAGE environment variable. - """ - env = job.get("env", {}) - # Return the IMAGE environment variable if it exists, otherwise return the job name - return env.get("IMAGE", job["name"]) - - -def is_linux_job(job: Job) -> bool: - return "ubuntu" in job["os"] - - -def find_linux_job(job_data: Dict[str, Any], job_name: str, pr_jobs: bool) -> Job: - candidates = job_data["pr"] if pr_jobs else job_data["auto"] - jobs = [job for job in candidates if job.get("name") == job_name] - if len(jobs) == 0: - available_jobs = "\n".join( - sorted(job["name"] for job in candidates if is_linux_job(job)) - ) - raise Exception(f"""Job `{job_name}` not found in {'pr' if pr_jobs else 'auto'} jobs. -The following jobs are available: -{available_jobs}""") - assert len(jobs) == 1 - - job = jobs[0] - if not is_linux_job(job): - raise Exception("Only Linux jobs can be executed locally") - return job - - -def run_workflow_locally(job_data: Dict[str, Any], job_name: str, pr_jobs: bool): - DOCKER_DIR = Path(__file__).absolute().parent.parent / "docker" - - job = find_linux_job(job_data, job_name=job_name, pr_jobs=pr_jobs) - - custom_env = {} - # Replicate src/ci/scripts/setup-environment.sh - # Adds custom environment variables to the job - if job_name.startswith("dist-"): - if job_name.endswith("-alt"): - custom_env["DEPLOY_ALT"] = "1" - else: - custom_env["DEPLOY"] = "1" - custom_env.update({k: str(v) for (k, v) in job.get("env", {}).items()}) - - args = [str(DOCKER_DIR / "run.sh"), get_job_image(job)] - env_formatted = [f"{k}={v}" for (k, v) in sorted(custom_env.items())] - print(f"Executing `{' '.join(env_formatted)} {' '.join(args)}`") - - env = os.environ.copy() - env.update(custom_env) - - subprocess.run(args, env=env, check=True) - - -def calculate_job_matrix(job_data: Dict[str, Any]): - github_ctx = get_github_ctx() - - run_type = find_run_type(github_ctx) - logging.info(f"Job type: {run_type}") - - with open(CI_DIR / "channel") as f: - channel = f.read().strip() - - jobs = [] - if run_type is not None: - jobs = calculate_jobs(run_type, job_data) - jobs = skip_jobs(jobs, channel) - - if not jobs: - raise Exception("Scheduled job list is empty, this is an error") - - run_type = format_run_type(run_type) - - logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}") - print(f"jobs={json.dumps(jobs)}") - print(f"run_type={run_type}") - - -def create_cli_parser(): - parser = argparse.ArgumentParser( - prog="ci.py", description="Generate or run CI workflows" - ) - subparsers = parser.add_subparsers( - help="Command to execute", dest="command", required=True - ) - subparsers.add_parser( - "calculate-job-matrix", - help="Generate a matrix of jobs that should be executed in CI", - ) - run_parser = subparsers.add_parser( - "run-local", help="Run a CI jobs locally (on Linux)" - ) - run_parser.add_argument( - "job_name", - help="CI job that should be executed. By default, a merge (auto) " - "job with the given name will be executed", - ) - run_parser.add_argument( - "--pr", action="store_true", help="Run a PR job instead of an auto job" - ) - return parser - - -if __name__ == "__main__": - logging.basicConfig(level=logging.INFO) - - with open(JOBS_YAML_PATH) as f: - data = yaml.safe_load(f) - - parser = create_cli_parser() - args = parser.parse_args() - - if args.command == "calculate-job-matrix": - calculate_job_matrix(data) - elif args.command == "run-local": - run_workflow_locally(data, args.job_name, args.pr) - else: - raise Exception(f"Unknown command {args.command}") diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 64e64867de26f..d8c3625af2861 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -51,9 +51,11 @@ runners: # Free some disk space to avoid running out of space during the build. free_disk: true os: ubuntu-24.04-arm + <<: *base-job - &job-aarch64-linux-8c - os: ubuntu-22.04-arm64-8core-32gb + os: ubuntu-24.04-arm64-8core-32gb + <<: *base-job envs: env-x86_64-apple-tests: &env-x86_64-apple-tests SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc -- --exact @@ -265,11 +267,13 @@ auto: # nightly features to compile, and this job would fail if # executed on beta and stable. only_on_channel: nightly + doc_url: https://rustc-dev-guide.rust-lang.org/tests/fuchsia.html <<: *job-linux-8c # Tests integration with Rust for Linux. # Builds stage 1 compiler and tries to compile a few RfL examples with it. - name: x86_64-rust-for-linux + doc_url: https://rustc-dev-guide.rust-lang.org/tests/rust-for-linux.html <<: *job-linux-4c - name: x86_64-gnu @@ -589,7 +593,7 @@ auto: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc --host=i686-pc-windows-msvc - --target=i686-pc-windows-msvc,i586-pc-windows-msvc + --target=i686-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist bootstrap --include-default-paths diff --git a/src/ci/package-lock.json b/src/ci/package-lock.json deleted file mode 100644 index 6bbdc6adcfd31..0000000000000 --- a/src/ci/package-lock.json +++ /dev/null @@ -1,5004 +0,0 @@ -{ - "name": "ci", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "dependencies": { - "@datadog/datadog-ci": "^2.45.1" - } - }, - "node_modules/@aws-crypto/crc32": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", - "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch-logs": { - "version": "3.703.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cloudwatch-logs/-/client-cloudwatch-logs-3.703.0.tgz", - "integrity": "sha512-KkLMwrNhkLZr3OCRWakJY16OF8pUZCoexxZkWzHfR/Pw3WBcDtBMEiEO13P6oHlGAn1VvIDxxMBSxeg/89xyJA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/client-sts": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/eventstream-serde-browser": "^3.0.13", - "@smithy/eventstream-serde-config-resolver": "^3.0.10", - "@smithy/eventstream-serde-node": "^3.0.12", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-cloudwatch-logs/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.699.0.tgz", - "integrity": "sha512-9tFt+we6AIvj/f1+nrLHuCWcQmyfux5gcBSOy9d9+zIG56YxGEX7S9TaZnybogpVV8A0BYWml36WvIHS9QjIpA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/client-sts": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-cognito-identity/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-iam": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-iam/-/client-iam-3.699.0.tgz", - "integrity": "sha512-JBVcmkGaV7tW/mEntqt6KdkhsyYU2oIMUbkNHJextKqu6odSkuB1mN70TgctwFP8x2LDgFzvT6WcWVCKc/g3Ng==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/client-sts": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.9", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-iam/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.699.0.tgz", - "integrity": "sha512-K9TGvQB8hkjwNhfWSfYllUpttqxTcd78ShSRCIhlcwzzsmQphET10xEb0Tm1k8sqriSQ+CiVOFSkX78gqoHzBg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/client-sts": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/eventstream-serde-browser": "^3.0.13", - "@smithy/eventstream-serde-config-resolver": "^3.0.10", - "@smithy/eventstream-serde-node": "^3.0.12", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-stream": "^3.3.1", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.1.9", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-lambda/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sfn": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sfn/-/client-sfn-3.699.0.tgz", - "integrity": "sha512-66/+rOMVvjKRhKDDsrxtfRzXXsAfVu/RbhxPYepcVhO+0/ii6DL2uQCeNhMN3+MPg+HWX695H5RyBVJ6QGli8w==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/client-sts": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", - "@types/uuid": "^9.0.1", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sfn/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.696.0.tgz", - "integrity": "sha512-q5TTkd08JS0DOkHfUL853tuArf7NrPeqoS5UOvqJho8ibV9Ak/a/HO4kNvy9Nj3cib/toHYHsQIEtecUPSUUrQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.699.0.tgz", - "integrity": "sha512-u8a1GorY5D1l+4FQAf4XBUC1T10/t7neuwT21r0ymrtMFSK2a9QqVHKMoLkvavAwyhJnARSBM9/UQC797PFOFw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.699.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.699.0.tgz", - "integrity": "sha512-++lsn4x2YXsZPIzFVwv3fSUVM55ZT0WRFmPeNilYIhZClxHLmVAWKH4I55cY9ry60/aTKYjzOXkWwyBKGsGvQg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/client-sso-oidc": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/middleware-host-header": "3.696.0", - "@aws-sdk/middleware-logger": "3.696.0", - "@aws-sdk/middleware-recursion-detection": "3.696.0", - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/region-config-resolver": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@aws-sdk/util-user-agent-browser": "3.696.0", - "@aws-sdk/util-user-agent-node": "3.696.0", - "@smithy/config-resolver": "^3.0.12", - "@smithy/core": "^2.5.3", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/hash-node": "^3.0.10", - "@smithy/invalid-dependency": "^3.0.10", - "@smithy/middleware-content-length": "^3.0.12", - "@smithy/middleware-endpoint": "^3.2.3", - "@smithy/middleware-retry": "^3.0.27", - "@smithy/middleware-serde": "^3.0.10", - "@smithy/middleware-stack": "^3.0.10", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/url-parser": "^3.0.10", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.27", - "@smithy/util-defaults-mode-node": "^3.0.27", - "@smithy/util-endpoints": "^2.1.6", - "@smithy/util-middleware": "^3.0.10", - "@smithy/util-retry": "^3.0.10", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.696.0.tgz", - "integrity": "sha512-3c9III1k03DgvRZWg8vhVmfIXPG6hAciN9MzQTzqGngzWAELZF/WONRTRQuDFixVtarQatmLHYVw/atGeA2Byw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/core": "^2.5.3", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/property-provider": "^3.1.9", - "@smithy/protocol-http": "^4.1.7", - "@smithy/signature-v4": "^4.2.2", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/util-middleware": "^3.0.10", - "fast-xml-parser": "4.4.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core/node_modules/fast-xml-parser": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", - "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - } - ], - "license": "MIT", - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.699.0.tgz", - "integrity": "sha512-iuaTnudaBfEET+o444sDwf71Awe6UiZfH+ipUPmswAi2jZDwdFF1nxMKDEKL8/LV5WpXsdKSfwgS0RQeupURew==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.699.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.696.0.tgz", - "integrity": "sha512-T9iMFnJL7YTlESLpVFT3fg1Lkb1lD+oiaIC8KMpepb01gDUBIpj9+Y+pA/cgRWW0yRxmkDXNazAE2qQTVFGJzA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.696.0.tgz", - "integrity": "sha512-GV6EbvPi2eq1+WgY/o2RFA3P7HGmnkIzCNmhwtALFlqMroLYWKE7PSeHw66Uh1dFQeVESn0/+hiUNhu1mB0emA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/fetch-http-handler": "^4.1.1", - "@smithy/node-http-handler": "^3.3.1", - "@smithy/property-provider": "^3.1.9", - "@smithy/protocol-http": "^4.1.7", - "@smithy/smithy-client": "^3.4.4", - "@smithy/types": "^3.7.1", - "@smithy/util-stream": "^3.3.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.699.0.tgz", - "integrity": "sha512-dXmCqjJnKmG37Q+nLjPVu22mNkrGHY8hYoOt3Jo9R2zr5MYV7s/NHsCHr+7E+BZ+tfZYLRPeB1wkpTeHiEcdRw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-env": "3.696.0", - "@aws-sdk/credential-provider-http": "3.696.0", - "@aws-sdk/credential-provider-process": "3.696.0", - "@aws-sdk/credential-provider-sso": "3.699.0", - "@aws-sdk/credential-provider-web-identity": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/credential-provider-imds": "^3.2.6", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.699.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.699.0.tgz", - "integrity": "sha512-MmEmNDo1bBtTgRmdNfdQksXu4uXe66s0p1hi1YPrn1h59Q605eq/xiWbGL6/3KdkViH6eGUuABeV2ODld86ylg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.696.0", - "@aws-sdk/credential-provider-http": "3.696.0", - "@aws-sdk/credential-provider-ini": "3.699.0", - "@aws-sdk/credential-provider-process": "3.696.0", - "@aws-sdk/credential-provider-sso": "3.699.0", - "@aws-sdk/credential-provider-web-identity": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/credential-provider-imds": "^3.2.6", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.696.0.tgz", - "integrity": "sha512-mL1RcFDe9sfmyU5K1nuFkO8UiJXXxLX4JO1gVaDIOvPqwStpUAwi3A1BoeZhWZZNQsiKI810RnYGo0E0WB/hUA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.699.0.tgz", - "integrity": "sha512-Ekp2cZG4pl9D8+uKWm4qO1xcm8/MeiI8f+dnlZm8aQzizeC+aXYy9GyoclSf6daK8KfRPiRfM7ZHBBL5dAfdMA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-sso": "3.696.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/token-providers": "3.699.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.696.0.tgz", - "integrity": "sha512-XJ/CVlWChM0VCoc259vWguFUjJDn/QwDqHwbx+K9cg3v6yrqXfK5ai+p/6lx0nQpnk4JzPVeYYxWRpaTsGC9rg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.696.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.699.0.tgz", - "integrity": "sha512-jBjOntl9zN9Nvb0jmbMGRbiTzemDz64ij7W6BDavxBJRZpRoNeN0QCz6RolkCyXnyUJjo5mF2unY2wnv00A+LQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cognito-identity": "3.699.0", - "@aws-sdk/client-sso": "3.696.0", - "@aws-sdk/client-sts": "3.699.0", - "@aws-sdk/core": "3.696.0", - "@aws-sdk/credential-provider-cognito-identity": "3.699.0", - "@aws-sdk/credential-provider-env": "3.696.0", - "@aws-sdk/credential-provider-http": "3.696.0", - "@aws-sdk/credential-provider-ini": "3.699.0", - "@aws-sdk/credential-provider-node": "3.699.0", - "@aws-sdk/credential-provider-process": "3.696.0", - "@aws-sdk/credential-provider-sso": "3.699.0", - "@aws-sdk/credential-provider-web-identity": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/credential-provider-imds": "^3.2.6", - "@smithy/property-provider": "^3.1.9", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-providers/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.696.0.tgz", - "integrity": "sha512-zELJp9Ta2zkX7ELggMN9qMCgekqZhFC5V2rOr4hJDEb/Tte7gpfKSObAnw/3AYiVqt36sjHKfdkoTsuwGdEoDg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.696.0.tgz", - "integrity": "sha512-KhkHt+8AjCxcR/5Zp3++YPJPpFQzxpr+jmONiT/Jw2yqnSngZ0Yspm5wGoRx2hS1HJbyZNuaOWEGuJoxLeBKfA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.696.0.tgz", - "integrity": "sha512-si/maV3Z0hH7qa99f9ru2xpS5HlfSVcasRlNUXKSDm611i7jFMWwGNLUOXFAOLhXotPX5G3Z6BLwL34oDeBMug==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.696.0.tgz", - "integrity": "sha512-Lvyj8CTyxrHI6GHd2YVZKIRI5Fmnugt3cpJo0VrKKEgK5zMySwEZ1n4dqPK6czYRWKd5+WnYHYAuU+Wdk6Jsjw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@aws-sdk/util-endpoints": "3.696.0", - "@smithy/core": "^2.5.3", - "@smithy/protocol-http": "^4.1.7", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.696.0.tgz", - "integrity": "sha512-7EuH142lBXjI8yH6dVS/CZeiK/WZsmb/8zP6bQbVYpMrppSTgB3MzZZdxVZGzL5r8zPQOU10wLC4kIMy0qdBVQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/types": "^3.7.1", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.10", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.699.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.699.0.tgz", - "integrity": "sha512-kuiEW9DWs7fNos/SM+y58HCPhcIzm1nEZLhe2/7/6+TvAYLuEWURYsbK48gzsxXlaJ2k/jGY3nIsA7RptbMOwA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/property-provider": "^3.1.9", - "@smithy/shared-ini-file-loader": "^3.1.10", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.699.0" - } - }, - "node_modules/@aws-sdk/token-providers/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.696.0.tgz", - "integrity": "sha512-9rTvUJIAj5d3//U5FDPWGJ1nFJLuWb30vugGOrWk7aNZ6y9tuA3PI7Cc9dP8WEXKVyK1vuuk8rSFP2iqXnlgrw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.696.0.tgz", - "integrity": "sha512-T5s0IlBVX+gkb9g/I6CLt4yAZVzMSiGnbUqWihWsHvQR1WOoIcndQy/Oz/IJXT9T2ipoy7a80gzV6a5mglrioA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", - "@smithy/util-endpoints": "^2.1.6", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.693.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.693.0.tgz", - "integrity": "sha512-ttrag6haJLWABhLqtg1Uf+4LgHWIMOVSYL+VYZmAp2v4PUGOwWmWQH0Zk8RM7YuQcLfH/EoR72/Yxz6A4FKcuw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.696.0.tgz", - "integrity": "sha512-Z5rVNDdmPOe6ELoM5AhF/ja5tSjbe6ctSctDPb0JdDf4dT0v2MfwhJKzXju2RzX8Es/77Glh7MlaXLE0kCB9+Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "3.696.0", - "@smithy/types": "^3.7.1", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.696.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.696.0.tgz", - "integrity": "sha512-KhKqcfyXIB0SCCt+qsu4eJjsfiOrNzK5dCV7RAW2YIpp+msxGUUX0NdRE9rkzjiv+3EMktgJm3eEIS+yxtlVdQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/middleware-user-agent": "3.696.0", - "@aws-sdk/types": "3.696.0", - "@smithy/node-config-provider": "^3.1.11", - "@smithy/types": "^3.7.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "node_modules/@datadog/datadog-ci": { - "version": "2.45.1", - "resolved": "https://registry.npmjs.org/@datadog/datadog-ci/-/datadog-ci-2.45.1.tgz", - "integrity": "sha512-na4c4UuhT2jGFTOh+/uUVGR0CVj7c2B6Q7pRp9AMxb6NF2o3McjnSFJzmVc7YFdZwr+eHXeKXKf6bEYw/PjNWw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/client-cloudwatch-logs": "^3.624.0", - "@aws-sdk/client-iam": "^3.624.0", - "@aws-sdk/client-lambda": "^3.624.0", - "@aws-sdk/client-sfn": "^3.624.0", - "@aws-sdk/core": "^3.624.0", - "@aws-sdk/credential-provider-ini": "^3.624.0", - "@aws-sdk/credential-providers": "^3.624.0", - "@google-cloud/logging": "^11.1.0", - "@google-cloud/run": "^1.4.0", - "@smithy/property-provider": "^2.0.12", - "@smithy/util-retry": "^2.0.4", - "@types/datadog-metrics": "0.6.1", - "ajv": "^8.12.0", - "ajv-formats": "^2.1.1", - "async-retry": "1.3.1", - "axios": "^1.7.4", - "chalk": "3.0.0", - "clipanion": "^3.2.1", - "datadog-metrics": "0.9.3", - "deep-extend": "0.6.0", - "deep-object-diff": "^1.1.9", - "fast-levenshtein": "^3.0.0", - "fast-xml-parser": "^4.4.1", - "form-data": "4.0.0", - "fuzzy": "^0.1.3", - "glob": "^7.1.4", - "google-auth-library": "^9.12.0", - "inquirer": "^8.2.5", - "inquirer-checkbox-plus-prompt": "^1.4.2", - "js-yaml": "3.13.1", - "jszip": "^3.10.1", - "ora": "5.4.1", - "proxy-agent": "^6.4.0", - "rimraf": "^3.0.2", - "semver": "^7.5.3", - "simple-git": "3.16.0", - "ssh2": "^1.15.0", - "ssh2-streams": "0.4.10", - "sshpk": "1.16.1", - "terminal-link": "2.1.1", - "tiny-async-pool": "^2.1.0", - "typanion": "^3.14.0", - "uuid": "^9.0.0", - "ws": "^7.5.10", - "xml2js": "0.5.0", - "yamux-js": "0.1.2" - }, - "bin": { - "datadog-ci": "dist/cli.js" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@google-cloud/common": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-5.0.2.tgz", - "integrity": "sha512-V7bmBKYQyu0eVG2BFejuUjlBt+zrya6vtsKdY+JxMM/dNntPF41vZ9+LhOshEUH01zOHEqBSvI7Dad7ZS6aUeA==", - "license": "Apache-2.0", - "dependencies": { - "@google-cloud/projectify": "^4.0.0", - "@google-cloud/promisify": "^4.0.0", - "arrify": "^2.0.1", - "duplexify": "^4.1.1", - "extend": "^3.0.2", - "google-auth-library": "^9.0.0", - "html-entities": "^2.5.2", - "retry-request": "^7.0.0", - "teeny-request": "^9.0.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@google-cloud/logging": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@google-cloud/logging/-/logging-11.2.0.tgz", - "integrity": "sha512-Ma94jvuoMpbgNniwtelOt8w82hxK62FuOXZonEv0Hyk3B+/YVuLG/SWNyY9yMso/RXnPEc1fP2qo9kDrjf/b2w==", - "license": "Apache-2.0", - "dependencies": { - "@google-cloud/common": "^5.0.0", - "@google-cloud/paginator": "^5.0.0", - "@google-cloud/projectify": "^4.0.0", - "@google-cloud/promisify": "^4.0.0", - "@opentelemetry/api": "^1.7.0", - "arrify": "^2.0.1", - "dot-prop": "^6.0.0", - "eventid": "^2.0.0", - "extend": "^3.0.2", - "gcp-metadata": "^6.0.0", - "google-auth-library": "^9.0.0", - "google-gax": "^4.0.3", - "on-finished": "^2.3.0", - "pumpify": "^2.0.1", - "stream-events": "^1.0.5", - "uuid": "^9.0.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@google-cloud/paginator": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-5.0.2.tgz", - "integrity": "sha512-DJS3s0OVH4zFDB1PzjxAsHqJT6sKVbRwwML0ZBP9PbU7Yebtu/7SWMRzvO2J3nUi9pRNITCfu4LJeooM2w4pjg==", - "license": "Apache-2.0", - "dependencies": { - "arrify": "^2.0.0", - "extend": "^3.0.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@google-cloud/projectify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-4.0.0.tgz", - "integrity": "sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@google-cloud/promisify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-4.0.0.tgz", - "integrity": "sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@google-cloud/run": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@google-cloud/run/-/run-1.5.0.tgz", - "integrity": "sha512-Ct0ZIuicd2O6fJHv7Lbwl4CcCWKK7NjACvUc4pOJVbKo75B5proOa7/9TrXVpI6oWu1n7EFx1s8xsavYHLxRAg==", - "license": "Apache-2.0", - "dependencies": { - "google-gax": "^4.0.3" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@grpc/grpc-js": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.12.4.tgz", - "integrity": "sha512-NBhrxEWnFh0FxeA0d//YP95lRFsSx2TNLEUQg4/W+5f/BMxcCjgOOIT24iD+ZB/tZw057j44DaIxja7w4XMrhg==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" - }, - "engines": { - "node": ">=12.10.0" - } - }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "license": "Apache-2.0", - "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/@kwsites/file-exists": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", - "license": "MIT", - "dependencies": { - "debug": "^4.1.1" - } - }, - "node_modules/@kwsites/file-exists/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@kwsites/file-exists/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", - "license": "MIT" - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" - }, - "node_modules/@smithy/abort-controller": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.9.tgz", - "integrity": "sha512-yiW0WI30zj8ZKoSYNx90no7ugVn3khlyH/z5W8qtKBtVE6awRALbhSG+2SAHA1r6bO/6M9utxYKVZ3PCJ1rWxw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.13.tgz", - "integrity": "sha512-Gr/qwzyPaTL1tZcq8WQyHhTZREER5R1Wytmz4WnVGL4onA3dNk6Btll55c8Vr58pLdvWZmtG8oZxJTw3t3q7Jg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^3.1.12", - "@smithy/types": "^3.7.2", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.11", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.5.5.tgz", - "integrity": "sha512-G8G/sDDhXA7o0bOvkc7bgai6POuSld/+XhNnWAbpQTpLv2OZPvyqQ58tLPPlz0bSNsXktldDDREIv1LczFeNEw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/middleware-serde": "^3.0.11", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-stream": "^3.3.2", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "3.2.8", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.8.tgz", - "integrity": "sha512-ZCY2yD0BY+K9iMXkkbnjo+08T2h8/34oHd0Jmh6BZUSZwaaGlGCyBT/3wnS7u7Xl33/EEfN4B6nQr3Gx5bYxgw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^3.1.12", - "@smithy/property-provider": "^3.1.11", - "@smithy/types": "^3.7.2", - "@smithy/url-parser": "^3.0.11", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/eventstream-codec": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.10.tgz", - "integrity": "sha512-323B8YckSbUH0nMIpXn7HZsAVKHYHFUODa8gG9cHo0ySvA1fr5iWaNT+iIL0UCqUzG6QPHA3BSsBtRQou4mMqQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/crc32": "5.2.0", - "@smithy/types": "^3.7.2", - "@smithy/util-hex-encoding": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/eventstream-serde-browser": { - "version": "3.0.14", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.14.tgz", - "integrity": "sha512-kbrt0vjOIihW3V7Cqj1SXQvAI5BR8SnyQYsandva0AOR307cXAc+IhPngxIPslxTLfxwDpNu0HzCAq6g42kCPg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^3.0.13", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-config-resolver": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.11.tgz", - "integrity": "sha512-P2pnEp4n75O+QHjyO7cbw/vsw5l93K/8EWyjNCAAybYwUmj3M+hjSQZ9P5TVdUgEG08ueMAP5R4FkuSkElZ5tQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-node": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.13.tgz", - "integrity": "sha512-zqy/9iwbj8Wysmvi7Lq7XFLeDgjRpTbCfwBhJa8WbrylTAHiAu6oQTwdY7iu2lxigbc9YYr9vPv5SzYny5tCXQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-serde-universal": "^3.0.13", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/eventstream-serde-universal": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.13.tgz", - "integrity": "sha512-L1Ib66+gg9uTnqp/18Gz4MDpJPKRE44geOjOQ2SVc0eiaO5l255ADziATZgjQjqumC7yPtp1XnjHlF1srcwjKw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/eventstream-codec": "^3.1.10", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.2.tgz", - "integrity": "sha512-R7rU7Ae3ItU4rC0c5mB2sP5mJNbCfoDc8I5XlYjIZnquyUwec7fEo78F6DA3SmgJgkU1qTMcZJuGblxZsl10ZA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^4.1.8", - "@smithy/querystring-builder": "^3.0.11", - "@smithy/types": "^3.7.2", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/hash-node": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.11.tgz", - "integrity": "sha512-emP23rwYyZhQBvklqTtwetkQlqbNYirDiEEwXl2v0GYWMnCzxst7ZaRAnWuy28njp5kAH54lvkdG37MblZzaHA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.11.tgz", - "integrity": "sha512-NuQmVPEJjUX6c+UELyVz8kUx8Q539EDeNwbRyu4IIF8MeV7hUtq1FB3SHVyki2u++5XLMFqngeMKk7ccspnNyQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.13.tgz", - "integrity": "sha512-zfMhzojhFpIX3P5ug7jxTjfUcIPcGjcQYzB9t+rv0g1TX7B0QdwONW+ATouaLoD7h7LOw/ZlXfkq4xJ/g2TrIw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.2.5.tgz", - "integrity": "sha512-VhJNs/s/lyx4weiZdXSloBgoLoS8osV0dKIain8nGmx7of3QFKu5BSdEuk1z/U8x9iwes1i+XCiNusEvuK1ijg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^2.5.5", - "@smithy/middleware-serde": "^3.0.11", - "@smithy/node-config-provider": "^3.1.12", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", - "@smithy/url-parser": "^3.0.11", - "@smithy/util-middleware": "^3.0.11", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "3.0.29", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.29.tgz", - "integrity": "sha512-/FfI/N2tIVCG9escHYLLABJlNHbO1gWFSdMlvbPOTV+Y+Aa8Q1FuS7Yaghb8NUfFmGYjkbeIu3bnbta6KbarsA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^3.1.12", - "@smithy/protocol-http": "^4.1.8", - "@smithy/service-error-classification": "^3.0.11", - "@smithy/smithy-client": "^3.4.6", - "@smithy/types": "^3.7.2", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-retry": "^3.0.11", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-retry/node_modules/@smithy/util-retry": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.11.tgz", - "integrity": "sha512-hJUC6W7A3DQgaee3Hp9ZFcOxVDZzmBIRBPlUAk8/fSOEl7pE/aX7Dci0JycNOnm9Mfr0KV2XjIlUOcGWXQUdVQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.11.tgz", - "integrity": "sha512-KzPAeySp/fOoQA82TpnwItvX8BBURecpx6ZMu75EZDkAcnPtO6vf7q4aH5QHs/F1s3/snQaSFbbUMcFFZ086Mw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.11.tgz", - "integrity": "sha512-1HGo9a6/ikgOMrTrWL/WiN9N8GSVYpuRQO5kjstAq4CvV59bjqnh7TbdXGQ4vxLD3xlSjfBjq5t1SOELePsLnA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.12.tgz", - "integrity": "sha512-O9LVEu5J/u/FuNlZs+L7Ikn3lz7VB9hb0GtPT9MQeiBmtK8RSY3ULmsZgXhe6VAlgTw0YO+paQx4p8xdbs43vQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^3.1.11", - "@smithy/shared-ini-file-loader": "^3.1.12", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-config-provider/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.3.2.tgz", - "integrity": "sha512-t4ng1DAd527vlxvOfKFYEe6/QFBcsj7WpNlWTyjorwXXcKw3XlltBGbyHfSJ24QT84nF+agDha9tNYpzmSRZPA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^3.1.9", - "@smithy/protocol-http": "^4.1.8", - "@smithy/querystring-builder": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.2.0.tgz", - "integrity": "sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/property-provider/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.8.tgz", - "integrity": "sha512-hmgIAVyxw1LySOwkgMIUN0kjN8TG9Nc85LJeEmEE/cNEe2rkHDUWhnJf2gxcSRFLWsyqWsrZGw40ROjUogg+Iw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.11.tgz", - "integrity": "sha512-u+5HV/9uJaeLj5XTb6+IEF/dokWWkEqJ0XiaRRogyREmKGUgZnNecLucADLdauWFKUNbQfulHFEZEdjwEBjXRg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.11.tgz", - "integrity": "sha512-Je3kFvCsFMnso1ilPwA7GtlbPaTixa3WwC+K21kmMZHsBEOZYQaqxcMqeFFoU7/slFjKDIpiiPydvdJm8Q/MCw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.11.tgz", - "integrity": "sha512-QnYDPkyewrJzCyaeI2Rmp7pDwbUETe+hU8ADkXmgNusO1bgHBH7ovXJiYmba8t0fNfJx75fE8dlM6SEmZxheog==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.1.12", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.12.tgz", - "integrity": "sha512-1xKSGI+U9KKdbG2qDvIR9dGrw3CNx+baqJfyr0igKEpjbHL5stsqAesYBzHChYHlelWtb87VnLWlhvfCz13H8Q==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.2.4.tgz", - "integrity": "sha512-5JWeMQYg81TgU4cG+OexAWdvDTs5JDdbEZx+Qr1iPbvo91QFGzjy0IkXAKaXUHqmKUJgSHK0ZxnCkgZpzkeNTA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.11", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "3.4.6", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.4.6.tgz", - "integrity": "sha512-j/WYdfzdx4asqb0YZch1rb6Y5OQcuTdXY7xnEMtc05diB5jfLQQtys9J/2lzmGKri9m9mUBrcnNTv3jbXvtk7A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^2.5.5", - "@smithy/middleware-endpoint": "^3.2.5", - "@smithy/middleware-stack": "^3.0.11", - "@smithy/protocol-http": "^4.1.8", - "@smithy/types": "^3.7.2", - "@smithy/util-stream": "^3.3.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.7.2.tgz", - "integrity": "sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.11.tgz", - "integrity": "sha512-TmlqXkSk8ZPhfc+SQutjmFr5FjC0av3GZP4B/10caK1SbRwe/v+Wzu/R6xEKxoNqL+8nY18s1byiy6HqPG37Aw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/querystring-parser": "^3.0.11", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.29", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.29.tgz", - "integrity": "sha512-7k0kOfDjnSM44GG74UnjEixtHmtF/do6pCNEvp1DQlFjktEz8pv06p9RSjxp2J3Lv6I3+Ba9FLfurpFeBv+Pvw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/property-provider": "^3.1.11", - "@smithy/smithy-client": "^3.4.6", - "@smithy/types": "^3.7.2", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.29", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.29.tgz", - "integrity": "sha512-lu8jaXAt1TIVkTAKMuGdZwWQ1L03iV/n8WPbY5hdjcNqLg2ysp5DqiINmtuLL8EgzDv1TXvKDaBAN+9bGH4sEQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/config-resolver": "^3.0.13", - "@smithy/credential-provider-imds": "^3.2.8", - "@smithy/node-config-provider": "^3.1.12", - "@smithy/property-provider": "^3.1.11", - "@smithy/smithy-client": "^3.4.6", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/property-provider": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.11.tgz", - "integrity": "sha512-I/+TMc4XTQ3QAjXfOcUWbSS073oOEAxgx4aZy8jHaf8JQnRkq2SZWw8+PfDtBvLUjcGMdxl+YwtzWe6i5uhL/A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.1.7.tgz", - "integrity": "sha512-tSfcqKcN/Oo2STEYCABVuKgJ76nyyr6skGl9t15hs+YaiU06sgMkN7QYjo0BbVw+KT26zok3IzbdSOksQ4YzVw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/node-config-provider": "^3.1.12", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.11.tgz", - "integrity": "sha512-dWpyc1e1R6VoXrwLoLDd57U1z6CwNSdkM69Ie4+6uYh2GC7Vg51Qtan7ITzczuVpqezdDTKJGJB95fFvvjU/ow==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.2.0.tgz", - "integrity": "sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/service-error-classification": "^2.1.5", - "@smithy/types": "^2.12.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@smithy/util-retry/node_modules/@smithy/service-error-classification": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.5.tgz", - "integrity": "sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^2.12.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-retry/node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-stream": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.2.tgz", - "integrity": "sha512-sInAqdiVeisUGYAv/FrXpmJ0b4WTFmciTRqzhb7wVuem9BHvhIG7tpiYHLDWrl2stOokNZpTTGqz3mzB2qFwXg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/fetch-http-handler": "^4.1.2", - "@smithy/node-http-handler": "^3.3.2", - "@smithy/types": "^3.7.2", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-waiter": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.2.0.tgz", - "integrity": "sha512-PpjSboaDUE6yl+1qlg3Si57++e84oXdWGbuFUSAciXsVfEZJJJupR2Nb0QuXHiunt2vGR+1PTizOMvnUPaG2Qg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/abort-controller": "^3.1.9", - "@smithy/types": "^3.7.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "license": "MIT" - }, - "node_modules/@types/caseless": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.5.tgz", - "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", - "license": "MIT" - }, - "node_modules/@types/datadog-metrics": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@types/datadog-metrics/-/datadog-metrics-0.6.1.tgz", - "integrity": "sha512-p6zVpfmNcXwtcXjgpz7do/fKyfndGhU5sGJVtb5Gn5PvLDiQUAgD0mI/itf/99sBi9DRxeyhFQ9dQF6OxxQNbA==", - "license": "MIT" - }, - "node_modules/@types/long": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.0" - } - }, - "node_modules/@types/request": { - "version": "2.48.12", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.12.tgz", - "integrity": "sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==", - "license": "MIT", - "dependencies": { - "@types/caseless": "*", - "@types/node": "*", - "@types/tough-cookie": "*", - "form-data": "^2.5.0" - } - }, - "node_modules/@types/request/node_modules/form-data": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.2.tgz", - "integrity": "sha512-GgwY0PS7DbXqajuGf4OYlsrIu3zgxD6Vvql43IBhm6MahqA5SK/7mwhtNj2AdH2z35YR34ujJ7BN+3fFC3jP5Q==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12", - "safe-buffer": "^5.2.1" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/@types/tough-cookie": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", - "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", - "license": "MIT" - }, - "node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "license": "MIT" - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/async-retry": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.1.tgz", - "integrity": "sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==", - "license": "MIT", - "dependencies": { - "retry": "0.12.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bowser": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/buildcheck": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", - "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==", - "optional": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "license": "MIT" - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "license": "ISC", - "engines": { - "node": ">= 10" - } - }, - "node_modules/clipanion": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/clipanion/-/clipanion-3.2.1.tgz", - "integrity": "sha512-dYFdjLb7y1ajfxQopN05mylEpK9ZX0sO1/RfMXdfmwjlIsPkbh4p7A682x++zFPLDCo1x3p82dtljHf5cW2LKA==", - "license": "MIT", - "workspaces": [ - "website" - ], - "dependencies": { - "typanion": "^3.8.0" - }, - "peerDependencies": { - "typanion": "*" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/cpu-features": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz", - "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "buildcheck": "~0.0.6", - "nan": "^2.19.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", - "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/datadog-metrics": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/datadog-metrics/-/datadog-metrics-0.9.3.tgz", - "integrity": "sha512-BVsBX2t+4yA3tHs7DnB5H01cHVNiGJ/bHA8y6JppJDyXG7s2DLm6JaozPGpgsgVGd42Is1CHRG/yMDQpt877Xg==", - "license": "MIT", - "dependencies": { - "debug": "3.1.0", - "dogapi": "2.8.4" - } - }, - "node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/deep-object-diff": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz", - "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==", - "license": "MIT" - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/degenerator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", - "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", - "license": "MIT", - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/dogapi": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/dogapi/-/dogapi-2.8.4.tgz", - "integrity": "sha512-065fsvu5dB0o4+ENtLjZILvXMClDNH/yA9H6L8nsdcNiz9l0Hzpn7aQaCOPYXxqyzq4CRPOdwkFXUjDOXfRGbg==", - "license": "MIT", - "dependencies": { - "extend": "^3.0.2", - "json-bigint": "^1.0.0", - "lodash": "^4.17.21", - "minimist": "^1.2.5", - "rc": "^1.2.8" - }, - "bin": { - "dogapi": "bin/dogapi" - } - }, - "node_modules/dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "license": "MIT", - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/duplexify": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", - "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.4.1", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1", - "stream-shift": "^1.0.2" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "license": "MIT", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/ecc-jsbn/node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "license": "MIT" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/eventid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/eventid/-/eventid-2.0.1.tgz", - "integrity": "sha512-sPNTqiMokAvV048P2c9+foqVJzk49o6d4e0D/sq5jog3pw+4kBgyR0gaM1FM7Mx6Kzd9dztesh9oYz1LWWOpzw==", - "license": "Apache-2.0", - "dependencies": { - "uuid": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/eventid/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz", - "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==", - "license": "MIT", - "dependencies": { - "fastest-levenshtein": "^1.0.7" - } - }, - "node_modules/fast-uri": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", - "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", - "license": "BSD-3-Clause" - }, - "node_modules/fast-xml-parser": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz", - "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/NaturalIntelligence" - }, - { - "type": "paypal", - "url": "https://paypal.me/naturalintelligence" - } - ], - "license": "MIT", - "dependencies": { - "strnum": "^1.0.5" - }, - "bin": { - "fxparser": "src/cli/cli.js" - } - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.16", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", - "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" - }, - "node_modules/fuzzy": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/fuzzy/-/fuzzy-0.1.3.tgz", - "integrity": "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/gaxios": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", - "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", - "license": "Apache-2.0", - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/gcp-metadata": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", - "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^6.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-uri": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", - "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", - "license": "MIT", - "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/get-uri/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/get-uri/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/google-auth-library": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.0.tgz", - "integrity": "sha512-7ccSEJFDFO7exFbO6NRyC+xH8/mZ1GZGG2xxx9iHxZWcjUjJpjWxIMw3cofAKcueZ6DATiukmmprD7yavQHOyQ==", - "license": "Apache-2.0", - "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^6.1.1", - "gcp-metadata": "^6.1.0", - "gtoken": "^7.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/google-gax": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-4.4.1.tgz", - "integrity": "sha512-Phyp9fMfA00J3sZbJxbbB4jC55b7DBjE3F6poyL3wKMEBVKA79q6BGuHcTiM28yOzVql0NDbRL8MLLh8Iwk9Dg==", - "license": "Apache-2.0", - "dependencies": { - "@grpc/grpc-js": "^1.10.9", - "@grpc/proto-loader": "^0.7.13", - "@types/long": "^4.0.0", - "abort-controller": "^3.0.0", - "duplexify": "^4.0.0", - "google-auth-library": "^9.3.0", - "node-fetch": "^2.7.0", - "object-hash": "^3.0.0", - "proto3-json-serializer": "^2.0.2", - "protobufjs": "^7.3.2", - "retry-request": "^7.0.0", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/gtoken": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", - "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", - "license": "MIT", - "dependencies": { - "gaxios": "^6.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/html-entities": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", - "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/mdevils" - }, - { - "type": "patreon", - "url": "https://patreon.com/mdevils" - } - ], - "license": "MIT" - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer-checkbox-plus-prompt": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/inquirer-checkbox-plus-prompt/-/inquirer-checkbox-plus-prompt-1.4.2.tgz", - "integrity": "sha512-W8/NL9x5A81Oq9ZfbYW5c1LuwtAhc/oB/u9YZZejna0pqrajj27XhnUHygJV0Vn5TvcDy1VJcD2Ld9kTk40dvg==", - "license": "MIT", - "dependencies": { - "chalk": "4.1.2", - "cli-cursor": "^3.1.0", - "figures": "^3.0.0", - "lodash": "^4.17.5", - "rxjs": "^6.6.7" - }, - "peerDependencies": { - "inquirer": "< 9.x" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/inquirer-checkbox-plus-prompt/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "license": "0BSD" - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" - }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/jszip": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", - "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", - "dependencies": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" - } - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/lie": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", - "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", - "dependencies": { - "immediate": "~3.0.5" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "license": "MIT" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "license": "MIT", - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", - "license": "Apache-2.0" - }, - "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "license": "ISC" - }, - "node_modules/nan": { - "version": "2.22.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", - "integrity": "sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==", - "license": "MIT", - "optional": true - }, - "node_modules/netmask": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", - "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "license": "MIT", - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pac-proxy-agent": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz", - "integrity": "sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw==", - "license": "MIT", - "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.6", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/pac-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "license": "MIT", - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/proto3-json-serializer": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/proto3-json-serializer/-/proto3-json-serializer-2.0.2.tgz", - "integrity": "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ==", - "license": "Apache-2.0", - "dependencies": { - "protobufjs": "^7.2.5" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/protobufjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", - "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/proxy-agent": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", - "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.6", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.1.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/pump": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", - "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", - "license": "MIT", - "dependencies": { - "duplexify": "^4.1.1", - "inherits": "^2.0.3", - "pump": "^3.0.0" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/retry-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-7.0.2.tgz", - "integrity": "sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==", - "license": "MIT", - "dependencies": { - "@types/request": "^2.48.8", - "extend": "^3.0.2", - "teeny-request": "^9.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/sax": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", - "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==", - "license": "ISC" - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/simple-git": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.16.0.tgz", - "integrity": "sha512-zuWYsOLEhbJRWVxpjdiXl6eyAyGo/KzVW+KFhhw9MqEEJttcq+32jTWSGyxTdf9e/YCohxRE+9xpWFj9FdiJNw==", - "license": "MIT", - "dependencies": { - "@kwsites/file-exists": "^1.1.1", - "@kwsites/promise-deferred": "^1.1.1", - "debug": "^4.3.4" - }, - "funding": { - "type": "github", - "url": "https://github.com/steveukx/git-js?sponsor=1" - } - }, - "node_modules/simple-git/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/simple-git/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", - "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socks-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "license": "BSD-3-Clause" - }, - "node_modules/ssh2": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.16.0.tgz", - "integrity": "sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==", - "hasInstallScript": true, - "dependencies": { - "asn1": "^0.2.6", - "bcrypt-pbkdf": "^1.0.2" - }, - "engines": { - "node": ">=10.16.0" - }, - "optionalDependencies": { - "cpu-features": "~0.0.10", - "nan": "^2.20.0" - } - }, - "node_modules/ssh2-streams": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/ssh2-streams/-/ssh2-streams-0.4.10.tgz", - "integrity": "sha512-8pnlMjvnIZJvmTzUIIA5nT4jr2ZWNNVHwyXfMGdRJbug9TpI3kd99ffglgfSWqujVv/0gxwMsDn9j9RVst8yhQ==", - "dependencies": { - "asn1": "~0.2.0", - "bcrypt-pbkdf": "^1.0.2", - "streamsearch": "~0.1.2" - }, - "engines": { - "node": ">=5.2.0" - } - }, - "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "license": "MIT", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sshpk/node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "license": "MIT" - }, - "node_modules/stream-events": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", - "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", - "license": "MIT", - "dependencies": { - "stubs": "^3.0.0" - } - }, - "node_modules/stream-shift": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", - "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", - "license": "MIT" - }, - "node_modules/streamsearch": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", - "integrity": "sha512-jos8u++JKm0ARcSUTAZXOVC0mSox7Bhn6sBgty73P1f3JGf7yG2clTbBNHUdde/kdvP2FESam+vM6l8jBrNxHA==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strnum": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "license": "MIT" - }, - "node_modules/stubs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", - "integrity": "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==", - "license": "MIT" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/teeny-request": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-9.0.0.tgz", - "integrity": "sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==", - "license": "Apache-2.0", - "dependencies": { - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.9", - "stream-events": "^1.0.5", - "uuid": "^9.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/teeny-request/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/teeny-request/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/teeny-request/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "license": "MIT", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/teeny-request/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/teeny-request/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "license": "MIT", - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "license": "MIT" - }, - "node_modules/tiny-async-pool": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-2.1.0.tgz", - "integrity": "sha512-ltAHPh/9k0STRQqaoUX52NH4ZQYAJz24ZAEwf1Zm+HYg3l9OXTWeqWKyYsHu40wF/F0rxd2N2bk5sLvX2qlSvg==", - "license": "MIT" - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "license": "Unlicense" - }, - "node_modules/typanion": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/typanion/-/typanion-3.14.0.tgz", - "integrity": "sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==", - "license": "MIT", - "workspaces": [ - "website" - ] - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "7.5.10", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", - "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "license": "MIT", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "license": "MIT", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yamux-js": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yamux-js/-/yamux-js-0.1.2.tgz", - "integrity": "sha512-bhsPlPZ9xB4Dawyf6nkS58u4F3IvGCaybkEKGnneUeepcI7MPoG3Tt6SaKCU5x/kP2/2w20Qm/GqbpwAM16vYw==", - "license": "MIT" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - } - } -} diff --git a/src/ci/package.json b/src/ci/package.json deleted file mode 100644 index 91f21e5531e77..0000000000000 --- a/src/ci/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "dependencies": { - "@datadog/datadog-ci": "^2.45.1" - } -} diff --git a/src/ci/run.sh b/src/ci/run.sh index 536754f12bc6d..63e79c737d6ad 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -6,6 +6,10 @@ if [ -n "$CI_JOB_NAME" ]; then echo "[CI_JOB_NAME=$CI_JOB_NAME]" fi +if [ -n "$CI_JOB_DOC_URL" ]; then + echo "[CI_JOB_DOC_URL=$CI_JOB_DOC_URL]" +fi + if [ "$NO_CHANGE_USER" = "" ]; then if [ "$LOCAL_USER_ID" != "" ]; then id -u user &>/dev/null || useradd --shell /bin/bash -u $LOCAL_USER_ID -o -c "" -m user @@ -54,13 +58,8 @@ if [ "$FORCE_CI_RUSTC" == "" ]; then DISABLE_CI_RUSTC_IF_INCOMPATIBLE=1 fi -if ! isCI || isCiBranch auto || isCiBranch beta || isCiBranch try || isCiBranch try-perf || \ - isCiBranch automation/bors/try; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests" - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics" - HAS_METRICS=1 -fi - +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests" +RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.metrics" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-verbose-configure" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache" RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules" @@ -261,23 +260,6 @@ else do_make "$RUST_CHECK_TARGET" fi -if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then - rm -f config.toml - $SRC/configure --set change-id=99999999 - - # Save the build metrics before we wipe the directory - if [ "$HAS_METRICS" = 1 ]; then - mv build/metrics.json . - fi - rm -rf build - if [ "$HAS_METRICS" = 1 ]; then - mkdir build - mv metrics.json build - fi - - CARGO_INCREMENTAL=0 ../x check -fi - echo "::group::sccache stats" sccache --show-adv-stats || true echo "::endgroup::" diff --git a/src/ci/scripts/install-sccache.sh b/src/ci/scripts/install-sccache.sh index e143152f330cf..b055e76a80504 100755 --- a/src/ci/scripts/install-sccache.sh +++ b/src/ci/scripts/install-sccache.sh @@ -8,11 +8,13 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isMacOS; then - curl -fo /usr/local/bin/sccache "${MIRRORS_BASE}/2021-08-25-sccache-v0.2.15-x86_64-apple-darwin" + curl -fo /usr/local/bin/sccache \ + "${MIRRORS_BASE}/2025-02-24-sccache-v0.10.0-x86_64-apple-darwin" chmod +x /usr/local/bin/sccache elif isWindows; then mkdir -p sccache - curl -fo sccache/sccache.exe "${MIRRORS_BASE}/2018-04-26-sccache-x86_64-pc-windows-msvc" + curl -fo sccache/sccache.exe \ + "${MIRRORS_BASE}/2025-02-24-sccache-v0.10.0-x86_64-pc-windows-msvc.exe" ciCommandAddPath "$(pwd)/sccache" fi diff --git a/src/ci/scripts/upload-build-metrics.py b/src/ci/scripts/upload-build-metrics.py deleted file mode 100644 index 915ba95398466..0000000000000 --- a/src/ci/scripts/upload-build-metrics.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -This script postprocesses data gathered during a CI run, computes certain metrics -from them, and uploads these metrics to DataDog. - -This script is expected to be executed from within a GitHub Actions job. - -It expects the following environment variables: -- DATADOG_SITE: path to the DataDog API endpoint -- DATADOG_API_KEY: DataDog API token -- DD_GITHUB_JOB_NAME: Name of the current GitHub Actions job - -It expects the presence of a binary called `datadog-ci` inside `node_modules`. -It can be installed with `npm ci` at `src/ci`. - -Usage: -```bash -$ python3 upload-build-metrics.py -``` - -`path-to-CPU-usage-CSV` is a path to a CSV generated by the `src/ci/cpu-usage-over-time.py` script. -""" - -import argparse -import csv -import os -import subprocess -import sys -from pathlib import Path -from typing import List - - -def load_cpu_usage(path: Path) -> List[float]: - usage = [] - with open(path) as f: - reader = csv.reader(f, delimiter=",") - for row in reader: - # The log might contain incomplete rows or some Python exception - if len(row) == 2: - try: - idle = float(row[1]) - usage.append(100.0 - idle) - except ValueError: - pass - return usage - - -def upload_datadog_measure(name: str, value: float): - """ - Uploads a single numeric metric for the current GitHub Actions job to DataDog. - """ - print(f"Metric {name}: {value:.4f}") - - cmd = "npx" - if os.getenv("GITHUB_ACTIONS") is not None and sys.platform.lower().startswith( - "win" - ): - # Due to weird interaction of MSYS2 and Python, we need to use an absolute path, - # and also specify the ".cmd" at the end. See https://github.com/rust-lang/rust/pull/125771. - cmd = "C:\\Program Files\\nodejs\\npx.cmd" - - subprocess.run( - [ - cmd, - "datadog-ci", - "measure", - "--level", - "job", - "--measures", - f"{name}:{value}", - ], - check=False, - ) - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(prog="DataDog metric uploader") - parser.add_argument("cpu-usage-history-csv") - args = parser.parse_args() - - build_usage_csv = vars(args)["cpu-usage-history-csv"] - usage_timeseries = load_cpu_usage(Path(build_usage_csv)) - if len(usage_timeseries) > 0: - avg_cpu_usage = sum(usage_timeseries) / len(usage_timeseries) - else: - avg_cpu_usage = 0 - upload_datadog_measure("avg-cpu-usage", avg_cpu_usage) diff --git a/src/doc/book b/src/doc/book index d4d2c18cbd208..81a976a237f84 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit d4d2c18cbd20876b2130a546e790446a8444cb32 +Subproject commit 81a976a237f84b8392c4ce1bd5fd076eb757a2eb diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 8dbdda7cae4fa..1e27e5e6d5133 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 8dbdda7cae4fa030f09f8f5b63994d4d1dde74b9 +Subproject commit 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9c diff --git a/src/doc/nomicon b/src/doc/nomicon index 336f75835a6c0..b4448fa406a6d 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 336f75835a6c0514852cc65aba9a698b699b13c8 +Subproject commit b4448fa406a6dccde62d1e2f34f70fc51814cdcc diff --git a/src/doc/reference b/src/doc/reference index 6195dbd70fc6f..dda31c85f2ef2 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 6195dbd70fc6f0980c314b4d23875ac570d8253a +Subproject commit dda31c85f2ef2e5d2f0f2f643c9231690a30a626 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 66543bbc5b7db..6f69823c28ae8 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 66543bbc5b7dbd4e679092c07ae06ba6c73fd912 +Subproject commit 6f69823c28ae8d929d6c815181c73d3e99ef16d3 diff --git a/src/doc/rustc-dev-guide/.github/workflows/ci.yml b/src/doc/rustc-dev-guide/.github/workflows/ci.yml index 3f810e2fbcc99..22a4fb1901ab8 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/ci.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/ci.yml @@ -6,8 +6,8 @@ on: - master pull_request: schedule: - # Run at 18:00 UTC every day - - cron: '0 18 * * *' + # Run multiple times a day as the successfull cached links are not checked every time. + - cron: '0 */8 * * *' jobs: ci: @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest env: MDBOOK_VERSION: 0.4.21 - MDBOOK_LINKCHECK2_VERSION: 0.8.1 + MDBOOK_LINKCHECK2_VERSION: 0.9.1 MDBOOK_MERMAID_VERSION: 0.12.6 MDBOOK_TOC_VERSION: 0.11.2 DEPLOY_DIR: book/html diff --git a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml index dc5395a19dd03..b19eccf9eb8c1 100644 --- a/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml +++ b/src/doc/rustc-dev-guide/.github/workflows/rustc-pull.yml @@ -111,4 +111,4 @@ jobs: to: 196385 type: "stream" topic: "Subtree sync automation" - content: ${{ steps.message.outputs.message }} + content: ${{ steps.create-message.outputs.message }} diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md index 2464ffbbc5032..6a25a91f56a5d 100644 --- a/src/doc/rustc-dev-guide/README.md +++ b/src/doc/rustc-dev-guide/README.md @@ -82,6 +82,7 @@ cargo +stable install josh-proxy --git https://github.com/josh-project/josh --ta Older versions of `josh-proxy` may not round trip commits losslessly so it is important to install this exact version. ### Pull changes from `rust-lang/rust` into this repository + 1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide` 2) Run the pull command ``` @@ -95,3 +96,15 @@ Older versions of `josh-proxy` may not round trip commits losslessly so it is im $ cargo run --manifest-path josh-sync/Cargo.toml rustc-push ``` 2) Create a PR from `` into `rust-lang/rust` + +#### Minimal git config + +For simplicity (ease of implementation purposes), the josh-sync script simply calls out to system git. This means that the git invocation may be influenced by global (or local) git configuration. + +You may observe "Nothing to pull" even if you *know* rustc-pull has something to pull if your global git config sets `fetch.prunetags = true` (and possibly other configurations may cause unexpected outcomes). + +To minimize the likelihood of this happening, you may wish to keep a separate *minimal* git config that *only* has `[user]` entries from global git config, then repoint system git to use the minimal git config instead. E.g. + +``` +$ GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo +stable run --manifest-path josh-sync/Cargo.toml -- rustc-pull +``` diff --git a/src/doc/rustc-dev-guide/examples/README b/src/doc/rustc-dev-guide/examples/README index ca49dd74db260..05e44673700aa 100644 --- a/src/doc/rustc-dev-guide/examples/README +++ b/src/doc/rustc-dev-guide/examples/README @@ -4,7 +4,10 @@ For each example to compile, you will need to first run the following: To create an executable: - rustc rustc-driver-example.rs + rustup run nightly rustc rustc-driver-example.rs + +You might need to be more specific about the exact nightly version. See the comments at the top of +the examples for the version they were written for. To run an executable: diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs index 14998965ac863..984bd3e37ae30 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs @@ -1,3 +1,5 @@ +// Tested with nightly-2025-02-13 + #![feature(rustc_private)] extern crate rustc_ast; @@ -73,7 +75,7 @@ impl rustc_driver::Callbacks for MyCallbacks { let hir = tcx.hir(); let item = hir.item(id); match item.kind { - rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => { + rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn { .. } => { let name = item.ident; let ty = tcx.type_of(item.hir_id().owner.def_id); println!("{name:?}:\t{ty:?}") @@ -87,5 +89,13 @@ impl rustc_driver::Callbacks for MyCallbacks { } fn main() { - run_compiler(&["main.rs".to_string()], &mut MyCallbacks); + run_compiler( + &[ + // The first argument, which in practice contains the name of the binary being executed + // (i.e. "rustc") is ignored by rustc. + "ignored".to_string(), + "main.rs".to_string(), + ], + &mut MyCallbacks, + ); } diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs index dc63e1aa511bf..3270c722e0772 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs @@ -1,3 +1,5 @@ +// Tested with nightly-2025-02-13 + #![feature(rustc_private)] extern crate rustc_ast; @@ -18,7 +20,7 @@ use std::path::Path; use std::sync::Arc; use rustc_ast_pretty::pprust::item_to_string; -use rustc_driver::{Compilation, run_compiler}; +use rustc_driver::{run_compiler, Compilation}; use rustc_interface::interface::{Compiler, Config}; use rustc_middle::ty::TyCtxt; @@ -74,8 +76,8 @@ impl rustc_driver::Callbacks for MyCallbacks { for id in hir_krate.items() { let item = hir_krate.item(id); // Use pattern-matching to find a specific node inside the main function. - if let rustc_hir::ItemKind::Fn(_, _, body_id) = item.kind { - let expr = &tcx.hir_body(body_id).value; + if let rustc_hir::ItemKind::Fn { body, .. } = item.kind { + let expr = &tcx.hir_body(body).value; if let rustc_hir::ExprKind::Block(block, _) = expr.kind { if let rustc_hir::StmtKind::Let(let_stmt) = block.stmts[0].kind { if let Some(expr) = let_stmt.init { @@ -94,5 +96,13 @@ impl rustc_driver::Callbacks for MyCallbacks { } fn main() { - run_compiler(&["main.rs".to_string()], &mut MyCallbacks); + run_compiler( + &[ + // The first argument, which in practice contains the name of the binary being executed + // (i.e. "rustc") is ignored by rustc. + "ignored".to_string(), + "main.rs".to_string(), + ], + &mut MyCallbacks, + ); } diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs index 30f48ea52978b..70f27c2a82a9c 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-interface-example.rs @@ -1,3 +1,5 @@ +// Tested with nightly-2025-02-13 + #![feature(rustc_private)] extern crate rustc_driver; @@ -9,8 +11,6 @@ extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; -use std::sync::Arc; - use rustc_errors::registry; use rustc_hash::FxHashMap; use rustc_session::config; @@ -56,7 +56,7 @@ fn main() { expanded_args: Vec::new(), ice_file: None, hash_untracked_state: None, - using_internal_features: Arc::default(), + using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES, }; rustc_interface::run_compiler(config, |compiler| { // Parse the program and print the syntax tree. @@ -68,7 +68,7 @@ fn main() { let hir = tcx.hir(); let item = hir.item(id); match item.kind { - rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn(_, _, _) => { + rustc_hir::ItemKind::Static(_, _, _) | rustc_hir::ItemKind::Fn { .. } => { let name = item.ident; let ty = tcx.type_of(item.hir_id().owner.def_id); println!("{name:?}:\t{ty:?}") diff --git a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs index 2355cb85ab3dd..39b236e1783a6 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-interface-getting-diagnostics.rs @@ -1,3 +1,5 @@ +// Tested with nightly-2025-02-13 + #![feature(rustc_private)] extern crate rustc_data_structures; @@ -15,7 +17,7 @@ use std::sync::{Arc, Mutex}; use rustc_errors::emitter::Emitter; use rustc_errors::registry::{self, Registry}; use rustc_errors::translation::Translate; -use rustc_errors::{DiagCtxt, DiagInner, FluentBundle}; +use rustc_errors::{DiagInner, FluentBundle}; use rustc_session::config; use rustc_span::source_map::SourceMap; @@ -79,7 +81,7 @@ fn main() { expanded_args: Vec::new(), ice_file: None, hash_untracked_state: None, - using_internal_features: Arc::default(), + using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES, }; rustc_interface::run_compiler(config, |compiler| { let krate = rustc_interface::passes::parse(&compiler.sess); diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 78e9ecdf174be..eb779d9ab0509 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -124cc92199ffa924f6b4c7cc819a85b65e0c3984 +8536f201ffdb2c24925d7f9e87996d7dca93428b diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 91c4aeacbd749..ce74c741b3936 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -75,6 +75,7 @@ - [Prologue](./building/bootstrapping/intro.md) - [What Bootstrapping does](./building/bootstrapping/what-bootstrapping-does.md) - [How Bootstrap does it](./building/bootstrapping/how-bootstrap-does-it.md) +- [Writing tools in Bootstrap](./building/bootstrapping/writing-tools-in-bootstrap.md) - [Debugging bootstrap](./building/bootstrapping/debugging-bootstrap.md) # High-level Compiler Architecture @@ -177,7 +178,7 @@ - [Inference details](./opaque-types-impl-trait-inference.md) - [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md) - [Region inference restrictions][opaque-infer] -- [Effect checking](./effects.md) +- [Const condition checking](./effects.md) - [Pattern and Exhaustiveness Checking](./pat-exhaustive-checking.md) - [Unsafety Checking](./unsafety-checking.md) - [MIR dataflow](./mir/dataflow.md) diff --git a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md index 92d4ce32f9248..0b45956b16096 100644 --- a/src/doc/rustc-dev-guide/src/backend/updating-llvm.md +++ b/src/doc/rustc-dev-guide/src/backend/updating-llvm.md @@ -116,14 +116,14 @@ so let's go through each in detail. at the time of the branch, and the remaining part is the current date. -2. Apply Rust-specific patches to the llvm-project repository. +1. Apply Rust-specific patches to the llvm-project repository. All features and bugfixes are upstream, but there's often some weird build-related patches that don't make sense to upstream. These patches are typically the latest patches in the rust-lang/llvm-project branch that rustc is currently using. -3. Build the new LLVM in the `rust` repository. +1. Build the new LLVM in the `rust` repository. To do this, you'll want to update the `src/llvm-project` repository to your branch, and the revision you've created. @@ -151,7 +151,7 @@ so let's go through each in detail. download-ci-llvm = false ``` -4. Test for regressions across other platforms. LLVM often has at least one bug +1. Test for regressions across other platforms. LLVM often has at least one bug for non-tier-1 architectures, so it's good to do some more testing before sending this to bors! If you're low on resources you can send the PR as-is now to bors, though, and it'll get tested anyway. @@ -170,22 +170,17 @@ so let's go through each in detail. * `./src/ci/docker/run.sh dist-various-2` * `./src/ci/docker/run.sh armhf-gnu` -5. Prepare a PR to `rust-lang/rust`. Work with maintainers of +1. Prepare a PR to `rust-lang/rust`. Work with maintainers of `rust-lang/llvm-project` to get your commit in a branch of that repository, and then you can send a PR to `rust-lang/rust`. You'll change at least `src/llvm-project` and will likely also change [`llvm-wrapper`] as well. - + > For prior art, here are some previous LLVM updates: - > - [LLVM 11](https://github.com/rust-lang/rust/pull/73526) - > - [LLVM 12](https://github.com/rust-lang/rust/pull/81451) - > - [LLVM 13](https://github.com/rust-lang/rust/pull/87570) - > - [LLVM 14](https://github.com/rust-lang/rust/pull/93577) - > - [LLVM 15](https://github.com/rust-lang/rust/pull/99464) - > - [LLVM 16](https://github.com/rust-lang/rust/pull/109474) > - [LLVM 17](https://github.com/rust-lang/rust/pull/115959) > - [LLVM 18](https://github.com/rust-lang/rust/pull/120055) > - [LLVM 19](https://github.com/rust-lang/rust/pull/127513) + > - [LLVM 20](https://github.com/rust-lang/rust/pull/135763) Note that sometimes it's easiest to land [`llvm-wrapper`] compatibility as a PR before actually updating `src/llvm-project`. @@ -194,7 +189,7 @@ so let's go through each in detail. others interested in trying out the new LLVM can benefit from work you've done to update the C++ bindings. -3. Over the next few months, +1. Over the next few months, LLVM will continually push commits to its `release/a.b` branch. We will often want to have those bug fixes as well. The merge process for that is to use `git merge` itself to merge LLVM's @@ -202,9 +197,9 @@ so let's go through each in detail. This is typically done multiple times when necessary while LLVM's release branch is baking. -4. LLVM then announces the release of version `a.b`. +1. LLVM then announces the release of version `a.b`. -5. After LLVM's official release, +1. After LLVM's official release, we follow the process of creating a new branch on the rust-lang/llvm-project repository again, this time with a new date. diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md index 04d8e91dcb4f1..35d33ebdb0e7f 100644 --- a/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/debugging-bootstrap.md @@ -1,7 +1,46 @@ # Debugging bootstrap +There are two main ways to debug bootstrap itself. The first is through println logging, and the second is through the `tracing` feature. + > FIXME: this section should be expanded +## `println` logging + +Bootstrap has extensive unstructured logging. Most of it is gated behind the `--verbose` flag (pass `-vv` for even more detail). + +If you want to know which `Step` ran a command, you could invoke bootstrap like so: + +``` +$ ./x dist rustc --dry-run -vv +learning about cargo +running: RUSTC_BOOTSTRAP="1" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "metadata" "--format-version" "1" "--no-deps" "--manifest-path" "/home/jyn/src/rust2/Cargo.toml" (failure_mode=Exit) (created at src/bootstrap/src/core/metadata.rs:81:25, executed at src/bootstrap/src/core/metadata.rs:92:50) +running: RUSTC_BOOTSTRAP="1" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "metadata" "--format-version" "1" "--no-deps" "--manifest-path" "/home/jyn/src/rust2/library/Cargo.toml" (failure_mode=Exit) (created at src/bootstrap/src/core/metadata.rs:81:25, executed at src/bootstrap/src/core/metadata.rs:92:50) +> Assemble { target_compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu } } + > Libdir { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, target: x86_64-unknown-linux-gnu } + > Sysroot { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, force_recompile: false } +Removing sysroot /home/jyn/src/rust2/build/tmp-dry-run/x86_64-unknown-linux-gnu/stage1 to avoid caching bugs + < Sysroot { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, force_recompile: false } + < Libdir { compiler: Compiler { stage: 1, host: x86_64-unknown-linux-gnu }, target: x86_64-unknown-linux-gnu } +... +``` + +This will go through all the recursive dependency calculations, where `Step`s internally call `builder.ensure()`, without actually running cargo or the compiler. + +In some cases, even this may not be enough logging (if so, please add more!). In that case, you can omit `--dry-run`, which will show the normal output inline with the debug logging: + +``` + c Sysroot { compiler: Compiler { stage: 0, host: x86_64-unknown-linux-gnu }, force_recompile: false } +using sysroot /home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0-sysroot +Building stage0 library artifacts (x86_64-unknown-linux-gnu) +running: cd "/home/jyn/src/rust2" && env ... RUSTC_VERBOSE="2" RUSTC_WRAPPER="/home/jyn/src/rust2/build/bootstrap/debug/rustc" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "build" "--target" "x86_64-unknown-linux-gnu" "-Zbinary-dep-depinfo" "-Zroot-dir=/home/jyn/src/rust2" "-v" "-v" "--manifest-path" "/home/jyn/src/rust2/library/sysroot/Cargo.toml" "--message-format" "json-render-diagnostics" + 0.293440230s INFO prepare_target{force=false package_id=sysroot v0.0.0 (/home/jyn/src/rust2/library/sysroot) target="sysroot"}: cargo::core::compiler::fingerprint: fingerprint error for sysroot v0.0.0 (/home/jyn/src/rust2/library/sysroot)/Build/TargetInner { name_inferred: true, ..: lib_target("sysroot", ["lib"], "/home/jyn/src/rust2/library/sysroot/src/lib.rs", Edition2021) } +... +``` + +In most cases this should not be necessary. + +TODO: we should convert all this to structured logging so it's easier to control precisely. + ## `tracing` in bootstrap Bootstrap has conditional [`tracing`][tracing] setup to provide structured logging. @@ -53,11 +92,11 @@ Checking stage0 bootstrap artifacts (x86_64-unknown-linux-gnu) Build completed successfully in 0:00:08 ``` -#### Controlling log output +#### Controlling tracing output The env var `BOOTSTRAP_TRACING` accepts a [`tracing` env-filter][tracing-env-filter]. -There are two orthogonal ways to control which kind of logs you want: +There are two orthogonal ways to control which kind of tracing logs you want: 1. You can specify the log **level**, e.g. `DEBUG` or `TRACE`. 2. You can also control the log **target**, e.g. `bootstrap` or `bootstrap::core::config` vs custom targets like `CONFIG_HANDLING`. @@ -90,7 +129,7 @@ Both `tracing::*` macros and the `tracing::instrument` proc-macro attribute need ```rs #[cfg(feature = "tracing")] -use tracing::{instrument, trace}; +use tracing::instrument; struct Foo; @@ -99,7 +138,6 @@ impl Step for Foo { #[cfg_attr(feature = "tracing", instrument(level = "trace", name = "Foo::should_run", skip_all))] fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - #[cfg(feature = "tracing")] trace!(?run, "entered Foo::should_run"); todo!() @@ -115,7 +153,6 @@ impl Step for Foo { ), )] fn run(self, builder: &Builder<'_>) -> Self::Output { - #[cfg(feature = "tracing")] trace!(?run, "entered Foo::run"); todo!() diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md new file mode 100644 index 0000000000000..6046d5b133d7d --- /dev/null +++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/writing-tools-in-bootstrap.md @@ -0,0 +1,23 @@ +# Writing tools in Bootstrap + +There are three types of tools you can write in bootstrap: + +- **`Mode::ToolBootstrap`** + Use this for tools that don’t need anything from the in-tree compiler and can run with the stage0 `rustc`. + The output is placed in the "stage0-bootstrap-tools" directory. This mode is for general-purpose tools built + entirely with the stage0 compiler, including target libraries and only works for stage 0. + +- **`Mode::ToolStd`** + Use this for tools that rely on the locally built std. The output goes into the "stageN-tools" directory. + This mode is rarely used, mainly for `compiletest` which requires `libtest`. + +- **`Mode::ToolRustc`** + Use this for tools that depend on both the locally built `rustc` and the target `std`. This is more complex than + the other modes because the tool must be built with the same compiler used for `rustc` and placed in the "stageN-tools" + directory. When you choose `Mode::ToolRustc`, `ToolBuild` implementation takes care of this automatically. + If you need to use the builder’s compiler for something specific, you can get it from `ToolBuildResult`, which is + returned by the tool's [`Step`]. + +Regardless of the tool type you must return `ToolBuildResult` from the tool’s [`Step`] implementation and use `ToolBuild` inside it. + +[`Step`]: https://doc.rust-lang.org/nightly/nightly-rustc/bootstrap/core/builder/trait.Step.html diff --git a/src/doc/rustc-dev-guide/src/building/new-target.md b/src/doc/rustc-dev-guide/src/building/new-target.md index cd215277e69f6..14d10d4a59ddb 100644 --- a/src/doc/rustc-dev-guide/src/building/new-target.md +++ b/src/doc/rustc-dev-guide/src/building/new-target.md @@ -4,12 +4,11 @@ These are a set of steps to add support for a new target. There are numerous end states and paths to get there, so not all sections may be relevant to your desired goal. -See also the associated documentation in the -[target tier policy][target_tier_policy_add]. +See also the associated documentation in the [target tier policy]. -[target_tier_policy_add]: https://doc.rust-lang.org/rustc/target-tier-policy.html#adding-a-new-target +[target tier policy]: https://doc.rust-lang.org/rustc/target-tier-policy.html#adding-a-new-target ## Specifying a new LLVM diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md index 8feda59829b45..f8ca1d0dc3919 100644 --- a/src/doc/rustc-dev-guide/src/building/optimized-build.md +++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md @@ -126,4 +126,4 @@ Here is an example of how can `opt-dist` be used locally (outside of CI): [`Environment`]: https://github.com/rust-lang/rust/blob/ee451f8faccf3050c76cdcd82543c917b40c7962/src/tools/opt-dist/src/environment.rs#L5 > Note: if you want to run the actual CI pipeline, instead of running `opt-dist` locally, -> you can execute `python3 src/ci/github-actions/ci.py run-local dist-x86_64-linux`. +> you can execute `cargo run --manifest-path src/ci/citool/Cargo.toml run-local dist-x86_64-linux`. diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md index 5c041d6cb70f9..2498838144e70 100644 --- a/src/doc/rustc-dev-guide/src/building/suggested.md +++ b/src/doc/rustc-dev-guide/src/building/suggested.md @@ -120,10 +120,35 @@ create a `.vim/coc-settings.json`. The settings can be edited with [`src/etc/rust_analyzer_settings.json`]. Another way is without a plugin, and creating your own logic in your -configuration. To do this you must translate the JSON to Lua yourself. The -translation is 1:1 and fairly straight-forward. It must be put in the -`["rust-analyzer"]` key of the setup table, which is [shown -here](https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#rust_analyzer). +configuration. The following code will work for any checkout of rust-lang/rust (newer than Febuary 2025): + +```lua +lspconfig.rust_analyzer.setup { + root_dir = function() + local default = lspconfig.rust_analyzer.config_def.default_config.root_dir() + -- the default root detection uses the cargo workspace root. + -- but for rust-lang/rust, the standard library is in its own workspace. + -- use the git root instead. + local compiler_config = vim.fs.joinpath(default, "../src/bootstrap/defaults/config.compiler.toml") + if vim.fs.basename(default) == "library" and vim.uv.fs_stat(compiler_config) then + return vim.fs.dirname(default) + end + return default + end, + on_init = function(client) + local path = client.workspace_folders[1].name + local config = vim.fs.joinpath(path, "src/etc/rust_analyzer_zed.json") + if vim.uv.fs_stat(config) then + -- load rust-lang/rust settings + local file = io.open(config) + local json = vim.json.decode(file:read("*a")) + client.config.settings["rust-analyzer"] = json.lsp["rust-analyzer"].initialization_options + client.notify("workspace/didChangeConfiguration", { settings = client.config.settings }) + end + return true + end +} +``` If you would like to use the build task that is described above, you may either make your own command in your config, or you can install a plugin such as diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md index e2097b26e5c83..c16b3ee7abdb7 100644 --- a/src/doc/rustc-dev-guide/src/compiler-debugging.md +++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md @@ -368,7 +368,7 @@ error: layout_of(&'a u32) = Layout { error: aborting due to previous error ``` -[`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/abi/struct.Layout.html +[`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/stable_mir/abi/struct.Layout.html ## Configuring CodeLLDB for debugging `rustc` diff --git a/src/doc/rustc-dev-guide/src/effects.md b/src/doc/rustc-dev-guide/src/effects.md index 1fda7bcbb1380..c7aa271466868 100644 --- a/src/doc/rustc-dev-guide/src/effects.md +++ b/src/doc/rustc-dev-guide/src/effects.md @@ -1,66 +1,159 @@ -# Effects and effect checking - -Note: all of this describes the implementation of the unstable `effects` and -`const_trait_impl` features. None of this implementation is usable or visible from -stable Rust. - -The implementation of const traits and `~const` bounds is a limited effect system. -It is used to allow trait bounds on `const fn` to be used within the `const fn` for -method calls. Within the function, in order to know whether a method on a trait -bound is `const`, we need to know whether there is a `~const` bound for the trait. -In order to know whether we can instantiate a `~const` bound on a `const fn`, we -need to know whether there is a `const_trait` impl for the type and trait being -used (or whether the `const fn` is used at runtime, then any type implementing the -trait is ok, just like with other bounds). - -We perform these checks via a const generic boolean that gets attached to all -`const fn` and `const trait`. The following sections will explain the desugarings -and the way we perform the checks at call sites. - -The const generic boolean is inverted to the meaning of `const`. In the compiler -it is called `host`, because it enables "host APIs" like `static` items, network -access, disk access, random numbers and everything else that isn't available in -`const` contexts. So `false` means "const", `true` means "not const" and if it's -a generic parameter, it means "maybe const" (meaning we're in a const fn or const -trait). - -## `const fn` - -All `const fn` have a `#[rustc_host] const host: bool` generic parameter that is -hidden from users. Any `~const Trait` bounds in the generics list or `where` bounds -of a `const fn` get converted to `Trait + Trait` bounds. The `Trait` -exists so that associated types of the generic param can be used from projections -like `::Assoc`, because there are no `` projections for now. - -## `#[const_trait] trait`s - -The `#[const_trait]` attribute gives the marked trait a `#[rustc_host] const host: bool` -generic parameter. All functions of the trait "inherit" this generic parameter, just like -they have all the regular generic parameters of the trait. Any `~const Trait` super-trait -bounds get desugared to `Trait + Trait` in order to allow using associated -types and consts of the super traits in the trait declaration. This is necessary, because -`::Assoc` is always `>::Assoc` as there is -no `` syntax. - -## `typeck` performing method and function call checks. - -When generic parameters are instantiated for any items, the `host` generic parameter -is always instantiated as an inference variable. This is a special kind of inference var -that is not part of the type or const inference variables, similar to how we have -special inference variables for type variables that we know to be an integer, but not -yet which one. These separate inference variables fall back to `true` at -the end of typeck (in `fallback_effects`) to ensure that `let _ = some_fn_item_name;` -will keep compiling. - -All actually used (in function calls, casts, or anywhere else) function items, will -have the `enforce_context_effects` method invoked. -It trivially returns if the function being called has no `host` generic parameter. - -In order to error if a non-const function is called in a const context, we have not -yet disabled the const-check logic that happens on MIR, because -`enforce_context_effects` does not yet perform this check. - -The function call's `host` parameter is then equated to the context's `host` value, -which almost always trivially succeeds, as it was an inference var. If the inference -var has already been bound (since the function item is invoked twice), the second -invocation checks it against the first. +# Effects and const condition checking + +## The `HostEffect` predicate + +[`HostEffectPredicate`]s are a kind of predicate from `~const Tr` or `const Tr` +bounds. It has a trait reference, and a `constness` which could be `Maybe` or +`Const` depending on the bound. Because `~const Tr`, or rather `Maybe` bounds +apply differently based on whichever contexts they are in, they have different +behavior than normal bounds. Where normal trait bounds on a function such as +`T: Tr` are collected within the [`predicates_of`] query to be proven when a +function is called and to be assumed within the function, bounds such as +`T: ~const Tr` will behave as a normal trait bound and add `T: Tr` to the result +from `predicates_of`, but also adds a `HostEffectPredicate` to the +[`const_conditions`] query. + +On the other hand, `T: const Tr` bounds do not change meaning across contexts, +therefore they will result in `HostEffect(T: Tr, const)` being added to +`predicates_of`, and not `const_conditions`. + +[`HostEffectPredicate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/predicate/struct.HostEffectPredicate.html +[`predicates_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.predicates_of +[`const_conditions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.const_conditions + +## The `const_conditions` query + +`predicates_of` represents a set of predicates that need to be proven to use an +item. For example, to use `foo` in the example below: + +```rust +fn foo() where T: Default {} +``` + +We must be able to prove that `T` implements `Default`. In a similar vein, +`const_conditions` represents a set of predicates that need to be proven to use +an item *in const contexts*. If we adjust the example above to use `const` trait +bounds: + +```rust +const fn foo() where T: ~const Default {} +``` + +Then `foo` would get a `HostEffect(T: Default, maybe)` in the `const_conditions` +query, suggesting that in order to call `foo` from const contexts, one must +prove that `T` has a const implementation of `Default`. + +## Enforcement of `const_conditions` + +`const_conditions` are currently checked in various places. + +Every call in HIR from a const context (which includes `const fn` and `const` +items) will check that `const_conditions` of the function we are calling hold. +This is done in [`FnCtxt::enforce_context_effects`]. Note that we don't check +if the function is only referred to but not called, as the following code needs +to compile: + +```rust +const fn hi() -> T { + T::default() +} +const X: fn() -> u32 = hi::; +``` + +For a trait `impl` to be well-formed, we must be able to prove the +`const_conditions` of the trait from the `impl`'s environment. This is checked +in [`wfcheck::check_impl`]. + +Here's an example: + +```rust +#[const_trait] +trait Bar {} +#[const_trait] +trait Foo: ~const Bar {} +// `const_conditions` contains `HostEffect(Self: Bar, maybe)` + +impl const Bar for () {} +impl const Foo for () {} +// ^ here we check `const_conditions` for the impl to be well-formed +``` + +Methods of trait impls must not have stricter bounds than the method of the +trait that they are implementing. To check that the methods are compatible, a +hybrid environment is constructed with the predicates of the `impl` plus the +predicates of the trait method, and we attempt to prove the predicates of the +impl method. We do the same for `const_conditions`: + +```rust +#[const_trait] +trait Foo { + fn hi(); +} + +impl Foo for Vec { + fn hi(); + // ^ we can't prove `T: ~const PartialEq` given `T: ~const Clone` and + // `T: ~const Default`, therefore we know that the method on the impl + // is stricter than the method on the trait. +} +``` + +These checks are done in [`compare_method_predicate_entailment`]. A similar +function that does the same check for associated types is called +[`compare_type_predicate_entailment`]. Both of these need to consider +`const_conditions` when in const contexts. + +In MIR, as part of const checking, `const_conditions` of items that are called +are revalidated again in [`Checker::revalidate_conditional_constness`]. + +[`compare_method_predicate_entailment`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_method_predicate_entailment.html +[`compare_type_predicate_entailment`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.compare_type_predicate_entailment.html +[`FnCtxt::enforce_context_effects`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_typeck/fn_ctxt/struct.FnCtxt.html#method.enforce_context_effects +[`wfcheck::check_impl`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/wfcheck/fn.check_impl.html +[`Checker::revalidate_conditional_constness`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_const_eval/check_consts/check/struct.Checker.html#method.revalidate_conditional_constness + +## `explicit_implied_const_bounds` on associated types and traits + +Bounds on associated types, opaque types, and supertraits such as +```rust +trait Foo: ~const PartialEq { + type X: ~const PartialEq; +} + +fn foo() -> impl ~const PartialEq { + // ^ unimplemented syntax +} +``` + +Have their bounds represented differently. Unlike `const_conditions` which need +to be proved for callers, and can be assumed inside the definition (e.g. trait +bounds on functions), these bounds need to be proved at definition (at the impl, +or when returning the opaque) but can be assumed for callers. The non-const +equivalent of these bounds are called [`explicit_item_bounds`]. + +These bounds are checked in [`compare_impl_item::check_type_bounds`] for HIR +typeck, [`evaluate_host_effect_from_item_bounds`] in the old solver and +[`consider_additional_alias_assumptions`] in the new solver. + +[`explicit_item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.explicit_item_bounds +[`compare_impl_item::check_type_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/check/compare_impl_item/fn.check_type_bounds.html +[`evaluate_host_effect_from_item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_trait_selection/traits/effects/fn.evaluate_host_effect_from_item_bounds.html +[`consider_additional_alias_assumptions`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_next_trait_solver/solve/assembly/trait.GoalKind.html#tymethod.consider_additional_alias_assumptions + +## Proving `HostEffectPredicate`s + +`HostEffectPredicate`s are implemented both in the [old solver] and the [new +trait solver]. In general, we can prove a `HostEffect` predicate when either of +these conditions are met: + +* The predicate can be assumed from caller bounds; +* The type has a `const` `impl` for the trait, *and* that const conditions on +the impl holds, *and* that the `explicit_implied_const_bounds` on the trait +holds; or +* The type has a built-in implementation for the trait in const contexts. For +example, `Fn` may be implemented by function items if their const conditions +are satisfied, or `Destruct` is implemented in const contexts if the type can +be dropped at compile time. + +[old solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_trait_selection/traits/effects.rs.html +[new trait solver]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_next_trait_solver/solve/effect_goals.rs.html diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md index 51893d537d750..75f5a9e204528 100644 --- a/src/doc/rustc-dev-guide/src/hir.md +++ b/src/doc/rustc-dev-guide/src/hir.md @@ -139,12 +139,12 @@ defined in the map. By matching on this, you can find out what sort of node the `HirId` referred to and also get a pointer to the data itself. Often, you know what sort of node `n` is – e.g. if you know that `n` must be some HIR expression, you can do -[`tcx.hir().expect_expr(n)`][expect_expr], which will extract and return the +[`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the [`&hir::Expr`][Expr], panicking if `n` is not in fact an expression. [find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find [`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html -[expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.expect_expr +[expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr [Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html Finally, you can use the HIR map to find the parents of nodes, via diff --git a/src/doc/rustc-dev-guide/src/parallel-rustc.md b/src/doc/rustc-dev-guide/src/parallel-rustc.md index c5b70706a8180..690fb19c9f524 100644 --- a/src/doc/rustc-dev-guide/src/parallel-rustc.md +++ b/src/doc/rustc-dev-guide/src/parallel-rustc.md @@ -46,10 +46,8 @@ are implemented differently depending on whether `parallel-compiler` is true. | data structure | parallel | non-parallel | | -------------------------------- | --------------------------------------------------- | ------------ | -| OnceCell | std::sync::OnceLock | std::cell::OnceCell | | Lock\ | (parking_lot::Mutex\) | (std::cell::RefCell) | | RwLock\ | (parking_lot::RwLock\) | (std::cell::RefCell) | -| MTRef<'a, T> | &'a T | &'a mut T | | MTLock\ | (Lock\) | (T) | | ReadGuard | parking_lot::RwLockReadGuard | std::cell::Ref | | MappedReadGuard | parking_lot::MappedRwLockReadGuard | std::cell::Ref | diff --git a/src/doc/rustc-dev-guide/src/profiling/with_perf.md b/src/doc/rustc-dev-guide/src/profiling/with_perf.md index 6cd98f886ddd2..51a22d18577ed 100644 --- a/src/doc/rustc-dev-guide/src/profiling/with_perf.md +++ b/src/doc/rustc-dev-guide/src/profiling/with_perf.md @@ -52,6 +52,13 @@ you made in the beginning. But there are some things to be aware of: - You probably don't want incremental messing about with your profile. So something like `CARGO_INCREMENTAL=0` can be helpful. +In case to avoid the issue of `addr2line xxx/elf: could not read first record` when reading +collected data from `cargo`, you may need use the latest version of `addr2line`: + +```bash +cargo install addr2line --features="bin" +``` + ### Gathering a perf profile from a `perf.rust-lang.org` test Often we want to analyze a specific test from `perf.rust-lang.org`. diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md b/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md index e3ca323058c88..1043df6ecb65c 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver/getting-diagnostics.md @@ -8,7 +8,6 @@ otherwise be printed to stderr. To get diagnostics from the compiler, configure [`rustc_interface::Config`] to output diagnostic to a buffer, and run [`TyCtxt.analysis`]. -The following was tested with `nightly-2024-09-16`: ```rust {{#include ../../examples/rustc-interface-getting-diagnostics.rs}} diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/interacting-with-the-ast.md b/src/doc/rustc-dev-guide/src/rustc-driver/interacting-with-the-ast.md index 5eaa0c82c9ee7..f46418701a7d7 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver/interacting-with-the-ast.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver/interacting-with-the-ast.md @@ -5,7 +5,6 @@ ## Getting the type of an expression To get the type of an expression, use the [`after_analysis`] callback to get a [`TyCtxt`]. -The following was tested with `nightly-2024-12-15`: ```rust {{#include ../../examples/rustc-driver-interacting-with-the-ast.rs}} diff --git a/src/doc/rustc-dev-guide/src/solve/trait-solving.md b/src/doc/rustc-dev-guide/src/solve/trait-solving.md index 345ee0b094e8f..c1eb1a94b9634 100644 --- a/src/doc/rustc-dev-guide/src/solve/trait-solving.md +++ b/src/doc/rustc-dev-guide/src/solve/trait-solving.md @@ -2,8 +2,7 @@ This chapter describes how trait solving works with the new WIP solver located in [`rustc_trait_selection/solve`][solve]. Feel free to also look at the docs for -[the current solver](../traits/resolution.md) and [the chalk solver](../traits/chalk.md) -can be found separately. +[the current solver](../traits/resolution.md) and [the chalk solver](../traits/chalk.md). ## Core concepts diff --git a/src/doc/rustc-dev-guide/src/tests/ci.md b/src/doc/rustc-dev-guide/src/tests/ci.md index a4b22392f1976..0c0f750a45d72 100644 --- a/src/doc/rustc-dev-guide/src/tests/ci.md +++ b/src/doc/rustc-dev-guide/src/tests/ci.md @@ -28,7 +28,7 @@ Our CI is primarily executed on [GitHub Actions], with a single workflow defined in [`.github/workflows/ci.yml`], which contains a bunch of steps that are unified for all CI jobs that we execute. When a commit is pushed to a corresponding branch or a PR, the workflow executes the -[`src/ci/github-actions/ci.py`] script, which dynamically generates the specific CI +[`src/ci/citool`] crate, which dynamically generates the specific CI jobs that should be executed. This script uses the [`jobs.yml`] file as an input, which contains a declarative configuration of all our CI jobs. @@ -133,29 +133,37 @@ There are several use-cases for try builds: Again, a working compiler build is needed for this, which can be produced by the [dist-x86_64-linux] CI job. - Run a specific CI job (e.g. Windows tests) on a PR, to quickly test if it - passes the test suite executed by that job. You can select which CI jobs will - be executed in the try build by adding up to 10 lines containing `try-job: - ` to the PR description. All such specified jobs will be executed - in the try build once the `@bors try` command is used on the PR. If no try - jobs are specified in this way, the jobs defined in the `try` section of - [`jobs.yml`] will be executed by default. + passes the test suite executed by that job. + +You can select which CI jobs will +be executed in the try build by adding lines containing `try-job: +` to the PR description. All such specified jobs will be executed +in the try build once the `@bors try` command is used on the PR. If no try +jobs are specified in this way, the jobs defined in the `try` section of +[`jobs.yml`] will be executed by default. + +Each pattern can either be an exact name of a job or a glob pattern that matches multiple jobs, +for example `*msvc*` or `*-alt`. You can start at most 20 jobs in a single try build. When using +glob patterns, you might want to wrap them in backticks (`` ` ``) to avoid GitHub rendering +the pattern as Markdown. > **Using `try-job` PR description directives** > -> 1. Identify which set of try-jobs (max 10) you would like to exercise. You can +> 1. Identify which set of try-jobs you would like to exercise. You can > find the name of the CI jobs in [`jobs.yml`]. > -> 2. Amend PR description to include (usually at the end of the PR description) -> e.g. +> 2. Amend PR description to include a set of patterns (usually at the end +> of the PR description), for example: > > ```text > This PR fixes #123456. > > try-job: x86_64-msvc > try-job: test-various +> try-job: `*-alt` > ``` > -> Each `try-job` directive must be on its own line. +> Each `try-job` pattern must be on its own line. > > 3. Run the prescribed try jobs with `@bors try`. As aforementioned, this > requires the user to either (1) have `try` permissions or (2) be delegated @@ -299,7 +307,7 @@ platform’s custom [Docker container]. This has a lot of advantages for us: - We can avoid reinstalling tools (like QEMU or the Android emulator) every time thanks to Docker image caching. - Users can run the same tests in the same environment locally by just running - `python3 src/ci/github-actions/ci.py run-local `, which is awesome to debug failures. Note that there are only linux docker images available locally due to licensing and + `cargo run --manifest-path src/ci/citool/Cargo.toml run-local `, which is awesome to debug failures. Note that there are only linux docker images available locally due to licensing and other restrictions. The docker images prefixed with `dist-` are used for building artifacts while @@ -443,7 +451,7 @@ this: [GitHub Actions]: https://github.com/rust-lang/rust/actions [`jobs.yml`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/jobs.yml [`.github/workflows/ci.yml`]: https://github.com/rust-lang/rust/blob/master/.github/workflows/ci.yml -[`src/ci/github-actions/ci.py`]: https://github.com/rust-lang/rust/blob/master/src/ci/github-actions/ci.py +[`src/ci/citool`]: https://github.com/rust-lang/rust/blob/master/src/ci/citool [rust-lang-ci]: https://github.com/rust-lang-ci/rust/actions [bors]: https://github.com/bors [homu]: https://github.com/rust-lang/homu diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 459c082906eba..a6996e3982215 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -74,8 +74,7 @@ The following test suites are available, with links for more information: ### General purpose test suite -[`run-make`](#run-make-tests) are general purpose tests using Rust programs (or -Makefiles (legacy)). +[`run-make`](#run-make-tests) are general purpose tests using Rust programs. ### Rustdoc test suites @@ -396,14 +395,6 @@ your test, causing separate files to be generated for 32bit and 64bit systems. ### `run-make` tests -> **Note on phasing out `Makefile`s** -> -> We are planning to migrate all existing Makefile-based `run-make` tests -> to Rust programs. You should not be adding new Makefile-based `run-make` -> tests. -> -> See . - The tests in [`tests/run-make`] are general-purpose tests using Rust *recipes*, which are small programs (`rmake.rs`) allowing arbitrary Rust code such as `rustc` invocations, and is supported by a [`run_make_support`] library. Using @@ -424,10 +415,9 @@ Compiletest directives like `//@ only-` or `//@ ignore-` are supported in `rmake.rs`, like in UI tests. However, revisions or building auxiliary via directives are not currently supported. -Two `run-make` tests are ported over to Rust recipes as examples: - -- -- +`rmake.rs` and `run-make-support` may *not* use any nightly/unstable features, +as they must be compilable by a stage 0 rustc that may be a beta or even stable +rustc. #### Quickly check if `rmake.rs` tests can be compiled @@ -481,20 +471,6 @@ Then add a corresponding entry to `"rust-analyzer.linkedProjects"` ], ``` -#### Using Makefiles (legacy) - -
-You should avoid writing new Makefile-based `run-make` tests. -
- -Each test should be in a separate directory with a `Makefile` indicating the -commands to run. - -There is a [`tools.mk`] Makefile which you can include which provides a bunch of -utilities to make it easier to run commands and compare outputs. Take a look at -some of the other tests for some examples on how to get started. - -[`tools.mk`]: https://github.com/rust-lang/rust/blob/master/tests/run-make/tools.mk [`tests/run-make`]: https://github.com/rust-lang/rust/tree/master/tests/run-make [`run_make_support`]: https://github.com/rust-lang/rust/tree/master/src/tools/run-make-support diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 00bb2bc4dbb1e..d5b896a8eeebb 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -6,10 +6,7 @@ FIXME(jieyouxu) completely revise this chapter. --> -Directives are special comments that tell compiletest how to build and interpret -a test. They must appear before the Rust source in the test. They may also -appear in `rmake.rs` or legacy Makefiles for [run-make -tests](compiletest.md#run-make-tests). +Directives are special comments that tell compiletest how to build and interpret a test. They must appear before the Rust source in the test. They may also appear in `rmake.rs` [run-make tests](compiletest.md#run-make-tests). They are normally put after the short comment that explains the point of this test. Compiletest test suites use `//@` to signal that a comment is a directive. @@ -122,8 +119,7 @@ for more details. These directives are used to ignore the test in some situations, which means the test won't be compiled or run. -* `ignore-X` where `X` is a target detail or stage will ignore the test - accordingly (see below) +* `ignore-X` where `X` is a target detail or other criteria on which to ignore the test (see below) * `only-X` is like `ignore-X`, but will *only* run the test on that target or stage * `ignore-test` always ignores the test. This can be used to temporarily disable @@ -142,7 +138,8 @@ Some examples of `X` in `ignore-X` or `only-X`: matches that target as well as the emscripten targets. - Pointer width: `32bit`, `64bit` - Endianness: `endian-big` -- Stage: `stage0`, `stage1`, `stage2` +- Stage: `stage1`, `stage2` +- Binary format: `elf` - Channel: `stable`, `beta` - When cross compiling: `cross-compile` - When [remote testing] is used: `remote` @@ -198,7 +195,6 @@ settings: The following directives will check LLVM support: -- `no-system-llvm` — ignores if the system llvm is used - `exact-llvm-major-version: 19` — ignores if the llvm major version does not match the specified llvm major version. - `min-llvm-version: 13.0` — ignored if the LLVM version is less than the given @@ -221,8 +217,6 @@ The following directives will check LLVM support: [`aarch64-gnu-debug`]), which only runs a subset of `run-make` tests. Other tests with this directive will not run at all, which is usually not what you want. - - Notably, the [`aarch64-gnu-debug`] CI job *currently* only runs `run-make` - tests which additionally contain `clang` in their test name. See also [Debuginfo tests](compiletest.md#debuginfo-tests) for directives for ignoring debuggers. diff --git a/src/doc/rustc-dev-guide/src/tests/docker.md b/src/doc/rustc-dev-guide/src/tests/docker.md index 2ca08d42130a5..a8a388ef90cfb 100644 --- a/src/doc/rustc-dev-guide/src/tests/docker.md +++ b/src/doc/rustc-dev-guide/src/tests/docker.md @@ -53,6 +53,15 @@ Some additional notes about using the interactive mode: containers. With the container name, run `docker exec -it /bin/bash` where `` is the container name like `4ba195e95cef`. +The approach described above is a relatively low-level interface for running the Docker images +directly. If you want to run a full CI Linux job locally with Docker, in a way that is as close to CI as possible, you can use the following command: + +```bash +cargo run --manifest-path src/ci/citool/Cargo.toml run-local +# For example: +cargo run --manifest-path src/ci/citool/Cargo.toml run-local dist-x86_64-linux-alt +``` + [Docker]: https://www.docker.com/ [`src/ci/docker`]: https://github.com/rust-lang/rust/tree/master/src/ci/docker [`src/ci/docker/run.sh`]: https://github.com/rust-lang/rust/blob/master/src/ci/docker/run.sh diff --git a/src/doc/rustc-dev-guide/src/tests/running.md b/src/doc/rustc-dev-guide/src/tests/running.md index 6ce65092389bd..03d4123cb02b5 100644 --- a/src/doc/rustc-dev-guide/src/tests/running.md +++ b/src/doc/rustc-dev-guide/src/tests/running.md @@ -24,8 +24,8 @@ collection. The test results are cached and previously successful tests are `ignored` during testing. The stdout/stderr contents as well as a timestamp file for every test -can be found under `build//test/` for the given -``. To force-rerun a test (e.g. in case the test runner fails to +can be found under `build//test/` for the given +``. To force-rerun a test (e.g. in case the test runner fails to notice a change) you can use the `--force-rerun` CLI option. > **Note on requirements of external dependencies** @@ -49,7 +49,7 @@ test suite ([`tests/ui`]): ./x test tests/ui ``` -This will run the `ui` test suite. Of course, the choice of test suites is +Of course, the choice of test suites is somewhat arbitrary, and may not suit the task you are doing. For example, if you are hacking on debuginfo, you may be better off with the debuginfo test suite: @@ -112,8 +112,8 @@ crates, you have to specify those explicitly. ./x test --stage 1 library/std ``` -By listing which test suites you want to run you avoid having to run tests for -components you did not change at all. +By listing which test suites you want to run, +you avoid having to run tests for components you did not change at all.
Note that bors only runs the tests with the full stage 2 build; therefore, while @@ -172,16 +172,18 @@ additional arguments to the compiler when building the tests. ## Editing and updating the reference files If you have changed the compiler's output intentionally, or you are making a new -test, you can pass `--bless` to the test subcommand. E.g. if some tests in -`tests/ui` are failing, you can run +test, you can pass `--bless` to the test subcommand. + +As an example, +if some tests in `tests/ui` are failing, you can run this command: ```text ./x test tests/ui --bless ``` -to automatically adjust the `.stderr`, `.stdout` or `.fixed` files of -all tests. Of course you can also target just specific tests with the -`--test-args your_test_name` flag, just like when running the tests. +It automatically adjusts the `.stderr`, `.stdout`, or `.fixed` files of all `test/ui` tests. +Of course you can also target just specific tests with the `--test-args your_test_name` flag, +just like when running the tests without the `--bless` flag. ## Configuring test running @@ -190,7 +192,7 @@ There are a few options for running tests: * `config.toml` has the `rust.verbose-tests` option. If `false`, each test will print a single dot (the default). If `true`, the name of every test will be printed. This is equivalent to the `--quiet` option in the [Rust test - harness](https://doc.rust-lang.org/rustc/tests/) + harness](https://doc.rust-lang.org/rustc/tests/). * The environment variable `RUST_TEST_THREADS` can be set to the number of concurrent threads to use for testing. @@ -238,30 +240,6 @@ This is much faster, but doesn't always work. For example, some tests include directives that specify specific compiler flags, or which rely on other crates, and they may not run the same without those options. -## Running `run-make` tests - -### Windows - -Running the `run-make` test suite on Windows is a currently bit more involved. -There are numerous prerequisites and environmental requirements: - -- Install msys2: -- Specify `MSYS2_PATH_TYPE=inherit` in `msys2.ini` in the msys2 installation directory, run the - following with `MSYS2 MSYS`: - - `pacman -Syuu` - - `pacman -S make` - - `pacman -S diffutils` - - `pacman -S binutils` - - `./x test run-make` (`./x test tests/run-make` doesn't work) - -There is [on-going work][port-run-make] to not rely on `Makefile`s in the -run-make test suite. Once this work is completed, you can run the entire -`run-make` test suite on native Windows inside `cmd` or `PowerShell` without -needing to install and use MSYS2. As of Oct 2024, it is -already possible to run the vast majority of the `run-make` test suite outside -of MSYS2, but there will be failures for the tests that still use `Makefile`s -due to not finding `make`. - ## Running tests on a remote machine Tests may be run on a remote machine (e.g. to test builds for a different @@ -406,4 +384,3 @@ If you encounter bugs or problems, don't hesitate to open issues on the repository](https://github.com/rust-lang/rustc_codegen_gcc/). [`tests/ui`]: https://github.com/rust-lang/rust/tree/master/tests/ui -[port-run-make]: https://github.com/rust-lang/rust/issues/121876 diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 6c7cdec348024..542ee9fffce3a 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -50,6 +50,7 @@ - [\*-linux-ohos](platform-support/openharmony.md) - [\*-hurd-gnu](platform-support/hurd.md) - [aarch64-unknown-teeos](platform-support/aarch64-unknown-teeos.md) + - [avr-none](platform-support/avr-none.md) - [\*-espidf](platform-support/esp-idf.md) - [\*-unknown-fuchsia](platform-support/fuchsia.md) - [\*-unknown-trusty](platform-support/trusty.md) @@ -68,8 +69,10 @@ - [mipsisa\*r6\*-unknown-linux-gnu\*](platform-support/mips-release-6.md) - [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md) - [powerpc-unknown-openbsd](platform-support/powerpc-unknown-openbsd.md) + - [powerpc-unknown-linux-gnuspe](platform-support/powerpc-unknown-linux-gnuspe.md) - [powerpc-unknown-linux-muslspe](platform-support/powerpc-unknown-linux-muslspe.md) - [powerpc64-ibm-aix](platform-support/aix.md) + - [powerpc64le-unknown-linux-gnu](platform-support/powerpc64le-unknown-linux-gnu.md) - [powerpc64le-unknown-linux-musl](platform-support/powerpc64le-unknown-linux-musl.md) - [riscv32e\*-unknown-none-elf](platform-support/riscv32e-unknown-none-elf.md) - [riscv32i\*-unknown-none-elf](platform-support/riscv32-unknown-none-elf.md) @@ -95,6 +98,7 @@ - [wasm32-wasip1](platform-support/wasm32-wasip1.md) - [wasm32-wasip1-threads](platform-support/wasm32-wasip1-threads.md) - [wasm32-wasip2](platform-support/wasm32-wasip2.md) + - [wasm32-wali-linux-musl](platform-support/wasm32-wali-linux.md) - [wasm32-unknown-emscripten](platform-support/wasm32-unknown-emscripten.md) - [wasm32-unknown-unknown](platform-support/wasm32-unknown-unknown.md) - [wasm32v1-none](platform-support/wasm32v1-none.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c4e5c1aac2f5d..c74a9e9849686 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -96,7 +96,7 @@ target | notes [`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) `powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) `powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) -`powerpc64le-unknown-linux-gnu` | PPC64LE Linux (kernel 3.10, glibc 2.17) +[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17) [`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19, musl 1.2.3) [`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) [`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) @@ -162,7 +162,6 @@ target | std | notes [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat -`i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] @@ -266,7 +265,7 @@ target | std | host | notes [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD [`aarch64-unknown-redox`](platform-support/redox.md) | ✓ | | ARM64 Redox OS [`aarch64-unknown-teeos`](platform-support/aarch64-unknown-teeos.md) | ? | | ARM64 TEEOS | -[`aarch64-unknown-trusty`](platform-support/trusty.md) | ? | | +[`aarch64-unknown-trusty`](platform-support/trusty.md) | ✓ | | [`aarch64-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [`aarch64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | ARM64 VxWorks OS `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) @@ -291,7 +290,7 @@ target | std | host | notes [`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | Armv7-A Linux with uClibc, softfloat [`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | Armv7-A Linux with uClibc, hardfloat [`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | Armv7-A NetBSD w/hard-float -[`armv7-unknown-trusty`](platform-support/trusty.md) | ? | | +[`armv7-unknown-trusty`](platform-support/trusty.md) | ✓ | | [`armv7-wrs-vxworks-eabihf`](platform-support/vxworks.md) | ✓ | | Armv7-A for VxWorks [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat @@ -301,7 +300,7 @@ target | std | host | notes [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * | | Bare Armv8-R, hardfloat [`armv7a-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX [`armv7a-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv7-A with NuttX, hardfloat -`avr-none` | * | | AVR; requires `-Zbuild-std=core` and `-Ctarget-cpu=...` +[`avr-none`](platform-support/avr-none.md) | * | | AVR; requires `-Zbuild-std=core` and `-Ctarget-cpu=...` `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) `csky-unknown-linux-gnuabiv2` | ✓ | | C-SKY abiv2 Linux (little endian) @@ -348,9 +347,9 @@ target | std | host | notes [`mipsisa64r6el-unknown-linux-gnuabi64`](platform-support/mips-release-6.md) | ✓ | ✓ | 64-bit MIPS Release 6 Little Endian `msp430-none-elf` | * | | 16-bit MSP430 microcontrollers [`powerpc-unknown-freebsd`](platform-support/freebsd.md) | ? | | PowerPC FreeBSD -`powerpc-unknown-linux-gnuspe` | ✓ | | PowerPC SPE Linux +[`powerpc-unknown-linux-gnuspe`](platform-support/powerpc-unknown-linux-gnuspe.md) | ✓ | | PowerPC SPE Linux `powerpc-unknown-linux-musl` | ? | | PowerPC Linux with musl 1.2.3 -[`powerpc-unknown-linux-muslspe`](platform-support/powerpc-unknown-linux-muslspe.md) | ? | | PowerPC SPE Linux +[`powerpc-unknown-linux-muslspe`](platform-support/powerpc-unknown-linux-muslspe.md) | ? | | PowerPC SPE Linux with musl 1.2.3 [`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems [`powerpc-unknown-openbsd`](platform-support/powerpc-unknown-openbsd.md) | * | | [`powerpc-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | @@ -405,6 +404,7 @@ target | std | host | notes [`thumbv8m.main-nuttx-eabi`](platform-support/nuttx.md) | ✓ | | ARMv8M Mainline with NuttX [`thumbv8m.main-nuttx-eabihf`](platform-support/nuttx.md) | ✓ | | ARMv8M Mainline with NuttX, hardfloat [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly +[`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? | | WebAssembly with [WALI](https://github.com/arjunr2/WALI) [`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator [`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ? | | 64-bit x86 Cygwin | @@ -419,7 +419,7 @@ target | std | host | notes `x86_64-unknown-l4re-uclibc` | ? | | [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD -[`x86_64-unknown-trusty`](platform-support/trusty.md) | ? | | +[`x86_64-unknown-trusty`](platform-support/trusty.md) | ✓ | | `x86_64-uwp-windows-gnu` | ✓ | | [`x86_64-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [`x86_64-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 64-bit Windows 7 support diff --git a/src/doc/rustc/src/platform-support/powerpc-unknown-linux-gnuspe.md b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-gnuspe.md new file mode 100644 index 0000000000000..a9983a141115f --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-gnuspe.md @@ -0,0 +1,20 @@ +# powerpc-unknown-linux-gnuspe + +**Tier: 3** + +`powerpc-unknown-linux-gnuspe` is a target for Linux on 32-bit PowerPC +processors that implement the Signal Processing Engine (SPE), such as e500, and +uses a different ABI than standard `powerpc-unknown-linux-gnu`. +When building for other 32-bit PowerPC processors, use +`powerpc-unknown-linux-gnu` instead. + +See also [Debian Wiki](https://wiki.debian.org/PowerPCSPEPort) for details on +this platform, and [ABI reference](https://web.archive.org/web/20120608163804/https://www.power.org/resources/downloads/Power-Arch-32-bit-ABI-supp-1.0-Unified.pdf) +for details on SPE ABI. + +Note that support for PowerPC SPE by GCC was [removed in GCC 9](https://gcc.gnu.org/gcc-8/changes.html), +so recent GCC cannot be used as linker/compiler for this target. + +## Target maintainers + +There are currently no formally documented target maintainers. diff --git a/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md index 4c416b5192994..6b62e9ddba109 100644 --- a/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md +++ b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md @@ -2,9 +2,11 @@ **Tier: 3** -This target is very similar to already existing ones like `powerpc_unknown_linux_musl` and `powerpc_unknown_linux_gnuspe`. +This target is very similar to already existing ones like `powerpc-unknown-linux-musl` and `powerpc-unknown-linux-gnuspe`. This one has PowerPC SPE support for musl. Unfortunately, the last supported gcc version with PowerPC SPE is 8.4.0. +See also [platform support documentation of `powerpc-unknown-linux-gnuspe`](powerpc-unknown-linux-gnuspe.md) for information about PowerPC SPE. + ## Target maintainers - [@BKPepe](https://github.com/BKPepe) diff --git a/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md new file mode 100644 index 0000000000000..6cb34b2a777a5 --- /dev/null +++ b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md @@ -0,0 +1,47 @@ +# `powerpc64le-unknown-linux-gnu` + +**Tier: 2** + +Target for 64-bit little endian PowerPC Linux programs + +## Target maintainers + +- David Tenty `daltenty@ibm.com`, https://github.com/daltenty +- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr + +## Requirements + +Building the target itself requires a 64-bit little endian PowerPC compiler that is supported by `cc-rs`. + +## Building the target + +The target can be built by enabling it for a `rustc` build. + +```toml +[build] +target = ["powerpc64le-unknown-linux-gnu"] +``` + +Make sure your C compiler is included in `$PATH`, then add it to the `config.toml`: + +```toml +[target.powerpc64le-unknown-linux-gnu] +cc = "powerpc64le-linux-gnu-gcc" +cxx = "powerpc64le-linux-gnu-g++" +ar = "powerpc64le-linux-gnu-ar" +linker = "powerpc64le-linux-gnu-gcc" +``` + +## Building Rust programs + +This target is distributed through `rustup`, and requires no special +configuration. + +## Cross-compilation + +This target can be cross-compiled from any host. + +## Testing + +This target can be tested as normal with `x.py` on a 64-bit little endian +PowerPC host or via QEMU emulation. diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md index b57083980d275..dda2a50c33d7e 100644 --- a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md +++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md @@ -65,7 +65,7 @@ section below. A RISC-V toolchain can be obtained for Windows/Mac/Linux from the [`riscv-gnu-toolchain`](https://github.com/riscv-collab/riscv-gnu-toolchain) -repostory. Binaries are available via +repository. Binaries are available via [embecosm](https://www.embecosm.com/resources/tool-chain-downloads/#riscv-linux), and may also be available from your OS's package manager. diff --git a/src/doc/rustc/src/platform-support/trusty.md b/src/doc/rustc/src/platform-support/trusty.md index 6b37543b600a7..73fcbbdddca36 100644 --- a/src/doc/rustc/src/platform-support/trusty.md +++ b/src/doc/rustc/src/platform-support/trusty.md @@ -16,8 +16,10 @@ Environment (TEE) for Android. These targets are cross-compiled. They have no special requirements for the host. -Support for the standard library is work-in-progress. It is expected that -they will support alloc with the default allocator, and partially support std. +Trusty targets have partial support for the standard library: `alloc` is fully +supported and `std` has limited support that excludes things like filesystem +access, network I/O, and spawning processes/threads. File descriptors are +supported for the purpose of IPC. Trusty uses the ELF file format. diff --git a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md new file mode 100644 index 0000000000000..0c46ea2c01dad --- /dev/null +++ b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md @@ -0,0 +1,98 @@ +# `wasm32-wali-linux-*` + +**Tier: 3** + +WebAssembly targets that use the [WebAssembly Linux Interface (WALI)](https://github.com/arjunr2/WALI) with 32-bit memory. The latest status of the WALI specification and support are documented within the repo. + +WALI offers seamless targetability of traditional Linux applications to Wasm by exposing Linux syscalls strategically into the sandbox. Numerous applications and build system work unmodified over WALI, including complex low-level system libraries -- a list of applications are included in the research paper linked in the main repo. + +From the wider Wasm ecosystem perspective, implementing WALI within engines allows layering of high-level security policies (e.g. WASI) above it, arming the latter's implementations with sandboxing and portability. + +## Target maintainers + +- Arjun Ramesh [@arjunr2](https://github.com/arjunr2) + +## Requirements + +### Compilation +This target is cross-compiled and requires an installation of the [WALI compiler/sysroot](https://github.com/arjunr2/WALI). This produces standard `wasm32` binaries with the WALI interface methods as module imports that need to be implemented by a supported engine (see the "Execution" section below). + +`wali` targets *minimally require* the following LLVM feature flags: + +* [Bulk memory] - `+bulk-memory` +* Mutable imported globals - `+mutable-globals` +* [Sign-extending operations] - `+sign-ext` +* [Threading/Atomics] - `+atomics` + +[Bulk memory]: https://github.com/WebAssembly/spec/blob/main/proposals/bulk-memory-operations/Overview.md +[Sign-extending operations]: https://github.com/WebAssembly/spec/blob/main/proposals/sign-extension-ops/Overview.md +[Threading/Atomics]: https://github.com/WebAssembly/threads/blob/main/proposals/threads/Overview.md + +> **Note**: Users can expect that new enabled-by-default Wasm features for LLVM are transitively incorporatable into this target -- see [wasm32-unknown-unknown](wasm32-unknown-unknown.md) for detailed information on WebAssembly features. + + +> **Note**: The WALI ABI is similar to default Clang wasm32 ABIs but *not identical*. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to mantain minimum source code changes for 64-bit host platforms currently supported. This may change in the future as the spec evolves. + +### Execution +Running generated WALI binaries also requires a supported compliant engine implementation -- a working implementation in the [WebAssembly Micro-Runtime (WAMR)](https://github.com/arjunr2/WALI) is included in the repo. + +> **Note**: WALI is still somewhat experimental and bugs may exist in the Rust support, WALI toolchain, or the LLVM compiler. The former can be filed in Rust repos while the latter two in the WALI repo. + +## Building the target + +You can build Rust with support for the target by adding it to the `target` +list in `config.toml`, and pointing to the toolchain artifacts from the previous section ("Requirements->Compilation"). A sample `config.toml` for the `musl` environment will look like this, where `` is the absolute path to the root directory of the [WALI repo](https://github.com/arjunr2/WALI): + +```toml +[build] +target = ["wasm32-wali-linux-musl"] + +[target.wasm32-wali-linux-musl] +musl-root = "/wali-musl/sysroot" +llvm-config = "/llvm-project/build/bin/llvm-config" +cc = "/llvm-project/build/bin/clang-18" +cxx = "/llvm-project/build/bin/clang-18" +ar = "/llvm-project/build/bin/llvm-ar" +ranlib = "/llvm-project/build/bin/llvm-ranlib" +llvm-libunwind = "system" +crt-static = true +``` + +> The `llvm-config` settings are only temporary, and the changes will eventually be upstreamed into LLVM + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To compile for +this target, you will either need to build Rust with the target enabled (see +"Building the target" above), or build your own copy of `core` by using +`build-std` or similar. + +Rust program builds can use this target normally. Currently, linking WALI programs may require pointing the `linker` to the llvm build in the [Cargo config](https://doc.rust-lang.org/cargo/reference/config.html) (until LLVM is upstreamed). A `config.toml` for Cargo will look like the following: + +```toml +[target.wasm32-wali-linux-musl] +linker = "/llvm-project/build/bin/lld" +``` + +Note that the following `cfg` directives are set for `wasm32-wali-linux-*`: + +* `cfg(target_arch = "wasm32")` +* `cfg(target_family = {"wasm", "unix"})` +* `cfg(target_r = "wasm")` +* `cfg(target_os = "linux")` +* `cfg(target_env = *)` + +### Restrictions + +Hardware or platform-specific support, besides `syscall` is mostly unsupported in WALI for ISA portability (these tend to be uncommon). + +## Testing + +Currently testing is not supported for `wali` targets and the Rust project doesn't run any tests for this target. + +However, standard ISA-agnostic tests for Linux should be thereotically reusable for WALI targets and minor changes. Testing integration will be continually incorporated as support evolves. + + +## Cross-compilation toolchains and C code + +Most fully featured C code is compilable with the WALI toolchain -- examples can be seen in the repo. diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md index 994c0f4bbb3e9..1b0a312ca9c71 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md +++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md @@ -100,7 +100,7 @@ This target is not a stable target. This means that there are a few engines which implement the `wasi-threads` feature and if they do they're likely behind a flag, for example: -* Wasmtime - `--wasm-features=threads --wasi-modules=experimental-wasi-threads` +* Wasmtime - `--wasi threads` * [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) - needs to be built with WAMR_BUILD_LIB_WASI_THREADS=1 ## Building the target diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md index 6932e6a5764bc..a717f5dad7979 100644 --- a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md @@ -36,7 +36,7 @@ which implement the `memory64` feature and if they do they're likely behind a flag, for example: * Nodejs - `--experimental-wasm-memory64` -* Wasmtime - `--wasm-features memory64` +* Wasmtime - `--wasm memory64` Also note that at this time the `wasm64-unknown-unknown` target assumes the presence of other merged wasm proposals such as (with their LLVM feature flags): diff --git a/src/doc/rustdoc/src/write-documentation/re-exports.md b/src/doc/rustdoc/src/write-documentation/re-exports.md index 34688545c74e9..ee60916351ab8 100644 --- a/src/doc/rustdoc/src/write-documentation/re-exports.md +++ b/src/doc/rustdoc/src/write-documentation/re-exports.md @@ -85,7 +85,22 @@ pub struct Hidden; pub use self::Hidden as InlinedHidden; ``` -The same applies on re-exports themselves: if you have multiple re-exports and some of them have +However, if you still want the re-export itself to be visible, you can add the `#[doc(inline)]` +attribute on it: + +```rust,ignore (inline) +// This struct won't be visible. +#[doc(hidden)] +pub struct Hidden; + +#[doc(inline)] +pub use self::Hidden as InlinedHidden; +``` + +In this case, you will have `pub use self::Hidden as InlinedHidden;` in the generated documentation +but no link to the `Hidden` item. + +So back to `#[doc(hidden)]`: if you have multiple re-exports and some of them have `#[doc(hidden)]`, then these ones (and only these) won't appear in the documentation: ```rust,ignore (inline) diff --git a/src/doc/unstable-book/src/compiler-flags/crate-attr.md b/src/doc/unstable-book/src/compiler-flags/crate-attr.md new file mode 100644 index 0000000000000..8c9c501a23e3d --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/crate-attr.md @@ -0,0 +1,16 @@ +# `crate-attr` + +The tracking issue for this feature is: [#138287](https://github.com/rust-lang/rust/issues/138287). + +------------------------ + +The `-Z crate-attr` flag allows you to inject attributes into the crate root. +For example, `-Z crate-attr=crate_name="test"` acts as if `#![crate_name="test"]` were present before the first source line of the crate root. + +To inject multiple attributes, pass `-Z crate-attr` multiple times. + +Formally, the expansion behaves as follows: +1. The crate is parsed as if `-Z crate-attr` were not present. +2. The attributes in `-Z crate-attr` are parsed. +3. The attributes are injected at the top of the crate root. +4. Macro expansion is performed. diff --git a/src/doc/unstable-book/src/language-features/default-field-values.md b/src/doc/unstable-book/src/language-features/default-field-values.md index 3143b2d7cae3d..6da6c4e6c57e4 100644 --- a/src/doc/unstable-book/src/language-features/default-field-values.md +++ b/src/doc/unstable-book/src/language-features/default-field-values.md @@ -67,7 +67,7 @@ have default field values. ## Lints When manually implementing the `Default` trait for a type that has default -field values, if any of these are overriden in the impl the +field values, if any of these are overridden in the impl the `default_overrides_default_fields` lint will trigger. This lint is in place to avoid surprising diverging behavior between `S { .. }` and `S::default()`, where using the same type in both ways could result in diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index 13a6814d31be9..975b400447eb8 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -62,13 +62,19 @@ These must be implemented by all backends. ### `#[rustc_intrinsic]` declarations -These are written like intrinsics with fallback bodies, but the body is irrelevant. -Use `loop {}` for the body or call the intrinsic recursively and add -`#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't -invoke the body. +These are written without a body: +```rust +#![feature(intrinsics)] +#![allow(internal_features)] + +#[rustc_intrinsic] +pub fn abort() -> !; +``` ### Legacy extern ABI based intrinsics +*This style is deprecated, always prefer the above form.* + These are imported as if they were FFI functions, with the special `rust-intrinsic` ABI. For example, if one was in a freestanding context, but wished to be able to `transmute` between types, and diff --git a/src/doc/unstable-book/src/language-features/offset-of-enum.md b/src/doc/unstable-book/src/language-features/offset-of-enum.md new file mode 100644 index 0000000000000..1960d6299eb00 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/offset-of-enum.md @@ -0,0 +1,29 @@ +# `offset_of_slice` + +The tracking issue for this feature is: [#120141] + +[#120141]: https://github.com/rust-lang/rust/issues/120141 + +------------------------ + +When the `offset_of_enum` feature is enabled, the [`offset_of!`] macro may be used to obtain the +offsets of fields of `enum`s; to express this, `enum` variants may be traversed as if they were +fields. Variants themselves do not have an offset, so they cannot appear as the last path component. + +```rust +#![feature(offset_of_enum)] +use std::mem; + +#[repr(u8)] +enum Enum { + A(u8, u16), + B { one: u8, two: u16 }, +} + +assert_eq!(mem::offset_of!(Enum, A.0), 1); +assert_eq!(mem::offset_of!(Enum, B.two), 2); + +assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); +``` + +[`offset_of!`]: ../../std/mem/macro.offset_of.html diff --git a/src/doc/unstable-book/src/language-features/offset-of-slice.md b/src/doc/unstable-book/src/language-features/offset-of-slice.md new file mode 100644 index 0000000000000..c887fa07f67e1 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/offset-of-slice.md @@ -0,0 +1,30 @@ +# `offset_of_slice` + +The tracking issue for this feature is: [#126151] + +[#126151]: https://github.com/rust-lang/rust/issues/126151 + +------------------------ + +When the `offset_of_slice` feature is enabled, the [`offset_of!`] macro may be used to determine +the offset of fields whose type is `[T]`, that is, a slice of dynamic size. + +In general, fields whose type is dynamically sized do not have statically known offsets because +they do not have statically known alignments. However, `[T]` has the same alignment as `T`, so +it specifically may be allowed. + +```rust +#![feature(offset_of_slice)] + +#[repr(C)] +pub struct Struct { + head: u32, + tail: [u8], +} + +fn main() { + assert_eq!(std::mem::offset_of!(Struct, tail), 4); +} +``` + +[`offset_of!`]: ../../std/mem/macro.offset_of.html diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md index bfdb579cd3523..b2f59732801bc 100644 --- a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024-structural.md @@ -9,12 +9,32 @@ The tracking issue for this feature is: [#123076] This feature is incomplete and not yet intended for general use. This implements experimental, Edition-dependent match ergonomics under consideration for inclusion -in Rust. -For more information, see the corresponding typing rules for [Editions 2021 and earlier] and for -[Editions 2024 and later]. +in Rust, allowing `&` patterns in more places. For example: +```rust,edition2024 +#![feature(ref_pat_eat_one_layer_2024_structural)] +#![allow(incomplete_features)] +# +# // Tests type equality in a way that avoids coercing `&&T` or `&mut T` to `&T`. +# trait Eq {} +# impl Eq for T {} +# fn has_type(_: impl Eq) {} + +// `&` can match against a `ref` binding mode instead of a reference type: +let (x, &y) = &(0, 1); +has_type::<&u8>(x); +has_type::(y); + +// `&` can match against `&mut` references: +let &z = &mut 2; +has_type::(z); +``` + +For specifics, see the corresponding typing rules for [Editions 2021 and earlier] and for +[Editions 2024 and later]. For more information on binding modes, see [The Rust Reference]. For alternative experimental match ergonomics, see the feature [`ref_pat_eat_one_layer_2024`](./ref-pat-eat-one-layer-2024.md). [Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQEBAAAAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false [Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAgEBAQEBAgIAAAAAAAAAAAAAAAA%3D&mode=rules&do_cmp=false +[The Rust Reference]: https://doc.rust-lang.org/reference/patterns.html#binding-modes diff --git a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md index 0c90cec0dbddb..f7c85eec2d28e 100644 --- a/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md +++ b/src/doc/unstable-book/src/language-features/ref-pat-eat-one-layer-2024.md @@ -9,12 +9,33 @@ The tracking issue for this feature is: [#123076] This feature is incomplete and not yet intended for general use. This implements experimental, Edition-dependent match ergonomics under consideration for inclusion -in Rust. -For more information, see the corresponding typing rules for [Editions 2021 and earlier] and for -[Editions 2024 and later]. +in Rust, allowing `&` patterns in more places. For example: + +```rust,edition2024 +#![feature(ref_pat_eat_one_layer_2024)] +#![allow(incomplete_features)] +# +# // Tests type equality in a way that avoids coercing `&&T` or `&mut T` to `&T`. +# trait Eq {} +# impl Eq for T {} +# fn has_type(_: impl Eq) {} + +// `&` can match against a `ref` binding mode instead of a reference type: +let (x, &y) = &(0, 1); +has_type::<&u8>(x); +has_type::(y); + +// `&` can match against `&mut` references: +let &z = &mut 2; +has_type::(z); +``` + +For specifics, see the corresponding typing rules for [Editions 2021 and earlier] and for +[Editions 2024 and later]. For more information on binding modes, see [The Rust Reference]. For alternative experimental match ergonomics, see the feature [`ref_pat_eat_one_layer_2024_structural`](./ref-pat-eat-one-layer-2024-structural.md). [Editions 2021 and earlier]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAQIBAQABAAAAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false [Editions 2024 and later]: https://nadrieril.github.io/typing-rust-patterns/?compare=false&opts1=AQEBAAABAQABAgIAAQEBAAEBAAABAAA%3D&mode=rules&do_cmp=false +[The Rust Reference]: https://doc.rust-lang.org/reference/patterns.html#binding-modes diff --git a/src/doc/unstable-book/src/language-features/rustc-private.md b/src/doc/unstable-book/src/language-features/rustc-private.md index 3b83a3cf4df8a..57ed857cdfe1b 100644 --- a/src/doc/unstable-book/src/language-features/rustc-private.md +++ b/src/doc/unstable-book/src/language-features/rustc-private.md @@ -12,3 +12,33 @@ The presence of this feature changes the way the linkage format for dylibs is ca that is necessary for linking against dylibs that statically link `std` (such as `rustc_driver`). This makes this feature "viral" in linkage; its use in a given crate makes its use required in dependent crates which link to it (including integration tests, which are built as separate crates). + +## Common linker failures related to missing LLVM libraries + +### When using `rustc-private` with Official Toolchains + +When using the `rustc_private` feature with official toolchains distributed via rustup, you'll need to install: + +1. The `rustc-dev` component (provides compiler libraries) +2. The `llvm-tools` component (provides LLVM libraries needed for linking) + +You can install these components using `rustup`: + +```text +rustup component add rustc-dev llvm-tools +``` + +Without the `llvm-tools` component, you may encounter linking errors like: + +```text +error: linking with `cc` failed: exit status: 1 + | + = note: rust-lld: error: unable to find library -lLLVM-{version} +``` + +### When using `rustc-private` with Custom Toolchains + +For custom-built toolchains or environments not using rustup, different configuration may be required: + +- Ensure LLVM libraries are available in your library search paths +- You might need to configure library paths explicitly depending on your LLVM installation diff --git a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md deleted file mode 100644 index 310c8d962948a..0000000000000 --- a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md +++ /dev/null @@ -1,27 +0,0 @@ -# `unsized_tuple_coercion` - -The tracking issue for this feature is: [#42877] - -[#42877]: https://github.com/rust-lang/rust/issues/42877 - ------------------------- - -This is a part of [RFC0401]. According to the RFC, there should be an implementation like this: - -```rust,ignore (partial-example) -impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized {} -``` - -This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this: - -```rust -#![feature(unsized_tuple_coercion)] - -fn main() { - let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]); - let y : &([i32; 3], [i32]) = &x; - assert_eq!(y.1[0], 4); -} -``` - -[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index d6b594aca71a2..06fc6518e3b1b 100755 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -297,10 +297,24 @@ def filter_line(line): re.X | re.UNICODE, ) +DEPRECATED_LINE_PATTERN = re.compile( + r""" + //\s+@ +""", + re.X | re.UNICODE, +) + def get_commands(template): with io.open(template, encoding="utf-8") as f: for lineno, line in concat_multi_lines(f): + if DEPRECATED_LINE_PATTERN.search(line): + print_err( + lineno, + line, + "Deprecated command syntax, replace `// @` with `//@ `", + ) + continue m = LINE_PATTERN.search(line) if not m: continue diff --git a/src/etc/lldb_batchmode.py b/src/etc/lldb_batchmode.py index cf88c53e085e1..5cc9bb23628f0 100644 --- a/src/etc/lldb_batchmode.py +++ b/src/etc/lldb_batchmode.py @@ -40,7 +40,7 @@ def print_debug(s): def normalize_whitespace(s): """Replace newlines, tabs, multiple spaces, etc with exactly one space""" - return re.sub("\s+", " ", s) + return re.sub(r"\s+", " ", s) def breakpoint_callback(frame, bp_loc, dict): @@ -234,7 +234,7 @@ def watchdog(): if ( command == "run" or command == "r" - or re.match("^process\s+launch.*", command) + or re.match(r"^process\s+launch.*", command) ): # Before starting to run the program, let the thread sleep a bit, so all # breakpoint added events can be processed diff --git a/src/etc/lldb_commands b/src/etc/lldb_commands index ef0c3740f0326..508296c3a5aec 100644 --- a/src/etc/lldb_commands +++ b/src/etc/lldb_commands @@ -1,43 +1,80 @@ -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)String$" --category Rust +# Forces test-compliant formatting to all other types +type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust +type summary add -F _ -e -x -h "^.*$" --category Rust +# Std String +type synthetic add -l lldb_lookup.StdStringSyntheticProvider -x "^(alloc::([a-z_]+::)+)String$" --category Rust +type summary add -F lldb_lookup.StdStringSummaryProvider -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust +# Std str type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?str$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?str$" --category Rust +## MSVC +type synthetic add -l lldb_lookup.MSVCStrSyntheticProvider -x "^ref(_mut)?\$$" --category Rust +type summary add -F lldb_lookup.StdStrSummaryProvider -e -h -x "^ref(_mut)?\$$" --category Rust +# Array type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?\\[.+\\]$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?\\[.+\\]$" --category Rust +# Slice +## MSVC +type synthetic add -l lldb_lookup.MSVCStdSliceSyntheticProvider -x "^ref(_mut)?\$ >" --category Rust +type summary add -F lldb_lookup.StdSliceSummaryProvider -e -x -h "^ref(_mut)?\$ >" --category Rust +# OsString type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust +# Vec type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust +# VecDeque type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust +# BTreeSet type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust +# BTreeMap type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust +# HashMap type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust +# HashSet type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust +# Rc type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust +# Arc type synthetic add -l lldb_lookup.synthetic_lookup -x "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust +# Cell type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust +# RefCell type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust -type synthetic add -l lldb_lookup.synthetic_lookup -x "^(.*)$" --category Rust -type summary add -F _ -e -x -h "^.*$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?str$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?\\[.+\\]$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeSet<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)BTreeMap<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashMap<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::collections::([a-z_]+::)+)HashSet<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Rc<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Arc<.+>$" --category Rust -type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Cell<.+>$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)Ref<.+>$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefMut<.+>$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)RefCell<.+>$" --category Rust +# NonZero +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust +type synthetic add -l lldb_lookup.synthetic_lookup -x "^core::num::([a-z_]+::)*NonZero.+$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(core::([a-z_]+::)+)NonZero<.+>$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^core::num::([a-z_]+::)*NonZero.+$" --category Rust +# PathBuf +type synthetic add -l lldb_lookup.synthetic_lookup -x "^(std::([a-z_]+::)+)PathBuf$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::([a-z_]+::)+)PathBuf$" --category Rust +# Path +type synthetic add -l lldb_lookup.synthetic_lookup -x "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?(std::([a-z_]+::)+)Path$" --category Rust +# Enum +## MSVC +type synthetic add -l lldb_lookup.MSVCEnumSyntheticProvider -x "^enum2\$<.+>$" --category Rust +type summary add -F lldb_lookup.MSVCEnumSummaryProvider -e -x -h "^enum2\$<.+>$" --category Rust +## MSVC Variants +type synthetic add -l lldb_lookup.synthetic_lookup -x "^enum2\$<.+>::.*$" --category Rust +type summary add -F lldb_lookup.summary_lookup -e -x -h "^enum2\$<.+>::.*$" --category Rust +# Tuple +type synthetic add -l lldb_lookup.synthetic_lookup -x "^\(.*\)$" --category Rust +## MSVC +type synthetic add -l lldb_lookup.MSVCTupleSyntheticProvider -x "^tuple\$<.+>$" --category Rust +type summary add -F lldb_lookup.TupleSummaryProvider -e -x -h "^tuple\$<.+>$" --category Rust type category enable Rust diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 2f32ed833af1e..98426e4242398 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,14 +1,19 @@ +from __future__ import annotations import sys +from typing import List, TYPE_CHECKING from lldb import ( SBData, SBError, - SBValue, eBasicTypeLong, eBasicTypeUnsignedLong, eBasicTypeUnsignedChar, + eFormatChar, ) +if TYPE_CHECKING: + from lldb import SBValue, SBType, SBTypeStaticField + # from lldb.formatters import Logger #################################################################################################### @@ -127,6 +132,36 @@ def has_children(self) -> bool: return False +def get_template_args(type_name: str) -> list[str]: + """ + Takes a type name `T, D>` and returns a list of its generic args + `["A", "tuple$", "D"]`. + + String-based replacement for LLDB's `SBType.template_args`, as LLDB is currently unable to + populate this field for targets with PDB debug info. Also useful for manually altering the type + name of generics (e.g. `Vec` -> `Vec<&str>`). + + Each element of the returned list can be looked up for its `SBType` value via + `SBTarget.FindFirstType()` + """ + params = [] + level = 0 + start = 0 + for i, c in enumerate(type_name): + if c == "<": + level += 1 + if level == 1: + start = i + 1 + elif c == ">": + level -= 1 + if level == 0: + params.append(type_name[start:i].strip()) + elif c == "," and level == 1: + params.append(type_name[start:i].strip()) + start = i + 1 + return params + + def SizeSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: return "size=" + str(valobj.GetNumChildren()) @@ -141,11 +176,32 @@ def vec_to_string(vec: SBValue) -> str: ) -def StdStringSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: - # logger = Logger.Logger() - # logger >> "[StdStringSummaryProvider] for " + str(valobj.GetName()) - vec = valobj.GetChildAtIndex(0) - return '"%s"' % vec_to_string(vec) +def StdStringSummaryProvider(valobj, dict): + inner_vec = ( + valobj.GetNonSyntheticValue() + .GetChildMemberWithName("vec") + .GetNonSyntheticValue() + ) + + pointer = ( + inner_vec.GetChildMemberWithName("buf") + .GetChildMemberWithName("inner") + .GetChildMemberWithName("ptr") + .GetChildMemberWithName("pointer") + .GetChildMemberWithName("pointer") + ) + + length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned() + + if length <= 0: + return '""' + error = SBError() + process = pointer.GetProcess() + data = process.ReadMemory(pointer.GetValueAsUnsigned(), length, error) + if error.Success(): + return '"' + data.decode("utf8", "replace") + '"' + else: + raise Exception("ReadMemory error: %s", error.GetCString()) def StdOsStringSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: @@ -205,6 +261,31 @@ def StdPathSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: return '"%s"' % data +def sequence_formatter(output: str, valobj: SBValue, _dict: LLDBOpaque): + length: int = valobj.GetNumChildren() + + long: bool = False + for i in range(0, length): + if len(output) > 32: + long = True + break + + child: SBValue = valobj.GetChildAtIndex(i) + + summary = child.summary + if summary is None: + summary = child.value + if summary is None: + summary = "{...}" + output += f"{summary}, " + if long: + output = f"(len: {length}) " + output + "..." + else: + output = output[:-2] + + return output + + class StructSyntheticProvider: """Pretty-printer for structs and struct enum variants""" @@ -246,6 +327,89 @@ def has_children(self) -> bool: return True +class StdStringSyntheticProvider: + def __init__(self, valobj: SBValue, _dict: LLDBOpaque): + self.valobj = valobj + self.update() + + def update(self): + inner_vec = self.valobj.GetChildMemberWithName("vec").GetNonSyntheticValue() + self.data_ptr = ( + inner_vec.GetChildMemberWithName("buf") + .GetChildMemberWithName("inner") + .GetChildMemberWithName("ptr") + .GetChildMemberWithName("pointer") + .GetChildMemberWithName("pointer") + ) + self.length = inner_vec.GetChildMemberWithName("len").GetValueAsUnsigned() + self.element_type = self.data_ptr.GetType().GetPointeeType() + + def has_children(self) -> bool: + return True + + def num_children(self) -> int: + return self.length + + def get_child_index(self, name: str) -> int: + index = name.lstrip("[").rstrip("]") + if index.isdigit(): + return int(index) + + return -1 + + def get_child_at_index(self, index: int) -> SBValue: + if not 0 <= index < self.length: + return None + start = self.data_ptr.GetValueAsUnsigned() + address = start + index + element = self.data_ptr.CreateValueFromAddress( + f"[{index}]", address, self.element_type + ) + element.SetFormat(eFormatChar) + return element + + +class MSVCStrSyntheticProvider: + __slots__ = ["valobj", "data_ptr", "length"] + + def __init__(self, valobj: SBValue, _dict: LLDBOpaque): + self.valobj = valobj + self.update() + + def update(self): + self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr") + self.length = self.valobj.GetChildMemberWithName("length").GetValueAsUnsigned() + + def has_children(self) -> bool: + return True + + def num_children(self) -> int: + return self.length + + def get_child_index(self, name: str) -> int: + index = name.lstrip("[").rstrip("]") + if index.isdigit(): + return int(index) + + return -1 + + def get_child_at_index(self, index: int) -> SBValue: + if not 0 <= index < self.length: + return None + start = self.data_ptr.GetValueAsUnsigned() + address = start + index + element = self.data_ptr.CreateValueFromAddress( + f"[{index}]", address, self.data_ptr.GetType().GetPointeeType() + ) + return element + + def get_type_name(self): + if self.valobj.GetTypeName().startswith("ref_mut"): + return "&mut str" + else: + return "&str" + + class ClangEncodedEnumProvider: """Pretty-printer for 'clang-encoded' enums support implemented in LLDB""" @@ -308,6 +472,242 @@ def _getCurrentVariantIndex(self, all_variants: SBValue) -> int: return default_index +class MSVCEnumSyntheticProvider: + """ + Synthetic provider for sum-type enums on MSVC. For a detailed explanation of the internals, + see: + + https://github.com/rust-lang/rust/blob/master/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs + """ + + __slots__ = ["valobj", "variant", "value"] + + def __init__(self, valobj: SBValue, _dict: LLDBOpaque): + self.valobj = valobj + self.variant: SBValue + self.value: SBValue + self.update() + + def update(self): + tag: SBValue = self.valobj.GetChildMemberWithName("tag") + + if tag.IsValid(): + tag: int = tag.GetValueAsUnsigned() + for child in self.valobj.GetNonSyntheticValue().children: + if not child.name.startswith("variant"): + continue + + variant_type: SBType = child.GetType() + try: + exact: SBTypeStaticField = variant_type.GetStaticFieldWithName( + "DISCR_EXACT" + ) + except AttributeError: + # LLDB versions prior to 19.0.0 do not have the `SBTypeGetStaticField` API. + # With current DI generation there's not a great way to provide a "best effort" + # evaluation either, so we just return the object itself with no further + # attempts to inspect the type information + self.variant = self.valobj + self.value = self.valobj + return + + if exact.IsValid(): + discr: int = exact.GetConstantValue( + self.valobj.target + ).GetValueAsUnsigned() + if tag == discr: + self.variant = child + self.value = child.GetChildMemberWithName( + "value" + ).GetSyntheticValue() + return + else: # if invalid, DISCR must be a range + begin: int = ( + variant_type.GetStaticFieldWithName("DISCR_BEGIN") + .GetConstantValue(self.valobj.target) + .GetValueAsUnsigned() + ) + end: int = ( + variant_type.GetStaticFieldWithName("DISCR_END") + .GetConstantValue(self.valobj.target) + .GetValueAsUnsigned() + ) + + # begin isn't necessarily smaller than end, so we must test for both cases + if begin < end: + if begin <= tag <= end: + self.variant = child + self.value = child.GetChildMemberWithName( + "value" + ).GetSyntheticValue() + return + else: + if tag >= begin or tag <= end: + self.variant = child + self.value = child.GetChildMemberWithName( + "value" + ).GetSyntheticValue() + return + else: # if invalid, tag is a 128 bit value + tag_lo: int = self.valobj.GetChildMemberWithName( + "tag128_lo" + ).GetValueAsUnsigned() + tag_hi: int = self.valobj.GetChildMemberWithName( + "tag128_hi" + ).GetValueAsUnsigned() + + tag: int = (tag_hi << 64) | tag_lo + + for child in self.valobj.GetNonSyntheticValue().children: + if not child.name.startswith("variant"): + continue + + variant_type: SBType = child.GetType() + exact_lo: SBTypeStaticField = variant_type.GetStaticFieldWithName( + "DISCR128_EXACT_LO" + ) + + if exact_lo.IsValid(): + exact_lo: int = exact_lo.GetConstantValue( + self.valobj.target + ).GetValueAsUnsigned() + exact_hi: int = ( + variant_type.GetStaticFieldWithName("DISCR128_EXACT_HI") + .GetConstantValue(self.valobj.target) + .GetValueAsUnsigned() + ) + + discr: int = (exact_hi << 64) | exact_lo + if tag == discr: + self.variant = child + self.value = child.GetChildMemberWithName( + "value" + ).GetSyntheticValue() + return + else: # if invalid, DISCR must be a range + begin_lo: int = ( + variant_type.GetStaticFieldWithName("DISCR128_BEGIN_LO") + .GetConstantValue(self.valobj.target) + .GetValueAsUnsigned() + ) + begin_hi: int = ( + variant_type.GetStaticFieldWithName("DISCR128_BEGIN_HI") + .GetConstantValue(self.valobj.target) + .GetValueAsUnsigned() + ) + + end_lo: int = ( + variant_type.GetStaticFieldWithName("DISCR128_END_LO") + .GetConstantValue(self.valobj.target) + .GetValueAsUnsigned() + ) + end_hi: int = ( + variant_type.GetStaticFieldWithName("DISCR128_END_HI") + .GetConstantValue(self.valobj.target) + .GetValueAsUnsigned() + ) + + begin = (begin_hi << 64) | begin_lo + end = (end_hi << 64) | end_lo + + # begin isn't necessarily smaller than end, so we must test for both cases + if begin < end: + if begin <= tag <= end: + self.variant = child + self.value = child.GetChildMemberWithName( + "value" + ).GetSyntheticValue() + return + else: + if tag >= begin or tag <= end: + self.variant = child + self.value = child.GetChildMemberWithName( + "value" + ).GetSyntheticValue() + return + + def num_children(self) -> int: + return self.value.GetNumChildren() + + def get_child_index(self, name: str) -> int: + return self.value.GetIndexOfChildWithName(name) + + def get_child_at_index(self, index: int) -> SBValue: + return self.value.GetChildAtIndex(index) + + def has_children(self) -> bool: + return self.value.MightHaveChildren() + + def get_type_name(self) -> str: + name = self.valobj.GetTypeName() + # remove "enum2$<", str.removeprefix() is python 3.9+ + name = name[7:] + + # MSVC misinterprets ">>" as a shift operator, so spaces are inserted by rust to + # avoid that + if name.endswith(" >"): + name = name[:-2] + elif name.endswith(">"): + name = name[:-1] + + return name + + +def MSVCEnumSummaryProvider(valobj: SBValue, _dict: LLDBOpaque) -> str: + enum_synth = MSVCEnumSyntheticProvider(valobj.GetNonSyntheticValue(), _dict) + variant_names: SBType = valobj.target.FindFirstType( + f"{enum_synth.valobj.GetTypeName()}::VariantNames" + ) + try: + name_idx = ( + enum_synth.variant.GetType() + .GetStaticFieldWithName("NAME") + .GetConstantValue(valobj.target) + .GetValueAsUnsigned() + ) + except AttributeError: + # LLDB versions prior to 19 do not have the `SBTypeGetStaticField` API, and have no way + # to determine the value based on the tag field. + tag: SBValue = valobj.GetChildMemberWithName("tag") + + if tag.IsValid(): + discr: int = tag.GetValueAsUnsigned() + return "".join(["{tag = ", str(tag.unsigned), "}"]) + else: + tag_lo: int = valobj.GetChildMemberWithName( + "tag128_lo" + ).GetValueAsUnsigned() + tag_hi: int = valobj.GetChildMemberWithName( + "tag128_hi" + ).GetValueAsUnsigned() + + discr: int = (tag_hi << 64) | tag_lo + + return "".join(["{tag = ", str(discr), "}"]) + + name: str = variant_names.enum_members[name_idx].name + + if enum_synth.num_children() == 0: + return name + + child_name: str = enum_synth.value.GetChildAtIndex(0).name + if child_name == "0" or child_name == "__0": + # enum variant is a tuple struct + return name + TupleSummaryProvider(enum_synth.value, _dict) + else: + # enum variant is a regular struct + var_list = ( + str(enum_synth.value.GetNonSyntheticValue()).split("= ", 1)[1].splitlines() + ) + vars = [x.strip() for x in var_list if x not in ("{", "}")] + if vars[0][0] == "(": + vars[0] = vars[0][1:] + if vars[-1][-1] == ")": + vars[-1] = vars[-1][:-1] + + return f"{name}{{{', '.join(vars)}}}" + + class TupleSyntheticProvider: """Pretty-printer for tuples and tuple enum variants""" @@ -348,6 +748,50 @@ def has_children(self) -> bool: return True +class MSVCTupleSyntheticProvider: + __slots__ = ["valobj"] + + def __init__(self, valobj: SBValue, _dict: LLDBOpaque): + self.valobj = valobj + + def num_children(self) -> int: + return self.valobj.GetNumChildren() + + def get_child_index(self, name: str) -> int: + return self.valobj.GetIndexOfChildWithName(name) + + def get_child_at_index(self, index: int) -> SBValue: + child: SBValue = self.valobj.GetChildAtIndex(index) + return child.CreateChildAtOffset(str(index), 0, child.GetType()) + + def update(self): + pass + + def has_children(self) -> bool: + return self.valobj.MightHaveChildren() + + def get_type_name(self) -> str: + name = self.valobj.GetTypeName() + # remove "tuple$<" and ">", str.removeprefix and str.removesuffix require python 3.9+ + name = name[7:-1] + return "(" + name + ")" + + +def TupleSummaryProvider(valobj: SBValue, _dict: LLDBOpaque): + output: List[str] = [] + + for i in range(0, valobj.GetNumChildren()): + child: SBValue = valobj.GetChildAtIndex(i) + summary = child.summary + if summary is None: + summary = child.value + if summary is None: + summary = "{...}" + output.append(summary) + + return "(" + ", ".join(output) + ")" + + class StdVecSyntheticProvider: """Pretty-printer for alloc::vec::Vec @@ -396,6 +840,11 @@ def update(self): ) self.element_type = self.valobj.GetType().GetTemplateArgumentType(0) + + if not self.element_type.IsValid(): + element_name = get_template_args(self.valobj.GetTypeName())[0] + self.element_type = self.valobj.target.FindFirstType(element_name) + self.element_type_size = self.element_type.GetByteSize() def has_children(self) -> bool: @@ -403,6 +852,8 @@ def has_children(self) -> bool: class StdSliceSyntheticProvider: + __slots__ = ["valobj", "length", "data_ptr", "element_type", "element_size"] + def __init__(self, valobj: SBValue, _dict: LLDBOpaque): self.valobj = valobj self.update() @@ -419,7 +870,7 @@ def get_child_index(self, name: str) -> int: def get_child_at_index(self, index: int) -> SBValue: start = self.data_ptr.GetValueAsUnsigned() - address = start + index * self.element_type_size + address = start + index * self.element_size element = self.data_ptr.CreateValueFromAddress( "[%s]" % index, address, self.element_type ) @@ -430,12 +881,34 @@ def update(self): self.data_ptr = self.valobj.GetChildMemberWithName("data_ptr") self.element_type = self.data_ptr.GetType().GetPointeeType() - self.element_type_size = self.element_type.GetByteSize() + self.element_size = self.element_type.GetByteSize() def has_children(self) -> bool: return True +class MSVCStdSliceSyntheticProvider(StdSliceSyntheticProvider): + def get_type_name(self) -> str: + name = self.valobj.GetTypeName() + + if name.startswith("ref_mut"): + # remove "ref_mut$ >" + name = name[17:-3] + ref = "&mut " + else: + # remove "ref$ >" + name = name[13:-3] + ref = "&" + + return "".join([ref, "[", name, "]"]) + + +def StdSliceSummaryProvider(valobj, dict): + output = sequence_formatter("[", valobj, dict) + output += "]" + return output + + class StdVecDequeSyntheticProvider: """Pretty-printer for alloc::collections::vec_deque::VecDeque @@ -627,7 +1100,16 @@ def update(self): ctrl = inner_table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) self.size = inner_table.GetChildMemberWithName("items").GetValueAsUnsigned() - self.pair_type = table.type.template_args[0] + + template_args = table.type.template_args + + if template_args is None: + type_name = table.GetTypeName() + args = get_template_args(type_name) + self.pair_type = self.valobj.target.FindFirstType(args[0]) + else: + self.pair_type = template_args[0] + if self.pair_type.IsTypedefType(): self.pair_type = self.pair_type.GetTypedefedType() self.pair_type_size = self.pair_type.GetByteSize() diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh index 6f86c7ab8a448..7bacc943f258b 100755 --- a/src/etc/pre-push.sh +++ b/src/etc/pre-push.sh @@ -7,6 +7,20 @@ set -Euo pipefail +# Check if the push is doing anything other than deleting remote branches +SKIP=true +while read LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA; do + if [[ "$LOCAL_REF" != "(delete)" || \ + "$LOCAL_SHA" != "0000000000000000000000000000000000000000" ]]; then + SKIP=false + fi +done + +if $SKIP; then + echo "Skipping tidy check for branch deletion" + exit 0 +fi + ROOT_DIR="$(git rev-parse --show-toplevel)" echo "Running pre-push script $ROOT_DIR/x test tidy" diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el index 7b4309f8e188f..6b40371d9af11 100644 --- a/src/etc/rust_analyzer_eglot.el +++ b/src/etc/rust_analyzer_eglot.el @@ -8,7 +8,6 @@ "check" "--json-output"]) :linkedProjects ["Cargo.toml" - "src/tools/x/Cargo.toml" "src/bootstrap/Cargo.toml" "src/tools/rust-analyzer/Cargo.toml" "compiler/rustc_codegen_cranelift/Cargo.toml" diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml index afddd089eb168..05fc7716a7252 100644 --- a/src/etc/rust_analyzer_helix.toml +++ b/src/etc/rust_analyzer_helix.toml @@ -15,7 +15,6 @@ linkedProjects = [ "library/Cargo.toml", "src/bootstrap/Cargo.toml", "src/tools/rust-analyzer/Cargo.toml", - "src/tools/x/Cargo.toml", ] [language-server.rust-analyzer.config.check] diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index b104356d44cb5..da7d326a512cc 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -10,7 +10,6 @@ "rust-analyzer.linkedProjects": [ "Cargo.toml", "library/Cargo.toml", - "src/tools/x/Cargo.toml", "src/bootstrap/Cargo.toml", "src/tools/rust-analyzer/Cargo.toml", "compiler/rustc_codegen_cranelift/Cargo.toml", diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json index 469ea0506218f..abc6ddbc213c4 100644 --- a/src/etc/rust_analyzer_zed.json +++ b/src/etc/rust_analyzer_zed.json @@ -22,7 +22,6 @@ "linkedProjects": [ "Cargo.toml", "library/Cargo.toml", - "src/tools/x/Cargo.toml", "src/bootstrap/Cargo.toml", "src/tools/rust-analyzer/Cargo.toml", "compiler/rustc_codegen_cranelift/Cargo.toml", diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index 56cb5cddeea52..bacb9e09f3f6a 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -7,8 +7,8 @@ publish = false [dependencies] indicatif = { version = "0.17.8", default-features = false } num = "0.4.3" -rand = "0.8.5" -rand_chacha = "0.3" +rand = "0.9.0" +rand_chacha = "0.9.0" rayon = "1" [lib] diff --git a/src/etc/test-float-parse/src/gen/exhaustive.rs b/src/etc/test-float-parse/src/gen/exhaustive.rs index 5d4b6df8e59b9..01458fb0b6084 100644 --- a/src/etc/test-float-parse/src/gen/exhaustive.rs +++ b/src/etc/test-float-parse/src/gen/exhaustive.rs @@ -13,13 +13,12 @@ impl Generator for Exhaustive where RangeInclusive: Iterator, { - const NAME: &'static str = "exhaustive"; const SHORT_NAME: &'static str = "exhaustive"; type WriteCtx = F; fn total_tests() -> u64 { - F::Int::MAX.try_into().unwrap_or(u64::MAX) + 1u64.checked_shl(F::Int::BITS).expect("More than u64::MAX tests") } fn new() -> Self { diff --git a/src/etc/test-float-parse/src/gen/fuzz.rs b/src/etc/test-float-parse/src/gen/fuzz.rs index 0c63e8aae26ea..1d6c5562a14c8 100644 --- a/src/etc/test-float-parse/src/gen/fuzz.rs +++ b/src/etc/test-float-parse/src/gen/fuzz.rs @@ -6,7 +6,7 @@ use std::ops::Range; use std::sync::Mutex; use rand::Rng; -use rand::distributions::{Distribution, Standard}; +use rand::distr::{Distribution, StandardUniform}; use rand_chacha::ChaCha8Rng; use rand_chacha::rand_core::SeedableRng; @@ -47,9 +47,8 @@ impl Fuzz { impl Generator for Fuzz where - Standard: Distribution<::Int>, + StandardUniform: Distribution<::Int>, { - const NAME: &'static str = "fuzz"; const SHORT_NAME: &'static str = "fuzz"; type WriteCtx = F; @@ -75,13 +74,13 @@ where impl Iterator for Fuzz where - Standard: Distribution<::Int>, + StandardUniform: Distribution<::Int>, { type Item = >::WriteCtx; fn next(&mut self) -> Option { let _ = self.iter.next()?; - let i: F::Int = self.rng.gen(); + let i: F::Int = self.rng.random(); Some(F::from_bits(i)) } diff --git a/src/etc/test-float-parse/src/gen/many_digits.rs b/src/etc/test-float-parse/src/gen/many_digits.rs index aab8d5d704bec..741e11437fe29 100644 --- a/src/etc/test-float-parse/src/gen/many_digits.rs +++ b/src/etc/test-float-parse/src/gen/many_digits.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use std::marker::PhantomData; use std::ops::{Range, RangeInclusive}; -use rand::distributions::{Distribution, Uniform}; +use rand::distr::{Distribution, Uniform}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; @@ -40,7 +40,7 @@ impl Generator for RandDigits { fn new() -> Self { let rng = ChaCha8Rng::from_seed(SEED); - let range = Uniform::from(0..10); + let range = Uniform::try_from(0..10).unwrap(); Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData } } @@ -55,11 +55,11 @@ impl Iterator for RandDigits { fn next(&mut self) -> Option { let _ = self.iter.next()?; - let num_digits = self.rng.gen_range(POSSIBLE_NUM_DIGITS); - let has_decimal = self.rng.gen_bool(0.2); - let has_exp = self.rng.gen_bool(0.2); + let num_digits = self.rng.random_range(POSSIBLE_NUM_DIGITS); + let has_decimal = self.rng.random_bool(0.2); + let has_exp = self.rng.random_bool(0.2); - let dec_pos = if has_decimal { Some(self.rng.gen_range(0..num_digits)) } else { None }; + let dec_pos = if has_decimal { Some(self.rng.random_range(0..num_digits)) } else { None }; let mut s = String::with_capacity(num_digits); @@ -75,7 +75,7 @@ impl Iterator for RandDigits { } if has_exp { - let exp = self.rng.gen_range(EXP_RANGE); + let exp = self.rng.random_range(EXP_RANGE); write!(s, "e{exp}").unwrap(); } diff --git a/src/etc/test-float-parse/src/gen/sparse.rs b/src/etc/test-float-parse/src/gen/sparse.rs index 389b71056a3e5..72b65d4ce7f10 100644 --- a/src/etc/test-float-parse/src/gen/sparse.rs +++ b/src/etc/test-float-parse/src/gen/sparse.rs @@ -35,7 +35,6 @@ impl Generator for FewOnesInt where >::Error: std::fmt::Debug, { - const NAME: &'static str = "few ones int"; const SHORT_NAME: &'static str = "few ones int"; type WriteCtx = F::Int; diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs index 3c71b0dc32e74..e2f84b085c6f5 100644 --- a/src/etc/test-float-parse/src/lib.rs +++ b/src/etc/test-float-parse/src/lib.rs @@ -2,19 +2,19 @@ mod traits; mod ui; mod validate; -use std::any::{TypeId, type_name}; +use std::any::type_name; use std::cmp::min; use std::ops::RangeInclusive; use std::process::ExitCode; +use std::sync::OnceLock; use std::sync::atomic::{AtomicU64, Ordering}; -use std::sync::{OnceLock, mpsc}; use std::{fmt, time}; -use indicatif::{MultiProgress, ProgressBar}; -use rand::distributions::{Distribution, Standard}; +use rand::distr::{Distribution, StandardUniform}; use rayon::prelude::*; use time::{Duration, Instant}; use traits::{Float, Generator, Int}; +use validate::CheckError; /// Test generators. mod gen { @@ -43,7 +43,7 @@ const HUGE_TEST_CUTOFF: u64 = 5_000_000; /// Seed for tests that use a deterministic RNG. const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; -/// Global configuration +/// Global configuration. #[derive(Debug)] pub struct Config { pub timeout: Duration, @@ -104,9 +104,9 @@ pub fn run(cfg: Config, include: &[String], exclude: &[String]) -> ExitCode { println!("Skipping test '{exc}'"); } - println!("launching"); + println!("Launching all"); let elapsed = launch_tests(&mut tests, &cfg); - ui::finish(&tests, elapsed, &cfg) + ui::finish_all(&tests, elapsed, &cfg) } /// Enumerate tests to run but don't actually run them. @@ -132,7 +132,7 @@ fn register_float(tests: &mut Vec, cfg: &Config) where RangeInclusive: Iterator, >::Error: std::fmt::Debug, - Standard: Distribution<::Int>, + StandardUniform: Distribution<::Int>, { if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE { // Only run exhaustive tests if there is a chance of completion. @@ -160,18 +160,18 @@ where #[derive(Debug)] pub struct TestInfo { pub name: String, - /// Tests are identified by the type ID of `(F, G)` (tuple of the float and generator type). - /// This gives an easy way to associate messages with tests. - id: TypeId, float_name: &'static str, + float_bits: u32, gen_name: &'static str, /// Name for display in the progress bar. short_name: String, + /// Pad the short name to a common width for progress bar use. + short_name_padded: String, total_tests: u64, /// Function to launch this test. - launch: fn(&mpsc::Sender, &TestInfo, &Config), + launch: fn(&TestInfo, &Config), /// Progress bar to be updated. - pb: Option, + progress: Option, /// Once completed, this will be set. completed: OnceLock, } @@ -187,14 +187,18 @@ impl TestInfo { let f_name = type_name::(); let gen_name = G::NAME; let gen_short_name = G::SHORT_NAME; + let name = format!("{f_name} {gen_name}"); + let short_name = format!("{f_name} {gen_short_name}"); + let short_name_padded = format!("{short_name:18}"); let info = TestInfo { - id: TypeId::of::<(F, G)>(), float_name: f_name, + float_bits: F::BITS, gen_name, - pb: None, - name: format!("{f_name} {gen_name}"), - short_name: format!("{f_name} {gen_short_name}"), + progress: None, + name, + short_name_padded, + short_name, launch: test_runner::, total_tests: G::total_tests(), completed: OnceLock::new(), @@ -202,106 +206,18 @@ impl TestInfo { v.push(info); } - /// Pad the short name to a common width for progress bar use. - fn short_name_padded(&self) -> String { - format!("{:18}", self.short_name) - } - - /// Create a progress bar for this test within a multiprogress bar. - fn register_pb(&mut self, mp: &MultiProgress, drop_bars: &mut Vec) { - self.pb = Some(ui::create_pb(mp, self.total_tests, &self.short_name_padded(), drop_bars)); - } - - /// When the test is finished, update progress bar messages and finalize. - fn finalize_pb(&self, c: &Completed) { - let pb = self.pb.as_ref().unwrap(); - ui::finalize_pb(pb, &self.short_name_padded(), c); - } - /// True if this should be run after all others. fn is_huge_test(&self) -> bool { self.total_tests >= HUGE_TEST_CUTOFF } -} - -/// A message sent from test runner threads to the UI/log thread. -#[derive(Clone, Debug)] -struct Msg { - id: TypeId, - update: Update, -} -impl Msg { - /// Wrap an `Update` into a message for the specified type. We use the `TypeId` of `(F, G)` to - /// identify which test a message in the channel came from. - fn new>(u: Update) -> Self { - Self { id: TypeId::of::<(F, G)>(), update: u } - } - - /// Get the matching test from a list. Panics if not found. - fn find_test<'a>(&self, tests: &'a [TestInfo]) -> &'a TestInfo { - tests.iter().find(|t| t.id == self.id).unwrap() - } - - /// Update UI as needed for a single message received from the test runners. - fn handle(self, tests: &[TestInfo], mp: &MultiProgress) { - let test = self.find_test(tests); - let pb = test.pb.as_ref().unwrap(); - - match self.update { - Update::Started => { - mp.println(format!("Testing '{}'", test.name)).unwrap(); - } - Update::Progress { executed, failures } => { - pb.set_message(format! {"{failures}"}); - pb.set_position(executed); - } - Update::Failure { fail, input, float_res } => { - mp.println(format!( - "Failure in '{}': {fail}. parsing '{input}'. Parsed as: {float_res}", - test.name - )) - .unwrap(); - } - Update::Completed(c) => { - test.finalize_pb(&c); - - let prefix = match c.result { - Ok(FinishedAll) => "Completed tests for", - Err(EarlyExit::Timeout) => "Timed out", - Err(EarlyExit::MaxFailures) => "Max failures reached for", - }; - - mp.println(format!( - "{prefix} generator '{}' in {:?}. {} tests run, {} failures", - test.name, c.elapsed, c.executed, c.failures - )) - .unwrap(); - test.completed.set(c).unwrap(); - } - }; + /// When the test is finished, update progress bar messages and finalize. + fn complete(&self, c: Completed) { + self.progress.as_ref().unwrap().complete(&c, 0); + self.completed.set(c).unwrap(); } } -/// Status sent with a message. -#[derive(Clone, Debug)] -enum Update { - /// Starting a new test runner. - Started, - /// Completed a out of b tests. - Progress { executed: u64, failures: u64 }, - /// Received a failed test. - Failure { - fail: CheckFailure, - /// String for which parsing was attempted. - input: Box, - /// The parsed & decomposed `FloatRes`, already stringified so we don't need generics here. - float_res: Box, - }, - /// Exited with an unexpected condition. - Completed(Completed), -} - /// Result of an input did not parsing successfully. #[derive(Clone, Debug)] enum CheckFailure { @@ -329,6 +245,10 @@ enum CheckFailure { /// two representable values. incorrect_midpoint_rounding: bool, }, + /// String did not parse successfully. + ParsingFailed(Box), + /// A panic was caught. + Panic(Box), } impl fmt::Display for CheckFailure { @@ -363,6 +283,8 @@ impl fmt::Display for CheckFailure { } Ok(()) } + CheckFailure::ParsingFailed(e) => write!(f, "parsing failed: {e}"), + CheckFailure::Panic(e) => write!(f, "function panicked: {e}"), } } } @@ -398,55 +320,21 @@ enum EarlyExit { /// This launches a main thread that receives messages and handlees UI updates, and uses the /// rest of the thread pool to execute the tests. fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration { - // Run shorter tests first - tests.sort_unstable_by_key(|test| test.total_tests); + // Run shorter tests and smaller float types first. + tests.sort_unstable_by_key(|test| (test.total_tests, test.float_bits)); for test in tests.iter() { println!("Launching test '{}'", test.name); } - // Configure progress bars let mut all_progress_bars = Vec::new(); - let mp = MultiProgress::new(); - mp.set_move_cursor(true); - for test in tests.iter_mut() { - test.register_pb(&mp, &mut all_progress_bars); - } - - ui::set_panic_hook(all_progress_bars); - - let (tx, rx) = mpsc::channel::(); let start = Instant::now(); - rayon::scope(|scope| { - // Thread that updates the UI - scope.spawn(|_scope| { - let rx = rx; // move rx - - loop { - if tests.iter().all(|t| t.completed.get().is_some()) { - break; - } - - let msg = rx.recv().unwrap(); - msg.handle(tests, &mp); - } - - // All tests completed; finish things up - drop(mp); - assert_eq!(rx.try_recv().unwrap_err(), mpsc::TryRecvError::Empty); - }); - - // Don't let the thread pool be starved by huge tests. Run faster tests first in parallel, - // then parallelize only within the rest of the tests. - let (huge_tests, normal_tests): (Vec<_>, Vec<_>) = - tests.iter().partition(|t| t.is_huge_test()); - - // Run the actual tests - normal_tests.par_iter().for_each(|test| ((test.launch)(&tx, test, cfg))); - - huge_tests.par_iter().for_each(|test| ((test.launch)(&tx, test, cfg))); - }); + for test in tests.iter_mut() { + test.progress = Some(ui::Progress::new(test, &mut all_progress_bars)); + ui::set_panic_hook(&all_progress_bars); + ((test.launch)(test, cfg)); + } start.elapsed() } @@ -454,15 +342,12 @@ fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration { /// Test runer for a single generator. /// /// This calls the generator's iterator multiple times (in parallel) and validates each output. -fn test_runner>(tx: &mpsc::Sender, _info: &TestInfo, cfg: &Config) { - tx.send(Msg::new::(Update::Started)).unwrap(); - - let total = G::total_tests(); +fn test_runner>(test: &TestInfo, cfg: &Config) { let gen = G::new(); let executed = AtomicU64::new(0); let failures = AtomicU64::new(0); - let checks_per_update = min(total, 1000); + let checks_per_update = min(test.total_tests, 1000); let started = Instant::now(); // Function to execute for a single test iteration. @@ -474,7 +359,12 @@ fn test_runner>(tx: &mpsc::Sender, _info: &TestIn match validate::validate::(buf) { Ok(()) => (), Err(e) => { - tx.send(Msg::new::(e)).unwrap(); + let CheckError { fail, input, float_res } = e; + test.progress.as_ref().unwrap().println(&format!( + "Failure in '{}': {fail}. parsing '{input}'. Parsed as: {float_res}", + test.name + )); + let f = failures.fetch_add(1, Ordering::Relaxed); // End early if the limit is exceeded. if f >= cfg.max_failures { @@ -486,9 +376,7 @@ fn test_runner>(tx: &mpsc::Sender, _info: &TestIn // Send periodic updates if executed % checks_per_update == 0 { let failures = failures.load(Ordering::Relaxed); - - tx.send(Msg::new::(Update::Progress { executed, failures })).unwrap(); - + test.progress.as_ref().unwrap().update(executed, failures); if started.elapsed() > cfg.timeout { return Err(EarlyExit::Timeout); } @@ -499,15 +387,19 @@ fn test_runner>(tx: &mpsc::Sender, _info: &TestIn // Run the test iterations in parallel. Each thread gets a string buffer to write // its check values to. - let res = gen.par_bridge().try_for_each_init(|| String::with_capacity(100), check_one); + let res = gen.par_bridge().try_for_each_init(String::new, check_one); let elapsed = started.elapsed(); let executed = executed.into_inner(); let failures = failures.into_inner(); // Warn about bad estimates if relevant. - let warning = if executed != total && res.is_ok() { - let msg = format!("executed tests != estimated ({executed} != {total}) for {}", G::NAME); + let warning = if executed != test.total_tests && res.is_ok() { + let msg = format!( + "executed tests != estimated ({executed} != {}) for {}", + test.total_tests, + G::NAME + ); Some(msg.into()) } else { @@ -515,12 +407,5 @@ fn test_runner>(tx: &mpsc::Sender, _info: &TestIn }; let result = res.map(|()| FinishedAll); - tx.send(Msg::new::(Update::Completed(Completed { - executed, - failures, - result, - warning, - elapsed, - }))) - .unwrap(); + test.complete(Completed { executed, failures, result, warning, elapsed }); } diff --git a/src/etc/test-float-parse/src/traits.rs b/src/etc/test-float-parse/src/traits.rs index f5333d63b3693..57e702b7d0913 100644 --- a/src/etc/test-float-parse/src/traits.rs +++ b/src/etc/test-float-parse/src/traits.rs @@ -147,12 +147,12 @@ pub trait Float: } macro_rules! impl_float { - ($($fty:ty, $ity:ty, $bits:literal);+) => { + ($($fty:ty, $ity:ty);+) => { $( impl Float for $fty { type Int = $ity; type SInt = ::Signed; - const BITS: u32 = $bits; + const BITS: u32 = <$ity>::BITS; const MAN_BITS: u32 = Self::MANTISSA_DIGITS - 1; const MAN_MASK: Self::Int = (Self::Int::ONE << Self::MAN_BITS) - Self::Int::ONE; const SIGN_MASK: Self::Int = Self::Int::ONE << (Self::BITS-1); @@ -168,7 +168,7 @@ macro_rules! impl_float { } } -impl_float!(f32, u32, 32; f64, u64, 64); +impl_float!(f32, u32; f64, u64); /// A test generator. Should provide an iterator that produces unique patterns to parse. /// @@ -177,7 +177,7 @@ impl_float!(f32, u32, 32; f64, u64, 64); /// allocations (which otherwise turn out to be a pretty expensive part of these tests). pub trait Generator: Iterator + Send + 'static { /// Full display and filtering name - const NAME: &'static str; + const NAME: &'static str = Self::SHORT_NAME; /// Name for display with the progress bar const SHORT_NAME: &'static str; diff --git a/src/etc/test-float-parse/src/ui.rs b/src/etc/test-float-parse/src/ui.rs index f333bd4a55dc9..1ee57723e6a62 100644 --- a/src/etc/test-float-parse/src/ui.rs +++ b/src/etc/test-float-parse/src/ui.rs @@ -1,67 +1,92 @@ //! Progress bars and such. +use std::any::type_name; +use std::fmt; use std::io::{self, Write}; use std::process::ExitCode; use std::time::Duration; -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; +use indicatif::{ProgressBar, ProgressStyle}; use crate::{Completed, Config, EarlyExit, FinishedAll, TestInfo}; /// Templates for progress bars. -const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME ({pos}/{len}, {msg} f, {per_sec}, eta {eta})"; -const PB_TEMPLATE_FINAL: &str = - "[{elapsed:3} {percent:3}%] NAME ({pos}/{len}, {msg:.COLOR}, {per_sec}, {elapsed_precise})"; - -/// Create a new progress bar within a multiprogress bar. -pub fn create_pb( - mp: &MultiProgress, - total_tests: u64, - short_name_padded: &str, - all_bars: &mut Vec, -) -> ProgressBar { - let pb = mp.add(ProgressBar::new(total_tests)); - let pb_style = ProgressStyle::with_template(&PB_TEMPLATE.replace("NAME", short_name_padded)) - .unwrap() - .progress_chars("##-"); - - pb.set_style(pb_style.clone()); - pb.set_message("0"); - all_bars.push(pb.clone()); - pb +const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>8}/{human_len:8} {msg} f {per_sec:14} eta {eta:8}"; +const PB_TEMPLATE_FINAL: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME \ + {human_pos:>8}/{human_len:8} {msg:.COLOR} {per_sec:18} {elapsed_precise}"; + +/// Thin abstraction over our usage of a `ProgressBar`. +#[derive(Debug)] +pub struct Progress { + pb: ProgressBar, + make_final_style: NoDebug ProgressStyle + Sync>>, } -/// Removes the status bar and replace it with a message. -pub fn finalize_pb(pb: &ProgressBar, short_name_padded: &str, c: &Completed) { - let f = c.failures; +impl Progress { + /// Create a new progress bar within a multiprogress bar. + pub fn new(test: &TestInfo, all_bars: &mut Vec) -> Self { + let initial_template = PB_TEMPLATE.replace("NAME", &test.short_name_padded); + let final_template = PB_TEMPLATE_FINAL.replace("NAME", &test.short_name_padded); + let initial_style = + ProgressStyle::with_template(&initial_template).unwrap().progress_chars("##-"); + let make_final_style = move |color| { + ProgressStyle::with_template(&final_template.replace("COLOR", color)) + .unwrap() + .progress_chars("##-") + }; - // Use a tuple so we can use colors - let (color, msg, finish_pb): (&str, String, fn(&ProgressBar, String)) = match &c.result { - Ok(FinishedAll) if f > 0 => { - ("red", format!("{f} f (finished with errors)",), ProgressBar::finish_with_message) - } - Ok(FinishedAll) => { - ("green", format!("{f} f (finished successfully)",), ProgressBar::finish_with_message) - } - Err(EarlyExit::Timeout) => { - ("red", format!("{f} f (timed out)"), ProgressBar::abandon_with_message) + let pb = ProgressBar::new(test.total_tests); + pb.set_style(initial_style); + pb.set_length(test.total_tests); + pb.set_message("0"); + all_bars.push(pb.clone()); + + Progress { pb, make_final_style: NoDebug(Box::new(make_final_style)) } + } + + /// Completed a out of b tests. + pub fn update(&self, completed: u64, failures: u64) { + // Infrequently update the progress bar. + if completed % 5_000 == 0 || failures > 0 { + self.pb.set_position(completed); } - Err(EarlyExit::MaxFailures) => { - ("red", format!("{f} f (failure limit)"), ProgressBar::abandon_with_message) + + if failures > 0 { + self.pb.set_message(format! {"{failures}"}); } - }; + } + + /// Finalize the progress bar. + pub fn complete(&self, c: &Completed, real_total: u64) { + let f = c.failures; + let (color, msg, finish_fn): (&str, String, fn(&ProgressBar)) = match &c.result { + Ok(FinishedAll) if f > 0 => { + ("red", format!("{f} f (completed with errors)",), ProgressBar::finish) + } + Ok(FinishedAll) => { + ("green", format!("{f} f (completed successfully)",), ProgressBar::finish) + } + Err(EarlyExit::Timeout) => ("red", format!("{f} f (timed out)"), ProgressBar::abandon), + Err(EarlyExit::MaxFailures) => { + ("red", format!("{f} f (failure limit)"), ProgressBar::abandon) + } + }; - let pb_style = ProgressStyle::with_template( - &PB_TEMPLATE_FINAL.replace("NAME", short_name_padded).replace("COLOR", color), - ) - .unwrap(); + self.pb.set_position(real_total); + self.pb.set_style(self.make_final_style.0(color)); + self.pb.set_message(msg); + finish_fn(&self.pb); + } - pb.set_style(pb_style); - finish_pb(pb, msg); + /// Print a message to stdout above the current progress bar. + pub fn println(&self, msg: &str) { + self.pb.suspend(|| println!("{msg}")); + } } /// Print final messages after all tests are complete. -pub fn finish(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> ExitCode { +pub fn finish_all(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> ExitCode { println!("\n\nResults:"); let mut failed_generators = 0; @@ -118,8 +143,9 @@ pub fn finish(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> Exit /// indicatif likes to eat panic messages. This workaround isn't ideal, but it improves things. /// . -pub fn set_panic_hook(drop_bars: Vec) { +pub fn set_panic_hook(drop_bars: &[ProgressBar]) { let hook = std::panic::take_hook(); + let drop_bars = drop_bars.to_owned(); std::panic::set_hook(Box::new(move |info| { for bar in &drop_bars { bar.abandon(); @@ -130,3 +156,13 @@ pub fn set_panic_hook(drop_bars: Vec) { hook(info); })); } + +/// Allow non-Debug items in a `derive(Debug)` struct`. +#[derive(Clone)] +struct NoDebug(T); + +impl fmt::Debug for NoDebug { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(type_name::()) + } +} diff --git a/src/etc/test-float-parse/src/validate.rs b/src/etc/test-float-parse/src/validate.rs index 1eb3699cfb9f7..40dda274e3b86 100644 --- a/src/etc/test-float-parse/src/validate.rs +++ b/src/etc/test-float-parse/src/validate.rs @@ -1,6 +1,6 @@ //! Everything related to verifying that parsed outputs are correct. -use std::any::type_name; +use std::any::{Any, type_name}; use std::collections::BTreeMap; use std::ops::RangeInclusive; use std::str::FromStr; @@ -9,7 +9,7 @@ use std::sync::LazyLock; use num::bigint::ToBigInt; use num::{BigInt, BigRational, FromPrimitive, Signed, ToPrimitive}; -use crate::{CheckFailure, Float, Int, Update}; +use crate::{CheckFailure, Float, Int}; /// Powers of two that we store for constants. Account for binary128 which has a 15-bit exponent. const POWERS_OF_TWO_RANGE: RangeInclusive = (-(2 << 15))..=(2 << 15); @@ -89,10 +89,16 @@ impl Constants { } /// Validate that a string parses correctly -pub fn validate(input: &str) -> Result<(), Update> { - let parsed: F = input - .parse() - .unwrap_or_else(|e| panic!("parsing failed for {}: {e}. Input: {input}", type_name::())); +pub fn validate(input: &str) -> Result<(), CheckError> { + // Catch panics in case debug assertions within `std` fail. + let parsed = std::panic::catch_unwind(|| { + input.parse::().map_err(|e| CheckError { + fail: CheckFailure::ParsingFailed(e.to_string().into()), + input: input.into(), + float_res: "none".into(), + }) + }) + .map_err(|e| convert_panic_error(&e, input))??; // Parsed float, decoded into significand and exponent let decoded = decode(parsed); @@ -104,6 +110,21 @@ pub fn validate(input: &str) -> Result<(), Update> { decoded.check(rational, input) } +/// Turn panics into concrete error types. +fn convert_panic_error(e: &dyn Any, input: &str) -> CheckError { + let msg = e + .downcast_ref::() + .map(|s| s.as_str()) + .or_else(|| e.downcast_ref::<&str>().copied()) + .unwrap_or("(no contents)"); + + CheckError { + fail: CheckFailure::Panic(msg.into()), + input: input.into(), + float_res: "none".into(), + } +} + /// The result of parsing a string to a float type. #[derive(Clone, Copy, Debug, PartialEq)] pub enum FloatRes { @@ -118,10 +139,19 @@ pub enum FloatRes { }, } +#[derive(Clone, Debug)] +pub struct CheckError { + pub fail: CheckFailure, + /// String for which parsing was attempted. + pub input: Box, + /// The parsed & decomposed `FloatRes`, already stringified so we don't need generics here. + pub float_res: Box, +} + impl FloatRes { /// Given a known exact rational, check that this representation is accurate within the /// limits of the float representation. If not, construct a failure `Update` to send. - fn check(self, expected: Rational, input: &str) -> Result<(), Update> { + fn check(self, expected: Rational, input: &str) -> Result<(), CheckError> { let consts = F::constants(); // let bool_helper = |cond: bool, err| cond.then_some(()).ok_or(err); @@ -173,7 +203,7 @@ impl FloatRes { (Rational::Finite(r), FloatRes::Real { sig, exp }) => Self::validate_real(r, sig, exp), }; - res.map_err(|fail| Update::Failure { + res.map_err(|fail| CheckError { fail, input: input.into(), float_res: format!("{self:?}").into(), diff --git a/src/gcc b/src/gcc index fd3498bff0b93..48664a6cab29d 160000 --- a/src/gcc +++ b/src/gcc @@ -1 +1 @@ -Subproject commit fd3498bff0b939dda91d56960acc33d55f2f9cdf +Subproject commit 48664a6cab29d48138ffa004b7978d52ef73e3ac diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index c07cc4dc347aa..909b81a723b48 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustdoc" version = "0.0.0" -edition = "2021" +edition = "2024" build = "build.rs" [lib] @@ -15,6 +15,7 @@ itertools = "0.12" indexmap = "2" minifier = { version = "0.3.5", default-features = false } pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } +pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } serde_json = "1.0" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 185898c31b75b..6ace626fdcd93 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -2,8 +2,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; use rustc_hir as hir; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::bug; -use rustc_middle::ty::fold::fold_regions; -use rustc_middle::ty::{self, Region, Ty}; +use rustc_middle::ty::{self, Region, Ty, fold_regions}; use rustc_span::def_id::DefId; use rustc_span::symbol::{Symbol, kw}; use rustc_trait_selection::traits::auto_trait::{self, RegionTarget}; diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index bec7fbe8f52bd..ab169f3c2a4d5 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -48,12 +48,12 @@ impl Cfg { exclude: &FxHashSet, ) -> Result, InvalidCfgError> { match nested_cfg { - MetaItemInner::MetaItem(ref cfg) => Cfg::parse_without(cfg, exclude), + MetaItemInner::MetaItem(cfg) => Cfg::parse_without(cfg, exclude), MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => match *b { true => Ok(Some(Cfg::True)), false => Ok(Some(Cfg::False)), }, - MetaItemInner::Lit(ref lit) => { + MetaItemInner::Lit(lit) => { Err(InvalidCfgError { msg: "unexpected literal", span: lit.span }) } } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index e10a74221ae2e..e973b89b2375b 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -181,7 +181,7 @@ pub(crate) fn try_inline_glob( .filter_map(|child| child.res.opt_def_id()) .filter(|def_id| !cx.tcx.is_doc_hidden(def_id)) .collect(); - let attrs = cx.tcx.hir().attrs(import.hir_id()); + let attrs = cx.tcx.hir_attrs(import.hir_id()); let mut items = build_module_items( cx, did, @@ -455,7 +455,7 @@ pub(crate) fn build_impl( } let impl_item = match did.as_local() { - Some(did) => match &tcx.hir().expect_item(did).kind { + Some(did) => match &tcx.hir_expect_item(did).kind { hir::ItemKind::Impl(impl_) => Some(impl_), _ => panic!("`DefID` passed to `build_impl` is not an `impl"), }, @@ -563,11 +563,13 @@ pub(crate) fn build_impl( // Return if the trait itself or any types of the generic parameters are doc(hidden). let mut stack: Vec<&Type> = vec![&for_]; - if let Some(did) = trait_.as_ref().map(|t| t.def_id()) { - if !document_hidden && tcx.is_doc_hidden(did) { - return; - } + if let Some(did) = trait_.as_ref().map(|t| t.def_id()) + && !document_hidden + && tcx.is_doc_hidden(did) + { + return; } + if let Some(generics) = trait_.as_ref().and_then(|t| t.generics()) { stack.extend(generics); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index dcc5fd12d81bf..929402d41707e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -112,7 +112,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< items.extend(doc.inlined_foreigns.iter().flat_map(|((_, renamed), (res, local_import_id))| { let Some(def_id) = res.opt_def_id() else { return Vec::new() }; let name = renamed.unwrap_or_else(|| cx.tcx.item_name(def_id)); - let import = cx.tcx.hir().expect_item(*local_import_id); + let import = cx.tcx.hir_expect_item(*local_import_id); match import.kind { hir::ItemKind::Use(path, kind) => { let hir::UsePath { segments, span, .. } = *path; @@ -125,7 +125,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< items.extend(doc.items.values().flat_map(|(item, renamed, _)| { // Now we actually lower the imports, skipping everything else. if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { - let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); + let name = renamed.unwrap_or_else(|| cx.tcx.hir_name(item.hir_id())); clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) } else { // skip everything else @@ -231,7 +231,7 @@ fn clean_generic_bound<'tcx>( GenericBound::TraitBound(clean_poly_trait_ref(t, cx), t.modifiers) } hir::GenericBound::Use(args, ..) => { - GenericBound::Use(args.iter().map(|arg| arg.name()).collect()) + GenericBound::Use(args.iter().map(|arg| clean_precise_capturing_arg(arg, cx)).collect()) } }) } @@ -286,6 +286,18 @@ fn clean_lifetime(lifetime: &hir::Lifetime, cx: &DocContext<'_>) -> Lifetime { Lifetime(lifetime.ident.name) } +pub(crate) fn clean_precise_capturing_arg( + arg: &hir::PreciseCapturingArg<'_>, + cx: &DocContext<'_>, +) -> PreciseCapturingArg { + match arg { + hir::PreciseCapturingArg::Lifetime(lt) => { + PreciseCapturingArg::Lifetime(clean_lifetime(lt, cx)) + } + hir::PreciseCapturingArg::Param(param) => PreciseCapturingArg::Param(param.ident.name), + } +} + pub(crate) fn clean_const<'tcx>( constant: &hir::ConstArg<'tcx>, _cx: &mut DocContext<'tcx>, @@ -741,7 +753,7 @@ pub(crate) fn clean_generics<'tcx>( for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { let mut p = clean_generic_param(cx, Some(gens), p); match &mut p.kind { - GenericParamDefKind::Lifetime { ref mut outlives } => { + GenericParamDefKind::Lifetime { outlives } => { if let Some(region_pred) = region_predicates.get_mut(&Lifetime(p.name)) { // We merge bounds in the `where` clause. for outlive in outlives.drain(..) { @@ -828,30 +840,26 @@ fn clean_ty_generics<'tcx>( .iter() .flat_map(|(pred, _)| { let mut projection = None; - let param_idx = (|| { + let param_idx = { let bound_p = pred.kind(); match bound_p.skip_binder() { - ty::ClauseKind::Trait(pred) => { - if let ty::Param(param) = pred.self_ty().kind() { - return Some(param.index); - } + ty::ClauseKind::Trait(pred) if let ty::Param(param) = pred.self_ty().kind() => { + Some(param.index) } - ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { - if let ty::Param(param) = ty.kind() { - return Some(param.index); - } + ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) + if let ty::Param(param) = ty.kind() => + { + Some(param.index) } - ty::ClauseKind::Projection(p) => { - if let ty::Param(param) = p.projection_term.self_ty().kind() { - projection = Some(bound_p.rebind(p)); - return Some(param.index); - } + ty::ClauseKind::Projection(p) + if let ty::Param(param) = p.projection_term.self_ty().kind() => + { + projection = Some(bound_p.rebind(p)); + Some(param.index) } - _ => (), + _ => None, } - - None - })(); + }; if let Some(param_idx) = param_idx && let Some(bounds) = impl_trait.get_mut(¶m_idx) @@ -990,7 +998,7 @@ fn clean_proc_macro<'tcx>( kind: MacroKind, cx: &mut DocContext<'tcx>, ) -> ItemKind { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); if kind == MacroKind::Derive && let Some(derive_name) = hir_attr_lists(attrs, sym::proc_macro_derive).find_map(|mi| mi.ident()) @@ -1023,7 +1031,7 @@ fn clean_fn_or_proc_macro<'tcx>( name: &mut Symbol, cx: &mut DocContext<'tcx>, ) -> ItemKind { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); let macro_kind = attrs.iter().find_map(|a| { if a.has_name(sym::proc_macro) { Some(MacroKind::Bang) @@ -1378,12 +1386,12 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder(); if self_arg_ty == self_ty { item.decl.inputs.values[0].type_ = SelfTy; - } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { - if ty == self_ty { - match item.decl.inputs.values[0].type_ { - BorrowedRef { ref mut type_, .. } => **type_ = SelfTy, - _ => unreachable!(), - } + } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() + && ty == self_ty + { + match item.decl.inputs.values[0].type_ { + BorrowedRef { ref mut type_, .. } => **type_ = SelfTy, + _ => unreachable!(), } } } @@ -1480,6 +1488,9 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo // The only time this happens is if we're inside the rustdoc for Fn(), // which only has one associated type, which is not a GAT, so whatever. } + GenericArgs::ReturnTypeNotation => { + // Never move these. + } } bounds.extend(mem::take(pred_bounds)); false @@ -1760,7 +1771,7 @@ fn maybe_expand_private_type_alias<'tcx>( let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) && !cx.current_type_aliases.contains_key(&def_id.to_def_id()) { - &cx.tcx.hir().expect_item(def_id).kind + &cx.tcx.hir_expect_item(def_id).kind } else { return None; }; @@ -2331,25 +2342,22 @@ fn clean_middle_opaque_bounds<'tcx>( let bindings: ThinVec<_> = bounds .iter() .filter_map(|(bound, _)| { - if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() { - if proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() { - Some(AssocItemConstraint { - assoc: projection_to_path_segment( - // FIXME: This needs to be made resilient for `AliasTerm`s that - // are associated consts. - bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)), - cx, - ), - kind: AssocItemConstraintKind::Equality { - term: clean_middle_term(bound.kind().rebind(proj.term), cx), - }, - }) - } else { - None - } - } else { - None + if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() + && proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() + { + return Some(AssocItemConstraint { + assoc: projection_to_path_segment( + // FIXME: This needs to be made resilient for `AliasTerm`s that + // are associated consts. + bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)), + cx, + ), + kind: AssocItemConstraintKind::Equality { + term: clean_middle_term(bound.kind().rebind(proj.term), cx), + }, + }); } + None }) .collect(); @@ -2371,7 +2379,18 @@ fn clean_middle_opaque_bounds<'tcx>( } if let Some(args) = cx.tcx.rendered_precise_capturing_args(impl_trait_def_id) { - bounds.push(GenericBound::Use(args.to_vec())); + bounds.push(GenericBound::Use( + args.iter() + .map(|arg| match arg { + hir::PreciseCapturingArgKind::Lifetime(lt) => { + PreciseCapturingArg::Lifetime(Lifetime(*lt)) + } + hir::PreciseCapturingArgKind::Param(param) => { + PreciseCapturingArg::Param(*param) + } + }) + .collect(), + )); } ImplTrait(bounds) @@ -2537,37 +2556,42 @@ fn clean_generic_args<'tcx>( generic_args: &hir::GenericArgs<'tcx>, cx: &mut DocContext<'tcx>, ) -> GenericArgs { - // FIXME(return_type_notation): Fix RTN parens rendering - if let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() { - let inputs = inputs.iter().map(|x| clean_ty(x, cx)).collect::>().into(); - let output = match output.kind { - hir::TyKind::Tup(&[]) => None, - _ => Some(Box::new(clean_ty(output, cx))), - }; - GenericArgs::Parenthesized { inputs, output } - } else { - let args = generic_args - .args - .iter() - .map(|arg| match arg { - hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => { - GenericArg::Lifetime(clean_lifetime(lt, cx)) - } - hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), - hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)), - hir::GenericArg::Const(ct) => { - GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx))) - } - hir::GenericArg::Infer(_inf) => GenericArg::Infer, - }) - .collect::>() - .into(); - let constraints = generic_args - .constraints - .iter() - .map(|c| clean_assoc_item_constraint(c, cx)) - .collect::>(); - GenericArgs::AngleBracketed { args, constraints } + match generic_args.parenthesized { + hir::GenericArgsParentheses::No => { + let args = generic_args + .args + .iter() + .map(|arg| match arg { + hir::GenericArg::Lifetime(lt) if !lt.is_anonymous() => { + GenericArg::Lifetime(clean_lifetime(lt, cx)) + } + hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), + hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty.as_unambig_ty(), cx)), + hir::GenericArg::Const(ct) => { + GenericArg::Const(Box::new(clean_const(ct.as_unambig_ct(), cx))) + } + hir::GenericArg::Infer(_inf) => GenericArg::Infer, + }) + .collect(); + let constraints = generic_args + .constraints + .iter() + .map(|c| clean_assoc_item_constraint(c, cx)) + .collect::>(); + GenericArgs::AngleBracketed { args, constraints } + } + hir::GenericArgsParentheses::ParenSugar => { + let Some((inputs, output)) = generic_args.paren_sugar_inputs_output() else { + bug!(); + }; + let inputs = inputs.iter().map(|x| clean_ty(x, cx)).collect(); + let output = match output.kind { + hir::TyKind::Tup(&[]) => None, + _ => Some(Box::new(clean_ty(output, cx))), + }; + GenericArgs::Parenthesized { inputs, output } + } + hir::GenericArgsParentheses::ReturnTypeNotation => GenericArgs::ReturnTypeNotation, } } @@ -2688,7 +2712,7 @@ fn filter_doc_attr_ident(ident: Symbol, is_inline: bool) -> bool { /// Before calling this function, make sure `normal` is a `#[doc]` attribute. fn filter_doc_attr(args: &mut hir::AttrArgs, is_inline: bool) { match args { - hir::AttrArgs::Delimited(ref mut args) => { + hir::AttrArgs::Delimited(args) => { let tokens = filter_tokens_from_list(&args.tokens, |token| { !matches!( token, @@ -2737,25 +2761,26 @@ fn add_without_unwanted_attributes<'hir>( import_parent: Option, ) { for attr in new_attrs { - if matches!(attr.kind, hir::AttrKind::DocComment(..)) { + if attr.is_doc_comment() { attrs.push((Cow::Borrowed(attr), import_parent)); continue; } let mut attr = attr.clone(); - match attr.kind { - hir::AttrKind::Normal(ref mut normal) => { - if let [ident] = &*normal.path.segments { - let ident = ident.name; - if ident == sym::doc { - filter_doc_attr(&mut normal.args, is_inline); - attrs.push((Cow::Owned(attr), import_parent)); - } else if is_inline || ident != sym::cfg { - // If it's not a `cfg()` attribute, we keep it. - attrs.push((Cow::Owned(attr), import_parent)); - } + match attr { + hir::Attribute::Unparsed(ref mut normal) if let [ident] = &*normal.path.segments => { + let ident = ident.name; + if ident == sym::doc { + filter_doc_attr(&mut normal.args, is_inline); + attrs.push((Cow::Owned(attr), import_parent)); + } else if is_inline || ident != sym::cfg { + // If it's not a `cfg()` attribute, we keep it. + attrs.push((Cow::Owned(attr), import_parent)); } } - _ => unreachable!(), + hir::Attribute::Parsed(..) if is_inline => { + attrs.push((Cow::Owned(attr), import_parent)); + } + _ => {} } } } @@ -2769,7 +2794,7 @@ fn clean_maybe_renamed_item<'tcx>( use hir::ItemKind; let def_id = item.owner_id.to_def_id(); - let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); + let mut name = renamed.unwrap_or_else(|| cx.tcx.hir_name(item.hir_id())); cx.with_param_env(def_id, |cx| { let kind = match item.kind { ItemKind::Static(ty, mutability, body_id) => StaticItem(Static { @@ -2944,7 +2969,7 @@ fn clean_extern_crate<'tcx>( let cnum = cx.tcx.extern_mod_stmt_cnum(krate.owner_id.def_id).unwrap_or(LOCAL_CRATE); // this is the ID of the crate itself let crate_def_id = cnum.as_def_id(); - let attrs = cx.tcx.hir().attrs(krate.hir_id()); + let attrs = cx.tcx.hir_attrs(krate.hir_id()); let ty_vis = cx.tcx.visibility(krate.owner_id); let please_inline = ty_vis.is_public() && attrs.iter().any(|a| { @@ -2957,16 +2982,16 @@ fn clean_extern_crate<'tcx>( && !cx.is_json_output(); let krate_owner_def_id = krate.owner_id.def_id; - if please_inline { - if let Some(items) = inline::try_inline( + if please_inline + && let Some(items) = inline::try_inline( cx, Res::Def(DefKind::Mod, crate_def_id), name, Some((attrs, Some(krate_owner_def_id))), &mut Default::default(), - ) { - return items; - } + ) + { + return items; } vec![Item::from_def_id_and_parts( @@ -3013,7 +3038,7 @@ fn clean_use_statement_inner<'tcx>( } let visibility = cx.tcx.visibility(import.owner_id); - let attrs = cx.tcx.hir().attrs(import.hir_id()); + let attrs = cx.tcx.hir_attrs(import.hir_id()); let inline_attr = hir_attr_lists(attrs, sym::doc).get_word_attr(sym::inline); let pub_underscore = visibility.is_public() && name == kw::Underscore; let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id); diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs index 3cc5f8d615a4e..88db853d7c38f 100644 --- a/src/librustdoc/clean/render_macro_matchers.rs +++ b/src/librustdoc/clean/render_macro_matchers.rs @@ -1,4 +1,4 @@ -use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw}; +use rustc_ast::token::{self, Delimiter, IdentIsRaw}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_ast_pretty::pprust::PrintState; use rustc_ast_pretty::pprust::state::State as Printer; @@ -137,15 +137,10 @@ fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) { (Dollar, token::Ident(..)) => (false, DollarIdent), (DollarIdent, token::Colon) => (false, DollarIdentColon), (DollarIdentColon, token::Ident(..)) => (false, Other), - ( - DollarParen, - token::BinOp(BinOpToken::Plus | BinOpToken::Star) | token::Question, - ) => (false, Other), + (DollarParen, token::Plus | token::Star | token::Question) => (false, Other), (DollarParen, _) => (false, DollarParenSep), - (DollarParenSep, token::BinOp(BinOpToken::Plus | BinOpToken::Star)) => { - (false, Other) - } - (Pound, token::Not) => (false, PoundBang), + (DollarParenSep, token::Plus | token::Star) => (false, Other), + (Pound, token::Bang) => (false, PoundBang), (_, token::Ident(symbol, IdentIsRaw::No)) if !usually_needs_space_between_keyword_and_open_delim(*symbol, tt.span) => { diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs index b8db82e540c61..41943b94d1e21 100644 --- a/src/librustdoc/clean/simplify.rs +++ b/src/librustdoc/clean/simplify.rs @@ -102,6 +102,10 @@ pub(crate) fn merge_bounds( } } }, + PP::ReturnTypeNotation => { + // Cannot merge bounds with RTN. + return false; + } }; true }) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index fc7c4b42047db..3f9023659dbac 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -208,11 +208,11 @@ impl ExternalCrate { .get_attrs(def_id, sym::doc) .flat_map(|attr| attr.meta_item_list().unwrap_or_default()); for meta in meta_items { - if meta.has_name(sym::keyword) { - if let Some(v) = meta.value_str() { - keyword = Some(v); - break; - } + if meta.has_name(sym::keyword) + && let Some(v) = meta.value_str() + { + keyword = Some(v); + break; } } return keyword.map(|p| (def_id, p)); @@ -265,7 +265,7 @@ impl ExternalCrate { let attr_value = attr.value_str().expect("syntax should already be validated"); let Some(prim) = PrimitiveType::from_symbol(attr_value) else { span_bug!( - attr.span, + attr.span(), "primitive `{attr_value}` is not a member of `PrimitiveType`" ); }; @@ -502,7 +502,7 @@ impl Item { let Some(links) = cx.cache().intra_doc_links.get(&self.item_id) else { return vec![] }; links .iter() - .filter_map(|ItemLink { link: s, link_text, page_id: id, ref fragment }| { + .filter_map(|ItemLink { link: s, link_text, page_id: id, fragment }| { debug!(?id); if let Ok((mut href, ..)) = href(*id, cx) { debug!(?href); @@ -1071,16 +1071,14 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well for attr in hir_attr_lists(attrs, sym::target_feature) { - if attr.has_name(sym::enable) { - if attr.value_str().is_some() { - // Clone `enable = "feat"`, change to `target_feature = "feat"`. - // Unwrap is safe because `value_str` succeeded above. - let mut meta = attr.meta_item().unwrap().clone(); - meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); - - if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { - cfg &= feat_cfg; - } + if attr.has_name(sym::enable) && attr.value_str().is_some() { + // Clone `enable = "feat"`, change to `target_feature = "feat"`. + // Unwrap is safe because `value_str` succeeded above. + let mut meta = attr.meta_item().unwrap().clone(); + meta.path = ast::Path::from_ident(Ident::with_dummy_span(sym::target_feature)); + + if let Ok(feat_cfg) = Cfg::parse(&ast::MetaItemInner::MetaItem(meta)) { + cfg &= feat_cfg; } } } @@ -1150,7 +1148,7 @@ pub(crate) struct Attributes { } impl Attributes { - pub(crate) fn lists(&self, name: Symbol) -> impl Iterator + '_ { + pub(crate) fn lists(&self, name: Symbol) -> impl Iterator { hir_attr_lists(&self.other_attrs[..], name) } @@ -1160,10 +1158,10 @@ impl Attributes { continue; } - if let Some(items) = attr.meta_item_list() { - if items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) { - return true; - } + if let Some(items) = attr.meta_item_list() + && items.iter().filter_map(|i| i.meta_item()).any(|it| it.has_name(flag)) + { + return true; } } @@ -1242,7 +1240,7 @@ pub(crate) enum GenericBound { TraitBound(PolyTrait, hir::TraitBoundModifiers), Outlives(Lifetime), /// `use<'a, T>` precise-capturing bound syntax - Use(Vec), + Use(Vec), } impl GenericBound { @@ -1306,6 +1304,21 @@ impl Lifetime { } } +#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] +pub(crate) enum PreciseCapturingArg { + Lifetime(Lifetime), + Param(Symbol), +} + +impl PreciseCapturingArg { + pub(crate) fn name(self) -> Symbol { + match self { + PreciseCapturingArg::Lifetime(lt) => lt.0, + PreciseCapturingArg::Param(param) => param, + } + } +} + #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub(crate) enum WherePredicate { BoundPredicate { ty: Type, bounds: Vec, bound_params: Vec }, @@ -1864,7 +1877,7 @@ impl PrimitiveType { .copied() } - pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator + '_ { + pub(crate) fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator { Self::simplified_types() .values() .flatten() @@ -2246,8 +2259,12 @@ impl GenericArg { #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub(crate) enum GenericArgs { + /// `` AngleBracketed { args: ThinVec, constraints: ThinVec }, + /// `(inputs) -> output` Parenthesized { inputs: ThinVec, output: Option> }, + /// `(..)` + ReturnTypeNotation, } impl GenericArgs { @@ -2257,9 +2274,10 @@ impl GenericArgs { args.is_empty() && constraints.is_empty() } GenericArgs::Parenthesized { inputs, output } => inputs.is_empty() && output.is_none(), + GenericArgs::ReturnTypeNotation => false, } } - pub(crate) fn constraints<'a>(&'a self) -> Box + 'a> { + pub(crate) fn constraints(&self) -> Box + '_> { match self { GenericArgs::AngleBracketed { constraints, .. } => { Box::new(constraints.iter().cloned()) @@ -2281,6 +2299,7 @@ impl GenericArgs { }) .into_iter(), ), + GenericArgs::ReturnTypeNotation => Box::new([].into_iter()), } } } @@ -2292,8 +2311,10 @@ impl<'a> IntoIterator for &'a GenericArgs { match self { GenericArgs::AngleBracketed { args, .. } => Box::new(args.iter().cloned()), GenericArgs::Parenthesized { inputs, .. } => { + // FIXME: This isn't really right, since `Fn(A, B)` is `Fn<(A, B)>` Box::new(inputs.iter().cloned().map(GenericArg::Type)) } + GenericArgs::ReturnTypeNotation => Box::new([].into_iter()), } } } @@ -2419,7 +2440,7 @@ impl ConstantKind { ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => { rendered_const(tcx, tcx.hir_body(body), tcx.hir_body_owner_def_id(body)) } - ConstantKind::Infer { .. } => "_".to_string(), + ConstantKind::Infer => "_".to_string(), } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 34656b26ce28c..f81db58950cbd 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -60,7 +60,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { let primitives = local_crate.primitives(cx.tcx); let keywords = local_crate.keywords(cx.tcx); { - let ItemKind::ModuleItem(ref mut m) = &mut module.inner.kind else { unreachable!() }; + let ItemKind::ModuleItem(m) = &mut module.inner.kind else { unreachable!() }; m.items.extend(primitives.iter().map(|&(def_id, prim)| { Item::from_def_id_and_parts( def_id, @@ -223,7 +223,7 @@ fn clean_middle_generic_args_with_constraints<'tcx>( let args = clean_middle_generic_args(cx, args.map_bound(|args| &args[..]), has_self, did); - GenericArgs::AngleBracketed { args: args.into(), constraints } + GenericArgs::AngleBracketed { args, constraints } } pub(super) fn clean_middle_path<'tcx>( @@ -302,7 +302,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { use rustc_hir::*; debug!("trying to get a name from pattern: {p:?}"); - Symbol::intern(&match p.kind { + Symbol::intern(&match &p.kind { // FIXME(never_patterns): does this make sense? PatKind::Wild | PatKind::Err(_) @@ -313,8 +313,9 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { } PatKind::Binding(_, _, ident, _) => return ident.name, PatKind::Box(p) | PatKind::Ref(p, _) | PatKind::Guard(p, _) => return name_from_pat(p), - PatKind::TupleStruct(ref p, ..) - | PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p), + PatKind::TupleStruct(p, ..) | PatKind::Expr(PatExpr { kind: PatExprKind::Path(p), .. }) => { + qpath_to_string(p) + } PatKind::Or(pats) => { fmt::from_fn(|f| pats.iter().map(|p| name_from_pat(p)).joined(" | ", f)).to_string() } @@ -329,7 +330,7 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol { return Symbol::intern("()"); } PatKind::Slice(begin, mid, end) => { - fn print_pat<'a>(pat: &'a Pat<'a>, wild: bool) -> impl Display + 'a { + fn print_pat(pat: &Pat<'_>, wild: bool) -> impl Display { fmt::from_fn(move |f| { if wild { f.write_str("..")?; @@ -393,7 +394,7 @@ pub(crate) fn print_evaluated_const( fn format_integer_with_underscore_sep(num: &str) -> String { let num_chars: Vec<_> = num.chars().collect(); let mut num_start_index = if num_chars.first() == Some(&'-') { 1 } else { 0 }; - let chunk_size = match num[num_start_index..].as_bytes() { + let chunk_size = match &num.as_bytes()[num_start_index..] { [b'0', b'b' | b'x', ..] => { num_start_index += 2; 4 @@ -493,7 +494,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { pub(crate) fn synthesize_auto_trait_and_blanket_impls( cx: &mut DocContext<'_>, item_def_id: DefId, -) -> impl Iterator { +) -> impl Iterator + use<> { let auto_impls = cx .sess() .prof @@ -523,7 +524,7 @@ pub(crate) fn register_res(cx: &mut DocContext<'_>, res: Res) -> DefId { | AssocConst | Variant | Fn - | TyAlias { .. } + | TyAlias | Enum | Trait | Struct diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index fd4d9845c8920..23a2bcd9011ee 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -103,6 +103,8 @@ pub(crate) struct Options { /// compiling doctests from the crate. pub(crate) edition: Edition, /// The path to the sysroot. Used during the compilation process. + pub(crate) sysroot: PathBuf, + /// Has the same value as `sysroot` except is `None` when the user didn't pass `---sysroot`. pub(crate) maybe_sysroot: Option, /// Lint information passed over the command-line. pub(crate) lint_opts: Vec<(String, Level)>, @@ -202,6 +204,7 @@ impl fmt::Debug for Options { .field("unstable_options", &"...") .field("target", &self.target) .field("edition", &self.edition) + .field("sysroot", &self.sysroot) .field("maybe_sysroot", &self.maybe_sysroot) .field("lint_opts", &self.lint_opts) .field("describe_lints", &self.describe_lints) @@ -315,23 +318,30 @@ pub(crate) enum ModuleSorting { Alphabetical, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub(crate) enum EmitType { Unversioned, Toolchain, InvocationSpecific, + DepInfo(Option), } impl FromStr for EmitType { type Err = (); fn from_str(s: &str) -> Result { - use EmitType::*; match s { - "unversioned-shared-resources" => Ok(Unversioned), - "toolchain-shared-resources" => Ok(Toolchain), - "invocation-specific" => Ok(InvocationSpecific), - _ => Err(()), + "unversioned-shared-resources" => Ok(Self::Unversioned), + "toolchain-shared-resources" => Ok(Self::Toolchain), + "invocation-specific" => Ok(Self::InvocationSpecific), + "dep-info" => Ok(Self::DepInfo(None)), + option => { + if let Some(file) = option.strip_prefix("dep-info=") { + Ok(Self::DepInfo(Some(Path::new(file).into()))) + } else { + Err(()) + } + } } } } @@ -340,6 +350,15 @@ impl RenderOptions { pub(crate) fn should_emit_crate(&self) -> bool { self.emit.is_empty() || self.emit.contains(&EmitType::InvocationSpecific) } + + pub(crate) fn dep_info(&self) -> Option> { + for emit in &self.emit { + if let EmitType::DepInfo(file) = emit { + return Some(file.as_deref()); + } + } + None + } } /// Create the input (string or file path) @@ -629,10 +648,10 @@ impl Options { let extension_css = matches.opt_str("e").map(|s| PathBuf::from(&s)); - if let Some(ref p) = extension_css { - if !p.is_file() { - dcx.fatal("option --extend-css argument must be a file"); - } + if let Some(ref p) = extension_css + && !p.is_file() + { + dcx.fatal("option --extend-css argument must be a file"); } let mut themes = Vec::new(); @@ -704,21 +723,16 @@ impl Options { } let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s)); - if let Some(ref index_page) = index_page { - if !index_page.is_file() { - dcx.fatal("option `--index-page` argument must be a file"); - } + if let Some(ref index_page) = index_page + && !index_page.is_file() + { + dcx.fatal("option `--index-page` argument must be a file"); } let target = parse_target_triple(early_dcx, matches); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); - let sysroot = match &maybe_sysroot { - Some(s) => s.clone(), - None => { - rustc_session::filesearch::get_or_default_sysroot().expect("Failed finding sysroot") - } - }; + let sysroot = rustc_session::filesearch::materialize_sysroot(maybe_sysroot.clone()); let libs = matches .opt_strs("L") @@ -818,6 +832,7 @@ impl Options { unstable_opts_strs, target, edition, + sysroot, maybe_sysroot, lint_opts, describe_lints, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 757a2a6e0dd06..c47e42670c909 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -15,11 +15,12 @@ use rustc_hir::def::Res; use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{HirId, Path}; -use rustc_interface::interface; use rustc_lint::{MissingDoc, late_lint_mod}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; -use rustc_session::config::{self, CrateType, ErrorOutputType, Input, ResolveDocLinks}; +use rustc_session::config::{ + self, CrateType, ErrorOutputType, Input, OutFileName, OutputType, OutputTypes, ResolveDocLinks, +}; pub(crate) use rustc_session::config::{Options, UnstableOptions}; use rustc_session::{Session, lint}; use rustc_span::source_map; @@ -153,13 +154,12 @@ pub(crate) fn new_dcx( false, ); let emitter: Box = match error_format { - ErrorOutputType::HumanReadable(kind, color_config) => { + ErrorOutputType::HumanReadable { kind, color_config } => { let short = kind.short(); Box::new( HumanEmitter::new(stderr_destination(color_config), fallback_bundle) .sm(source_map.map(|sm| sm as _)) .short_message(short) - .teach(unstable_opts.teach) .diagnostic_width(diagnostic_width) .track_diagnostics(unstable_opts.track_diagnostics) .theme(if let HumanReadableErrorType::Unicode = kind { @@ -210,7 +210,7 @@ pub(crate) fn create_config( unstable_opts, target, edition, - maybe_sysroot, + sysroot, lint_opts, describe_lints, lint_cap, @@ -219,7 +219,7 @@ pub(crate) fn create_config( remap_path_prefix, .. }: RustdocOptions, - RenderOptions { document_private, .. }: &RenderOptions, + render_options: &RenderOptions, ) -> rustc_interface::Config { // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); @@ -245,12 +245,15 @@ pub(crate) fn create_config( let crate_types = if proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; - let resolve_doc_links = - if *document_private { ResolveDocLinks::All } else { ResolveDocLinks::Exported }; + let resolve_doc_links = if render_options.document_private { + ResolveDocLinks::All + } else { + ResolveDocLinks::Exported + }; let test = scrape_examples_options.map(|opts| opts.scrape_tests).unwrap_or(false); // plays with error output here! let sessopts = config::Options { - maybe_sysroot, + sysroot, search_paths: libs, crate_types, lint_opts, @@ -269,10 +272,18 @@ pub(crate) fn create_config( crate_name, test, remap_path_prefix, + output_types: if let Some(file) = render_options.dep_info() { + OutputTypes::new(&[( + OutputType::DepInfo, + file.map(|f| OutFileName::Real(f.to_path_buf())), + )]) + } else { + OutputTypes::new(&[]) + }, ..Options::default() }; - interface::Config { + rustc_interface::Config { opts: sessopts, crate_cfg: cfgs, crate_check_cfg: check_cfgs, diff --git a/src/librustdoc/display.rs b/src/librustdoc/display.rs index ee8dde013ee93..aa0fad265208d 100644 --- a/src/librustdoc/display.rs +++ b/src/librustdoc/display.rs @@ -22,7 +22,7 @@ where let mut iter = self.into_iter(); let Some(first) = iter.next() else { return Ok(()) }; first.fmt(f)?; - while let Some(item) = iter.next() { + for item in iter { f.write_str(sep)?; item.fmt(f)?; } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 4a379b4235ff0..a2808bddb3acc 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -96,7 +96,7 @@ pub(crate) fn generate_args_file(file_path: &Path, options: &RustdocOptions) -> .map_err(|error| format!("failed to create args file: {error:?}"))?; // We now put the common arguments into the file we created. - let mut content = vec!["--crate-type=bin".to_string()]; + let mut content = vec![]; for cfg in &options.cfgs { content.push(format!("--cfg={cfg}")); @@ -158,7 +158,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions if options.proc_macro_crate { vec![CrateType::ProcMacro] } else { vec![CrateType::Rlib] }; let sessopts = config::Options { - maybe_sysroot: options.maybe_sysroot.clone(), + sysroot: options.sysroot.clone(), search_paths: options.libs.clone(), crate_types, lint_opts, @@ -216,7 +216,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions let collector = rustc_interface::create_and_enter_global_ctxt(compiler, krate, |tcx| { let crate_name = tcx.crate_name(LOCAL_CRATE).to_string(); - let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID); + let crate_attrs = tcx.hir_attrs(CRATE_HIR_ID); let opts = scrape_test_config(crate_name, crate_attrs, args_path); let enable_per_target_ignores = options.enable_per_target_ignores; @@ -513,12 +513,18 @@ pub(crate) struct RunnableDocTest { line: usize, edition: Edition, no_run: bool, - is_multiple_tests: bool, + merged_test_code: Option, } impl RunnableDocTest { - fn path_for_merged_doctest(&self) -> PathBuf { - self.test_opts.outdir.path().join(format!("doctest_{}.rs", self.edition)) + fn path_for_merged_doctest_bundle(&self) -> PathBuf { + self.test_opts.outdir.path().join(format!("doctest_bundle_{}.rs", self.edition)) + } + fn path_for_merged_doctest_runner(&self) -> PathBuf { + self.test_opts.outdir.path().join(format!("doctest_runner_{}.rs", self.edition)) + } + fn is_multiple_tests(&self) -> bool { + self.merged_test_code.is_some() } } @@ -537,91 +543,108 @@ fn run_test( let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target); let output_file = doctest.test_opts.outdir.path().join(rust_out); - let rustc_binary = rustdoc_options - .test_builder - .as_deref() - .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc")); - let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary); + // Common arguments used for compiling the doctest runner. + // On merged doctests, the compiler is invoked twice: once for the test code itself, + // and once for the runner wrapper (which needs to use `#![feature]` on stable). + let mut compiler_args = vec![]; - compiler.arg(format!("@{}", doctest.global_opts.args_file.display())); + compiler_args.push(format!("@{}", doctest.global_opts.args_file.display())); if let Some(sysroot) = &rustdoc_options.maybe_sysroot { - compiler.arg(format!("--sysroot={}", sysroot.display())); + compiler_args.push(format!("--sysroot={}", sysroot.display())); } - compiler.arg("--edition").arg(doctest.edition.to_string()); - if !doctest.is_multiple_tests { - // Setting these environment variables is unneeded if this is a merged doctest. - compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path); - compiler.env( - "UNSTABLE_RUSTDOC_TEST_LINE", - format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize), - ); - } - compiler.arg("-o").arg(&output_file); + compiler_args.extend_from_slice(&["--edition".to_owned(), doctest.edition.to_string()]); if langstr.test_harness { - compiler.arg("--test"); + compiler_args.push("--test".to_owned()); } if rustdoc_options.json_unused_externs.is_enabled() && !langstr.compile_fail { - compiler.arg("--error-format=json"); - compiler.arg("--json").arg("unused-externs"); - compiler.arg("-W").arg("unused_crate_dependencies"); - compiler.arg("-Z").arg("unstable-options"); + compiler_args.push("--error-format=json".to_owned()); + compiler_args.extend_from_slice(&["--json".to_owned(), "unused-externs".to_owned()]); + compiler_args.extend_from_slice(&["-W".to_owned(), "unused_crate_dependencies".to_owned()]); + compiler_args.extend_from_slice(&["-Z".to_owned(), "unstable-options".to_owned()]); } if doctest.no_run && !langstr.compile_fail && rustdoc_options.persist_doctests.is_none() { // FIXME: why does this code check if it *shouldn't* persist doctests // -- shouldn't it be the negation? - compiler.arg("--emit=metadata"); + compiler_args.push("--emit=metadata".to_owned()); } - compiler.arg("--target").arg(match &rustdoc_options.target { - TargetTuple::TargetTuple(s) => s, - TargetTuple::TargetJson { path_for_rustdoc, .. } => { - path_for_rustdoc.to_str().expect("target path must be valid unicode") - } - }); - if let ErrorOutputType::HumanReadable(kind, color_config) = rustdoc_options.error_format { + compiler_args.extend_from_slice(&[ + "--target".to_owned(), + match &rustdoc_options.target { + TargetTuple::TargetTuple(s) => s.clone(), + TargetTuple::TargetJson { path_for_rustdoc, .. } => { + path_for_rustdoc.to_str().expect("target path must be valid unicode").to_owned() + } + }, + ]); + if let ErrorOutputType::HumanReadable { kind, color_config } = rustdoc_options.error_format { let short = kind.short(); let unicode = kind == HumanReadableErrorType::Unicode; if short { - compiler.arg("--error-format").arg("short"); + compiler_args.extend_from_slice(&["--error-format".to_owned(), "short".to_owned()]); } if unicode { - compiler.arg("--error-format").arg("human-unicode"); + compiler_args + .extend_from_slice(&["--error-format".to_owned(), "human-unicode".to_owned()]); } match color_config { ColorConfig::Never => { - compiler.arg("--color").arg("never"); + compiler_args.extend_from_slice(&["--color".to_owned(), "never".to_owned()]); } ColorConfig::Always => { - compiler.arg("--color").arg("always"); + compiler_args.extend_from_slice(&["--color".to_owned(), "always".to_owned()]); } ColorConfig::Auto => { - compiler.arg("--color").arg(if supports_color { "always" } else { "never" }); + compiler_args.extend_from_slice(&[ + "--color".to_owned(), + if supports_color { "always" } else { "never" }.to_owned(), + ]); } } } + let rustc_binary = rustdoc_options + .test_builder + .as_deref() + .unwrap_or_else(|| rustc_interface::util::rustc_path().expect("found rustc")); + let mut compiler = wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary); + + compiler.args(&compiler_args); + // If this is a merged doctest, we need to write it into a file instead of using stdin // because if the size of the merged doctests is too big, it'll simply break stdin. - if doctest.is_multiple_tests { + if doctest.is_multiple_tests() { // It makes the compilation failure much faster if it is for a combined doctest. compiler.arg("--error-format=short"); - let input_file = doctest.path_for_merged_doctest(); + let input_file = doctest.path_for_merged_doctest_bundle(); if std::fs::write(&input_file, &doctest.full_test_code).is_err() { // If we cannot write this file for any reason, we leave. All combined tests will be // tested as standalone tests. return Err(TestFailure::CompileError); } - compiler.arg(input_file); if !rustdoc_options.nocapture { // If `nocapture` is disabled, then we don't display rustc's output when compiling // the merged doctests. compiler.stderr(Stdio::null()); } + // bundled tests are an rlib, loaded by a separate runner executable + compiler + .arg("--crate-type=lib") + .arg("--out-dir") + .arg(doctest.test_opts.outdir.path()) + .arg(input_file); } else { + compiler.arg("--crate-type=bin").arg("-o").arg(&output_file); + // Setting these environment variables is unneeded if this is a merged doctest. + compiler.env("UNSTABLE_RUSTDOC_TEST_PATH", &doctest.test_opts.path); + compiler.env( + "UNSTABLE_RUSTDOC_TEST_LINE", + format!("{}", doctest.line as isize - doctest.full_test_line_offset as isize), + ); compiler.arg("-"); compiler.stdin(Stdio::piped()); compiler.stderr(Stdio::piped()); @@ -630,8 +653,65 @@ fn run_test( debug!("compiler invocation for doctest: {compiler:?}"); let mut child = compiler.spawn().expect("Failed to spawn rustc process"); - let output = if doctest.is_multiple_tests { + let output = if let Some(merged_test_code) = &doctest.merged_test_code { + // compile-fail tests never get merged, so this should always pass let status = child.wait().expect("Failed to wait"); + + // the actual test runner is a separate component, built with nightly-only features; + // build it now + let runner_input_file = doctest.path_for_merged_doctest_runner(); + + let mut runner_compiler = + wrapped_rustc_command(&rustdoc_options.test_builder_wrappers, rustc_binary); + // the test runner does not contain any user-written code, so this doesn't allow + // the user to exploit nightly-only features on stable + runner_compiler.env("RUSTC_BOOTSTRAP", "1"); + runner_compiler.args(compiler_args); + runner_compiler.args(&["--crate-type=bin", "-o"]).arg(&output_file); + let mut extern_path = std::ffi::OsString::from(format!( + "--extern=doctest_bundle_{edition}=", + edition = doctest.edition + )); + for extern_str in &rustdoc_options.extern_strs { + if let Some((_cratename, path)) = extern_str.split_once('=') { + // Direct dependencies of the tests themselves are + // indirect dependencies of the test runner. + // They need to be in the library search path. + let dir = Path::new(path) + .parent() + .filter(|x| x.components().count() > 0) + .unwrap_or(Path::new(".")); + runner_compiler.arg("-L").arg(dir); + } + } + let output_bundle_file = doctest + .test_opts + .outdir + .path() + .join(format!("libdoctest_bundle_{edition}.rlib", edition = doctest.edition)); + extern_path.push(&output_bundle_file); + runner_compiler.arg(extern_path); + runner_compiler.arg(&runner_input_file); + if std::fs::write(&runner_input_file, &merged_test_code).is_err() { + // If we cannot write this file for any reason, we leave. All combined tests will be + // tested as standalone tests. + return Err(TestFailure::CompileError); + } + if !rustdoc_options.nocapture { + // If `nocapture` is disabled, then we don't display rustc's output when compiling + // the merged doctests. + runner_compiler.stderr(Stdio::null()); + } + runner_compiler.arg("--error-format=short"); + debug!("compiler invocation for doctest runner: {runner_compiler:?}"); + + let status = if !status.success() { + status + } else { + let mut child_runner = runner_compiler.spawn().expect("Failed to spawn rustc process"); + child_runner.wait().expect("Failed to wait") + }; + process::Output { status, stdout: Vec::new(), stderr: Vec::new() } } else { let stdin = child.stdin.as_mut().expect("Failed to open stdin"); @@ -708,7 +788,7 @@ fn run_test( cmd.arg(&output_file); } else { cmd = Command::new(&output_file); - if doctest.is_multiple_tests { + if doctest.is_multiple_tests() { cmd.env("RUSTDOC_DOCTEST_BIN_PATH", &output_file); } } @@ -716,7 +796,7 @@ fn run_test( cmd.current_dir(run_directory); } - let result = if doctest.is_multiple_tests || rustdoc_options.nocapture { + let result = if doctest.is_multiple_tests() || rustdoc_options.nocapture { cmd.status().map(|status| process::Output { status, stdout: Vec::new(), @@ -1003,7 +1083,7 @@ fn doctest_run_fn( line: scraped_test.line, edition: scraped_test.edition(&rustdoc_options), no_run: scraped_test.no_run(&rustdoc_options), - is_multiple_tests: false, + merged_test_code: None, }; let res = run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs); diff --git a/src/librustdoc/doctest/extracted.rs b/src/librustdoc/doctest/extracted.rs index 03c8814a4c960..ce362eabfc4c9 100644 --- a/src/librustdoc/doctest/extracted.rs +++ b/src/librustdoc/doctest/extracted.rs @@ -33,7 +33,7 @@ impl ExtractedDocTests { opts: &super::GlobalTestOptions, options: &RustdocOptions, ) { - let edition = scraped_test.edition(&options); + let edition = scraped_test.edition(options); let ScrapedDocTest { filename, line, langstr, text, name } = scraped_test; @@ -48,7 +48,7 @@ impl ExtractedDocTests { let (full_test_code, size) = doctest.generate_unique_doctest( &text, langstr.test_harness, - &opts, + opts, Some(&opts.crate_name), ); self.doctests.push(ExtractedDocTest { diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 4792bc525a592..9935074877bc8 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -208,7 +208,7 @@ impl DocTestBuilder { let (main_pre, main_post) = if returns_result { ( format!( - "fn main() {{ {inner_attr}fn {inner_fn_name}() -> Result<(), impl core::fmt::Debug> {{\n", + "fn main() {{ {inner_attr}fn {inner_fn_name}() -> core::result::Result<(), impl core::fmt::Debug> {{\n", ), format!("\n}} {inner_fn_name}().unwrap() }}"), ) diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 234f40c6c1ab2..f891505d2a609 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -14,6 +14,7 @@ pub(crate) struct DocTestRunner { crate_attrs: FxIndexSet, ids: String, output: String, + output_merged_tests: String, supports_color: bool, nb_tests: usize, } @@ -24,6 +25,7 @@ impl DocTestRunner { crate_attrs: FxIndexSet::default(), ids: String::new(), output: String::new(), + output_merged_tests: String::new(), supports_color: true, nb_tests: 0, } @@ -45,17 +47,15 @@ impl DocTestRunner { self.crate_attrs.insert(line.to_string()); } } - if !self.ids.is_empty() { - self.ids.push(','); - } self.ids.push_str(&format!( - "{}::TEST", + "tests.push({}::TEST);\n", generate_mergeable_doctest( doctest, scraped_test, ignore, self.nb_tests, - &mut self.output + &mut self.output, + &mut self.output_merged_tests, ), )); self.supports_color &= doctest.supports_color; @@ -78,9 +78,11 @@ impl DocTestRunner { " .to_string(); + let mut code_prefix = String::new(); + for crate_attr in &self.crate_attrs { - code.push_str(crate_attr); - code.push('\n'); + code_prefix.push_str(crate_attr); + code_prefix.push('\n'); } if opts.attrs.is_empty() { @@ -88,15 +90,16 @@ impl DocTestRunner { // lints that are commonly triggered in doctests. The crate-level test attributes are // commonly used to make tests fail in case they trigger warnings, so having this there in // that case may cause some tests to pass when they shouldn't have. - code.push_str("#![allow(unused)]\n"); + code_prefix.push_str("#![allow(unused)]\n"); } // Next, any attributes that came from the crate root via #![doc(test(attr(...)))]. for attr in &opts.attrs { - code.push_str(&format!("#![{attr}]\n")); + code_prefix.push_str(&format!("#![{attr}]\n")); } code.push_str("extern crate test;\n"); + writeln!(code, "extern crate doctest_bundle_{edition} as doctest_bundle;").unwrap(); let test_args = test_args.iter().fold(String::new(), |mut x, arg| { write!(x, "{arg:?}.to_string(),").unwrap(); @@ -136,7 +139,11 @@ mod __doctest_mod {{ #[rustc_main] fn main() -> std::process::ExitCode {{ -const TESTS: [test::TestDescAndFn; {nb_tests}] = [{ids}]; +let tests = {{ + let mut tests = Vec::with_capacity({nb_tests}); + {ids} + tests +}}; let test_marker = std::ffi::OsStr::new(__doctest_mod::RUN_OPTION); let test_args = &[{test_args}]; const ENV_BIN: &'static str = \"RUSTDOC_DOCTEST_BIN_PATH\"; @@ -144,11 +151,11 @@ const ENV_BIN: &'static str = \"RUSTDOC_DOCTEST_BIN_PATH\"; if let Ok(binary) = std::env::var(ENV_BIN) {{ let _ = crate::__doctest_mod::BINARY_PATH.set(binary.into()); unsafe {{ std::env::remove_var(ENV_BIN); }} - return std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), None)); + return std::process::Termination::report(test::test_main(test_args, tests, None)); }} else if let Ok(nb_test) = std::env::var(__doctest_mod::RUN_OPTION) {{ if let Ok(nb_test) = nb_test.parse::() {{ - if let Some(test) = TESTS.get(nb_test) {{ - if let test::StaticTestFn(f) = test.testfn {{ + if let Some(test) = tests.get(nb_test) {{ + if let test::StaticTestFn(f) = &test.testfn {{ return std::process::Termination::report(f()); }} }} @@ -158,15 +165,15 @@ if let Ok(binary) = std::env::var(ENV_BIN) {{ eprintln!(\"WARNING: No rustdoc doctest environment variable provided so doctests will be run in \ the same process\"); -std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), None)) +std::process::Termination::report(test::test_main(test_args, tests, None)) }}", nb_tests = self.nb_tests, - output = self.output, + output = self.output_merged_tests, ids = self.ids, ) .expect("failed to generate test code"); let runnable_test = RunnableDocTest { - full_test_code: code, + full_test_code: format!("{code_prefix}{code}", code = self.output), full_test_line_offset: 0, test_opts: test_options, global_opts: opts.clone(), @@ -174,7 +181,7 @@ std::process::Termination::report(test::test_main(test_args, Vec::from(TESTS), N line: 0, edition, no_run: false, - is_multiple_tests: true, + merged_test_code: Some(code), }; let ret = run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {}); @@ -189,14 +196,15 @@ fn generate_mergeable_doctest( ignore: bool, id: usize, output: &mut String, + output_merged_tests: &mut String, ) -> String { let test_id = format!("__doctest_{id}"); if ignore { // We generate nothing else. - writeln!(output, "mod {test_id} {{\n").unwrap(); + writeln!(output, "pub mod {test_id} {{}}\n").unwrap(); } else { - writeln!(output, "mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs) + writeln!(output, "pub mod {test_id} {{\n{}{}", doctest.crates, doctest.maybe_crate_attrs) .unwrap(); if doctest.has_main_fn { output.push_str(&doctest.everything_else); @@ -216,11 +224,17 @@ fn main() {returns_result} {{ ) .unwrap(); } + writeln!( + output, + "\npub fn __main_fn() -> impl std::process::Termination {{ main() }} \n}}\n" + ) + .unwrap(); } let not_running = ignore || scraped_test.langstr.no_run; writeln!( - output, + output_merged_tests, " +mod {test_id} {{ pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest( {test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic}, test::StaticTestFn( @@ -242,7 +256,7 @@ test::StaticTestFn( if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{ test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id})) }} else {{ - test::assert_test_result(self::main()) + test::assert_test_result(doctest_bundle::{test_id}::__main_fn()) }} ", ) diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index 1ac3c040b5918..18ad442d01789 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -95,13 +95,12 @@ impl HirCollector<'_> { sp: Span, nested: F, ) { - let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); + let ast_attrs = self.tcx.hir_attrs(self.tcx.local_def_id_to_hir_id(def_id)); if let Some(ref cfg) = extract_cfg_from_attrs(ast_attrs.iter(), self.tcx, &FxHashSet::default()) + && !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) { - if !cfg.matches(&self.tcx.sess.psess, Some(self.tcx.features())) { - return; - } + return; } let has_name = !name.is_empty(); @@ -123,7 +122,7 @@ impl HirCollector<'_> { .iter() .find(|attr| attr.doc_str().is_some()) .map(|attr| { - attr.span.ctxt().outer_expn().expansion_cause().unwrap_or(attr.span) + attr.span().ctxt().outer_expn().expansion_cause().unwrap_or(attr.span()) }) .unwrap_or(DUMMY_SP) }; diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index fa6cca3681be5..e2b964bf5af57 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -316,7 +316,7 @@ let mut input = String::new(); io::stdin().read_line(&mut input)?; Ok::<(), io:Error>(())"; let expected = "#![allow(unused)] -fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> { +fn main() { fn _inner() -> core::result::Result<(), impl core::fmt::Debug> { use std::io; let mut input = String::new(); io::stdin().read_line(&mut input)?; diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 4760e579199aa..2648641e53e75 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -419,7 +419,9 @@ impl DocFolder for CacheBuilder<'_, '_> { } } - if let Some(generics) = i.trait_.as_ref().and_then(|t| t.generics()) { + if let Some(trait_) = &i.trait_ + && let Some(generics) = trait_.generics() + { for bound in generics { dids.extend(bound.def_id(self.cache)); } diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs index 88654ed32da93..ac9e2f42cc6d0 100644 --- a/src/librustdoc/html/escape.rs +++ b/src/librustdoc/html/escape.rs @@ -5,6 +5,7 @@ use std::fmt; +use pulldown_cmark_escape::FmtWriter; use unicode_segmentation::UnicodeSegmentation; /// Wrapper struct which will emit the HTML-escaped version of the contained @@ -13,31 +14,7 @@ pub(crate) struct Escape<'a>(pub &'a str); impl fmt::Display for Escape<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - // Because the internet is always right, turns out there's not that many - // characters to escape: http://stackoverflow.com/questions/7381974 - let Escape(s) = *self; - let pile_o_bits = s; - let mut last = 0; - for (i, ch) in s.char_indices() { - let s = match ch { - '>' => ">", - '<' => "<", - '&' => "&", - '\'' => "'", - '"' => """, - _ => continue, - }; - fmt.write_str(&pile_o_bits[last..i])?; - fmt.write_str(s)?; - // NOTE: we only expect single byte characters here - which is fine as long as we - // only match single byte characters - last = i + 1; - } - - if last < s.len() { - fmt.write_str(&pile_o_bits[last..])?; - } - Ok(()) + pulldown_cmark_escape::escape_html(FmtWriter(fmt), self.0) } } @@ -51,29 +28,7 @@ pub(crate) struct EscapeBodyText<'a>(pub &'a str); impl fmt::Display for EscapeBodyText<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - // Because the internet is always right, turns out there's not that many - // characters to escape: http://stackoverflow.com/questions/7381974 - let EscapeBodyText(s) = *self; - let pile_o_bits = s; - let mut last = 0; - for (i, ch) in s.char_indices() { - let s = match ch { - '>' => ">", - '<' => "<", - '&' => "&", - _ => continue, - }; - fmt.write_str(&pile_o_bits[last..i])?; - fmt.write_str(s)?; - // NOTE: we only expect single byte characters here - which is fine as long as we - // only match single byte characters - last = i + 1; - } - - if last < s.len() { - fmt.write_str(&pile_o_bits[last..])?; - } - Ok(()) + pulldown_cmark_escape::escape_html_body_text(FmtWriter(fmt), self.0) } } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 91b4b3ba1ebac..41e9a5a665169 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -15,7 +15,6 @@ use std::iter::{self, once}; use itertools::Either; use rustc_abi::ExternAbi; use rustc_attr_parsing::{ConstStability, StabilityLevel, StableSince}; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -30,7 +29,7 @@ use super::url_parts_builder::{UrlPartsBuilder, estimate_item_path_byte_length}; use crate::clean::types::ExternalLocation; use crate::clean::utils::find_nearest_parent_module; use crate::clean::{self, ExternalCrate, PrimitiveType}; -use crate::display::Joined as _; +use crate::display::{Joined as _, MaybeDisplay as _}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::{Escape, EscapeBodyText}; @@ -41,10 +40,10 @@ pub(crate) fn write_str(s: &mut String, f: fmt::Arguments<'_>) { s.write_fmt(f).unwrap(); } -pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( - bounds: &'a [clean::GenericBound], - cx: &'a Context<'tcx>, -) -> impl Display + 'a + Captures<'tcx> { +pub(crate) fn print_generic_bounds( + bounds: &[clean::GenericBound], + cx: &Context<'_>, +) -> impl Display { fmt::from_fn(move |f| { let mut bounds_dup = FxHashSet::default(); @@ -57,10 +56,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( } impl clean::GenericParamDef { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match &self.kind { clean::GenericParamDefKind::Lifetime { outlives } => { write!(f, "{}", self.name)?; @@ -80,7 +76,7 @@ impl clean::GenericParamDef { print_generic_bounds(bounds, cx).fmt(f)?; } - if let Some(ref ty) = default { + if let Some(ty) = default { f.write_str(" = ")?; ty.print(cx).fmt(f)?; } @@ -107,10 +103,7 @@ impl clean::GenericParamDef { } impl clean::Generics { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable(); if real_params.peek().is_none() { @@ -134,10 +127,7 @@ pub(crate) enum Ending { NoNewline, } -fn print_where_predicate<'a, 'tcx: 'a>( - predicate: &'a clean::WherePredicate, - cx: &'a Context<'tcx>, -) -> impl Display + 'a + Captures<'tcx> { +fn print_where_predicate(predicate: &clean::WherePredicate, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { match predicate { clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => { @@ -173,17 +163,17 @@ fn print_where_predicate<'a, 'tcx: 'a>( /// * The Generics from which to emit a where-clause. /// * The number of spaces to indent each line with. /// * Whether the where-clause needs to add a comma and newline after the last bound. -pub(crate) fn print_where_clause<'a, 'tcx: 'a>( - gens: &'a clean::Generics, - cx: &'a Context<'tcx>, +pub(crate) fn print_where_clause( + gens: &clean::Generics, + cx: &Context<'_>, indent: usize, ending: Ending, -) -> impl Display + 'a + Captures<'tcx> { - fmt::from_fn(move |f| { - if gens.where_predicates.is_empty() { - return Ok(()); - } +) -> Option { + if gens.where_predicates.is_empty() { + return None; + } + Some(fmt::from_fn(move |f| { let where_preds = fmt::from_fn(|f| { gens.where_predicates .iter() @@ -246,17 +236,17 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( } }; write!(f, "{clause}") - }) + })) } impl clean::Lifetime { - pub(crate) fn print(&self) -> impl Display + '_ { + pub(crate) fn print(&self) -> impl Display { self.0.as_str() } } impl clean::ConstantKind { - pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ { + pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display { let expr = self.expr(tcx); fmt::from_fn(move |f| { if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) } @@ -265,7 +255,7 @@ impl clean::ConstantKind { } impl clean::PolyTrait { - fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> { + fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?; self.trait_.print(cx).fmt(f) @@ -274,10 +264,7 @@ impl clean::PolyTrait { } impl clean::GenericBound { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), clean::GenericBound::TraitBound(ty, modifiers) => { @@ -296,7 +283,7 @@ impl clean::GenericBound { } else { f.write_str("use<")?; } - args.iter().joined(", ", f)?; + args.iter().map(|arg| arg.name()).joined(", ", f)?; if f.alternate() { f.write_str(">") } else { f.write_str(">") } } }) @@ -304,7 +291,7 @@ impl clean::GenericBound { } impl clean::GenericArgs { - fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> { + fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { match self { clean::GenericArgs::AngleBracketed { args, constraints } => { @@ -345,6 +332,9 @@ impl clean::GenericArgs { } } } + clean::GenericArgs::ReturnTypeNotation => { + f.write_str("(..)")?; + } } Ok(()) }) @@ -636,10 +626,9 @@ pub(crate) fn href_relative_parts<'fqp>( // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1) if f != r { let dissimilar_part_count = relative_to_fqp.len() - i; - let fqp_module = &fqp[i..fqp.len()]; + let fqp_module = &fqp[i..]; return Box::new( - iter::repeat(sym::dotdot) - .take(dissimilar_part_count) + iter::repeat_n(sym::dotdot, dissimilar_part_count) .chain(fqp_module.iter().copied()), ); } @@ -652,7 +641,7 @@ pub(crate) fn href_relative_parts<'fqp>( Ordering::Greater => { // e.g. linking to std::sync from std::sync::atomic let dissimilar_part_count = relative_to_fqp.len() - fqp.len(); - Box::new(iter::repeat(sym::dotdot).take(dissimilar_part_count)) + Box::new(iter::repeat_n(sym::dotdot, dissimilar_part_count)) } Ordering::Equal => { // linking to the same module @@ -783,10 +772,9 @@ fn primitive_link_fragment( ExternalLocation::Local => { let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()); Some(if cx.current.first() == Some(&cname_sym) { - iter::repeat(sym::dotdot).take(cx.current.len() - 1).collect() + iter::repeat_n(sym::dotdot, cx.current.len() - 1).collect() } else { - iter::repeat(sym::dotdot) - .take(cx.current.len()) + iter::repeat_n(sym::dotdot, cx.current.len()) .chain(iter::once(cname_sym)) .collect() }) @@ -809,11 +797,11 @@ fn primitive_link_fragment( Ok(()) } -fn tybounds<'a, 'tcx: 'a>( - bounds: &'a [clean::PolyTrait], - lt: &'a Option, - cx: &'a Context<'tcx>, -) -> impl Display + 'a + Captures<'tcx> { +fn tybounds( + bounds: &[clean::PolyTrait], + lt: &Option, + cx: &Context<'_>, +) -> impl Display { fmt::from_fn(move |f| { bounds.iter().map(|bound| bound.print(cx)).joined(" + ", f)?; if let Some(lt) = lt { @@ -825,11 +813,11 @@ fn tybounds<'a, 'tcx: 'a>( }) } -fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( - params: &'a [clean::GenericParamDef], - cx: &'a Context<'tcx>, +fn print_higher_ranked_params_with_space( + params: &[clean::GenericParamDef], + cx: &Context<'_>, keyword: &'static str, -) -> impl Display + 'a + Captures<'tcx> { +) -> impl Display { fmt::from_fn(move |f| { if !params.is_empty() { f.write_str(keyword)?; @@ -841,11 +829,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( }) } -pub(crate) fn anchor<'a: 'cx, 'cx>( - did: DefId, - text: Symbol, - cx: &'cx Context<'a>, -) -> impl Display + Captures<'a> + 'cx { +pub(crate) fn anchor(did: DefId, text: Symbol, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { let parts = href(did, cx); if let Ok((url, short_ty, fqp)) = parts { @@ -1121,29 +1105,19 @@ fn fmt_type( } impl clean::Type { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'b + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| fmt_type(self, f, false, cx)) } } impl clean::Path { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'b + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) } } impl clean::Impl { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - use_absolute: bool, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, use_absolute: bool, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { f.write_str("impl")?; self.generics.print(cx).fmt(f)?; @@ -1179,15 +1153,15 @@ impl clean::Impl { self.print_type(&self.for_, f, use_absolute, cx)?; } - print_where_clause(&self.generics, cx, 0, Ending::Newline).fmt(f) + print_where_clause(&self.generics, cx, 0, Ending::Newline).maybe_display().fmt(f) }) } - fn print_type<'a, 'tcx: 'a>( + fn print_type( &self, type_: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool, - cx: &'a Context<'tcx>, + cx: &Context<'_>, ) -> Result<(), fmt::Error> { if let clean::Type::Tuple(types) = type_ && let [clean::Type::Generic(name)] = &types[..] @@ -1258,10 +1232,7 @@ impl clean::Impl { } impl clean::Arguments { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { self.values .iter() @@ -1301,10 +1272,7 @@ impl Display for Indent { } impl clean::FnDecl { - pub(crate) fn print<'b, 'a: 'b, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'b + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { let ellipsis = if self.c_variadic { ", ..." } else { "" }; if f.alternate() { @@ -1333,12 +1301,12 @@ impl clean::FnDecl { /// are preserved. /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is /// necessary. - pub(crate) fn full_print<'a, 'tcx: 'a>( - &'a self, + pub(crate) fn full_print( + &self, header_len: usize, indent: usize, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + cx: &Context<'_>, + ) -> impl Display { fmt::from_fn(move |f| { // First, generate the text form of the declaration, with no line wrapping, and count the bytes. let mut counter = WriteCounter(0); @@ -1420,10 +1388,7 @@ impl clean::FnDecl { self.print_output(cx).fmt(f) } - fn print_output<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + fn print_output(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match &self.output { clean::Tuple(tys) if tys.is_empty() => Ok(()), ty if f.alternate() => { @@ -1434,10 +1399,7 @@ impl clean::FnDecl { } } -pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( - item: &clean::Item, - cx: &'a Context<'tcx>, -) -> impl Display + 'a + Captures<'tcx> { +pub(crate) fn visibility_print_with_space(item: &clean::Item, cx: &Context<'_>) -> impl Display { use std::fmt::Write as _; let vis: Cow<'static, str> = match item.visibility(cx.tcx()) { None => "".into(), @@ -1546,10 +1508,7 @@ pub(crate) fn print_constness_with_space( } impl clean::Import { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match self.kind { clean::ImportKind::Simple(name) => { if name == self.source.path.last() { @@ -1570,10 +1529,7 @@ impl clean::Import { } impl clean::ImportSource { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match self.did { Some(did) => resolved_path(f, did, &self.path, true, false, cx), _ => { @@ -1593,10 +1549,7 @@ impl clean::ImportSource { } impl clean::AssocItemConstraint { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| { f.write_str(self.assoc.name.as_str())?; self.assoc.args.print(cx).fmt(f)?; @@ -1627,15 +1580,12 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display { }) } -pub(crate) fn print_default_space<'a>(v: bool) -> &'a str { +pub(crate) fn print_default_space(v: bool) -> &'static str { if v { "default " } else { "" } } impl clean::GenericArg { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match self { clean::GenericArg::Lifetime(lt) => lt.print().fmt(f), clean::GenericArg::Type(ty) => ty.print(cx).fmt(f), @@ -1646,10 +1596,7 @@ impl clean::GenericArg { } impl clean::Term { - pub(crate) fn print<'a, 'tcx: 'a>( - &'a self, - cx: &'a Context<'tcx>, - ) -> impl Display + 'a + Captures<'tcx> { + pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display { fmt::from_fn(move |f| match self { clean::Term::Type(ty) => ty.print(cx).fmt(f), clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f), diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index ed4b97d36252c..c943d3ad4d056 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -100,7 +100,7 @@ fn write_header( } if let Some(extra) = extra_content { - out.push_str(&extra); + out.push_str(extra); } if class.is_empty() { write_str( @@ -131,7 +131,7 @@ fn write_header( /// * If the other `Class` is unclassified and only contains white characters (backline, /// whitespace, etc), it can be merged. /// * `Class::Ident` is considered the same as unclassified (because it doesn't have an associated -/// CSS class). +/// CSS class). fn can_merge(class1: Option, class2: Option, text: &str) -> bool { match (class1, class2) { (Some(c1), Some(c2)) => c1.is_equal_to(c2), @@ -233,7 +233,7 @@ impl TokenHandler<'_, '_, F> { #[inline] fn write_line_number(&mut self, line: u32, extra: &'static str) { - (self.write_line_number)(&mut self.out, line, extra); + (self.write_line_number)(self.out, line, extra); } } @@ -610,7 +610,7 @@ impl Decorations { let (mut starts, mut ends): (Vec<_>, Vec<_>) = info .0 .iter() - .flat_map(|(&kind, ranges)| ranges.into_iter().map(move |&(lo, hi)| ((lo, kind), hi))) + .flat_map(|(&kind, ranges)| ranges.iter().map(move |&(lo, hi)| ((lo, kind), hi))) .unzip(); // Sort the sequences in document order. @@ -1102,53 +1102,52 @@ fn string_without_closing_tag( }); } - if let Some(href_context) = href_context { - if let Some(href) = - href_context.context.shared.span_correspondence_map.get(&def_span).and_then(|href| { - let context = href_context.context; - // FIXME: later on, it'd be nice to provide two links (if possible) for all items: - // one to the documentation page and one to the source definition. - // FIXME: currently, external items only generate a link to their documentation, - // a link to their definition can be generated using this: - // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 - match href { - LinkFromSrc::Local(span) => { - context.href_from_span_relative(*span, &href_context.current_href) - } - LinkFromSrc::External(def_id) => { - format::href_with_root_path(*def_id, context, Some(href_context.root_path)) - .ok() - .map(|(url, _, _)| url) - } - LinkFromSrc::Primitive(prim) => format::href_with_root_path( - PrimitiveType::primitive_locations(context.tcx())[prim], - context, - Some(href_context.root_path), - ) - .ok() - .map(|(url, _, _)| url), - LinkFromSrc::Doc(def_id) => { - format::href_with_root_path(*def_id, context, Some(href_context.root_path)) - .ok() - .map(|(doc_link, _, _)| doc_link) - } + if let Some(href_context) = href_context + && let Some(href) = href_context.context.shared.span_correspondence_map.get(&def_span) + && let Some(href) = { + let context = href_context.context; + // FIXME: later on, it'd be nice to provide two links (if possible) for all items: + // one to the documentation page and one to the source definition. + // FIXME: currently, external items only generate a link to their documentation, + // a link to their definition can be generated using this: + // https://github.com/rust-lang/rust/blob/60f1a2fc4b535ead9c85ce085fdce49b1b097531/src/librustdoc/html/render/context.rs#L315-L338 + match href { + LinkFromSrc::Local(span) => { + context.href_from_span_relative(*span, &href_context.current_href) } - }) - { - if !open_tag { - // We're already inside an element which has the same klass, no need to give it - // again. + LinkFromSrc::External(def_id) => { + format::href_with_root_path(*def_id, context, Some(href_context.root_path)) + .ok() + .map(|(url, _, _)| url) + } + LinkFromSrc::Primitive(prim) => format::href_with_root_path( + PrimitiveType::primitive_locations(context.tcx())[prim], + context, + Some(href_context.root_path), + ) + .ok() + .map(|(url, _, _)| url), + LinkFromSrc::Doc(def_id) => { + format::href_with_root_path(*def_id, context, Some(href_context.root_path)) + .ok() + .map(|(doc_link, _, _)| doc_link) + } + } + } + { + if !open_tag { + // We're already inside an element which has the same klass, no need to give it + // again. + write!(out, "{text_s}").unwrap(); + } else { + let klass_s = klass.as_html(); + if klass_s.is_empty() { write!(out, "{text_s}").unwrap(); } else { - let klass_s = klass.as_html(); - if klass_s.is_empty() { - write!(out, "{text_s}").unwrap(); - } else { - write!(out, "{text_s}").unwrap(); - } + write!(out, "{text_s}").unwrap(); } - return Some(""); } + return Some(""); } if !open_tag { write!(out, "{}", text_s).unwrap(); diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index d9e49577d3929..079651e860319 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -1308,18 +1308,17 @@ impl LangString { seen_other_tags = true; data.unknown.push(x.to_owned()); } - LangStringToken::KeyValueAttribute(key, value) => { - if key == "class" { - data.added_classes.push(value.to_owned()); - } else if let Some(extra) = extra { - extra.error_invalid_codeblock_attr(format!( - "unsupported attribute `{key}`" - )); - } + LangStringToken::KeyValueAttribute("class", value) => { + data.added_classes.push(value.to_owned()); + } + LangStringToken::KeyValueAttribute(key, ..) if let Some(extra) = extra => { + extra + .error_invalid_codeblock_attr(format!("unsupported attribute `{key}`")); } LangStringToken::ClassAttribute(class) => { data.added_classes.push(class.to_owned()); } + _ => {} } } }; @@ -1792,7 +1791,7 @@ pub(crate) fn markdown_links<'md, R>( } } } else if !c.is_ascii_whitespace() { - while let Some((j, c)) = iter.next() { + for (j, c) in iter.by_ref() { if c.is_ascii_whitespace() { return MarkdownLinkRange::Destination(i + span.start..j + span.start); } diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 146bdd340697b..5f69e79f3ab1f 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -237,8 +237,7 @@ impl<'tcx> Context<'tcx> { }; if !render_redirect_pages { - let mut page_buffer = String::new(); - print_item(self, it, &mut page_buffer); + let content = print_item(self, it); let page = layout::Page { css_class: tyname_s, root_path: &self.root_path(), @@ -254,7 +253,7 @@ impl<'tcx> Context<'tcx> { BufDisplay(|buf: &mut String| { print_sidebar(self, it, buf); }), - page_buffer, + content, &self.shared.style_files, ) } else { diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 204631063a23a..b2ad2fa773ae5 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -38,7 +38,7 @@ mod type_layout; mod write_shared; use std::collections::VecDeque; -use std::fmt::{self, Write}; +use std::fmt::{self, Display as _, Write}; use std::iter::Peekable; use std::path::PathBuf; use std::{fs, str}; @@ -47,7 +47,6 @@ use rinja::Template; use rustc_attr_parsing::{ ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince, }; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::Mutability; use rustc_hir::def_id::{DefId, DefIdSet}; @@ -82,7 +81,7 @@ use crate::html::{highlight, sources}; use crate::scrape_examples::{CallData, CallLocation}; use crate::{DOC_RUST_LANG_ORG_VERSION, try_none}; -pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { +pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display { fmt::from_fn(move |f| { if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) } }) @@ -310,7 +309,7 @@ impl ItemEntry { } impl ItemEntry { - pub(crate) fn print(&self) -> impl fmt::Display + '_ { + pub(crate) fn print(&self) -> impl fmt::Display { fmt::from_fn(move |f| write!(f, "{}", self.url, Escape(&self.name))) } } @@ -505,12 +504,12 @@ fn scrape_examples_help(shared: &SharedContext<'_>) -> String { ) } -fn document<'a, 'cx: 'a>( - cx: &'a Context<'cx>, - item: &'a clean::Item, - parent: Option<&'a clean::Item>, +fn document( + cx: &Context<'_>, + item: &clean::Item, + parent: Option<&clean::Item>, heading_offset: HeadingOffset, -) -> impl fmt::Display + 'a + Captures<'cx> { +) -> impl fmt::Display { if let Some(ref name) = item.name { info!("Documenting {name}"); } @@ -526,12 +525,12 @@ fn document<'a, 'cx: 'a>( } /// Render md_text as markdown. -fn render_markdown<'a, 'cx: 'a>( - cx: &'a Context<'cx>, - md_text: &'a str, +fn render_markdown( + cx: &Context<'_>, + md_text: &str, links: Vec, heading_offset: HeadingOffset, -) -> impl fmt::Display + 'a + Captures<'cx> { +) -> impl fmt::Display { fmt::from_fn(move |f| { write!( f, @@ -552,13 +551,13 @@ fn render_markdown<'a, 'cx: 'a>( /// Writes a documentation block containing only the first paragraph of the documentation. If the /// docs are longer, a "Read more" link is appended to the end. -fn document_short<'a, 'cx: 'a>( - item: &'a clean::Item, - cx: &'a Context<'cx>, - link: AssocItemLink<'a>, - parent: &'a clean::Item, +fn document_short( + item: &clean::Item, + cx: &Context<'_>, + link: AssocItemLink<'_>, + parent: &clean::Item, show_def_docs: bool, -) -> impl fmt::Display + 'a + Captures<'cx> { +) -> impl fmt::Display { fmt::from_fn(move |f| { document_item_info(cx, item, Some(parent)).render_into(f).unwrap(); if !show_def_docs { @@ -595,28 +594,28 @@ fn document_short<'a, 'cx: 'a>( }) } -fn document_full_collapsible<'a, 'cx: 'a>( - item: &'a clean::Item, - cx: &'a Context<'cx>, +fn document_full_collapsible( + item: &clean::Item, + cx: &Context<'_>, heading_offset: HeadingOffset, -) -> impl fmt::Display + 'a + Captures<'cx> { +) -> impl fmt::Display { document_full_inner(item, cx, true, heading_offset) } -fn document_full<'a, 'cx: 'a>( - item: &'a clean::Item, - cx: &'a Context<'cx>, +fn document_full( + item: &clean::Item, + cx: &Context<'_>, heading_offset: HeadingOffset, -) -> impl fmt::Display + 'a + Captures<'cx> { +) -> impl fmt::Display { document_full_inner(item, cx, false, heading_offset) } -fn document_full_inner<'a, 'cx: 'a>( - item: &'a clean::Item, - cx: &'a Context<'cx>, +fn document_full_inner( + item: &clean::Item, + cx: &Context<'_>, is_collapsible: bool, heading_offset: HeadingOffset, -) -> impl fmt::Display + 'a + Captures<'cx> { +) -> impl fmt::Display { fmt::from_fn(move |f| { if let Some(s) = item.opt_doc_value() { debug!("Doc block: =====\n{s}\n====="); @@ -774,9 +773,7 @@ pub(crate) fn render_impls( let did = i.trait_did().unwrap(); let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx()); let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods); - let mut buffer = String::new(); - render_impl( - &mut buffer, + let imp = render_impl( cx, i, containing_item, @@ -791,7 +788,7 @@ pub(crate) fn render_impls( toggle_open_by_default, }, ); - buffer + imp.to_string() }) .collect::>(); rendered_impls.sort(); @@ -799,11 +796,11 @@ pub(crate) fn render_impls( } /// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item. -fn assoc_href_attr<'a, 'tcx>( +fn assoc_href_attr( it: &clean::Item, - link: AssocItemLink<'a>, - cx: &Context<'tcx>, -) -> Option> { + link: AssocItemLink<'_>, + cx: &Context<'_>, +) -> Option { let name = it.name.unwrap(); let item_type = it.type_(); @@ -814,7 +811,7 @@ fn assoc_href_attr<'a, 'tcx>( } let href = match link { - AssocItemLink::Anchor(Some(ref id)) => Href::AnchorId(id), + AssocItemLink::Anchor(Some(id)) => Href::AnchorId(id), AssocItemLink::Anchor(None) => Href::Anchor(item_type), AssocItemLink::GotoSource(did, provided_methods) => { // We're creating a link from the implementation of an associated item to its @@ -880,7 +877,6 @@ enum AssocConstValue<'a> { } fn assoc_const( - w: &mut String, it: &clean::Item, generics: &clean::Generics, ty: &clean::Type, @@ -888,11 +884,11 @@ fn assoc_const( link: AssocItemLink<'_>, indent: usize, cx: &Context<'_>, -) { +) -> impl fmt::Display { let tcx = cx.tcx(); - write_str( - w, - format_args!( + fmt::from_fn(move |w| { + write!( + w, "{indent}{vis}const {name}{generics}: {ty}", indent = " ".repeat(indent), vis = visibility_print_with_space(it, cx), @@ -900,28 +896,27 @@ fn assoc_const( name = it.name.as_ref().unwrap(), generics = generics.print(cx), ty = ty.print(cx), - ), - ); - if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value { - // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the - // hood which adds noisy underscores and a type suffix to number literals. - // This hurts readability in this context especially when more complex expressions - // are involved and it doesn't add much of value. - // Find a way to print constants here without all that jazz. - let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx)); - if match value { - AssocConstValue::TraitDefault(_) => true, // always show - AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show - AssocConstValue::None => unreachable!(), - } { - write_str(w, format_args!(" = {}", Escape(&repr))); + )?; + if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value { + // FIXME: `.value()` uses `clean::utils::format_integer_with_underscore_sep` under the + // hood which adds noisy underscores and a type suffix to number literals. + // This hurts readability in this context especially when more complex expressions + // are involved and it doesn't add much of value. + // Find a way to print constants here without all that jazz. + let repr = konst.value(tcx).unwrap_or_else(|| konst.expr(tcx)); + if match value { + AssocConstValue::TraitDefault(_) => true, // always show + AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show + AssocConstValue::None => unreachable!(), + } { + write!(w, " = {}", Escape(&repr))?; + } } - } - write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline))); + write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display()) + }) } fn assoc_type( - w: &mut String, it: &clean::Item, generics: &clean::Generics, bounds: &[clean::GenericBound], @@ -929,30 +924,29 @@ fn assoc_type( link: AssocItemLink<'_>, indent: usize, cx: &Context<'_>, -) { - write_str( - w, - format_args!( +) -> impl fmt::Display { + fmt::from_fn(move |w| { + write!( + w, "{indent}{vis}type {name}{generics}", indent = " ".repeat(indent), vis = visibility_print_with_space(it, cx), href = assoc_href_attr(it, link, cx).maybe_display(), name = it.name.as_ref().unwrap(), generics = generics.print(cx), - ), - ); - if !bounds.is_empty() { - write_str(w, format_args!(": {}", print_generic_bounds(bounds, cx))); - } - // Render the default before the where-clause which aligns with the new recommended style. See #89122. - if let Some(default) = default { - write_str(w, format_args!(" = {}", default.print(cx))); - } - write_str(w, format_args!("{}", print_where_clause(generics, cx, indent, Ending::NoNewline))); + )?; + if !bounds.is_empty() { + write!(w, ": {}", print_generic_bounds(bounds, cx))?; + } + // Render the default before the where-clause which aligns with the new recommended style. See #89122. + if let Some(default) = default { + write!(w, " = {}", default.print(cx))?; + } + write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display()) + }) } fn assoc_method( - w: &mut String, meth: &clean::Item, g: &clean::Generics, d: &clean::FnDecl, @@ -960,7 +954,7 @@ fn assoc_method( parent: ItemType, cx: &Context<'_>, render_mode: RenderMode, -) { +) -> impl fmt::Display { let tcx = cx.tcx(); let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item"); let name = meth.name.as_ref().unwrap(); @@ -976,61 +970,53 @@ fn assoc_method( ), RenderMode::ForDeref { .. } => "", }; - let asyncness = header.asyncness.print_with_space(); - let safety = header.safety.print_with_space(); - let abi = print_abi_with_space(header.abi).to_string(); - let href = assoc_href_attr(meth, link, cx).maybe_display(); - - // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`. - let generics_len = format!("{:#}", g.print(cx)).len(); - let mut header_len = "fn ".len() - + vis.len() - + defaultness.len() - + constness.len() - + asyncness.len() - + safety.len() - + abi.len() - + name.as_str().len() - + generics_len; - - let notable_traits = notable_traits_button(&d.output, cx).maybe_display(); - - let (indent, indent_str, end_newline) = if parent == ItemType::Trait { - header_len += 4; - let indent_str = " "; - write_str(w, format_args!("{}", render_attributes_in_pre(meth, indent_str, cx))); - (4, indent_str, Ending::NoNewline) - } else { - render_attributes_in_code(w, meth, cx); - (0, "", Ending::Newline) - }; - w.reserve(header_len + "{".len() + "".len()); - write_str( - w, - format_args!( + + fmt::from_fn(move |w| { + let asyncness = header.asyncness.print_with_space(); + let safety = header.safety.print_with_space(); + let abi = print_abi_with_space(header.abi).to_string(); + let href = assoc_href_attr(meth, link, cx).maybe_display(); + + // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`. + let generics_len = format!("{:#}", g.print(cx)).len(); + let mut header_len = "fn ".len() + + vis.len() + + defaultness.len() + + constness.len() + + asyncness.len() + + safety.len() + + abi.len() + + name.as_str().len() + + generics_len; + + let notable_traits = notable_traits_button(&d.output, cx).maybe_display(); + + let (indent, indent_str, end_newline) = if parent == ItemType::Trait { + header_len += 4; + let indent_str = " "; + write!(w, "{}", render_attributes_in_pre(meth, indent_str, cx))?; + (4, indent_str, Ending::NoNewline) + } else { + render_attributes_in_code(w, meth, cx); + (0, "", Ending::Newline) + }; + write!( + w, "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \ - {name}{generics}{decl}{notable_traits}{where_clause}", + {name}{generics}{decl}{notable_traits}{where_clause}", indent = indent_str, - vis = vis, - defaultness = defaultness, - constness = constness, - asyncness = asyncness, - safety = safety, - abi = abi, - href = href, - name = name, generics = g.print(cx), decl = d.full_print(header_len, indent, cx), - where_clause = print_where_clause(g, cx, indent, end_newline), - ), - ); + where_clause = print_where_clause(g, cx, indent, end_newline).maybe_display(), + ) + }) } /// Writes a span containing the versions at which an item became stable and/or const-stable. For /// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would /// write a span containing "1.0.0 (const: 1.45.0)". /// -/// Returns `true` if a stability annotation was rendered. +/// Returns `None` if there is no stability annotation to be rendered. /// /// Stability and const-stability are considered separately. If the item is unstable, no version /// will be written. If the item is const-unstable, "const: unstable" will be appended to the @@ -1041,11 +1027,10 @@ fn assoc_method( /// will include the const-stable version, but no stable version will be emitted, as a natural /// consequence of the above rules. fn render_stability_since_raw_with_extra( - w: &mut String, stable_version: Option, const_stability: Option, extra_class: &str, -) -> bool { +) -> Option { let mut title = String::new(); let mut stability = String::new(); @@ -1095,14 +1080,9 @@ fn render_stability_since_raw_with_extra( } } - if !stability.is_empty() { - write_str( - w, - format_args!(r#"{stability}"#), - ); - } - - !stability.is_empty() + (!stability.is_empty()).then_some(fmt::from_fn(move |w| { + write!(w, r#"{stability}"#) + })) } fn since_to_string(since: &StableSince) -> Option { @@ -1115,31 +1095,25 @@ fn since_to_string(since: &StableSince) -> Option { #[inline] fn render_stability_since_raw( - w: &mut String, ver: Option, const_stability: Option, -) -> bool { - render_stability_since_raw_with_extra(w, ver, const_stability, "") +) -> Option { + render_stability_since_raw_with_extra(ver, const_stability, "") } fn render_assoc_item( - w: &mut String, item: &clean::Item, link: AssocItemLink<'_>, parent: ItemType, cx: &Context<'_>, render_mode: RenderMode, -) { - match &item.kind { - clean::StrippedItem(..) => {} - clean::RequiredMethodItem(m) => { - assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) - } - clean::MethodItem(m, _) => { - assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode) +) -> impl fmt::Display { + fmt::from_fn(move |f| match &item.kind { + clean::StrippedItem(..) => Ok(()), + clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => { + assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f) } clean::RequiredAssocConstItem(generics, ty) => assoc_const( - w, item, generics, ty, @@ -1147,9 +1121,9 @@ fn render_assoc_item( link, if parent == ItemType::Trait { 4 } else { 0 }, cx, - ), + ) + .fmt(f), clean::ProvidedAssocConstItem(ci) => assoc_const( - w, item, &ci.generics, &ci.type_, @@ -1157,9 +1131,9 @@ fn render_assoc_item( link, if parent == ItemType::Trait { 4 } else { 0 }, cx, - ), + ) + .fmt(f), clean::ImplAssocConstItem(ci) => assoc_const( - w, item, &ci.generics, &ci.type_, @@ -1167,9 +1141,9 @@ fn render_assoc_item( link, if parent == ItemType::Trait { 4 } else { 0 }, cx, - ), - clean::RequiredAssocTypeItem(ref generics, ref bounds) => assoc_type( - w, + ) + .fmt(f), + clean::RequiredAssocTypeItem(generics, bounds) => assoc_type( item, generics, bounds, @@ -1177,9 +1151,9 @@ fn render_assoc_item( link, if parent == ItemType::Trait { 4 } else { 0 }, cx, - ), - clean::AssocTypeItem(ref ty, ref bounds) => assoc_type( - w, + ) + .fmt(f), + clean::AssocTypeItem(ty, bounds) => assoc_type( item, &ty.generics, bounds, @@ -1187,18 +1161,15 @@ fn render_assoc_item( link, if parent == ItemType::Trait { 4 } else { 0 }, cx, - ), + ) + .fmt(f), _ => panic!("render_assoc_item called on non-associated-item"), - } + }) } // When an attribute is rendered inside a `
` tag, it is formatted using
 // a whitespace prefix and newline.
-fn render_attributes_in_pre<'a, 'tcx: 'a>(
-    it: &'a clean::Item,
-    prefix: &'a str,
-    cx: &'a Context<'tcx>,
-) -> impl fmt::Display + Captures<'a> + Captures<'tcx> {
+fn render_attributes_in_pre(it: &clean::Item, prefix: &str, cx: &Context<'_>) -> impl fmt::Display {
     fmt::from_fn(move |f| {
         for a in it.attributes(cx.tcx(), cx.cache(), false) {
             writeln!(f, "{prefix}{a}")?;
@@ -1231,28 +1202,28 @@ impl<'a> AssocItemLink<'a> {
 }
 
 pub fn write_section_heading(
-    w: &mut impl fmt::Write,
     title: &str,
     id: &str,
     extra_class: Option<&str>,
     extra: impl fmt::Display,
-) {
-    let (extra_class, whitespace) = match extra_class {
-        Some(extra) => (extra, " "),
-        None => ("", ""),
-    };
-    write!(
-        w,
-        "

\ +) -> impl fmt::Display { + fmt::from_fn(move |w| { + let (extra_class, whitespace) = match extra_class { + Some(extra) => (extra, " "), + None => ("", ""), + }; + write!( + w, + "

\ {title}\ §\

{extra}", - ) - .unwrap(); + ) + }) } -fn write_impl_section_heading(w: &mut impl fmt::Write, title: &str, id: &str) { - write_section_heading(w, title, id, None, "") +fn write_impl_section_heading(title: &str, id: &str) -> impl fmt::Display { + write_section_heading(title, id, None, "") } pub(crate) fn render_all_impls( @@ -1269,35 +1240,43 @@ pub(crate) fn render_all_impls( buf }; if !impls.is_empty() { - write_impl_section_heading(&mut w, "Trait Implementations", "trait-implementations"); - write!(w, "
{impls}
").unwrap(); + write!( + w, + "{}
{impls}
", + write_impl_section_heading("Trait Implementations", "trait-implementations") + ) + .unwrap(); } if !synthetic.is_empty() { - write_impl_section_heading( - &mut w, - "Auto Trait Implementations", - "synthetic-implementations", - ); - w.write_str("
").unwrap(); + write!( + w, + "{}
", + write_impl_section_heading("Auto Trait Implementations", "synthetic-implementations",) + ) + .unwrap(); render_impls(cx, &mut w, synthetic, containing_item, false); w.write_str("
").unwrap(); } if !blanket_impl.is_empty() { - write_impl_section_heading(&mut w, "Blanket Implementations", "blanket-implementations"); - w.write_str("
").unwrap(); + write!( + w, + "{}
", + write_impl_section_heading("Blanket Implementations", "blanket-implementations") + ) + .unwrap(); render_impls(cx, &mut w, blanket_impl, containing_item, false); w.write_str("
").unwrap(); } } -fn render_assoc_items<'a, 'cx: 'a>( - cx: &'a Context<'cx>, - containing_item: &'a clean::Item, +fn render_assoc_items( + cx: &Context<'_>, + containing_item: &clean::Item, it: DefId, - what: AssocItemRender<'a>, -) -> impl fmt::Display + 'a + Captures<'cx> { + what: AssocItemRender<'_>, +) -> impl fmt::Display { fmt::from_fn(move |f| { let mut derefs = DefIdSet::default(); derefs.insert(it); @@ -1323,25 +1302,34 @@ fn render_assoc_items_inner( let mut tmp_buf = String::new(); let (render_mode, id, class_html) = match what { AssocItemRender::All => { - write_impl_section_heading(&mut tmp_buf, "Implementations", "implementations"); + write_str( + &mut tmp_buf, + format_args!( + "{}", + write_impl_section_heading("Implementations", "implementations") + ), + ); (RenderMode::Normal, "implementations-list".to_owned(), "") } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { let id = cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx)))); let derived_id = cx.derive_id(&id); - tmp_buf.push_str("
"); close_tags.push("
"); - write_impl_section_heading( + write_str( &mut tmp_buf, - &format!( - "Methods from {trait_}<Target = {type_}>", - trait_ = trait_.print(cx), - type_ = type_.print(cx), + format_args!( + "
{}", + write_impl_section_heading( + &format!( + "Methods from {trait_}<Target = {type_}>", + trait_ = trait_.print(cx), + type_ = type_.print(cx), + ), + &id, + ) ), - &id, ); - tmp_buf.push_str(""); if let Some(def_id) = type_.def_id(cx.cache()) { cx.deref_id_map.borrow_mut().insert(def_id, id); } @@ -1350,21 +1338,26 @@ fn render_assoc_items_inner( }; let mut impls_buf = String::new(); for i in &non_trait { - render_impl( + write_str( &mut impls_buf, - cx, - i, - containing_item, - AssocItemLink::Anchor(None), - render_mode, - None, - &[], - ImplRenderingParameters { - show_def_docs: true, - show_default_items: true, - show_non_assoc_items: true, - toggle_open_by_default: true, - }, + format_args!( + "{}", + render_impl( + cx, + i, + containing_item, + AssocItemLink::Anchor(None), + render_mode, + None, + &[], + ImplRenderingParameters { + show_def_docs: true, + show_default_items: true, + show_non_assoc_items: true, + toggle_open_by_default: true, + }, + ) + ), ); } if !impls_buf.is_empty() { @@ -1468,10 +1461,10 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> } } -pub(crate) fn notable_traits_button<'a, 'tcx>( - ty: &'a clean::Type, - cx: &'a Context<'tcx>, -) -> Option> { +pub(crate) fn notable_traits_button( + ty: &clean::Type, + cx: &Context<'_>, +) -> Option { let mut has_notable_trait = false; if ty.is_unit() { @@ -1564,20 +1557,23 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { ); for it in &impl_.items { if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind { - out.push_str("
"); let empty_set = FxIndexSet::default(); let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set); - assoc_type( + write_str( &mut out, - it, - &tydef.generics, - &[], // intentionally leaving out bounds - Some(&tydef.type_), - src_link, - 0, - cx, + format_args!( + "
{};
", + assoc_type( + it, + &tydef.generics, + &[], // intentionally leaving out bounds + Some(&tydef.type_), + src_link, + 0, + cx, + ) + ), ); - out.push_str(";
"); } } } @@ -1623,7 +1619,6 @@ struct ImplRenderingParameters { } fn render_impl( - w: &mut String, cx: &Context<'_>, i: &Impl, parent: &clean::Item, @@ -1632,513 +1627,549 @@ fn render_impl( use_absolute: Option, aliases: &[String], rendering_params: ImplRenderingParameters, -) { - let cache = &cx.shared.cache; - let traits = &cache.traits; - let trait_ = i.trait_did().map(|did| &traits[&did]); - let mut close_tags = >::with_capacity(2); - - // For trait implementations, the `interesting` output contains all methods that have doc - // comments, and the `boring` output contains all methods that do not. The distinction is - // used to allow hiding the boring methods. - // `containing_item` is used for rendering stability info. If the parent is a trait impl, - // `containing_item` will the grandparent, since trait impls can't have stability attached. - fn doc_impl_item( - boring: &mut String, - interesting: &mut String, - cx: &Context<'_>, - item: &clean::Item, - parent: &clean::Item, - link: AssocItemLink<'_>, - render_mode: RenderMode, - is_default_item: bool, - trait_: Option<&clean::Trait>, - rendering_params: ImplRenderingParameters, - ) { - let item_type = item.type_(); - let name = item.name.as_ref().unwrap(); - - let render_method_item = rendering_params.show_non_assoc_items - && match render_mode { - RenderMode::Normal => true, - RenderMode::ForDeref { mut_: deref_mut_ } => { - should_render_item(item, deref_mut_, cx.tcx()) - } - }; +) -> impl fmt::Display { + fmt::from_fn(move |w| { + let cache = &cx.shared.cache; + let traits = &cache.traits; + let trait_ = i.trait_did().map(|did| &traits[&did]); + let mut close_tags = >::with_capacity(2); + + // For trait implementations, the `interesting` output contains all methods that have doc + // comments, and the `boring` output contains all methods that do not. The distinction is + // used to allow hiding the boring methods. + // `containing_item` is used for rendering stability info. If the parent is a trait impl, + // `containing_item` will the grandparent, since trait impls can't have stability attached. + fn doc_impl_item( + boring: &mut String, + interesting: &mut String, + cx: &Context<'_>, + item: &clean::Item, + parent: &clean::Item, + link: AssocItemLink<'_>, + render_mode: RenderMode, + is_default_item: bool, + trait_: Option<&clean::Trait>, + rendering_params: ImplRenderingParameters, + ) { + let item_type = item.type_(); + let name = item.name.as_ref().unwrap(); + + let render_method_item = rendering_params.show_non_assoc_items + && match render_mode { + RenderMode::Normal => true, + RenderMode::ForDeref { mut_: deref_mut_ } => { + should_render_item(item, deref_mut_, cx.tcx()) + } + }; - let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" }; - - let mut doc_buffer = String::new(); - let mut info_buffer = String::new(); - let mut short_documented = true; - - if render_method_item { - if !is_default_item { - if let Some(t) = trait_ { - // The trait item may have been stripped so we might not - // find any documentation or stability for it. - if let Some(it) = t.items.iter().find(|i| i.name == item.name) { - // We need the stability of the item from the trait - // because impls can't have a stability. - if !item.doc_value().is_empty() { - document_item_info(cx, it, Some(parent)) - .render_into(&mut info_buffer) - .unwrap(); + let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" }; + + let mut doc_buffer = String::new(); + let mut info_buffer = String::new(); + let mut short_documented = true; + + if render_method_item { + if !is_default_item { + if let Some(t) = trait_ { + // The trait item may have been stripped so we might not + // find any documentation or stability for it. + if let Some(it) = t.items.iter().find(|i| i.name == item.name) { + // We need the stability of the item from the trait + // because impls can't have a stability. + if !item.doc_value().is_empty() { + document_item_info(cx, it, Some(parent)) + .render_into(&mut info_buffer) + .unwrap(); + write_str( + &mut doc_buffer, + format_args!("{}", document_full(item, cx, HeadingOffset::H5)), + ); + short_documented = false; + } else { + // In case the item isn't documented, + // provide short documentation from the trait. + write_str( + &mut doc_buffer, + format_args!( + "{}", + document_short( + it, + cx, + link, + parent, + rendering_params.show_def_docs, + ) + ), + ); + } + } + } else { + document_item_info(cx, item, Some(parent)) + .render_into(&mut info_buffer) + .unwrap(); + if rendering_params.show_def_docs { write_str( &mut doc_buffer, format_args!("{}", document_full(item, cx, HeadingOffset::H5)), ); short_documented = false; - } else { - // In case the item isn't documented, - // provide short documentation from the trait. - write_str( - &mut doc_buffer, - format_args!( - "{}", - document_short( - it, - cx, - link, - parent, - rendering_params.show_def_docs, - ) - ), - ); } } } else { - document_item_info(cx, item, Some(parent)) - .render_into(&mut info_buffer) - .unwrap(); - if rendering_params.show_def_docs { - write_str( - &mut doc_buffer, - format_args!("{}", document_full(item, cx, HeadingOffset::H5)), - ); - short_documented = false; - } + write_str( + &mut doc_buffer, + format_args!( + "{}", + document_short(item, cx, link, parent, rendering_params.show_def_docs) + ), + ); } - } else { + } + let w = if short_documented && trait_.is_some() { interesting } else { boring }; + + let toggled = !doc_buffer.is_empty(); + if toggled { + let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; write_str( - &mut doc_buffer, - format_args!( - "{}", - document_short(item, cx, link, parent, rendering_params.show_def_docs) - ), + w, + format_args!("
"), ); } - } - let w = if short_documented && trait_.is_some() { interesting } else { boring }; - - let toggled = !doc_buffer.is_empty(); - if toggled { - let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write_str( - w, - format_args!("
"), - ); - } - match &item.kind { - clean::MethodItem(..) | clean::RequiredMethodItem(_) => { - // Only render when the method is not static or we allow static methods - if render_method_item { - let id = cx.derive_id(format!("{item_type}.{name}")); - let source_id = trait_ - .and_then(|trait_| { - trait_ - .items - .iter() - .find(|item| item.name.map(|n| n == *name).unwrap_or(false)) - }) - .map(|item| format!("{}.{name}", item.type_())); + match &item.kind { + clean::MethodItem(..) | clean::RequiredMethodItem(_) => { + // Only render when the method is not static or we allow static methods + if render_method_item { + let id = cx.derive_id(format!("{item_type}.{name}")); + let source_id = trait_ + .and_then(|trait_| { + trait_ + .items + .iter() + .find(|item| item.name.map(|n| n == *name).unwrap_or(false)) + }) + .map(|item| format!("{}.{name}", item.type_())); + write_str( + w, + format_args!( + "
\ + {}", + render_rightside(cx, item, render_mode) + ), + ); + if trait_.is_some() { + // Anchors are only used on trait impls. + write_str(w, format_args!("§")); + } + write_str( + w, + format_args!( + "

{}

", + render_assoc_item( + item, + link.anchor(source_id.as_ref().unwrap_or(&id)), + ItemType::Impl, + cx, + render_mode, + ), + ), + ); + } + } + clean::RequiredAssocConstItem(generics, ty) => { + let source_id = format!("{item_type}.{name}"); + let id = cx.derive_id(&source_id); write_str( w, - format_args!("
"), + format_args!( + "
\ + {}", + render_rightside(cx, item, render_mode) + ), ); - render_rightside(w, cx, item, render_mode); if trait_.is_some() { // Anchors are only used on trait impls. write_str(w, format_args!("§")); } - w.push_str("

"); - render_assoc_item( + write_str( w, - item, - link.anchor(source_id.as_ref().unwrap_or(&id)), - ItemType::Impl, - cx, - render_mode, + format_args!( + "

{}

", + assoc_const( + item, + generics, + ty, + AssocConstValue::None, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, + ) + ), ); - w.push_str("
"); } - } - clean::RequiredAssocConstItem(ref generics, ref ty) => { - let source_id = format!("{item_type}.{name}"); - let id = cx.derive_id(&source_id); - write_str( - w, - format_args!("
"), - ); - render_rightside(w, cx, item, render_mode); - if trait_.is_some() { - // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => { + let source_id = format!("{item_type}.{name}"); + let id = cx.derive_id(&source_id); + write_str( + w, + format_args!( + "
\ + {}", + render_rightside(cx, item, render_mode) + ), + ); + if trait_.is_some() { + // Anchors are only used on trait impls. + write_str(w, format_args!("§")); + } + write_str( + w, + format_args!( + "

{}

", + assoc_const( + item, + &ci.generics, + &ci.type_, + match item.kind { + clean::ProvidedAssocConstItem(_) => + AssocConstValue::TraitDefault(&ci.kind), + clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind), + _ => unreachable!(), + }, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, + ) + ), + ); } - w.push_str("

"); - assoc_const( - w, - item, - generics, - ty, - AssocConstValue::None, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ); - w.push_str("

"); - } - clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => { - let source_id = format!("{item_type}.{name}"); - let id = cx.derive_id(&source_id); - write_str( - w, - format_args!("
"), - ); - render_rightside(w, cx, item, render_mode); - if trait_.is_some() { - // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + clean::RequiredAssocTypeItem(generics, bounds) => { + let source_id = format!("{item_type}.{name}"); + let id = cx.derive_id(&source_id); + write_str( + w, + format_args!( + "
\ + {}", + render_rightside(cx, item, render_mode) + ), + ); + if trait_.is_some() { + // Anchors are only used on trait impls. + write_str(w, format_args!("§")); + } + write_str( + w, + format_args!( + "

{}

", + assoc_type( + item, + generics, + bounds, + None, + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, + ) + ), + ); } - w.push_str("

"); - assoc_const( - w, - item, - &ci.generics, - &ci.type_, - match item.kind { - clean::ProvidedAssocConstItem(_) => AssocConstValue::TraitDefault(&ci.kind), - clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind), - _ => unreachable!(), - }, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, - cx, - ); - w.push_str("

"); + clean::AssocTypeItem(tydef, _bounds) => { + let source_id = format!("{item_type}.{name}"); + let id = cx.derive_id(&source_id); + write_str( + w, + format_args!( + "
\ + {}", + render_rightside(cx, item, render_mode) + ), + ); + if trait_.is_some() { + // Anchors are only used on trait impls. + write_str(w, format_args!("§")); + } + write_str( + w, + format_args!( + "

{}

", + assoc_type( + item, + &tydef.generics, + &[], // intentionally leaving out bounds + Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)), + link.anchor(if trait_.is_some() { &source_id } else { &id }), + 0, + cx, + ) + ), + ); + } + clean::StrippedItem(..) => return, + _ => panic!("can't make docs for trait item with name {:?}", item.name), } - clean::RequiredAssocTypeItem(ref generics, ref bounds) => { - let source_id = format!("{item_type}.{name}"); - let id = cx.derive_id(&source_id); - write_str( - w, - format_args!("
"), - ); - render_rightside(w, cx, item, render_mode); - if trait_.is_some() { - // Anchors are only used on trait impls. - write_str(w, format_args!("§")); + + w.push_str(&info_buffer); + if toggled { + w.push_str("
"); + w.push_str(&doc_buffer); + w.push_str("
"); + } + } + + let mut impl_items = String::new(); + let mut default_impl_items = String::new(); + let impl_ = i.inner_impl(); + + // Impl items are grouped by kinds: + // + // 1. Constants + // 2. Types + // 3. Functions + // + // This order is because you can have associated constants used in associated types (like array + // length), and both in associcated functions. So with this order, when reading from top to + // bottom, you should see items definitions before they're actually used most of the time. + let mut assoc_types = Vec::new(); + let mut methods = Vec::new(); + + if !impl_.is_negative_trait_impl() { + for trait_item in &impl_.items { + match trait_item.kind { + clean::MethodItem(..) | clean::RequiredMethodItem(_) => { + methods.push(trait_item) + } + clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => { + assoc_types.push(trait_item) + } + clean::RequiredAssocConstItem(..) + | clean::ProvidedAssocConstItem(_) + | clean::ImplAssocConstItem(_) => { + // We render it directly since they're supposed to come first. + doc_impl_item( + &mut default_impl_items, + &mut impl_items, + cx, + trait_item, + if trait_.is_some() { &i.impl_item } else { parent }, + link, + render_mode, + false, + trait_, + rendering_params, + ); + } + _ => {} } - w.push_str("

"); - assoc_type( - w, - item, - generics, - bounds, - None, - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, + } + + for assoc_type in assoc_types { + doc_impl_item( + &mut default_impl_items, + &mut impl_items, cx, + assoc_type, + if trait_.is_some() { &i.impl_item } else { parent }, + link, + render_mode, + false, + trait_, + rendering_params, ); - w.push_str("

"); } - clean::AssocTypeItem(tydef, _bounds) => { - let source_id = format!("{item_type}.{name}"); - let id = cx.derive_id(&source_id); - write_str( - w, - format_args!("
"), - ); - render_rightside(w, cx, item, render_mode); - if trait_.is_some() { - // Anchors are only used on trait impls. - write_str(w, format_args!("§")); - } - w.push_str("

"); - assoc_type( - w, - item, - &tydef.generics, - &[], // intentionally leaving out bounds - Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)), - link.anchor(if trait_.is_some() { &source_id } else { &id }), - 0, + for method in methods { + doc_impl_item( + &mut default_impl_items, + &mut impl_items, cx, + method, + if trait_.is_some() { &i.impl_item } else { parent }, + link, + render_mode, + false, + trait_, + rendering_params, ); - w.push_str("

"); } - clean::StrippedItem(..) => return, - _ => panic!("can't make docs for trait item with name {:?}", item.name), } - w.push_str(&info_buffer); - if toggled { - w.push_str("
"); - w.push_str(&doc_buffer); - w.push_str("
"); - } - } - - let mut impl_items = String::new(); - let mut default_impl_items = String::new(); - let impl_ = i.inner_impl(); - - // Impl items are grouped by kinds: - // - // 1. Constants - // 2. Types - // 3. Functions - // - // This order is because you can have associated constants used in associated types (like array - // length), and both in associcated functions. So with this order, when reading from top to - // bottom, you should see items definitions before they're actually used most of the time. - let mut assoc_types = Vec::new(); - let mut methods = Vec::new(); - - if !impl_.is_negative_trait_impl() { - for trait_item in &impl_.items { - match trait_item.kind { - clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(trait_item), - clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => { - assoc_types.push(trait_item) + fn render_default_items( + boring: &mut String, + interesting: &mut String, + cx: &Context<'_>, + t: &clean::Trait, + i: &clean::Impl, + parent: &clean::Item, + render_mode: RenderMode, + rendering_params: ImplRenderingParameters, + ) { + for trait_item in &t.items { + // Skip over any default trait items that are impossible to reference + // (e.g. if it has a `Self: Sized` bound on an unsized type). + if let Some(impl_def_id) = parent.item_id.as_def_id() + && let Some(trait_item_def_id) = trait_item.item_id.as_def_id() + && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id)) + { + continue; } - clean::RequiredAssocConstItem(..) - | clean::ProvidedAssocConstItem(_) - | clean::ImplAssocConstItem(_) => { - // We render it directly since they're supposed to come first. - doc_impl_item( - &mut default_impl_items, - &mut impl_items, - cx, - trait_item, - if trait_.is_some() { &i.impl_item } else { parent }, - link, - render_mode, - false, - trait_, - rendering_params, - ); + + let n = trait_item.name; + if i.items.iter().any(|m| m.name == n) { + continue; } - _ => {} - } - } + let did = i.trait_.as_ref().unwrap().def_id(); + let provided_methods = i.provided_trait_methods(cx.tcx()); + let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods); - for assoc_type in assoc_types { - doc_impl_item( - &mut default_impl_items, - &mut impl_items, - cx, - assoc_type, - if trait_.is_some() { &i.impl_item } else { parent }, - link, - render_mode, - false, - trait_, - rendering_params, - ); - } - for method in methods { - doc_impl_item( - &mut default_impl_items, - &mut impl_items, - cx, - method, - if trait_.is_some() { &i.impl_item } else { parent }, - link, - render_mode, - false, - trait_, - rendering_params, - ); + doc_impl_item( + boring, + interesting, + cx, + trait_item, + parent, + assoc_link, + render_mode, + true, + Some(t), + rendering_params, + ); + } } - } - fn render_default_items( - boring: &mut String, - interesting: &mut String, - cx: &Context<'_>, - t: &clean::Trait, - i: &clean::Impl, - parent: &clean::Item, - render_mode: RenderMode, - rendering_params: ImplRenderingParameters, - ) { - for trait_item in &t.items { - // Skip over any default trait items that are impossible to reference - // (e.g. if it has a `Self: Sized` bound on an unsized type). - if let Some(impl_def_id) = parent.item_id.as_def_id() - && let Some(trait_item_def_id) = trait_item.item_id.as_def_id() - && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id)) + // If we've implemented a trait, then also emit documentation for all + // default items which weren't overridden in the implementation block. + // We don't emit documentation for default items if they appear in the + // Implementations on Foreign Types or Implementors sections. + if rendering_params.show_default_items { + if let Some(t) = trait_ + && !impl_.is_negative_trait_impl() { - continue; - } - - let n = trait_item.name; - if i.items.iter().any(|m| m.name == n) { - continue; + render_default_items( + &mut default_impl_items, + &mut impl_items, + cx, + t, + impl_, + &i.impl_item, + render_mode, + rendering_params, + ); } - let did = i.trait_.as_ref().unwrap().def_id(); - let provided_methods = i.provided_trait_methods(cx.tcx()); - let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods); - - doc_impl_item( - boring, - interesting, - cx, - trait_item, - parent, - assoc_link, - render_mode, - true, - Some(t), - rendering_params, - ); - } - } - - // If we've implemented a trait, then also emit documentation for all - // default items which weren't overridden in the implementation block. - // We don't emit documentation for default items if they appear in the - // Implementations on Foreign Types or Implementors sections. - if rendering_params.show_default_items { - if let Some(t) = trait_ - && !impl_.is_negative_trait_impl() - { - render_default_items( - &mut default_impl_items, - &mut impl_items, - cx, - t, - impl_, - &i.impl_item, - render_mode, - rendering_params, - ); } - } - if render_mode == RenderMode::Normal { - let toggled = !(impl_items.is_empty() && default_impl_items.is_empty()); - if toggled { - close_tags.push("
"); - write_str( - w, - format_args!( + if render_mode == RenderMode::Normal { + let toggled = !(impl_items.is_empty() && default_impl_items.is_empty()); + if toggled { + close_tags.push(""); + write!( + w, "
\ ", if rendering_params.toggle_open_by_default { " open" } else { "" } - ), - ); - } + )?; + } - let (before_dox, after_dox) = i - .impl_item - .opt_doc_value() - .map(|dox| { - Markdown { - content: &dox, - links: &i.impl_item.links(cx), - ids: &mut cx.id_map.borrow_mut(), - error_codes: cx.shared.codes, - edition: cx.shared.edition(), - playground: &cx.shared.playground, - heading_offset: HeadingOffset::H4, - } - .split_summary_and_content() - }) - .unwrap_or((None, None)); - render_impl_summary( - w, - cx, - i, - parent, - rendering_params.show_def_docs, - use_absolute, - aliases, - &before_dox, - ); - if toggled { - w.push_str(""); - } + let (before_dox, after_dox) = i + .impl_item + .opt_doc_value() + .map(|dox| { + Markdown { + content: &dox, + links: &i.impl_item.links(cx), + ids: &mut cx.id_map.borrow_mut(), + error_codes: cx.shared.codes, + edition: cx.shared.edition(), + playground: &cx.shared.playground, + heading_offset: HeadingOffset::H4, + } + .split_summary_and_content() + }) + .unwrap_or((None, None)); + write!( + w, + "{}", + render_impl_summary( + cx, + i, + parent, + rendering_params.show_def_docs, + use_absolute, + aliases, + before_dox.as_deref(), + ) + )?; + if toggled { + w.write_str("")?; + } - if before_dox.is_some() { - if trait_.is_none() && impl_.items.is_empty() { - w.push_str( - "
\ + if before_dox.is_some() { + if trait_.is_none() && impl_.items.is_empty() { + w.write_str( + "
\
This impl block contains no items.
\
", - ); + )?; + } + if let Some(after_dox) = after_dox { + write!(w, "
{after_dox}
")?; + } } - if let Some(after_dox) = after_dox { - write_str(w, format_args!("
{after_dox}
")); + if !default_impl_items.is_empty() || !impl_items.is_empty() { + w.write_str("
")?; + close_tags.push("
"); } } if !default_impl_items.is_empty() || !impl_items.is_empty() { - w.push_str("
"); - close_tags.push("
"); + w.write_str(&default_impl_items)?; + w.write_str(&impl_items)?; } - } - if !default_impl_items.is_empty() || !impl_items.is_empty() { - w.push_str(&default_impl_items); - w.push_str(&impl_items); - } - for tag in close_tags.into_iter().rev() { - w.push_str(tag); - } + for tag in close_tags.into_iter().rev() { + w.write_str(tag)?; + } + Ok(()) + }) } // Render the items that appear on the right side of methods, impls, and // associated types. For example "1.0.0 (const: 1.39.0) · source". -fn render_rightside(w: &mut String, cx: &Context<'_>, item: &clean::Item, render_mode: RenderMode) { +fn render_rightside( + cx: &Context<'_>, + item: &clean::Item, + render_mode: RenderMode, +) -> impl fmt::Display { let tcx = cx.tcx(); - // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove - // this condition. - let const_stability = match render_mode { - RenderMode::Normal => item.const_stability(tcx), - RenderMode::ForDeref { .. } => None, - }; - let src_href = cx.src_href(item); - let has_src_ref = src_href.is_some(); - - let mut rightside = String::new(); - let has_stability = render_stability_since_raw_with_extra( - &mut rightside, - item.stable_since(tcx), - const_stability, - if has_src_ref { "" } else { " rightside" }, - ); - if let Some(link) = src_href { - if has_stability { - write_str( - &mut rightside, - format_args!(" · Source"), - ); - } else { - write_str( - &mut rightside, - format_args!("Source"), - ); + fmt::from_fn(move |w| { + // FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove + // this condition. + let const_stability = match render_mode { + RenderMode::Normal => item.const_stability(tcx), + RenderMode::ForDeref { .. } => None, + }; + let src_href = cx.src_href(item); + let stability = render_stability_since_raw_with_extra( + item.stable_since(tcx), + const_stability, + if src_href.is_some() { "" } else { " rightside" }, + ); + + match (stability, src_href) { + (Some(stability), Some(link)) => { + write!( + w, + "{stability} · Source", + ) + } + (Some(stability), None) => { + write!(w, "{stability}") + } + (None, Some(link)) => { + write!(w, "Source") + } + (None, None) => Ok(()), } - } - if has_stability && has_src_ref { - write_str(w, format_args!("{rightside}")); - } else { - w.push_str(&rightside); - } + }) } pub(crate) fn render_impl_summary( - w: &mut String, cx: &Context<'_>, i: &Impl, parent: &clean::Item, @@ -2147,67 +2178,67 @@ pub(crate) fn render_impl_summary( // This argument is used to reference same type with different paths to avoid duplication // in documentation pages for trait with automatic implementations like "Send" and "Sync". aliases: &[String], - doc: &Option, -) { - let inner_impl = i.inner_impl(); - let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id)); - let aliases = (!aliases.is_empty()) - .then_some(fmt::from_fn(|f| { - write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f))) - })) - .maybe_display(); - write_str(w, format_args!("
")); - render_rightside(w, cx, &i.impl_item, RenderMode::Normal); - write_str( - w, - format_args!( - "§\ -

" - ), - ); - - if let Some(use_absolute) = use_absolute { - write_str(w, format_args!("{}", inner_impl.print(use_absolute, cx))); - if show_def_docs { - for it in &inner_impl.items { - if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind { - w.push_str("
"); - assoc_type( - w, - it, - &tydef.generics, - &[], // intentionally leaving out bounds - Some(&tydef.type_), - AssocItemLink::Anchor(None), - 0, - cx, - ); - w.push_str(";
"); + doc: Option<&str>, +) -> impl fmt::Display { + fmt::from_fn(move |w| { + let inner_impl = i.inner_impl(); + let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id)); + let aliases = (!aliases.is_empty()) + .then_some(fmt::from_fn(|f| { + write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f))) + })) + .maybe_display(); + write!( + w, + "
\ + {}\ + §\ +

", + render_rightside(cx, &i.impl_item, RenderMode::Normal) + )?; + + if let Some(use_absolute) = use_absolute { + write!(w, "{}", inner_impl.print(use_absolute, cx))?; + if show_def_docs { + for it in &inner_impl.items { + if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind { + write!( + w, + "
{};
", + assoc_type( + it, + &tydef.generics, + &[], // intentionally leaving out bounds + Some(&tydef.type_), + AssocItemLink::Anchor(None), + 0, + cx, + ) + )?; + } } } + } else { + write!(w, "{}", inner_impl.print(false, cx))?; } - } else { - write_str(w, format_args!("{}", inner_impl.print(false, cx))); - } - w.push_str("

"); + w.write_str("

")?; - let is_trait = inner_impl.trait_.is_some(); - if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) { - write_str( - w, - format_args!( + let is_trait = inner_impl.trait_.is_some(); + if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) { + write!( + w, "\ -
{portability}
\ -
", - ), - ); - } +
{portability}
\ + ", + )?; + } - if let Some(doc) = doc { - write_str(w, format_args!("
{doc}
")); - } + if let Some(doc) = doc { + write!(w, "
{doc}
")?; + } - w.push_str("
"); + w.write_str("") + }) } pub(crate) fn small_url_encode(s: String) -> String { diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f320114703996..3c5c2ce19767d 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1,10 +1,9 @@ use std::cmp::Ordering; -use std::fmt; -use std::fmt::Display; +use std::fmt::{self, Display, Write as _}; +use std::iter; use rinja::Template; use rustc_abi::VariantIdx; -use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::CtorKind; @@ -32,7 +31,7 @@ use crate::formats::item_type::ItemType; use crate::html::escape::{Escape, EscapeBodyTextWithWbr}; use crate::html::format::{ Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space, - print_constness_with_space, print_where_clause, visibility_print_with_space, write_str, + print_constness_with_space, print_where_clause, visibility_print_with_space, }; use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; use crate::html::render::{document_full, document_item_info}; @@ -92,44 +91,32 @@ macro_rules! item_template { macro_rules! item_template_methods { () => {}; (document $($rest:tt)*) => { - fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - fmt::from_fn(move |f| { - let (item, cx) = self.item_and_cx(); - let v = document(cx, item, None, HeadingOffset::H2); - write!(f, "{v}") - }) + fn document(&self) -> impl fmt::Display { + let (item, cx) = self.item_and_cx(); + document(cx, item, None, HeadingOffset::H2) } item_template_methods!($($rest)*); }; (document_type_layout $($rest:tt)*) => { - fn document_type_layout<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - fmt::from_fn(move |f| { - let (item, cx) = self.item_and_cx(); - let def_id = item.item_id.expect_def_id(); - let v = document_type_layout(cx, def_id); - write!(f, "{v}") - }) + fn document_type_layout(&self) -> impl fmt::Display { + let (item, cx) = self.item_and_cx(); + let def_id = item.item_id.expect_def_id(); + document_type_layout(cx, def_id) } item_template_methods!($($rest)*); }; (render_attributes_in_pre $($rest:tt)*) => { - fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - fmt::from_fn(move |f| { - let (item, cx) = self.item_and_cx(); - let v = render_attributes_in_pre(item, "", cx); - write!(f, "{v}") - }) + fn render_attributes_in_pre(&self) -> impl fmt::Display { + let (item, cx) = self.item_and_cx(); + render_attributes_in_pre(item, "", cx) } item_template_methods!($($rest)*); }; (render_assoc_items $($rest:tt)*) => { - fn render_assoc_items<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - fmt::from_fn(move |f| { - let (item, cx) = self.item_and_cx(); - let def_id = item.item_id.expect_def_id(); - let v = render_assoc_items(cx, item, def_id, AssocItemRender::All); - write!(f, "{v}") - }) + fn render_assoc_items(&self) -> impl fmt::Display { + let (item, cx) = self.item_and_cx(); + let def_id = item.item_id.expect_def_id(); + render_assoc_items(cx, item, def_id, AssocItemRender::All) } item_template_methods!($($rest)*); }; @@ -162,132 +149,136 @@ struct ItemVars<'a> { src_href: Option<&'a str>, } -/// Calls `print_where_clause` and returns `true` if a `where` clause was generated. -fn print_where_clause_and_check<'a, 'tcx: 'a>( - buffer: &mut String, - gens: &'a clean::Generics, - cx: &'a Context<'tcx>, -) -> bool { - let len_before = buffer.len(); - write_str(buffer, format_args!("{}", print_where_clause(gens, cx, 0, Ending::Newline))); - len_before != buffer.len() -} - -pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut String) { +pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item) -> impl fmt::Display { debug_assert!(!item.is_stripped()); - let typ = match item.kind { - clean::ModuleItem(_) => { - if item.is_crate() { - "Crate " - } else { - "Module " - } - } - clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ", - clean::TraitItem(..) => "Trait ", - clean::StructItem(..) => "Struct ", - clean::UnionItem(..) => "Union ", - clean::EnumItem(..) => "Enum ", - clean::TypeAliasItem(..) => "Type Alias ", - clean::MacroItem(..) => "Macro ", - clean::ProcMacroItem(ref mac) => match mac.kind { - MacroKind::Bang => "Macro ", - MacroKind::Attr => "Attribute Macro ", - MacroKind::Derive => "Derive Macro ", - }, - clean::PrimitiveItem(..) => "Primitive Type ", - clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ", - clean::ConstantItem(..) => "Constant ", - clean::ForeignTypeItem => "Foreign Type ", - clean::KeywordItem => "Keyword ", - clean::TraitAliasItem(..) => "Trait Alias ", - _ => { - // We don't generate pages for any other type. - unreachable!(); - } - }; - let stability_since_raw = { - let mut buf = String::new(); - render_stability_since_raw( - &mut buf, - item.stable_since(cx.tcx()), - item.const_stability(cx.tcx()), - ); - buf - }; - // Write source tag - // - // When this item is part of a `crate use` in a downstream crate, the - // source link in the downstream documentation will actually come back to - // this page, and this link will be auto-clicked. The `id` attribute is - // used to find the link to auto-click. - let src_href = - if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None }; - - let path_components = if item.is_primitive() || item.is_keyword() { - vec![] - } else { - let cur = &cx.current; - let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() }; - cur.iter() - .enumerate() - .take(amt) - .map(|(i, component)| PathComponent { - path: "../".repeat(cur.len() - i - 1), - name: *component, - }) - .collect() - }; + fmt::from_fn(|buf| { + let typ = match item.kind { + clean::ModuleItem(_) => { + if item.is_crate() { + "Crate " + } else { + "Module " + } + } + clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ", + clean::TraitItem(..) => "Trait ", + clean::StructItem(..) => "Struct ", + clean::UnionItem(..) => "Union ", + clean::EnumItem(..) => "Enum ", + clean::TypeAliasItem(..) => "Type Alias ", + clean::MacroItem(..) => "Macro ", + clean::ProcMacroItem(ref mac) => match mac.kind { + MacroKind::Bang => "Macro ", + MacroKind::Attr => "Attribute Macro ", + MacroKind::Derive => "Derive Macro ", + }, + clean::PrimitiveItem(..) => "Primitive Type ", + clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ", + clean::ConstantItem(..) => "Constant ", + clean::ForeignTypeItem => "Foreign Type ", + clean::KeywordItem => "Keyword ", + clean::TraitAliasItem(..) => "Trait Alias ", + _ => { + // We don't generate pages for any other type. + unreachable!(); + } + }; + let stability_since_raw = + render_stability_since_raw(item.stable_since(cx.tcx()), item.const_stability(cx.tcx())) + .maybe_display() + .to_string(); + + // Write source tag + // + // When this item is part of a `crate use` in a downstream crate, the + // source link in the downstream documentation will actually come back to + // this page, and this link will be auto-clicked. The `id` attribute is + // used to find the link to auto-click. + let src_href = + if cx.info.include_sources && !item.is_primitive() { cx.src_href(item) } else { None }; + + let path_components = if item.is_primitive() || item.is_keyword() { + vec![] + } else { + let cur = &cx.current; + let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() }; + cur.iter() + .enumerate() + .take(amt) + .map(|(i, component)| PathComponent { + path: "../".repeat(cur.len() - i - 1), + name: *component, + }) + .collect() + }; - let item_vars = ItemVars { - typ, - name: item.name.as_ref().unwrap().as_str(), - item_type: &item.type_().to_string(), - path_components, - stability_since_raw: &stability_since_raw, - src_href: src_href.as_deref(), - }; + let item_vars = ItemVars { + typ, + name: item.name.as_ref().unwrap().as_str(), + item_type: &item.type_().to_string(), + path_components, + stability_since_raw: &stability_since_raw, + src_href: src_href.as_deref(), + }; - item_vars.render_into(buf).unwrap(); + item_vars.render_into(buf).unwrap(); - match &item.kind { - clean::ModuleItem(ref m) => item_module(buf, cx, item, &m.items), - clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f, _) => { - item_function(buf, cx, item, f) - } - clean::TraitItem(ref t) => item_trait(buf, cx, item, t), - clean::StructItem(ref s) => item_struct(buf, cx, item, s), - clean::UnionItem(ref s) => item_union(buf, cx, item, s), - clean::EnumItem(ref e) => item_enum(buf, cx, item, e), - clean::TypeAliasItem(ref t) => item_type_alias(buf, cx, item, t), - clean::MacroItem(ref m) => item_macro(buf, cx, item, m), - clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), - clean::PrimitiveItem(_) => item_primitive(buf, cx, item), - clean::StaticItem(ref i) => item_static(buf, cx, item, i, None), - clean::ForeignStaticItem(ref i, safety) => item_static(buf, cx, item, i, Some(*safety)), - clean::ConstantItem(ci) => item_constant(buf, cx, item, &ci.generics, &ci.type_, &ci.kind), - clean::ForeignTypeItem => item_foreign_type(buf, cx, item), - clean::KeywordItem => item_keyword(buf, cx, item), - clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta), - _ => { - // We don't generate pages for any other type. - unreachable!(); - } - } + match &item.kind { + clean::ModuleItem(m) => { + write!(buf, "{}", item_module(cx, item, &m.items)) + } + clean::FunctionItem(f) | clean::ForeignFunctionItem(f, _) => { + write!(buf, "{}", item_function(cx, item, f)) + } + clean::TraitItem(t) => write!(buf, "{}", item_trait(cx, item, t)), + clean::StructItem(s) => { + write!(buf, "{}", item_struct(cx, item, s)) + } + clean::UnionItem(s) => write!(buf, "{}", item_union(cx, item, s)), + clean::EnumItem(e) => write!(buf, "{}", item_enum(cx, item, e)), + clean::TypeAliasItem(t) => { + write!(buf, "{}", item_type_alias(cx, item, t)) + } + clean::MacroItem(m) => write!(buf, "{}", item_macro(cx, item, m)), + clean::ProcMacroItem(m) => { + write!(buf, "{}", item_proc_macro(cx, item, m)) + } + clean::PrimitiveItem(_) => write!(buf, "{}", item_primitive(cx, item)), + clean::StaticItem(i) => { + write!(buf, "{}", item_static(cx, item, i, None)) + } + clean::ForeignStaticItem(i, safety) => { + write!(buf, "{}", item_static(cx, item, i, Some(*safety))) + } + clean::ConstantItem(ci) => { + write!(buf, "{}", item_constant(cx, item, &ci.generics, &ci.type_, &ci.kind)) + } + clean::ForeignTypeItem => { + write!(buf, "{}", item_foreign_type(cx, item)) + } + clean::KeywordItem => write!(buf, "{}", item_keyword(cx, item)), + clean::TraitAliasItem(ta) => { + write!(buf, "{}", item_trait_alias(cx, item, ta)) + } + _ => { + // We don't generate pages for any other type. + unreachable!(); + } + }?; - // Render notable-traits.js used for all methods in this module. - let mut types_with_notable_traits = cx.types_with_notable_traits.borrow_mut(); - if !types_with_notable_traits.is_empty() { - write_str( - buf, - format_args!( + // Render notable-traits.js used for all methods in this module. + let mut types_with_notable_traits = cx.types_with_notable_traits.borrow_mut(); + if !types_with_notable_traits.is_empty() { + write!( + buf, r#""#, - notable_traits_json(types_with_notable_traits.iter(), cx) - ), - ); - types_with_notable_traits.clear(); - } + notable_traits_json(types_with_notable_traits.iter(), cx), + )?; + types_with_notable_traits.clear(); + } + Ok(()) + }) } /// For large structs, enums, unions, etc, determine whether to hide their fields @@ -314,192 +305,194 @@ trait ItemTemplate<'a, 'cx: 'a>: rinja::Template + Display { fn item_and_cx(&self) -> (&'a clean::Item, &'a Context<'cx>); } -fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) { - write_str(w, format_args!("{}", document(cx, item, None, HeadingOffset::H2))); - - let mut not_stripped_items = - items.iter().filter(|i| !i.is_stripped()).enumerate().collect::>(); - - // the order of item types in the listing - fn reorder(ty: ItemType) -> u8 { - match ty { - ItemType::ExternCrate => 0, - ItemType::Import => 1, - ItemType::Primitive => 2, - ItemType::Module => 3, - ItemType::Macro => 4, - ItemType::Struct => 5, - ItemType::Enum => 6, - ItemType::Constant => 7, - ItemType::Static => 8, - ItemType::Trait => 9, - ItemType::Function => 10, - ItemType::TypeAlias => 12, - ItemType::Union => 13, - _ => 14 + ty as u8, +fn item_module(cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) -> impl fmt::Display { + fmt::from_fn(|w| { + write!(w, "{}", document(cx, item, None, HeadingOffset::H2))?; + + let mut not_stripped_items = + items.iter().filter(|i| !i.is_stripped()).enumerate().collect::>(); + + // the order of item types in the listing + fn reorder(ty: ItemType) -> u8 { + match ty { + ItemType::ExternCrate => 0, + ItemType::Import => 1, + ItemType::Primitive => 2, + ItemType::Module => 3, + ItemType::Macro => 4, + ItemType::Struct => 5, + ItemType::Enum => 6, + ItemType::Constant => 7, + ItemType::Static => 8, + ItemType::Trait => 9, + ItemType::Function => 10, + ItemType::TypeAlias => 12, + ItemType::Union => 13, + _ => 14 + ty as u8, + } } - } - fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering { - let rty1 = reorder(i1.type_()); - let rty2 = reorder(i2.type_()); - if rty1 != rty2 { - return rty1.cmp(&rty2); - } - let is_stable1 = i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true); - let is_stable2 = i2.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true); - if is_stable1 != is_stable2 { - // true is bigger than false in the standard bool ordering, - // but we actually want stable items to come first - return is_stable2.cmp(&is_stable1); + fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering { + let rty1 = reorder(i1.type_()); + let rty2 = reorder(i2.type_()); + if rty1 != rty2 { + return rty1.cmp(&rty2); + } + let is_stable1 = + i1.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true); + let is_stable2 = + i2.stability(tcx).as_ref().map(|s| s.level.is_stable()).unwrap_or(true); + if is_stable1 != is_stable2 { + // true is bigger than false in the standard bool ordering, + // but we actually want stable items to come first + return is_stable2.cmp(&is_stable1); + } + let lhs = i1.name.unwrap_or(kw::Empty); + let rhs = i2.name.unwrap_or(kw::Empty); + compare_names(lhs.as_str(), rhs.as_str()) } - let lhs = i1.name.unwrap_or(kw::Empty); - let rhs = i2.name.unwrap_or(kw::Empty); - compare_names(lhs.as_str(), rhs.as_str()) - } - let tcx = cx.tcx(); + let tcx = cx.tcx(); - match cx.shared.module_sorting { - ModuleSorting::Alphabetical => { - not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx)); - } - ModuleSorting::DeclarationOrder => {} - } - // This call is to remove re-export duplicates in cases such as: - // - // ``` - // pub(crate) mod foo { - // pub(crate) mod bar { - // pub(crate) trait Double { fn foo(); } - // } - // } - // - // pub(crate) use foo::bar::*; - // pub(crate) use foo::*; - // ``` - // - // `Double` will appear twice in the generated docs. - // - // FIXME: This code is quite ugly and could be improved. Small issue: DefId - // can be identical even if the elements are different (mostly in imports). - // So in case this is an import, we keep everything by adding a "unique id" - // (which is the position in the vector). - not_stripped_items.dedup_by_key(|(idx, i)| { - ( - i.item_id, - if i.name.is_some() { Some(full_path(cx, i)) } else { None }, - i.type_(), - if i.is_import() { *idx } else { 0 }, - ) - }); + match cx.shared.module_sorting { + ModuleSorting::Alphabetical => { + not_stripped_items.sort_by(|(_, i1), (_, i2)| cmp(i1, i2, tcx)); + } + ModuleSorting::DeclarationOrder => {} + } + // This call is to remove re-export duplicates in cases such as: + // + // ``` + // pub(crate) mod foo { + // pub(crate) mod bar { + // pub(crate) trait Double { fn foo(); } + // } + // } + // + // pub(crate) use foo::bar::*; + // pub(crate) use foo::*; + // ``` + // + // `Double` will appear twice in the generated docs. + // + // FIXME: This code is quite ugly and could be improved. Small issue: DefId + // can be identical even if the elements are different (mostly in imports). + // So in case this is an import, we keep everything by adding a "unique id" + // (which is the position in the vector). + not_stripped_items.dedup_by_key(|(idx, i)| { + ( + i.item_id, + if i.name.is_some() { Some(full_path(cx, i)) } else { None }, + i.type_(), + if i.is_import() { *idx } else { 0 }, + ) + }); - debug!("{not_stripped_items:?}"); - let mut last_section = None; + debug!("{not_stripped_items:?}"); + let mut last_section = None; - for (_, myitem) in ¬_stripped_items { - let my_section = item_ty_to_section(myitem.type_()); - if Some(my_section) != last_section { - if last_section.is_some() { - w.push_str(ITEM_TABLE_CLOSE); + for (_, myitem) in ¬_stripped_items { + let my_section = item_ty_to_section(myitem.type_()); + if Some(my_section) != last_section { + if last_section.is_some() { + w.write_str(ITEM_TABLE_CLOSE)?; + } + last_section = Some(my_section); + let section_id = my_section.id(); + let tag = + if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN }; + write!( + w, + "{}", + write_section_heading(my_section.name(), &cx.derive_id(section_id), None, tag) + )?; } - last_section = Some(my_section); - let section_id = my_section.id(); - let tag = - if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN }; - write_section_heading(w, my_section.name(), &cx.derive_id(section_id), None, tag); - } - match myitem.kind { - clean::ExternCrateItem { ref src } => { - use crate::html::format::anchor; + match myitem.kind { + clean::ExternCrateItem { ref src } => { + use crate::html::format::anchor; - match *src { - Some(src) => { - write_str( - w, - format_args!( + match *src { + Some(src) => { + write!( + w, "
{}extern crate {} as {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), src, cx), EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()) - ), - ); - } - None => { - write_str( - w, - format_args!( + )?; + } + None => { + write!( + w, "
{}extern crate {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx) - ), - ); + )?; + } } + w.write_str("
")?; } - w.push_str(""); - } - clean::ImportItem(ref import) => { - let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| { - extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() - }); + clean::ImportItem(ref import) => { + let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| { + extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() + }); - let id = match import.kind { - clean::ImportKind::Simple(s) => { - format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}"))) - } - clean::ImportKind::Glob => String::new(), - }; - write_str( - w, - format_args!( + let id = match import.kind { + clean::ImportKind::Simple(s) => { + format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}"))) + } + clean::ImportKind::Glob => String::new(), + }; + write!( + w, "\ {vis}{imp}{stab_tags}\ ", vis = visibility_print_with_space(myitem, cx), imp = import.print(cx) - ), - ); - } - - _ => { - if myitem.name.is_none() { - continue; + )?; } - let unsafety_flag = match myitem.kind { - clean::FunctionItem(_) | clean::ForeignFunctionItem(..) - if myitem.fn_header(tcx).unwrap().is_unsafe() => - { - "" - } - clean::ForeignStaticItem(_, hir::Safety::Unsafe) => { - "" + _ => { + if myitem.name.is_none() { + continue; } - _ => "", - }; - let visibility_and_hidden = match myitem.visibility(tcx) { - Some(ty::Visibility::Restricted(_)) => { - if myitem.is_doc_hidden() { - // Don't separate with a space when there are two of them - " 🔒👻 " - } else { - " 🔒 " + let unsafety_flag = match myitem.kind { + clean::FunctionItem(_) | clean::ForeignFunctionItem(..) + if myitem.fn_header(tcx).unwrap().is_unsafe() => + { + "" } - } - _ if myitem.is_doc_hidden() => " 👻 ", - _ => "", - }; - - let docs = - MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string(); - let (docs_before, docs_after) = - if docs.is_empty() { ("", "") } else { ("
", "
") }; - write_str( - w, - format_args!( + clean::ForeignStaticItem(_, hir::Safety::Unsafe) => { + "" + } + _ => "", + }; + + let visibility_and_hidden = match myitem.visibility(tcx) { + Some(ty::Visibility::Restricted(_)) => { + if myitem.is_doc_hidden() { + // Don't separate with a space when there are two of them + " 🔒👻 " + } else { + " 🔒 " + } + } + _ if myitem.is_doc_hidden() => { + " 👻 " + } + _ => "", + }; + + let docs = + MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string(); + let (docs_before, docs_after) = + if docs.is_empty() { ("", "") } else { ("
", "
") }; + write!( + w, "
\ {name}\ {visibility_and_hidden}\ @@ -514,27 +507,28 @@ fn item_module(w: &mut String, cx: &Context<'_>, item: &clean::Item, items: &[cl unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), title = format_args!("{} {}", myitem.type_(), full_path(cx, myitem)), - ), - ); + )?; + } } } - } - if last_section.is_some() { - w.push_str(ITEM_TABLE_CLOSE); - } + if last_section.is_some() { + w.write_str(ITEM_TABLE_CLOSE)?; + } + Ok(()) + }) } /// Render the stability, deprecation and portability tags that are displayed in the item's summary /// at the module level. -fn extra_info_tags<'a, 'tcx: 'a>( - tcx: TyCtxt<'tcx>, - item: &'a clean::Item, - parent: &'a clean::Item, +fn extra_info_tags( + tcx: TyCtxt<'_>, + item: &clean::Item, + parent: &clean::Item, import_def_id: Option, -) -> impl Display + 'a + Captures<'tcx> { +) -> impl Display { fmt::from_fn(move |f| { - fn tag_html<'a>(class: &'a str, title: &'a str, contents: &'a str) -> impl Display + 'a { + fn tag_html(class: &str, title: &str, contents: &str) -> impl Display { fmt::from_fn(move |f| { write!( f, @@ -583,44 +577,43 @@ fn extra_info_tags<'a, 'tcx: 'a>( }) } -fn item_function(w: &mut String, cx: &Context<'_>, it: &clean::Item, f: &clean::Function) { - let tcx = cx.tcx(); - let header = it.fn_header(tcx).expect("printing a function which isn't a function"); - debug!( - "item_function/const: {:?} {:?} {:?} {:?}", - it.name, - &header.constness, - it.stable_since(tcx), - it.const_stability(tcx), - ); - let constness = print_constness_with_space( - &header.constness, - it.stable_since(tcx), - it.const_stability(tcx), - ); - let safety = header.safety.print_with_space(); - let abi = print_abi_with_space(header.abi).to_string(); - let asyncness = header.asyncness.print_with_space(); - let visibility = visibility_print_with_space(it, cx).to_string(); - let name = it.name.unwrap(); - - let generics_len = format!("{:#}", f.generics.print(cx)).len(); - let header_len = "fn ".len() - + visibility.len() - + constness.len() - + asyncness.len() - + safety.len() - + abi.len() - + name.as_str().len() - + generics_len; - - let notable_traits = notable_traits_button(&f.decl.output, cx).maybe_display(); - - wrap_item(w, |w| { - w.reserve(header_len); - write_str( - w, - format_args!( +fn item_function(cx: &Context<'_>, it: &clean::Item, f: &clean::Function) -> impl fmt::Display { + fmt::from_fn(|w| { + let tcx = cx.tcx(); + let header = it.fn_header(tcx).expect("printing a function which isn't a function"); + debug!( + "item_function/const: {:?} {:?} {:?} {:?}", + it.name, + &header.constness, + it.stable_since(tcx), + it.const_stability(tcx), + ); + let constness = print_constness_with_space( + &header.constness, + it.stable_since(tcx), + it.const_stability(tcx), + ); + let safety = header.safety.print_with_space(); + let abi = print_abi_with_space(header.abi).to_string(); + let asyncness = header.asyncness.print_with_space(); + let visibility = visibility_print_with_space(it, cx).to_string(); + let name = it.name.unwrap(); + + let generics_len = format!("{:#}", f.generics.print(cx)).len(); + let header_len = "fn ".len() + + visibility.len() + + constness.len() + + asyncness.len() + + safety.len() + + abi.len() + + name.as_str().len() + + generics_len; + + let notable_traits = notable_traits_button(&f.decl.output, cx).maybe_display(); + + wrap_item(w, |w| { + write!( + w, "{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \ {name}{generics}{decl}{notable_traits}{where_clause}", attrs = render_attributes_in_pre(it, "", cx), @@ -631,35 +624,37 @@ fn item_function(w: &mut String, cx: &Context<'_>, it: &clean::Item, f: &clean:: abi = abi, name = name, generics = f.generics.print(cx), - where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline), + where_clause = + print_where_clause(&f.generics, cx, 0, Ending::Newline).maybe_display(), decl = f.decl.full_print(header_len, 0, cx), - ), - ); - }); - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); + ) + })?; + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + }) } -fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) { - let tcx = cx.tcx(); - let bounds = bounds(&t.bounds, false, cx); - let required_types = - t.items.iter().filter(|m| m.is_required_associated_type()).collect::>(); - let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); - let required_consts = - t.items.iter().filter(|m| m.is_required_associated_const()).collect::>(); - let provided_consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); - let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::>(); - let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::>(); - let count_types = required_types.len() + provided_types.len(); - let count_consts = required_consts.len() + provided_consts.len(); - let count_methods = required_methods.len() + provided_methods.len(); - let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone(); - - // Output the trait definition - wrap_item(w, |mut w| { - write_str( - w, - format_args!( +fn item_trait(cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) -> impl fmt::Display { + fmt::from_fn(|w| { + let tcx = cx.tcx(); + let bounds = bounds(&t.bounds, false, cx); + let required_types = + t.items.iter().filter(|m| m.is_required_associated_type()).collect::>(); + let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); + let required_consts = + t.items.iter().filter(|m| m.is_required_associated_const()).collect::>(); + let provided_consts = + t.items.iter().filter(|m| m.is_associated_const()).collect::>(); + let required_methods = t.items.iter().filter(|m| m.is_ty_method()).collect::>(); + let provided_methods = t.items.iter().filter(|m| m.is_method()).collect::>(); + let count_types = required_types.len() + provided_types.len(); + let count_consts = required_consts.len() + provided_consts.len(); + let count_methods = required_methods.len() + provided_methods.len(); + let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone(); + + // Output the trait definition + wrap_item(w, |mut w| { + write!( + w, "{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}", attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it, cx), @@ -667,747 +662,804 @@ fn item_trait(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra is_auto = if t.is_auto(tcx) { "auto " } else { "" }, name = it.name.unwrap(), generics = t.generics.print(cx), - ), - ); - - if !t.generics.where_predicates.is_empty() { - write_str( - w, - format_args!("{}", print_where_clause(&t.generics, cx, 0, Ending::Newline)), - ); - } else { - w.push_str(" "); - } + )?; - if t.items.is_empty() { - w.push_str("{ }"); - } else { - // FIXME: we should be using a derived_id for the Anchors here - w.push_str("{\n"); - let mut toggle = false; - - // If there are too many associated types, hide _everything_ - if should_hide_fields(count_types) { - toggle = true; - toggle_open( - &mut w, - format_args!("{} associated items", count_types + count_consts + count_methods), - ); + if !t.generics.where_predicates.is_empty() { + write!( + w, + "{}", + print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display() + )?; + } else { + w.write_char(' ')?; } - for types in [&required_types, &provided_types] { - for t in types { - render_assoc_item( - w, - t, - AssocItemLink::Anchor(None), - ItemType::Trait, - cx, - RenderMode::Normal, + + if t.items.is_empty() { + w.write_str("{ }") + } else { + // FIXME: we should be using a derived_id for the Anchors here + w.write_str("{\n")?; + let mut toggle = false; + + // If there are too many associated types, hide _everything_ + if should_hide_fields(count_types) { + toggle = true; + toggle_open( + &mut w, + format_args!( + "{} associated items", + count_types + count_consts + count_methods + ), ); - w.push_str(";\n"); } - } - // If there are too many associated constants, hide everything after them - // We also do this if the types + consts is large because otherwise we could - // render a bunch of types and _then_ a bunch of consts just because both were - // _just_ under the limit - if !toggle && should_hide_fields(count_types + count_consts) { - toggle = true; - toggle_open( - &mut w, - format_args!( - "{count_consts} associated constant{plural_const} and \ + for types in [&required_types, &provided_types] { + for t in types { + writeln!( + w, + "{};", + render_assoc_item( + t, + AssocItemLink::Anchor(None), + ItemType::Trait, + cx, + RenderMode::Normal, + ) + )?; + } + } + // If there are too many associated constants, hide everything after them + // We also do this if the types + consts is large because otherwise we could + // render a bunch of types and _then_ a bunch of consts just because both were + // _just_ under the limit + if !toggle && should_hide_fields(count_types + count_consts) { + toggle = true; + toggle_open( + &mut w, + format_args!( + "{count_consts} associated constant{plural_const} and \ {count_methods} method{plural_method}", - plural_const = pluralize(count_consts), - plural_method = pluralize(count_methods), - ), - ); - } - if count_types != 0 && (count_consts != 0 || count_methods != 0) { - w.push_str("\n"); - } - for consts in [&required_consts, &provided_consts] { - for c in consts { - render_assoc_item( - w, - c, - AssocItemLink::Anchor(None), - ItemType::Trait, - cx, - RenderMode::Normal, + plural_const = pluralize(count_consts), + plural_method = pluralize(count_methods), + ), ); - w.push_str(";\n"); } - } - if !toggle && should_hide_fields(count_methods) { - toggle = true; - toggle_open(&mut w, format_args!("{count_methods} methods")); - } - if count_consts != 0 && count_methods != 0 { - w.push_str("\n"); - } - - if !required_methods.is_empty() { - write_str( - w, - format_args_nl!(" // Required method{}", pluralize(required_methods.len())), - ); - } - for (pos, m) in required_methods.iter().enumerate() { - render_assoc_item( - w, - m, - AssocItemLink::Anchor(None), - ItemType::Trait, - cx, - RenderMode::Normal, - ); - w.push_str(";\n"); + if count_types != 0 && (count_consts != 0 || count_methods != 0) { + w.write_str("\n")?; + } + for consts in [&required_consts, &provided_consts] { + for c in consts { + writeln!( + w, + "{};", + render_assoc_item( + c, + AssocItemLink::Anchor(None), + ItemType::Trait, + cx, + RenderMode::Normal, + ) + )?; + } + } + if !toggle && should_hide_fields(count_methods) { + toggle = true; + toggle_open(&mut w, format_args!("{count_methods} methods")); + } + if count_consts != 0 && count_methods != 0 { + w.write_str("\n")?; + } - if pos < required_methods.len() - 1 { - w.push_str(""); + if !required_methods.is_empty() { + writeln!(w, " // Required method{}", pluralize(required_methods.len()))?; } - } - if !required_methods.is_empty() && !provided_methods.is_empty() { - w.push_str("\n"); - } + for (pos, m) in required_methods.iter().enumerate() { + writeln!( + w, + "{};", + render_assoc_item( + m, + AssocItemLink::Anchor(None), + ItemType::Trait, + cx, + RenderMode::Normal, + ) + )?; - if !provided_methods.is_empty() { - write_str( - w, - format_args_nl!(" // Provided method{}", pluralize(provided_methods.len())), - ); - } - for (pos, m) in provided_methods.iter().enumerate() { - render_assoc_item( - w, - m, - AssocItemLink::Anchor(None), - ItemType::Trait, - cx, - RenderMode::Normal, - ); + if pos < required_methods.len() - 1 { + w.write_str("")?; + } + } + if !required_methods.is_empty() && !provided_methods.is_empty() { + w.write_str("\n")?; + } - w.push_str(" { ... }\n"); + if !provided_methods.is_empty() { + writeln!(w, " // Provided method{}", pluralize(provided_methods.len()))?; + } + for (pos, m) in provided_methods.iter().enumerate() { + writeln!( + w, + "{} {{ ... }}", + render_assoc_item( + m, + AssocItemLink::Anchor(None), + ItemType::Trait, + cx, + RenderMode::Normal, + ) + )?; - if pos < provided_methods.len() - 1 { - w.push_str(""); + if pos < provided_methods.len() - 1 { + w.write_str("")?; + } } + if toggle { + toggle_close(&mut w); + } + w.write_str("}") } - if toggle { - toggle_close(&mut w); - } - w.push_str("}"); - } - }); + })?; - // Trait documentation - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); + // Trait documentation + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; - fn trait_item(w: &mut String, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) { - let name = m.name.unwrap(); - info!("Documenting {name} on {ty_name:?}", ty_name = t.name); - let item_type = m.type_(); - let id = cx.derive_id(format!("{item_type}.{name}")); + fn trait_item(cx: &Context<'_>, m: &clean::Item, t: &clean::Item) -> impl fmt::Display { + fmt::from_fn(|w| { + let name = m.name.unwrap(); + info!("Documenting {name} on {ty_name:?}", ty_name = t.name); + let item_type = m.type_(); + let id = cx.derive_id(format!("{item_type}.{name}")); - let mut content = String::new(); - write_str(&mut content, format_args!("{}", document_full(m, cx, HeadingOffset::H5))); + let content = document_full(m, cx, HeadingOffset::H5).to_string(); - let toggled = !content.is_empty(); - if toggled { - let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" }; - write_str( - w, - format_args!("
"), - ); - } - write_str(w, format_args!("
")); - render_rightside(w, cx, m, RenderMode::Normal); - write_str(w, format_args!("

")); - render_assoc_item( - w, - m, - AssocItemLink::Anchor(Some(&id)), - ItemType::Impl, - cx, - RenderMode::Normal, - ); - w.push_str("

"); - document_item_info(cx, m, Some(t)).render_into(w).unwrap(); - if toggled { - write_str(w, format_args!("
")); - w.push_str(&content); - write_str(w, format_args!("
")); + let toggled = !content.is_empty(); + if toggled { + let method_toggle_class = + if item_type.is_method() { " method-toggle" } else { "" }; + write!(w, "
")?; + } + write!( + w, + "
\ + {}\ +

{}

", + render_rightside(cx, m, RenderMode::Normal), + render_assoc_item( + m, + AssocItemLink::Anchor(Some(&id)), + ItemType::Impl, + cx, + RenderMode::Normal, + ) + )?; + document_item_info(cx, m, Some(t)).render_into(w).unwrap(); + if toggled { + write!(w, "
{content}
")?; + } + Ok(()) + }) } - } - if !required_consts.is_empty() { - write_section_heading( - w, - "Required Associated Constants", - "required-associated-consts", - None, - "
", - ); - for t in required_consts { - trait_item(w, cx, t, it); + if !required_consts.is_empty() { + write!( + w, + "{}", + write_section_heading( + "Required Associated Constants", + "required-associated-consts", + None, + "
", + ) + )?; + for t in required_consts { + write!(w, "{}", trait_item(cx, t, it))?; + } + w.write_str("
")?; } - w.push_str("
"); - } - if !provided_consts.is_empty() { - write_section_heading( - w, - "Provided Associated Constants", - "provided-associated-consts", - None, - "
", - ); - for t in provided_consts { - trait_item(w, cx, t, it); + if !provided_consts.is_empty() { + write!( + w, + "{}", + write_section_heading( + "Provided Associated Constants", + "provided-associated-consts", + None, + "
", + ) + )?; + for t in provided_consts { + write!(w, "{}", trait_item(cx, t, it))?; + } + w.write_str("
")?; } - w.push_str("
"); - } - if !required_types.is_empty() { - write_section_heading( - w, - "Required Associated Types", - "required-associated-types", - None, - "
", - ); - for t in required_types { - trait_item(w, cx, t, it); + if !required_types.is_empty() { + write!( + w, + "{}", + write_section_heading( + "Required Associated Types", + "required-associated-types", + None, + "
", + ) + )?; + for t in required_types { + write!(w, "{}", trait_item(cx, t, it))?; + } + w.write_str("
")?; } - w.push_str("
"); - } - if !provided_types.is_empty() { - write_section_heading( - w, - "Provided Associated Types", - "provided-associated-types", - None, - "
", - ); - for t in provided_types { - trait_item(w, cx, t, it); + if !provided_types.is_empty() { + write!( + w, + "{}", + write_section_heading( + "Provided Associated Types", + "provided-associated-types", + None, + "
", + ) + )?; + for t in provided_types { + write!(w, "{}", trait_item(cx, t, it))?; + } + w.write_str("
")?; } - w.push_str("
"); - } - - // Output the documentation for each function individually - if !required_methods.is_empty() || must_implement_one_of_functions.is_some() { - write_section_heading( - w, - "Required Methods", - "required-methods", - None, - "
", - ); - if let Some(list) = must_implement_one_of_functions.as_deref() { - write_str( + // Output the documentation for each function individually + if !required_methods.is_empty() || must_implement_one_of_functions.is_some() { + write!( w, - format_args!( + "{}", + write_section_heading( + "Required Methods", + "required-methods", + None, + "
", + ) + )?; + + if let Some(list) = must_implement_one_of_functions.as_deref() { + write!( + w, "
At least one of the `{}` methods is required.
", - fmt::from_fn(|f| list.iter().joined("`, `", f)) - ), - ); - } + fmt::from_fn(|f| list.iter().joined("`, `", f)), + )?; + } - for m in required_methods { - trait_item(w, cx, m, it); + for m in required_methods { + write!(w, "{}", trait_item(cx, m, it))?; + } + w.write_str("
")?; } - w.push_str("
"); - } - if !provided_methods.is_empty() { - write_section_heading( - w, - "Provided Methods", - "provided-methods", - None, - "
", - ); - for m in provided_methods { - trait_item(w, cx, m, it); + if !provided_methods.is_empty() { + write!( + w, + "{}", + write_section_heading( + "Provided Methods", + "provided-methods", + None, + "
", + ) + )?; + for m in provided_methods { + write!(w, "{}", trait_item(cx, m, it))?; + } + w.write_str("
")?; } - w.push_str("
"); - } - // If there are methods directly on this trait object, render them here. - write_str( - w, - format_args!( + // If there are methods directly on this trait object, render them here. + write!( + w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All) - ), - ); + )?; - let mut extern_crates = FxIndexSet::default(); + let mut extern_crates = FxIndexSet::default(); - if !t.is_dyn_compatible(cx.tcx()) { - write_section_heading( - w, - "Dyn Compatibility", - "dyn-compatibility", - None, - format!( - "

This trait is not \ - dyn compatible.

\ -

In older versions of Rust, dyn compatibility was called \"object safety\", \ - so this trait is not object safe.

", - base = crate::clean::utils::DOC_RUST_LANG_ORG_VERSION - ), - ); - } + if !t.is_dyn_compatible(cx.tcx()) { + write!( + w, + "{}", + write_section_heading( + "Dyn Compatibility", + "dyn-compatibility", + None, + format!( + "

This trait is not \ + dyn compatible.

\ +

In older versions of Rust, dyn compatibility was called \"object safety\", \ + so this trait is not object safe.

", + base = crate::clean::utils::DOC_RUST_LANG_ORG_VERSION + ), + ), + )?; + } - if let Some(implementors) = cx.shared.cache.implementors.get(&it.item_id.expect_def_id()) { - // The DefId is for the first Type found with that name. The bool is - // if any Types with the same name but different DefId have been found. - let mut implementor_dups: FxHashMap = FxHashMap::default(); - for implementor in implementors { - if let Some(did) = - implementor.inner_impl().for_.without_borrowed_ref().def_id(&cx.shared.cache) - && !did.is_local() - { - extern_crates.insert(did.krate); - } - match implementor.inner_impl().for_.without_borrowed_ref() { - clean::Type::Path { ref path } if !path.is_assoc_ty() => { - let did = path.def_id(); - let &mut (prev_did, ref mut has_duplicates) = - implementor_dups.entry(path.last()).or_insert((did, false)); - if prev_did != did { - *has_duplicates = true; + if let Some(implementors) = cx.shared.cache.implementors.get(&it.item_id.expect_def_id()) { + // The DefId is for the first Type found with that name. The bool is + // if any Types with the same name but different DefId have been found. + let mut implementor_dups: FxHashMap = FxHashMap::default(); + for implementor in implementors { + if let Some(did) = + implementor.inner_impl().for_.without_borrowed_ref().def_id(&cx.shared.cache) + && !did.is_local() + { + extern_crates.insert(did.krate); + } + match implementor.inner_impl().for_.without_borrowed_ref() { + clean::Type::Path { path } if !path.is_assoc_ty() => { + let did = path.def_id(); + let &mut (prev_did, ref mut has_duplicates) = + implementor_dups.entry(path.last()).or_insert((did, false)); + if prev_did != did { + *has_duplicates = true; + } } + _ => {} } - _ => {} } - } - let (local, mut foreign) = - implementors.iter().partition::, _>(|i| i.is_on_local_type(cx)); + let (local, mut foreign) = + implementors.iter().partition::, _>(|i| i.is_on_local_type(cx)); - let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = - local.iter().partition(|i| i.inner_impl().kind.is_auto()); + let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) = + local.iter().partition(|i| i.inner_impl().kind.is_auto()); - synthetic.sort_by_cached_key(|i| ImplString::new(i, cx)); - concrete.sort_by_cached_key(|i| ImplString::new(i, cx)); - foreign.sort_by_cached_key(|i| ImplString::new(i, cx)); + synthetic.sort_by_cached_key(|i| ImplString::new(i, cx)); + concrete.sort_by_cached_key(|i| ImplString::new(i, cx)); + foreign.sort_by_cached_key(|i| ImplString::new(i, cx)); - if !foreign.is_empty() { - write_section_heading(w, "Implementations on Foreign Types", "foreign-impls", None, ""); - - for implementor in foreign { - let provided_methods = implementor.inner_impl().provided_trait_methods(tcx); - let assoc_link = - AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods); - render_impl( + if !foreign.is_empty() { + write!( w, - cx, - implementor, - it, - assoc_link, - RenderMode::Normal, - None, - &[], - ImplRenderingParameters { - show_def_docs: false, - show_default_items: false, - show_non_assoc_items: true, - toggle_open_by_default: false, - }, - ); - } - } + "{}", + write_section_heading( + "Implementations on Foreign Types", + "foreign-impls", + None, + "" + ) + )?; - write_section_heading( - w, - "Implementors", - "implementors", - None, - "
", - ); - for implementor in concrete { - render_implementor(cx, implementor, it, w, &implementor_dups, &[]); - } - w.push_str("
"); + for implementor in foreign { + let provided_methods = implementor.inner_impl().provided_trait_methods(tcx); + let assoc_link = + AssocItemLink::GotoSource(implementor.impl_item.item_id, &provided_methods); + write!( + w, + "{}", + render_impl( + cx, + implementor, + it, + assoc_link, + RenderMode::Normal, + None, + &[], + ImplRenderingParameters { + show_def_docs: false, + show_default_items: false, + show_non_assoc_items: true, + toggle_open_by_default: false, + }, + ) + )?; + } + } - if t.is_auto(tcx) { - write_section_heading( + write!( w, - "Auto implementors", - "synthetic-implementors", - None, - "
", - ); - for implementor in synthetic { - render_implementor( - cx, - implementor, - it, - w, - &implementor_dups, - &collect_paths_for_type( - implementor.inner_impl().for_.clone(), - &cx.shared.cache, - ), - ); + "{}", + write_section_heading( + "Implementors", + "implementors", + None, + "
", + ) + )?; + for implementor in concrete { + write!(w, "{}", render_implementor(cx, implementor, it, &implementor_dups, &[]))?; } - w.push_str("
"); - } - } else { - // even without any implementations to write in, we still want the heading and list, so the - // implementors javascript file pulled in below has somewhere to write the impls into - write_section_heading( - w, - "Implementors", - "implementors", - None, - "
", - ); + w.write_str("
")?; - if t.is_auto(tcx) { - write_section_heading( + if t.is_auto(tcx) { + write!( + w, + "{}", + write_section_heading( + "Auto implementors", + "synthetic-implementors", + None, + "
", + ) + )?; + for implementor in synthetic { + write!( + w, + "{}", + render_implementor( + cx, + implementor, + it, + &implementor_dups, + &collect_paths_for_type( + implementor.inner_impl().for_.clone(), + &cx.shared.cache, + ), + ) + )?; + } + w.write_str("
")?; + } + } else { + // even without any implementations to write in, we still want the heading and list, so the + // implementors javascript file pulled in below has somewhere to write the impls into + write!( w, - "Auto implementors", - "synthetic-implementors", - None, - "
", - ); - } - } + "{}", + write_section_heading( + "Implementors", + "implementors", + None, + "
", + ) + )?; - // [RUSTDOCIMPL] trait.impl - // - // Include implementors in crates that depend on the current crate. - // - // This is complicated by the way rustdoc is invoked, which is basically - // the same way rustc is invoked: it gets called, one at a time, for each - // crate. When building the rustdocs for the current crate, rustdoc can - // see crate metadata for its dependencies, but cannot see metadata for its - // dependents. - // - // To make this work, we generate a "hook" at this stage, and our - // dependents can "plug in" to it when they build. For simplicity's sake, - // it's [JSONP]: a JavaScript file with the data we need (and can parse), - // surrounded by a tiny wrapper that the Rust side ignores, but allows the - // JavaScript side to include without having to worry about Same Origin - // Policy. The code for *that* is in `write_shared.rs`. - // - // This is further complicated by `#[doc(inline)]`. We want all copies - // of an inlined trait to reference the same JS file, to address complex - // dependency graphs like this one (lower crates depend on higher crates): - // - // ```text - // -------------------------------------------- - // | crate A: trait Foo | - // -------------------------------------------- - // | | - // -------------------------------- | - // | crate B: impl A::Foo for Bar | | - // -------------------------------- | - // | | - // --------------------------------------------- - // | crate C: #[doc(inline)] use A::Foo as Baz | - // | impl Baz for Quux | - // --------------------------------------------- - // ``` - // - // Basically, we want `C::Baz` and `A::Foo` to show the same set of - // impls, which is easier if they both treat `/trait.impl/A/trait.Foo.js` - // as the Single Source of Truth. - // - // We also want the `impl Baz for Quux` to be written to - // `trait.Foo.js`. However, when we generate plain HTML for `C::Baz`, - // we're going to want to generate plain HTML for `impl Baz for Quux` too, - // because that'll load faster, and it's better for SEO. And we don't want - // the same impl to show up twice on the same page. - // - // To make this work, the trait.impl/A/trait.Foo.js JS file has a structure kinda - // like this: - // - // ```js - // JSONP({ - // "B": {"impl A::Foo for Bar"}, - // "C": {"impl Baz for Quux"}, - // }); - // ``` - // - // First of all, this means we can rebuild a crate, and it'll replace its own - // data if something changes. That is, `rustdoc` is idempotent. The other - // advantage is that we can list the crates that get included in the HTML, - // and ignore them when doing the JavaScript-based part of rendering. - // So C's HTML will have something like this: - // - // ```html - // - // ``` - // - // And, when the JS runs, anything in data-ignore-extern-crates is known - // to already be in the HTML, and will be ignored. - // - // [JSONP]: https://en.wikipedia.org/wiki/JSONP - let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..") - .take(cx.current.len()) - .chain(std::iter::once("trait.impl")) - .collect(); - if let Some(did) = it.item_id.as_def_id() - && let get_extern = { || cx.shared.cache.external_paths.get(&did).map(|s| &s.0) } - && let Some(fqp) = cx.shared.cache.exact_paths.get(&did).or_else(get_extern) - { - js_src_path.extend(fqp[..fqp.len() - 1].iter().copied()); - js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap())); - } else { - js_src_path.extend(cx.current.iter().copied()); - js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap())); - } - let extern_crates = fmt::from_fn(|f| { - if !extern_crates.is_empty() { - f.write_str(" data-ignore-extern-crates=\"")?; - extern_crates.iter().map(|&cnum| tcx.crate_name(cnum)).joined(",", f)?; - f.write_str("\"")?; + if t.is_auto(tcx) { + write!( + w, + "{}", + write_section_heading( + "Auto implementors", + "synthetic-implementors", + None, + "
", + ) + )?; + } } - Ok(()) - }); - write_str( - w, - format_args!( + + // [RUSTDOCIMPL] trait.impl + // + // Include implementors in crates that depend on the current crate. + // + // This is complicated by the way rustdoc is invoked, which is basically + // the same way rustc is invoked: it gets called, one at a time, for each + // crate. When building the rustdocs for the current crate, rustdoc can + // see crate metadata for its dependencies, but cannot see metadata for its + // dependents. + // + // To make this work, we generate a "hook" at this stage, and our + // dependents can "plug in" to it when they build. For simplicity's sake, + // it's [JSONP]: a JavaScript file with the data we need (and can parse), + // surrounded by a tiny wrapper that the Rust side ignores, but allows the + // JavaScript side to include without having to worry about Same Origin + // Policy. The code for *that* is in `write_shared.rs`. + // + // This is further complicated by `#[doc(inline)]`. We want all copies + // of an inlined trait to reference the same JS file, to address complex + // dependency graphs like this one (lower crates depend on higher crates): + // + // ```text + // -------------------------------------------- + // | crate A: trait Foo | + // -------------------------------------------- + // | | + // -------------------------------- | + // | crate B: impl A::Foo for Bar | | + // -------------------------------- | + // | | + // --------------------------------------------- + // | crate C: #[doc(inline)] use A::Foo as Baz | + // | impl Baz for Quux | + // --------------------------------------------- + // ``` + // + // Basically, we want `C::Baz` and `A::Foo` to show the same set of + // impls, which is easier if they both treat `/trait.impl/A/trait.Foo.js` + // as the Single Source of Truth. + // + // We also want the `impl Baz for Quux` to be written to + // `trait.Foo.js`. However, when we generate plain HTML for `C::Baz`, + // we're going to want to generate plain HTML for `impl Baz for Quux` too, + // because that'll load faster, and it's better for SEO. And we don't want + // the same impl to show up twice on the same page. + // + // To make this work, the trait.impl/A/trait.Foo.js JS file has a structure kinda + // like this: + // + // ```js + // JSONP({ + // "B": {"impl A::Foo for Bar"}, + // "C": {"impl Baz for Quux"}, + // }); + // ``` + // + // First of all, this means we can rebuild a crate, and it'll replace its own + // data if something changes. That is, `rustdoc` is idempotent. The other + // advantage is that we can list the crates that get included in the HTML, + // and ignore them when doing the JavaScript-based part of rendering. + // So C's HTML will have something like this: + // + // ```html + // + // ``` + // + // And, when the JS runs, anything in data-ignore-extern-crates is known + // to already be in the HTML, and will be ignored. + // + // [JSONP]: https://en.wikipedia.org/wiki/JSONP + let mut js_src_path: UrlPartsBuilder = + iter::repeat_n("..", cx.current.len()).chain(iter::once("trait.impl")).collect(); + if let Some(did) = it.item_id.as_def_id() + && let get_extern = { || cx.shared.cache.external_paths.get(&did).map(|s| &s.0) } + && let Some(fqp) = cx.shared.cache.exact_paths.get(&did).or_else(get_extern) + { + js_src_path.extend(fqp[..fqp.len() - 1].iter().copied()); + js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), fqp.last().unwrap())); + } else { + js_src_path.extend(cx.current.iter().copied()); + js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap())); + } + let extern_crates = fmt::from_fn(|f| { + if !extern_crates.is_empty() { + f.write_str(" data-ignore-extern-crates=\"")?; + extern_crates.iter().map(|&cnum| tcx.crate_name(cnum)).joined(",", f)?; + f.write_str("\"")?; + } + Ok(()) + }); + write!( + w, "", src = js_src_path.finish() - ), - ); + ) + }) } fn item_trait_alias( - w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item, t: &clean::TraitAlias, -) { - wrap_item(w, |w| { +) -> impl fmt::Display { + fmt::from_fn(|w| { + wrap_item(w, |w| { + write!( + w, + "{attrs}trait {name}{generics}{where_b} = {bounds};", + attrs = render_attributes_in_pre(it, "", cx), + name = it.name.unwrap(), + generics = t.generics.print(cx), + where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(), + bounds = bounds(&t.bounds, true, cx), + ) + })?; + + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + // Render any items associated directly to this alias, as otherwise they + // won't be visible anywhere in the docs. It would be nice to also show + // associated items from the aliased type (see discussion in #32077), but + // we need #14072 to make sense of the generics. write!( w, - "{attrs}trait {name}{generics}{where_b} = {bounds};", - attrs = render_attributes_in_pre(it, "", cx), - name = it.name.unwrap(), - generics = t.generics.print(cx), - where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline), - bounds = bounds(&t.bounds, true, cx), + "{}", + render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All) ) - .unwrap(); - }); - - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); - // Render any items associated directly to this alias, as otherwise they - // won't be visible anywhere in the docs. It would be nice to also show - // associated items from the aliased type (see discussion in #32077), but - // we need #14072 to make sense of the generics. - write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) - .unwrap(); + }) } -fn item_type_alias(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) { - wrap_item(w, |w| { - write_str( - w, - format_args!( +fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> impl fmt::Display { + fmt::from_fn(|w| { + wrap_item(w, |w| { + write!( + w, "{attrs}{vis}type {name}{generics}{where_clause} = {type_};", attrs = render_attributes_in_pre(it, "", cx), vis = visibility_print_with_space(it, cx), name = it.name.unwrap(), generics = t.generics.print(cx), - where_clause = print_where_clause(&t.generics, cx, 0, Ending::Newline), + where_clause = + print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(), type_ = t.type_.print(cx), - ), - ); - }); + ) + })?; - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; - if let Some(inner_type) = &t.inner_type { - write_section_heading(w, "Aliased Type", "aliased-type", None, ""); + if let Some(inner_type) = &t.inner_type { + write!(w, "{}", write_section_heading("Aliased Type", "aliased-type", None, ""),)?; - match inner_type { - clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { - let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); - let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); - let enum_def_id = ty.ty_adt_def().unwrap().did(); + match inner_type { + clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { + let variants_iter = || variants.iter().filter(|i| !i.is_stripped()); + let ty = cx.tcx().type_of(it.def_id().unwrap()).instantiate_identity(); + let enum_def_id = ty.ty_adt_def().unwrap().did(); - wrap_item(w, |w| { - let variants_len = variants.len(); - let variants_count = variants_iter().count(); - let has_stripped_entries = variants_len != variants_count; + wrap_item(w, |w| { + let variants_len = variants.len(); + let variants_count = variants_iter().count(); + let has_stripped_entries = variants_len != variants_count; - write_str(w, format_args!("enum {}{}", it.name.unwrap(), t.generics.print(cx))); - render_enum_fields( - w, - cx, - Some(&t.generics), - variants, - variants_count, - has_stripped_entries, - *is_non_exhaustive, - enum_def_id, - ) - }); - item_variants(w, cx, it, variants, enum_def_id); - } - clean::TypeAliasInnerType::Union { fields } => { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; + write!( + w, + "enum {}{}{}", + it.name.unwrap(), + t.generics.print(cx), + render_enum_fields( + cx, + Some(&t.generics), + variants, + variants_count, + has_stripped_entries, + *is_non_exhaustive, + enum_def_id, + ) + ) + })?; + write!(w, "{}", item_variants(cx, it, variants, enum_def_id))?; + } + clean::TypeAliasInnerType::Union { fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; - write_str( - w, - format_args!("union {}{}", it.name.unwrap(), t.generics.print(cx)), - ); - render_struct_fields( - w, - Some(&t.generics), - None, - fields, - "", - true, - has_stripped_fields, - cx, - ); - }); - item_fields(w, cx, it, fields, None); - } - clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { - wrap_item(w, |w| { - let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); - let has_stripped_fields = fields.len() != fields_count; + write!( + w, + "union {}{}{}", + it.name.unwrap(), + t.generics.print(cx), + render_struct_fields( + Some(&t.generics), + None, + fields, + "", + true, + has_stripped_fields, + cx, + ), + ) + })?; + write!(w, "{}", item_fields(cx, it, fields, None))?; + } + clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { + wrap_item(w, |w| { + let fields_count = fields.iter().filter(|i| !i.is_stripped()).count(); + let has_stripped_fields = fields.len() != fields_count; - write_str( - w, - format_args!("struct {}{}", it.name.unwrap(), t.generics.print(cx)), - ); - render_struct_fields( - w, - Some(&t.generics), - *ctor_kind, - fields, - "", - true, - has_stripped_fields, - cx, - ); - }); - item_fields(w, cx, it, fields, None); + write!( + w, + "struct {}{}{}", + it.name.unwrap(), + t.generics.print(cx), + render_struct_fields( + Some(&t.generics), + *ctor_kind, + fields, + "", + true, + has_stripped_fields, + cx, + ), + ) + })?; + write!(w, "{}", item_fields(cx, it, fields, None))?; + } } } - } - let def_id = it.item_id.expect_def_id(); - // Render any items associated directly to this alias, as otherwise they - // won't be visible anywhere in the docs. It would be nice to also show - // associated items from the aliased type (see discussion in #32077), but - // we need #14072 to make sense of the generics. - write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All))); - write_str(w, format_args!("{}", document_type_layout(cx, def_id))); - - // [RUSTDOCIMPL] type.impl - // - // Include type definitions from the alias target type. - // - // Earlier versions of this code worked by having `render_assoc_items` - // include this data directly. That generates *O*`(types*impls)` of HTML - // text, and some real crates have a lot of types and impls. - // - // To create the same UX without generating half a gigabyte of HTML for a - // crate that only contains 20 megabytes of actual documentation[^115718], - // rustdoc stashes these type-alias-inlined docs in a [JSONP] - // "database-lite". The file itself is generated in `write_shared.rs`, - // and hooks into functions provided by `main.js`. - // - // The format of `trait.impl` and `type.impl` JS files are superficially - // similar. Each line, except the JSONP wrapper itself, belongs to a crate, - // and they are otherwise separate (rustdoc should be idempotent). The - // "meat" of the file is HTML strings, so the frontend code is very simple. - // Links are relative to the doc root, though, so the frontend needs to fix - // that up, and inlined docs can reuse these files. - // - // However, there are a few differences, caused by the sophisticated - // features that type aliases have. Consider this crate graph: - // - // ```text - // --------------------------------- - // | crate A: struct Foo | - // | type Bar = Foo | - // | impl X for Foo | - // | impl Y for Foo | - // --------------------------------- - // | - // ---------------------------------- - // | crate B: type Baz = A::Foo | - // | type Xyy = A::Foo | - // | impl Z for Xyy | - // ---------------------------------- - // ``` - // - // The type.impl/A/struct.Foo.js JS file has a structure kinda like this: - // - // ```js - // JSONP({ - // "A": [["impl Y for Foo", "Y", "A::Bar"]], - // "B": [["impl X for Foo", "X", "B::Baz", "B::Xyy"], ["impl Z for Xyy", "Z", "B::Baz"]], - // }); - // ``` - // - // When the type.impl file is loaded, only the current crate's docs are - // actually used. The main reason to bundle them together is that there's - // enough duplication in them for DEFLATE to remove the redundancy. - // - // The contents of a crate are a list of impl blocks, themselves - // represented as lists. The first item in the sublist is the HTML block, - // the second item is the name of the trait (which goes in the sidebar), - // and all others are the names of type aliases that successfully match. - // - // This way: - // - // - There's no need to generate these files for types that have no aliases - // in the current crate. If a dependent crate makes a type alias, it'll - // take care of generating its own docs. - // - There's no need to reimplement parts of the type checker in - // JavaScript. The Rust backend does the checking, and includes its - // results in the file. - // - Docs defined directly on the type alias are dropped directly in the - // HTML by `render_assoc_items`, and are accessible without JavaScript. - // The JSONP file will not list impl items that are known to be part - // of the main HTML file already. - // - // [JSONP]: https://en.wikipedia.org/wiki/JSONP - // [^115718]: https://github.com/rust-lang/rust/issues/115718 - let cache = &cx.shared.cache; - if let Some(target_did) = t.type_.def_id(cache) && - let get_extern = { || cache.external_paths.get(&target_did) } && - let Some(&(ref target_fqp, target_type)) = cache.paths.get(&target_did).or_else(get_extern) && - target_type.is_adt() && // primitives cannot be inlined - let Some(self_did) = it.item_id.as_def_id() && - let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) } && - let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local) - { - let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..") - .take(cx.current.len()) - .chain(std::iter::once("type.impl")) - .collect(); - js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied()); - js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap())); - let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f)); - write_str( + let def_id = it.item_id.expect_def_id(); + // Render any items associated directly to this alias, as otherwise they + // won't be visible anywhere in the docs. It would be nice to also show + // associated items from the aliased type (see discussion in #32077), but + // we need #14072 to make sense of the generics. + write!( w, - format_args!( + "{}{}", + render_assoc_items(cx, it, def_id, AssocItemRender::All), + document_type_layout(cx, def_id) + )?; + + // [RUSTDOCIMPL] type.impl + // + // Include type definitions from the alias target type. + // + // Earlier versions of this code worked by having `render_assoc_items` + // include this data directly. That generates *O*`(types*impls)` of HTML + // text, and some real crates have a lot of types and impls. + // + // To create the same UX without generating half a gigabyte of HTML for a + // crate that only contains 20 megabytes of actual documentation[^115718], + // rustdoc stashes these type-alias-inlined docs in a [JSONP] + // "database-lite". The file itself is generated in `write_shared.rs`, + // and hooks into functions provided by `main.js`. + // + // The format of `trait.impl` and `type.impl` JS files are superficially + // similar. Each line, except the JSONP wrapper itself, belongs to a crate, + // and they are otherwise separate (rustdoc should be idempotent). The + // "meat" of the file is HTML strings, so the frontend code is very simple. + // Links are relative to the doc root, though, so the frontend needs to fix + // that up, and inlined docs can reuse these files. + // + // However, there are a few differences, caused by the sophisticated + // features that type aliases have. Consider this crate graph: + // + // ```text + // --------------------------------- + // | crate A: struct Foo | + // | type Bar = Foo | + // | impl X for Foo | + // | impl Y for Foo | + // --------------------------------- + // | + // ---------------------------------- + // | crate B: type Baz = A::Foo | + // | type Xyy = A::Foo | + // | impl Z for Xyy | + // ---------------------------------- + // ``` + // + // The type.impl/A/struct.Foo.js JS file has a structure kinda like this: + // + // ```js + // JSONP({ + // "A": [["impl Y for Foo", "Y", "A::Bar"]], + // "B": [["impl X for Foo", "X", "B::Baz", "B::Xyy"], ["impl Z for Xyy", "Z", "B::Baz"]], + // }); + // ``` + // + // When the type.impl file is loaded, only the current crate's docs are + // actually used. The main reason to bundle them together is that there's + // enough duplication in them for DEFLATE to remove the redundancy. + // + // The contents of a crate are a list of impl blocks, themselves + // represented as lists. The first item in the sublist is the HTML block, + // the second item is the name of the trait (which goes in the sidebar), + // and all others are the names of type aliases that successfully match. + // + // This way: + // + // - There's no need to generate these files for types that have no aliases + // in the current crate. If a dependent crate makes a type alias, it'll + // take care of generating its own docs. + // - There's no need to reimplement parts of the type checker in + // JavaScript. The Rust backend does the checking, and includes its + // results in the file. + // - Docs defined directly on the type alias are dropped directly in the + // HTML by `render_assoc_items`, and are accessible without JavaScript. + // The JSONP file will not list impl items that are known to be part + // of the main HTML file already. + // + // [JSONP]: https://en.wikipedia.org/wiki/JSONP + // [^115718]: https://github.com/rust-lang/rust/issues/115718 + let cache = &cx.shared.cache; + if let Some(target_did) = t.type_.def_id(cache) + && let get_extern = { || cache.external_paths.get(&target_did) } + && let Some(&(ref target_fqp, target_type)) = + cache.paths.get(&target_did).or_else(get_extern) + && target_type.is_adt() // primitives cannot be inlined + && let Some(self_did) = it.item_id.as_def_id() + && let get_local = { || cache.paths.get(&self_did).map(|(p, _)| p) } + && let Some(self_fqp) = cache.exact_paths.get(&self_did).or_else(get_local) + { + let mut js_src_path: UrlPartsBuilder = + iter::repeat_n("..", cx.current.len()).chain(iter::once("type.impl")).collect(); + js_src_path.extend(target_fqp[..target_fqp.len() - 1].iter().copied()); + js_src_path.push_fmt(format_args!("{target_type}.{}.js", target_fqp.last().unwrap())); + let self_path = fmt::from_fn(|f| self_fqp.iter().joined("::", f)); + write!( + w, "", - src = js_src_path.finish() - ), - ); - } + src = js_src_path.finish(), + )?; + } + Ok(()) + }) } -fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) { +fn item_union(cx: &Context<'_>, it: &clean::Item, s: &clean::Union) -> impl fmt::Display { item_template!( #[template(path = "item_union.html")] struct ItemUnion<'a, 'cx> { @@ -1419,40 +1471,25 @@ fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni ); impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { - fn render_union<'b>(&'b self) -> impl Display + Captures<'a> + 'b + Captures<'cx> { - fmt::from_fn(move |f| { - let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx); - write!(f, "{v}") - }) + fn render_union(&self) -> impl Display { + render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx) } - fn document_field<'b>( - &'b self, - field: &'a clean::Item, - ) -> impl Display + Captures<'a> + 'b + Captures<'cx> { - fmt::from_fn(move |f| { - let v = document(self.cx, field, Some(self.it), HeadingOffset::H3); - write!(f, "{v}") - }) + fn document_field(&self, field: &'a clean::Item) -> impl Display { + document(self.cx, field, Some(self.it), HeadingOffset::H3) } fn stability_field(&self, field: &clean::Item) -> Option { field.stability_class(self.cx.tcx()) } - fn print_ty<'b>( - &'b self, - ty: &'a clean::Type, - ) -> impl Display + Captures<'a> + 'b + Captures<'cx> { - fmt::from_fn(move |f| { - let v = ty.print(self.cx); - write!(f, "{v}") - }) + fn print_ty(&self, ty: &'a clean::Type) -> impl Display { + ty.print(self.cx) } fn fields_iter( &self, - ) -> std::iter::Peekable> { + ) -> iter::Peekable> { self.s .fields .iter() @@ -1464,13 +1501,13 @@ fn item_union(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni } } - ItemUnion { cx, it, s }.render_into(w).unwrap(); + fmt::from_fn(|w| { + ItemUnion { cx, it, s }.render_into(w).unwrap(); + Ok(()) + }) } -fn print_tuple_struct_fields<'a, 'cx: 'a>( - cx: &'a Context<'cx>, - s: &'a [clean::Item], -) -> impl Display + 'a + Captures<'cx> { +fn print_tuple_struct_fields(cx: &Context<'_>, s: &[clean::Item]) -> impl Display { fmt::from_fn(|f| { if !s.is_empty() && s.iter().all(|field| { @@ -1492,40 +1529,42 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( }) } -fn item_enum(w: &mut String, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) { - let count_variants = e.variants().count(); - wrap_item(w, |w| { - render_attributes_in_code(w, it, cx); - write_str( - w, - format_args!( - "{}enum {}{}", +fn item_enum(cx: &Context<'_>, it: &clean::Item, e: &clean::Enum) -> impl fmt::Display { + fmt::from_fn(|w| { + let count_variants = e.variants().count(); + wrap_item(w, |w| { + render_attributes_in_code(w, it, cx); + write!( + w, + "{}enum {}{}{}", visibility_print_with_space(it, cx), it.name.unwrap(), e.generics.print(cx), - ), - ); - - render_enum_fields( - w, - cx, - Some(&e.generics), - &e.variants, - count_variants, - e.has_stripped_entries(), - it.is_non_exhaustive(), - it.def_id().unwrap(), - ); - }); + render_enum_fields( + cx, + Some(&e.generics), + &e.variants, + count_variants, + e.has_stripped_entries(), + it.is_non_exhaustive(), + it.def_id().unwrap(), + ), + ) + })?; - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; - if count_variants != 0 { - item_variants(w, cx, it, &e.variants, it.def_id().unwrap()); - } - let def_id = it.item_id.expect_def_id(); - write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All))); - write_str(w, format_args!("{}", document_type_layout(cx, def_id))); + if count_variants != 0 { + write!(w, "{}", item_variants(cx, it, &e.variants, it.def_id().unwrap()))?; + } + let def_id = it.item_id.expect_def_id(); + write!( + w, + "{}{}", + render_assoc_items(cx, it, def_id, AssocItemRender::All), + document_type_layout(cx, def_id) + ) + }) } /// It'll return false if any variant is not a C-like variant. Otherwise it'll return true if at @@ -1554,32 +1593,33 @@ fn should_show_enum_discriminant( } fn display_c_like_variant( - w: &mut String, cx: &Context<'_>, item: &clean::Item, variant: &clean::Variant, index: VariantIdx, should_show_enum_discriminant: bool, enum_def_id: DefId, -) { - let name = item.name.unwrap(); - if let Some(ref value) = variant.discriminant { - write_str(w, format_args!("{} = {}", name.as_str(), value.value(cx.tcx(), true))); - } else if should_show_enum_discriminant { - let adt_def = cx.tcx().adt_def(enum_def_id); - let discr = adt_def.discriminant_for_variant(cx.tcx(), index); - if discr.ty.is_signed() { - write_str(w, format_args!("{} = {}", name.as_str(), discr.val as i128)); +) -> impl fmt::Display { + fmt::from_fn(move |w| { + let name = item.name.unwrap(); + if let Some(ref value) = variant.discriminant { + write!(w, "{} = {}", name.as_str(), value.value(cx.tcx(), true))?; + } else if should_show_enum_discriminant { + let adt_def = cx.tcx().adt_def(enum_def_id); + let discr = adt_def.discriminant_for_variant(cx.tcx(), index); + if discr.ty.is_signed() { + write!(w, "{} = {}", name.as_str(), discr.val as i128)?; + } else { + write!(w, "{} = {}", name.as_str(), discr.val)?; + } } else { - write_str(w, format_args!("{} = {}", name.as_str(), discr.val)); + write!(w, "{name}")?; } - } else { - w.push_str(name.as_str()); - } + Ok(()) + }) } fn render_enum_fields( - mut w: &mut String, cx: &Context<'_>, g: Option<&clean::Generics>, variants: &IndexVec, @@ -1587,422 +1627,452 @@ fn render_enum_fields( has_stripped_entries: bool, is_non_exhaustive: bool, enum_def_id: DefId, -) { - let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants); - if !g.is_some_and(|g| print_where_clause_and_check(w, g, cx)) { - // If there wasn't a `where` clause, we add a whitespace. - w.push_str(" "); - } - - let variants_stripped = has_stripped_entries; - if count_variants == 0 && !variants_stripped { - w.push_str("{}"); - } else { - w.push_str("{\n"); - let toggle = should_hide_fields(count_variants); - if toggle { - toggle_open(&mut w, format_args!("{count_variants} variants")); +) -> impl fmt::Display { + fmt::from_fn(move |w| { + let should_show_enum_discriminant = + should_show_enum_discriminant(cx, enum_def_id, variants); + if let Some(generics) = g + && let Some(where_clause) = print_where_clause(generics, cx, 0, Ending::Newline) + { + write!(w, "{where_clause}")?; + } else { + // If there wasn't a `where` clause, we add a whitespace. + w.write_char(' ')?; } - const TAB: &str = " "; - for (index, v) in variants.iter_enumerated() { - if v.is_stripped() { - continue; + + let variants_stripped = has_stripped_entries; + if count_variants == 0 && !variants_stripped { + w.write_str("{}") + } else { + w.write_str("{\n")?; + let toggle = should_hide_fields(count_variants); + if toggle { + toggle_open(&mut *w, format_args!("{count_variants} variants")); } - w.push_str(TAB); - match v.kind { - clean::VariantItem(ref var) => match var.kind { - clean::VariantKind::CLike => display_c_like_variant( - w, - cx, - v, - var, - index, - should_show_enum_discriminant, - enum_def_id, - ), - clean::VariantKind::Tuple(ref s) => { - write_str( - w, - format_args!( - "{}({})", - v.name.unwrap(), - print_tuple_struct_fields(cx, s) - ), - ); - } - clean::VariantKind::Struct(ref s) => { - render_struct(w, v, None, None, &s.fields, TAB, false, cx); - } - }, - _ => unreachable!(), + const TAB: &str = " "; + for (index, v) in variants.iter_enumerated() { + if v.is_stripped() { + continue; + } + w.write_str(TAB)?; + match v.kind { + clean::VariantItem(ref var) => match var.kind { + clean::VariantKind::CLike => { + write!( + w, + "{}", + display_c_like_variant( + cx, + v, + var, + index, + should_show_enum_discriminant, + enum_def_id, + ) + )?; + } + clean::VariantKind::Tuple(ref s) => { + write!(w, "{}({})", v.name.unwrap(), print_tuple_struct_fields(cx, s))?; + } + clean::VariantKind::Struct(ref s) => { + write!( + w, + "{}", + render_struct(v, None, None, &s.fields, TAB, false, cx) + )?; + } + }, + _ => unreachable!(), + } + w.write_str(",\n")?; } - w.push_str(",\n"); - } - if variants_stripped && !is_non_exhaustive { - w.push_str(" // some variants omitted\n"); - } - if toggle { - toggle_close(&mut w); + if variants_stripped && !is_non_exhaustive { + w.write_str(" // some variants omitted\n")?; + } + if toggle { + toggle_close(&mut *w); + } + w.write_str("}") } - w.push_str("}"); - } + }) } fn item_variants( - w: &mut String, cx: &Context<'_>, it: &clean::Item, variants: &IndexVec, enum_def_id: DefId, -) { - let tcx = cx.tcx(); - write_section_heading( - w, - &format!("Variants{}", document_non_exhaustive_header(it)), - "variants", - Some("variants"), - format!("{}
", document_non_exhaustive(it)), - ); - - let should_show_enum_discriminant = should_show_enum_discriminant(cx, enum_def_id, variants); - for (index, variant) in variants.iter_enumerated() { - if variant.is_stripped() { - continue; - } - let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); - write_str( +) -> impl fmt::Display { + fmt::from_fn(move |w| { + let tcx = cx.tcx(); + write!( w, - format_args!( - "
\ - §" + "{}", + write_section_heading( + &format!("Variants{}", document_non_exhaustive_header(it)), + "variants", + Some("variants"), + format!("{}
", document_non_exhaustive(it)), ), - ); - render_stability_since_raw_with_extra( - w, - variant.stable_since(tcx), - variant.const_stability(tcx), - " rightside", - ); - w.push_str("

"); - if let clean::VariantItem(ref var) = variant.kind - && let clean::VariantKind::CLike = var.kind - { - display_c_like_variant( + )?; + + let should_show_enum_discriminant = + should_show_enum_discriminant(cx, enum_def_id, variants); + for (index, variant) in variants.iter_enumerated() { + if variant.is_stripped() { + continue; + } + let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap())); + write!( w, - cx, - variant, - var, - index, - should_show_enum_discriminant, - enum_def_id, - ); - } else { - w.push_str(variant.name.unwrap().as_str()); - } + "
\ + §\ + {}\ +

", + render_stability_since_raw_with_extra( + variant.stable_since(tcx), + variant.const_stability(tcx), + " rightside", + ) + .maybe_display() + )?; + if let clean::VariantItem(ref var) = variant.kind + && let clean::VariantKind::CLike = var.kind + { + write!( + w, + "{}", + display_c_like_variant( + cx, + variant, + var, + index, + should_show_enum_discriminant, + enum_def_id, + ) + )?; + } else { + w.write_str(variant.name.unwrap().as_str())?; + } - let clean::VariantItem(variant_data) = &variant.kind else { unreachable!() }; + let clean::VariantItem(variant_data) = &variant.kind else { unreachable!() }; - if let clean::VariantKind::Tuple(ref s) = variant_data.kind { - write_str(w, format_args!("({})", print_tuple_struct_fields(cx, s))); - } - w.push_str("

"); + if let clean::VariantKind::Tuple(ref s) = variant_data.kind { + write!(w, "({})", print_tuple_struct_fields(cx, s))?; + } + w.write_str("

")?; - write_str(w, format_args!("{}", document(cx, variant, Some(it), HeadingOffset::H4))); + write!(w, "{}", document(cx, variant, Some(it), HeadingOffset::H4))?; - let heading_and_fields = match &variant_data.kind { - clean::VariantKind::Struct(s) => { - // If there is no field to display, no need to add the heading. - if s.fields.iter().any(|f| !f.is_doc_hidden()) { - Some(("Fields", &s.fields)) - } else { - None + let heading_and_fields = match &variant_data.kind { + clean::VariantKind::Struct(s) => { + // If there is no field to display, no need to add the heading. + if s.fields.iter().any(|f| !f.is_doc_hidden()) { + Some(("Fields", &s.fields)) + } else { + None + } } - } - clean::VariantKind::Tuple(fields) => { - // Documentation on tuple variant fields is rare, so to reduce noise we only emit - // the section if at least one field is documented. - if fields.iter().any(|f| !f.doc_value().is_empty()) { - Some(("Tuple Fields", fields)) - } else { - None + clean::VariantKind::Tuple(fields) => { + // Documentation on tuple variant fields is rare, so to reduce noise we only emit + // the section if at least one field is documented. + if fields.iter().any(|f| !f.doc_value().is_empty()) { + Some(("Tuple Fields", fields)) + } else { + None + } } - } - clean::VariantKind::CLike => None, - }; + clean::VariantKind::CLike => None, + }; - if let Some((heading, fields)) = heading_and_fields { - let variant_id = - cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); - write_str( - w, - format_args!( + if let Some((heading, fields)) = heading_and_fields { + let variant_id = + cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap())); + write!( + w, "
\

{heading}

\ {}", document_non_exhaustive(variant) - ), - ); - for field in fields { - match field.kind { - clean::StrippedItem(box clean::StructFieldItem(_)) => {} - clean::StructFieldItem(ref ty) => { - let id = cx.derive_id(format!( - "variant.{}.field.{}", - variant.name.unwrap(), - field.name.unwrap() - )); - write_str( - w, - format_args!( + )?; + for field in fields { + match field.kind { + clean::StrippedItem(box clean::StructFieldItem(_)) => {} + clean::StructFieldItem(ref ty) => { + let id = cx.derive_id(format!( + "variant.{}.field.{}", + variant.name.unwrap(), + field.name.unwrap() + )); + write!( + w, "
\ \ §\ {f}: {t}\ - ", + \ + {doc}\ +
", f = field.name.unwrap(), t = ty.print(cx), - ), - ); - write_str( - w, - format_args!( - "{}
", - document(cx, field, Some(variant), HeadingOffset::H5), - ), - ); + doc = document(cx, field, Some(variant), HeadingOffset::H5), + )?; + } + _ => unreachable!(), } - _ => unreachable!(), } + w.write_str("
")?; } - w.push_str("
"); } - } - write_str(w, format_args!("
")); + w.write_str("
") + }) } -fn item_macro(w: &mut String, cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) { - wrap_item(w, |w| { - // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`. - if !t.macro_rules { - write_str(w, format_args!("{}", visibility_print_with_space(it, cx))); - } - write_str(w, format_args!("{}", Escape(&t.source))); - }); - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); +fn item_macro(cx: &Context<'_>, it: &clean::Item, t: &clean::Macro) -> impl fmt::Display { + fmt::from_fn(|w| { + wrap_item(w, |w| { + // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`. + if !t.macro_rules { + write!(w, "{}", visibility_print_with_space(it, cx))?; + } + write!(w, "{}", Escape(&t.source)) + })?; + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + }) } -fn item_proc_macro( - w: &mut impl fmt::Write, - cx: &Context<'_>, - it: &clean::Item, - m: &clean::ProcMacro, -) { - wrap_item(w, |buffer| { - let name = it.name.expect("proc-macros always have names"); - match m.kind { - MacroKind::Bang => { - write!(buffer, "{name}!() {{ /* proc-macro */ }}") - .unwrap(); - } - MacroKind::Attr => { - write!(buffer, "#[{name}]").unwrap(); - } - MacroKind::Derive => { - write!(buffer, "#[derive({name})]").unwrap(); - if !m.helpers.is_empty() { - buffer - .write_str( +fn item_proc_macro(cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) -> impl fmt::Display { + fmt::from_fn(|w| { + wrap_item(w, |w| { + let name = it.name.expect("proc-macros always have names"); + match m.kind { + MacroKind::Bang => { + write!(w, "{name}!() {{ /* proc-macro */ }}")?; + } + MacroKind::Attr => { + write!(w, "#[{name}]")?; + } + MacroKind::Derive => { + write!(w, "#[derive({name})]")?; + if !m.helpers.is_empty() { + w.write_str( "\n{\n \ - // Attributes available to this derive:\n", - ) - .unwrap(); - for attr in &m.helpers { - writeln!(buffer, " #[{attr}]").unwrap(); + // Attributes available to this derive:\n", + )?; + for attr in &m.helpers { + writeln!(w, " #[{attr}]")?; + } + w.write_str("}\n")?; } - buffer.write_str("}\n").unwrap(); } } - } - }); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); + Ok(()) + })?; + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + }) } -fn item_primitive(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) { - let def_id = it.item_id.expect_def_id(); - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); - if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { - write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All)).unwrap(); - } else { - // We handle the "reference" primitive type on its own because we only want to list - // implementations on generic types. - let (concrete, synthetic, blanket_impl) = get_filtered_impls_for_reference(&cx.shared, it); - - render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl); - } +fn item_primitive(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { + fmt::from_fn(|w| { + let def_id = it.item_id.expect_def_id(); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; + if it.name.map(|n| n.as_str() != "reference").unwrap_or(false) { + write!(w, "{}", render_assoc_items(cx, it, def_id, AssocItemRender::All))?; + } else { + // We handle the "reference" primitive type on its own because we only want to list + // implementations on generic types. + let (concrete, synthetic, blanket_impl) = + get_filtered_impls_for_reference(&cx.shared, it); + + render_all_impls(w, cx, it, &concrete, &synthetic, &blanket_impl); + } + Ok(()) + }) } fn item_constant( - w: &mut String, cx: &Context<'_>, it: &clean::Item, generics: &clean::Generics, ty: &clean::Type, c: &clean::ConstantKind, -) { - wrap_item(w, |w| { - let tcx = cx.tcx(); - render_attributes_in_code(w, it, cx); +) -> impl fmt::Display { + fmt::from_fn(|w| { + wrap_item(w, |w| { + let tcx = cx.tcx(); + render_attributes_in_code(w, it, cx); - write_str( - w, - format_args!( + write!( + w, "{vis}const {name}{generics}: {typ}{where_clause}", vis = visibility_print_with_space(it, cx), name = it.name.unwrap(), generics = generics.print(cx), typ = ty.print(cx), - where_clause = print_where_clause(generics, cx, 0, Ending::NoNewline) - ), - ); + where_clause = + print_where_clause(generics, cx, 0, Ending::NoNewline).maybe_display(), + )?; - // FIXME: The code below now prints - // ` = _; // 100i32` - // if the expression is - // `50 + 50` - // which looks just wrong. - // Should we print - // ` = 100i32;` - // instead? - - let value = c.value(tcx); - let is_literal = c.is_literal(tcx); - let expr = c.expr(tcx); - if value.is_some() || is_literal { - write_str(w, format_args!(" = {expr};", expr = Escape(&expr))); - } else { - w.push_str(";"); - } + // FIXME: The code below now prints + // ` = _; // 100i32` + // if the expression is + // `50 + 50` + // which looks just wrong. + // Should we print + // ` = 100i32;` + // instead? + + let value = c.value(tcx); + let is_literal = c.is_literal(tcx); + let expr = c.expr(tcx); + if value.is_some() || is_literal { + write!(w, " = {expr};", expr = Escape(&expr))?; + } else { + w.write_str(";")?; + } - if !is_literal { - if let Some(value) = &value { - let value_lowercase = value.to_lowercase(); - let expr_lowercase = expr.to_lowercase(); + if !is_literal { + if let Some(value) = &value { + let value_lowercase = value.to_lowercase(); + let expr_lowercase = expr.to_lowercase(); - if value_lowercase != expr_lowercase - && value_lowercase.trim_end_matches("i32") != expr_lowercase - { - write_str(w, format_args!(" // {value}", value = Escape(value))); + if value_lowercase != expr_lowercase + && value_lowercase.trim_end_matches("i32") != expr_lowercase + { + write!(w, " // {value}", value = Escape(value))?; + } } } - } - }); + Ok(()) + })?; - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + }) } -fn item_struct(w: &mut String, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) { - wrap_item(w, |w| { - render_attributes_in_code(w, it, cx); - render_struct(w, it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx); - }); - - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); +fn item_struct(cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) -> impl fmt::Display { + fmt::from_fn(|w| { + wrap_item(w, |w| { + render_attributes_in_code(w, it, cx); + write!( + w, + "{}", + render_struct(it, Some(&s.generics), s.ctor_kind, &s.fields, "", true, cx) + ) + })?; - item_fields(w, cx, it, &s.fields, s.ctor_kind); + let def_id = it.item_id.expect_def_id(); - let def_id = it.item_id.expect_def_id(); - write_str(w, format_args!("{}", render_assoc_items(cx, it, def_id, AssocItemRender::All))); - write_str(w, format_args!("{}", document_type_layout(cx, def_id))); + write!( + w, + "{}{}{}{}", + document(cx, it, None, HeadingOffset::H2), + item_fields(cx, it, &s.fields, s.ctor_kind), + render_assoc_items(cx, it, def_id, AssocItemRender::All), + document_type_layout(cx, def_id), + ) + }) } fn item_fields( - w: &mut String, cx: &Context<'_>, it: &clean::Item, fields: &[clean::Item], ctor_kind: Option, -) { - let mut fields = fields - .iter() - .filter_map(|f| match f.kind { - clean::StructFieldItem(ref ty) => Some((f, ty)), - _ => None, - }) - .peekable(); - if let None | Some(CtorKind::Fn) = ctor_kind { - if fields.peek().is_some() { - let title = format!( - "{}{}", - if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, - document_non_exhaustive_header(it), - ); - write_section_heading(w, &title, "fields", Some("fields"), document_non_exhaustive(it)); - for (index, (field, ty)) in fields.enumerate() { - let field_name = - field.name.map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); - let id = cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField)); - write_str( +) -> impl fmt::Display { + fmt::from_fn(move |w| { + let mut fields = fields + .iter() + .filter_map(|f| match f.kind { + clean::StructFieldItem(ref ty) => Some((f, ty)), + _ => None, + }) + .peekable(); + if let None | Some(CtorKind::Fn) = ctor_kind { + if fields.peek().is_some() { + let title = format!( + "{}{}", + if ctor_kind.is_none() { "Fields" } else { "Tuple Fields" }, + document_non_exhaustive_header(it), + ); + write!( w, - format_args!( + "{}", + write_section_heading( + &title, + "fields", + Some("fields"), + document_non_exhaustive(it) + ) + )?; + for (index, (field, ty)) in fields.enumerate() { + let field_name = field + .name + .map_or_else(|| index.to_string(), |sym| sym.as_str().to_string()); + let id = + cx.derive_id(format!("{typ}.{field_name}", typ = ItemType::StructField)); + write!( + w, "\ §\ {field_name}: {ty}\ - ", + \ + {doc}", item_type = ItemType::StructField, - ty = ty.print(cx) - ), - ); - write_str(w, format_args!("{}", document(cx, field, Some(it), HeadingOffset::H3))); + ty = ty.print(cx), + doc = document(cx, field, Some(it), HeadingOffset::H3), + )?; + } } } - } + Ok(()) + }) } fn item_static( - w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item, s: &clean::Static, safety: Option, -) { - wrap_item(w, |buffer| { - render_attributes_in_code(buffer, it, cx); - write!( - buffer, - "{vis}{safe}static {mutability}{name}: {typ}", - vis = visibility_print_with_space(it, cx), - safe = safety.map(|safe| safe.prefix_str()).unwrap_or(""), - mutability = s.mutability.print_with_space(), - name = it.name.unwrap(), - typ = s.type_.print(cx) - ) - .unwrap(); - }); +) -> impl fmt::Display { + fmt::from_fn(move |w| { + wrap_item(w, |w| { + render_attributes_in_code(w, it, cx); + write!( + w, + "{vis}{safe}static {mutability}{name}: {typ}", + vis = visibility_print_with_space(it, cx), + safe = safety.map(|safe| safe.prefix_str()).unwrap_or(""), + mutability = s.mutability.print_with_space(), + name = it.name.unwrap(), + typ = s.type_.print(cx) + ) + })?; - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); + write!(w, "{}", document(cx, it, None, HeadingOffset::H2)) + }) } -fn item_foreign_type(w: &mut impl fmt::Write, cx: &Context<'_>, it: &clean::Item) { - wrap_item(w, |buffer| { - buffer.write_str("extern {\n").unwrap(); - render_attributes_in_code(buffer, it, cx); +fn item_foreign_type(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { + fmt::from_fn(|w| { + wrap_item(w, |w| { + w.write_str("extern {\n")?; + render_attributes_in_code(w, it, cx); + write!(w, " {}type {};\n}}", visibility_print_with_space(it, cx), it.name.unwrap(),) + })?; + write!( - buffer, - " {}type {};\n}}", - visibility_print_with_space(it, cx), - it.name.unwrap(), + w, + "{}{}", + document(cx, it, None, HeadingOffset::H2), + render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All) ) - .unwrap(); - }); - - write!(w, "{}", document(cx, it, None, HeadingOffset::H2)).unwrap(); - write!(w, "{}", render_assoc_items(cx, it, it.item_id.expect_def_id(), AssocItemRender::All)) - .unwrap(); + }) } -fn item_keyword(w: &mut String, cx: &Context<'_>, it: &clean::Item) { - write_str(w, format_args!("{}", document(cx, it, None, HeadingOffset::H2))); +fn item_keyword(cx: &Context<'_>, it: &clean::Item) -> impl fmt::Display { + document(cx, it, None, HeadingOffset::H2) } /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order). @@ -2111,18 +2181,14 @@ pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String { s } -pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display + '_ { +pub(super) fn item_path(ty: ItemType, name: &str) -> impl Display { fmt::from_fn(move |f| match ty { ItemType::Module => write!(f, "{}index.html", ensure_trailing_slash(name)), _ => write!(f, "{ty}.{name}.html"), }) } -fn bounds<'a, 'tcx>( - bounds: &'a [clean::GenericBound], - trait_alias: bool, - cx: &'a Context<'tcx>, -) -> impl Display + 'a + Captures<'tcx> { +fn bounds(bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> impl Display { (!bounds.is_empty()) .then_some(fmt::from_fn(move |f| { let has_lots_of_bounds = bounds.len() > 2; @@ -2140,14 +2206,15 @@ fn bounds<'a, 'tcx>( .maybe_display() } -fn wrap_item(w: &mut W, f: F) +fn wrap_item(w: &mut W, f: F) -> T where W: fmt::Write, - F: FnOnce(&mut W), + F: FnOnce(&mut W) -> T, { write!(w, r#"
"#).unwrap();
-    f(w);
+    let res = f(w);
     write!(w, "
").unwrap(); + res } #[derive(PartialEq, Eq)] @@ -2175,10 +2242,9 @@ fn render_implementor( cx: &Context<'_>, implementor: &Impl, trait_: &clean::Item, - w: &mut String, implementor_dups: &FxHashMap, aliases: &[String], -) { +) -> impl fmt::Display { // If there's already another implementor that has the same abridged name, use the // full path, for example in `std::iter::ExactSizeIterator` let use_absolute = match implementor.inner_impl().for_ { @@ -2191,7 +2257,6 @@ fn render_implementor( _ => false, }; render_impl( - w, cx, implementor, trait_, @@ -2205,26 +2270,29 @@ fn render_implementor( show_non_assoc_items: false, toggle_open_by_default: false, }, - ); + ) } -fn render_union<'a, 'cx: 'a>( - it: &'a clean::Item, - g: Option<&'a clean::Generics>, - fields: &'a [clean::Item], - cx: &'a Context<'cx>, -) -> impl Display + 'a + Captures<'cx> { +fn render_union( + it: &clean::Item, + g: Option<&clean::Generics>, + fields: &[clean::Item], + cx: &Context<'_>, +) -> impl Display { fmt::from_fn(move |mut f| { write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?; - let where_displayed = g - .map(|g| { - let mut buf = g.print(cx).to_string(); - let where_displayed = print_where_clause_and_check(&mut buf, g, cx); - f.write_str(&buf).unwrap(); - where_displayed - }) - .unwrap_or(false); + let where_displayed = if let Some(generics) = g { + write!(f, "{}", generics.print(cx))?; + if let Some(where_clause) = print_where_clause(generics, cx, 0, Ending::Newline) { + write!(f, "{where_clause}")?; + true + } else { + false + } + } else { + false + }; // If there wasn't a `where` clause, we add a whitespace. if !where_displayed { @@ -2263,7 +2331,6 @@ fn render_union<'a, 'cx: 'a>( } fn render_struct( - w: &mut String, it: &clean::Item, g: Option<&clean::Generics>, ty: Option, @@ -2271,33 +2338,35 @@ fn render_struct( tab: &str, structhead: bool, cx: &Context<'_>, -) { - write_str( - w, - format_args!( +) -> impl fmt::Display { + fmt::from_fn(move |w| { + write!( + w, "{}{}{}", visibility_print_with_space(it, cx), if structhead { "struct " } else { "" }, it.name.unwrap() - ), - ); - if let Some(g) = g { - write_str(w, format_args!("{}", g.print(cx))); - } - render_struct_fields( - w, - g, - ty, - fields, - tab, - structhead, - it.has_stripped_entries().unwrap_or(false), - cx, - ) + )?; + if let Some(g) = g { + write!(w, "{}", g.print(cx))?; + } + write!( + w, + "{}", + render_struct_fields( + g, + ty, + fields, + tab, + structhead, + it.has_stripped_entries().unwrap_or(false), + cx, + ) + ) + }) } fn render_struct_fields( - mut w: &mut String, g: Option<&clean::Generics>, ty: Option, fields: &[clean::Item], @@ -2305,112 +2374,123 @@ fn render_struct_fields( structhead: bool, has_stripped_entries: bool, cx: &Context<'_>, -) { - match ty { - None => { - let where_displayed = - g.map(|g| print_where_clause_and_check(w, g, cx)).unwrap_or(false); +) -> impl fmt::Display { + fmt::from_fn(move |w| { + match ty { + None => { + let where_displayed = if let Some(generics) = g + && let Some(where_clause) = print_where_clause(generics, cx, 0, Ending::Newline) + { + write!(w, "{where_clause}")?; + true + } else { + false + }; - // If there wasn't a `where` clause, we add a whitespace. - if !where_displayed { - w.push_str(" {"); - } else { - w.push_str("{"); - } - let count_fields = - fields.iter().filter(|f| matches!(f.kind, clean::StructFieldItem(..))).count(); - let has_visible_fields = count_fields > 0; - let toggle = should_hide_fields(count_fields); - if toggle { - toggle_open(&mut w, format_args!("{count_fields} fields")); - } - for field in fields { - if let clean::StructFieldItem(ref ty) = field.kind { - write_str( - w, - format_args!( + // If there wasn't a `where` clause, we add a whitespace. + if !where_displayed { + w.write_str(" {")?; + } else { + w.write_str("{")?; + } + let count_fields = + fields.iter().filter(|f| matches!(f.kind, clean::StructFieldItem(..))).count(); + let has_visible_fields = count_fields > 0; + let toggle = should_hide_fields(count_fields); + if toggle { + toggle_open(&mut *w, format_args!("{count_fields} fields")); + } + for field in fields { + if let clean::StructFieldItem(ref ty) = field.kind { + write!( + w, "\n{tab} {vis}{name}: {ty},", vis = visibility_print_with_space(field, cx), name = field.name.unwrap(), ty = ty.print(cx) - ), - ); + )?; + } } - } - if has_visible_fields { - if has_stripped_entries { - write_str( - w, - format_args!( + if has_visible_fields { + if has_stripped_entries { + write!( + w, "\n{tab} /* private fields */" - ), - ); + )?; + } + write!(w, "\n{tab}")?; + } else if has_stripped_entries { + write!(w, " /* private fields */ ")?; } - write_str(w, format_args!("\n{tab}")); - } else if has_stripped_entries { - write_str(w, format_args!(" /* private fields */ ")); - } - if toggle { - toggle_close(&mut w); + if toggle { + toggle_close(&mut *w); + } + w.write_str("}")?; } - w.push_str("}"); - } - Some(CtorKind::Fn) => { - w.push_str("("); - if !fields.is_empty() - && fields.iter().all(|field| { - matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..))) - }) - { - write_str(w, format_args!("/* private fields */")); - } else { - for (i, field) in fields.iter().enumerate() { - if i > 0 { - w.push_str(", "); - } - match field.kind { - clean::StrippedItem(box clean::StructFieldItem(..)) => { - write_str(w, format_args!("_")); + Some(CtorKind::Fn) => { + w.write_str("(")?; + if !fields.is_empty() + && fields.iter().all(|field| { + matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..))) + }) + { + write!(w, "/* private fields */")?; + } else { + for (i, field) in fields.iter().enumerate() { + if i > 0 { + w.write_str(", ")?; } - clean::StructFieldItem(ref ty) => { - write_str( - w, - format_args!( + match field.kind { + clean::StrippedItem(box clean::StructFieldItem(..)) => { + write!(w, "_")?; + } + clean::StructFieldItem(ref ty) => { + write!( + w, "{}{}", visibility_print_with_space(field, cx), ty.print(cx) - ), - ); + )?; + } + _ => unreachable!(), } - _ => unreachable!(), } } + w.write_str(")")?; + if let Some(g) = g { + write!( + w, + "{}", + print_where_clause(g, cx, 0, Ending::NoNewline).maybe_display() + )?; + } + // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct. + if structhead { + w.write_str(";")?; + } } - w.push_str(")"); - if let Some(g) = g { - write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline))); - } - // We only want a ";" when we are displaying a tuple struct, not a variant tuple struct. - if structhead { - w.push_str(";"); - } - } - Some(CtorKind::Const) => { - // Needed for PhantomData. - if let Some(g) = g { - write_str(w, format_args!("{}", print_where_clause(g, cx, 0, Ending::NoNewline))); + Some(CtorKind::Const) => { + // Needed for PhantomData. + if let Some(g) = g { + write!( + w, + "{}", + print_where_clause(g, cx, 0, Ending::NoNewline).maybe_display() + )?; + } + w.write_str(";")?; } - w.push_str(";"); } - } + Ok(()) + }) } fn document_non_exhaustive_header(item: &clean::Item) -> &str { if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" } } -fn document_non_exhaustive(item: &clean::Item) -> impl Display + '_ { +fn document_non_exhaustive(item: &clean::Item) -> impl Display { fmt::from_fn(|f| { if item.is_non_exhaustive() { write!( diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 95f617c98390a..b39701fae1d6a 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -842,10 +842,7 @@ pub(crate) fn get_function_type_for_search( } clean::ConstantItem(ref c) => make_nullary_fn(&c.type_), clean::StaticItem(ref s) => make_nullary_fn(&s.type_), - clean::StructFieldItem(ref t) => { - let Some(parent) = parent else { - return None; - }; + clean::StructFieldItem(ref t) if let Some(parent) = parent => { let mut rgen: FxIndexMap)> = Default::default(); let output = get_index_type(t, vec![], &mut rgen); diff --git a/src/librustdoc/html/render/search_index/encode.rs b/src/librustdoc/html/render/search_index/encode.rs index 8816ea650593b..de2f54558ff81 100644 --- a/src/librustdoc/html/render/search_index/encode.rs +++ b/src/librustdoc/html/render/search_index/encode.rs @@ -182,9 +182,9 @@ pub(crate) fn write_bitmap_to_bytes( out.write_all(&[b])?; } if size < NO_OFFSET_THRESHOLD { - 4 + 4 * size + ((size + 7) / 8) + 4 + 4 * size + size.div_ceil(8) } else { - 4 + 8 * size + ((size + 7) / 8) + 4 + 8 * size + size.div_ceil(8) } } else { out.write_all(&u32::to_le_bytes(SERIAL_COOKIE_NO_RUNCONTAINER))?; diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 64dbaf9083e70..3130815af0bd0 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -79,7 +79,7 @@ impl<'a> LinkBlock<'a> { } /// A link to an item. Content should not be escaped. -#[derive(Ord, PartialEq, Eq, Hash, Clone)] +#[derive(PartialEq, Eq, Hash, Clone)] pub(crate) struct Link<'a> { /// The content for the anchor tag and title attr name: Cow<'a, str>, @@ -91,13 +91,13 @@ pub(crate) struct Link<'a> { children: Vec>, } -impl PartialOrd for Link<'_> { - fn partial_cmp(&self, other: &Link<'_>) -> Option { +impl Ord for Link<'_> { + fn cmp(&self, other: &Self) -> Ordering { match compare_names(&self.name, &other.name) { - Ordering::Equal => (), - result => return Some(result), + Ordering::Equal => {} + result => return result, } - (&self.name_html, &self.href, &self.children).partial_cmp(&( + (&self.name_html, &self.href, &self.children).cmp(&( &other.name_html, &other.href, &other.children, @@ -105,6 +105,12 @@ impl PartialOrd for Link<'_> { } } +impl PartialOrd for Link<'_> { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl<'a> Link<'a> { pub fn new(href: impl Into>, name: impl Into>) -> Self { Self { href: href.into(), name: name.into(), children: vec![], name_html: None } diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 658d5965b3d2a..3228f71df0743 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -95,10 +95,8 @@ impl SpanMapVisitor<'_> { .unwrap_or(path.span); self.matches.insert(span, link); } - Res::Local(_) => { - if let Some(span) = self.tcx.hir().res_span(path.res) { - self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span))); - } + Res::Local(_) if let Some(span) = self.tcx.hir().res_span(path.res) => { + self.matches.insert(path.span, LinkFromSrc::Local(clean::Span::new(span))); } Res::PrimTy(p) => { // FIXME: Doesn't handle "path-like" primitives like arrays or tuples. @@ -111,15 +109,15 @@ impl SpanMapVisitor<'_> { /// Used to generate links on items' definition to go to their documentation page. pub(crate) fn extract_info_from_hir_id(&mut self, hir_id: HirId) { - if let Node::Item(item) = self.tcx.hir_node(hir_id) { - if let Some(span) = self.tcx.def_ident_span(item.owner_id) { - let cspan = clean::Span::new(span); - // If the span isn't from the current crate, we ignore it. - if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE { - return; - } - self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id())); + if let Node::Item(item) = self.tcx.hir_node(hir_id) + && let Some(span) = self.tcx.def_ident_span(item.owner_id) + { + let cspan = clean::Span::new(span); + // If the span isn't from the current crate, we ignore it. + if cspan.inner().is_dummy() || cspan.cnum(self.tcx.sess) != LOCAL_CRATE { + return; } + self.matches.insert(span, LinkFromSrc::Doc(item.owner_id.to_def_id())); } } @@ -253,7 +251,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { // If it's a "mod foo {}", we want to look to its documentation page. self.extract_info_from_hir_id(id); } - intravisit::walk_mod(self, m, id); + intravisit::walk_mod(self, m); } fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'tcx>) { @@ -274,7 +272,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx Item<'tcx>) { match item.kind { - ItemKind::Static(_, _, _) + ItemKind::Static(..) | ItemKind::Const(_, _, _) | ItemKind::Fn { .. } | ItemKind::Macro(_, _) @@ -288,7 +286,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { | ItemKind::Use(_, _) | ItemKind::ExternCrate(_) | ItemKind::ForeignMod { .. } - | ItemKind::GlobalAsm(_) + | ItemKind::GlobalAsm { .. } // We already have "visit_mod" above so no need to check it here. | ItemKind::Mod(_) => {} } diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index 0f01db5f6bcc7..a1ee5c8c548b7 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -2,7 +2,6 @@ use std::fmt; use rinja::Template; use rustc_abi::{Primitive, TagEncoding, Variants}; -use rustc_data_structures::captures::Captures; use rustc_hir::def_id::DefId; use rustc_middle::span_bug; use rustc_middle::ty::layout::LayoutError; @@ -26,10 +25,7 @@ struct TypeLayoutSize { size: u64, } -pub(crate) fn document_type_layout<'a, 'cx: 'a>( - cx: &'a Context<'cx>, - ty_def_id: DefId, -) -> impl fmt::Display + 'a + Captures<'cx> { +pub(crate) fn document_type_layout(cx: &Context<'_>, ty_def_id: DefId) -> impl fmt::Display { fmt::from_fn(move |f| { if !cx.shared.show_type_layout { return Ok(()); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index a4dec013fc040..b2bbf4614bf45 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -153,7 +153,7 @@ fn write_rendered_cross_crate_info( include_sources: bool, ) -> Result<(), Error> { let m = &opt.should_merge; - if opt.emit.is_empty() || opt.emit.contains(&EmitType::InvocationSpecific) { + if opt.should_emit_crate() { if include_sources { write_rendered_cci::(SourcesPart::blank, dst, crates, m)?; } @@ -636,26 +636,22 @@ impl TypeAliasPart { } else { AssocItemLink::Anchor(None) }; - let text = { - let mut buf = String::new(); - super::render_impl( - &mut buf, - cx, - impl_, - type_alias_item, - assoc_link, - RenderMode::Normal, - None, - &[], - ImplRenderingParameters { - show_def_docs: true, - show_default_items: true, - show_non_assoc_items: true, - toggle_open_by_default: true, - }, - ); - buf - }; + let text = super::render_impl( + cx, + impl_, + type_alias_item, + assoc_link, + RenderMode::Normal, + None, + &[], + ImplRenderingParameters { + show_def_docs: true, + show_default_items: true, + show_non_assoc_items: true, + toggle_open_by_default: true, + }, + ) + .to_string(); let type_alias_fqp = (*type_alias_fqp).iter().join("::"); if Some(&text) == ret.last().map(|s: &AliasSerializableImpl| &s.text) { ret.last_mut() diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 78c86a27632b1..cbbd4b01d83ed 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -333,7 +333,7 @@ pub(crate) fn print_src( source_context: &SourceContext<'_>, ) { let mut lines = s.lines().count(); - let line_info = if let SourceContext::Embedded(ref info) = source_context { + let line_info = if let SourceContext::Embedded(info) = source_context { highlight::LineInfo::new_scraped(lines as u32, info.offset as u32) } else { highlight::LineInfo::new(lines as u32) diff --git a/src/librustdoc/html/static/COPYRIGHT.txt b/src/librustdoc/html/static/COPYRIGHT.txt index 111340298c5eb..752dab0a3478d 100644 --- a/src/librustdoc/html/static/COPYRIGHT.txt +++ b/src/librustdoc/html/static/COPYRIGHT.txt @@ -45,6 +45,27 @@ included, and carry their own copyright notices and license terms: Licensed under the SIL Open Font License, Version 1.1. See SourceSerif4-LICENSE.md. +* Nanum Barun Gothic Font (NanumBarunGothic.woff2) + + Copyright 2010, NAVER Corporation (http://www.nhncorp.com) + with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, + NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, + Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, + Naver NanumMyeongjoEco, NanumMyeongjoEco, Naver NanumGothicLight, + NanumGothicLight, NanumBarunGothic, Naver NanumBarunGothic. + + https://hangeul.naver.com/2017/nanum + https://github.com/hiun/NanumBarunGothic + + Licensed under the SIL Open Font License, Version 1.1. + See NanumBarunGothic-LICENSE.txt. + +* Rust logos (rust-logo.svg, favicon.svg, favicon-32x32.png) + + Copyright 2025 Rust Foundation. + Licensed under the Creative Commons Attribution license (CC-BY). + https://rustfoundation.org/policy/rust-trademark-policy/ + This copyright file is intended to be distributed with rustdoc output. # REUSE-IgnoreEnd diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 4f5f8f92264c1..0ea4d8f1e3914 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -41,6 +41,7 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ --font-family: "Source Serif 4", NanumBarunGothic, serif; --font-family-code: "Source Code Pro", monospace; --line-number-padding: 4px; + --line-number-right-margin: 20px; /* scraped examples icons (34x33px) */ --prev-arrow-image: url('data:image/svg+xml, .example-line-numbers, -.rustdoc .scraped-example .src-line-numbers, -.rustdoc .scraped-example .src-line-numbers > pre { - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} -.rustdoc .example-wrap > .example-line-numbers + pre, -.rustdoc .scraped-example .rust { - border-top-left-radius: 0; - border-bottom-left-radius: 0; -} - .rustdoc .scraped-example { position: relative; } @@ -908,45 +893,31 @@ both the code example and the line numbers, so we need to remove the radius in t overflow: auto; } -.rustdoc .example-wrap pre.example-line-numbers, -.rustdoc .example-wrap .src-line-numbers { - min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */ - flex-grow: 0; - text-align: right; - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; - padding: 14px 8px; - padding-right: 2px; - color: var(--src-line-numbers-span-color); -} - -.example-wrap.digits-1 [data-nosnippet] { +.example-wrap.digits-1:not(.hide-lines) [data-nosnippet] { width: calc(1ch + var(--line-number-padding) * 2); } -.example-wrap.digits-2 [data-nosnippet] { +.example-wrap.digits-2:not(.hide-lines) [data-nosnippet] { width: calc(2ch + var(--line-number-padding) * 2); } -.example-wrap.digits-3 [data-nosnippet] { +.example-wrap.digits-3:not(.hide-lines) [data-nosnippet] { width: calc(3ch + var(--line-number-padding) * 2); } -.example-wrap.digits-4 [data-nosnippet] { +.example-wrap.digits-4:not(.hide-lines) [data-nosnippet] { width: calc(4ch + var(--line-number-padding) * 2); } -.example-wrap.digits-5 [data-nosnippet] { +.example-wrap.digits-5:not(.hide-lines) [data-nosnippet] { width: calc(5ch + var(--line-number-padding) * 2); } -.example-wrap.digits-6 [data-nosnippet] { +.example-wrap.digits-6:not(.hide-lines) [data-nosnippet] { width: calc(6ch + var(--line-number-padding) * 2); } -.example-wrap.digits-7 [data-nosnippet] { +.example-wrap.digits-7:not(.hide-lines) [data-nosnippet] { width: calc(7ch + var(--line-number-padding) * 2); } -.example-wrap.digits-8 [data-nosnippet] { +.example-wrap.digits-8:not(.hide-lines) [data-nosnippet] { width: calc(8ch + var(--line-number-padding) * 2); } -.example-wrap.digits-9 [data-nosnippet] { +.example-wrap.digits-9:not(.hide-lines) [data-nosnippet] { width: calc(9ch + var(--line-number-padding) * 2); } @@ -954,12 +925,12 @@ both the code example and the line numbers, so we need to remove the radius in t color: var(--src-line-numbers-span-color); text-align: right; display: inline-block; - margin-right: 20px; + margin-right: var(--line-number-right-margin); -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; user-select: none; - padding: 0 4px; + padding: 0 var(--line-number-padding); } .example-wrap [data-nosnippet]:target { border-right: none; @@ -967,6 +938,60 @@ both the code example and the line numbers, so we need to remove the radius in t .example-wrap .line-highlighted[data-nosnippet] { background-color: var(--src-line-number-highlighted-background-color); } +:root.word-wrap-source-code .example-wrap [data-nosnippet] { + position: absolute; + left: 0; +} +.word-wrap-source-code .example-wrap pre > code { + position: relative; + word-break: break-all; +} +:root.word-wrap-source-code .example-wrap pre > code { + display: block; + white-space: pre-wrap; +} +:root.word-wrap-source-code .example-wrap pre > code * { + word-break: break-all; +} +:root.word-wrap-source-code .example-wrap.digits-1 pre > code { + padding-left: calc( + 1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-2 pre > code { + padding-left: calc( + 2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-3 pre > code { + padding-left: calc( + 3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-4 pre > code { + padding-left: calc( + 4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-5 pre > code { + padding-left: calc( + 5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-6 pre > code { + padding-left: calc( + 6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-7 pre > code { + padding-left: calc( + 7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-8 pre > code { + padding-left: calc( + 8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +:root.word-wrap-source-code .example-wrap.digits-9 pre > code { + padding-left: calc( + 9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin)); +} +.example-wrap.hide-lines [data-nosnippet] { + display: none; +} .search-loading { text-align: center; diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index e46cc1897e9e0..4150c5609a97e 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1,5 +1,5 @@ // Local js definitions: -/* global addClass, getSettingValue, hasClass, searchState, updateLocalStorage */ +/* global addClass, getSettingValue, hasClass, updateLocalStorage */ /* global onEachLazy, removeClass, getVar */ "use strict"; @@ -121,12 +121,9 @@ function getNakedUrl() { * doesn't have a parent node. * * @param {HTMLElement} newNode - * @param {HTMLElement} referenceNode + * @param {HTMLElement & { parentNode: HTMLElement }} referenceNode */ function insertAfter(newNode, referenceNode) { - // You're not allowed to pass an element with no parent. - // I dunno how to make TS's typechecker see that. - // @ts-expect-error referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } @@ -305,11 +302,10 @@ function preLoadCss(cssUrl) { window.searchState.timeout = null; } }, - // @ts-expect-error isDisplayed: () => { const outputElement = window.searchState.outputElement(); - return outputElement && - outputElement.parentElement && + return !!outputElement && + !!outputElement.parentElement && outputElement.parentElement.id === ALTERNATIVE_DISPLAY_ID; }, // Sets the focus on the search bar at the top of the page @@ -325,8 +321,6 @@ function preLoadCss(cssUrl) { search = window.searchState.outputElement(); } switchDisplayedElement(search); - // @ts-expect-error - window.searchState.mouseMovedAfterSearch = false; document.title = window.searchState.title; }, removeQueryParameters: () => { @@ -503,34 +497,40 @@ function preLoadCss(cssUrl) { handleHashes(ev); } - // @ts-expect-error + /** + * @param {HTMLElement|null} elem + */ function openParentDetails(elem) { while (elem) { if (elem.tagName === "DETAILS") { + // @ts-expect-error elem.open = true; } - elem = elem.parentNode; + elem = elem.parentElement; } } - // @ts-expect-error + /** + * @param {string} id + */ function expandSection(id) { openParentDetails(document.getElementById(id)); } - // @ts-expect-error + /** + * @param {KeyboardEvent} ev + */ function handleEscape(ev) { - // @ts-expect-error - searchState.clearInputTimeout(); - // @ts-expect-error - searchState.hideResults(); + window.searchState.clearInputTimeout(); + window.searchState.hideResults(); ev.preventDefault(); - // @ts-expect-error - searchState.defocus(); + window.searchState.defocus(); window.hideAllModals(true); // true = reset focus for tooltips } - // @ts-expect-error + /** + * @param {KeyboardEvent} ev + */ function handleShortcut(ev) { // Don't interfere with browser shortcuts const disableShortcuts = getSettingValue("disable-shortcuts") === "true"; @@ -538,8 +538,8 @@ function preLoadCss(cssUrl) { return; } - // @ts-expect-error - if (document.activeElement.tagName === "INPUT" && + if (document.activeElement && + document.activeElement.tagName === "INPUT" && // @ts-expect-error document.activeElement.type !== "checkbox" && // @ts-expect-error @@ -559,8 +559,7 @@ function preLoadCss(cssUrl) { case "S": case "/": ev.preventDefault(); - // @ts-expect-error - searchState.focus(); + window.searchState.focus(); break; case "+": @@ -586,7 +585,6 @@ function preLoadCss(cssUrl) { document.addEventListener("keydown", handleShortcut); function addSidebarItems() { - // @ts-expect-error if (!window.SIDEBAR_ITEMS) { return; } @@ -675,7 +673,6 @@ function preLoadCss(cssUrl) { } // - // @ts-expect-error window.register_implementors = imp => { const implementors = document.getElementById("implementors-list"); const synthetic_implementors = document.getElementById("synthetic-implementors-list"); @@ -767,9 +764,7 @@ function preLoadCss(cssUrl) { } } }; - // @ts-expect-error if (window.pending_implementors) { - // @ts-expect-error window.register_implementors(window.pending_implementors); } @@ -802,16 +797,14 @@ function preLoadCss(cssUrl) { * * - After processing all of the impls, it sorts the sidebar items by name. * - * @param {{[cratename: string]: Array>}} imp + * @param {rustdoc.TypeImpls} imp */ - // @ts-expect-error window.register_type_impls = imp => { // @ts-expect-error if (!imp || !imp[window.currentCrate]) { return; } - // @ts-expect-error - window.pending_type_impls = null; + window.pending_type_impls = undefined; const idMap = new Map(); let implementations = document.getElementById("implementations-list"); @@ -997,9 +990,7 @@ function preLoadCss(cssUrl) { list.replaceChildren(...newChildren); } }; - // @ts-expect-error if (window.pending_type_impls) { - // @ts-expect-error window.register_type_impls(window.pending_type_impls); } @@ -1112,35 +1103,32 @@ function preLoadCss(cssUrl) { // @ts-expect-error window.rustdoc_add_line_numbers_to_examples = () => { - if (document.querySelector(".rustdoc.src")) { - // We are in the source code page, nothing to be done here! - return; + // @ts-expect-error + function generateLine(nb) { + return `${nb}`; } + onEachLazy(document.querySelectorAll( - ":not(.scraped-example) > .example-wrap > pre:not(.example-line-numbers)", - ), x => { - const parent = x.parentNode; - const line_numbers = parent.querySelectorAll(".example-line-numbers"); - if (line_numbers.length > 0) { + ".rustdoc:not(.src) :not(.scraped-example) > .example-wrap > pre > code", + ), code => { + if (hasClass(code.parentElement.parentElement, "hide-lines")) { + removeClass(code.parentElement.parentElement, "hide-lines"); return; } - const count = x.textContent.split("\n").length; - const elems = []; - for (let i = 0; i < count; ++i) { - elems.push(i + 1); - } - const node = document.createElement("pre"); - addClass(node, "example-line-numbers"); - node.innerHTML = elems.join("\n"); - parent.insertBefore(node, x); + const lines = code.innerHTML.split("\n"); + const digits = (lines.length + "").length; + // @ts-expect-error + code.innerHTML = lines.map((line, index) => generateLine(index + 1) + line).join("\n"); + addClass(code.parentElement.parentElement, `digits-${digits}`); }); }; // @ts-expect-error window.rustdoc_remove_line_numbers_from_examples = () => { - onEachLazy(document.querySelectorAll(".example-wrap > .example-line-numbers"), x => { - x.parentNode.removeChild(x); - }); + onEachLazy( + document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"), + x => addClass(x, "hide-lines"), + ); }; if (getSettingValue("line-numbers") === "true") { @@ -1698,8 +1686,7 @@ function preLoadCss(cssUrl) { addSidebarCrates(); onHashChange(null); window.addEventListener("hashchange", onHashChange); - // @ts-expect-error - searchState.setup(); + window.searchState.setup(); }()); // Hide, show, and resize the sidebar diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index acea7828e86a9..4b43c00730d47 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -7,6 +7,8 @@ declare global { interface Window { /** Make the current theme easy to find */ currentTheme: HTMLLinkElement|null; + /** Generated in `render/context.rs` */ + SIDEBAR_ITEMS?: { [key: string]: string[] }; /** Used by the popover tooltip code. */ RUSTDOC_TOOLTIP_HOVER_MS: number; /** Used by the popover tooltip code. */ @@ -42,6 +44,17 @@ declare global { * Set up event listeners for a scraped source example. */ updateScrapedExample?: function(HTMLElement, HTMLElement), + /** + * register trait implementors, called by code generated in + * `write_shared.rs` + */ + register_implementors?: function(rustdoc.Implementors): void, + /** + * fallback in case `register_implementors` isn't defined yet. + */ + pending_implementors?: rustdoc.Implementors, + register_type_impls?: function(rustdoc.TypeImpls): void, + pending_type_impls?: rustdoc.TypeImpls, } interface HTMLElement { /** Used by the popover tooltip code. */ @@ -123,7 +136,7 @@ declare namespace rustdoc { * Same as QueryElement, but bindings and typeFilter support strings */ interface ParserQueryElement { - name: string, + name: string|null, id: number|null, fullPath: Array, pathWithoutLast: Array, @@ -131,10 +144,16 @@ declare namespace rustdoc { normalizedPathLast: string, generics: Array, bindings: Map>, - bindingName: {name: string, generics: ParserQueryElement[]}|null, - typeFilter: string|null, + bindingName: {name: string|null, generics: ParserQueryElement[]}|null, + typeFilter: number|string|null, } + /** + * Same as ParserQueryElement, but all fields are optional. + */ + type ParserQueryElementFields = { + [K in keyof ParserQueryElement]?: ParserQueryElement[T] + } /** * Intermediate parser state. Discarded when parsing is done. */ @@ -176,10 +195,11 @@ declare namespace rustdoc { name: string, normalizedName: string, word: string, + paramNames: string[], parent: ({ty: number, name: string, path: string, exactPath: string}|null|undefined), path: string, ty: number, - type?: FunctionSearchType + type: FunctionSearchType | null, } /** @@ -390,7 +410,7 @@ declare namespace rustdoc { */ type RawSearchIndexCrate = { doc: string, - a: Object, + a: { [key: string]: number[] }, n: Array, t: string, D: string, @@ -406,4 +426,16 @@ declare namespace rustdoc { }; type VlqData = VlqData[] | number; + + /** + * Maps from crate names to trait implementation data. + * Provied by generated `trait.impl` files. + */ + type Implementors = { + [key: string]: Array<[string, number, Array]> + } + + type TypeImpls = { + [cratename: string]: Array> + } } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index ccbd6811b0712..c275127997ab1 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -638,7 +638,6 @@ function getNextElem(query, parserState, elems, isInGenerics) { getFilteredNextElem(query, parserState, generics, isInGenerics); generics[generics.length - 1].bindingName = makePrimitiveElement("output"); } else { - // @ts-expect-error generics.push(makePrimitiveElement(null, { bindingName: makePrimitiveElement("output"), typeFilter: null, @@ -791,7 +790,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) { generics: generics.filter(gen => { // Syntactically, bindings are parsed as generics, // but the query engine treats them differently. - if (gen.bindingName !== null) { + if (gen.bindingName !== null && gen.bindingName.name !== null) { if (gen.name !== null) { gen.bindingName.generics.unshift(gen); } @@ -811,8 +810,8 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) { /** * - * @param {string} name - * @param {Object=} extra + * @param {string|null} name + * @param {rustdoc.ParserQueryElementFields=} extra * @returns {rustdoc.ParserQueryElement} */ function makePrimitiveElement(name, extra) { @@ -1478,73 +1477,61 @@ class DocSearch { * Special type name IDs for searching by array. * @type {number} */ - // @ts-expect-error this.typeNameIdOfArray = this.buildTypeMapIndex("array"); /** * Special type name IDs for searching by slice. * @type {number} */ - // @ts-expect-error this.typeNameIdOfSlice = this.buildTypeMapIndex("slice"); /** * Special type name IDs for searching by both array and slice (`[]` syntax). * @type {number} */ - // @ts-expect-error this.typeNameIdOfArrayOrSlice = this.buildTypeMapIndex("[]"); /** * Special type name IDs for searching by tuple. * @type {number} */ - // @ts-expect-error this.typeNameIdOfTuple = this.buildTypeMapIndex("tuple"); /** * Special type name IDs for searching by unit. * @type {number} */ - // @ts-expect-error this.typeNameIdOfUnit = this.buildTypeMapIndex("unit"); /** * Special type name IDs for searching by both tuple and unit (`()` syntax). * @type {number} */ - // @ts-expect-error this.typeNameIdOfTupleOrUnit = this.buildTypeMapIndex("()"); /** * Special type name IDs for searching `fn`. * @type {number} */ - // @ts-expect-error this.typeNameIdOfFn = this.buildTypeMapIndex("fn"); /** * Special type name IDs for searching `fnmut`. * @type {number} */ - // @ts-expect-error this.typeNameIdOfFnMut = this.buildTypeMapIndex("fnmut"); /** * Special type name IDs for searching `fnonce`. * @type {number} */ - // @ts-expect-error this.typeNameIdOfFnOnce = this.buildTypeMapIndex("fnonce"); /** * Special type name IDs for searching higher order functions (`->` syntax). * @type {number} */ - // @ts-expect-error this.typeNameIdOfHof = this.buildTypeMapIndex("->"); /** * Special type name IDs the output assoc type. * @type {number} */ - // @ts-expect-error this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true); /** * Special type name IDs for searching by reference. * @type {number} */ - // @ts-expect-error this.typeNameIdOfReference = this.buildTypeMapIndex("reference"); /** @@ -1586,7 +1573,6 @@ class DocSearch { /** * @type {Array} */ - // @ts-expect-error this.searchIndex = this.buildIndex(rawSearchIndex); } @@ -1598,10 +1584,16 @@ class DocSearch { * done more quickly. Two types with the same name but different item kinds * get the same ID. * - * @param {string} name + * @template T extends string + * @overload + * @param {T} name * @param {boolean=} isAssocType - True if this is an assoc type + * @returns {T extends "" ? null : number} + * + * @param {string} name + * @param {boolean=} isAssocType + * @returns {number | null} * - * @returns {number?} */ buildTypeMapIndex(name, isAssocType) { if (name === "" || name === null) { @@ -1909,6 +1901,7 @@ class DocSearch { * Convert raw search index into in-memory search index. * * @param {Map} rawSearchIndex + * @returns {rustdoc.Row[]} */ buildIndex(rawSearchIndex) { /** @@ -2008,6 +2001,7 @@ class DocSearch { return cb; }; + /** @type {rustdoc.Row[]} */ const searchIndex = []; let currentIndex = 0; let id = 0; @@ -2108,8 +2102,6 @@ class DocSearch { // an array of [(Number) item type, // (String) name] const rawPaths = crateCorpus.p; - // an array of [(String) alias name - // [Number] index to items] const aliases = crateCorpus.a; // an array of [(Number) item index, // (String) comma-separated list of function generic param names] @@ -2232,6 +2224,7 @@ class DocSearch { // object defined above. const itemParentIdx = itemParentIdxDecoder.next(); normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, ""); + /** @type {rustdoc.Row} */ const row = { crate, ty: itemTypes.charCodeAt(i) - 65, // 65 = "A" @@ -2274,16 +2267,14 @@ class DocSearch { continue; } - // @ts-expect-error + /** @type{number[]} */ let currentNameAliases; if (currentCrateAliases.has(alias_name)) { currentNameAliases = currentCrateAliases.get(alias_name); } else { currentNameAliases = []; - // @ts-expect-error currentCrateAliases.set(alias_name, currentNameAliases); } - // @ts-expect-error for (const local_alias of aliases[alias_name]) { currentNameAliases.push(local_alias + currentIndex); } @@ -2326,15 +2317,13 @@ class DocSearch { * @param {rustdoc.ParserQueryElement} elem */ function convertTypeFilterOnElem(elem) { - if (elem.typeFilter !== null) { + if (typeof elem.typeFilter === "string") { let typeFilter = elem.typeFilter; if (typeFilter === "const") { typeFilter = "constant"; } - // @ts-expect-error elem.typeFilter = itemTypeFromName(typeFilter); } else { - // @ts-expect-error elem.typeFilter = NO_TYPE_FILTER; } for (const elem2 of elem.generics) { @@ -2407,9 +2396,9 @@ class DocSearch { continue; } if (!foundStopChar) { - let extra = ""; + /** @type String[] */ + let extra = []; if (isLastElemGeneric(query.elems, parserState)) { - // @ts-expect-error extra = [" after ", ">"]; } else if (prevIs(parserState, "\"")) { throw ["Cannot have more than one element if you use quotes"]; @@ -2547,7 +2536,7 @@ class DocSearch { * See `buildTypeMapIndex` for more information. * * @param {rustdoc.QueryElement} elem - * @param {boolean} isAssocType + * @param {boolean=} isAssocType */ const convertNameToId = (elem, isAssocType) => { const loweredName = elem.pathLast.toLowerCase(); @@ -2627,7 +2616,6 @@ class DocSearch { ]; } for (const elem2 of elem.generics) { - // @ts-expect-error convertNameToId(elem2); } elem.bindings = new Map(Array.from(elem.bindings.entries()) @@ -2750,7 +2738,11 @@ class DocSearch { return [displayPath, href, `${exactPath}::${name}`]; }; - // @ts-expect-error + /** + * + * @param {string} path + * @returns {string} + */ function pathSplitter(path) { const tmp = "" + path.replace(/::/g, "::"); if (tmp.endsWith("")) { @@ -2763,9 +2755,9 @@ class DocSearch { * Add extra data to result objects, and filter items that have been * marked for removal. * - * @param {[rustdoc.ResultObject]} results + * @param {rustdoc.ResultObject[]} results * @param {"sig"|"elems"|"returned"|null} typeInfo - * @returns {[rustdoc.ResultObject]} + * @returns {rustdoc.ResultObject[]} */ const transformResults = (results, typeInfo) => { const duplicates = new Set(); @@ -2840,7 +2832,7 @@ class DocSearch { } let fnInputs = null; let fnOutput = null; - // @ts-expect-error + /** @type {Map | null} */ let mgens = null; if (typeInfo !== "elems" && typeInfo !== "returned") { fnInputs = unifyFunctionTypes( @@ -3053,7 +3045,6 @@ class DocSearch { writeFn(nested, result); } return; - // @ts-expect-error } else if (mgens) { for (const [queryId, fnId] of mgens) { if (fnId === fnType.id) { @@ -3069,7 +3060,7 @@ class DocSearch { name: fnParamNames[-1 - fnType.id], highlighted: !!fnType.highlighted, }, result); - // @ts-expect-error + /** @type{string[]} */ const where = []; onEachBtwn( fnType.generics, @@ -3079,7 +3070,6 @@ class DocSearch { () => pushText({ name: " + ", highlighted: false }, where), ); if (where.length > 0) { - // @ts-expect-error whereClause.set(fnParamNames[-1 - fnType.id], where); } } else { @@ -3181,7 +3171,7 @@ class DocSearch { * @param {rustdoc.Results} results * @param {"sig"|"elems"|"returned"|null} typeInfo * @param {string} preferredCrate - * @returns {Promise<[rustdoc.ResultObject]>} + * @returns {Promise} */ const sortResults = async(results, typeInfo, preferredCrate) => { const userQuery = parsedQuery.userQuery; @@ -3337,7 +3327,6 @@ class DocSearch { return 0; }); - // @ts-expect-error return transformResults(result_list, typeInfo); }; diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index bf33e0f17e5fe..5f1bbd27328cb 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -59,6 +59,14 @@ } else { removeClass(document.documentElement, "sans-serif"); } + break; + case "word-wrap-source-code": + if (value === true) { + addClass(document.documentElement, "word-wrap-source-code"); + } else { + removeClass(document.documentElement, "word-wrap-source-code"); + } + break; } } @@ -246,6 +254,11 @@ "js_name": "sans-serif-fonts", "default": false, }, + { + "name": "Word wrap source code", + "js_name": "word-wrap-source-code", + "default": false, + }, ]; // Then we build the DOM. diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index 3042373fb096f..425b915b5f94e 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -286,6 +286,9 @@ if (getSettingValue("hide-modnav") === "true") { if (getSettingValue("sans-serif-fonts") === "true") { addClass(document.documentElement, "sans-serif"); } +if (getSettingValue("word-wrap-source-code") === "true") { + addClass(document.documentElement, "word-wrap-source-code"); +} function updateSidebarWidth() { const desktopSidebarWidth = getSettingValue("desktop-sidebar-width"); if (desktopSidebarWidth && desktopSidebarWidth !== "null") { diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 9606ba76991a7..a5351b350dd5f 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -7,14 +7,13 @@ use rustc_abi::ExternAbi; use rustc_ast::ast; use rustc_attr_parsing::DeprecatedSince; -use rustc_hir::def::{CtorKind, DefKind}; +use rustc_hir::def::CtorKind; use rustc_hir::def_id::DefId; use rustc_metadata::rendered_const; use rustc_middle::{bug, ty}; -use rustc_span::{Pos, Symbol, sym}; +use rustc_span::{Pos, Symbol}; use rustdoc_json_types::*; -use super::FullItemId; use crate::clean::{self, ItemId}; use crate::formats::FormatRenderer; use crate::formats::item_type::ItemType; @@ -108,67 +107,6 @@ impl JsonRenderer<'_> { } } - pub(crate) fn id_from_item_default(&self, item_id: ItemId) -> Id { - self.id_from_item_inner(item_id, None, None) - } - - pub(crate) fn id_from_item_inner( - &self, - item_id: ItemId, - name: Option, - extra: Option, - ) -> Id { - let make_part = |def_id: DefId, name: Option, extra: Option| { - let name = match name { - Some(name) => Some(name), - None => { - // We need this workaround because primitive types' DefId actually refers to - // their parent module, which isn't present in the output JSON items. So - // instead, we directly get the primitive symbol - if matches!(self.tcx.def_kind(def_id), DefKind::Mod) - && let Some(prim) = self - .tcx - .get_attrs(def_id, sym::rustc_doc_primitive) - .find_map(|attr| attr.value_str()) - { - Some(prim) - } else { - self.tcx.opt_item_name(def_id) - } - } - }; - - FullItemId { def_id, name, extra } - }; - - let key = match item_id { - ItemId::DefId(did) => (make_part(did, name, extra), None), - ItemId::Blanket { for_, impl_id } => { - (make_part(impl_id, None, None), Some(make_part(for_, name, extra))) - } - ItemId::Auto { for_, trait_ } => { - (make_part(trait_, None, None), Some(make_part(for_, name, extra))) - } - }; - - let mut interner = self.id_interner.borrow_mut(); - let len = interner.len(); - *interner - .entry(key) - .or_insert_with(|| Id(len.try_into().expect("too many items in a crate"))) - } - - pub(crate) fn id_from_item(&self, item: &clean::Item) -> Id { - match item.kind { - clean::ItemKind::ImportItem(ref import) => { - let extra = - import.source.did.map(ItemId::from).map(|i| self.id_from_item_default(i)); - self.id_from_item_inner(item.item_id, item.name, extra) - } - _ => self.id_from_item_inner(item.item_id, item.name, None), - } - } - fn ids(&self, items: impl IntoIterator) -> Vec { items .into_iter() @@ -238,6 +176,7 @@ impl FromClean for GenericArgs { inputs: inputs.into_json(renderer), output: output.map(|a| (*a).into_json(renderer)), }, + ReturnTypeNotation => GenericArgs::ReturnTypeNotation, } } } @@ -548,7 +487,18 @@ impl FromClean for GenericBound { } } Outlives(lifetime) => GenericBound::Outlives(convert_lifetime(lifetime)), - Use(args) => GenericBound::Use(args.into_iter().map(|arg| arg.to_string()).collect()), + Use(args) => GenericBound::Use( + args.iter() + .map(|arg| match arg { + clean::PreciseCapturingArg::Lifetime(lt) => { + PreciseCapturingArg::Lifetime(convert_lifetime(*lt)) + } + clean::PreciseCapturingArg::Param(param) => { + PreciseCapturingArg::Param(param.to_string()) + } + }) + .collect(), + ), } } } diff --git a/src/librustdoc/json/ids.rs b/src/librustdoc/json/ids.rs new file mode 100644 index 0000000000000..737148bad4e88 --- /dev/null +++ b/src/librustdoc/json/ids.rs @@ -0,0 +1,122 @@ +//! Id handling for rustdoc-json. +//! +//! Manages the creation of [`rustdoc_json_types::Id`] and the +//! fact that these don't correspond exactly to [`DefId`], because +//! [`rustdoc_json_types::Item`] doesn't correspond exactly to what +//! other phases think of as an "item". + +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefId; +use rustc_span::{Symbol, sym}; +use rustdoc_json_types as types; + +use super::JsonRenderer; +use crate::clean; + +pub(super) type IdInterner = FxHashMap; + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +/// An uninterned id. +/// +/// Each one corresponds to exactly one of both: +/// 1. [`rustdoc_json_types::Item`]. +/// 2. [`rustdoc_json_types::Id`] transitively (as each `Item` has an `Id`). +/// +/// It's *broadly* equivalent to a [`DefId`], but needs slightly more information +/// to fully disambiguate items, because sometimes we choose to split a single HIR +/// item into multiple JSON items, or have items with no corresponding HIR item. +pub(super) struct FullItemId { + /// The "main" id of the item. + /// + /// In most cases this uniquely identifies the item, the other fields are just + /// used for edge-cases. + def_id: DefId, + + /// An extra [`DefId`], which we need for: + /// + /// 1. Auto-trait impls synthesized by rustdoc. + /// 2. Blanket impls synthesized by rustdoc. + /// 3. Splitting of reexports of multiple items. + /// + /// E.g: + /// + /// ```rust + /// mod module { + /// pub struct Foo {} // Exists in type namespace + /// pub fn Foo(){} // Exists in value namespace + /// } + /// + /// pub use module::Foo; // Imports both items + /// ``` + /// + /// In HIR, the `pub use` is just 1 item, but in rustdoc-json it's 2, so + /// we need to disambiguate. + extra_id: Option, + + /// Needed for `#[rustc_doc_primitive]` modules. + /// + /// For these, 1 [`DefId`] is used for both the primitive and the fake-module + /// that holds its docs. + /// + /// N.B. This only matters when documenting the standard library with + /// `--document-private-items`. Maybe we should delete that module, and + /// remove this. + name: Option, +} + +impl JsonRenderer<'_> { + pub(crate) fn id_from_item_default(&self, item_id: clean::ItemId) -> types::Id { + self.id_from_item_inner(item_id, None, None) + } + + fn id_from_item_inner( + &self, + item_id: clean::ItemId, + name: Option, + imported_id: Option, + ) -> types::Id { + let (def_id, extra_id) = match item_id { + clean::ItemId::DefId(did) => (did, imported_id), + clean::ItemId::Blanket { for_, impl_id } => (for_, Some(impl_id)), + clean::ItemId::Auto { for_, trait_ } => (for_, Some(trait_)), + }; + + let name = match name { + Some(name) => Some(name), + None => { + // We need this workaround because primitive types' DefId actually refers to + // their parent module, which isn't present in the output JSON items. So + // instead, we directly get the primitive symbol + if matches!(self.tcx.def_kind(def_id), DefKind::Mod) + && let Some(prim) = self + .tcx + .get_attrs(def_id, sym::rustc_doc_primitive) + .find_map(|attr| attr.value_str()) + { + Some(prim) + } else { + self.tcx.opt_item_name(def_id) + } + } + }; + + let key = FullItemId { def_id, extra_id, name }; + + let mut interner = self.id_interner.borrow_mut(); + let len = interner.len(); + *interner + .entry(key) + .or_insert_with(|| types::Id(len.try_into().expect("too many items in a crate"))) + } + + pub(crate) fn id_from_item(&self, item: &clean::Item) -> types::Id { + match item.kind { + clean::ItemKind::ImportItem(ref import) => { + let imported_id = import.source.did; + self.id_from_item_inner(item.item_id, item.name, imported_id) + } + _ => self.id_from_item_inner(item.item_id, item.name, None), + } + } +} diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 6f8cf25554fd2..ba27eed7c1136 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -5,6 +5,7 @@ //! docs for usage and details. mod conversions; +mod ids; mod import_finder; use std::cell::RefCell; @@ -16,7 +17,6 @@ use std::rc::Rc; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::Symbol; use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; // It's important to use the FxHashMap from rustdoc_json_types here, instead of @@ -35,14 +35,6 @@ use crate::formats::cache::Cache; use crate::json::conversions::IntoJson; use crate::{clean, try_err}; -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] -struct FullItemId { - def_id: DefId, - name: Option, - /// Used to distinguish imports of different items with the same name - extra: Option, -} - #[derive(Clone)] pub(crate) struct JsonRenderer<'tcx> { tcx: TyCtxt<'tcx>, @@ -55,7 +47,7 @@ pub(crate) struct JsonRenderer<'tcx> { out_dir: Option, cache: Rc, imported_items: DefIdSet, - id_interner: Rc), types::Id>>>, + id_interner: Rc>, } impl<'tcx> JsonRenderer<'tcx> { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1f2f8f7d33a4a..4fe5e13c3afe0 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -147,7 +147,7 @@ pub fn main() { #[cfg(target_os = "macos")] { - extern "C" { + unsafe extern "C" { fn _rjem_je_zone_register(); } @@ -561,7 +561,7 @@ fn opts() -> Vec { "", "emit", "Comma separated list of types of output for rustdoc to emit", - "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific]", + "[unversioned-shared-resources,toolchain-shared-resources,invocation-specific,dep-info]", ), opt(Unstable, FlagMulti, "", "no-run", "Compile doctests without running them", ""), opt( @@ -890,7 +890,13 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { // if we ran coverage, bail early, we don't need to also generate docs at this point // (also we didn't load in any of the useful passes) return; - } else if run_check { + } + + if render_opts.dep_info().is_some() { + rustc_interface::passes::write_dep_info(tcx); + } + + if run_check { // Since we're in "check" mode, no need to generate anything beyond this point. return; } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 97e6d3146427c..fdbb792d25dab 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -58,7 +58,7 @@ fn filter_assoc_items_by_name_and_namespace( assoc_items_of: DefId, ident: Ident, ns: Namespace, -) -> impl Iterator + '_ { +) -> impl Iterator { tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| { item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of) }) @@ -1334,14 +1334,12 @@ impl LinkCollector<'_, '_> { } // item can be non-local e.g. when using `#[rustc_doc_primitive = "pointer"]` - if let Some((src_id, dst_id)) = id.as_local().and_then(|dst_id| { - diag_info.item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id)) - }) { - if self.cx.tcx.effective_visibilities(()).is_exported(src_id) - && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id) - { - privacy_error(self.cx, diag_info, path_str); - } + if let Some(dst_id) = id.as_local() + && let Some(src_id) = diag_info.item.item_id.expect_def_id().as_local() + && self.cx.tcx.effective_visibilities(()).is_exported(src_id) + && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id) + { + privacy_error(self.cx, diag_info, path_str); } Some(()) @@ -1405,10 +1403,10 @@ impl LinkCollector<'_, '_> { // which we want in some cases but not in others. cache_errors: bool, ) -> Option)>> { - if let Some(res) = self.visited_links.get(&key) { - if res.is_some() || cache_errors { - return res.clone().map(|r| vec![r]); - } + if let Some(res) = self.visited_links.get(&key) + && (res.is_some() || cache_errors) + { + return res.clone().map(|r| vec![r]); } let mut candidates = self.resolve_with_disambiguator(&key, diag.clone()); @@ -1432,10 +1430,10 @@ impl LinkCollector<'_, '_> { // and after removing duplicated kinds, only one remains, the `ambiguity_error` function // won't emit an error. So at this point, we can just take the first candidate as it was // the first retrieved and use it to generate the link. - if let [candidate, _candidate2, ..] = *candidates { - if !ambiguity_error(self.cx, &diag, &key.path_str, &candidates, false) { - candidates = vec![candidate]; - } + if let [candidate, _candidate2, ..] = *candidates + && !ambiguity_error(self.cx, &diag, &key.path_str, &candidates, false) + { + candidates = vec![candidate]; } let mut out = Vec::with_capacity(candidates.len()); @@ -1480,17 +1478,16 @@ impl LinkCollector<'_, '_> { // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach. let mut err = ResolutionFailure::NotResolved(err); for other_ns in [TypeNS, ValueNS, MacroNS] { - if other_ns != expected_ns { - if let Ok(&[res, ..]) = self + if other_ns != expected_ns + && let Ok(&[res, ..]) = self .resolve(path_str, other_ns, None, item_id, module_id) .as_deref() - { - err = ResolutionFailure::WrongNamespace { - res: full_res(self.cx.tcx, res), - expected_ns, - }; - break; - } + { + err = ResolutionFailure::WrongNamespace { + res: full_res(self.cx.tcx, res), + expected_ns, + }; + break; } } resolution_failure(self, diag, path_str, disambiguator, smallvec![err]); @@ -1674,11 +1671,11 @@ impl Disambiguator { Ok(Some((d, &rest[1..], &rest[1..]))) } else { for (suffix, kind) in suffixes { - if let Some(path_str) = link.strip_suffix(suffix) { - // Avoid turning `!` or `()` into an empty string - if !path_str.is_empty() { - return Ok(Some((Kind(kind), path_str, link))); - } + // Avoid turning `!` or `()` into an empty string + if let Some(path_str) = link.strip_suffix(suffix) + && !path_str.is_empty() + { + return Ok(Some((Kind(kind), path_str, link))); } } Ok(None) @@ -2060,7 +2057,7 @@ fn resolution_failure( return; } Trait - | TyAlias { .. } + | TyAlias | ForeignTy | OpaqueTy | TraitAlias diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 87f85c5731528..f4e4cd924f7ff 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -177,23 +177,22 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> } else if let Some(did) = target.def_id(&cx.cache) { cleaner.items.insert(did.into()); } - if let Some(for_did) = for_.def_id(&cx.cache) { - if type_did_to_deref_target.insert(for_did, target).is_none() { - // Since only the `DefId` portion of the `Type` instances is known to be same for both the - // `Deref` target type and the impl for type positions, this map of types is keyed by - // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly. - if cleaner.keep_impl_with_def_id(for_did.into()) { - let mut targets = DefIdSet::default(); - targets.insert(for_did); - add_deref_target( - cx, - &type_did_to_deref_target, - &mut cleaner, - &mut targets, - for_did, - ); - } - } + if let Some(for_did) = for_.def_id(&cx.cache) + && type_did_to_deref_target.insert(for_did, target).is_none() + // Since only the `DefId` portion of the `Type` instances is known to be same for both the + // `Deref` target type and the impl for type positions, this map of types is keyed by + // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly. + && cleaner.keep_impl_with_def_id(for_did.into()) + { + let mut targets = DefIdSet::default(); + targets.insert(for_did); + add_deref_target( + cx, + &type_did_to_deref_target, + &mut cleaner, + &mut targets, + for_did, + ); } } } diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 3fb154dc51549..b9739726c9569 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -28,9 +28,9 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & // We don't try to detect stuff `` because that's not valid HTML, // and we don't try to detect stuff `` because that's not valid Rust. let mut generics_end = range.end; - if let Some(Some(mut generics_start)) = (is_open_tag - && dox[..generics_end].ends_with('>')) - .then(|| extract_path_backwards(dox, range.start)) + if is_open_tag + && dox[..generics_end].ends_with('>') + && let Some(mut generics_start) = extract_path_backwards(dox, range.start) { while generics_start != 0 && generics_end < dox.len() diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs index a3c3134f4c2c5..95646413a2d2f 100644 --- a/src/librustdoc/passes/lint/unportable_markdown.rs +++ b/src/librustdoc/passes/lint/unportable_markdown.rs @@ -73,15 +73,15 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & } let parser_old = cmarko::Parser::new_ext(dox, main_body_opts_old()).into_offset_iter(); for (event, span) in parser_old { - if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event { - if !dox[span.clone()].starts_with("> ") { - spaceless_block_quotes.remove(&span.start); - } + if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event + && !dox[span.clone()].starts_with("> ") + { + spaceless_block_quotes.remove(&span.start); } - if let cmarko::Event::FootnoteReference(_) = event { - if !found_footnote_references.contains(&(span.start + 1)) { - missing_footnote_references.insert(span.start + 1, span); - } + if let cmarko::Event::FootnoteReference(_) = event + && !found_footnote_references.contains(&(span.start + 1)) + { + missing_footnote_references.insert(span.start + 1, span); } } } diff --git a/src/librustdoc/passes/propagate_stability.rs b/src/librustdoc/passes/propagate_stability.rs index 9c958710c4200..fdab2b087799a 100644 --- a/src/librustdoc/passes/propagate_stability.rs +++ b/src/librustdoc/passes/propagate_stability.rs @@ -39,6 +39,16 @@ impl DocFolder for StabilityPropagator<'_, '_> { let item_stability = self.cx.tcx.lookup_stability(def_id); let inline_stability = item.inline_stmt_id.and_then(|did| self.cx.tcx.lookup_stability(did)); + let is_glob_export = item.inline_stmt_id.map(|id| { + let hir_id = self.cx.tcx.local_def_id_to_hir_id(id); + matches!( + self.cx.tcx.hir_node(hir_id), + rustc_hir::Node::Item(rustc_hir::Item { + kind: rustc_hir::ItemKind::Use(_, rustc_hir::UseKind::Glob), + .. + }) + ) + }); let own_stability = if let Some(item_stab) = item_stability && let StabilityLevel::Stable { since: _, allowed_through_unstable_modules } = item_stab.level @@ -47,6 +57,8 @@ impl DocFolder for StabilityPropagator<'_, '_> { since: inline_since, allowed_through_unstable_modules: _, } = inline_stab.level + && let Some(is_global_export) = is_glob_export + && !is_global_export { inline_stab.level = StabilityLevel::Stable { since: inline_since, diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index a71bb62e56c74..bcdca862862d4 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -7,9 +7,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; use tracing::debug; -use crate::clean; use crate::clean::utils::inherits_doc_hidden; -use crate::clean::{Item, ItemIdSet}; +use crate::clean::{self, Item, ItemIdSet, reexport_chain}; use crate::core::DocContext; use crate::fold::{DocFolder, strip_item}; use crate::passes::{ImplStripper, Pass}; @@ -89,6 +88,25 @@ impl Stripper<'_, '_> { impl DocFolder for Stripper<'_, '_> { fn fold_item(&mut self, i: Item) -> Option { let has_doc_hidden = i.is_doc_hidden(); + + if let clean::ImportItem(clean::Import { source, .. }) = &i.kind + && let Some(source_did) = source.did + && let Some(import_def_id) = i.def_id().and_then(|def_id| def_id.as_local()) + { + let reexports = reexport_chain(self.tcx, import_def_id, source_did); + + // Check if any reexport in the chain has a hidden source + let has_hidden_source = reexports + .iter() + .filter_map(|reexport| reexport.id()) + .any(|reexport_did| self.tcx.is_doc_hidden(reexport_did)) + || self.tcx.is_doc_hidden(source_did); + + if has_hidden_source { + return None; + } + } + let is_impl_or_exported_macro = match i.kind { clean::ImplItem(..) => true, // If the macro has the `#[macro_export]` attribute, it means it's accessible at the diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f606a3d8a9270..68e381fa3f171 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -143,7 +143,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { && self.cx.tcx.has_attr(def_id, sym::macro_export) && inserted.insert(def_id) { - let item = self.cx.tcx.hir().expect_item(local_def_id); + let item = self.cx.tcx.hir_expect_item(local_def_id); top_level_module .items .insert((local_def_id, Some(item.ident.name)), (item, None, None)); @@ -153,8 +153,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { self.cx.cache.hidden_cfg = self .cx .tcx - .hir() - .attrs(CRATE_HIR_ID) + .hir_attrs(CRATE_HIR_ID) .iter() .filter(|attr| attr.has_name(sym::doc)) .flat_map(|attr| attr.meta_item_list().into_iter().flatten()) @@ -245,7 +244,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; let document_hidden = self.cx.render_options.document_hidden; - let use_attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); + let use_attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. let is_no_inline = hir_attr_lists(use_attrs, sym::doc).has_word(sym::no_inline) || (document_hidden && hir_attr_lists(use_attrs, sym::doc).has_word(sym::hidden)); @@ -439,7 +438,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } // If we're inlining, skip private items. _ if self.inlining && !is_pub => {} - hir::ItemKind::GlobalAsm(..) => {} + hir::ItemKind::GlobalAsm { .. } => {} hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} hir::ItemKind::Use(path, kind) => { for &res in &path.res { @@ -449,7 +448,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { continue; } - let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(item.owner_id.def_id)); + let attrs = tcx.hir_attrs(tcx.local_def_id_to_hir_id(item.owner_id.def_id)); // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. diff --git a/src/librustdoc/visit_lib.rs b/src/librustdoc/visit_lib.rs index 3e66ed9f56da8..369fc52860ee2 100644 --- a/src/librustdoc/visit_lib.rs +++ b/src/librustdoc/visit_lib.rs @@ -57,10 +57,10 @@ impl LibEmbargoVisitor<'_, '_> { } for item in self.tcx.module_children(def_id).iter() { - if let Some(def_id) = item.res.opt_def_id() { - if item.vis.is_public() { - self.visit_item(def_id); - } + if let Some(def_id) = item.res.opt_def_id() + && item.vis.is_public() + { + self.visit_item(def_id); } } } diff --git a/src/llvm-project b/src/llvm-project index 92e80685d0d5d..1c3bb96fdb6db 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit 92e80685d0d5dcea3ccf321995c43b72338639c6 +Subproject commit 1c3bb96fdb6db7b8e8f24edb016099c223fdd27e diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index a92f3ded77466..44e82c7d8b195 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -30,7 +30,7 @@ pub type FxHashMap = HashMap; // re-export for use in src/librustdoc /// This integer is incremented with every breaking change to the API, /// and is returned along with the JSON blob as [`Crate::format_version`]. /// Consuming code should assert that this value matches the format version(s) that it supports. -pub const FORMAT_VERSION: u32 = 39; +pub const FORMAT_VERSION: u32 = 42; /// The root of the emitted JSON blob. /// @@ -120,7 +120,9 @@ pub struct Item { pub docs: Option, /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs pub links: HashMap, - /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`) + /// Stringified versions of parsed attributes on this item. + /// Essentially debug printed (e.g. `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`). + /// Equivalent to the hir pretty-printing of attributes. pub attrs: Vec, /// Information about the item’s deprecation, if present. pub deprecation: Option, @@ -227,6 +229,8 @@ pub enum GenericArgs { /// The output type provided after the `->`, if present. output: Option, }, + /// `T::method(..)` + ReturnTypeNotation, } /// One argument in a list of generic arguments to a path segment. @@ -907,7 +911,7 @@ pub enum GenericBound { /// ``` Outlives(String), /// `use<'a, T>` precise-capturing bound syntax - Use(Vec), + Use(Vec), } /// A set of modifiers applied to a trait. @@ -925,6 +929,22 @@ pub enum TraitBoundModifier { MaybeConst, } +/// One precise capturing argument. See [the rust reference](https://doc.rust-lang.org/reference/types/impl-trait.html#precise-capturing). +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum PreciseCapturingArg { + /// A lifetime. + /// ```rust + /// pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} + /// // ^^ + Lifetime(String), + /// A type or constant parameter. + /// ```rust + /// pub fn hello<'a, T, const N: usize>() -> impl Sized + use<'a, T, N> {} + /// // ^ ^ + Param(String), +} + /// Either a type or a constant, usually stored as the right-hand side of an equation in places like /// [`AssocItemConstraint`] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/src/stage0 b/src/stage0 index 5c3e3a7cebcc7..9d6a08d378d8e 100644 --- a/src/stage0 +++ b/src/stage0 @@ -13,469 +13,469 @@ nightly_branch=master # # All changes below this comment will be overridden the next time the # tool is executed. - -compiler_date=2025-02-08 + +compiler_date=2025-02-18 compiler_version=beta -rustfmt_date=2025-02-08 +rustfmt_date=2025-02-18 rustfmt_version=nightly -dist/2025-02-08/rustc-beta-aarch64-apple-darwin.tar.gz=ca5440402ebfd3ba7ce3b30ecbcdc3e9341861996a5dd51601de3131d62d0bc2 -dist/2025-02-08/rustc-beta-aarch64-apple-darwin.tar.xz=bb7c79e5adb6998ac3a57ae7434a247029777bf3e1687c51ff3fdca938b72b3d -dist/2025-02-08/rustc-beta-aarch64-pc-windows-msvc.tar.gz=596a586332d87beaf3d52fead6e6c286a1da6abc89b53da5f6874f5da134cded -dist/2025-02-08/rustc-beta-aarch64-pc-windows-msvc.tar.xz=6828f88d3d576cdea838d975e0dc61ae2daf32746d7dbefce07f12684f5c0d97 -dist/2025-02-08/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=86943f595d3ad4b4ee5b7c9db63df9addf9c5e50e25267f64daa504dc4bb63b6 -dist/2025-02-08/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=13449944b13c4a8ef9aae649e1edf0bfbedc9816f7f32445ce9623098a21e51d -dist/2025-02-08/rustc-beta-aarch64-unknown-linux-musl.tar.gz=ce7fc3bed538a938f11b1cc15da20dc7d68097cf7d68a37ecc969c225bf5dcaf -dist/2025-02-08/rustc-beta-aarch64-unknown-linux-musl.tar.xz=a3b77720f7ff2a4707ecf44cab11ef088c3903ed6e123de14237b2149858f1a0 -dist/2025-02-08/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=a9f02a5eb65c85f98b73dfd88ef4eb48e6782455b3ccb77032b2df5bbfa39e84 -dist/2025-02-08/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=93c5ad3bcb8473a7ec0dcc81b788436c9881c9d9c276906dc09bada56b45180c -dist/2025-02-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=90f46141b9590ad69f60ffabdceb262e0940081994bda97a74692b76fd5cf8c0 -dist/2025-02-08/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=364a0b19dd91fe47c7152bd5a495d5ebf10170e4e5896859b02aef81225fc72e -dist/2025-02-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=977901c4eaf17b2acc8f7b7dd4e2efe5c45b45f5763f94b2ca36beadcc1544fc -dist/2025-02-08/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=4f60ec3e8a48c97a98567338be479499dbfb48db328d3d208763a8e6ad36e80d -dist/2025-02-08/rustc-beta-i686-pc-windows-gnu.tar.gz=ab1f6cf30ac8abf6dd130144355b79510633b24b06b416d82ba1fbccd318c2e5 -dist/2025-02-08/rustc-beta-i686-pc-windows-gnu.tar.xz=68327052940d99080217450553c42f3df81507385b5b90734c9b41a57e601ec6 -dist/2025-02-08/rustc-beta-i686-pc-windows-msvc.tar.gz=479053067ce64241d06a09d88b23cfb3da6dbcff46b5e8e33c2c1797ecdefb19 -dist/2025-02-08/rustc-beta-i686-pc-windows-msvc.tar.xz=12a4286b430fdd49e8806aa98a4395fc2ded6eae5ca254fb2cddc2c6db2cd893 -dist/2025-02-08/rustc-beta-i686-unknown-linux-gnu.tar.gz=865d88d2a9bb177851e901a56c5b3a295aa4ecdec8f73c72d4f9914b2e4aac60 -dist/2025-02-08/rustc-beta-i686-unknown-linux-gnu.tar.xz=3f17f91cd666e59efd5a47c2db28af8eee0d89d4ebbc6263f005e1d8d7d5b839 -dist/2025-02-08/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=a1c42bc975d9ccd10771aa83874d0ea382780a8a925016d966d50084fb45c267 -dist/2025-02-08/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=5452b62e9cccb5dac1cd36b01d31b11ac97c85bf4f82a559a15a08c278061d78 -dist/2025-02-08/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=eb9d9ac867835710ef4dd301aed0afbfeb4221c818ef4d7f70f4bb2b5bc02790 -dist/2025-02-08/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=0afbff667ada4671511c48d6c5558009f395f3c2f3ad3d10c716882f6c9860f6 -dist/2025-02-08/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=db77ef515643b4ced71ab9ffce80338fe99b03abd6b7672f627f38e33e6642d9 -dist/2025-02-08/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=cac3b683fb606be111d5788b1a4194ec0ea77e0226350454cb7d1904d6f2f78e -dist/2025-02-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=a86bb2a0cd6f2c25f6f6c55b070a3f841c0a006588f759d0aa7c8d6b3401d904 -dist/2025-02-08/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=050e07098291a659baa3fb31e2a83c7e6e203614139dab3f3eb2c486c20b9f8b -dist/2025-02-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=c20d1b649bb28b8abba4a5dd8e881a03061ebe091e5cdbc44310706fc76b55b0 -dist/2025-02-08/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=24c742968242e5bb3d81b865c0fdfdb021772a40fe4d25f3b83fdcf8ccb087bd -dist/2025-02-08/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=2aa9e78148c44ae2c01f554449811993e592aa9c428de37fbdb42dead53eb60c -dist/2025-02-08/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=2e6751dacf4ce4a60c61e1fa8afb746ac38285c62e567df78f2de27ce25e5770 -dist/2025-02-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=d0d365fdba806bda1263767d40365da7b5c2e5d01cfe6e9e4c5a2fd66ad4608a -dist/2025-02-08/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=fef429294c81caa19fc0dac00eda00d55c087e94c7235e032b17c2b4f5556850 -dist/2025-02-08/rustc-beta-s390x-unknown-linux-gnu.tar.gz=75ea2ad9e2377d09c9517a932126f876eaf377ff0f38a382187bb4a8c31be34e -dist/2025-02-08/rustc-beta-s390x-unknown-linux-gnu.tar.xz=908e6fff603ef6d0721efc24e8faf014f5cafa71fc0220da4dac5c870b974c04 -dist/2025-02-08/rustc-beta-x86_64-apple-darwin.tar.gz=ccea051b3787d3682258edcfa6a35f2d7a44ac5c3d8117fcd55cc0a97e7b9b92 -dist/2025-02-08/rustc-beta-x86_64-apple-darwin.tar.xz=3555ff1e179da6a249861086c8986039ab7dcdcf581beb1f27246f987da436f6 -dist/2025-02-08/rustc-beta-x86_64-pc-windows-gnu.tar.gz=227da932cd028d2c2415f4df4c14daf225e2a917a0879e1debcee2b8ebbfc790 -dist/2025-02-08/rustc-beta-x86_64-pc-windows-gnu.tar.xz=231c0fb2989746424f8ad394e9015ef13a6b991a50f62009e7bca3e010e9320e -dist/2025-02-08/rustc-beta-x86_64-pc-windows-msvc.tar.gz=b75be89ce511758f7b9ab6b5701155349e5675e4b85975c33a91483d78666927 -dist/2025-02-08/rustc-beta-x86_64-pc-windows-msvc.tar.xz=bf529ca4409fefe3d38e2b0ee6b3102e9f8b7ace4352bea7e6d3148a84e98767 -dist/2025-02-08/rustc-beta-x86_64-unknown-freebsd.tar.gz=e2dcaf33887031f8d169ab734f3b3eb6858e5247097e46293c11ba1a2887a919 -dist/2025-02-08/rustc-beta-x86_64-unknown-freebsd.tar.xz=2cf5c49c04e57bcc34ada76ff22dd149c4d643b5af5766267663f2e0e4031d17 -dist/2025-02-08/rustc-beta-x86_64-unknown-illumos.tar.gz=c7572379985941a513b7b9e750043a74097655600cb34cb0460a34a5587b7e0d -dist/2025-02-08/rustc-beta-x86_64-unknown-illumos.tar.xz=4e98bbcbae02618c3f95a21fdb22b4e067ce0bacd8370076a1bf8107964d2896 -dist/2025-02-08/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=bcc22d77b53b54bcb95a5b92b19af7cf5d3e4b4418c3c9ed1d5ab9db3cd6c3a0 -dist/2025-02-08/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=8f3eb1b74e06bbdbf1d09e5df205677db6f6ff78e94f80fc1fd1441deed86f80 -dist/2025-02-08/rustc-beta-x86_64-unknown-linux-musl.tar.gz=ccd5ba2c7c7d8c8eeaae2f7c7b462945d7c7ac552d6175dd33c0b77ee3d6730b -dist/2025-02-08/rustc-beta-x86_64-unknown-linux-musl.tar.xz=ab198284a035b8b5ef584a925b5f7ef08228d1eeb43b17a33dab8c7ae93cbc96 -dist/2025-02-08/rustc-beta-x86_64-unknown-netbsd.tar.gz=5b52a1e3f591e6f65ac50d885cfa38e2bb655abc3db7f09ea860450b4b95d6e0 -dist/2025-02-08/rustc-beta-x86_64-unknown-netbsd.tar.xz=fad94b63a75e789df1e5d25e0bf44d1fc29146dea862006d5b1ffb5c20fdfc8d -dist/2025-02-08/rust-std-beta-aarch64-apple-darwin.tar.gz=19c355276bb12522f3c8e94e843e6e54434c66c4e2e49bf68e084d43e1c83350 -dist/2025-02-08/rust-std-beta-aarch64-apple-darwin.tar.xz=c05a1e3e86e2846c4322df02f9b02a1bf16edbf39d3394da56e1a8b3b36d9a60 -dist/2025-02-08/rust-std-beta-aarch64-apple-ios.tar.gz=ade5b194bd6b7737f505d201f6560ec3aeb41345ea692b2d262317fe0a3bfc38 -dist/2025-02-08/rust-std-beta-aarch64-apple-ios.tar.xz=026a233fab1b27e70dd1455a9a9a0f097d0617b720f82549a413bc4b2d9a2755 -dist/2025-02-08/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=fe743c3895565a7e641b8727a0e96172e0a735bb77f9ced18e201f54d5bab19e -dist/2025-02-08/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=66fd5b769ae7f0e4dd587fdf81ac31cb780cd20eadd082ef0252d7346354bfdb -dist/2025-02-08/rust-std-beta-aarch64-apple-ios-sim.tar.gz=ccc55643bde9f89be185b560e44d379ef85a0cc7f087f2f2bf7738d523b7a32d -dist/2025-02-08/rust-std-beta-aarch64-apple-ios-sim.tar.xz=b1d4c3de214fa207e987742ab73d316537ad9856eb3499d046f6aea4e9d3bc0c -dist/2025-02-08/rust-std-beta-aarch64-linux-android.tar.gz=b17466c9da602c1c282826bdd878e6ba4592906f74b0e8bbe3df302c2358ede4 -dist/2025-02-08/rust-std-beta-aarch64-linux-android.tar.xz=4addf9a4ed3ae4c80b097027fef7237261d2e9ada641e549cc91595c83614d6e -dist/2025-02-08/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=391f0b460feb164d29ed222b322380586743b19ab03c217690e8053e22903d3e -dist/2025-02-08/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=d81567dc4e204f7080854d0a3a7e7e16424758ff122dfc14448fa9da630932aa -dist/2025-02-08/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=91ff95f6a56ee5db99e72b293ea2048be0fd5ac3788bd32d9fc97337e7ee8b68 -dist/2025-02-08/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=d6eb64cdaa12fcc469687f99d03a30329847e89bf802361bb6acd61f65b0547e -dist/2025-02-08/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=c9f43315d352ecddbc18a9034723c58d5d8ec77fffa9e0e82322743d162e3db7 -dist/2025-02-08/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=2356a2902f91323d1492ef12fa2f17d1e4934748cec03d6621d6ecfe272f1c3e -dist/2025-02-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=ccc8c1777dc8d2e04d4d0640ece7b7820a8fea60a0fe371efcaa055972dcd7b3 -dist/2025-02-08/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=4208ef48af14c5feee97c16fe7e894777a479492760dc0eb838febf2eb92ece7 -dist/2025-02-08/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=b67e319c5e447e9ebf4b9a7e51800e7d7aec3564f0829fa23df953d8ee714131 -dist/2025-02-08/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=432ea33a49f0010125c960d7b93b585e7b4c91b34f9d07989cf1664bf7e71fe5 -dist/2025-02-08/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=53bbbc52c4f99733c7b4a1038fa014867c0d6ca8f1d7eccba651fab4f794247e -dist/2025-02-08/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=6df101f4d5416cba695be66b975a4e4dcab2a3041d079f0a454f342a6d24d7db -dist/2025-02-08/rust-std-beta-aarch64-unknown-none.tar.gz=f1ef3141ac9c634e7e6686cf3c13b83323eb168a249f596b1490f874372c1423 -dist/2025-02-08/rust-std-beta-aarch64-unknown-none.tar.xz=a709c52f479c73ed15709b3cb0b8e7641606cf86375a4c9a60b1c9d381c70183 -dist/2025-02-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=31b8fec1cd20dd1809bdf733209288d60de0f096fbd0cc2955982ce119703772 -dist/2025-02-08/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=afb3872ffa8ab3c79d08f713aeb76c658ea00a3b9d79d5516d89aa78ec1eab8e -dist/2025-02-08/rust-std-beta-aarch64-unknown-uefi.tar.gz=d73b90fa9d3a330274b2004ec535d396f90a82ac5b10fb8688f82472bd2c5ac1 -dist/2025-02-08/rust-std-beta-aarch64-unknown-uefi.tar.xz=ae05fa6bf0638b0e26fcb8bcac5973835aa965a56507588fa3d43981f20eee89 -dist/2025-02-08/rust-std-beta-arm-linux-androideabi.tar.gz=c18354734b678f0665dd60bb8765df00bca5d3fb7bb6e6a4b83e3cde971c26cf -dist/2025-02-08/rust-std-beta-arm-linux-androideabi.tar.xz=5f6bc44bbe3b24140fecad715cc5528249906bacf98fc3a0618a9c0cc92913e0 -dist/2025-02-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=d9a2ab83df4240431479fe27600ab1098333699e14103b8a627dc09a3dad6976 -dist/2025-02-08/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=4f95a441ff45c16fb8aa37432cffeef60f2e0711c9cb1015cf440f4da51d5425 -dist/2025-02-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=dacdeceea6625041f75c3f2fad4382d2c957b9511666987695fed8e3a2216c88 -dist/2025-02-08/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=e338c1d2cef57e4c4ef613e6b080371751b874f94a246ab32e872a008e9166ab -dist/2025-02-08/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=8bd4174934e5d0e4dd8e757db494a238c95024be5336e6062923b479c0275b6a -dist/2025-02-08/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=1637b8d23bc8052803d785f15031a75594860f2263808c9dee68dead29bcd37e -dist/2025-02-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=db6eb6a2af3395e1eee0060d0c022c74c0741c765009f081c0646d696bd0b873 -dist/2025-02-08/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=ca21a4af4de66abf9d31ae6b3fbc33df152656feef7a269bf7d039d2766176ee -dist/2025-02-08/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=118c52dfa7142c0ee281b126da5b043b2357b78e7e110000f490b20e6a1e7eed -dist/2025-02-08/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=558fbb7453a2e633630ed33ad150dce87fa515b5b443ae66c5f85ee27e0e771f -dist/2025-02-08/rust-std-beta-armebv7r-none-eabi.tar.gz=96ff6441b0577b25b83540dc803d692d3444bcd0b4f6128a7743970726facce9 -dist/2025-02-08/rust-std-beta-armebv7r-none-eabi.tar.xz=2621a9f82f73a3a2a2a0c6a7446549c5ad29a430a3e0b961909fe68da21b8491 -dist/2025-02-08/rust-std-beta-armebv7r-none-eabihf.tar.gz=0ef78d66dea96d1a6565fb3469bdcb3368f9e61a55a59a5d2508c54c091484e9 -dist/2025-02-08/rust-std-beta-armebv7r-none-eabihf.tar.xz=1c586301ae2a20ed1caaf0d62d985f9fd95bf2b937ebe7b6d738ca5812713722 -dist/2025-02-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=aaeb690b0a08e8f6546ac5608fade5852bb029db9189d6d036c69c4895c6ce32 -dist/2025-02-08/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=1d6ae672d5ebcd302a654c4347a386fabc3bf53aec9664cdf76b9c5a061d4eb1 -dist/2025-02-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=5557c7444e72eb29c904436f0221cb40c3156c5289c39b7e8c1a057dfd56c394 -dist/2025-02-08/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=ae9abe3580b1751854305200bd6a5dbf98aeef396e163534ac5521d04d7bfa7c -dist/2025-02-08/rust-std-beta-armv7-linux-androideabi.tar.gz=c466403dfb8e15cd674859fad24e2e0dd1ba100946c662a9bf29f2440f02a938 -dist/2025-02-08/rust-std-beta-armv7-linux-androideabi.tar.xz=83ad7b8237ae7ab0ddd6f43b604b27677ec9e83453f3127c356936af12140ee2 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=12489ebd742dd611937c2942c6f897608d1c4acb0fcb103a2a18f70b9b2d0596 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=54231b6c641736b29317682be9d1de9463e23478a892c16e083bc1bf20c9c925 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=e41b6582cc6eb2340208a3473d54d441e13fab87bfee3091a513da4039c224c6 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=9ca2df0ba2afd630a94a3bac08f8c412fdb6f905333c8978ac9b6bb5be777774 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=dd9f6f6d930d18dc5e1764691acd2e33cdd032ef757d534ea70202fcdc18e461 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=9d0e4864ecb7e33b231dedd10b54ad7707d79c61ff455256fd693a46a4ecddb5 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=b508af76bcabed45442fc1587ea1c74bbbf85d75fbd2fb64d7078cd799485ae6 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=3f9916a37ac0b79586756f09986516ba08e1c24b4d4675bd17d66058e42494cd -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=a80bdd0178f0b9c98c2fe80e59a1b936115a509d9b1be0202bea09d275b4c5d0 -dist/2025-02-08/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=6cb0340d4633e52f7a6f3419a0f18a9d0b75f604fbfe99ce5886186f81204264 -dist/2025-02-08/rust-std-beta-armv7a-none-eabi.tar.gz=f9ac794582c73c7e0a36990daa6c2e2d637213dc16a0063aed330bf68cf04d4d -dist/2025-02-08/rust-std-beta-armv7a-none-eabi.tar.xz=7463c6f6e9ba1bc056ab528e00017db0d6ac2b0e06812f0b1d7b569a8a7e51ab -dist/2025-02-08/rust-std-beta-armv7r-none-eabi.tar.gz=c676cfbcaae8c7686a231693b923f98e23ed3dfa174ecf42aab57d94e2bddd85 -dist/2025-02-08/rust-std-beta-armv7r-none-eabi.tar.xz=93b2802c8f555fdf03cd309539eabfa2f8e434114f8f750b89ec3005249e9b91 -dist/2025-02-08/rust-std-beta-armv7r-none-eabihf.tar.gz=077cf1bbe4fdb0c011bd625a59ebc4b3d2876a50b544b76934523504c59042b9 -dist/2025-02-08/rust-std-beta-armv7r-none-eabihf.tar.xz=3be6d9e04ad155e78be5ecce391b57b285c7675cd9a4f86e2ddb388c934c21f8 -dist/2025-02-08/rust-std-beta-i586-pc-windows-msvc.tar.gz=2e705d5660544cec738cda300b059dcc1d730f7ff3cb029980a1ac9c1f9e6831 -dist/2025-02-08/rust-std-beta-i586-pc-windows-msvc.tar.xz=4cc0760e20f53648ae5b171c6948af3950cda4c468f2bb437016d92a2eeb2465 -dist/2025-02-08/rust-std-beta-i586-unknown-linux-gnu.tar.gz=3a516cf5c265899c9a548f6b9305b78069cc03864dcf1b3fa0e247adfa978cb8 -dist/2025-02-08/rust-std-beta-i586-unknown-linux-gnu.tar.xz=25144f4fb500ab9ba438042dd24796b25660fc3d16d3e04b64561bd35f84e46b -dist/2025-02-08/rust-std-beta-i586-unknown-linux-musl.tar.gz=70bf9429de2e11fe9e14216d3c1cc61a3923e1a7c7bc17d5b0d63785716a9e26 -dist/2025-02-08/rust-std-beta-i586-unknown-linux-musl.tar.xz=35cfef70aa5c59ecbe0d563959c62ec0162a8943d32cdc45dd0207b6ad3d16eb -dist/2025-02-08/rust-std-beta-i686-linux-android.tar.gz=a17f82a5f41e38c5c9ccaf1b2cf5182ed2e3c459e87c841497f0594cda7f71bf -dist/2025-02-08/rust-std-beta-i686-linux-android.tar.xz=06565daae363ed88f579f261a89f75d126785c894e439976ae47870cedd56378 -dist/2025-02-08/rust-std-beta-i686-pc-windows-gnu.tar.gz=986595d50c1c5799f67bd04575b248c5cd81dc03f318bd137b46248f75b2727f -dist/2025-02-08/rust-std-beta-i686-pc-windows-gnu.tar.xz=9daf96aa939ec6ed4ac8ff6119da06fca827a7f160e5c7db658653d5839846af -dist/2025-02-08/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=f793d7a5ce20392287a7d178a2403d1d72dec2437401c447a7c5e3168c25bcf6 -dist/2025-02-08/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=039a361f65fd610b14142f0d654895f4ac271cfb03918f7fcd8b2e9c5ffc3c98 -dist/2025-02-08/rust-std-beta-i686-pc-windows-msvc.tar.gz=6cdd125eafa981da12bff2a7e519866cfe40b7d6d7b6debabbd2415759fd9dc8 -dist/2025-02-08/rust-std-beta-i686-pc-windows-msvc.tar.xz=7f1a722bc007efe77dbd099ff36f2c682ec4bcdb7e8b60d6ad868e9d08a9a367 -dist/2025-02-08/rust-std-beta-i686-unknown-freebsd.tar.gz=b7dc78d6d4e6ce343ce90a7153082575a991eebd8acbc3cdfbcb56d1cc281b83 -dist/2025-02-08/rust-std-beta-i686-unknown-freebsd.tar.xz=91d19c3086de738b3d11a2bd0f0ad31c9f6a9c39ef800fdb2040638fc91c69ac -dist/2025-02-08/rust-std-beta-i686-unknown-linux-gnu.tar.gz=fdd0f12816d4bfc15c441cd26c7ef0f9ac05f19b03f471f162e8781f04bfc392 -dist/2025-02-08/rust-std-beta-i686-unknown-linux-gnu.tar.xz=a1ba9ce61110a1a64cba2bad7274865979d8d10cf30dba44137cd0acd4b49bf1 -dist/2025-02-08/rust-std-beta-i686-unknown-linux-musl.tar.gz=3774b47f5d6748c32d634f0414391121f2a68d7e3e15162cce62ca42bfce1db3 -dist/2025-02-08/rust-std-beta-i686-unknown-linux-musl.tar.xz=fb0203eb986554773288b732feb65a76aa7e4510b30acf60a9a879614332f0e1 -dist/2025-02-08/rust-std-beta-i686-unknown-uefi.tar.gz=a388f43900f4ac040e2263f06e89ef92c3d630f2631b37147eb1234e3ff5555b -dist/2025-02-08/rust-std-beta-i686-unknown-uefi.tar.xz=5fcc43194705468d31fc07ea2cca780fef717adc2d46bd9508d006adcd237c23 -dist/2025-02-08/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=c1d25f88813fb558bf47478a7e2a43e735f2e7ceba87f3ab8e658200825ac6a5 -dist/2025-02-08/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=66ae16763fba1c9e54519a34b70811f4b54c2a3985bd0faab4ae1a454f837556 -dist/2025-02-08/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=0cf97c80c7dc0e760d9aa2f6a6d6b82ecceed06b0c0e7f56b2f3fee98f558d3e -dist/2025-02-08/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=7b8284890d5c90e9a3d2cee73ee6b77ed0f023321a547a9add7d25e64886c9b9 -dist/2025-02-08/rust-std-beta-loongarch64-unknown-none.tar.gz=67f97000b8786928eb7ff7f060fdaa2fa9e3805c23e5f3fc24350c6ab0954c17 -dist/2025-02-08/rust-std-beta-loongarch64-unknown-none.tar.xz=5660100854fbe9fd87c0854b560a91dd5b653f07a0c374ba6349c44ff54b3b76 -dist/2025-02-08/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=a885c29e4eea19ada52cc22bfe395eb0f2e884932885c3978187a44405d5873a -dist/2025-02-08/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=acbfef3c94943ebc1a44e662a5eeffea6c3c0f8b2518568b03d2e1c5baf323ea -dist/2025-02-08/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=2bb3f9493afdd89c52bd62e2597c8687335e0d4fbe5a486782335a614881a516 -dist/2025-02-08/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=0702664eceb39c21390e3ee8dbfc0a7a181877449642b1b47dc74e1f463d8ebc -dist/2025-02-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=788b46512726f8350f8266f4dc7e3bd4108ea96b2c257876d42d6c62cef71507 -dist/2025-02-08/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=a746eeeb6c41696c95144068e348237bc7a3b254b1c3db626797dd2947194999 -dist/2025-02-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=48f11a2d3aee9b3cb8d9e7f6480c8859427f446ebde617e2575a17dda6605fc7 -dist/2025-02-08/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=5a3933b2465cfe93daab1b5d339a0da17bc364d5621d85e192283250b337e38f -dist/2025-02-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=50bddd9780ebcb5bc081b41c071c6059618881e1cc384f30787caa6fd2f28127 -dist/2025-02-08/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=4630d67082a6c2211a8c59a6da45d260616bd026d7cf7d2bbee5ae6d24b218c1 -dist/2025-02-08/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=4a0bcf103df6febd7b3e04bb24d54b30b6a2f4ffaf150f6774811c149f450588 -dist/2025-02-08/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=6a37963463641ddc14e03c0f9d8b037cd62afe3af89aeaa73f1f1d3aea1a6f93 -dist/2025-02-08/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=7e2c0f7ea78086cc2b8674aacf350b6de737ca68a51778a8a66c75932161a8a8 -dist/2025-02-08/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=a575b31731a910d2db684a931ced914b4286b942ce878fde94f08bafae92903c -dist/2025-02-08/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=096407f438062be73bdd4f2efb6e06ddcb6c6c8e08b3c2db76388a4f4c4a731f -dist/2025-02-08/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=38b771d01c0a56330d9547692c424e92b243d3f2448c13b29873cb2e4fe70b17 -dist/2025-02-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=218d5db0b8427fcc0a81612134d830e6807db8d66eaa4365c4b101f29ab75ae2 -dist/2025-02-08/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=1227b4dbfe7f3a0c7715904d3ed1e9f9846c49e522bb579d7dd76de370ab83a2 -dist/2025-02-08/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=8e5ad6f6116b0fef61650f2a3788cc9a9e6da1cd76dd0dc300d81060ef42ee6b -dist/2025-02-08/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=777cc9ec22cb9b92ea3569d6835770f45ea7793397be670edeafa65660d411eb -dist/2025-02-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=16d6414fcbfd0356206cccb10f0d5ec1391300c8bd92029d9457fc3030cf3cff -dist/2025-02-08/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=bd4ffe303e7b6a9031eae2dca7b4af4c7095e06961a55a6eff01db57178c1635 -dist/2025-02-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=facbe91da7b765e03b058682a1353153b89632f5f60692b25077ba4152105faf -dist/2025-02-08/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=e130dbd1aa2f19c308ca3e72e0456769ab0898a9bacdc667261396d786a22fca -dist/2025-02-08/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=3849880a18e3176c4acb895dcee7f5befa64ad3413ac8476325d97a9a2bbc542 -dist/2025-02-08/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=8a14b3cb0c9e20ec84ab686e6eca5acd201e71364ab5007c96b884feb4b59340 -dist/2025-02-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=f5f58c50d793cb26103f812bb32b2d3623c57319a141e151201764f20032262b -dist/2025-02-08/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=db7ea697f41b8dc2610c6d71ded8dc0b80ec848c002cb6af8faa3105023ec424 -dist/2025-02-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=b081a9b131703cbc11658eb84e54e495fca021bdc6487d902c7aeb8126629437 -dist/2025-02-08/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=2a3327ffdd3bfb9b4ce6d1aa13202958587d0819dc49ce08e635970d8e608b6c -dist/2025-02-08/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=3b0abfeb0a6bda721e1faad0fe4ed2db072ae04beaef53d895f3902a26387522 -dist/2025-02-08/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=5d6314a99746c5fd7f1d0eb0ac426848b4baafb9e2f4e08b7ce361091909a485 -dist/2025-02-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=01f85bdc840f6d354fbc765b2574cbf039a97e7a8cd4345f31d4a93f41ea2936 -dist/2025-02-08/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=350aa8e77ce705d04d996ae3911121c14213fed5db6d179ae4efeb54e64d5554 -dist/2025-02-08/rust-std-beta-sparcv9-sun-solaris.tar.gz=4cdb48054bcd8c596657c466145e1ec9d9a513d6019694895b7b1218183d7ed1 -dist/2025-02-08/rust-std-beta-sparcv9-sun-solaris.tar.xz=abda0bf8356c63fcf50fafb196c86a6c2275f3155362fe6b9eb63c8a145e07dc -dist/2025-02-08/rust-std-beta-thumbv6m-none-eabi.tar.gz=87ce4c701797be511509773e6121d69470d604f143c4e46e18866105193d503e -dist/2025-02-08/rust-std-beta-thumbv6m-none-eabi.tar.xz=d0af4c523a37df6ef2519d2abd680e2abc21e8806904cbbfa2bad3ddebc55252 -dist/2025-02-08/rust-std-beta-thumbv7em-none-eabi.tar.gz=9c183442ae8a7bf18303331e23c2263d180157a4fa9d000735b57f54f894fbf3 -dist/2025-02-08/rust-std-beta-thumbv7em-none-eabi.tar.xz=c9278b82123969a4f9c8536f6d27ceb6b6cae182335cee4cfc1ba8f297d503c7 -dist/2025-02-08/rust-std-beta-thumbv7em-none-eabihf.tar.gz=cda7f615c006369dea46c6d00660d596459d2ca809b27802c15a9e71e741f806 -dist/2025-02-08/rust-std-beta-thumbv7em-none-eabihf.tar.xz=7b2bf45033d1849ced101c696641a3e0037dc65029bea06fcedf3b11af1b21b8 -dist/2025-02-08/rust-std-beta-thumbv7m-none-eabi.tar.gz=bbe3db6ddb17830708086940294a8931054c09d781968f69c810a5a17cb4299d -dist/2025-02-08/rust-std-beta-thumbv7m-none-eabi.tar.xz=4cf28e2656f8927cbb75c007aded9d0fcac8d8d34841e9ac5486ba8ad3a75a58 -dist/2025-02-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=6021afefa8b06c99e09e63c07a8d4580ef7a6d9e004205d85f8fea47fb7c77d7 -dist/2025-02-08/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=7fb5c89a7605b0b377fd3e11d3ac5e33dc59667557b690b02df5c852109cefe8 -dist/2025-02-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=f1cbb573556272077f7a119e019ee4c1f8c533cfcbdb2b12c858c7d72c05212a -dist/2025-02-08/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=2d7c0f7ece15f6ad5de053a4b0292113efd8b45457a7ea4ac4a84534985a6e7c -dist/2025-02-08/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=fb5c1d99eeedb48edac78bce237351bb2a04b3ce1e028b47c488a28a0f5b258d -dist/2025-02-08/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=301ced2f4ca8766183cfbd84b94ca09f21c9c2fee62b3e1afca440f5872ec6f0 -dist/2025-02-08/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=c720cd1896d201ecee177381386cf37ff58a0ad2e153efa8752dc11358489774 -dist/2025-02-08/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=f2e14c2a08777200dcec2c18677a1bd68c57a7caaed8751e17d4a82af0f61e9c -dist/2025-02-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=146bfeecf574cab3bc15396c2523f27cc463ba9030d9a8c9a07118781a78227c -dist/2025-02-08/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=093364007abdcb942a1d095bba6b3f6a63cb891e3897764923828db5aa44f970 -dist/2025-02-08/rust-std-beta-wasm32-unknown-emscripten.tar.gz=f2e4ef8637a02510dc3edf78f7117dc16671946e1eebf3ee8911160bde53f3a2 -dist/2025-02-08/rust-std-beta-wasm32-unknown-emscripten.tar.xz=d30b8b9a7607de4cee24b144452439726eb8b4a436f53c058c2b0c21b686a391 -dist/2025-02-08/rust-std-beta-wasm32-unknown-unknown.tar.gz=242403cc6e3df3d47c566c63fccfb40e6a95d2f2295630bb13f4875c9e28ae62 -dist/2025-02-08/rust-std-beta-wasm32-unknown-unknown.tar.xz=8ba08c010e49593d417feb05f3efe407200421bc26d40b51a8d92ae6cbc46200 -dist/2025-02-08/rust-std-beta-wasm32-wasip1.tar.gz=25cdad2de0d599c5e90373765acba871e2facc7656ea1362b3e0d1132fe8805b -dist/2025-02-08/rust-std-beta-wasm32-wasip1.tar.xz=0eb3ae579124a47f7e8b63e6933e703d00c535f8369c614678e35c431a5480ff -dist/2025-02-08/rust-std-beta-wasm32-wasip1-threads.tar.gz=08d400d8ad036c2b240f4044adc6cf484cf996b5f1cca5e9c0fe81814a71635e -dist/2025-02-08/rust-std-beta-wasm32-wasip1-threads.tar.xz=46aeb5066e5fe4bc613a704c760292a85d2cd5ae10d135412adf5cb42de24015 -dist/2025-02-08/rust-std-beta-wasm32-wasip2.tar.gz=9df47e7c8280b8780ca41ed3dac9326375c76955560491ade1c2fdc8682b70d4 -dist/2025-02-08/rust-std-beta-wasm32-wasip2.tar.xz=275cc332f6d29c685ecfc308e143edccf58fce0359f632b038733a7759ae7389 -dist/2025-02-08/rust-std-beta-wasm32v1-none.tar.gz=96ee2faa07796474ea348b83b626cfa0bd07d108ffd05aed8051b63960315ee5 -dist/2025-02-08/rust-std-beta-wasm32v1-none.tar.xz=965650429f8129c65a6180025fdb69c0890f5c6f9c1fc16566c08b055e4ed93c -dist/2025-02-08/rust-std-beta-x86_64-apple-darwin.tar.gz=92ebd93de4f4da8267e13824db8455dbcb7bb95ffda8ae480c648c2eb8f820da -dist/2025-02-08/rust-std-beta-x86_64-apple-darwin.tar.xz=00e4b5a44f69a2c9235e522eee91e972624c75e3ce773928b09e9ee20d2d51ba -dist/2025-02-08/rust-std-beta-x86_64-apple-ios.tar.gz=dfb3d88798ff9b490c1a517d57e459a77cf2bb2e8b427493a3a612405534ebb3 -dist/2025-02-08/rust-std-beta-x86_64-apple-ios.tar.xz=7091bae8ccf328336261c2b096d1565c0dc9dca02b03d4e228a7c3f4c412a6df -dist/2025-02-08/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=79628c744d12c1bc5514801a530d903ec539efd16e82d0c871adfaa168b7f55b -dist/2025-02-08/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=2b12ae64c94a4f11591de8484998391d2825bc68535257dd305d31a1c51a7210 -dist/2025-02-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=54f4caf75ac93676fd61fec65e2ea6b73774d5de7d7abe8d47d9c2d8030d8fe0 -dist/2025-02-08/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=abc1feb82d4449c0d098a1ee0861ad991e79911cf0d5cc9ed9b5ca1e134248e6 -dist/2025-02-08/rust-std-beta-x86_64-linux-android.tar.gz=fdc1afd6334f725cfd913faf0915da711cdbcc45c05ec2672fae34d97e73ca60 -dist/2025-02-08/rust-std-beta-x86_64-linux-android.tar.xz=9451c74b695dce762d56354fac148263b0a7de75209c127bc7126da54ede7114 -dist/2025-02-08/rust-std-beta-x86_64-pc-solaris.tar.gz=d32731be8a9d3c5e8279a1b4971d105fe457717acbdfcfd720bc0ae55a34df26 -dist/2025-02-08/rust-std-beta-x86_64-pc-solaris.tar.xz=a5a08cfaae7eb3d77c137bf0d436beb7a84a19e351f529fe459861a8841df44c -dist/2025-02-08/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=7c41f46506f93132c5f90184d7ad1577edec98d47be17c6330f24cd172c673d5 -dist/2025-02-08/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=e439c8a7368e70685b239ab7b84bffcd8081ddc80c2d9f6d2b686485316aed68 -dist/2025-02-08/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=128c7e526e37551ba3b6a347cb870c4ceefb272d964512fa10635c8f1f6e239c -dist/2025-02-08/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=660409184e81625419b91a4fb5d84572abb0505d9bc11bacbed50121f9230790 -dist/2025-02-08/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=10b37018a254f81e55f555628fcc535a54b0eae0097f02a148c443a3d7e762f9 -dist/2025-02-08/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=d61e44948d2ea70b44c8d3f958a3657dae9eb8a551aedb3ef90327da0124d9d5 -dist/2025-02-08/rust-std-beta-x86_64-unknown-freebsd.tar.gz=7ed5b948a50946b518040170be16cba1b5ec0c02f823436c973e5afbd335d26b -dist/2025-02-08/rust-std-beta-x86_64-unknown-freebsd.tar.xz=0bdce5b2f88448dbbe101f4ef48231763739533b52c32ab6ef858b6b37d98a50 -dist/2025-02-08/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=49676d645ef9c49a421f3fa1d908830b61542541f1ea12c2d240ceaac3b977d4 -dist/2025-02-08/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=1c0854c619e2a0dd7e508513fb68c22352ddc170572bfe6535d2f759de069c53 -dist/2025-02-08/rust-std-beta-x86_64-unknown-illumos.tar.gz=8ded61102c481e7c000292a8c6d39d84c016f81b00618947ac7357a7c72fb142 -dist/2025-02-08/rust-std-beta-x86_64-unknown-illumos.tar.xz=b76ed9b0896cfe863fd2aff88fd6d075e6091a651cb0d5fa65307948316f7ebd -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=1cbcf5ae9dd2c61212b82bf27bf1b1b7d9504f077119c1fa04a978fa0ef3b2e6 -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=86f236dc4222f5f93f160ca847f43f364e1659b6d4c9f68a31c202f5346f2221 -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=2225ae88e8cf954b7eef8fc2e4f391c0194fd7be6433928dbc8aa6e2235ac479 -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=6017a3197b7a103a4444b81f8fa4f790a2b11bf1c3db0af297e2ed0c97f78172 -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=e7b3c4d8efb8f56fa76c3cfe51eb0683fc41308691ac194b9eb70e13b1b2e976 -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=f0ad48db569e21b8fa1053de3320d766cbb10962ebbd69ed56f170bdaf76fe45 -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=f1baa7f02c0969d74cd0ba420ae0a8d5e761cd5545c04fd2e432c889db8cb655 -dist/2025-02-08/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=e572e1a7db7e0127bf7072e5361b91dac84c019afa6433538b40dc984957f1d7 -dist/2025-02-08/rust-std-beta-x86_64-unknown-netbsd.tar.gz=c714b5f4a61041b5c68abc532203c88d65a852a813b7af8e11ab3207804886fc -dist/2025-02-08/rust-std-beta-x86_64-unknown-netbsd.tar.xz=61d6c87b146f114d14fe637257b9feccbb1d787958a7291f7800c7541bd8e21b -dist/2025-02-08/rust-std-beta-x86_64-unknown-none.tar.gz=5ab7c9985beb3f07520cecbb60c2fcb8bf60b3079b253267fb55d2139619331a -dist/2025-02-08/rust-std-beta-x86_64-unknown-none.tar.xz=992257d8f922654977d1c1fdad2b57654b4ea7fd2c27d6a4bcb8f85b9a75fc5a -dist/2025-02-08/rust-std-beta-x86_64-unknown-redox.tar.gz=e5090b881329fd94e4250cef92464bf3fc42ae6566ab3bf461e1f3c843d3d1fe -dist/2025-02-08/rust-std-beta-x86_64-unknown-redox.tar.xz=89cc1ad229a453c15d4a88137646d6824c572eed602c9c131982e3ddc62abd75 -dist/2025-02-08/rust-std-beta-x86_64-unknown-uefi.tar.gz=f42383deea91ab9dfdffede178b4411d751772a482811058dfc0bcc33da2fab6 -dist/2025-02-08/rust-std-beta-x86_64-unknown-uefi.tar.xz=3b4e67edf9785c0eff0fd83e357fbd4c0840620d1b7380ba5d270729f751e4b1 -dist/2025-02-08/cargo-beta-aarch64-apple-darwin.tar.gz=f197e428af3ea3d409a43b54372c9f0f7f8f70ef8d048e066b5c609364211e35 -dist/2025-02-08/cargo-beta-aarch64-apple-darwin.tar.xz=e84b8ec6f87512fbf31c823703b94ebee8531675430224331845158b8997121f -dist/2025-02-08/cargo-beta-aarch64-pc-windows-msvc.tar.gz=16b73927483117d158a3f3aa36d9cd14d74dce707071345fab9e6c359b68665b -dist/2025-02-08/cargo-beta-aarch64-pc-windows-msvc.tar.xz=3fb1381b750a1ccf386602394af21130e9cc6384b962bd008ffb2e11bcac4c1b -dist/2025-02-08/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=2b0d90694987ee10a0f0e5b40c1f95c65c9bbeae6c921556b85067a1920f5988 -dist/2025-02-08/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=b47667e97225ce7542c6e9a137adbc7c002ee1e4b1e0c1255b5dcb87743d886f -dist/2025-02-08/cargo-beta-aarch64-unknown-linux-musl.tar.gz=843bea38aaeaf6629060a046e6654fde6f4a73221a996e56ea9a1f35466cc6cb -dist/2025-02-08/cargo-beta-aarch64-unknown-linux-musl.tar.xz=147827cb32d5ff3628f347800a9202eb0b3caaa142d363dffde94bc6bf821352 -dist/2025-02-08/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=0dd6585f3e93a60d4084a4f7f6c58748e82c03ea38fee164828d3911d024459b -dist/2025-02-08/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=2e8240d79a86de26e7782265bd6551c6357a025b7084a3ba88161c84e2fee54b -dist/2025-02-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=323095df9d5c9f47463c5b05729960ee0db5f910619050ed548adb2b8c59fc35 -dist/2025-02-08/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=8f5be63da1f8e9a7d90116c9793e03021855dde170a356002f306180d4ba7ff7 -dist/2025-02-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=63dfca05df7a8d14c27070ce882a96defa2e5c3134fe17e848273694b42b3c88 -dist/2025-02-08/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=3881f42ce8e69953804cb0c566fe08f44ab8763cefe8c0d6a4461645dd44f518 -dist/2025-02-08/cargo-beta-i686-pc-windows-gnu.tar.gz=70aabf19aa3db89599131fc09fc005a9c8c0974d3f04267df0e41007f5bc46d7 -dist/2025-02-08/cargo-beta-i686-pc-windows-gnu.tar.xz=c57bfddc9285dd7c1151c3bfbde4f92da394fe6c8d0239c1f9ee8eceeb15e29c -dist/2025-02-08/cargo-beta-i686-pc-windows-msvc.tar.gz=056e750115574ab4e008d76d1bda67aa30f3818a9f46cc88d7ad13bb4238d772 -dist/2025-02-08/cargo-beta-i686-pc-windows-msvc.tar.xz=663a9ec0ba07807ce289bd61c66e196262e991046da44dd583fdc1414759f5e8 -dist/2025-02-08/cargo-beta-i686-unknown-linux-gnu.tar.gz=95dee9910674196f2bf655e91a8443be5b46e36747bf1e980e1585fa3789375b -dist/2025-02-08/cargo-beta-i686-unknown-linux-gnu.tar.xz=09af49a00e181084e7f766c9008c2d3446ff1cb801780feb79d0b7cc31a038b6 -dist/2025-02-08/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=ab1ac3686ed7b3b50ace61efe20ea6848370de691cf0f287337113d7ca52c61b -dist/2025-02-08/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=bee237e641da0d804f2002d33910bfb199127c5006af39dd06d877ca5fd1ff82 -dist/2025-02-08/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=9beb2a39f1ef7630f03ed1da5e1e68964a4b198fe7f18d0db9efb4f10d70b35f -dist/2025-02-08/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=f1528e4aec2095d55b98e3421d2310f3aa3fcf7c2493f83e75d3cbc80e18f923 -dist/2025-02-08/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=2ee460d198339449e85ff8c7e522c47f33677e90f8b215c0a13514fe5f05cdb1 -dist/2025-02-08/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=4a9fc5e31abfe582b580e395ada8d59a1aecf65b07b09b8ce526a84fdf61830b -dist/2025-02-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=9e471ec06debbe078b8c92773a1c4380969e92dbbd9f20884986b2cc7e942106 -dist/2025-02-08/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=1cc6e9e448f036af3bd6f8e597ee242edc65811835e20545e84ab917744b50ca -dist/2025-02-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=08fb88ea0a4d904b28ef7a51275ccfd1f8480f1d33c7a5a83461d322143e81be -dist/2025-02-08/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=0809a5f718157763bbf67e8c3a3b9b868a6694bd88b87277b542fc3207c1f1d7 -dist/2025-02-08/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=dcbf18b645016eee37a23dce4126d0ad61f8886e8997b480609e8f8fffe0191a -dist/2025-02-08/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=f4f9350ec459016cc0fe54414d75fee119b0051e3ae1b839971ec5b569be97ce -dist/2025-02-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=dbeee82ff5cec6c16ba873b40f986e85b55f831efbd4d09d0107b2e66037db87 -dist/2025-02-08/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=2974493a708fd5c793b9f1920a11b66aa5ad6aaffecb0b9c597416b7200e411a -dist/2025-02-08/cargo-beta-s390x-unknown-linux-gnu.tar.gz=ca157ff6dac3d680f63c99fc2efbc30376eb6ae54682f40369c4d2aa8647b77c -dist/2025-02-08/cargo-beta-s390x-unknown-linux-gnu.tar.xz=ea5ebe153fbe3d1fdf514ebc050f46776b075268aaf7e7e3ef308f13d0ad545f -dist/2025-02-08/cargo-beta-x86_64-apple-darwin.tar.gz=dd19dc295a1c430a52c223478a01610b359e2e0b40abce7111c9a02a51d4d313 -dist/2025-02-08/cargo-beta-x86_64-apple-darwin.tar.xz=f729d46cb4ca8945657671d5d0c0a55792a2ac9f5ea21b3e2991843004fc23ae -dist/2025-02-08/cargo-beta-x86_64-pc-windows-gnu.tar.gz=9a7dbfaaafd177a725aef60ec6c4fe3c5b732bcbd69a2e25a91ad7461a76ef4c -dist/2025-02-08/cargo-beta-x86_64-pc-windows-gnu.tar.xz=ef585bc9e5f23368fbb960959f80fd34961909e62cd65bb847db06a7178b174a -dist/2025-02-08/cargo-beta-x86_64-pc-windows-msvc.tar.gz=5e396a15cc63f084467d9afcb30cb374c070856b0aa3fcf209d88bcccfc6436b -dist/2025-02-08/cargo-beta-x86_64-pc-windows-msvc.tar.xz=78cdbf2cf0d7fec4d24308853e96a39bf5c417905abfcad34de4d1b2d498a617 -dist/2025-02-08/cargo-beta-x86_64-unknown-freebsd.tar.gz=1e485ce036055c7b3e1949d9e34e7d3dca436438b3f09bd75d36e49217d53d44 -dist/2025-02-08/cargo-beta-x86_64-unknown-freebsd.tar.xz=80c5d0d5860eebbb807a2e5cf8ccba8ed4461f932825439ec8182f6f0c8939c4 -dist/2025-02-08/cargo-beta-x86_64-unknown-illumos.tar.gz=5681331e1d29b476c4f458fee453f73efc86856caf1d30c49df9dec3e147f4b1 -dist/2025-02-08/cargo-beta-x86_64-unknown-illumos.tar.xz=9f7d97045851bb1ab334761cddb38cd8bf3bb0b26f2fca4903c09301c70fbca4 -dist/2025-02-08/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=24bda5749883e133ac58ddcfdbd8dbeeb660c3b33d613852dd1d993cc13f6e8f -dist/2025-02-08/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=2304e5cde3efdb5c6e7319d8239bca7d1c69306846cc3eba84d70d49b8c24e51 -dist/2025-02-08/cargo-beta-x86_64-unknown-linux-musl.tar.gz=825a42ae4bab8be081c7320f06fc7ce6d0c0c31f2224fb0c13af4d01e04c3626 -dist/2025-02-08/cargo-beta-x86_64-unknown-linux-musl.tar.xz=656d148e383896d06483297d785d62c8e235020081acb4110a8bf698a3d6d6e5 -dist/2025-02-08/cargo-beta-x86_64-unknown-netbsd.tar.gz=1e6a750acd6c1f44e37b3d1b1dceef7e8a0d2b0806e1577b667573a6340e7cf9 -dist/2025-02-08/cargo-beta-x86_64-unknown-netbsd.tar.xz=c45bd23fd1004cea41f133a40bd102e55e9f7ed29c9e8cec83dcacc4653da7c7 -dist/2025-02-08/clippy-beta-aarch64-apple-darwin.tar.gz=cd22d4191ca0fb9d8ec3d627805f297ca4528018e34c4f627e7e4fc05d6b0954 -dist/2025-02-08/clippy-beta-aarch64-apple-darwin.tar.xz=0c408799a742b00dce013553a597e62d8f84232ede6883632dade6b3d024904f -dist/2025-02-08/clippy-beta-aarch64-pc-windows-msvc.tar.gz=b4d902d9a096cdc6eb655ae2a0960db6fe4b83ccb681cc5bb5124dcfc5e1fdc0 -dist/2025-02-08/clippy-beta-aarch64-pc-windows-msvc.tar.xz=9e2514d7f304e3253e7205cec8189b8f9b1d49da5b14b2c03e69b8bb0223a65c -dist/2025-02-08/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=1496cc4bbd0edc18ce05bc2ca76d9ed78934f1d1c4749ff830dff7d1acc2535f -dist/2025-02-08/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=4577dce94261cdf07064f43404ade755a8906ed0b1a39a148333d9309e011916 -dist/2025-02-08/clippy-beta-aarch64-unknown-linux-musl.tar.gz=d28217818fb6c1a13456684bfdbf9caa687dcc257fadffcde2d2fd94dfbb228a -dist/2025-02-08/clippy-beta-aarch64-unknown-linux-musl.tar.xz=bae2f1841776e321f5f950678516bb31c05dea8f825fda23f3a3cd423dc00249 -dist/2025-02-08/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=e1698a07ab47d02954bdb67034de33a8414731e3d12a8937cdea97004d98e45f -dist/2025-02-08/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=631499b2ee136c428f1c6045eb6aefee3e6c765dec1baeb0c3e4da056d540d71 -dist/2025-02-08/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=248a15737924d07afee2108e6545cb4bd5cce91878dedb5368c358c16a0b016d -dist/2025-02-08/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=6581c968d48e37baf99addf17baf8b4fdda1417c201da311959c62a51783209a -dist/2025-02-08/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=8ff9d93ea49d805ffd3534c6aa03692fa7dc8bf0460bba7c22259257dae863d1 -dist/2025-02-08/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=b267e928b9708cc168d84c005036d155547274e8fe03f23b14232609b780d219 -dist/2025-02-08/clippy-beta-i686-pc-windows-gnu.tar.gz=957e8d14451557ce11de7303be61a50c68af7b90293a46e48c9a1bb3db05d154 -dist/2025-02-08/clippy-beta-i686-pc-windows-gnu.tar.xz=576732c661cd0998f7b47e99fe84c3dbcb919e787e3222e1c27b5377361083aa -dist/2025-02-08/clippy-beta-i686-pc-windows-msvc.tar.gz=5a4ea7d3fd79823b2342ec9069e865000dc5ab58be0fcf3655bcb161cb195858 -dist/2025-02-08/clippy-beta-i686-pc-windows-msvc.tar.xz=fbe4f93a9f1ab718a5dd3995ce67b7b0768f7f211f8fc3f1e6b181c4e4f1f467 -dist/2025-02-08/clippy-beta-i686-unknown-linux-gnu.tar.gz=0c013dba1ac3db5ec21e672f357c6a86c379c29f7cac0d43df4857e0332abe22 -dist/2025-02-08/clippy-beta-i686-unknown-linux-gnu.tar.xz=0e585010d88a8f04f9e031fcef623a12da7f82ed9f0d827157b10f6be80eb920 -dist/2025-02-08/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=2716e252361ac72dfebc8521b3f2c0edaa6e0a0bb0b9a3ea3b9b888a5d747104 -dist/2025-02-08/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=3d400fda76fbc8a830e12f5f71e40d4993019e9e53d58434ca23e3d8761d530f -dist/2025-02-08/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=8d7cd64c2ec8ee5f25bbd6aa01ba22001a4ab2eae6ca481583f736a1da07dc31 -dist/2025-02-08/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=f60bca644d441e36e537e896d4b122ca0f8cde0fbd886f12c3a312efd5225997 -dist/2025-02-08/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=a3fc359554026ae39c7cc46c53c6928de0522387ad2327444745eefd0fdcc43b -dist/2025-02-08/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=8344b79f4a2a61cf68e526c144bbe797f1c60dec047845fc731f4c47a58b7be6 -dist/2025-02-08/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=05c2cd6e95a7c8ef36703b9bc39cedb8e5eb5b3c93a66a16deef2e18e96be489 -dist/2025-02-08/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=2a0c36d392c3b69fc437c8ab8358f87c6c50380e8c5ced6690c9a7d0be9c95e8 -dist/2025-02-08/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=c9c6975ec5ef1e206a917d03841db90e1f4a3562b0afec32a4753134752454d3 -dist/2025-02-08/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=efe920b25316d84c08693f28d0593d227ca18456be2dd9b426c8cbf49d81a352 -dist/2025-02-08/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=b133cb9709d11da1710b3b833a3e15d3fc216cacfd37e6e1c7c8fe1dbc202067 -dist/2025-02-08/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=7db8db7300b87bc7841ef59111c8f83fc6e6ffedbb6dd8fbb79431edb821e017 -dist/2025-02-08/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=2fea1f879ca90478a2fb75566da4cbed2f2afec31af6d18160fe183772241658 -dist/2025-02-08/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=668ef736714909588cae0bc77c30c3063d2911b0e1c28fc77678081099d38a83 -dist/2025-02-08/clippy-beta-s390x-unknown-linux-gnu.tar.gz=a05eb2ea42fc2ed7df974610b076adae42ec456bb80eaf9191521dda5c0cf12b -dist/2025-02-08/clippy-beta-s390x-unknown-linux-gnu.tar.xz=5874e0cfa3b7f7c3b8d9d0c84a519b98908b6228fcd9f29d971b9c36d639a998 -dist/2025-02-08/clippy-beta-x86_64-apple-darwin.tar.gz=e259a0e7776430f1697153505f937c92e942fb5c436c00dd9da3b160ef9a7856 -dist/2025-02-08/clippy-beta-x86_64-apple-darwin.tar.xz=a311ec69770a431837a26e63591dba11dedbad411b688ee69e457bb7a4596c50 -dist/2025-02-08/clippy-beta-x86_64-pc-windows-gnu.tar.gz=2b8278419633f83ca22e2d1c54a170e04775d903076935ce13e91575d6122715 -dist/2025-02-08/clippy-beta-x86_64-pc-windows-gnu.tar.xz=13190a1e83debb9483abc7b0e4e3a4b8d53895542ffa56ebc012dbd72b8e7637 -dist/2025-02-08/clippy-beta-x86_64-pc-windows-msvc.tar.gz=9c8c8de0bd646bb0284e47b6adc1db6443d9da7c06ed6d237c421339a446fd83 -dist/2025-02-08/clippy-beta-x86_64-pc-windows-msvc.tar.xz=32dbce4ca3f3abf6da249e33297efea856b3b0ff39b3571531d71e1d0f90a46c -dist/2025-02-08/clippy-beta-x86_64-unknown-freebsd.tar.gz=55b22726920214e2ca9c4e552b50401fb3eef872c63de554623aaeebf9e11e75 -dist/2025-02-08/clippy-beta-x86_64-unknown-freebsd.tar.xz=b67e699d65462020333c037f206287e609f35e448cffeed6ecaec6874ccb2233 -dist/2025-02-08/clippy-beta-x86_64-unknown-illumos.tar.gz=6bf570aa87c05050e5dffcc191db07b1b0abf18bce160637a1be39e5caa130e6 -dist/2025-02-08/clippy-beta-x86_64-unknown-illumos.tar.xz=52ae7e8906f27c020df67beae61c1c1faf6458a0ccb3e904b909841b2b504d89 -dist/2025-02-08/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=fadc4ff0f2acc6d44a5a29d01101152c8570dcca69ea4fd60e8ca6cc2cfac1e9 -dist/2025-02-08/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=fd8472509ffdb81ff5ce786784274f654eb213ce963caf6e5cb90baa9e641c3b -dist/2025-02-08/clippy-beta-x86_64-unknown-linux-musl.tar.gz=c94e847aae4aa7a04981a4be424cdb2a1eae81a808858a5fc14a20134b7575e3 -dist/2025-02-08/clippy-beta-x86_64-unknown-linux-musl.tar.xz=b1f2a240069cda55c7c49afda6137822d7aee855557cf7269ac4f440d54a0ca9 -dist/2025-02-08/clippy-beta-x86_64-unknown-netbsd.tar.gz=86ada6c1406ff381a81624da25e65f415380da01252e6016bffe50ef7ca5b49d -dist/2025-02-08/clippy-beta-x86_64-unknown-netbsd.tar.xz=2b24a66215cd93b84065cd35d00bb3e7c9482b118eaeaf089bb2a128450add88 -dist/2025-02-08/rustfmt-nightly-aarch64-apple-darwin.tar.gz=0e6740aa70ccffed1e2649619990b75586638b8eb34747aab58ba4cccfb09f29 -dist/2025-02-08/rustfmt-nightly-aarch64-apple-darwin.tar.xz=c5c166763202c35bb7844f0866f05cfb7e2666fe9416776a092372362e7bd8e3 -dist/2025-02-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=cf025264c087d9339787db6f8cd4c76aaa9c3118b7875de7413dc1894b660fcd -dist/2025-02-08/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=f788a44b9542ddda3a88e3000c31644e1b9ee874ce523798b6638f7f181b8df0 -dist/2025-02-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=0a7d236cd45ef4f3f12e4516b202cf9b5190e70a19044c8b17c5eef16c45032e -dist/2025-02-08/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=80cf271c8adc2192b212d1b40992d90aa21fcc695375774c17a4f70468c82c11 -dist/2025-02-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=58d0eef426f8f0c4bf191118161db008db378ee3e77d973d7e15e39e88c3f7ea -dist/2025-02-08/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=7eedaef7100f7272f38fbc3cc14a1f4fee7deddd31a59f7db71c2a6f2f03f946 -dist/2025-02-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=df5190ea7d9bb84d5ffdda74cec7591388d3501c2a4084c667e0f29ca0a0ba9d -dist/2025-02-08/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=96334a22d0534adc8521b6a000f422f1727f80235303137eac32f4e76e85194b -dist/2025-02-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=2944da8dab479b4892f512711ed6bb3b242602ab11c81c6b22352a467c898165 -dist/2025-02-08/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=5aa59c9ded50503a2f05d5330ef41ae888254887559b31c4304422aa4ba9e73f -dist/2025-02-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=bf17c1d62ae3f59b595c6536add64453d5584135e1d238bae55216c428416767 -dist/2025-02-08/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=c60925816b01596b846e56efa7cd0e186391e212da077b36d781b926799704ad -dist/2025-02-08/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=5c73dce13f7e0ad408f39f49ae647b0fbda00416027ba43228a443f311b33fb1 -dist/2025-02-08/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=df005321b30d82854f97a3e68a702c64ded7f4cde18edc69c3b1d7c8927b53e0 -dist/2025-02-08/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=2483fe75cd360607f29fc5f7cfc6d55074047291544f398946b5c263eef6b164 -dist/2025-02-08/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=f2553f96bb513e999597c89d0655bf1b28a338d6510f9a146b3e47674c83c550 -dist/2025-02-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=9cbc32383a8b6025ab9b7d75bf95b831cba32826f2732597cc3749b1a44278d6 -dist/2025-02-08/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=07f16dcf8340feaa8ac400eb54833017d501f78f11f699c095febec148f35aef -dist/2025-02-08/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=03f7b562d15fb47e8e3ad244b127ed170c6296fbf5bf822fddd51eb5ab2a4f1d -dist/2025-02-08/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=834186eb75bff0e05f1a7d9ea63382c7b96a18519aa6815060554b06f3d7b90e -dist/2025-02-08/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=45c7db895ae3751fe07dc7483d0c1ae6dae989ec0b3507eabdfaaf9b1f24af04 -dist/2025-02-08/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=8aef8265279fca165e1627639d64c1f980877744cbd8a927c6c6f3f1e9ef2fd8 -dist/2025-02-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=4f85245ee5c997a7d821ea3c397c5bc7315c8cb07605f2b5a4746f254ef567aa -dist/2025-02-08/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=ec1326a520eb4bac792bce1e260b261e3cd638c123dc2da962bf2f25bf3a89a6 -dist/2025-02-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=dd473534cd897998f6dd361f18a61ea12ed38bbb323c3d602b3124e832ce37fb -dist/2025-02-08/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=a3523178a5186ebd3847b1b0fbdf91f300b29f780fc7910fa867ccddaecbab73 -dist/2025-02-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=625777f6ccf6ede941a88252bea183f8f285f6d282f95a78153e5d45e63edaad -dist/2025-02-08/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=7c57c7c0163c74beaa80378974cfbe222f70057e44a025e042989f3816cf02e0 -dist/2025-02-08/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=b431d8683230d783641bbacf7fee8102ecccf527485e8a753781b49906cdfb56 -dist/2025-02-08/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=637801af10b564fa8b2bc8b3075b3fc26efd69237702bdd95b60f6d55e7a92ea -dist/2025-02-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=2532bededd1512c36f97ad91d065ccf681b4df47db86dc382635cbd55e6f1aaa -dist/2025-02-08/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=16eb4fcdc66b86d45af649905b33eb1a9cb9a859eaf4becae10b443a747b790f -dist/2025-02-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=2c29615e4de5f4f9aac64102afee2f7775e961037c2b044ff5ea4690564a0af5 -dist/2025-02-08/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=0f88b8da8d50b7bc1fef09a53c5cedb79d24b3a63b8ab8cc6960285acb7fde7a -dist/2025-02-08/rustfmt-nightly-x86_64-apple-darwin.tar.gz=f46c2a065cf61ba644062b20efbbd6cfd0dcba5b15bc8f333c35e32dd4640e03 -dist/2025-02-08/rustfmt-nightly-x86_64-apple-darwin.tar.xz=9bd81b4ec3625d959f96d7b6b17d6c548673c10f7246b712f99fe40e8dcb4844 -dist/2025-02-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=2d37451b9314b525d41817c432e3bff5e90028cb020f0331f39490975376bf82 -dist/2025-02-08/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=e8ad4c33272708ba094a2a14e1a69d9071345351921b357ebd0df7d32ccfdcd3 -dist/2025-02-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=1d8e24202a8b2111b78531e5313446c6d2e3be083aef77cbd95c09b909b7c49b -dist/2025-02-08/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=9217ed18bb34379079aa529e3ef2fcc899db75780db942b1b6a45cb8f9b317eb -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=f82fdf61057bae8a38daa767f72c74efefaa6043ef48229bed9d8a86787387be -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=60857a9f3518fa6e1a0b8f17a0391672af55bf37bf5fc965b18079060086f946 -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=67384f76d40cb80dc79bf0221a4c021e33f11f283e793404421bd5391d75f0af -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=e1238f9c47666b623feca48243e88ad40ba70d3d762e5e0326dd29eef41f8c83 -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=cdf48fd39c450219ecbc0801aab198c74e31e543b663030bcff9d6df8829f7b0 -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=a5a461c01b8709335c7e2dfef9378ee49aee5f9491f4bf6173142ab87bee3d31 -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=d9881dac0e6d10758cc5e28d3c63be557d596336685b5d095cb77f69853ad978 -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=beec700c0c6829c8975abbd26f7330a3ddc21040a8f2d531f1991f99ac11363f -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=188004d4990d1ca6f8fa7b00dfab510b0cbe840fda4e7318942bc2664c03588a -dist/2025-02-08/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=ff25e65591a638072362122059d71888ddef0b9b81f0b0d7b2fc285fe82192f9 -dist/2025-02-08/rustc-nightly-aarch64-apple-darwin.tar.gz=c97c0921c6749ab5eebb2fcc65cc7fc98af43d1504fa1cf4ef360e299c74fdde -dist/2025-02-08/rustc-nightly-aarch64-apple-darwin.tar.xz=51e12e1a1bb60b65145a5742899f0ba3c60840c60962c424351dd337de7b2906 -dist/2025-02-08/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=469e68dc2e1546ca27117cb3d282a77bd783e84c351d911a2e45c91916fc5944 -dist/2025-02-08/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=ca16024d975f6c4835d53a47cc12e728380ed9e9126f4f523854b5c8af148499 -dist/2025-02-08/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=75e9f08ced58ed868a1c5e727b632c1ea9ed8f483cadc68d30d7394ab3f60215 -dist/2025-02-08/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=c5d3906481bed31bfa563f216e8c17e8be971cf64d0a5d66820025900aa82893 -dist/2025-02-08/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=a6dab5d9fd0ddb5fd83f5332e3608df71b62891c1bc02f73479cf0aa344c4d1a -dist/2025-02-08/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=9b4412cb694f46774b5642b972b0c149b5ba8d4081069cf078ee83e7f7ab1c45 -dist/2025-02-08/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=cda11234e3e2370fb2a9ae7d4f50a7c44c646c5ea9dee4d4a576383785ae993d -dist/2025-02-08/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=bd6cece56d6559ae261d5494af10d665bb7293f439287f1d190cd959c598ab15 -dist/2025-02-08/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=c29c0ace7fe5b160e9399813848e70865d4eb90536169d9c6089a90b74e4e0b7 -dist/2025-02-08/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=bea382931c0b9804ab6ea0f3666679493c1c4390a2f732ad367b6540d4279614 -dist/2025-02-08/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=c83086892fb1ce1b4ca0c778e9efe57334bd18d74a961fccca78125d58f185b0 -dist/2025-02-08/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=30ac3e64449a919ccb70dd30350086bcd5e8f4d12e0da6851f685fb60cdb871b -dist/2025-02-08/rustc-nightly-i686-pc-windows-gnu.tar.gz=f51df0f5c9a8a89fabfb347f1164000a99485bd85dd67ca7bc84e2a48f9c80e6 -dist/2025-02-08/rustc-nightly-i686-pc-windows-gnu.tar.xz=153a564d7930f3c217b25f8573f79b279af82b8ea5ad7ccf09f8c127d4cb6c33 -dist/2025-02-08/rustc-nightly-i686-pc-windows-msvc.tar.gz=2d9c05cb1d60804cfca6076f231ac03081d3b2072cdb87e5f1d9f036325a17a1 -dist/2025-02-08/rustc-nightly-i686-pc-windows-msvc.tar.xz=fbb95c6c97a5e4389b761a1ba712f111f808113ef30abbbf0e95bedc5344708a -dist/2025-02-08/rustc-nightly-i686-unknown-linux-gnu.tar.gz=df09eea18c7be163abd768ede37cfdec306563d0b33219ae040d8f9eef263154 -dist/2025-02-08/rustc-nightly-i686-unknown-linux-gnu.tar.xz=3ba7cab1234713f4fffade6344b62fc6b89d264e3b8b993799e5e0051d869e08 -dist/2025-02-08/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=ae94de4d5bcd8c265fb0297078d446fd84bb5ca7f9e61f87e956330d2c439ccd -dist/2025-02-08/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=be81df065f92bd25825af0935b3188418c97e377ed7ce05ae287f576ff2eec9c -dist/2025-02-08/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=96ccf45347235ac893cb61aa0d61aedcc46ae7c93d26f3ad964a73ddd1c274f9 -dist/2025-02-08/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=1e19c00ef298e5cd1334aa60df8873c0925304bb2a996d0ca590d363443f2f20 -dist/2025-02-08/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=3e44c93e6be85dfcd8031fce279b1d1604859d149a979d91144272ed4da920fd -dist/2025-02-08/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=c3651fdbfec98c155159d799a895917c0df3599dcda71a79bdcedee3c9cb616d -dist/2025-02-08/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=4875368f83906c9f447657ed70b0d53ae75ff563e6bd9b75110defbaf44ba134 -dist/2025-02-08/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=069716dd18791fea69df0b97627bba5fc83ee466883080ef934f4cb6b6342ee7 -dist/2025-02-08/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=0aa826fe16a9245091b84972be39aae113f62c1a254b82ec91df81a2c2c2da82 -dist/2025-02-08/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=2324bf8323d784cd37ca9546295e252a0327e25386ba406409e5c4172412d356 -dist/2025-02-08/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=2b5debffe5fd870828cf54365b21b1cb989bc5223b76a911299208c5ec105c2c -dist/2025-02-08/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=34342b7ac92698d15b53afa13897fa37401e33b591e2a9ebb00ea17bf2ad7741 -dist/2025-02-08/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=e189c8be0a75ebc0c65e1b467476c510415231c5bb67d742719b39c425ee98a6 -dist/2025-02-08/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=2407a0e42ff8280a16e944f430d2724bed6765295a64a53f463e341d35f9fb0b -dist/2025-02-08/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=ffbaaee6cb11d1cbed985601a58fa5e9d796161b0435b9a8ef547148f042200a -dist/2025-02-08/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=3c6dcdea50189f815b16033dfc8524687d7101eafb266be8f16681fcf348dbd5 -dist/2025-02-08/rustc-nightly-x86_64-apple-darwin.tar.gz=43b2f1b7d16b46419d8fcede2b5b354ab778a1f2c3f59e691b71db8cfa00d727 -dist/2025-02-08/rustc-nightly-x86_64-apple-darwin.tar.xz=6f18083854625d41b5ace4aa8b33f9c1aadfba764a6cb8ce1d5986f745ddfe3c -dist/2025-02-08/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=eba376122f9f9439aa2f6f08a08d496e07fd3e5ac99c82a69eab279e44755b8f -dist/2025-02-08/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=e5b67e358ae1068482f6e09cdacb6f212b6b6c5e87056909b54182d21c6ba5bb -dist/2025-02-08/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=310f2fc7bf1d32926d78e264638d2795718a1406209238c8c18ba76680c58fca -dist/2025-02-08/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=f8915c772b352fd7f25a7f1be36c94f7b383b813d9dae139831c9f7f2b960de8 -dist/2025-02-08/rustc-nightly-x86_64-unknown-freebsd.tar.gz=05bd6715082b006f6d43c369f37c262732e4bb1c44cabe50a201ceb8556ce651 -dist/2025-02-08/rustc-nightly-x86_64-unknown-freebsd.tar.xz=d03c251f78273d4a3de99e650634d30287c4868031ddd3cc929cef8d7cb5d215 -dist/2025-02-08/rustc-nightly-x86_64-unknown-illumos.tar.gz=16804058f8c88358ae2ab0a8302acb092c27a459ca7217d30fde504746be14f9 -dist/2025-02-08/rustc-nightly-x86_64-unknown-illumos.tar.xz=b76535703edb204daf577e42b0a1ae2a41bfa18e0e3205fb5773e7ec12ec9fc7 -dist/2025-02-08/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=5a63f9f4ee7c5a91252ae8b235780ed6349641c9b6593e9038021c3a3927374d -dist/2025-02-08/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=0a53b3706ab2981fadb020362dd497917f8361cc778a11d9a7fa05a3b329eea2 -dist/2025-02-08/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=ab4e3c5a4eaabf0f227b160efcf2f8d0e9a572d079ece83c6313fca9865a5dc3 -dist/2025-02-08/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=dcd74640d883aa75df93b86b041f98ef99178d5f39e78de3ff6801077703da32 -dist/2025-02-08/rustc-nightly-x86_64-unknown-netbsd.tar.gz=cdb3d9ac0651e3d44dbb50b3e341e609e228cbc4c358b126547a2909b807901a -dist/2025-02-08/rustc-nightly-x86_64-unknown-netbsd.tar.xz=f4227393819e678dd67c579fc00b52fc1a3974e270f10593d8b550f7362b5a63 \ No newline at end of file +dist/2025-02-18/rustc-beta-aarch64-apple-darwin.tar.gz=1b51ca064350d8b15c7ab6c8ec996a497e912dc237cafc2c205066fc6416e0ff +dist/2025-02-18/rustc-beta-aarch64-apple-darwin.tar.xz=e4b71f6456d9e62ada6909254606da7f6681f3da0f5bc7d2c3d5c387fea35743 +dist/2025-02-18/rustc-beta-aarch64-pc-windows-msvc.tar.gz=1ff70a5bd238d959d806c3b471a5b03c6cde784944a96a585e0ae0837d2a9c92 +dist/2025-02-18/rustc-beta-aarch64-pc-windows-msvc.tar.xz=5017b351bb90a08041757eae61386b224ec0161c5734293184a87d8903f30098 +dist/2025-02-18/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=8a58b6cc4577615efc76bb9472229098d6f938c1f051ea540409e9dc812dbd8f +dist/2025-02-18/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=330e217dbd1c507c8706aef5fbd0baf9584495445743f38668cdc962adfb125e +dist/2025-02-18/rustc-beta-aarch64-unknown-linux-musl.tar.gz=4060ec54281975880a9819b815120d6a450e4c31ddf1136ecce348e28875d50d +dist/2025-02-18/rustc-beta-aarch64-unknown-linux-musl.tar.xz=0f92b9267a55ac0c764cde63b8cbc8a0a317f7e0817185d380fc2aa35a933687 +dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=4e989e00725e7cfb08ea834c74ec6dd352eda74c13218f7da423ed598af9f9df +dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=b06181daf8842c2e544e5d54169f9bbfc70ee76115495de033ac4e341617a588 +dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=93fe2efcde1032ad636ef509a73168f0ab7fadbca699a27e2882b3832539e8fa +dist/2025-02-18/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=b49d0256381c928785035578e5b7624c37ba732ea7aefca37dbb66b5162c8090 +dist/2025-02-18/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=56fd36c20d78085f39f0df40f15f7694e8744714104539865b9c3d7b06d47e2f +dist/2025-02-18/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=86587bea60c2b8a114ab33fe65a7152fcf8e1dcca14550712dca72af9fd65674 +dist/2025-02-18/rustc-beta-i686-pc-windows-gnu.tar.gz=32c95c78b223efea2ee8e02fbe3a58ac753ce9284e792bc87feaa051fcff5687 +dist/2025-02-18/rustc-beta-i686-pc-windows-gnu.tar.xz=d2e623f11aee7e81eceb6947e3f7150bfd727eb2f527e4abc6b10d3322959802 +dist/2025-02-18/rustc-beta-i686-pc-windows-msvc.tar.gz=f7ffd07eb2b5e83df513c6a313e28003e3ce923778583e78da9efbb5e62405dc +dist/2025-02-18/rustc-beta-i686-pc-windows-msvc.tar.xz=cd2e61b548a6849b17183fcacb2ac8f94955d893be439793580c39080feb28be +dist/2025-02-18/rustc-beta-i686-unknown-linux-gnu.tar.gz=fedeca202c1651fe4b15cfc411365ecf016376b3cc7c772d2e0d739e0ec02dc6 +dist/2025-02-18/rustc-beta-i686-unknown-linux-gnu.tar.xz=6389f10e2328bdfa81ef1f34406bb4ec8bcb6dcf64d39c95946d32c9fee7f0b7 +dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=21b565bbaacc2be5d066c5d0c49b7c0f5b0bd24690ca35e9c88e6ec91846f744 +dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=4a728e3ec41834775f0b288cdca5ae152314edcaf20d7ea46ea62fab1b9ef327 +dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-musl.tar.gz=0a72f650aa70708f9a72886ea33b7a2e3ffe2a6e2cbcb1d2248f3d9eca74a9d4 +dist/2025-02-18/rustc-beta-loongarch64-unknown-linux-musl.tar.xz=877c3c447f4c25068f70bd7d6dd5078d75b0c194777b2f8a9311a66fc6eda701 +dist/2025-02-18/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=67af5e05ab0a367d3f76c0656823b530a23fb26d9c86db2b433684b9191b8881 +dist/2025-02-18/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=2da086d39eaa000ba629ee15bec740db57039ca3e5c7c55feb9cb9ca6d39c785 +dist/2025-02-18/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=b079df9a3e5be95a755d22f5ecf3ddeb43f94d96eaa3985770ae98ad0e7e15bb +dist/2025-02-18/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=916fe3b67094bb351320371de9587f01bb65f9b9aed2c7aff7930e499822b660 +dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=356e3173c960aadfb91dcb607a26647895fb1ae11a7cb596b019c71c6dd808e7 +dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=9115c4c85d8c4b5254df41a5d3f55733648ba282711e18a692ee100ed13fb550 +dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-musl.tar.gz=b8a267f9ca2d23385c529924782f633b6b9f66b50cda5986eff91c223d715307 +dist/2025-02-18/rustc-beta-powerpc64le-unknown-linux-musl.tar.xz=84e65fc1d4282d737b6d0b1aaa1c2abd395af215983eb5b3700e925ca6ba3bc3 +dist/2025-02-18/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=19b1d8618edb5d3a6cf620c814f6b76a462bc965f4aac2cde7aca5849b92cac9 +dist/2025-02-18/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=9914408b5590fe7c43b2aa10c261bb5162b024e396c625b06546564a5eaddb89 +dist/2025-02-18/rustc-beta-s390x-unknown-linux-gnu.tar.gz=37ac73ea85f43a4859d8c4526cb9480e69bcaa778e842128852c8b21c6db6b45 +dist/2025-02-18/rustc-beta-s390x-unknown-linux-gnu.tar.xz=af1cab661b26cab1ade53f12ec08d13d60a74c2f370d9d3617154e0f01cb3719 +dist/2025-02-18/rustc-beta-x86_64-apple-darwin.tar.gz=aa9999ad56f8968e3e0f5417661ff42fbd1bd482a649d1a8c01d6ba5a6e78a72 +dist/2025-02-18/rustc-beta-x86_64-apple-darwin.tar.xz=bfd09bf8db9bbd7557df3f206207631cc4b10d59d0cf6b072e610646b5c7fa4a +dist/2025-02-18/rustc-beta-x86_64-pc-windows-gnu.tar.gz=dabab346a003a5b13265da6bab96fc703c34f728c852092bec4cf08d13daeadc +dist/2025-02-18/rustc-beta-x86_64-pc-windows-gnu.tar.xz=c2252dea69c8dcf6ba0213da8b05b8d9173676fb7448cde684da7b56d2c52577 +dist/2025-02-18/rustc-beta-x86_64-pc-windows-msvc.tar.gz=9ae9c3cb963872b2ef02650bcec15906e0b5e89cc6d3bee0aadfffcec7a1e6df +dist/2025-02-18/rustc-beta-x86_64-pc-windows-msvc.tar.xz=bcbf75c92e9afe6b25bbde275bd38c3cdeda6324baf5b8c99173ca5738760a7f +dist/2025-02-18/rustc-beta-x86_64-unknown-freebsd.tar.gz=5313d0780f6a9587e809da0f1ffc973721afad88a0ef8fb83005c383d79229d8 +dist/2025-02-18/rustc-beta-x86_64-unknown-freebsd.tar.xz=52ab3212d64b56a8da207fe976cbc8d266e962a61c742e6069137b10ff25c3c1 +dist/2025-02-18/rustc-beta-x86_64-unknown-illumos.tar.gz=527f839ddedc7bdff48527a276d3d7f64d475dd815b81c6664f1ce25668e0ce4 +dist/2025-02-18/rustc-beta-x86_64-unknown-illumos.tar.xz=3861d9928983a415cd44e5dc50a99af948fac392adfb6c2147b14fb98dd08890 +dist/2025-02-18/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=0054d14cf00b25cfbcb2a1560887c825f703223312ca9cdd0ad51076bf54a3cc +dist/2025-02-18/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=75a9d69d13e50bb22ec721f9c64d08282d76f285482b285bb61bacabeecd710c +dist/2025-02-18/rustc-beta-x86_64-unknown-linux-musl.tar.gz=305765ca6a413ea86360b970bd062a19f6bc52756551af43d74920fc2a021d95 +dist/2025-02-18/rustc-beta-x86_64-unknown-linux-musl.tar.xz=c7230b578a97fb234ac106c7333615074b9a7a8abc1422f149ad613c2af28134 +dist/2025-02-18/rustc-beta-x86_64-unknown-netbsd.tar.gz=881bd9b260b2c7838ea1b4de2cd6baf2ff4d317e0c159faba1a683c4c32ba267 +dist/2025-02-18/rustc-beta-x86_64-unknown-netbsd.tar.xz=0c4f2cc0bafbf8b41b257e851870b64d3b5fc112f02227f561c645dc439c96db +dist/2025-02-18/rust-std-beta-aarch64-apple-darwin.tar.gz=958434edfc07bf6d10da3d41f01d1511b28d1178423a78bff2f60cd10046dbca +dist/2025-02-18/rust-std-beta-aarch64-apple-darwin.tar.xz=80043af05fb96c497bce55063f2733e37f243f85084f9aa60ab504d7c15c5cce +dist/2025-02-18/rust-std-beta-aarch64-apple-ios.tar.gz=509aa8803b29ccbb97a1a8c12e2ca6b27310d5af313650c7afff45ab1843106a +dist/2025-02-18/rust-std-beta-aarch64-apple-ios.tar.xz=f0f05dafc9a3277b075023bb449675946706307f769590c065cb53ae615708d9 +dist/2025-02-18/rust-std-beta-aarch64-apple-ios-macabi.tar.gz=c37c0aee56c5858f91fb5aa60df28cc92649d4884d5edde57eb6690f494ba5f5 +dist/2025-02-18/rust-std-beta-aarch64-apple-ios-macabi.tar.xz=e5120697e4a118824fdebf6d2a644f8f338bb83e209303fc684095b8f6b4ab1c +dist/2025-02-18/rust-std-beta-aarch64-apple-ios-sim.tar.gz=d5b851917a3f57703378596828e92068c28e00fe0b02331891737c2fc697b5ff +dist/2025-02-18/rust-std-beta-aarch64-apple-ios-sim.tar.xz=ef33164320931007db65f4915b533e5078a7279a7a134fc80045751a5198834a +dist/2025-02-18/rust-std-beta-aarch64-linux-android.tar.gz=4b94607d7c09b4f0f85236fb2237f1859150e12745ee2020cb134db904c1e05b +dist/2025-02-18/rust-std-beta-aarch64-linux-android.tar.xz=3aa7807ef9da83e1a4deebe4a7085e4df1b60edd4e9f237870f827073100d09c +dist/2025-02-18/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=2d4c8a5a400c35443228087f8203f320253299a5018c1b92526f99023581c3e9 +dist/2025-02-18/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=df8741055b3d4f7eeedec9e0101a1c184a37ffb75b2d4474bfbca577300355f2 +dist/2025-02-18/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=8db9c07d4b68018cd3c67be1e7bc496078dfa8a6852a35c449db5ba19f6bf0df +dist/2025-02-18/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=f112e3d51013ceff37e8c05d80c3605b76ddec8e55474d55815b4860f96febc8 +dist/2025-02-18/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=2bb6d934225823c2dcdb86dca91dd8e488f69b238b283607f75abe9b5de46486 +dist/2025-02-18/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=99036fde94fe0cb3ab2d2f48cd9f9bbb4d2fa784f1bd21afaa71b032cd95b069 +dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=c49fee34a02f5d3fe4e03ed7da90e045f7967c3e2e8f7a30804f4da5d535225c +dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=88170a13f9448b9671d252f0315aed94b6324716230db7307061d4890cfda70a +dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=a5e7442d722f6742fd0436d3c7d75738bc6cbd936f3399190086a88ef311e34e +dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=5d07a95e3203ebe98eed1b271a2e6ae44bead53e7bda019a8d256c8553c21bd1 +dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=0af6b8fc7f46641d4de61ada9bc9ff01af7775d727121267177fa4c43cc9ed7b +dist/2025-02-18/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=fd68b34e7aba25d8a834c018febbde6c3de7d967e014a738681642f41ec61603 +dist/2025-02-18/rust-std-beta-aarch64-unknown-none.tar.gz=46025b0892498de8e311be7bd6df261065f80a70720cb9285062161a30af5d76 +dist/2025-02-18/rust-std-beta-aarch64-unknown-none.tar.xz=b4cbf42364270c158d801ac7d4b6cfd7bf1f5f9e74a3044e6d959f1971f5bc34 +dist/2025-02-18/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=ae2a5c63cce6ce237c81ae78cabc6e1e0634c956789c2e2f39e3a6c0d864636f +dist/2025-02-18/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=6bba5069c89d9a0d9a2013715814fb55ebcd77b342ed0dfc72115a18367c5e8c +dist/2025-02-18/rust-std-beta-aarch64-unknown-uefi.tar.gz=0bef07ceece7523d6f41f1d640569c52ebe8a6b97b35da84240d873fd68250da +dist/2025-02-18/rust-std-beta-aarch64-unknown-uefi.tar.xz=cff8b58e158786cee1a719552fb97cb2cd3a12b541641437809428a65eed42fa +dist/2025-02-18/rust-std-beta-arm-linux-androideabi.tar.gz=a34fbf0d01cea60876a6d0aa4ee96587a5e31b6d4f84aa7c1ba5b7fed261b639 +dist/2025-02-18/rust-std-beta-arm-linux-androideabi.tar.xz=7d72d638f5984726fb4a61e81671d9557d0a9a876bf5bbf39b2df3c9983d2962 +dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=9ef3aa1bcbe1a18658bd16359cbf3e94ae1b07f65bd5c69ffbfa964ad845baf5 +dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=93020195c2ce07204179e2d2f900953707e341a71d9371551c4a727afc58378e +dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=5b0a4c4831534de85a5ba5b0149bbd824ca83648bf66babe5dbf13291b06e03d +dist/2025-02-18/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=60f1ff95cc88330b6c9741520c02ec845e7b14943f2927091a9110b7fb1c4305 +dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=0f254a943b6e56873d2ab84e8a93fa7a3ab723df5a7926faeadae4696ed06121 +dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=0c682e7cbba8463682a0a20785ff7fd331d2bc7a32c0cf86b8159897fc5c5ee7 +dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=6c5be45f79035f57ac41fd209f6e7d4439cab5acaa766f7bf001b24196411b1e +dist/2025-02-18/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=bf25eb6650ad27377414d53af6857133a539530c841cf96e3cae4406bf4ad485 +dist/2025-02-18/rust-std-beta-arm64ec-pc-windows-msvc.tar.gz=39ec7fd0ecf47b36c6badc1fc71f1290e99d2edfa9d7cfa72446fbb32ba9c8b0 +dist/2025-02-18/rust-std-beta-arm64ec-pc-windows-msvc.tar.xz=f1d578e9251d95c94c20e3ee7888993ec7ea3d967a880f89963df7bea0bbe93b +dist/2025-02-18/rust-std-beta-armebv7r-none-eabi.tar.gz=3990bce70402da79a27fd0f4adb169e4e9faf617bdbca2676bc41d9f85845dd7 +dist/2025-02-18/rust-std-beta-armebv7r-none-eabi.tar.xz=ac944400a3da94e32d7010e10b30879bbb5da456d3d54dfd0efc792884b035de +dist/2025-02-18/rust-std-beta-armebv7r-none-eabihf.tar.gz=1196e2ae338b325ceb89edaab8b165478ec481270a7ce4c65f47f45d76e7b33b +dist/2025-02-18/rust-std-beta-armebv7r-none-eabihf.tar.xz=fead57620d21252c958020e340fc793102d177f76fd90b3936eaf3a22a3b87c9 +dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=e5e81e1501554c2b28745c4d905bbe50f909dce3b7806f6010a9d48cc528304e +dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=d3c9513cdb058685848de3d7864a7fa5a9b1e45f779a7ecf447ac7faae652772 +dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=6ca5598fbdbf77bcf971e62d5b3f486e25d01e95773670bdc600448f29b68a09 +dist/2025-02-18/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=7e0a8798586538c4b322b58b9e1ac90e27dea4a0b5b750873f90b8ec9dcdbe2e +dist/2025-02-18/rust-std-beta-armv7-linux-androideabi.tar.gz=cbd81d4f949248c0c48a60545648a384aa321ee5f590f52d50e8d3639a649745 +dist/2025-02-18/rust-std-beta-armv7-linux-androideabi.tar.xz=75216a970ba5a023717dbbd45b5a1a90ff9533f25deca241c11ebce80dc6229e +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=5acf37dc6035d3d83d003d70d3db3c196b20d461a70385e8e5d545be1f4392b4 +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=8c75b0c815465126d6c7516883c478c78fc83cfb294bd5b9387d5bad65c9810f +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=733fca96e3d6dd232c746a6034bd7cc864f06bfce3d5da3bfd72c5ca4cea221d +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=e9ef142105d0073bf070a6de74e7173fbc09f3f22fd50eef0fea8ab6cf0ab4d7 +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=13f2b55f297628bea201f3caaae0178f0d898c67a696d4b60a37c3ba5af0582b +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=455605ff7e88d69052a4b3798ba27a673807ac1be197a8ac9e57497b5bac1661 +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=5b4b8eae2d86baeb470ad2a143f5d91f0dedeb225607189d9d0f8c8115e5251f +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=fd36a0f0a001436195eacdb52baee2462c43a1f9899b2e01ed60019f8285a95d +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=093900dfc07c4c4f59bd84aa8e9b505890cd8736a994798da8cfd7fb6210ab5b +dist/2025-02-18/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=e5cef28308348a378835ced449affa965f49d9b7382d28cbf32337ae94ebc9cd +dist/2025-02-18/rust-std-beta-armv7a-none-eabi.tar.gz=210229d27f6d574670e9406b98748869212e66713a8ad37f2e5b67ebf27e43ab +dist/2025-02-18/rust-std-beta-armv7a-none-eabi.tar.xz=323197f1dc3fe70e0a540df8a5f5d9475dcb390f1685bef54ba355ad3b48f316 +dist/2025-02-18/rust-std-beta-armv7r-none-eabi.tar.gz=f66d3a794ea7ea0df73b5df389738e6b3e1790b27c06187de2ed1888743ecb57 +dist/2025-02-18/rust-std-beta-armv7r-none-eabi.tar.xz=ae1465d82ea49e5ed33ac95dc0ece4c8fd0ce3df20b21a6a44ed93f33d131aca +dist/2025-02-18/rust-std-beta-armv7r-none-eabihf.tar.gz=fa0d84655bfb7488c9c378ecf833edbde08c652d25fbc9092ed2707b320f657a +dist/2025-02-18/rust-std-beta-armv7r-none-eabihf.tar.xz=251ba3b71c4a0bbdc327a84ee1b3c3deeeed3917fe55aadff9a52a44063f6270 +dist/2025-02-18/rust-std-beta-i586-pc-windows-msvc.tar.gz=9d9d89b206dc85323a7ee765447d1cafc2fab9189be88e1558709d94c51f2298 +dist/2025-02-18/rust-std-beta-i586-pc-windows-msvc.tar.xz=b124483bdffbb41b5c806f6bcc1003ba15d031cf5fe02eaead555abe15da20a6 +dist/2025-02-18/rust-std-beta-i586-unknown-linux-gnu.tar.gz=914925fb75c45cd9939c8692b02efd337b814040ca9bce369d812b97698a4c3e +dist/2025-02-18/rust-std-beta-i586-unknown-linux-gnu.tar.xz=eefceae8f0d42a5e3524ac134afa9a13e938f1680edf605cca2e2d9dfbd33682 +dist/2025-02-18/rust-std-beta-i586-unknown-linux-musl.tar.gz=4baafd6924c5ab59c0c4dfd30272c08328ea1f31b70e8a9a3dababb94c1dee03 +dist/2025-02-18/rust-std-beta-i586-unknown-linux-musl.tar.xz=c75b6e4b50cd731d7f955956ce0afc02f04e2adc4268a1bec8b076eb1733ad28 +dist/2025-02-18/rust-std-beta-i686-linux-android.tar.gz=e067c5483336195763c2f1e9625644075fd93cc86180e6d24bee63aa26b22e99 +dist/2025-02-18/rust-std-beta-i686-linux-android.tar.xz=d4892feae881cc914b94b8bfd66b5e75cc4d62cbb697b8faa3f29d1d70d15f5f +dist/2025-02-18/rust-std-beta-i686-pc-windows-gnu.tar.gz=ff6f43c40e2f8edc9ca21df771c3c28ab77bcb0e254adaa09d8c9433bd56fa97 +dist/2025-02-18/rust-std-beta-i686-pc-windows-gnu.tar.xz=8d6088d7ef7f13bbf576fe238e8a032091359a773845f35e3329b5d8273d1fcc +dist/2025-02-18/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=cc62a0e5c529bb041455ed15f646e5c9c918f20a644ed7306ad8beb1abf07c1d +dist/2025-02-18/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=9cdcd32f73d9839c5e6322f8b1e18e3abf825ddbbe9bb498616f0c058c5fb061 +dist/2025-02-18/rust-std-beta-i686-pc-windows-msvc.tar.gz=fecfb22d75b38e9c92c64790833c8ed8b4ea70c40d3d9c67a23277216c1246bb +dist/2025-02-18/rust-std-beta-i686-pc-windows-msvc.tar.xz=a592d638118b0b95e8ef0e174b94c1825d0e3a3aab87d03737eb7415d1b32076 +dist/2025-02-18/rust-std-beta-i686-unknown-freebsd.tar.gz=e8546b2f4fe5746706d2b0d56fe174ee5993bd61a9fe451fd233236d7af0feee +dist/2025-02-18/rust-std-beta-i686-unknown-freebsd.tar.xz=09efaf8f4f26ce6d466c1e20758901dc64348cdf390f4b878b4ee9542f50dbae +dist/2025-02-18/rust-std-beta-i686-unknown-linux-gnu.tar.gz=e173f1ac1662deba8c719965d5d4c77e711cc0eac732d933b6c8ac021a44de5c +dist/2025-02-18/rust-std-beta-i686-unknown-linux-gnu.tar.xz=600aa6b6ed1b49afdcc4978c897cd1e1f801193b804b0d1723319464c8378c88 +dist/2025-02-18/rust-std-beta-i686-unknown-linux-musl.tar.gz=38f7ee73e7067df2b98064b9f0ed00b8aa7c7eeae5955719fa0e2cf1f126ed19 +dist/2025-02-18/rust-std-beta-i686-unknown-linux-musl.tar.xz=6e639d9c45eda6b43ce0ce52e3213172df1875adfa0c13e52385b5aa9fa05da1 +dist/2025-02-18/rust-std-beta-i686-unknown-uefi.tar.gz=2ae2a44ad2610bbe3a97d176bbfd3e43efa22b5713c9591b9f3bcd7609f3a30b +dist/2025-02-18/rust-std-beta-i686-unknown-uefi.tar.xz=d8fcf03e16ce9ada0253a2f8899ee9193083e1638d9e0da6cc76886b6ee14c91 +dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=cb0f09f7d81b1e49a761a94396dcb4e999dbbea7d70e044785992da9a2aa38e2 +dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=1cecfc8d91f5f3cb7bc67f49795d5e2c74638df0f7d66a3051a851522dae2860 +dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-musl.tar.gz=0369af7a8b56dac39448a22f1ad27df42c72ccdcb43cb96e7eaecf0c0d8b94e2 +dist/2025-02-18/rust-std-beta-loongarch64-unknown-linux-musl.tar.xz=a395fd16ea741c72b39db5d398a46a90cae8531be620a3468d0dc13f8a9979f0 +dist/2025-02-18/rust-std-beta-loongarch64-unknown-none.tar.gz=e2ce2c57ad140b9088052009efae96ed04ce14c258cd954ee049dfc9146242a7 +dist/2025-02-18/rust-std-beta-loongarch64-unknown-none.tar.xz=a055dd6cc47dad744fe9343d100750ea013cbe3a5bf4fcdac54e80809352a6d3 +dist/2025-02-18/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=26f8ba1c9594f7336ad530eef0076f2d30752d2edcf96d944cc962dde3d3caff +dist/2025-02-18/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=32c80782a30c7bf300510e4fa29dad76d9a40bed2d5746c4d55b17fb261d788c +dist/2025-02-18/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=2cd25291aa0c7610f10ab04cdf4ba4d214e0c684bed73d2ef31ae84af2da0eaf +dist/2025-02-18/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=a7f02677a5c35388593142ef95cf56ffe1632df7fd42ff35bff89dafb34a0bdf +dist/2025-02-18/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=64ee7c6fb36ea45490911ae5557f6a051728a05a7c88b1476489be87456be4bb +dist/2025-02-18/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=250993b5a1915a8970d91f7a10f3f50c907cc9508d71d3b2c8e20914f90254a6 +dist/2025-02-18/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=deb267998a725fb0288432a51aeac3004d6430fce8683c91d102b6708e5b99ea +dist/2025-02-18/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=49ba80f0a2970948699b78fc60ac09f77dda94e56931399c57c2c81fce8df9e4 +dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=06ff5073e946ed2a5f80f9a5befd7b0c27e9a959cebf26b6cefc5762a0fcdb03 +dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=27f12f5835f564b03f55d85121c9474b9fc93d3084c5b5d0fc63d33c8c9dcc64 +dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-musl.tar.gz=78aff087bbef054b5a6a8d2a1649dd59f69b7f98635eb0c130c4ba87b3018850 +dist/2025-02-18/rust-std-beta-powerpc64le-unknown-linux-musl.tar.xz=e82b6bdfed001c91f8f88f6c37e31ef35f2f25cdca6fe8adfd90d024cc068e15 +dist/2025-02-18/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=8dd6fdb684882ce4087bb96ec2d982c0d808c93c053c774b49cfc705959b4309 +dist/2025-02-18/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=4d6db36241c3d8735e7c2ee84a37ae0cfbc2fc79c6fd259ca4b74e7edb68b8f0 +dist/2025-02-18/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=32e8a2eb316b2a82f80e7268a318df89f732d7cbaba779debe10664aec7d40de +dist/2025-02-18/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=562030f1bdc1307bc0261a2e66c12a6f21fed0ed21fdb2140b1b1d55664aab00 +dist/2025-02-18/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=52e8c7ab87f5d2cbb712fb54ad8394b50a7f95961e1a7e5ffce981a962899a2c +dist/2025-02-18/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=74f13bf5f0ff428c323c3041771b653d3ccf5a999105869378bf09a6ce6ca040 +dist/2025-02-18/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=e2b8a784b4c6826d00a69de8e1891a40619f4b17c6e54c5cbed349fedefbd8f1 +dist/2025-02-18/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=a231848519003a9ea1306a7da2139675516c0d94e5cbd8af140bb1a37515d7fa +dist/2025-02-18/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=82d33d6527db7adaff8bec04c6edb4f3f7a1609fb5e5a91011a3b48dd47af93e +dist/2025-02-18/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=bfe440ce80c4547afef2c6b8379bccde9f7206a5406c5a7ed5c06ab460ad8ba1 +dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=728c559f432bf8487c345967a2ebc9e4eada676a6d56a68ec32d26ee9775857e +dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=51e7990ff209c27a15d40a684d634e5cad26d55913b897c2be6d92fcb849b7d8 +dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-musl.tar.gz=ea66ba0e6af1fc7ce741c0838bc005abc04c6ad85c6831d2e05d04f30066281b +dist/2025-02-18/rust-std-beta-riscv64gc-unknown-linux-musl.tar.xz=7429a295ccda168e41e9717647ba4639eceb81a73d66ad7ba01c9e7f1ca19c03 +dist/2025-02-18/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=01824c3ca49cfb433de4508282f0395bae8053866691869fb804a3058a403b02 +dist/2025-02-18/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=67e324c82c6a5c9fd279b9bf5ebabaecf35374c741e5728c2db3fbbb6eab1fd9 +dist/2025-02-18/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=466d4e5c1912937481fbd22d739987d663f3c771ff0efd676b34fc34e9266f87 +dist/2025-02-18/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=409c2870098222c09abcb1c89c7394633222bef2cba9756638e8cad058e3c524 +dist/2025-02-18/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=b31e3389756f78bf680982d6c6415c3712567e5050beddae10d2df52de560e61 +dist/2025-02-18/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=729b7433746947b88b8d4f488e2831bff1a92911b8c25f16a1208542e38d5834 +dist/2025-02-18/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=56caed9608e88e9ed6dec56ec3265d6464633ed57b14a455c626983defc87411 +dist/2025-02-18/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=9c9d16cac691185cf055117d6888a25f14c72cd110e3bc699c6e78b5d0dc70d8 +dist/2025-02-18/rust-std-beta-sparcv9-sun-solaris.tar.gz=6963215ffa1d2cf9650db8bc36f1eb5c97fb4d824a010c2a65f842fa00b4b4c0 +dist/2025-02-18/rust-std-beta-sparcv9-sun-solaris.tar.xz=9077823bd323a251347336f3c656c6847d5fefb90efed0cacadd510f42afbb74 +dist/2025-02-18/rust-std-beta-thumbv6m-none-eabi.tar.gz=f6d1b17e822403428a6ddf254caf78c75c2d91c208e035590779b51d45b7e081 +dist/2025-02-18/rust-std-beta-thumbv6m-none-eabi.tar.xz=1eb4e8ca0d8a52ddf754aec64b70e7a1f91d2746eef7e3c6d4580a0794cbfae3 +dist/2025-02-18/rust-std-beta-thumbv7em-none-eabi.tar.gz=7793950c2a0016ae90ee8fb70e881047a1f85c82f087fb02532009d6419ba6a8 +dist/2025-02-18/rust-std-beta-thumbv7em-none-eabi.tar.xz=14464141719b2b2c5d4a4b29685f3a2e336c2542ea33af01cfaec2ed7511baba +dist/2025-02-18/rust-std-beta-thumbv7em-none-eabihf.tar.gz=62612b4da1872950af31bf3d9f0a595f019e6c4074874f4cdfa9166c5ff39434 +dist/2025-02-18/rust-std-beta-thumbv7em-none-eabihf.tar.xz=07ab29714f76693f69273a5567408307186b272061501a9ac83eebe944f66d31 +dist/2025-02-18/rust-std-beta-thumbv7m-none-eabi.tar.gz=b2da60ea5d746b607c505279b84aa2a8f3bac3e258ca867f6aeca958e50691c8 +dist/2025-02-18/rust-std-beta-thumbv7m-none-eabi.tar.xz=3eee9280fdd35f30ee9b4a2e5d8614ee916f36cd08629a574f6450721a1fe05b +dist/2025-02-18/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=c5be169574de4fcd550b67d19834e064b81084e673764390b9f177631f3fb0ed +dist/2025-02-18/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=bcd6ddf6493cbe17236a74c26da7e16a9a752fd39ab453866ae3301cff0c8375 +dist/2025-02-18/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=e52c2e8272a9ff9442ae6bafb7526cac424d15d4d6d1d8d210fe981b42da9b73 +dist/2025-02-18/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=81adef669c6f8f08b941b0befc6af30eb78b2717c3aacd52a1526d9545548c53 +dist/2025-02-18/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=1036f47867b7d29ae468a040c50da016e20a6a3a291714df4193895234591c00 +dist/2025-02-18/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=508b4f1e307d0b033eab345ab5106eb83ad8dad212f491f1ba92b9680f699bc6 +dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=41c806851db8e59dc9ad8a756c8efde7dc14e8ef5dc4feb81be9351d267b6157 +dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=f3bb9c783f4350e491fd683d057521f497314e85576b26808f4edc7d1d8612c6 +dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=36a3e0675cc972fe6f4f860da47c9d4e0ac175191622c651fbb002207506b627 +dist/2025-02-18/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=c3287e3ebd4583a576f4bbdcfaa77fc21f6165b18573cbfdeb28593494ec14dc +dist/2025-02-18/rust-std-beta-wasm32-unknown-emscripten.tar.gz=4a7128b50478a05d4fdad69715a0a7c9dcc745aab33cbc2e137cb670c6265001 +dist/2025-02-18/rust-std-beta-wasm32-unknown-emscripten.tar.xz=6e3b5981cca095c2414ad4d23f3e69a942a12c1d51dc9e055ad8409c5edbdcf9 +dist/2025-02-18/rust-std-beta-wasm32-unknown-unknown.tar.gz=3b0cbbb35daf13711e8f211da8e2ed4ade96f728be5e5ad3ca02e4d3e32b7262 +dist/2025-02-18/rust-std-beta-wasm32-unknown-unknown.tar.xz=4e50db69d0917f205a16fa3c4ee5e4012c000194ff75641ddeb49bbec9a2ec49 +dist/2025-02-18/rust-std-beta-wasm32-wasip1.tar.gz=d382d7f9787018480329518035fc4ce3247775633423e0f2940c3670cbdd4705 +dist/2025-02-18/rust-std-beta-wasm32-wasip1.tar.xz=e1d9c800db62bf606d9be9a75dd00ac7190acf3fd3592cbdeba67170ddb092aa +dist/2025-02-18/rust-std-beta-wasm32-wasip1-threads.tar.gz=cc7cd664a483eace96710d341132de4f9cf2113f358722425ddcf84cfe821116 +dist/2025-02-18/rust-std-beta-wasm32-wasip1-threads.tar.xz=17156e3e57e304ab3ab10f8191a9952400182d2a46ebcd39d1cfde97b94c0756 +dist/2025-02-18/rust-std-beta-wasm32-wasip2.tar.gz=7ab89b39693bd1bc3f344dce6ad1c127ef38f64591c7be769d07603b2422800d +dist/2025-02-18/rust-std-beta-wasm32-wasip2.tar.xz=2f53c60d0c0388ff644c17e341368e8b15d4c41b2827b03507d4efee100a1841 +dist/2025-02-18/rust-std-beta-wasm32v1-none.tar.gz=3277ec65149e708925ca7fc062cde92953d01569d2700d2831e6ff68768e5b30 +dist/2025-02-18/rust-std-beta-wasm32v1-none.tar.xz=24df037c2c4bcb3d593033d93b6e26aa1dc38161452220d7a73a23a696dc93bc +dist/2025-02-18/rust-std-beta-x86_64-apple-darwin.tar.gz=3878e1506ee4642fdd1bd5e10025c9c289f8d03b7cea876d2348fabc2675b721 +dist/2025-02-18/rust-std-beta-x86_64-apple-darwin.tar.xz=46bdd522559b61848cfcbc8c55d95b190a134f2a0ac19e3c7ebfaea867f9780b +dist/2025-02-18/rust-std-beta-x86_64-apple-ios.tar.gz=e914a0a4a2824f12764b0b91b0dd97a25416686839f35dea2aabde41c011f850 +dist/2025-02-18/rust-std-beta-x86_64-apple-ios.tar.xz=b44ac0cc8cab86ba9d000d2164786b5bdc115ace7990ead57aaba2b0e02750aa +dist/2025-02-18/rust-std-beta-x86_64-apple-ios-macabi.tar.gz=497c75ec8b5f99a625d898b406d437b8902b8ad42ee1d629a0efd27cfee96e44 +dist/2025-02-18/rust-std-beta-x86_64-apple-ios-macabi.tar.xz=a53ed7bfd16d62a7f51509d32fb6cc6b1f3af331f4c4867cbc1eb57da5c3d521 +dist/2025-02-18/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=3cec5b6714f156e43c85b4b15377475bc38f65325f61de020bddfc2708b25a7b +dist/2025-02-18/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=ea2cc73a03644647dec905100154a3238dd819fd0421f770dbc433cd6dc49f33 +dist/2025-02-18/rust-std-beta-x86_64-linux-android.tar.gz=2eaebfe572503b69e34674ed414357c514bcfbf013e6a2a7bb3fb14f501872e8 +dist/2025-02-18/rust-std-beta-x86_64-linux-android.tar.xz=66c4f03b907515831f9a48c8f5036d4c3115e814507a27abe1e423ef4a7e7c0b +dist/2025-02-18/rust-std-beta-x86_64-pc-solaris.tar.gz=4c8f54f1709908a9edabd9e60d8492cda771db4b51fe766f2a2323a10f184e1e +dist/2025-02-18/rust-std-beta-x86_64-pc-solaris.tar.xz=60d74169e80b3e1297b010501fa5a46a29a7541c84ceeff304b4c2ace7631540 +dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=9d043fbcd7e180052b903180114d50c71a2ccbeb22fff7020514b4b0a11a8123 +dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=f08905c0b8192f23f214465d757d93e30aee0250dda279d648e948961e0745ca +dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=e35a42a9a6eccc4b738b389fdff24ba01ef23ff8d00fbd34100acafffb9c3763 +dist/2025-02-18/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=a1fd2d1b1bb1fe9593df7835b5fb81e5c9453c0bbbc17b9ee5deb0512ad12550 +dist/2025-02-18/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=feada263ce77cd0ec635ae78c8ce34099385a1f89d1eb680576a85a8adf0d75e +dist/2025-02-18/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=ee8def01984eba376773f7a055a18a4096750d26f96ab9150326dc60ece9fbe5 +dist/2025-02-18/rust-std-beta-x86_64-unknown-freebsd.tar.gz=7791a0155a0a3464d07b176383a4b61dcfaef4bf0247c58d447402fac3123186 +dist/2025-02-18/rust-std-beta-x86_64-unknown-freebsd.tar.xz=11bae401884cce0306b415bb1202c2c63f81395677057fbbe12e9302951a9d3d +dist/2025-02-18/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=4d05cd943f4e4250d50a5f732a64f32431a6cfef59b38bc087b1dbe1aa4b9561 +dist/2025-02-18/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=7bdc7161d66b6c330f027f53b15f164c9ad4d55debe77b7c34971a877bf82caa +dist/2025-02-18/rust-std-beta-x86_64-unknown-illumos.tar.gz=01edf8fdab00df25cfea2ade367dc4f66a1d08d11bfd9a7e56b65a723e14b517 +dist/2025-02-18/rust-std-beta-x86_64-unknown-illumos.tar.xz=9efccf8ba6fc68997123924cddd7008b15f1a57170d03597a370346fdc6c83d6 +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=9dbfabe77853e672d576e70332e07727882cd6af14dee9a00d5186b43763ce82 +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=04e31482a3ff18d8fdff40c4e95b22bc667bc0dd1ba06fadbe2479bae5d97288 +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=ebb6e0c56d905ef064fa15449a72746daa9e3998f5aba5c6a3c132bc676228cd +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=818fc179c8380f0fb70c46e04086926a69b026591ab62cfbc1051abc5c80012a +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=c0a1c692a334821d61a9b92cd1332f047175d4335336db3e2129687ba96ce5bc +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=2c71b87db4cec49e3c620e6b4e0e07f1aaaffe69020b07c87546232ed1ad3b20 +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=c1bbf445dd0b187904af5871bf48a720151ef75fdd3dd13161dad01ef5e87bbc +dist/2025-02-18/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=19963165ec2c35c15024869c16a707bdc90e72032ebf6e203cc67411ec8ba7c7 +dist/2025-02-18/rust-std-beta-x86_64-unknown-netbsd.tar.gz=63fbbd51047125fe30f1954ea19a05d6f051d2a77929952bab326c8ded6db8d3 +dist/2025-02-18/rust-std-beta-x86_64-unknown-netbsd.tar.xz=1c255d1de9c2629210575b862600bf369499a0eb8873178ceff4a337ba9dccfe +dist/2025-02-18/rust-std-beta-x86_64-unknown-none.tar.gz=781f14a54c5e68acde1e68042905a48f687294e2bc61450f422a6e15bf6ab509 +dist/2025-02-18/rust-std-beta-x86_64-unknown-none.tar.xz=d45921b98740f3cce5833bc4fb1e36816f34b81e96c3ca2c76deff4744134c6c +dist/2025-02-18/rust-std-beta-x86_64-unknown-redox.tar.gz=0cd76d3c5b051b0b2015cb08079ea3b5ecbb9b0b68779eb35946721b24c07008 +dist/2025-02-18/rust-std-beta-x86_64-unknown-redox.tar.xz=6dec719cdb7f35f6eafd901414525b40f030566bdf3fb55e3b05de162dbf0741 +dist/2025-02-18/rust-std-beta-x86_64-unknown-uefi.tar.gz=aad1e2cfd4f428acb67d9dac1fab4450eccfe9212f52f99f06c09899285b6b1e +dist/2025-02-18/rust-std-beta-x86_64-unknown-uefi.tar.xz=4252b618ffc906949756ad28a5437d11b0353fe1d755ee1d23502a208bdee74c +dist/2025-02-18/cargo-beta-aarch64-apple-darwin.tar.gz=2f7f459d2595d3f60bcef4ccbd3c72095a3ec54fa3f2221a647ae892c308d5b2 +dist/2025-02-18/cargo-beta-aarch64-apple-darwin.tar.xz=501feb9138f3c11a13fd649d6573924ead10f5e6fb1e759d880684bff11c12be +dist/2025-02-18/cargo-beta-aarch64-pc-windows-msvc.tar.gz=b589177b0287a42ce17939dbbee92d883dfec88ebad33bf9a719a3cb2f446533 +dist/2025-02-18/cargo-beta-aarch64-pc-windows-msvc.tar.xz=d795082d304ecdde233a4b6bb3aa558392b2c5a1553fab213ee99648c49f7a51 +dist/2025-02-18/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=8444d938514ad2d55769cf614774dfb4e5a27c34f8ba8b49329a2bcf0b000162 +dist/2025-02-18/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=02e52fc13ae52066031ac40dad039ad752b83582e5f9e74ecef206aa9206ac16 +dist/2025-02-18/cargo-beta-aarch64-unknown-linux-musl.tar.gz=e89709bb552e7ee73de02b08c6d8820b07bccdc09777eff9716efabb2bdd50cd +dist/2025-02-18/cargo-beta-aarch64-unknown-linux-musl.tar.xz=50944f0e51190f9db065764afc7a41a3a1e39767bd1ef5ec659c98fe9243cc98 +dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=0343dfc2f015d476b3aca59b33dd75f907f595bc24715e6c518194ab1a5dfec1 +dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=3dd6c378c10172b1abfdd1db2fa764d1b48153ac1b5065cf124399941d036e56 +dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=6eac5ffb9adaf2591d3b1872249f4a959c04afdf6694e62dc850936aa8d35972 +dist/2025-02-18/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=484510e6b9519c2b047864584253c8c1f725ce843e8dd3117349032314737462 +dist/2025-02-18/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=fcf4d4b2d401ea689ee32f38b4a61c77b52ff4d3d114b23d0262bd02c3d1ab5d +dist/2025-02-18/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=1a75296c42d6cf93a5e51ecb2b2bfbf0cdea350668d610e8b0c90937163b4f33 +dist/2025-02-18/cargo-beta-i686-pc-windows-gnu.tar.gz=d1b5147ec79466ab9441825b4761e89cebe57ad21a3199b0eca0779683c45ed6 +dist/2025-02-18/cargo-beta-i686-pc-windows-gnu.tar.xz=980850e06ccd90512baebbfe3baaa65b5c089edbae8146fd940c708fd7556abc +dist/2025-02-18/cargo-beta-i686-pc-windows-msvc.tar.gz=78c67ba481cc7b855b54a2edc0297bfb5eadcd83d5a028b05291415417bc6947 +dist/2025-02-18/cargo-beta-i686-pc-windows-msvc.tar.xz=6ea74c750e6e0a794965c6616e5b1a82dee295815b0c24a3898952b1a5a02c8a +dist/2025-02-18/cargo-beta-i686-unknown-linux-gnu.tar.gz=a0c8f67fe77b94674698b4816c081e2ef08500990c0f9eb069d0190df9c4f129 +dist/2025-02-18/cargo-beta-i686-unknown-linux-gnu.tar.xz=9b13f958ec4edff194858e90c54866a129e88769a76fe22582b07e17540708c3 +dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=f4d2f1c8a7bec6d2b8378aa87a324c42f0f414962174b40b6f0d1dc21d0cacf4 +dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=f25659ef3be1a28da8821eb178e02108f41cd5c0b87aa01a052a3a90e7a9da50 +dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-musl.tar.gz=b687a7c3fac08680818804e034af6689f1bbcf8fc0e406c99b2a49ddae1e900d +dist/2025-02-18/cargo-beta-loongarch64-unknown-linux-musl.tar.xz=e33818d2f94e8ba148dbf8cd53d6396e370157acba6d0865a5ac71d292939a0a +dist/2025-02-18/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=9cdc2115bd2022cb0b0ac4f1c71142c064957137decc028dde7585acabb8b780 +dist/2025-02-18/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=f722447494f0a7af9c31b71364aa4a2fde79a9887440d8281e4561f7d71620d3 +dist/2025-02-18/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=d8a30f9e48e89cb1d18532fd7fbef8eeceef6bc602ffaf9e730c635e2fdbb156 +dist/2025-02-18/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=ec6b3b1595c5761b8092a04a412e79534c28910ed78ed792c9af7ddc4d92a389 +dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=4bf9c73173199fd3ca952d33702288deb483c7fd392179352135b64e7e8fadb4 +dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=12aa06644e07344a77d0c16dc1ed96bfba63de02df1f432d57b82f8a1e2282b6 +dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-musl.tar.gz=eab362146d449dcdd10740c8e6f9dec6e640ffcca162eb51febbc835e34acdfd +dist/2025-02-18/cargo-beta-powerpc64le-unknown-linux-musl.tar.xz=867b716eae9225c66c0ab4642e4e497055ad2effd24343bdf80354ce2845d6f9 +dist/2025-02-18/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=0503ba2e4b1d668fa3a3174f96ec3fcc12ff767574a7af8ef5fc824ca86dc965 +dist/2025-02-18/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=478b9f1d4f517f93f15530d27a7d55ea29cdd06eccf01176ffd08c0ee3204c1f +dist/2025-02-18/cargo-beta-s390x-unknown-linux-gnu.tar.gz=419a679aaf6e164649538916daf28081a063bd56c7b86ff0e2df58072f334fdc +dist/2025-02-18/cargo-beta-s390x-unknown-linux-gnu.tar.xz=31b39e242035036c1101412b7c86387e1183063ff5f6ce67d311d0764435a588 +dist/2025-02-18/cargo-beta-x86_64-apple-darwin.tar.gz=d6d5224228dd54b6d16be30271111620c02fd88e656b8bbd22452b66b0d5cb56 +dist/2025-02-18/cargo-beta-x86_64-apple-darwin.tar.xz=cbeff7c031b4ab4732207b90ee8849b27f03cb28d3e085bf4d70444347dbfc99 +dist/2025-02-18/cargo-beta-x86_64-pc-windows-gnu.tar.gz=ae5922955ec579732aacd8112bc53bf5333438eb81d0f81dc5f387888ac979a3 +dist/2025-02-18/cargo-beta-x86_64-pc-windows-gnu.tar.xz=553c55a2bc8eae2c8ba831823a97f2232808af1f753642ec4cdd09c33dd3f6ae +dist/2025-02-18/cargo-beta-x86_64-pc-windows-msvc.tar.gz=d9b2cf14565478429fba6266f0c86a58f3bbd1ce11a63268828b33ccb55759cf +dist/2025-02-18/cargo-beta-x86_64-pc-windows-msvc.tar.xz=2e8c0560355d11a038219072d2503860f5c5b3cd137b89ad931f54d9bba60499 +dist/2025-02-18/cargo-beta-x86_64-unknown-freebsd.tar.gz=4b528361607845e6f8ece403bbdb8d77c6159ec137396319562ea2772502792f +dist/2025-02-18/cargo-beta-x86_64-unknown-freebsd.tar.xz=c244ec4f97420c29c690e32bd6d8f14994bf1d990747f31a3dc0f2b37644493e +dist/2025-02-18/cargo-beta-x86_64-unknown-illumos.tar.gz=7d3b49df93e87322a9e99e36c6df020d3311c5538ad2298d8b5d8f2d9ad3e0d3 +dist/2025-02-18/cargo-beta-x86_64-unknown-illumos.tar.xz=136ce90487448ee770472d4bd2c0d9c96200f0ec762419feb42fefa26ba36b58 +dist/2025-02-18/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=510538965ea142405925d3f4f03a87783516407989b8aa7be07fb84c0680e9fa +dist/2025-02-18/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=a8c569398d71cab0b90c809b1d869a2e3c5037407b5af804df08c205775981c2 +dist/2025-02-18/cargo-beta-x86_64-unknown-linux-musl.tar.gz=1493f66e5cb12e8b955841804e7df745e26daea2278144aa57670192c4c62cef +dist/2025-02-18/cargo-beta-x86_64-unknown-linux-musl.tar.xz=472bbe49415557b75b572879d0c33750731c1fe9e56cc6ef3b0fd5532e56446c +dist/2025-02-18/cargo-beta-x86_64-unknown-netbsd.tar.gz=d3baa6019e13449c01fbeebebce42027ce4ba70841cf28733f6849e7c6ce5d89 +dist/2025-02-18/cargo-beta-x86_64-unknown-netbsd.tar.xz=0db9af42e9ad914a99db4924721c895cdf490bc5351bc8c2d8993e3569e952e4 +dist/2025-02-18/clippy-beta-aarch64-apple-darwin.tar.gz=6ce3b464744082131c99a213454225e5702564c83032e11dd0f3d95530a4e0af +dist/2025-02-18/clippy-beta-aarch64-apple-darwin.tar.xz=925baff0d91b959a99c989a4ada70973baf3da03e1d7e7e8be1fa334c3acbc50 +dist/2025-02-18/clippy-beta-aarch64-pc-windows-msvc.tar.gz=76d265c2fb6280eb8ed399501964f301a50e09e548cee708ebacc978d8db538c +dist/2025-02-18/clippy-beta-aarch64-pc-windows-msvc.tar.xz=e3d1d69cbc838ab639b2e41537b10266f1b6998a228882d4041f35cbb8984909 +dist/2025-02-18/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=918191cad727d795b51f892abb6e4fc87ed735bfcb51433cfb4371cb8be8690c +dist/2025-02-18/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=157d6eb9e7dd80dda7daae5584d095a5e68d13ba8b1d1229e90b5b51f6670e8d +dist/2025-02-18/clippy-beta-aarch64-unknown-linux-musl.tar.gz=fd4de290450e3d3c9188263d9506167e298f4c2d4c781fb3573806694b5ca1ba +dist/2025-02-18/clippy-beta-aarch64-unknown-linux-musl.tar.xz=335c5fd24d1c118e4d1d8abc43d3529dafc9b30af39f6b009924cd0fea676182 +dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=209cdd2042e293d1061b149d97333515821dda0ffeb9b30f24dd2dbb4c1ad548 +dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=57dbfdc34ff4e74aaa8776b80d35aaf0317fdc314ee4b0f3bf58fc672963cf38 +dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=a89a2562fe9ac6492a5de220c395f433b0e53a8b29c72b3a8d4843f996649ca6 +dist/2025-02-18/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=0e6ff6453df1397e7b12e7e356e7c7300cfb1f85bc3a6705735067128d2a8135 +dist/2025-02-18/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=7764c2dbaf217f4b1d8ca4ed2ceaacbb91e8010d26ae1bb10b808afd5dc6a798 +dist/2025-02-18/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=b7a042eb6830653a623c6299ef57492ae6c9b51a9cd8480f0a6fc2fb6d378bbb +dist/2025-02-18/clippy-beta-i686-pc-windows-gnu.tar.gz=ff41e5b666b3531ccdc0ee836dceb270179d6a849e47024eedc6ea309d36791a +dist/2025-02-18/clippy-beta-i686-pc-windows-gnu.tar.xz=98c6386b63ed89dd96beea223f4c720320b6ca460f11b77c46427e128034cbbb +dist/2025-02-18/clippy-beta-i686-pc-windows-msvc.tar.gz=12bd371402e4d3251f60fa29b3b3aca88b4480229088b68791dffbb4ae1554ce +dist/2025-02-18/clippy-beta-i686-pc-windows-msvc.tar.xz=62a22d1e9b4fdba254e549f5edb276bef5252754ba67a76526d5aeca85515646 +dist/2025-02-18/clippy-beta-i686-unknown-linux-gnu.tar.gz=04179b3a20a68ae2fd8444832ea4edd8155dc9296c7a1edf101053e3ff934891 +dist/2025-02-18/clippy-beta-i686-unknown-linux-gnu.tar.xz=c955e464e99097025fc7d0e42bf90342f74f475c5148526df2f51ca46ce8db4d +dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=6f58d326a1f2a35246384640b999f95a961a9fe1e5a3c4a3e67d7f96e1ef43fb +dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=583b1d55a38fdd473a3f3f3cc0fbeac808fbeb593b8b45c7a6b8a09dec0d68cf +dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-musl.tar.gz=80d73fe94ecbbcdb14b35e1616d52e0bb9b1f04dcdd4fc384e7103cc36325014 +dist/2025-02-18/clippy-beta-loongarch64-unknown-linux-musl.tar.xz=1bae908e4d3931eb4dc71ac1524f990bbccaadd9d30897bf516899baebd4c5d5 +dist/2025-02-18/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=b882e7ea97e0d36b289a46ef84b14b2b44ccea93ebdc77b2ab3430361ad15b1f +dist/2025-02-18/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=91e52dc398dccbafd040e401f155c204f2a14d5f62aecfc24912910d5e45008d +dist/2025-02-18/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=c81497f2b2d2670b9dea2e35804e10780c1631a8761d4bc3331767c1ccaad6b9 +dist/2025-02-18/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=6236e129f3e551a3126fa07662cc8ad512ad5fcf436a8da9e27a915ad4c234cf +dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=1b031f055ea4ab4a9da0c8bfb0037e92b493caf7879351f8b404a96c447ec92c +dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=2f07224e49f7cab10d673116d9dee9f964b4c44ac3db336e7ddbab9e0b1bc698 +dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-musl.tar.gz=84a8295a7066d258404c87d2269a01d89cc7efd0f143ab53689597f3fb351417 +dist/2025-02-18/clippy-beta-powerpc64le-unknown-linux-musl.tar.xz=019460a6b0e1c5c1331d5a54f3e45306ba0d1b1c2206e2e69f38c1c3501cf741 +dist/2025-02-18/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=aba8f7bd0a89205961f9803418cdf9bb63a7d72bab4a1ff937f4a142921f4833 +dist/2025-02-18/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=4607503ba131ca655dab86ad48c1737f216f8ec25ba6dfddbf1f0807e5a6dd2a +dist/2025-02-18/clippy-beta-s390x-unknown-linux-gnu.tar.gz=b0170f9b9e13d4f6e016124fd40c858e00155479fb4f96c1edc896130bb76dcd +dist/2025-02-18/clippy-beta-s390x-unknown-linux-gnu.tar.xz=397f0a8944beffb87c74717bd0f422836b3daccfa848d91c0a65875031bf12fa +dist/2025-02-18/clippy-beta-x86_64-apple-darwin.tar.gz=11be90b9b09f4e24e56df2a602ed8161023314514121d9f76e424fb628df468c +dist/2025-02-18/clippy-beta-x86_64-apple-darwin.tar.xz=16d313798f12d0e74f888b627e079606958de58eb2ca4c70d5f7de8cce72620c +dist/2025-02-18/clippy-beta-x86_64-pc-windows-gnu.tar.gz=41ed081e4a7b205cde3fe958db18ffe1c1ac5a9c336f965a03fe89499a3eddbd +dist/2025-02-18/clippy-beta-x86_64-pc-windows-gnu.tar.xz=daaa3267dcbb3daa0cae47861683f29da5b7419214ec5949e242aa93e3f87148 +dist/2025-02-18/clippy-beta-x86_64-pc-windows-msvc.tar.gz=6d9b8f549e34d8fb65987b39c01c27fbb0e18e8950a07ec6fd1888d01e253971 +dist/2025-02-18/clippy-beta-x86_64-pc-windows-msvc.tar.xz=1c26b51c484f5b10ee693212e258fb86c63a2b59e631542918799d480a3587d4 +dist/2025-02-18/clippy-beta-x86_64-unknown-freebsd.tar.gz=a42777c542773a4262ac9fcb07ed13f769957f58a795160441241ad4e4f5258a +dist/2025-02-18/clippy-beta-x86_64-unknown-freebsd.tar.xz=9e809fa141ac68557f203aec2a6cc02a4ddd22169595c40ed4a964801ccadb1d +dist/2025-02-18/clippy-beta-x86_64-unknown-illumos.tar.gz=4e65b5db249a18e73247029506f619393be7042f2c91a00301962effb76a18ea +dist/2025-02-18/clippy-beta-x86_64-unknown-illumos.tar.xz=6714018d069fbce271c177f1941a6b77f18b67af462596aff273f7db1970ef4a +dist/2025-02-18/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=72a8ee3bad3d638af0cc3ba6c0c0ed1594abe609573de71d9c7a884a8ac7645c +dist/2025-02-18/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=f622befd60c3695d3d62642b953deabc3e3f04b32cae8a7cc228cb534244adbc +dist/2025-02-18/clippy-beta-x86_64-unknown-linux-musl.tar.gz=8946e02ab98281b6949c4d725a5fe3fb1bfc86651a675e451f126fec8d053762 +dist/2025-02-18/clippy-beta-x86_64-unknown-linux-musl.tar.xz=425907bd4320c516647e5dd6df6154746d64854fe2e78f27283b7fcb27164de7 +dist/2025-02-18/clippy-beta-x86_64-unknown-netbsd.tar.gz=505208d2d73ed7278e5b29d8450c382a89e4c0992d6199243e07c8640c611b85 +dist/2025-02-18/clippy-beta-x86_64-unknown-netbsd.tar.xz=d4b0306e7d7db5cb7da977a7ca72fff2070f102ac385c3b35286da25033582af +dist/2025-02-18/rustfmt-nightly-aarch64-apple-darwin.tar.gz=13854358645915af29d9337bb87301aa1a5e76ecc86a934dd640d02af3255ea2 +dist/2025-02-18/rustfmt-nightly-aarch64-apple-darwin.tar.xz=0cd190bd5a064235f9cd6f6e7eae4725b3b53ae36493b3ea54b8f190372ba3ee +dist/2025-02-18/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=20b3f8c4c7b02158181970804d419b16f85a1083943e1c384e0bcef441f32aff +dist/2025-02-18/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=1ace0f10060d2fc35a1f05a1d61adebf95212e8b46a2234c2e78030481c1b3e9 +dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=e5ad64d67931df49f6b7d3448e9860699d6549c2b4a96abda1a03069b45f339b +dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=e8112ae80c8fd43452612b79dabf471be561b7e828c9a2141c698429d761a49b +dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=8ad36bbe888e61b6d7e540ba4a2478652f14c1b28dbbcaab732003293b7c985b +dist/2025-02-18/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=1794af320a273f4a951942ff0cd73a359fd82a971c572af1ab7ff2961340791c +dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=67b9d1d3c46bcce0aa94d6cb4155cdf7376677caf2e19685553266f781eb7cc1 +dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=9d7b97a85b1368cfc78f1df42afb08aa04eb17fbb91ceb3c379d59fab4294890 +dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=42396c7bd206d0fa07f3b44fcb894ac074e2af07eb158c1ef630bb5467151c8f +dist/2025-02-18/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=6881c9681342f1430fd9cc8c9786cee40522be3dcd0fc4dcf2b3957d9d53f03e +dist/2025-02-18/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=6cb8973ac4215d67aad9bb56521024626d7883a6e00748623a728dd9107698db +dist/2025-02-18/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=920d877e04260be6ccf9963bea12220e886df673cbc48b55925650f8f5b21d9f +dist/2025-02-18/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=ec5c7105f2c2a2055f704435fff9edbbee0a234e63050676c034f983d4e341ee +dist/2025-02-18/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ab408b64db4bd47abf8e24c0f611f2c67a3c9ce7e2138a92772e0510c6dce5f9 +dist/2025-02-18/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=d04250bc2e57fcb03f1d80722f2ac1117f797d768262d7630c9b53af808a8c9d +dist/2025-02-18/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=6d7be9f04a46040f068544e32eb84c98afc1f81b750beb229def84a7513150fb +dist/2025-02-18/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=94f585a7c666dc9c95c3ae14744e614a3fbe37b3e31b476b48bc4ef3289bdd46 +dist/2025-02-18/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=83e82932245b3c1d3c275126184f942b9cb8bf20f0d40c7cb1efb6f918327b9d +dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=9c8cb5a14294c48f8ee972d5f460751a8bae5b541bff3d872c85812b621c39d8 +dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=4f616740bef30599e6950ae2d8ae694513003e14122f6002a9d60bdc64f77cfc +dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.gz=a668e7be7946f6a9099486a40256f17832288322c9237d931f172ed76caf678d +dist/2025-02-18/rustfmt-nightly-loongarch64-unknown-linux-musl.tar.xz=b02c57c217f358ff4344ee2afcbb8353cffc0a012f970d9520ad233d188d59e2 +dist/2025-02-18/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=9baf04e268999020372b21484ecc4f5aa001b3bcee05619ae5b0a11571a3a45f +dist/2025-02-18/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=b2c2c3a0eecca7b4c35eabf09e215158c48eb426899e365db1c91c1c560ad255 +dist/2025-02-18/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=c42df8e575a24a5edbc58b5b46a89a226188d2aafc59da89d568acbb6e9cceb6 +dist/2025-02-18/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=fee7c373bb8fee5c7d4e43d7a7046d3bb156d3e496ed21cddf20c21ffdef3e69 +dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=a0ae21a3b56e20e667c72d92ad4bacd4abb77d1fea32949d7dd62a56d6b531d3 +dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=fc7e21cbd61169b37e81c73d4d5353d7e54ca322fd01491d9f37ff3666557e7e +dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.gz=e08ceaa9241c2e53041b107af09674ca4fbc4e12b1371254869e3d80d5c907ab +dist/2025-02-18/rustfmt-nightly-powerpc64le-unknown-linux-musl.tar.xz=9f208dc6e5938a128174263349345e9fe7f587689f6a53fe5d026ae3c6fbed2c +dist/2025-02-18/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=44abe49dfc0492cb3ab28f0aae0d784c982063399a38f8f13016f3dde123948a +dist/2025-02-18/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=72fa294f92ab244608c384d6ad6eea0e540e6fc58181fd65a4fce0c5029c39fd +dist/2025-02-18/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=556dcf393856c6d9c9c6731b02e34146f9f956f588025b6a614b8802032d125a +dist/2025-02-18/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=93906364910891f71e13e0ecb07f02b707e42e11a0f1b117c590804dfa16a9d1 +dist/2025-02-18/rustfmt-nightly-x86_64-apple-darwin.tar.gz=7022c760f457075fb353e59984dcb551600581a315fd17ea1320b892b1d99a55 +dist/2025-02-18/rustfmt-nightly-x86_64-apple-darwin.tar.xz=e085ee261acbaa41361a0263dd8f13644f8a4e3679eca6bb0851b03c647b80e8 +dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=2436e18fefae02554e620a1131455d923c1b67e00e878c75a941a6eedb4eae28 +dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=9f6e37b5973925d07115e517e6a3e490a221218f48fd101a20670da2c3d01add +dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=78f492a26981e7a6f9f3e8bbd1e880682e55cede081f3cfb13a2ec5f736edbb2 +dist/2025-02-18/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=d4d788fa3e3b9a598aa7baec47af3b56362224533be85dd68a411f35f8800b2d +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=8922186dedf0b12e9aa2bb041b76be8fccd43b9322c3496c688355f34bbd7a59 +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=6325e43f2c28118a9525f5c5fc09de9fb9a09ffb4aaad31f28d394c233ee8398 +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=7f317107f8319c650973cef52f745c2a8e57ea6a087910b6979404f2cb2f1cff +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=b273be4897e83f786020bce1dc5dd1caf01e2ea43f085391c0031277718feba0 +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=0373011266a9ab62f45fa137a4bfdb970ccad8bbbb74bf776466d203f28d226b +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=62748525678370dbda7f1cbd12a384e95d4af76103de998785278f6d1f076177 +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=30eeb980720d8c22bc45c012c4fd212e118195206b8b993630f074e526e6693a +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=2f3843d9544fa56dc87f1d13ef79c68c1e68d84bec007f0345159a7448368dfe +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=a86eaeab8f5f45d16eaf355a46d8b19afcd8c46db732432091156e381aa79cb6 +dist/2025-02-18/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=144cd28da601c331f6501c634ad89286be213a69cf521435e35657c5f6fe2afd +dist/2025-02-18/rustc-nightly-aarch64-apple-darwin.tar.gz=21101db859a550ab39de1ecdec75f4f058934ed8e0ab7dfadbb2efab57bc5e0a +dist/2025-02-18/rustc-nightly-aarch64-apple-darwin.tar.xz=a40da26e908810701112b9d3f9ab83515c8e2f4b33219f8f773c5459366d37e1 +dist/2025-02-18/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=5391bc993b7208c10a6f4256417c9f76a4a33d167b2fd547b57af614d3fc8458 +dist/2025-02-18/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=d72a205f52173b1726d8341a9436e62439b1987fe0cd4d2bbff740e38f629b41 +dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=185e052bf2ba1cda4b6ad1c49a9f65b906899ad1ca09cd864d6041941ad344dc +dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=640f7af3fef5f0abacdaa292ce17255433ee16f12bfc2d2e81d70afcf9fcdd8f +dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=8cdee468a90606b21a8cc3305f2b6b3eb7e3d687263f4ca8319c709cda2a324f +dist/2025-02-18/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=358bbfb24816c781e07d5480a5606dce27068f856c0a606873ceba05c9540c3c +dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=b220757cc8ed39c429c49b55e293ded3e07239d2e2bab8a9054ce55581393c47 +dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=18d3cbc49e44b7810b498517d21390e39bee7ca8351c8b321592e83301ad79e9 +dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=77ac127bae48859f57d9bd8337ac4a0bda95b1190e451abeaf7e77f1a240a647 +dist/2025-02-18/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=79009bbf0325f9db0c905d74cb0f139c92478a0b2fb5edaf383366b0e654a172 +dist/2025-02-18/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=8264c7ed7bc47953ae76cf87236655562a55846abb195bc9281833a0da168db6 +dist/2025-02-18/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=c6a85e7f2a469fb05f0a84ceaea25dc0d95b57bd4d68dcee447918162cb36b2a +dist/2025-02-18/rustc-nightly-i686-pc-windows-gnu.tar.gz=0f31c9ed4ba7e942806fc2927d305f9d3ad676cf81e53e0f7c4123aef375fedc +dist/2025-02-18/rustc-nightly-i686-pc-windows-gnu.tar.xz=350f4b46dee2aa6ebfc31912cfae5c7c1db99b298c52834308e95c504cadbe7d +dist/2025-02-18/rustc-nightly-i686-pc-windows-msvc.tar.gz=e12a40b7178995ac223eb7fa317e1114a988256d99fe615f70d64cf3f2891fa7 +dist/2025-02-18/rustc-nightly-i686-pc-windows-msvc.tar.xz=09fb4a4744a55bf8fd6371e5496f6a9c00b119ddf20b19855653d66d9a618214 +dist/2025-02-18/rustc-nightly-i686-unknown-linux-gnu.tar.gz=52361a34730f8bf14eefad7e51f66fc3ba3be405a364d4520103208fe8fdc056 +dist/2025-02-18/rustc-nightly-i686-unknown-linux-gnu.tar.xz=ea81964fc8bcb8b43968acb6a4f7fdec2ddea9f75a8be5446fb01b4267d0d75f +dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=11e7a143112b6abf818652e425b6f092464cc9d8f5286e90180c7af8d5939643 +dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=86f5d40eecccb623ff744bbc1fb40458949db9b2f8501cadc6be9bca95f6c693 +dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-musl.tar.gz=1be7ecdf609958fb0ef945203b22a600f1e343ee7fc581f6451eecd39f1e0b7e +dist/2025-02-18/rustc-nightly-loongarch64-unknown-linux-musl.tar.xz=03d3b67092da64f7b7be7ba4e115cfad4071c0bea3abb5e60ac166127713b169 +dist/2025-02-18/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=4e33311490c2dcf79a16307e1141ce37574ec3829a1e93d0f5b06ff68ad5c861 +dist/2025-02-18/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=504c102fa1c8dc5042cb354a60b87c0f6d47f9adab341f496af723f3ea8bd548 +dist/2025-02-18/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=c559971ae42a5e0e999e2fe119033bffbfe8c64b767e697e0b95f5dfc271d13e +dist/2025-02-18/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=51159ab0ade5a62e128b6c794da5c9815324470c468e5808b50663c3a0df6d39 +dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=a8134f8f7ea4531d54ab5c0a0894f140ce5182a384c57395edbe06ed551970ab +dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=8f2f5d88ba9f4ee946db5f00d56c4852213dcb0b46ce2793966af6c96d934dc6 +dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-musl.tar.gz=7bfc6666757b57fa6160d076a9eb52852dcb5bf788bd12c0f014bbd552b8a7ef +dist/2025-02-18/rustc-nightly-powerpc64le-unknown-linux-musl.tar.xz=e2c3293e2a90012ad48bbc2b6f285adf20f356ff1f4146b3f11543511bbb3c44 +dist/2025-02-18/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=f582a59b5a6cbe6d58400c69f1cad4f34d0f1541c1ffb9df3ce71846edd828fe +dist/2025-02-18/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=244384bd94f7c3606a086abc8be9d36a855faf09d9bb6b121f42e168c526e717 +dist/2025-02-18/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=327e29662140cb76b1ff362fe51f9a12fb4ec304929317ed8de7295fdb9c5b9f +dist/2025-02-18/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=a2c4e19b3a8dabd5c8fe72edd60d1925947cad5971c77c62f12fca764c6e4e7a +dist/2025-02-18/rustc-nightly-x86_64-apple-darwin.tar.gz=b6812f92e08cff1b706380637fdd553b04b9cea746ffb69e6488fbec70680136 +dist/2025-02-18/rustc-nightly-x86_64-apple-darwin.tar.xz=f2502b2a810938c41e2302a9112c97d04998ada16583373e6488bcca00595761 +dist/2025-02-18/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=9159f7323718c6a8b98f7de5186ed507b3dca1bfcce9bdfa6437313bd630a989 +dist/2025-02-18/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=10d54c9b80570b6729d0e68f017d862c5126f09b42f150d004aa8fd5382b165c +dist/2025-02-18/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=1f29c1aef1dcc3ff9f2e3013b7ea0521829e6e474f9058cb70fea65180230b41 +dist/2025-02-18/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=18cddaf7653f146dcc8a44ca0cc33c6dd3c24f28fff87aedca01fe3beaaa9915 +dist/2025-02-18/rustc-nightly-x86_64-unknown-freebsd.tar.gz=e57c1477cf9b75e727db48b8b75435d65aa0a6ef0eb566ac1890b576c330f64f +dist/2025-02-18/rustc-nightly-x86_64-unknown-freebsd.tar.xz=725f9e9d25b7ad6f60d5596684964b0c3a63d98a62a2aeda6a134b9f02fdb681 +dist/2025-02-18/rustc-nightly-x86_64-unknown-illumos.tar.gz=86a9034fa275c0fc73d639fe6437fc4d2621bf12897c9f83a81ab6056173a95f +dist/2025-02-18/rustc-nightly-x86_64-unknown-illumos.tar.xz=4aeef66ad8a908589ddf0d89581a6ca809b7c2a57f06bbda6fd3927b531fe07b +dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=907aa282fb9f3d96c9fb03dadd62f4ea766e1242fe19106ae331a4f49a9b20f0 +dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=e63d13a6acd596ebfd7bf65b292eedd2a5e260b536ca11517a3fe1d8e6a6241f +dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=b7bee098c32b321551f68e96e002f85e3a0323c864aa7f65641a58ae24f4238e +dist/2025-02-18/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=e5c22c2fab89c7ba548b11104c54e8f82cafb1979ba73a318682bb10ed9e4fb9 +dist/2025-02-18/rustc-nightly-x86_64-unknown-netbsd.tar.gz=7bf40bffe95437244f6f8a5fde69499f42d2b716e166115530fbcdbdcd837887 +dist/2025-02-18/rustc-nightly-x86_64-unknown-netbsd.tar.xz=0adeaa382f289233ffc9229e116a340ac03a861f0fdbb5bd35aaf5d0d7370877 \ No newline at end of file diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index cd5ca74f8ade5..741d7e3fa16c1 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -97,7 +97,6 @@ static TARGETS: &[&str] = &[ "bpfeb-unknown-none", "bpfel-unknown-none", "i386-apple-ios", - "i586-pc-windows-msvc", "i586-unknown-linux-gnu", "i586-unknown-linux-musl", "i586-unknown-redox", @@ -387,7 +386,6 @@ impl Builder { // NOTE: this profile is effectively deprecated; do not add new components to it. let mut complete = default; complete.extend([ - Rls, RustAnalyzer, RustSrc, LlvmTools, @@ -476,7 +474,6 @@ impl Builder { // but might be marked as unavailable if they weren't built. PkgType::Clippy | PkgType::Miri - | PkgType::Rls | PkgType::RustAnalyzer | PkgType::Rustfmt | PkgType::LlvmTools diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index 495cab582eb07..6ef8a0e83de3f 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -51,7 +51,6 @@ pkg_type! { Cargo = "cargo", HtmlDocs = "rust-docs", RustAnalysis = "rust-analysis", - Rls = "rls"; preview = true, RustAnalyzer = "rust-analyzer"; preview = true, Clippy = "clippy"; preview = true, Rustfmt = "rustfmt"; preview = true, @@ -77,7 +76,6 @@ impl PkgType { fn should_use_rust_version(&self) -> bool { match self { PkgType::Cargo => false, - PkgType::Rls => false, PkgType::RustAnalyzer => false, PkgType::Clippy => false, PkgType::Rustfmt => false, @@ -118,7 +116,6 @@ impl PkgType { HtmlDocs => HOSTS, JsonDocs => HOSTS, RustSrc => &["*"], - Rls => HOSTS, RustAnalyzer => HOSTS, Clippy => HOSTS, Miri => HOSTS, diff --git a/src/tools/cargo b/src/tools/cargo index ce948f4616e3d..6cf8267012570 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit ce948f4616e3d4277e30c75c8bb01e094910df39 +Subproject commit 6cf8267012570f63d6b86e85a2ae5627de52df9e diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index fa03c953aa599..51441ab9fc0d8 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,53 @@ document. ## Unreleased / Beta / In Rust Nightly -[786fbd6d...master](https://github.com/rust-lang/rust-clippy/compare/786fbd6d...master) +[609cd310...master](https://github.com/rust-lang/rust-clippy/compare/609cd310...master) + +## Rust 1.85 + +Current stable, released 2025-02-20 + +[View all 72 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-11-15T19%3A31%3A08Z..2024-12-26T13%3A59%3A48Z+base%3Amaster) + +### New Lints + +* Added [`repr_packed_without_abi`] to `suspicious` + [#13398](https://github.com/rust-lang/rust-clippy/pull/13398) +* Added [`as_pointer_underscore`] to `restriction` + [#13251](https://github.com/rust-lang/rust-clippy/pull/13251) +* Added [`doc_nested_refdefs`] to `suspicious` + [#13707](https://github.com/rust-lang/rust-clippy/pull/13707) +* Added [`literal_string_with_formatting_args`] to `nursery` + [#13410](https://github.com/rust-lang/rust-clippy/pull/13410) +* Added [`doc_include_without_cfg`] to `restriction` + [#13625](https://github.com/rust-lang/rust-clippy/pull/13625) + +### Enhancements + +* [`indexing_slicing`]: Can now be allowed in tests using the [`allow-indexing-slicing-in-tests`] + configuration + [#13854](https://github.com/rust-lang/rust-clippy/pull/13854) +* [`if_let_mutex`]: disable lint from Edition 2024 since + [if_let_rescope](https://github.com/rust-lang/rust/issues/131154) was stabilized + [#13695](https://github.com/rust-lang/rust-clippy/pull/13695) +* [`format_in_format_args`], [`recursive_format_impl`], [`to_string_in_format_args`], + [`uninlined_format_args`], [`unused_format_specs`]: Can now support 3rd party format macros + if they're marked with the `#[clippy::format_args]` attribute + [#9948](https://github.com/rust-lang/rust-clippy/pull/9948) + +### ICE Fixes + +* [`trait_duplication_in_bounds`]: fix ICE on duplicate type or constant bound + [#13722](https://github.com/rust-lang/rust-clippy/pull/13722) + +### Others + +* `clippy_utils` is now published to crates.io. Note that this crate is and will remain unstable. + [#13700](https://github.com/rust-lang/rust-clippy/pull/13700) ## Rust 1.84 -Current stable, released 2025-01-09 +Released 2025-01-09 [View all 84 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-10-03T21%3A23%3A58Z..2024-11-14T17%3A41%3A37Z+base%3Amaster) @@ -5530,6 +5572,7 @@ Released 2018-09-13 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression [`doc_include_without_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_include_without_cfg [`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation +[`doc_link_code`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_code [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs @@ -5549,6 +5592,7 @@ Released 2018-09-13 [`duplicated_attributes`]: https://rust-lang.github.io/rust-clippy/master/index.html#duplicated_attributes [`duration_subsec`]: https://rust-lang.github.io/rust-clippy/master/index.html#duration_subsec [`eager_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#eager_transmute +[`elidable_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#elidable_lifetime_names [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else [`empty_docs`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_docs [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop @@ -5683,6 +5727,7 @@ Released 2018-09-13 [`invalid_utf8_in_unchecked`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_utf8_in_unchecked [`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters +[`io_other_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module @@ -5742,6 +5787,7 @@ Released 2018-09-13 [`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 +[`manual_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_contains [`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil [`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map @@ -5761,6 +5807,7 @@ Released 2018-09-13 [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy +[`manual_midpoint`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint [`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_err`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_err @@ -5812,6 +5859,7 @@ Released 2018-09-13 [`mem_discriminant_non_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_discriminant_non_enum [`mem_forget`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_forget [`mem_replace_option_with_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_none +[`mem_replace_option_with_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_some [`mem_replace_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default [`mem_replace_with_uninit`]: https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_uninit [`min_ident_chars`]: https://rust-lang.github.io/rust-clippy/master/index.html#min_ident_chars @@ -5939,6 +5987,7 @@ Released 2018-09-13 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional [`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr +[`owned_cow`]: https://rust-lang.github.io/rust-clippy/master/index.html#owned_cow [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params @@ -6067,6 +6116,7 @@ Released 2018-09-13 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop [`single_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match [`single_match_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_match_else +[`single_option_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_option_map [`single_range_in_vec_init`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_range_in_vec_init [`size_of_in_element_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_in_element_count [`size_of_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#size_of_ref @@ -6143,6 +6193,7 @@ Released 2018-09-13 [`type_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_complexity [`type_id_on_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_id_on_box [`type_repetition_in_bounds`]: https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds +[`unbuffered_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#unbuffered_bytes [`unchecked_duration_subtraction`]: https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction [`unconditional_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#unconditional_recursion [`undocumented_unsafe_blocks`]: https://rust-lang.github.io/rust-clippy/master/index.html#undocumented_unsafe_blocks @@ -6161,6 +6212,7 @@ Released 2018-09-13 [`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns [`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast [`unnecessary_clippy_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_clippy_cfg +[`unnecessary_debug_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_debug_formatting [`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions [`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map [`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map @@ -6267,6 +6319,7 @@ Released 2018-09-13 [`accept-comment-above-statement`]: https://doc.rust-lang.org/clippy/lint_configuration.html#accept-comment-above-statement [`allow-comparison-to-zero`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-comparison-to-zero [`allow-dbg-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-dbg-in-tests +[`allow-expect-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-consts [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests [`allow-indexing-slicing-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-indexing-slicing-in-tests [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args @@ -6275,6 +6328,7 @@ Released 2018-09-13 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception [`allow-renamed-params-for`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-renamed-params-for +[`allow-unwrap-in-consts`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-consts [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests [`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles @@ -6290,6 +6344,7 @@ Released 2018-09-13 [`avoid-breaking-exported-api`]: https://doc.rust-lang.org/clippy/lint_configuration.html#avoid-breaking-exported-api [`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types [`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish +[`check-incompatible-msrv-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-incompatible-msrv-in-tests [`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items [`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold [`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index c9e4f15afbf8e..c4588002dc990 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy" # begin autogenerated version -version = "0.1.86" +version = "0.1.87" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" @@ -25,7 +25,7 @@ path = "src/driver.rs" [dependencies] clippy_config = { path = "clippy_config" } clippy_lints = { path = "clippy_lints" } -rustc_tools_util = "0.4.0" +rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } tempfile = { version = "3.3", optional = true } termize = "0.1" color-print = "0.3.4" @@ -54,7 +54,7 @@ parking_lot = "0.12" tokio = { version = "1", features = ["io-util"] } [build-dependencies] -rustc_tools_util = "0.4.0" +rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" } [features] integration = ["tempfile"] diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index 48506127dee40..0b9010f01071f 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -169,7 +169,7 @@ from the lint to the code of the test file and compare that to the contents of a Use `cargo bless` to automatically generate the `.fixed` file while running the tests. -[rustfix]: https://github.com/rust-lang/rustfix +[rustfix]: https://github.com/rust-lang/cargo/tree/master/crates/rustfix ## Testing manually @@ -460,7 +460,7 @@ pub struct ManualStrip { impl ManualStrip { pub fn new(conf: &'static Conf) -> Self { - Self { msrv: conf.msrv.clone() } + Self { msrv: conf.msrv } } } ``` @@ -469,24 +469,13 @@ The project's MSRV can then be matched against the feature MSRV in the LintPass using the `Msrv::meets` method. ``` rust -if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) { +if !self.msrv.meets(cx, msrvs::STR_STRIP_PREFIX) { return; } ``` -The project's MSRV can also be specified as an attribute, which overrides -the value from `clippy.toml`. This can be accounted for using the -`extract_msrv_attr!(LintContext)` macro and passing -`LateContext`/`EarlyContext`. - -```rust,ignore -impl<'tcx> LateLintPass<'tcx> for ManualStrip { - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - ... - } - extract_msrv_attr!(LateContext); -} -``` +Early lint passes should instead use `MsrvStack` coupled with +`extract_msrv_attr!()` Once the `msrv` is added to the lint, a relevant test case should be added to the lint's test file, `tests/ui/manual_strip.rs` in this example. It should @@ -512,8 +501,16 @@ in `clippy_config/src/conf.rs`: ```rust define_Conf! { - /// Lint: LIST, OF, LINTS, . The minimum rust version that the project supports - (msrv: Option = None), + #[lints( + allow_attributes, + allow_attributes_without_reason, + .. + , + .. + unused_trait_names, + use_self, + )] + msrv: Msrv = Msrv::default(), ... } ``` diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md index 166b6aab9fb3b..931e5c3a2942a 100644 --- a/src/tools/clippy/book/src/development/basics.md +++ b/src/tools/clippy/book/src/development/basics.md @@ -75,7 +75,7 @@ or if you modify a test file to add a test case. > _Note:_ This command may update more files than you intended. In that case > only commit the files you wanted to update. -[UI test]: https://rustc-dev-guide.rust-lang.org/tests/adding.html#guide-to-the-ui-tests +[UI test]: https://rustc-dev-guide.rust-lang.org/tests/adding.html#ui-test-walkthrough ## `cargo dev` diff --git a/src/tools/clippy/book/src/development/writing_tests.md b/src/tools/clippy/book/src/development/writing_tests.md index 39a5ad9668851..d4cca2a72f0be 100644 --- a/src/tools/clippy/book/src/development/writing_tests.md +++ b/src/tools/clippy/book/src/development/writing_tests.md @@ -203,7 +203,7 @@ We'll talk about suggestions more in depth in a [later chapter](emitting_lints.m Use `cargo bless` to automatically generate the `.fixed` file after running the tests. -[`rustfix`]: https://github.com/rust-lang/rustfix +[`rustfix`]: https://github.com/rust-lang/cargo/tree/master/crates/rustfix [`span_lint_and_sugg`]: https://doc.rust-lang.org/beta/nightly-rustc/clippy_utils/diagnostics/fn.span_lint_and_sugg.html ## Testing Manually diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index dab2630a56fc4..28b613ea32951 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -71,6 +71,16 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` * [`dbg_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#dbg_macro) +## `allow-expect-in-consts` +Whether `expect` should be allowed in code always evaluated at compile time + +**Default Value:** `true` + +--- +**Affected lints:** +* [`expect_used`](https://rust-lang.github.io/rust-clippy/master/index.html#expect_used) + + ## `allow-expect-in-tests` Whether `expect` should be allowed in test functions or `#[cfg(test)]` @@ -108,7 +118,7 @@ Whether to allow `r#""#` when `r""` can be used --- **Affected lints:** -* [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes) +* [`needless_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_raw_string_hashes) ## `allow-panic-in-tests` @@ -164,6 +174,16 @@ default configuration of Clippy. By default, any configuration will replace the * [`renamed_function_params`](https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params) +## `allow-unwrap-in-consts` +Whether `unwrap` should be allowed in code always evaluated at compile time + +**Default Value:** `true` + +--- +**Affected lints:** +* [`unwrap_used`](https://rust-lang.github.io/rust-clippy/master/index.html#unwrap_used) + + ## `allow-unwrap-in-tests` Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` @@ -360,6 +380,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat * [`linkedlist`](https://rust-lang.github.io/rust-clippy/master/index.html#linkedlist) * [`needless_pass_by_ref_mut`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_pass_by_ref_mut) * [`option_option`](https://rust-lang.github.io/rust-clippy/master/index.html#option_option) +* [`owned_cow`](https://rust-lang.github.io/rust-clippy/master/index.html#owned_cow) * [`rc_buffer`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_buffer) * [`rc_mutex`](https://rust-lang.github.io/rust-clippy/master/index.html#rc_mutex) * [`redundant_allocation`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_allocation) @@ -394,6 +415,16 @@ For internal testing only, ignores the current `publish` settings in the Cargo m * [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata) +## `check-incompatible-msrv-in-tests` +Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. + +**Default Value:** `false` + +--- +**Affected lints:** +* [`incompatible_msrv`](https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv) + + ## `check-private-items` Whether to also run the listed lints on private items. @@ -738,15 +769,21 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`from_over_into`](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into) * [`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) +* [`io_other_error`](https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error) * [`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) +* [`lines_filter_map_ok`](https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok) * [`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) +* [`manual_div_ceil`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil) +* [`manual_flatten`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten) * [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one) * [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check) * [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else) +* [`manual_midpoint`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint) * [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive) +* [`manual_option_as_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_option_as_slice) * [`manual_pattern_char_comparison`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_pattern_char_comparison) * [`manual_range_contains`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains) * [`manual_rem_euclid`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid) @@ -761,6 +798,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`map_unwrap_or`](https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or) * [`map_with_unused_argument_over_ranges`](https://rust-lang.github.io/rust-clippy/master/index.html#map_with_unused_argument_over_ranges) * [`match_like_matches_macro`](https://rust-lang.github.io/rust-clippy/master/index.html#match_like_matches_macro) +* [`mem_replace_option_with_some`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_option_with_some) * [`mem_replace_with_default`](https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default) * [`missing_const_for_fn`](https://rust-lang.github.io/rust-clippy/master/index.html#missing_const_for_fn) * [`needless_borrow`](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow) @@ -770,6 +808,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio * [`ptr_as_ptr`](https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr) * [`redundant_field_names`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names) * [`redundant_static_lifetimes`](https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes) +* [`repeat_vec_with_capacity`](https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity) * [`same_item_push`](https://rust-lang.github.io/rust-clippy/master/index.html#same_item_push) * [`seek_from_current`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current) * [`seek_rewind`](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind) diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml index e473a58394022..934725fccb8ec 100644 --- a/src/tools/clippy/clippy_config/Cargo.toml +++ b/src/tools/clippy/clippy_config/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_config" # begin autogenerated version -version = "0.1.86" +version = "0.1.87" # end autogenerated version edition = "2024" publish = false diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index a1591188bee71..a61acbaa96bcf 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -1,8 +1,8 @@ use crate::ClippyConfiguration; use crate::types::{ - DisallowedPath, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, Rename, SourceItemOrdering, - SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, SourceItemOrderingModuleItemKind, - SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds, + DisallowedPath, DisallowedPathWithoutReplacement, MacroMatcher, MatchLintBehaviour, PubUnderscoreFieldsBehaviour, + Rename, SourceItemOrdering, SourceItemOrderingCategory, SourceItemOrderingModuleItemGroupings, + SourceItemOrderingModuleItemKind, SourceItemOrderingTraitAssocItemKind, SourceItemOrderingTraitAssocItemKinds, }; use clippy_utils::msrvs::Msrv; use rustc_errors::Applicability; @@ -288,6 +288,9 @@ define_Conf! { /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]` #[lints(dbg_macro)] allow_dbg_in_tests: bool = false, + /// Whether `expect` should be allowed in code always evaluated at compile time + #[lints(expect_used)] + allow_expect_in_consts: bool = true, /// Whether `expect` should be allowed in test functions or `#[cfg(test)]` #[lints(expect_used)] allow_expect_in_tests: bool = false, @@ -298,7 +301,7 @@ define_Conf! { #[lints(uninlined_format_args)] allow_mixed_uninlined_format_args: bool = true, /// Whether to allow `r#""#` when `r""` can be used - #[lints(unnecessary_raw_string_hashes)] + #[lints(needless_raw_string_hashes)] allow_one_hash_in_raw_strings: bool = false, /// Whether `panic` should be allowed in test functions or `#[cfg(test)]` #[lints(panic)] @@ -325,6 +328,9 @@ define_Conf! { #[lints(renamed_function_params)] allow_renamed_params_for: Vec = DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect(), + /// Whether `unwrap` should be allowed in code always evaluated at compile time + #[lints(unwrap_used)] + allow_unwrap_in_consts: bool = true, /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]` #[lints(unwrap_used)] allow_unwrap_in_tests: bool = false, @@ -432,6 +438,7 @@ define_Conf! { linkedlist, needless_pass_by_ref_mut, option_option, + owned_cow, rc_buffer, rc_mutex, redundant_allocation, @@ -448,7 +455,7 @@ define_Conf! { avoid_breaking_exported_api: bool = true, /// The list of types which may not be held across an await point. #[lints(await_holding_invalid_type)] - await_holding_invalid_types: Vec = Vec::new(), + await_holding_invalid_types: Vec = Vec::new(), /// DEPRECATED LINT: BLACKLISTED_NAME. /// /// Use the Disallowed Names lint instead @@ -457,6 +464,9 @@ define_Conf! { /// For internal testing only, ignores the current `publish` settings in the Cargo manifest. #[lints(cargo_common_metadata)] cargo_ignore_publish: bool = false, + /// Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code. + #[lints(incompatible_msrv)] + check_incompatible_msrv_in_tests: bool = false, /// Whether to also run the listed lints on private items. #[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)] check_private_items: bool = false, @@ -607,15 +617,21 @@ define_Conf! { from_over_into, if_then_some_else_none, index_refutable_slice, + io_other_error, iter_kv_map, legacy_numeric_constants, + lines_filter_map_ok, manual_bits, manual_c_str_literals, manual_clamp, + manual_div_ceil, + manual_flatten, manual_hash_one, manual_is_ascii_check, manual_let_else, + manual_midpoint, manual_non_exhaustive, + manual_option_as_slice, manual_pattern_char_comparison, manual_range_contains, manual_rem_euclid, @@ -630,6 +646,7 @@ define_Conf! { map_unwrap_or, map_with_unused_argument_over_ranges, match_like_matches_macro, + mem_replace_option_with_some, mem_replace_with_default, missing_const_for_fn, needless_borrow, @@ -639,6 +656,7 @@ define_Conf! { ptr_as_ptr, redundant_field_names, redundant_static_lifetimes, + repeat_vec_with_capacity, same_item_push, seek_from_current, seek_rewind, @@ -652,7 +670,7 @@ define_Conf! { unused_trait_names, use_self, )] - msrv: Msrv = Msrv::empty(), + msrv: Msrv = Msrv::default(), /// The minimum size (in bytes) to consider a type for passing by reference instead of by value. #[lints(large_types_passed_by_value)] pass_by_value_size_limit: u64 = 256, diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs index c949db9109dee..c72291e9799f1 100644 --- a/src/tools/clippy/clippy_config/src/types.rs +++ b/src/tools/clippy/clippy_config/src/types.rs @@ -1,6 +1,8 @@ use clippy_utils::def_path_def_ids; +use rustc_errors::{Applicability, Diag}; use rustc_hir::def_id::DefIdMap; use rustc_middle::ty::TyCtxt; +use rustc_span::Span; use serde::de::{self, Deserializer, Visitor}; use serde::{Deserialize, Serialize, ser}; use std::collections::HashMap; @@ -12,37 +14,99 @@ pub struct Rename { pub rename: String, } -#[derive(Debug, Deserialize)] +pub type DisallowedPathWithoutReplacement = DisallowedPath; + +#[derive(Debug, Serialize)] +pub struct DisallowedPath { + path: String, + reason: Option, + replacement: Option, +} + +impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let enum_ = DisallowedPathEnum::deserialize(deserializer)?; + if !REPLACEMENT_ALLOWED && enum_.replacement().is_some() { + return Err(de::Error::custom("replacement not allowed for this configuration")); + } + Ok(Self { + path: enum_.path().to_owned(), + reason: enum_.reason().map(ToOwned::to_owned), + replacement: enum_.replacement().map(ToOwned::to_owned), + }) + } +} + +// `DisallowedPathEnum` is an implementation detail to enable the `Deserialize` implementation just +// above. `DisallowedPathEnum` is not meant to be used outside of this file. +#[derive(Debug, Deserialize, Serialize)] #[serde(untagged)] -pub enum DisallowedPath { +enum DisallowedPathEnum { Simple(String), - WithReason { path: String, reason: Option }, + WithReason { + path: String, + reason: Option, + replacement: Option, + }, } -impl DisallowedPath { +impl DisallowedPath { + pub fn path(&self) -> &str { + &self.path + } + + pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use<'_, REPLACEMENT_ALLOWED> { + move |diag| { + if let Some(replacement) = &self.replacement { + diag.span_suggestion( + span, + self.reason.as_ref().map_or_else(|| String::from("use"), Clone::clone), + replacement, + Applicability::MachineApplicable, + ); + } else if let Some(reason) = &self.reason { + diag.note(reason.clone()); + } + } + } +} + +impl DisallowedPathEnum { pub fn path(&self) -> &str { let (Self::Simple(path) | Self::WithReason { path, .. }) = self; path } - pub fn reason(&self) -> Option<&str> { + fn reason(&self) -> Option<&str> { match &self { Self::WithReason { reason, .. } => reason.as_deref(), Self::Simple(_) => None, } } + + fn replacement(&self) -> Option<&str> { + match &self { + Self::WithReason { replacement, .. } => replacement.as_deref(), + Self::Simple(_) => None, + } + } } /// Creates a map of disallowed items to the reason they were disallowed. -pub fn create_disallowed_map( +pub fn create_disallowed_map( tcx: TyCtxt<'_>, - disallowed: &'static [DisallowedPath], -) -> DefIdMap<(&'static str, Option<&'static str>)> { + disallowed: &'static [DisallowedPath], +) -> DefIdMap<(&'static str, &'static DisallowedPath)> { disallowed .iter() - .map(|x| (x.path(), x.path().split("::").collect::>(), x.reason())) - .flat_map(|(name, path, reason)| def_path_def_ids(tcx, &path).map(move |id| (id, (name, reason)))) + .map(|x| (x.path(), x.path().split("::").collect::>(), x)) + .flat_map(|(name, path, disallowed_path)| { + def_path_def_ids(tcx, &path).map(move |id| (id, (name, disallowed_path))) + }) .collect() } @@ -436,7 +500,6 @@ macro_rules! unimplemented_serialize { } unimplemented_serialize! { - DisallowedPath, Rename, MacroMatcher, } diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs index 75a4cbd2f92e0..05fa24d8d4ee5 100644 --- a/src/tools/clippy/clippy_dev/src/dogfood.rs +++ b/src/tools/clippy/clippy_dev/src/dogfood.rs @@ -4,7 +4,8 @@ use std::process::Command; /// # Panics /// /// Panics if unable to run the dogfood test -pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) { +#[allow(clippy::fn_params_excessive_bools)] +pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) { let mut cmd = Command::new("cargo"); cmd.current_dir(clippy_project_root()) @@ -25,6 +26,10 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) { dogfood_args.push("--allow-staged"); } + if allow_no_vcs { + dogfood_args.push("--allow-no-vcs"); + } + cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" ")); exit_if_err(cmd.status()); diff --git a/src/tools/clippy/clippy_dev/src/fmt.rs b/src/tools/clippy/clippy_dev/src/fmt.rs index 790dafa811f9e..bdddf46a2cb19 100644 --- a/src/tools/clippy/clippy_dev/src/fmt.rs +++ b/src/tools/clippy/clippy_dev/src/fmt.rs @@ -290,8 +290,13 @@ fn run_rustfmt(context: &FmtContext) -> Result<(), Error> { .filter_map(|entry| { let entry = entry.expect("failed to find tests"); let path = entry.path(); - - if path.extension() != Some("rs".as_ref()) || entry.file_name() == "ice-3891.rs" { + if path.extension() != Some("rs".as_ref()) + || path + .components() + .nth_back(1) + .is_some_and(|c| c.as_os_str() == "syntax-error-recovery") + || entry.file_name() == "ice-3891.rs" + { None } else { Some(entry.into_path().into_os_string()) diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs index 125195397e6c1..e0e036757d565 100644 --- a/src/tools/clippy/clippy_dev/src/lint.rs +++ b/src/tools/clippy/clippy_dev/src/lint.rs @@ -2,7 +2,7 @@ use crate::utils::{cargo_clippy_path, exit_if_err}; use std::process::{self, Command}; use std::{env, fs}; -pub fn run<'a>(path: &str, args: impl Iterator) { +pub fn run<'a>(path: &str, edition: &str, args: impl Iterator) { let is_file = match fs::metadata(path) { Ok(metadata) => metadata.is_file(), Err(e) => { @@ -17,7 +17,7 @@ pub fn run<'a>(path: &str, args: impl Iterator) { .args(["run", "--bin", "clippy-driver", "--"]) .args(["-L", "./target/debug"]) .args(["-Z", "no-codegen"]) - .args(["--edition", "2021"]) + .args(["--edition", edition]) .arg(path) .args(args) // Prevent rustc from creating `rustc-ice-*` files the console output is enough. diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index 56ed60256f162..074dea4ab77b6 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -17,7 +17,8 @@ fn main() { fix, allow_dirty, allow_staged, - } => dogfood::dogfood(fix, allow_dirty, allow_staged), + allow_no_vcs, + } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), DevCommand::Fmt { check, verbose } => fmt::run(check, verbose), DevCommand::UpdateLints { print_only, check } => { if print_only { @@ -34,7 +35,7 @@ fn main() { category, r#type, msrv, - } => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) { + } => match new_lint::create(pass, &name, &category, r#type.as_deref(), msrv) { Ok(()) => update_lints::update(utils::UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), }, @@ -53,7 +54,12 @@ fn main() { setup::git_hook::install_hook(force_override); } }, - SetupSubcommand::Toolchain { force, release, name } => setup::toolchain::create(force, release, &name), + SetupSubcommand::Toolchain { + standalone, + force, + release, + name, + } => setup::toolchain::create(standalone, force, release, &name), SetupSubcommand::VscodeTasks { remove, force_override } => { if remove { setup::vscode::remove_tasks(); @@ -68,7 +74,7 @@ fn main() { RemoveSubcommand::VscodeTasks => setup::vscode::remove_tasks(), }, DevCommand::Serve { port, lint } => serve::run(port, lint), - DevCommand::Lint { path, args } => lint::run(&path, args.iter()), + DevCommand::Lint { path, edition, args } => lint::run(&path, &edition, args.iter()), DevCommand::RenameLint { old_name, new_name, @@ -106,6 +112,9 @@ enum DevCommand { #[arg(long, requires = "fix")] /// Fix code even if the working directory has staged changes allow_staged: bool, + #[arg(long, requires = "fix")] + /// Fix code even if a VCS was not detected + allow_no_vcs: bool, }, /// Run rustfmt on all projects and tests Fmt { @@ -138,9 +147,9 @@ enum DevCommand { #[command(name = "new_lint")] /// Create a new lint and run `cargo dev update_lints` NewLint { - #[arg(short, long, value_parser = ["early", "late"], conflicts_with = "type", default_value = "late")] + #[arg(short, long, conflicts_with = "type", default_value = "late")] /// Specify whether the lint runs during the early or late pass - pass: String, + pass: new_lint::Pass, #[arg( short, long, @@ -206,6 +215,9 @@ enum DevCommand { /// cargo dev lint file.rs -- -W clippy::pedantic {n} /// cargo dev lint ~/my-project -- -- -W clippy::pedantic Lint { + /// The Rust edition to use + #[arg(long, default_value = "2024")] + edition: String, /// The path to a file or package directory to lint path: String, /// Pass extra arguments to cargo/clippy-driver @@ -264,14 +276,25 @@ enum SetupSubcommand { force_override: bool, }, /// Install a rustup toolchain pointing to the local clippy build + /// + /// This creates a toolchain with symlinks pointing at + /// `target/.../{clippy-driver,cargo-clippy}`, rebuilds of the project will be reflected in the + /// created toolchain unless `--standalone` is passed Toolchain { + #[arg(long, short)] + /// Create a standalone toolchain by copying the clippy binaries instead + /// of symlinking them + /// + /// Use this for example to create a toolchain, make a small change and then make another + /// toolchain with a different name in order to easily compare the two + standalone: bool, #[arg(long, short)] /// Override an existing toolchain force: bool, #[arg(long, short)] /// Point to --release clippy binary release: bool, - #[arg(long, default_value = "clippy")] + #[arg(long, short, default_value = "clippy")] /// Name of the toolchain name: String, }, diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index cc4b26867a206..96e12706c9e24 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -1,14 +1,28 @@ use crate::utils::{clippy_project_root, clippy_version}; +use clap::ValueEnum; use indoc::{formatdoc, writedoc}; -use std::fmt; -use std::fmt::Write as _; +use std::fmt::{self, Write as _}; use std::fs::{self, OpenOptions}; -use std::io::prelude::*; -use std::io::{self, ErrorKind}; +use std::io::{self, Write as _}; use std::path::{Path, PathBuf}; +#[derive(Clone, Copy, PartialEq, ValueEnum)] +pub enum Pass { + Early, + Late, +} + +impl fmt::Display for Pass { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + Pass::Early => "early", + Pass::Late => "late", + }) + } +} + struct LintData<'a> { - pass: &'a str, + pass: Pass, name: &'a str, category: &'a str, ty: Option<&'a str>, @@ -25,7 +39,7 @@ impl Context for io::Result { Ok(t) => Ok(t), Err(e) => { let message = format!("{}: {e}", text.as_ref()); - Err(io::Error::new(ErrorKind::Other, message)) + Err(io::Error::other(message)) }, } } @@ -36,7 +50,7 @@ impl Context for io::Result { /// # Errors /// /// This function errors out if the files couldn't be created or written to. -pub fn create(pass: &str, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> { +pub fn create(pass: Pass, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> { if category == "cargo" && ty.is_none() { // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo` ty = Some("cargo"); @@ -57,7 +71,7 @@ pub fn create(pass: &str, name: &str, category: &str, mut ty: Option<&str>, msrv add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?; } - if pass == "early" { + if pass == Pass::Early { println!( "\n\ NOTE: Use a late pass unless you need something specific from\n\ @@ -137,23 +151,17 @@ fn add_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> { let mut lib_rs = fs::read_to_string(path).context("reading")?; let comment_start = lib_rs.find("// add lints here,").expect("Couldn't find comment"); + let ctor_arg = if lint.pass == Pass::Late { "_" } else { "" }; + let lint_pass = lint.pass; + let module_name = lint.name; + let camel_name = to_camel_case(lint.name); let new_lint = if enable_msrv { format!( "store.register_{lint_pass}_pass(move |{ctor_arg}| Box::new({module_name}::{camel_name}::new(conf)));\n ", - lint_pass = lint.pass, - ctor_arg = if lint.pass == "late" { "_" } else { "" }, - module_name = lint.name, - camel_name = to_camel_case(lint.name), ) } else { - format!( - "store.register_{lint_pass}_pass(|{ctor_arg}| Box::new({module_name}::{camel_name}));\n ", - lint_pass = lint.pass, - ctor_arg = if lint.pass == "late" { "_" } else { "" }, - module_name = lint.name, - camel_name = to_camel_case(lint.name), - ) + format!("store.register_{lint_pass}_pass(|{ctor_arg}| Box::new({module_name}::{camel_name}));\n ",) }; lib_rs.insert_str(comment_start, &new_lint); @@ -243,11 +251,16 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { let mut result = String::new(); let (pass_type, pass_lifetimes, pass_import, context_import) = match lint.pass { - "early" => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), - "late" => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"), - _ => { - unreachable!("`pass_type` should only ever be `early` or `late`!"); - }, + Pass::Early => ("EarlyLintPass", "", "use rustc_ast::ast::*;", "EarlyContext"), + Pass::Late => ("LateLintPass", "<'_>", "use rustc_hir::*;", "LateContext"), + }; + let (msrv_ty, msrv_ctor, extract_msrv) = match lint.pass { + Pass::Early => ( + "MsrvStack", + "MsrvStack::new(conf.msrv)", + "\n extract_msrv_attr!();\n", + ), + Pass::Late => ("Msrv", "conf.msrv", ""), }; let lint_name = lint.name; @@ -259,10 +272,10 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { let _: fmt::Result = writedoc!( result, r" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_utils::msrvs::{{self, {msrv_ty}}}; use clippy_config::Conf; {pass_import} - use rustc_lint::{{{context_import}, {pass_type}, LintContext}}; + use rustc_lint::{{{context_import}, {pass_type}}}; use rustc_session::impl_lint_pass; " @@ -286,20 +299,18 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String { result, r" pub struct {name_camel} {{ - msrv: Msrv, + msrv: {msrv_ty}, }} impl {name_camel} {{ pub fn new(conf: &'static Conf) -> Self {{ - Self {{ msrv: conf.msrv.clone() }} + Self {{ msrv: {msrv_ctor} }} }} }} impl_lint_pass!({name_camel} => [{name_upper}]); - impl {pass_type}{pass_lifetimes} for {name_camel} {{ - extract_msrv_attr!({context_import}); - }} + impl {pass_type}{pass_lifetimes} for {name_camel} {{{extract_msrv}}} // TODO: Add MSRV level to `clippy_config/src/msrvs.rs` if needed. // TODO: Update msrv config comment in `clippy_config/src/conf.rs` @@ -376,9 +387,9 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let mod_file_path = ty_dir.join("mod.rs"); let context_import = setup_mod_file(&mod_file_path, lint)?; - let pass_lifetimes = match context_import { - "LateContext" => "<'_>", - _ => "", + let (pass_lifetimes, msrv_ty, msrv_ref, msrv_cx) = match context_import { + "LateContext" => ("<'_>", "Msrv", "", "cx, "), + _ => ("", "MsrvStack", "&", ""), }; let name_upper = lint.name.to_uppercase(); @@ -388,14 +399,14 @@ fn create_lint_for_ty(lint: &LintData<'_>, enable_msrv: bool, ty: &str) -> io::R let _: fmt::Result = writedoc!( lint_file_contents, r#" - use clippy_utils::msrvs::{{self, Msrv}}; + use clippy_utils::msrvs::{{self, {msrv_ty}}}; use rustc_lint::{{{context_import}, LintContext}}; use super::{name_upper}; // TODO: Adjust the parameters as necessary - pub(super) fn check(cx: &{context_import}{pass_lifetimes}, msrv: &Msrv) {{ - if !msrv.meets(todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{ + pub(super) fn check(cx: &{context_import}{pass_lifetimes}, msrv: {msrv_ref}{msrv_ty}) {{ + if !msrv.meets({msrv_cx}todo!("Add a new entry in `clippy_utils/src/msrvs`")) {{ return; }} todo!(); diff --git a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs index 8d98c6c92d9d1..2966629cf70a3 100644 --- a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs +++ b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs @@ -3,11 +3,14 @@ use std::env::current_dir; use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; +use std::process::Command; use walkdir::WalkDir; +use crate::utils::exit_if_err; + use super::verify_inside_clippy_dir; -pub fn create(force: bool, release: bool, name: &str) { +pub fn create(standalone: bool, force: bool, release: bool, name: &str) { if !verify_inside_clippy_dir() { return; } @@ -48,14 +51,22 @@ pub fn create(force: bool, release: bool, name: &str) { } } - symlink_bin("cargo-clippy", &dest, release); - symlink_bin("clippy-driver", &dest, release); + let status = Command::new("cargo") + .arg("build") + .args(release.then_some("--release")) + .status(); + exit_if_err(status); + + install_bin("cargo-clippy", &dest, standalone, release); + install_bin("clippy-driver", &dest, standalone, release); println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`"); - println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes"); + if !standalone { + println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes"); + } } -fn symlink_bin(bin: &str, dest: &Path, release: bool) { +fn install_bin(bin: &str, dest: &Path, standalone: bool, release: bool) { #[cfg(windows)] use std::os::windows::fs::symlink_file as symlink; @@ -71,5 +82,9 @@ fn symlink_bin(bin: &str, dest: &Path, release: bool) { let mut dest = dest.to_path_buf(); dest.extend(["bin", &file_name]); - symlink(src, dest).unwrap(); + if standalone { + fs::copy(src, dest).unwrap(); + } else { + symlink(src, dest).unwrap(); + } } diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index c62a7ec783b6f..54347043a13d4 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_lints" # begin autogenerated version -version = "0.1.86" +version = "0.1.87" # end autogenerated version description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs index 0f7f779e8ea71..4f55968d56257 100644 --- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs +++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, MsrvStack}; use clippy_utils::source::{trim_span, walk_span_to_context}; use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits}; use rustc_errors::Applicability; @@ -31,12 +31,12 @@ declare_clippy_lint! { impl_lint_pass!(AlmostCompleteRange => [ALMOST_COMPLETE_RANGE]); pub struct AlmostCompleteRange { - msrv: Msrv, + msrv: MsrvStack, } impl AlmostCompleteRange { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: MsrvStack::new(conf.msrv), } } } @@ -96,7 +96,7 @@ impl EarlyLintPass for AlmostCompleteRange { } } - extract_msrv_attr!(EarlyContext); + extract_msrv_attr!(); } fn is_incomplete_range(start: &Expr, end: &Expr) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 95f64b74044b1..9ae746c13b261 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -69,13 +69,11 @@ pub struct ApproxConstant { impl ApproxConstant { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } -impl<'tcx> LateLintPass<'tcx> for ApproxConstant { +impl LateLintPass<'_> for ApproxConstant { fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) { match lit.node { LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { @@ -89,8 +87,6 @@ impl<'tcx> LateLintPass<'tcx> for ApproxConstant { _ => (), } } - - extract_msrv_attr!(LateContext); } impl ApproxConstant { @@ -98,7 +94,7 @@ impl ApproxConstant { let s = s.as_str(); if s.parse::().is_ok() { for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS { - if is_approx_const(constant, s, min_digits) && msrv.is_none_or(|msrv| self.msrv.meets(msrv)) { + if is_approx_const(constant, s, min_digits) && msrv.is_none_or(|msrv| self.msrv.meets(cx, msrv)) { span_lint_and_help( cx, APPROX_CONSTANT, diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index aff40fa846be2..c0ae4960e10d9 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -362,7 +362,7 @@ impl<'tcx> LateLintPass<'tcx> for ArbitrarySourceItemOrdering { } } else if let ItemKind::ForeignMod { .. } = item.kind { continue; - } else if let ItemKind::GlobalAsm(_) = item.kind { + } else if let ItemKind::GlobalAsm { .. } = item.kind { continue; } else if let ItemKind::Use(path, use_kind) = item.kind { if path.segments.is_empty() { @@ -467,7 +467,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte ItemKind::Macro(..) => Macro, ItemKind::Mod(..) => Mod, ItemKind::ForeignMod { .. } => ForeignMod, - ItemKind::GlobalAsm(..) => GlobalAsm, + ItemKind::GlobalAsm { .. } => GlobalAsm, ItemKind::TyAlias(..) => TyAlias, ItemKind::Enum(..) => Enum, ItemKind::Struct(..) => Struct, diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs index 847653ed6e987..78102772927c0 100644 --- a/src/tools/clippy/clippy_lints/src/as_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs @@ -9,12 +9,24 @@ declare_clippy_lint! { /// Checks for usage of `as` conversions. /// /// Note that this lint is specialized in linting *every single* use of `as` - /// regardless of whether good alternatives exist or not. - /// If you want more precise lints for `as`, please consider using these separate lints: - /// `unnecessary_cast`, `cast_lossless/cast_possible_truncation/cast_possible_wrap/cast_precision_loss/cast_sign_loss`, - /// `fn_to_numeric_cast(_with_truncation)`, `char_lit_as_u8`, `ref_to_mut` and `ptr_as_ptr`. - /// There is a good explanation the reason why this lint should work in this way and how it is useful - /// [in this issue](https://github.com/rust-lang/rust-clippy/issues/5122). + /// regardless of whether good alternatives exist or not. If you want more + /// precise lints for `as`, please consider using these separate lints: + /// + /// - clippy::cast_lossless + /// - clippy::cast_possible_truncation + /// - clippy::cast_possible_wrap + /// - clippy::cast_precision_loss + /// - clippy::cast_sign_loss + /// - clippy::char_lit_as_u8 + /// - clippy::fn_to_numeric_cast + /// - clippy::fn_to_numeric_cast_with_truncation + /// - clippy::ptr_as_ptr + /// - clippy::unnecessary_cast + /// - invalid_reference_casting + /// + /// There is a good explanation the reason why this lint should work in this + /// way and how it is useful [in this + /// issue](https://github.com/rust-lang/rust-clippy/issues/5122). /// /// ### Why restrict this? /// `as` conversions will perform many kinds of diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 348495f97a27b..ab34af7c31745 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -59,9 +59,7 @@ pub struct AssigningClones { impl AssigningClones { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -90,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone, _ if fn_name.as_str() == "to_owned" && is_diag_trait_item(cx, fn_id, sym::ToOwned) - && self.msrv.meets(msrvs::CLONE_INTO) => + && self.msrv.meets(cx, msrvs::CLONE_INTO) => { CloneTrait::ToOwned }, @@ -143,8 +141,6 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { ); } } - - extract_msrv_attr!(LateContext); } /// Checks if the data being cloned borrows from the place that is being assigned to: diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs index 3a462018e3e04..cd38aed26a3e0 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -1,12 +1,12 @@ use super::{Attribute, DEPRECATED_CFG_ATTR, DEPRECATED_CLIPPY_CFG_ATTR, unnecessary_clippy_cfg}; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, MsrvStack}; use rustc_ast::AttrStyle; use rustc_errors::Applicability; use rustc_lint::EarlyContext; use rustc_span::sym; -pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msrv) { +pub(super) fn check(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &MsrvStack) { // check cfg_attr if attr.has_name(sym::cfg_attr) && let Some(items) = 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 2325f914b0b0c..cb63fadb4e21c 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs @@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att span_lint( cx, INLINE_ALWAYS, - attr.span, + attr.span(), format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), ); } 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 5a26ba8bf932c..d71c8e9894bf7 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,4 +1,3 @@ -use std::sync::Arc; use super::MIXED_ATTRIBUTES_STYLE; use clippy_utils::diagnostics::span_lint; use rustc_ast::{AttrKind, AttrStyle, Attribute}; @@ -6,6 +5,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_lint::{EarlyContext, LintContext}; use rustc_span::source_map::SourceMap; use rustc_span::{SourceFile, Span, Symbol}; +use std::sync::Arc; #[derive(Hash, PartialEq, Eq)] enum SimpleAttrKind { diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs index 92efd1a4ddcda..f9a2f011a144f 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs @@ -14,7 +14,7 @@ mod useless_attribute; mod utils; use clippy_config::Conf; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, Msrv, MsrvStack}; use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind}; use rustc_hir::{ImplItem, Item, TraitItem}; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -305,7 +305,7 @@ declare_clippy_lint! { /// header_version: u16 /// } /// ``` - #[clippy::version = "1.84.0"] + #[clippy::version = "1.85.0"] pub REPR_PACKED_WITHOUT_ABI, suspicious, "ensures that `repr(packed)` always comes with a qualified ABI" @@ -459,44 +459,40 @@ impl_lint_pass!(Attributes => [ impl Attributes { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); if is_relevant_item(cx, item) { inline_always::check(cx, item.span, item.ident.name, attrs); } - repr_attributes::check(cx, item.span, attrs, &self.msrv); + repr_attributes::check(cx, item.span, attrs, self.msrv); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if is_relevant_impl(cx, item) { - inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); + inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir_attrs(item.hir_id())); } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if is_relevant_trait(cx, item) { - inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); + inline_always::check(cx, item.span, item.ident.name, cx.tcx.hir_attrs(item.hir_id())); } } - - extract_msrv_attr!(LateContext); } pub struct EarlyAttributes { - msrv: Msrv, + msrv: MsrvStack, } impl EarlyAttributes { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: MsrvStack::new(conf.msrv), } } } @@ -515,17 +511,17 @@ impl EarlyLintPass for EarlyAttributes { non_minimal_cfg::check(cx, attr); } - extract_msrv_attr!(EarlyContext); + extract_msrv_attr!(); } pub struct PostExpansionEarlyAttributes { - msrv: Msrv, + msrv: MsrvStack, } impl PostExpansionEarlyAttributes { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: MsrvStack::new(conf.msrv), } } } @@ -589,5 +585,5 @@ impl EarlyLintPass for PostExpansionEarlyAttributes { duplicated_attributes::check(cx, &item.attrs); } - extract_msrv_attr!(EarlyContext); + extract_msrv_attr!(); } diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs index 6d1ab46aa0c1f..e5cfbaf952a70 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs @@ -1,43 +1,39 @@ +use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; use rustc_hir::Attribute; use rustc_lint::LateContext; -use rustc_span::{Span, sym}; +use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs; +use clippy_utils::msrvs::{self, Msrv}; use super::REPR_PACKED_WITHOUT_ABI; -pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], msrv: &msrvs::Msrv) { - if msrv.meets(msrvs::REPR_RUST) { - check_packed(cx, item_span, attrs); - } -} +pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute], msrv: Msrv) { + if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) { + let packed_span = reprs + .iter() + .find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..))) + .map(|(_, s)| *s); -fn check_packed(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) { - if let Some(items) = attrs.iter().find_map(|attr| { - if attr.ident().is_some_and(|ident| matches!(ident.name, sym::repr)) { - attr.meta_item_list() - } else { - None - } - }) && let Some(packed) = items - .iter() - .find(|item| item.ident().is_some_and(|ident| matches!(ident.name, sym::packed))) - && !items.iter().any(|item| { - item.ident() - .is_some_and(|ident| matches!(ident.name, sym::C | sym::Rust)) - }) - { - span_lint_and_then( - cx, - REPR_PACKED_WITHOUT_ABI, - item_span, - "item uses `packed` representation without ABI-qualification", - |diag| { - diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI") + if let Some(packed_span) = packed_span + && !reprs + .iter() + .any(|(x, _)| *x == ReprAttr::ReprC || *x == ReprAttr::ReprRust) + && msrv.meets(cx, msrvs::REPR_RUST) + { + span_lint_and_then( + cx, + REPR_PACKED_WITHOUT_ABI, + item_span, + "item uses `packed` representation without ABI-qualification", + |diag| { + diag.warn( + "unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI", + ) .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`") - .span_label(packed.span(), "`packed` representation set here"); - }, - ); + .span_label(packed_span, "`packed` representation set here"); + }, + ); + } } } 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 478ba7a187be5..6ee3290fa761d 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 @@ -15,7 +15,7 @@ pub(super) fn check( ) { if cfg_attr.has_name(sym::clippy) && let Some(ident) = behind_cfg_attr.ident() - && Level::from_symbol(ident.name, Some(attr.id)).is_some() + && Level::from_symbol(ident.name, || Some(attr.id)).is_some() && let Some(items) = behind_cfg_attr.meta_item_list() { let nb_items = items.len(); diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs index a667649f73435..0e650e4939252 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs @@ -17,7 +17,7 @@ pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool { } pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool { - Level::from_symbol(symbol, Some(attr_id)).is_some() + Level::from_symbol(symbol, || Some(attr_id)).is_some() } pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool { 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 2eb0566bf9a61..92a0c7f9acbcd 100644 --- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs +++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_config::types::create_disallowed_map; +use clippy_config::types::{DisallowedPathWithoutReplacement, create_disallowed_map}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{match_def_path, paths}; use rustc_hir as hir; @@ -174,7 +174,7 @@ declare_clippy_lint! { impl_lint_pass!(AwaitHolding => [AWAIT_HOLDING_LOCK, AWAIT_HOLDING_REFCELL_REF, AWAIT_HOLDING_INVALID_TYPE]); pub struct AwaitHolding { - def_ids: DefIdMap<(&'static str, Option<&'static str>)>, + def_ids: DefIdMap<(&'static str, &'static DisallowedPathWithoutReplacement)>, } impl AwaitHolding { @@ -247,25 +247,26 @@ impl AwaitHolding { ); }, ); - } else if let Some(&(path, reason)) = self.def_ids.get(&adt.did()) { - emit_invalid_type(cx, ty_cause.source_info.span, path, reason); + } else if let Some(&(path, disallowed_path)) = self.def_ids.get(&adt.did()) { + emit_invalid_type(cx, ty_cause.source_info.span, path, disallowed_path); } } } } } -fn emit_invalid_type(cx: &LateContext<'_>, span: Span, path: &'static str, reason: Option<&'static str>) { +fn emit_invalid_type( + cx: &LateContext<'_>, + span: Span, + path: &'static str, + disallowed_path: &'static DisallowedPathWithoutReplacement, +) { span_lint_and_then( cx, AWAIT_HOLDING_INVALID_TYPE, span, format!("holding a disallowed type across an await point `{path}`"), - |diag| { - if let Some(reason) = reason { - diag.note(reason); - } - }, + disallowed_path.diag_amendment(span), ); } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index f30f16997d767..48b5d4da88860 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -3,6 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::eq_expr_value; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; +use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use rustc_ast::ast::LitKind; use rustc_attr_parsing::RustcVersion; @@ -84,9 +85,7 @@ pub struct NonminimalBool { impl NonminimalBool { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -102,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: Span, _: LocalDefId, ) { - NonminimalBoolVisitor { cx, msrv: &self.msrv }.visit_body(body); + NonminimalBoolVisitor { cx, msrv: self.msrv }.visit_body(body); } fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { @@ -119,8 +118,6 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _ => {}, } } - - extract_msrv_attr!(LateContext); } fn inverted_bin_op_eq_str(op: BinOpKind) -> Option<&'static str> { @@ -197,7 +194,7 @@ fn check_inverted_bool_in_condition( ); } -fn check_simplify_not(cx: &LateContext<'_>, msrv: &Msrv, expr: &Expr<'_>) { +fn check_simplify_not(cx: &LateContext<'_>, msrv: Msrv, expr: &Expr<'_>) { if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind && !expr.span.from_expansion() && !inner.span.from_expansion() @@ -233,7 +230,7 @@ fn check_simplify_not(cx: &LateContext<'_>, msrv: &Msrv, expr: &Expr<'_>) { struct NonminimalBoolVisitor<'a, 'tcx> { cx: &'a LateContext<'tcx>, - msrv: &'a Msrv, + msrv: Msrv, } use quine_mc_cluskey::Bool; @@ -326,7 +323,7 @@ impl<'v> Hir2Qmm<'_, '_, 'v> { struct SuggestContext<'a, 'tcx, 'v> { terminals: &'v [&'v Expr<'v>], cx: &'a LateContext<'tcx>, - msrv: &'a Msrv, + msrv: Msrv, output: String, } @@ -353,7 +350,8 @@ impl SuggestContext<'_, '_, '_> { self.output.push_str(&str); } else { self.output.push('!'); - self.output.push_str(&terminal.span.get_source_text(self.cx)?); + self.output + .push_str(&Sugg::hir_opt(self.cx, terminal)?.maybe_par().to_string()); } }, True | False | Not(_) => { @@ -396,7 +394,7 @@ impl SuggestContext<'_, '_, '_> { } } -fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Option { +fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Option { match &expr.kind { ExprKind::Binary(binop, lhs, rhs) => { if !implements_ord(cx, lhs) { @@ -438,7 +436,9 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Opti .iter() .copied() .flat_map(|(msrv, a, b)| vec![(msrv, a, b), (msrv, b, a)]) - .find(|&(msrv, a, _)| msrv.is_none_or(|msrv| curr_msrv.meets(msrv)) && a == path.ident.name.as_str()) + .find(|&(msrv, a, _)| { + a == path.ident.name.as_str() && msrv.is_none_or(|msrv| curr_msrv.meets(cx, msrv)) + }) .and_then(|(_, _, neg_method)| { let negated_args = args .iter() @@ -467,7 +467,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: &Msrv, expr: &Expr<'_>) -> Opti } } -fn suggest(cx: &LateContext<'_>, msrv: &Msrv, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String { +fn suggest(cx: &LateContext<'_>, msrv: Msrv, suggestion: &Bool, terminals: &[&Expr<'_>]) -> String { let mut suggest_context = SuggestContext { terminals, cx, @@ -553,7 +553,7 @@ impl<'tcx> NonminimalBoolVisitor<'_, 'tcx> { _ => simplified.push(Bool::Not(Box::new(simple.clone()))), } let simple_negated = simple_negate(simple); - if simplified.iter().any(|s| *s == simple_negated) { + if simplified.contains(&simple_negated) { continue; } simplified.push(simple_negated); diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs index 6057144bc6a4b..d143629da3a0d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs @@ -16,7 +16,7 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'_>, cast_expr: &'tcx Expr<'_>, cast_to: &'tcx Ty<'_>, - msrv: &Msrv, + msrv: Msrv, ) -> bool { if matches!(cast_to.kind, TyKind::Ptr(_)) && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind @@ -34,7 +34,7 @@ pub(super) fn check<'tcx>( return false; } - let (suggestion, span) = if msrv.meets(msrvs::RAW_REF_OP) { + let (suggestion, span) = if msrv.meets(cx, msrvs::RAW_REF_OP) { let operator_kind = match mutability { Mutability::Not => "const", Mutability::Mut => "mut", 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 ae433773193a8..8b3529e84fc6e 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 @@ -14,13 +14,13 @@ pub(super) fn check( cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, - msrv: &Msrv, + msrv: Msrv, ) { - if msrv.meets(msrvs::UNSIGNED_ABS) - && let ty::Int(from) = cast_from.kind() + if let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() && let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind && method_path.ident.name.as_str() == "abs" + && msrv.meets(cx, msrvs::UNSIGNED_ABS) { let span = if from.bit_width() == to.bit_width() { expr.span 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 c326a0d935c74..3ae43732dc03f 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -19,7 +19,7 @@ pub(super) fn check( cast_from: Ty<'_>, cast_to: Ty<'_>, cast_to_hir: &rustc_hir::Ty<'_>, - msrv: &Msrv, + msrv: Msrv, ) { if !should_lint(cx, cast_from, cast_to, msrv) { return; @@ -70,7 +70,7 @@ pub(super) fn check( ); } -fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool { +fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: Msrv) -> bool { // Do not suggest using From in consts/statics until it is valid to do so (see #2267). if is_in_const_context(cx) { return false; @@ -96,7 +96,7 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: & }; !is_isize_or_usize(cast_from) && from_nbits < to_nbits }, - (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(msrvs::FROM_BOOL) => true, + (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(cx, msrvs::FROM_BOOL) => true, (_, _) => { matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) }, 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 45045e58ac75e..c8abf9dac9af5 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 @@ -142,11 +142,11 @@ fn expr_sign<'cx, 'tcx>(cx: &LateContext<'cx>, mut expr: &'tcx Expr<'tcx>, ty: i expr = recv; } - if METHODS_POW.iter().any(|&name| method_name == name) + if METHODS_POW.contains(&method_name) && let [arg] = args { return pow_call_result_sign(cx, caller, arg); - } else if METHODS_RET_POSITIVE.iter().any(|&name| method_name == name) { + } else if METHODS_RET_POSITIVE.contains(&method_name) { return Sign::ZeroOrPositive; } } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs index 030c2d322db6d..c48f253606dcc 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs @@ -9,12 +9,7 @@ use rustc_middle::ty::{self, Ty, TypeAndMut}; use super::CAST_SLICE_DIFFERENT_SIZES; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv) { - // suggestion is invalid if `ptr::slice_from_raw_parts` does not exist - if !msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) { - return; - } - +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) { // if this cast is the child of another cast expression then don't emit something for it, the full // chain will be analyzed if is_child_of_cast(cx, expr) { @@ -30,7 +25,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) { let from_size = from_layout.size.bytes(); let to_size = to_layout.size.bytes(); - if from_size != to_size && from_size != 0 && to_size != 0 { + if from_size != to_size && from_size != 0 && to_size != 0 && msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) { span_lint_and_then( cx, CAST_SLICE_DIFFERENT_SIZES, 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 c3bc5c0c9f2a9..46b0c88d3feda 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 @@ -23,9 +23,8 @@ fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option { } } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: &Msrv) { - if msrv.meets(msrvs::PTR_SLICE_RAW_PARTS) - && let ty::RawPtr(ptrty, _) = cast_to.kind() +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>, msrv: Msrv) { + if let ty::RawPtr(ptrty, _) = cast_to.kind() && let ty::Slice(_) = ptrty.kind() && let ExprKind::Call(fun, [ptr_arg, len_arg]) = cast_expr.peel_blocks().kind && let ExprKind::Path(ref qpath) = fun.kind @@ -33,6 +32,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, && let Some(rpk) = raw_parts_kind(cx, fun_def_id) && let ctxt = expr.span.ctxt() && cast_expr.span.ctxt() == ctxt + && msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) { let func = match rpk { RawPartsKind::Immutable => "from_raw_parts", diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index 521bd394901a6..dc2a1fa85bf5c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -134,8 +134,14 @@ declare_clippy_lint! { /// /// ### Example /// ```no_run - /// u32::MAX as i32; // will yield a value of `-1` + /// let _ = u32::MAX as i32; // will yield a value of `-1` /// ``` + /// + /// Use instead: + /// ```no_run + /// let _ = i32::try_from(u32::MAX).ok(); + /// ``` + /// #[clippy::version = "pre 1.29.0"] pub CAST_POSSIBLE_WRAP, pedantic, @@ -747,7 +753,7 @@ declare_clippy_lint! { /// t as *const T as usize /// } /// ``` - #[clippy::version = "1.81.0"] + #[clippy::version = "1.85.0"] pub AS_POINTER_UNDERSCORE, restriction, "detects `as *mut _` and `as *const _` conversion" @@ -759,9 +765,7 @@ pub struct Casts { impl Casts { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -811,8 +815,8 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) { return; } - cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, &self.msrv); - ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv); + cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, self.msrv); + ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to); @@ -825,29 +829,27 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to); - cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv); + cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to); } - cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, &self.msrv); + cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, self.msrv); cast_enum_constructor::check(cx, expr, cast_from_expr, cast_from); } as_underscore::check(cx, expr, cast_to_hir); as_pointer_underscore::check(cx, cast_to, cast_to_hir); - let was_borrow_as_ptr_emitted = self.msrv.meets(msrvs::BORROW_AS_PTR) - && borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, &self.msrv); - if self.msrv.meets(msrvs::PTR_FROM_REF) && !was_borrow_as_ptr_emitted { + let was_borrow_as_ptr_emitted = self.msrv.meets(cx, msrvs::BORROW_AS_PTR) + && borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir, self.msrv); + if !was_borrow_as_ptr_emitted && self.msrv.meets(cx, msrvs::PTR_FROM_REF) { ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir); } } cast_ptr_alignment::check(cx, expr); char_lit_as_u8::check(cx, expr); - ptr_as_ptr::check(cx, expr, &self.msrv); - cast_slice_different_sizes::check(cx, expr, &self.msrv); + ptr_as_ptr::check(cx, expr, self.msrv); + cast_slice_different_sizes::check(cx, expr, self.msrv); ptr_cast_constness::check_null_ptr_cast_method(cx, expr); } - - extract_msrv_attr!(LateContext); } 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 bdc389d39dd37..d57e391b55d54 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 @@ -26,11 +26,7 @@ impl OmitFollowedCastReason<'_> { } } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { - if !msrv.meets(msrvs::POINTER_CAST) { - return; - } - +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr)) && let ty::RawPtr(_, from_mutbl) = cast_from.kind() @@ -40,6 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) { // The `U` in `pointer::cast` have to be `Sized` // as explained here: https://github.com/rust-lang/rust/issues/60602. && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) + && msrv.meets(cx, msrvs::POINTER_CAST) { let mut app = Applicability::MachineApplicable; let turbofish = match &cast_to_hir_ty.kind { 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 945c05ee94365..cad9c1df273f0 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 @@ -16,7 +16,7 @@ pub(super) fn check<'tcx>( cast_expr: &Expr<'_>, cast_from: Ty<'tcx>, cast_to: Ty<'tcx>, - msrv: &Msrv, + msrv: Msrv, ) { if let ty::RawPtr(from_ty, from_mutbl) = cast_from.kind() && let ty::RawPtr(to_ty, to_mutbl) = cast_to.kind() @@ -52,7 +52,7 @@ pub(super) fn check<'tcx>( return; } - if msrv.meets(msrvs::POINTER_CAST_CONSTNESS) { + if msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) { let sugg = Sugg::hir(cx, cast_expr, "_"); let constness = match *to_mutbl { Mutability::Not => "const", diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 9516af7334d7f..b36c8662289ca 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -39,9 +39,7 @@ pub struct CheckedConversions { impl CheckedConversions { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -65,7 +63,6 @@ impl LateLintPass<'_> for CheckedConversions { } && !item.span.in_external_macro(cx.sess().source_map()) && !is_in_const_context(cx) - && self.msrv.meets(msrvs::TRY_FROM) && let Some(cv) = match op2 { // todo: check for case signed -> larger unsigned == only x >= 0 None => check_upper_bound(lt1, gt1).filter(|cv| cv.cvt == ConversionType::FromUnsigned), @@ -79,6 +76,7 @@ impl LateLintPass<'_> for CheckedConversions { }, } && let Some(to_type) = cv.to_type + && self.msrv.meets(cx, msrvs::TRY_FROM) { let mut applicability = Applicability::MachineApplicable; let snippet = snippet_with_applicability(cx, cv.expr_to_cast.span, "_", &mut applicability); @@ -93,8 +91,6 @@ impl LateLintPass<'_> for CheckedConversions { ); } } - - extract_msrv_attr!(LateContext); } /// Contains the result of a tried conversion check diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 89808d38b9f39..03ed9c657b30a 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -18,7 +18,6 @@ use rustc_session::impl_lint_pass; use rustc_span::hygiene::walk_chain; use rustc_span::source_map::SourceMap; use rustc_span::{Span, Symbol}; -use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -130,11 +129,6 @@ declare_clippy_lint! { /// ### Why is this bad? /// Duplicate code is less maintainable. /// - /// ### Known problems - /// * The lint doesn't check if the moved expressions modify values that are being used in - /// the if condition. The suggestion can in that case modify the behavior of the program. - /// See [rust-clippy#7452](https://github.com/rust-lang/rust-clippy/issues/7452) - /// /// ### Example /// ```ignore /// let foo = if … { @@ -248,18 +242,18 @@ fn lint_branches_sharing_code<'tcx>( let first_line_span = first_line_of_span(cx, expr.span); let replace_span = first_line_span.with_hi(span.hi()); let cond_span = first_line_span.until(first_block.span); - let cond_snippet = reindent_multiline(snippet(cx, cond_span, "_"), false, None); + let cond_snippet = reindent_multiline(&snippet(cx, cond_span, "_"), false, None); let cond_indent = indent_of(cx, cond_span); - let moved_snippet = reindent_multiline(snippet(cx, span, "_"), true, None); + let moved_snippet = reindent_multiline(&snippet(cx, span, "_"), true, None); let suggestion = moved_snippet.to_string() + "\n" + &cond_snippet + "{"; - let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, cond_indent); + let suggestion = reindent_multiline(&suggestion, true, cond_indent); (replace_span, suggestion.to_string()) }); let end_suggestion = res.end_span(last_block, sm).map(|span| { - let moved_snipped = reindent_multiline(snippet(cx, span, "_"), true, None); + let moved_snipped = reindent_multiline(&snippet(cx, span, "_"), true, None); let indent = indent_of(cx, expr.span.shrink_to_hi()); let suggestion = "}\n".to_string() + &moved_snipped; - let suggestion = reindent_multiline(Cow::Borrowed(&suggestion), true, indent); + let suggestion = reindent_multiline(&suggestion, true, indent); let span = span.with_hi(last_block.span.hi()); // Improve formatting if the inner block has indention (i.e. normal Rust formatting) diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 5c5978b555985..0834618499c7b 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -139,6 +139,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::disallowed_types::DISALLOWED_TYPES_INFO, crate::doc::DOC_INCLUDE_WITHOUT_CFG_INFO, crate::doc::DOC_LAZY_CONTINUATION_INFO, + crate::doc::DOC_LINK_CODE_INFO, crate::doc::DOC_LINK_WITH_QUOTES_INFO, crate::doc::DOC_MARKDOWN_INFO, crate::doc::DOC_NESTED_REFDEFS_INFO, @@ -192,6 +193,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO, crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO, crate::format_args::UNINLINED_FORMAT_ARGS_INFO, + crate::format_args::UNNECESSARY_DEBUG_FORMATTING_INFO, crate::format_args::UNUSED_FORMAT_SPECS_INFO, crate::format_impl::PRINT_IN_FORMAT_IMPL_INFO, crate::format_impl::RECURSIVE_FORMAT_IMPL_INFO, @@ -272,6 +274,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::let_underscore::LET_UNDERSCORE_MUST_USE_INFO, crate::let_underscore::LET_UNDERSCORE_UNTYPED_INFO, crate::let_with_type_underscore::LET_WITH_TYPE_UNDERSCORE_INFO, + crate::lifetimes::ELIDABLE_LIFETIME_NAMES_INFO, crate::lifetimes::EXTRA_UNUSED_LIFETIMES_INFO, crate::lifetimes::NEEDLESS_LIFETIMES_INFO, crate::lines_filter_map_ok::LINES_FILTER_MAP_OK_INFO, @@ -362,6 +365,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO, crate::matches::WILDCARD_IN_OR_PATTERNS_INFO, crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO, + crate::mem_replace::MEM_REPLACE_OPTION_WITH_SOME_INFO, crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO, crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO, crate::methods::BIND_INSTEAD_OF_MAP_INFO, @@ -398,6 +402,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::INEFFICIENT_TO_STRING_INFO, crate::methods::INSPECT_FOR_EACH_INFO, crate::methods::INTO_ITER_ON_REF_INFO, + crate::methods::IO_OTHER_ERROR_INFO, crate::methods::IS_DIGIT_ASCII_RADIX_INFO, crate::methods::ITERATOR_STEP_BY_ZERO_INFO, crate::methods::ITER_CLONED_COLLECT_INFO, @@ -416,6 +421,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_SKIP_ZERO_INFO, crate::methods::ITER_WITH_DRAIN_INFO, crate::methods::JOIN_ABSOLUTE_PATHS_INFO, + crate::methods::MANUAL_CONTAINS_INFO, crate::methods::MANUAL_C_STR_LITERALS_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, @@ -452,7 +458,6 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::OPTION_AS_REF_CLONED_INFO, crate::methods::OPTION_AS_REF_DEREF_INFO, crate::methods::OPTION_FILTER_MAP_INFO, - crate::methods::OPTION_MAP_OR_ERR_OK_INFO, crate::methods::OPTION_MAP_OR_NONE_INFO, crate::methods::OR_FUN_CALL_INFO, crate::methods::OR_THEN_UNWRAP_INFO, @@ -483,6 +488,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::SUSPICIOUS_SPLITN_INFO, crate::methods::SUSPICIOUS_TO_OWNED_INFO, crate::methods::TYPE_ID_ON_BOX_INFO, + crate::methods::UNBUFFERED_BYTES_INFO, crate::methods::UNINIT_ASSUMED_INIT_INFO, crate::methods::UNIT_HASH_INFO, crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO, @@ -602,6 +608,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::operators::IMPOSSIBLE_COMPARISONS_INFO, crate::operators::INEFFECTIVE_BIT_MASK_INFO, crate::operators::INTEGER_DIVISION_INFO, + crate::operators::MANUAL_MIDPOINT_INFO, crate::operators::MISREFACTORED_ASSIGN_OP_INFO, crate::operators::MODULO_ARITHMETIC_INFO, crate::operators::MODULO_ONE_INFO, @@ -684,6 +691,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::single_call_fn::SINGLE_CALL_FN_INFO, crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO, crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO, + crate::single_option_map::SINGLE_OPTION_MAP_INFO, crate::single_range_in_vec_init::SINGLE_RANGE_IN_VEC_INIT_INFO, crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO, crate::size_of_ref::SIZE_OF_REF_INFO, @@ -741,6 +749,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::types::BOX_COLLECTION_INFO, crate::types::LINKEDLIST_INFO, crate::types::OPTION_OPTION_INFO, + crate::types::OWNED_COW_INFO, crate::types::RC_BUFFER_INFO, crate::types::RC_MUTEX_INFO, crate::types::REDUNDANT_ALLOCATION_INFO, 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 9f020d3081c40..7c64bf46e7bd2 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; use rustc_hir::{HirId, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, FieldDef}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -97,16 +97,7 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR } fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - cx.tcx.hir().attrs(hir_id).iter().any(|attr| { - if attr.has_name(sym::repr) { - if let Some(items) = attr.meta_item_list() { - for item in items { - if item.is_word() && matches!(item.name_or_empty(), sym::C) { - return true; - } - } - } - } - false - }) + let attrs = cx.tcx.hir_attrs(hir_id); + + find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC)) } diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 5604172d6f309..0031da406f17f 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -40,6 +40,8 @@ declare_with_version! { DEPRECATED(DEPRECATED_VERSION): &[(&str, &str)] = &[ ("clippy::pub_enum_variant_names", "`clippy::enum_variant_names` now covers this case via the `avoid-breaking-exported-api` config"), #[clippy::version = "1.54.0"] ("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"), + #[clippy::version = "1.86.0"] + ("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"), // end deprecated lints. used by `cargo dev deprecate_lint` ]} diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs index bb445e0155f65..8d9222e4bf61e 100644 --- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs +++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs @@ -62,9 +62,7 @@ pub struct DerivableImpls { impl DerivableImpls { pub fn new(conf: &'static Conf) -> Self { - DerivableImpls { - msrv: conf.msrv.clone(), - } + DerivableImpls { msrv: conf.msrv } } } @@ -199,17 +197,15 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls { && let ImplItemKind::Fn(_, b) = &impl_item.kind && let Body { value: func_expr, .. } = cx.tcx.hir_body(*b) && let &ty::Adt(adt_def, args) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind() - && let attrs = cx.tcx.hir().attrs(item.hir_id()) + && let attrs = cx.tcx.hir_attrs(item.hir_id()) && !attrs.iter().any(|attr| attr.doc_str().is_some()) - && cx.tcx.hir().attrs(impl_item_hir).is_empty() + && cx.tcx.hir_attrs(impl_item_hir).is_empty() { if adt_def.is_struct() { check_struct(cx, item, self_ty, func_expr, adt_def, args, cx.tcx.typeck_body(*b)); - } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) { + } else if adt_def.is_enum() && self.msrv.meets(cx, msrvs::DEFAULT_ENUM_ATTRIBUTE) { check_enum(cx, item, func_expr, adt_def); } } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index db3e6034c5baf..2ae35b4005579 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -384,7 +384,7 @@ fn check_unsafe_derive_deserialize<'tcx>( .tcx .inherent_impls(def.did()) .iter() - .map(|imp_did| cx.tcx.hir().expect_item(imp_did.expect_local())) + .map(|imp_did| cx.tcx.hir_expect_item(imp_did.expect_local())) .any(|imp| has_unsafe(cx, imp)) { span_lint_hir_and_then( diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs index 4e8853821c3ef..4b8a689e99478 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs @@ -1,9 +1,9 @@ + use clippy_config::Conf; -use clippy_config::types::create_disallowed_map; +use clippy_config::types::{DisallowedPath, create_disallowed_map}; use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then}; use clippy_utils::macros::macro_backtrace; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::Diag; use rustc_hir::def_id::DefIdMap; use rustc_hir::{ AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty, @@ -59,7 +59,7 @@ declare_clippy_lint! { } pub struct DisallowedMacros { - disallowed: DefIdMap<(&'static str, Option<&'static str>)>, + disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, seen: FxHashSet, // Track the most recently seen node that can have a `derive` attribute. // Needed to use the correct lint level. @@ -90,13 +90,9 @@ impl DisallowedMacros { return; } - if let Some(&(path, reason)) = self.disallowed.get(&mac.def_id) { + if let Some(&(path, disallowed_path)) = self.disallowed.get(&mac.def_id) { let msg = format!("use of a disallowed macro `{path}`"); - let add_note = |diag: &mut Diag<'_, _>| { - if let Some(reason) = reason { - diag.note(reason); - } - }; + let add_note = disallowed_path.diag_amendment(mac.span); if matches!(mac.kind, MacroKind::Derive) && let Some(derive_src) = derive_src { diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs index c4ed118b7c9fc..149cf1cf2def1 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs @@ -1,5 +1,5 @@ use clippy_config::Conf; -use clippy_config::types::create_disallowed_map; +use clippy_config::types::{DisallowedPath, create_disallowed_map}; use clippy_utils::diagnostics::span_lint_and_then; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefIdMap; @@ -31,6 +31,8 @@ declare_clippy_lint! { /// # When using an inline table, can add a `reason` for why the method /// # is disallowed. /// { path = "std::vec::Vec::leak", reason = "no leaking memory" }, + /// # Can also add a `replacement` that will be offered as a suggestion. + /// { path = "std::sync::Mutex::new", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex::new" }, /// ] /// ``` /// @@ -56,7 +58,7 @@ declare_clippy_lint! { } pub struct DisallowedMethods { - disallowed: DefIdMap<(&'static str, Option<&'static str>)>, + disallowed: DefIdMap<(&'static str, &'static DisallowedPath)>, } impl DisallowedMethods { @@ -83,17 +85,13 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods { }, _ => return, }; - if let Some(&(path, reason)) = self.disallowed.get(&id) { + if let Some(&(path, disallowed_path)) = self.disallowed.get(&id) { span_lint_and_then( cx, DISALLOWED_METHODS, span, format!("use of a disallowed method `{path}`"), - |diag| { - if let Some(reason) = reason { - diag.note(reason); - } - }, + disallowed_path.diag_amendment(span), ); } } diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 947677e14bd0b..3659946b70424 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs @@ -1,4 +1,5 @@ use clippy_config::Conf; +use clippy_config::types::DisallowedPath; use clippy_utils::diagnostics::span_lint_and_then; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::Res; @@ -31,6 +32,8 @@ declare_clippy_lint! { /// # When using an inline table, can add a `reason` for why the type /// # is disallowed. /// { path = "std::net::Ipv4Addr", reason = "no IPv4 allowed" }, + /// # Can also add a `replacement` that will be offered as a suggestion. + /// { path = "std::sync::Mutex", reason = "prefer faster & simpler non-poisonable mutex", replacement = "parking_lot::Mutex" }, /// ] /// ``` /// @@ -51,24 +54,23 @@ declare_clippy_lint! { } pub struct DisallowedTypes { - def_ids: DefIdMap<(&'static str, Option<&'static str>)>, - prim_tys: FxHashMap)>, + def_ids: DefIdMap<(&'static str, &'static DisallowedPath)>, + prim_tys: FxHashMap, } impl DisallowedTypes { pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self { let mut def_ids = DefIdMap::default(); let mut prim_tys = FxHashMap::default(); - for x in &conf.disallowed_types { - let path: Vec<_> = x.path().split("::").collect::>(); - let reason = x.reason(); + for disallowed_path in &conf.disallowed_types { + let path: Vec<_> = disallowed_path.path().split("::").collect::>(); for res in clippy_utils::def_path_res(tcx, &path) { match res { Res::Def(_, id) => { - def_ids.insert(id, (x.path(), reason)); + def_ids.insert(id, (disallowed_path.path(), disallowed_path)); }, Res::PrimTy(ty) => { - prim_tys.insert(ty, (x.path(), reason)); + prim_tys.insert(ty, (disallowed_path.path(), disallowed_path)); }, _ => {}, } @@ -78,7 +80,7 @@ impl DisallowedTypes { } fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) { - let (path, reason) = match res { + let (path, disallowed_path) = match res { Res::Def(_, did) if let Some(&x) = self.def_ids.get(did) => x, Res::PrimTy(prim) if let Some(&x) = self.prim_tys.get(prim) => x, _ => return, @@ -88,11 +90,7 @@ impl DisallowedTypes { DISALLOWED_TYPES, span, format!("use of a disallowed type `{path}`"), - |diag| { - if let Some(reason) = reason { - diag.note(reason); - } - }, + disallowed_path.diag_amendment(span), ); } } diff --git a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs index 4b40fc0b1ee2c..bca1cd03bb7ee 100644 --- a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs +++ b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs @@ -1,18 +1,17 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; -use rustc_ast::AttrStyle; +use rustc_ast::{AttrArgs, AttrKind, AttrStyle, Attribute}; use rustc_errors::Applicability; -use rustc_hir::{AttrArgs, AttrKind, Attribute}; -use rustc_lint::LateContext; +use rustc_lint::EarlyContext; use super::DOC_INCLUDE_WITHOUT_CFG; -pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) { +pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) { for attr in attrs { if !attr.span.from_expansion() && let AttrKind::Normal(ref item) = attr.kind && attr.doc_str().is_some() - && let AttrArgs::Eq { expr: meta, .. } = &item.args + && let AttrArgs::Eq { expr: meta, .. } = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs index 2577324f23df9..8aeb835fe3934 100644 --- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs +++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs @@ -16,7 +16,6 @@ fn map_container_to_text(c: &super::Container) -> &'static str { } } -// TODO: Adjust the parameters as necessary pub(super) fn check( cx: &LateContext<'_>, doc: &str, diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs index e8638595c4b26..e75abf28bace8 100644 --- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs +++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs @@ -25,7 +25,7 @@ pub fn check( && cx .tcx .hir_parent_iter(owner_id.into()) - .any(|(id, _node)| is_doc_hidden(cx.tcx.hir().attrs(id))) + .any(|(id, _node)| is_doc_hidden(cx.tcx.hir_attrs(id))) { return; } diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index 713d62a8801d8..0296ff13112f3 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::ty; use rustc_resolve::rustdoc::{ @@ -82,6 +82,28 @@ declare_clippy_lint! { "presence of `_`, `::` or camel-case outside backticks in documentation" } +declare_clippy_lint! { + /// ### What it does + /// Checks for links with code directly adjacent to code text: + /// `` [`MyItem`]`<`[`u32`]`>` ``. + /// + /// ### Why is this bad? + /// It can be written more simply using HTML-style `` tags. + /// + /// ### Example + /// ```no_run + /// //! [`first`](x)`second` + /// ``` + /// Use instead: + /// ```no_run + /// //! [first](x)second + /// ``` + #[clippy::version = "1.86.0"] + pub DOC_LINK_CODE, + nursery, + "link with code back-to-back with other code" +} + declare_clippy_lint! { /// ### What it does /// Checks for the doc comments of publicly visible @@ -453,7 +475,7 @@ declare_clippy_lint! { /// /// and this line is overindented. /// # fn foo() {} /// ``` - #[clippy::version = "1.80.0"] + #[clippy::version = "1.86.0"] pub DOC_OVERINDENTED_LIST_ITEMS, style, "ensure list items are not overindented" @@ -513,7 +535,7 @@ declare_clippy_lint! { /// ```no_run /// #![cfg_attr(doc, doc = include_str!("some_file.md"))] /// ``` - #[clippy::version = "1.84.0"] + #[clippy::version = "1.85.0"] pub DOC_INCLUDE_WITHOUT_CFG, restriction, "check if files included in documentation are behind `cfg(doc)`" @@ -539,7 +561,7 @@ declare_clippy_lint! { /// //! /// //! [link]: destination (for link reference definition) /// ``` - #[clippy::version = "1.84.0"] + #[clippy::version = "1.85.0"] pub DOC_NESTED_REFDEFS, suspicious, "link reference defined in list item or quote" @@ -560,6 +582,7 @@ impl Documentation { } impl_lint_pass!(Documentation => [ + DOC_LINK_CODE, DOC_LINK_WITH_QUOTES, DOC_MARKDOWN, DOC_NESTED_REFDEFS, @@ -577,6 +600,12 @@ impl_lint_pass!(Documentation => [ DOC_INCLUDE_WITHOUT_CFG, ]); +impl EarlyLintPass for Documentation { + fn check_attributes(&mut self, cx: &EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) { + include_in_doc_without_cfg::check(cx, attrs); + } +} + impl<'tcx> LateLintPass<'tcx> for Documentation { fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) { let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else { @@ -704,14 +733,13 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ Some(("fake".into(), "fake".into())) } - include_in_doc_without_cfg::check(cx, attrs); if suspicious_doc_comments::check(cx, attrs) || is_doc_hidden(attrs) { return None; } let (fragments, _) = attrs_to_doc_fragments( attrs.iter().filter_map(|attr| { - if attr.span.in_external_macro(cx.sess().source_map()) { + if attr.doc_str_and_comment_kind().is_none() || attr.span().in_external_macro(cx.sess().source_map()) { None } else { Some((attr, None)) @@ -741,6 +769,21 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs: &[ let mut cb = fake_broken_link_callback; + check_for_code_clusters( + cx, + pulldown_cmark::Parser::new_with_broken_link_callback( + &doc, + main_body_opts() - Options::ENABLE_SMART_PUNCTUATION, + Some(&mut cb), + ) + .into_offset_iter(), + &doc, + Fragments { + doc: &doc, + fragments: &fragments, + }, + ); + // disable smart punctuation to pick up ['link'] more easily let opts = main_body_opts() - Options::ENABLE_SMART_PUNCTUATION; let parser = pulldown_cmark::Parser::new_with_broken_link_callback(&doc, opts, Some(&mut cb)); @@ -764,6 +807,66 @@ enum Container { List(usize), } +/// Scan the documentation for code links that are back-to-back with code spans. +/// +/// This is done separately from the rest of the docs, because that makes it easier to produce +/// the correct messages. +fn check_for_code_clusters<'a, Events: Iterator, Range)>>( + cx: &LateContext<'_>, + events: Events, + doc: &str, + fragments: Fragments<'_>, +) { + let mut events = events.peekable(); + let mut code_starts_at = None; + let mut code_ends_at = None; + let mut code_includes_link = false; + while let Some((event, range)) = events.next() { + match event { + Start(Link { .. }) if matches!(events.peek(), Some((Code(_), _range))) => { + if code_starts_at.is_some() { + code_ends_at = Some(range.end); + } else { + code_starts_at = Some(range.start); + } + code_includes_link = true; + // skip the nested "code", because we're already handling it here + let _ = events.next(); + }, + Code(_) => { + if code_starts_at.is_some() { + code_ends_at = Some(range.end); + } else { + code_starts_at = Some(range.start); + } + }, + End(TagEnd::Link) => {}, + _ => { + if let Some(start) = code_starts_at + && let Some(end) = code_ends_at + && code_includes_link + { + if let Some(span) = fragments.span(cx, start..end) { + span_lint_and_then(cx, DOC_LINK_CODE, span, "code link adjacent to code text", |diag| { + let sugg = format!("{}", doc[start..end].replace('`', "")); + diag.span_suggestion_verbose( + span, + "wrap the entire group in `` tags", + sugg, + Applicability::MaybeIncorrect, + ); + diag.help("separate code snippets will be shown with a gap"); + }); + } + } + code_includes_link = false; + code_starts_at = None; + code_ends_at = None; + }, + } + } +} + /// Checks parsed documentation. /// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`, /// so lints here will generally access that information. @@ -906,7 +1009,12 @@ fn check_doc<'a, Events: Iterator, Range range.start { + start - range.start + } else { + 0 + } } } else { 0 @@ -1086,6 +1194,10 @@ impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> { #[expect(clippy::range_plus_one)] // inclusive ranges aren't the same type fn looks_like_refdef(doc: &str, range: Range) -> Option> { + if range.end < range.start { + return None; + } + let offset = range.start; let mut iterator = doc.as_bytes()[range].iter().copied().enumerate(); let mut start = None; diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs index ce5beab24bfa2..3008082c2329d 100644 --- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs +++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs @@ -1,6 +1,6 @@ use std::ops::Range; -use std::{io, thread}; use std::sync::Arc; +use std::{io, thread}; use crate::doc::{NEEDLESS_DOCTEST_MAIN, TEST_ATTR_IN_DOCTEST}; use clippy_utils::diagnostics::span_lint; diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs index 84393213e6f06..9637546b86800 100644 --- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use rustc_ast::AttrStyle; use rustc_ast::token::CommentKind; +use rustc_attr_parsing::AttributeKind; use rustc_errors::Applicability; use rustc_hir::Attribute; use rustc_lint::LateContext; @@ -36,15 +37,19 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> { attrs .iter() .filter_map(|attr| { - if let Some((sym, com_kind)) = attr.doc_str_and_comment_kind() - && let AttrStyle::Outer = attr.style - && let Some(com) = sym.as_str().strip_prefix('!') + if let Attribute::Parsed(AttributeKind::DocComment { + style: AttrStyle::Outer, + kind, + comment, + .. + }) = attr + && let Some(com) = comment.as_str().strip_prefix('!') { - let sugg = match com_kind { + let sugg = match kind { CommentKind::Line => format!("//!{com}"), CommentKind::Block => format!("/*!{com}*/"), }; - Some((attr.span, sugg)) + Some((attr.span(), sugg)) } else { None } diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs index 1f89cab91480e..dc6cbb4254302 100644 --- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs +++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs @@ -1,3 +1,4 @@ +use rustc_attr_parsing::AttributeKind; use rustc_errors::Applicability; use rustc_hir::{Attribute, Item, ItemKind}; use rustc_lint::LateContext; @@ -43,15 +44,19 @@ pub(super) fn check( let mut should_suggest_empty_doc = false; for attr in attrs { - if let Some(doc) = attr.doc_str() { - spans.push(attr.span); - let doc = doc.as_str(); + if let Attribute::Parsed(AttributeKind::DocComment { span, comment, .. }) = attr { + spans.push(span); + let doc = comment.as_str(); let doc = doc.trim(); if spans.len() == 1 { // We make this suggestion only if the first doc line ends with a punctuation // because it might just need to add an empty line with `///`. should_suggest_empty_doc = doc.ends_with('.') || doc.ends_with('!') || doc.ends_with('?'); + } else if spans.len() == 2 { + // We make this suggestion only if the second doc line is not empty. + should_suggest_empty_doc &= !doc.is_empty(); } + let len = doc.chars().count(); if len >= first_paragraph_len { break; @@ -78,7 +83,7 @@ pub(super) fn check( && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi()) && let Some(snippet) = snippet_opt(cx, new_span) { - let Some(first) = snippet_opt(cx, first_span) else { + let Some(first) = snippet_opt(cx, *first_span) else { return; }; let Some(comment_form) = first.get(..3) else { diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs index 578ff6e38a6a6..80c2b03c41cf4 100644 --- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs +++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs @@ -289,10 +289,13 @@ impl EmptyLineAfter { format!("empty {lines} after {kind_desc}"), |diag| { let info = self.items.last().unwrap(); - diag.span_label(info.span, match kind { - StopKind::Attr => format!("the attribute applies to this {}", info.kind), - StopKind::Doc(_) => format!("the comment documents this {}", info.kind), - }); + diag.span_label( + info.span, + match kind { + StopKind::Attr => format!("the attribute applies to this {}", info.kind), + StopKind::Doc(_) => format!("the comment documents this {}", info.kind), + }, + ); diag.multipart_suggestion_with_style( format!("if the empty {lines} {are} unintentional, remove {them}"), diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 2bec4f2f99e5b..f404bc59b3b88 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{reindent_multiline, snippet_indent, snippet_with_applicability, snippet_with_context}; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{ SpanlessEq, can_move_expr_to_closure_no_visit, higher, is_expr_final_block_expr, is_expr_used_or_unified, peel_hir_expr_while, @@ -7,11 +8,12 @@ use clippy_utils::{ use core::fmt::{self, Write}; use rustc_errors::Applicability; use rustc_hir::hir_id::HirIdSet; -use rustc_hir::intravisit::{Visitor, walk_expr}; +use rustc_hir::intravisit::{Visitor, walk_body, walk_expr}; use rustc_hir::{Block, Expr, ExprKind, HirId, Pat, Stmt, StmtKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{DUMMY_SP, Span, SyntaxContext, sym}; +use std::ops::ControlFlow; declare_clippy_lint! { /// ### What it does @@ -135,8 +137,8 @@ impl<'tcx> LateLintPass<'tcx> for HashMapPass { format!( "match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\ {indent_str} {entry}::{else_entry} => {}\n{indent_str}}}", - reindent_multiline(then_str.into(), true, Some(4 + indent_str.len())), - reindent_multiline(else_str.into(), true, Some(4 + indent_str.len())), + reindent_multiline(&then_str, true, Some(4 + indent_str.len())), + reindent_multiline(&else_str, true, Some(4 + indent_str.len())), entry = map_ty.entry_path(), ) } @@ -329,7 +331,7 @@ impl<'tcx> Edit<'tcx> { if let Self::Insertion(i) = self { Some(i) } else { None } } } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] struct Insertion<'tcx> { call: &'tcx Expr<'tcx>, value: &'tcx Expr<'tcx>, @@ -500,7 +502,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { self.visit_non_tail_expr(insert_expr.value); self.is_single_insert = is_single_insert; }, - _ if SpanlessEq::new(self.cx).eq_expr(self.map, expr) => { + _ if is_any_expr_in_map_used(self.cx, self.map, expr) => { self.is_map_used = true; }, _ => match expr.kind { @@ -542,6 +544,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { ExprKind::InlineAsm(_) => { self.can_use_entry = false; }, + ExprKind::Closure(closure) => walk_body(self, self.cx.tcx.hir_body(closure.body)), _ => { self.allow_insert_closure &= !self.in_tail_pos; self.allow_insert_closure &= @@ -562,6 +565,19 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { } } +/// Check if the given expression is used for each sub-expression in the given map. +/// For example, in map `a.b.c.my_map`, The expression `a.b.c.my_map`, `a.b.c`, `a.b`, and `a` are +/// all checked. +fn is_any_expr_in_map_used<'tcx>(cx: &LateContext<'tcx>, map: &'tcx Expr<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + for_each_expr(cx, map, |e| { + if SpanlessEq::new(cx).eq_expr(e, expr) { + return ControlFlow::Break(()); + } + ControlFlow::Continue(()) + }) + .is_some() +} + struct InsertSearchResults<'tcx> { edits: Vec>, allow_insert_closure: bool, diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 0c06c9117d737..9298f56b68bee 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -1,5 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_hir; +use rustc_abi::ExternAbi; use rustc_hir::{AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind, intravisit}; use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId}; use rustc_lint::{LateContext, LateLintPass}; @@ -10,7 +11,6 @@ use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_abi::ExternAbi; pub struct BoxedLocal { too_large_for_stack: u64, @@ -150,6 +150,8 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if cmt.place.projections.is_empty() { if let PlaceBase::Local(lid) = cmt.place.base { @@ -161,7 +163,6 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { if cmt.place.projections.is_empty() { - let map = &self.cx.tcx.hir(); if is_argument(self.cx.tcx, cmt.hir_id) { // Skip closure arguments let parent_id = self.cx.tcx.parent_hir_id(cmt.hir_id); @@ -172,7 +173,7 @@ impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> { // skip if there is a `self` parameter binding to a type // that contains `Self` (i.e.: `self: Box`), see #4804 if let Some(trait_self_ty) = self.trait_self_ty { - if map.name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) { + if self.cx.tcx.hir_name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) { return; } } diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index d1782d582f4d6..645f93068496b 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -6,6 +6,7 @@ use clippy_utils::usage::{local_used_after_expr, local_used_in}; use clippy_utils::{ get_path_from_caller_to_method_type, is_adjusted, is_no_std_crate, path_to_local, path_to_local_id, }; +use rustc_abi::ExternAbi; use rustc_errors::Applicability; use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind}; use rustc_infer::infer::TyCtxtInferExt; @@ -15,7 +16,6 @@ use rustc_middle::ty::{ }; use rustc_session::declare_lint_pass; use rustc_span::symbol::sym; -use rustc_abi::ExternAbi; use rustc_trait_selection::error_reporting::InferCtxtErrorExt as _; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index 15afe3e8c145c..54a1ac21c85c3 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -1,13 +1,13 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::{get_parent_as_impl, has_repr_attr, is_bool}; +use rustc_abi::ExternAbi; use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_abi::ExternAbi; declare_clippy_lint! { /// ### What it does diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs index 9bf3baba4b597..591912cc8d5e8 100644 --- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs +++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs @@ -84,7 +84,7 @@ impl LateLintPass<'_> for ExhaustiveItems { _ => return, }; if cx.effective_visibilities.is_exported(item.owner_id.def_id) - && let attrs = cx.tcx.hir().attrs(item.hir_id()) + && let attrs = cx.tcx.hir_attrs(item.hir_id()) && !attrs.iter().any(|a| a.has_name(sym::non_exhaustive)) && fields.iter().all(|f| cx.tcx.visibility(f.def_id).is_public()) { diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index da5825b7ab21e..fc5f76179f907 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -1,26 +1,28 @@ use arrayvec::ArrayVec; use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::is_diag_trait_item; use clippy_utils::macros::{ FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, }; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::SpanRangeExt; +use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{implements_trait, is_type_lang_item}; +use clippy_utils::{is_diag_trait_item, is_from_proc_macro}; use itertools::Itertools; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, FormatPlaceholder, FormatTrait, }; +use rustc_attr_parsing::RustcVersion; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::ty::Ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; +use rustc_middle::ty::{List, Ty, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition::Edition2021; use rustc_span::{Span, Symbol, sym}; @@ -50,6 +52,36 @@ declare_clippy_lint! { "`format!` used in a macro that does formatting" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `Debug` formatting (`{:?}`) applied to an `OsStr` or `Path`. + /// + /// ### Why is this bad? + /// Rust doesn't guarantee what `Debug` formatting looks like, and it could + /// change in the future. `OsStr`s and `Path`s can be `Display` formatted + /// using their `display` methods. + /// + /// Furthermore, with `Debug` formatting, certain characters are escaped. + /// Thus, a `Debug` formatted `Path` is less likely to be clickable. + /// + /// ### Example + /// ```no_run + /// # use std::path::Path; + /// let path = Path::new("..."); + /// println!("The path is {:?}", path); + /// ``` + /// Use instead: + /// ```no_run + /// # use std::path::Path; + /// let path = Path::new("…"); + /// println!("The path is {}", path.display()); + /// ``` + #[clippy::version = "1.87.0"] + pub UNNECESSARY_DEBUG_FORMATTING, + pedantic, + "`Debug` formatting applied to an `OsStr` or `Path` when `.display()` is available" +} + declare_clippy_lint! { /// ### What it does /// Checks for [`ToString::to_string`](https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string) @@ -162,31 +194,35 @@ declare_clippy_lint! { "use of a format specifier that has no effect" } -impl_lint_pass!(FormatArgs => [ +impl_lint_pass!(FormatArgs<'_> => [ FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS, UNINLINED_FORMAT_ARGS, + UNNECESSARY_DEBUG_FORMATTING, UNUSED_FORMAT_SPECS, ]); #[allow(clippy::struct_field_names)] -pub struct FormatArgs { +pub struct FormatArgs<'tcx> { format_args: FormatArgsStorage, msrv: Msrv, ignore_mixed: bool, + ty_msrv_map: FxHashMap, Option>, } -impl FormatArgs { - pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self { +impl<'tcx> FormatArgs<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf, format_args: FormatArgsStorage) -> Self { + let ty_msrv_map = make_ty_msrv_map(tcx); Self { format_args, - msrv: conf.msrv.clone(), + msrv: conf.msrv, ignore_mixed: conf.allow_mixed_uninlined_format_args, + ty_msrv_map, } } } -impl<'tcx> LateLintPass<'tcx> for FormatArgs { +impl<'tcx> LateLintPass<'tcx> for FormatArgs<'tcx> { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let Some(macro_call) = root_macro_call_first_node(cx, expr) && is_format_macro(cx, macro_call.def_id) @@ -198,17 +234,17 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs { macro_call: ¯o_call, format_args, ignore_mixed: self.ignore_mixed, + msrv: &self.msrv, + ty_msrv_map: &self.ty_msrv_map, }; linter.check_templates(); - if self.msrv.meets(msrvs::FORMAT_ARGS_CAPTURE) { + if self.msrv.meets(cx, msrvs::FORMAT_ARGS_CAPTURE) { linter.check_uninlined_args(); } } } - - extract_msrv_attr!(LateContext); } struct FormatArgsExpr<'a, 'tcx> { @@ -217,9 +253,11 @@ struct FormatArgsExpr<'a, 'tcx> { macro_call: &'a MacroCall, format_args: &'a rustc_ast::FormatArgs, ignore_mixed: bool, + msrv: &'a Msrv, + ty_msrv_map: &'a FxHashMap, Option>, } -impl FormatArgsExpr<'_, '_> { +impl<'tcx> FormatArgsExpr<'_, 'tcx> { fn check_templates(&self) { for piece in &self.format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece @@ -237,6 +275,11 @@ impl FormatArgsExpr<'_, '_> { self.check_format_in_format_args(name, arg_expr); self.check_to_string_in_format_args(name, arg_expr); } + + if placeholder.format_trait == FormatTrait::Debug { + let name = self.cx.tcx.item_name(self.macro_call.def_id); + self.check_unnecessary_debug_formatting(name, arg_expr); + } } } } @@ -439,6 +482,33 @@ impl FormatArgsExpr<'_, '_> { } } + fn check_unnecessary_debug_formatting(&self, name: Symbol, value: &Expr<'tcx>) { + let cx = self.cx; + if !value.span.from_expansion() + && !is_from_proc_macro(cx, value) + && let ty = cx.typeck_results().expr_ty(value) + && self.can_display_format(ty) + { + let snippet = snippet(cx.sess(), value.span, ".."); + span_lint_and_then( + cx, + UNNECESSARY_DEBUG_FORMATTING, + value.span, + format!("unnecessary `Debug` formatting in `{name}!` args"), + |diag| { + diag.help(format!( + "use `Display` formatting and change this to `{snippet}.display()`" + )); + diag.note( + "switching to `Display` formatting will change how the value is shown; \ + escaped characters will no longer be escaped and surrounding quotes will \ + be removed", + ); + }, + ); + } + } + fn format_arg_positions(&self) -> impl Iterator { self.format_args.template.iter().flat_map(|piece| match piece { FormatArgsPiece::Placeholder(placeholder) => { @@ -465,6 +535,41 @@ impl FormatArgsExpr<'_, '_> { .at_most_one() .is_err() } + + fn can_display_format(&self, ty: Ty<'tcx>) -> bool { + let ty = ty.peel_refs(); + + if let Some(msrv) = self.ty_msrv_map.get(&ty) + && msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv)) + { + return true; + } + + // Even if `ty` is not in `self.ty_msrv_map`, check whether `ty` implements `Deref` with + // a `Target` that is in `self.ty_msrv_map`. + if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait() + && implements_trait(self.cx, ty, deref_trait_id, &[]) + && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, "Target") + && let Some(msrv) = self.ty_msrv_map.get(&target_ty) + && msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv)) + { + return true; + } + + false + } +} + +fn make_ty_msrv_map(tcx: TyCtxt<'_>) -> FxHashMap, Option> { + [(sym::OsStr, Some(msrvs::OS_STR_DISPLAY)), (sym::Path, None)] + .into_iter() + .filter_map(|(name, feature)| { + tcx.get_diagnostic_item(name).map(|def_id| { + let ty = Ty::new_adt(tcx, tcx.adt_def(def_id), List::empty()); + (ty, feature) + }) + }) + .collect() } fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tcx>) diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index ff75fcf2b417c..5b42a40d850bb 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -209,9 +209,8 @@ impl FormatImplExpr<'_, '_> { // Handle dereference of &self -> self that is equivalent (i.e. via *self in fmt() impl) // Since the argument to fmt is itself a reference: &self let reference = peel_ref_operators(self.cx, arg); - let map = self.cx.tcx.hir(); // Is the reference self? - if path_to_local(reference).map(|x| map.name(x)) == Some(kw::SelfLower) { + if path_to_local(reference).map(|x| self.cx.tcx.hir_name(x)) == Some(kw::SelfLower) { let FormatTraitNames { name, .. } = self.format_trait_impl; span_lint( self.cx, diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs index 0599e08e6c0af..8822b87f92f72 100644 --- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs +++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs @@ -43,10 +43,10 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes { let sm = cx.sess().source_map(); let mut span = cx .tcx - .hir() - .attrs(item.hir_id()) + .hir_attrs(item.hir_id()) .iter() - .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span)); + .filter(|i| i.is_doc_comment()) + .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span())); let (Some(file), _, _, end_line, _) = sm.span_to_location_info(span) else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs index 41bf6e81916ac..6da5567d9c709 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -58,9 +58,7 @@ pub struct FromOverInto { impl FromOverInto { pub fn new(conf: &'static Conf) -> Self { - FromOverInto { - msrv: conf.msrv.clone(), - } + FromOverInto { msrv: conf.msrv } } } @@ -77,12 +75,12 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { && let Some(into_trait_seg) = hir_trait_ref.path.segments.last() // `impl Into for self_ty` && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args - && self.msrv.meets(msrvs::RE_REBALANCING_COHERENCE) && span_is_local(item.span) && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id) - .map(ty::EarlyBinder::instantiate_identity) + .map(ty::EarlyBinder::instantiate_identity) && cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id) && !matches!(middle_trait_ref.args.type_at(1).kind(), ty::Alias(ty::Opaque, _)) + && self.msrv.meets(cx, msrvs::RE_REBALANCING_COHERENCE) { span_lint_and_then( cx, @@ -114,8 +112,6 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { ); } } - - extract_msrv_attr!(LateContext); } /// Finds the occurrences of `Self` and `self` diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 243eb5cbfd40a..5f3fc5100e75b 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -471,7 +471,7 @@ impl Functions { .iter() .flat_map(|p| def_path_def_ids(tcx, &p.split("::").collect::>())) .collect(), - msrv: conf.msrv.clone(), + msrv: conf.msrv, } } } @@ -521,12 +521,12 @@ impl<'tcx> LateLintPass<'tcx> for Functions { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { must_use::check_item(cx, item); - result::check_item(cx, item, self.large_error_threshold, &self.msrv); + result::check_item(cx, item, self.large_error_threshold, self.msrv); } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) { must_use::check_impl_item(cx, item); - result::check_impl_item(cx, item, self.large_error_threshold, &self.msrv); + result::check_impl_item(cx, item, self.large_error_threshold, self.msrv); impl_trait_in_params::check_impl_item(cx, item); renamed_function_params::check_impl_item(cx, item, &self.trait_ids); } @@ -535,10 +535,8 @@ impl<'tcx> LateLintPass<'tcx> for Functions { too_many_arguments::check_trait_item(cx, item, self.too_many_arguments_threshold); not_unsafe_ptr_arg_deref::check_trait_item(cx, item); must_use::check_trait_item(cx, item); - result::check_trait_item(cx, item, self.large_error_threshold, &self.msrv); + result::check_trait_item(cx, item, self.large_error_threshold, self.msrv); impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api); ref_option::check_trait_item(cx, item, self.avoid_breaking_exported_api); } - - extract_msrv_attr!(LateContext); } 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 e6e3ea59a9f67..c3e0d5e8b694d 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -21,7 +21,7 @@ use core::ops::ControlFlow; use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT}; pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let hir::ItemKind::Fn { ref sig, @@ -51,7 +51,7 @@ pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Imp if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind { let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); @@ -74,7 +74,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id); let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); let attr = cx.tcx.get_attr(item.owner_id, sym::must_use); if let Some(attr) = attr { check_needless_must_use(cx, sig.decl, item.owner_id, item.span, fn_header_span, attr, attrs, sig); @@ -95,6 +95,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr } } +// FIXME: needs to be an EARLY LINT. all attribute lints should be #[allow(clippy::too_many_arguments)] fn check_needless_must_use( cx: &LateContext<'_>, @@ -117,38 +118,27 @@ fn check_needless_must_use( fn_header_span, "this unit-returning function has a `#[must_use]` attribute", |diag| { - diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable); + diag.span_suggestion( + attr.span(), + "remove the attribute", + "", + Applicability::MachineApplicable, + ); }, ); } else { // When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see // issue #12320. - span_lint_and_then( + // FIXME(jdonszelmann): this used to give a machine-applicable fix. However, it was super fragile, + // honestly looked incorrect, and is a little hard to support for a little bit now. Some day this + // could be re-added. + span_lint_and_help( cx, MUST_USE_UNIT, fn_header_span, "this unit-returning function has a `#[must_use]` attribute", - |diag| { - let mut attrs_without_must_use = attrs.to_vec(); - attrs_without_must_use.retain(|a| a.id != attr.id); - let sugg_str = attrs_without_must_use - .iter() - .map(|a| { - if a.value_str().is_none() { - return a.name_or_empty().to_string(); - } - format!("{} = \"{}\"", a.name_or_empty(), a.value_str().unwrap()) - }) - .collect::>() - .join(", "); - - diag.span_suggestion( - attrs[0].span.with_hi(attrs[attrs.len() - 1].span.hi()), - "change these attributes to", - sugg_str, - Applicability::MachineApplicable, - ); - }, + Some(attr.span()), + "remove `must_use`", ); } } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) { diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index 74d365a725560..cade56f582261 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -34,7 +34,7 @@ fn result_err_ty<'tcx>( } } -pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64, msrv: &Msrv) { +pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64, msrv: Msrv) { if let hir::ItemKind::Fn { ref sig, .. } = item.kind && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) { @@ -50,7 +50,7 @@ pub(super) fn check_impl_item<'tcx>( cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64, - msrv: &Msrv, + msrv: Msrv, ) { // Don't lint if method is a trait's implementation, we can't do anything about those if let hir::ImplItemKind::Fn(ref sig, _) = item.kind @@ -69,7 +69,7 @@ pub(super) fn check_trait_item<'tcx>( cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64, - msrv: &Msrv, + msrv: Msrv, ) { if let hir::TraitItemKind::Fn(ref sig, _) = item.kind { let fn_header_span = item.span.with_hi(sig.decl.output.span().hi()); @@ -82,8 +82,8 @@ pub(super) fn check_trait_item<'tcx>( } } -fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span, msrv: &Msrv) { - if err_ty.is_unit() && (!is_no_std_crate(cx) || msrv.meets(msrvs::ERROR_IN_CORE)) { +fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: Span, msrv: Msrv) { + if err_ty.is_unit() && (!is_no_std_crate(cx) || msrv.meets(cx, msrvs::ERROR_IN_CORE)) { span_lint_and_help( cx, RESULT_UNIT_ERR, 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 f17f687719f26..05dc47f6fe580 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 @@ -1,7 +1,7 @@ +use rustc_abi::ExternAbi; use rustc_hir::{self as hir, intravisit}; use rustc_lint::LateContext; use rustc_span::Span; -use rustc_abi::ExternAbi; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_trait_impl_item; @@ -23,11 +23,19 @@ pub(super) fn check_fn( intravisit::FnKind::Method( _, &hir::FnSig { - header: hir::FnHeader { abi: ExternAbi::Rust, .. }, + header: hir::FnHeader { + abi: ExternAbi::Rust, .. + }, .. }, ) - | intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: ExternAbi::Rust, .. }) => check_arg_number( + | intravisit::FnKind::ItemFn( + _, + _, + hir::FnHeader { + abi: ExternAbi::Rust, .. + }, + ) => check_arg_number( cx, decl, span.with_hi(decl.output.span().hi()), diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs index 2806d4d0e5d61..45f9aa0a53e47 100644 --- a/src/tools/clippy/clippy_lints/src/if_not_else.rs +++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs @@ -7,7 +7,6 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::Span; -use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -107,7 +106,7 @@ fn make_sugg<'a>( els_span: Span, default: &'a str, indent_relative_to: Option, -) -> Cow<'a, str> { +) -> String { let cond_inner_snip = snippet(sess, cond_inner, default); let els_snip = snippet(sess, els_span, default); let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); @@ -130,5 +129,5 @@ fn make_sugg<'a>( _ => String::new(), }; - reindent_multiline(suggestion.into(), true, indent) + reindent_multiline(&suggestion, true, indent) } 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 51e2944e6f994..fbbd33efd02d6 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 @@ -54,9 +54,7 @@ pub struct IfThenSomeElseNone { impl IfThenSomeElseNone { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -79,10 +77,10 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { && !is_else_clause(cx.tcx, expr) && !is_in_const_context(cx) && !expr.span.in_external_macro(cx.sess().source_map()) - && self.msrv.meets(msrvs::BOOL_THEN) + && self.msrv.meets(cx, msrvs::BOOL_THEN) && !contains_return(then_block.stmts) { - let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(msrvs::BOOL_THEN_SOME) { + let method_name = if switch_to_eager_eval(cx, expr) && self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { "then_some" } else { "then" @@ -94,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { expr.span, format!("this could be simplified with `bool::{method_name}`"), |diag| { - let mut app = Applicability::Unspecified; + let mut app = Applicability::MachineApplicable; let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app) .maybe_par() .to_string(); @@ -120,6 +118,4 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone { ); } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index 152d506a7c00d..f2d16ff2e5649 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -83,9 +83,7 @@ impl_lint_pass!(ImplicitSaturatingSub => [IMPLICIT_SATURATING_SUB, INVERTED_SATU impl ImplicitSaturatingSub { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -108,12 +106,10 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { && let ExprKind::Binary(ref cond_op, cond_left, cond_right) = cond.kind { check_manual_check( - cx, expr, cond_op, cond_left, cond_right, if_block, else_block, &self.msrv, + cx, expr, cond_op, cond_left, cond_right, if_block, else_block, self.msrv, ); } } - - extract_msrv_attr!(LateContext); } #[allow(clippy::too_many_arguments)] @@ -125,7 +121,7 @@ fn check_manual_check<'tcx>( right_hand: &Expr<'tcx>, if_block: &Expr<'tcx>, else_block: &Expr<'tcx>, - msrv: &Msrv, + msrv: Msrv, ) { let ty = cx.typeck_results().expr_ty(left_hand); if ty.is_numeric() && !ty.is_signed() { @@ -178,7 +174,7 @@ fn check_gt( little_var: &Expr<'_>, if_block: &Expr<'_>, else_block: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, is_composited: bool, ) { if let Some(big_var) = Var::new(big_var) @@ -221,7 +217,7 @@ fn check_subtraction( little_var: Var, if_block: &Expr<'_>, else_block: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, is_composited: bool, ) { let if_block = peel_blocks(if_block); @@ -258,7 +254,7 @@ fn check_subtraction( // if `snippet_opt` fails, it won't try the next conditions. if let Some(big_var_snippet) = snippet_opt(cx, big_var.span) && let Some(little_var_snippet) = snippet_opt(cx, little_var.span) - && (!is_in_const_context(cx) || msrv.meets(msrvs::SATURATING_SUB_CONST)) + && (!is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST)) { let sugg = format!( "{}{big_var_snippet}.saturating_sub({little_var_snippet}){}", diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs index b10206dcd05ec..12dfb14c454d2 100644 --- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs +++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs @@ -42,6 +42,7 @@ declare_clippy_lint! { pub struct IncompatibleMsrv { msrv: Msrv, is_above_msrv: FxHashMap, + check_in_tests: bool, } impl_lint_pass!(IncompatibleMsrv => [INCOMPATIBLE_MSRV]); @@ -49,8 +50,9 @@ impl_lint_pass!(IncompatibleMsrv => [INCOMPATIBLE_MSRV]); impl IncompatibleMsrv { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: conf.msrv, is_above_msrv: FxHashMap::default(), + check_in_tests: conf.check_incompatible_msrv_in_tests, } } @@ -86,39 +88,30 @@ impl IncompatibleMsrv { // We don't check local items since their MSRV is supposed to always be valid. return; } - let version = self.get_def_id_version(cx.tcx, def_id); - if self.msrv.meets(version) || is_in_test(cx.tcx, node) { - return; - } if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind { // Desugared expressions get to cheat and stability is ignored. // Intentionally not using `.from_expansion()`, since we do still care about macro expansions return; } - self.emit_lint_for(cx, span, version); - } - - fn emit_lint_for(&self, cx: &LateContext<'_>, span: Span, version: RustcVersion) { - span_lint( - cx, - INCOMPATIBLE_MSRV, - span, - format!( - "current MSRV (Minimum Supported Rust Version) is `{}` but this item is stable since `{version}`", - self.msrv - ), - ); + if (self.check_in_tests || !is_in_test(cx.tcx, node)) + && let Some(current) = self.msrv.current(cx) + && let version = self.get_def_id_version(cx.tcx, def_id) + && version > current + { + span_lint( + cx, + INCOMPATIBLE_MSRV, + span, + format!( + "current MSRV (Minimum Supported Rust Version) is `{current}` but this item is stable since `{version}`" + ), + ); + } } } impl<'tcx> LateLintPass<'tcx> for IncompatibleMsrv { - extract_msrv_attr!(LateContext); - fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if self.msrv.current().is_none() { - // If there is no MSRV, then no need to check anything... - return; - } match expr.kind { ExprKind::MethodCall(_, _, _, span) => { if let Some(method_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id) { diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index 39ff3c13bcce9..e1dd7872b9d48 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -182,8 +182,8 @@ fn suggestion<'tcx>( } fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span { - if let Some(attr) = tcx.hir().attrs(field.hir_id).first() { - field.span.with_lo(attr.span.lo()) + if let Some(attr) = tcx.hir_attrs(field.hir_id).first() { + field.span.with_lo(attr.span().lo()) } else { field.span } diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index deac51ab4c493..d53e139de014b 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -62,7 +62,7 @@ impl IndexRefutableSlice { pub fn new(conf: &'static Conf) -> Self { Self { max_suggested_slice: conf.max_suggested_slice_pattern_length, - msrv: conf.msrv.clone(), + msrv: conf.msrv, } } } @@ -74,19 +74,17 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice { if let Some(IfLet { let_pat, if_then, .. }) = IfLet::hir(cx, expr) && (!expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some()) && !is_lint_allowed(cx, INDEX_REFUTABLE_SLICE, expr.hir_id) - && self.msrv.meets(msrvs::SLICE_PATTERNS) && let found_slices = find_slice_values(cx, let_pat) && !found_slices.is_empty() && let filtered_slices = filter_lintable_slices(cx, found_slices, self.max_suggested_slice, if_then) && !filtered_slices.is_empty() + && self.msrv.meets(cx, msrvs::SLICE_PATTERNS) { for slice in filtered_slices.values() { lint_slice(cx, slice); } } } - - extract_msrv_attr!(LateContext); } fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap { 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 c58e8773e3a28..1d582fb0223e1 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::ty::{implements_trait, is_type_lang_item}; use clippy_utils::{return_ty, trait_ref_of_method}; +use rustc_abi::ExternAbi; use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; -use rustc_abi::ExternAbi; declare_clippy_lint! { /// ### What it does 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 1b900f6be8e85..6a436fb4a9d1e 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 @@ -34,18 +34,17 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind && let Some(attr) = cx .tcx - .hir() - .attrs(item.hir_id()) + .hir_attrs(item.hir_id()) .iter() .find(|a| a.has_name(sym::inline)) { span_lint_and_then( cx, INLINE_FN_WITHOUT_BODY, - attr.span, + attr.span(), format!("use of `#[inline]` on trait method `{}` which has no body", item.ident), |diag| { - diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable); + 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 f4e41dc826b0f..4ae1119ab3a27 100644 --- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs +++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs @@ -70,9 +70,7 @@ pub struct InstantSubtraction { impl InstantSubtraction { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -99,14 +97,12 @@ impl LateLintPass<'_> for InstantSubtraction { print_manual_instant_elapsed_sugg(cx, expr, sugg); } else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration) && !expr.span.from_expansion() - && self.msrv.meets(msrvs::TRY_FROM) + && self.msrv.meets(cx, msrvs::TRY_FROM) { print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr); } } } - - extract_msrv_attr!(LateContext); } fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { 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 1929fbded3b56..b42664340d1c8 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -22,9 +22,6 @@ declare_clippy_lint! { /// will mistakenly imply that it is possible for `x` to be outside the range of /// `u8`. /// - /// ### Known problems - /// https://github.com/rust-lang/rust-clippy/issues/886 - /// /// ### Example /// ```no_run /// let x: u8 = 1; 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 f3d62b513e840..621a2af1d322b 100644 --- a/src/tools/clippy/clippy_lints/src/large_include_file.rs +++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs @@ -2,11 +2,11 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_opt; -use rustc_ast::LitKind; -use rustc_hir::{AttrArgs, AttrKind, Attribute, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_ast::{AttrArgs, AttrKind, Attribute, LitKind}; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -52,24 +52,6 @@ impl LargeIncludeFile { impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]); -impl LargeIncludeFile { - fn emit_lint(&self, cx: &LateContext<'_>, span: Span) { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - LARGE_INCLUDE_FILE, - span, - "attempted to include a large file", - |diag| { - diag.note(format!( - "the configuration allows a maximum size of {} bytes", - self.max_file_size - )); - }, - ); - } -} - impl LateLintPass<'_> for LargeIncludeFile { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { if let ExprKind::Lit(lit) = &expr.kind @@ -85,18 +67,32 @@ impl LateLintPass<'_> for LargeIncludeFile { && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id) || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id)) { - self.emit_lint(cx, expr.span.source_callsite()); + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + cx, + LARGE_INCLUDE_FILE, + expr.span.source_callsite(), + "attempted to include a large file", + |diag| { + diag.note(format!( + "the configuration allows a maximum size of {} bytes", + self.max_file_size + )); + }, + ); } } +} - fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) { +impl EarlyLintPass for LargeIncludeFile { + fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { if !attr.span.from_expansion() // Currently, rustc limits the usage of macro at the top-level of attributes, // so we don't need to recurse into each level. && let AttrKind::Normal(ref item) = attr.kind && let Some(doc) = attr.doc_str() && doc.as_str().len() as u64 > self.max_file_size - && let AttrArgs::Eq { expr: meta, .. } = &item.args + && let AttrArgs::Eq { expr: meta, .. } = &item.item.args && !attr.span.contains(meta.span) // Since the `include_str` is already expanded at this point, we can only take the // whole attribute snippet and then modify for our suggestion. @@ -113,7 +109,19 @@ impl LateLintPass<'_> for LargeIncludeFile { && let sub_snippet = sub_snippet.trim() && (sub_snippet.starts_with("include_str!") || sub_snippet.starts_with("include_bytes!")) { - self.emit_lint(cx, attr.span); + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + cx, + LARGE_INCLUDE_FILE, + attr.span, + "attempted to include a large file", + |diag| { + diag.note(format!( + "the configuration allows a maximum size of {} bytes", + self.max_file_size + )); + }, + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs index 6f2ce04e8f8e9..3939318bee6ea 100644 --- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs +++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs @@ -39,9 +39,7 @@ pub struct LegacyNumericConstants { impl LegacyNumericConstants { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -52,9 +50,9 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { // 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 - && self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS) && !item.span.in_external_macro(cx.sess().source_map()) && let Some(def_id) = path.res[0].opt_def_id() + && self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS) { let module = if is_integer_module(cx, def_id) { true @@ -137,8 +135,8 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { return; }; - if self.msrv.meets(msrvs::NUMERIC_ASSOCIATED_CONSTANTS) - && !expr.span.in_external_macro(cx.sess().source_map()) + if !expr.span.in_external_macro(cx.sess().source_map()) + && self.msrv.meets(cx, msrvs::NUMERIC_ASSOCIATED_CONSTANTS) && !is_from_proc_macro(cx, expr) { span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| { @@ -151,8 +149,6 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants { }); } } - - extract_msrv_attr!(LateContext); } fn is_integer_module(cx: &LateContext<'_>, did: DefId) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 13218331a67b2..cc3d972f017b8 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -340,6 +340,7 @@ mod significant_drop_tightening; mod single_call_fn; mod single_char_lifetime_names; mod single_component_path_imports; +mod single_option_map; mod single_range_in_vec_init; mod size_of_in_element_count; mod size_of_ref; @@ -407,9 +408,9 @@ mod zombie_processes; use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; +use utils::attr_collector::{AttrCollector, AttrStorage}; use rustc_data_structures::fx::FxHashSet; use rustc_lint::{Lint, LintId}; -use utils::attr_collector::{AttrCollector, AttrStorage}; /// Register all pre expansion lints /// @@ -717,6 +718,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf))); store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf))); store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf))); + store.register_early_pass(move || Box::new(doc::Documentation::new(conf))); store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply)); store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq)); store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence)); @@ -840,7 +842,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(non_send_fields_in_send_ty::NonSendFieldInSendTy::new(conf))); store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(conf))); let format_args = format_args_storage.clone(); - store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(conf, format_args.clone()))); + store.register_late_pass(move |tcx| Box::new(format_args::FormatArgs::new(tcx, conf, format_args.clone()))); store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray)); store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes)); store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit)); @@ -860,6 +862,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(pub_use::PubUse)); store.register_late_pass(|_| Box::new(format_push_string::FormatPushString)); store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf))); + store.register_early_pass(move || Box::new(large_include_file::LargeIncludeFile::new(conf))); store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace)); store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit)); store.register_early_pass(|| Box::::default()); @@ -902,7 +905,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(conf))); store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); store.register_late_pass(move |_| Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new(conf))); - store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); + store.register_late_pass(move |_| Box::new(lines_filter_map_ok::LinesFilterMapOk::new(conf))); store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(move || Box::new(excessive_nesting::ExcessiveNesting::new(conf))); @@ -946,7 +949,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::>::default()); store.register_late_pass(|_| Box::new(iter_over_hash_type::IterOverHashType)); store.register_late_pass(|_| Box::new(impl_hash_with_borrow_str_and_bytes::ImplHashWithBorrowStrBytes)); - store.register_late_pass(|_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity)); + store.register_late_pass(move |_| Box::new(repeat_vec_with_capacity::RepeatVecWithCapacity::new(conf))); store.register_late_pass(|_| Box::new(uninhabited_references::UninhabitedReferences)); store.register_late_pass(|_| Box::new(ineffective_open_options::IneffectiveOpenOptions)); store.register_late_pass(|_| Box::::default()); @@ -980,5 +983,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::::default()); store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf))); store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf))); + store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index f08812017b9cd..3dd2de1fafc72 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -38,8 +38,8 @@ declare_clippy_lint! { /// them leads to more readable code. /// /// ### Known problems - /// - We bail out if the function has a `where` clause where lifetimes - /// are mentioned due to potential false positives. + /// This lint ignores functions with `where` clauses that reference + /// lifetimes to prevent false positives. /// /// ### Example /// ```no_run @@ -62,6 +62,38 @@ declare_clippy_lint! { would allow omitting them" } +declare_clippy_lint! { + /// ### What it does + /// Checks for lifetime annotations which can be replaced with anonymous lifetimes (`'_`). + /// + /// ### Why is this bad? + /// The additional lifetimes can make the code look more complicated. + /// + /// ### Known problems + /// This lint ignores functions with `where` clauses that reference + /// lifetimes to prevent false positives. + /// + /// ### Example + /// ```no_run + /// # use std::str::Chars; + /// fn f<'a>(x: &'a str) -> Chars<'a> { + /// x.chars() + /// } + /// ``` + /// + /// Use instead: + /// ```no_run + /// # use std::str::Chars; + /// fn f(x: &str) -> Chars<'_> { + /// x.chars() + /// } + /// ``` + #[clippy::version = "1.84.0"] + pub ELIDABLE_LIFETIME_NAMES, + pedantic, + "lifetime name that can be replaced with the anonymous lifetime" +} + declare_clippy_lint! { /// ### What it does /// Checks for lifetimes in generics that are never used @@ -98,13 +130,15 @@ pub struct Lifetimes { impl Lifetimes { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } -impl_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]); +impl_lint_pass!(Lifetimes => [ + NEEDLESS_LIFETIMES, + ELIDABLE_LIFETIME_NAMES, + EXTRA_UNUSED_LIFETIMES, +]); impl<'tcx> LateLintPass<'tcx> for Lifetimes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { @@ -115,7 +149,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { .. } = item.kind { - check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, &self.msrv); + check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv); } else if let ItemKind::Impl(impl_) = item.kind { if !item.span.from_expansion() { report_extra_impl_lifetimes(cx, impl_); @@ -134,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { item.generics, item.span, report_extra_lifetimes, - &self.msrv, + self.msrv, ); } } @@ -145,11 +179,9 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes { TraitFn::Required(sig) => (None, Some(sig)), TraitFn::Provided(id) => (Some(id), None), }; - check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true, &self.msrv); + check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true, self.msrv); } } - - extract_msrv_attr!(LateContext); } #[allow(clippy::too_many_arguments)] @@ -161,7 +193,7 @@ fn check_fn_inner<'tcx>( generics: &'tcx Generics<'_>, span: Span, report_extra_lifetimes: bool, - msrv: &Msrv, + msrv: Msrv, ) { if span.in_external_macro(cx.sess().source_map()) || has_where_lifetimes(cx, generics) { return; @@ -234,7 +266,7 @@ fn could_use_elision<'tcx>( body: Option, trait_sig: Option<&[Ident]>, named_generics: &'tcx [GenericParam<'_>], - msrv: &Msrv, + msrv: Msrv, ) -> Option<(Vec, Vec)> { // There are two scenarios where elision works: // * no output references, all input references have different LT @@ -352,17 +384,12 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet( - cx: &LateContext<'tcx>, - func: &FnDecl<'tcx>, - ident: Option, - msrv: &Msrv, -) -> bool { - if !msrv.meets(msrvs::EXPLICIT_SELF_TYPE_ELISION) - && let Some(ident) = ident +fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option, msrv: Msrv) -> bool { + if let Some(ident) = ident && ident.name == kw::SelfLower && !func.implicit_self.has_implicit_self() && let Some(self_ty) = func.inputs.first() + && !msrv.meets(cx, msrvs::EXPLICIT_SELF_TYPE_ELISION) { let mut visitor = RefVisitor::new(cx); visitor.visit_ty_unambig(self_ty); @@ -746,6 +773,15 @@ fn report_elidable_impl_lifetimes<'tcx>( report_elidable_lifetimes(cx, impl_.generics, &elidable_lts, &usages, true); } +#[derive(Copy, Clone)] +enum ElidableUsage { + /// Used in a ref (`&'a T`), can be removed + Ref(Span), + /// Used as a generic param (`T<'a>`) or an impl lifetime (`impl T + 'a`), can be replaced + /// with `'_` + Other(Span), +} + /// Generate diagnostic messages for elidable lifetimes. fn report_elidable_lifetimes( cx: &LateContext<'_>, @@ -763,9 +799,29 @@ fn report_elidable_lifetimes( .collect::>() .join(", "); + let elidable_usages: Vec = usages + .iter() + .filter(|usage| named_lifetime(usage).is_some_and(|id| elidable_lts.contains(&id))) + .map(|usage| match cx.tcx.parent_hir_node(usage.hir_id) { + Node::Ty(Ty { + kind: TyKind::Ref(..), .. + }) => ElidableUsage::Ref(usage.ident.span), + _ => ElidableUsage::Other(usage.ident.span), + }) + .collect(); + + let lint = if elidable_usages + .iter() + .any(|usage| matches!(usage, ElidableUsage::Other(_))) + { + ELIDABLE_LIFETIME_NAMES + } else { + NEEDLESS_LIFETIMES + }; + span_lint_and_then( cx, - NEEDLESS_LIFETIMES, + lint, elidable_lts .iter() .map(|<| cx.tcx.def_span(lt)) @@ -785,7 +841,7 @@ fn report_elidable_lifetimes( return; } - if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, usages) { + if let Some(suggestions) = elision_suggestions(cx, generics, elidable_lts, &elidable_usages) { diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable); } }, @@ -796,7 +852,7 @@ fn elision_suggestions( cx: &LateContext<'_>, generics: &Generics<'_>, elidable_lts: &[LocalDefId], - usages: &[Lifetime], + usages: &[ElidableUsage], ) -> Option> { let explicit_params = generics .params @@ -836,26 +892,21 @@ fn elision_suggestions( .collect::>>()? }; - suggestions.extend( - usages - .iter() - .filter(|usage| named_lifetime(usage).is_some_and(|id| elidable_lts.contains(&id))) - .map(|usage| { - match cx.tcx.parent_hir_node(usage.hir_id) { - Node::Ty(Ty { - kind: TyKind::Ref(..), .. - }) => { - // expand `&'a T` to `&'a T` - // ^^ ^^^ - let span = cx.sess().source_map().span_extend_while_whitespace(usage.ident.span); - - (span, String::new()) - }, - // `T<'a>` and `impl Foo + 'a` should be replaced by `'_` - _ => (usage.ident.span, String::from("'_")), - } - }), - ); + suggestions.extend(usages.iter().map(|&usage| { + match usage { + ElidableUsage::Ref(span) => { + // expand `&'a T` to `&'a T` + // ^^ ^^^ + let span = cx.sess().source_map().span_extend_while_whitespace(span); + + (span, String::new()) + }, + ElidableUsage::Other(span) => { + // `T<'a>` and `impl Foo + 'a` should be replaced by `'_` + (span, String::from("'_")) + }, + } + })); Some(suggestions) } 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 f022598651b77..d8af44233d3ee 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 @@ -1,12 +1,24 @@ +use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::{is_diag_item_method, is_trait_method, path_to_local_id}; use rustc_errors::Applicability; use rustc_hir::{Body, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::sym; +pub struct LinesFilterMapOk { + msrv: Msrv, +} + +impl LinesFilterMapOk { + pub fn new(conf: &Conf) -> Self { + Self { msrv: conf.msrv } + } +} + declare_clippy_lint! { /// ### What it does /// Checks for usage of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` @@ -55,7 +67,8 @@ declare_clippy_lint! { suspicious, "filtering `std::io::Lines` with `filter_map()`, `flat_map()`, or `flatten()` might cause an infinite loop" } -declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); + +impl_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]); impl LateLintPass<'_> for LinesFilterMapOk { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { @@ -65,6 +78,7 @@ impl LateLintPass<'_> for LinesFilterMapOk { && matches!(fm_method_str, "filter_map" | "flat_map" | "flatten") && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines) && should_lint(cx, fm_args, fm_method_str) + && self.msrv.meets(cx, msrvs::MAP_WHILE) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs b/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs index a957c0e22a292..975e6833a35f8 100644 --- a/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs +++ b/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs @@ -7,6 +7,7 @@ use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Span}; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_from_proc_macro; use clippy_utils::mir::enclosing_mir; declare_clippy_lint! { @@ -79,9 +80,9 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, spans: &[(Span, Option for LiteralStringWithFormattingArg { - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if expr.span.from_expansion() { +impl<'tcx> LateLintPass<'tcx> for LiteralStringWithFormattingArg { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { + if expr.span.from_expansion() || expr.span.is_dummy() { return; } if let ExprKind::Lit(lit) = expr.kind { @@ -95,6 +96,9 @@ impl LateLintPass<'_> for LiteralStringWithFormattingArg { }, _ => return, }; + if is_from_proc_macro(cx, expr) { + return; + } let fmt_str = symbol.as_str(); let lo = expr.span.lo(); let mut current = fmt_str; @@ -124,7 +128,11 @@ impl LateLintPass<'_> for LiteralStringWithFormattingArg { pos.start += diff_len; pos.end += diff_len; - let start = fmt_str[..pos.start].rfind('{').unwrap_or(pos.start); + let mut start = pos.start; + while start < fmt_str.len() && !fmt_str.is_char_boundary(start) { + start += 1; + } + let start = fmt_str[..start].rfind('{').unwrap_or(start); // If this is a unicode character escape, we don't want to lint. if start > 1 && fmt_str[..start].ends_with("\\u") { continue; diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index 06cf901bfb231..412c78cc80411 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -17,7 +17,7 @@ pub(super) fn check( cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, enforce_iter_loop_reborrow: bool, ) { let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr, enforce_iter_loop_reborrow, msrv) else { @@ -26,10 +26,11 @@ pub(super) fn check( if let ty::Array(_, count) = *ty.peel_refs().kind() { if !ty.is_ref() { - if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) { + if !msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) { return; } - } else if count.try_to_target_usize(cx.tcx).is_none_or(|x| x > 32) && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN) { + } else if count.try_to_target_usize(cx.tcx).is_none_or(|x| x > 32) && !msrv.meets(cx, msrvs::ARRAY_IMPL_ANY_LEN) + { return; } } @@ -106,7 +107,7 @@ fn is_ref_iterable<'tcx>( self_arg: &Expr<'_>, call_expr: &Expr<'_>, enforce_iter_loop_reborrow: bool, - msrv: &Msrv, + msrv: Msrv, ) -> Option<(AdjustKind, Ty<'tcx>)> { let typeck = cx.typeck_results(); if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) @@ -126,8 +127,8 @@ fn is_ref_iterable<'tcx>( let self_ty = typeck.expr_ty(self_arg); let self_is_copy = is_copy(cx, self_ty); - if !msrv.meets(msrvs::BOX_INTO_ITER) - && is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox) + if is_type_lang_item(cx, self_ty.peel_refs(), rustc_hir::LangItem::OwnedBox) + && !msrv.meets(cx, msrvs::BOX_INTO_ITER) { return None; } 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 366c310592f57..9b6f97b9a2eb0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -1,6 +1,7 @@ use super::MANUAL_FLATTEN; use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, path_to_local_id, peel_blocks_with_stmt}; use rustc_errors::Applicability; @@ -18,6 +19,7 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>, span: Span, + msrv: Msrv, ) { let inner_expr = peel_blocks_with_stmt(body); if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else: None, .. }) @@ -34,6 +36,7 @@ pub(super) fn check<'tcx>( && (some_ctor || ok_ctor) // Ensure expr in `if let` is not used afterwards && !is_local_used(cx, if_then, pat_hir_id) + && msrv.meets(cx, msrvs::ITER_FLATTEN) { let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs index 7c6564235796a..343f7c5d2d121 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_slice_fill.rs @@ -1,9 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; -use clippy_utils::macros::span_is_local; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{HasSession, snippet_with_applicability}; use clippy_utils::ty::implements_trait; +use clippy_utils::visitors::is_local_used; use clippy_utils::{higher, peel_blocks_with_stmt, span_contains_comment}; use rustc_ast::ast::LitKind; use rustc_ast::{RangeLimits, UnOp}; @@ -24,12 +24,8 @@ pub(super) fn check<'tcx>( arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>, expr: &'tcx Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) { - if !msrv.meets(msrvs::SLICE_FILL) { - return; - } - // `for _ in 0..slice.len() { slice[_] = value; }` if let Some(higher::Range { start: Some(start), @@ -43,7 +39,7 @@ pub(super) fn check<'tcx>( && let ExprKind::Block(..) = body.kind // Check if the body is an assignment to a slice element. && let ExprKind::Assign(assignee, assignval, _) = peel_blocks_with_stmt(body).kind - && let ExprKind::Index(slice, _, _) = assignee.kind + && let ExprKind::Index(slice, idx, _) = assignee.kind // Check if `len()` is used for the range end. && let ExprKind::MethodCall(path, recv,..) = end.kind && path.ident.name == sym::len @@ -54,10 +50,14 @@ pub(super) fn check<'tcx>( && !assignval.span.from_expansion() // It is generally not equivalent to use the `fill` method if `assignval` can have side effects && switch_to_eager_eval(cx, assignval) - && span_is_local(assignval.span) // The `fill` method requires that the slice's element type implements the `Clone` trait. && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() && implements_trait(cx, cx.typeck_results().expr_ty(slice), clone_trait, &[]) + // https://github.com/rust-lang/rust-clippy/issues/14192 + && let ExprKind::Path(Resolved(_, idx_path)) = idx.kind + && let Res::Local(idx_hir) = idx_path.res + && !is_local_used(cx, assignval, idx_hir) + && msrv.meets(cx, msrvs::SLICE_FILL) { sugg(cx, body, expr, slice.span, assignval.span); } @@ -73,10 +73,12 @@ pub(super) fn check<'tcx>( && local == pat.hir_id && !assignval.span.from_expansion() && switch_to_eager_eval(cx, assignval) - && span_is_local(assignval.span) + // `assignval` must not reference the iterator + && !is_local_used(cx, assignval, local) // The `fill` method cannot be used if the slice's element type does not implement the `Clone` trait. && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() && implements_trait(cx, cx.typeck_results().expr_ty(recv), clone_trait, &[]) + && msrv.meets(cx, msrvs::SLICE_FILL) { sugg(cx, body, expr, recv_path.span, assignval.span); } diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index cdc8c18c3b74e..ed725a0398910 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -747,7 +747,7 @@ pub struct Loops { impl Loops { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: conf.msrv, enforce_iter_loop_reborrow: conf.enforce_iter_loop_reborrow, } } @@ -832,8 +832,6 @@ impl<'tcx> LateLintPass<'tcx> for Loops { manual_while_let_some::check(cx, condition, body, span); } } - - extract_msrv_attr!(LateContext); } impl Loops { @@ -850,7 +848,7 @@ impl Loops { ) { let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr); if !is_manual_memcpy_triggered { - manual_slice_fill::check(cx, pat, arg, body, expr, &self.msrv); + manual_slice_fill::check(cx, pat, arg, body, expr, self.msrv); needless_range_loop::check(cx, pat, arg, body, expr); explicit_counter_loop::check(cx, pat, arg, body, expr, label); } @@ -858,8 +856,8 @@ impl Loops { for_kv_map::check(cx, pat, arg, body); mut_range_bound::check(cx, arg, body); single_element_loop::check(cx, pat, arg, body, expr); - same_item_push::check(cx, pat, arg, body, expr, &self.msrv); - manual_flatten::check(cx, pat, arg, body, span); + same_item_push::check(cx, pat, arg, body, expr, self.msrv); + manual_flatten::check(cx, pat, arg, body, span, self.msrv); manual_find::check(cx, pat, arg, body, span, expr); unused_enumerate_index::check(cx, pat, arg, body); } @@ -868,7 +866,7 @@ impl Loops { if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind { match method.ident.as_str() { "iter" | "iter_mut" => { - explicit_iter_loop::check(cx, self_arg, arg, &self.msrv, self.enforce_iter_loop_reborrow); + explicit_iter_loop::check(cx, self_arg, arg, self.msrv, self.enforce_iter_loop_reborrow); }, "into_iter" => { explicit_into_iter_loop::check(cx, self_arg, arg); 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 39e5e140b7a40..fb5d49a100475 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 @@ -79,6 +79,8 @@ struct MutatePairDelegate<'a, 'tcx> { impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { if let PlaceBase::Local(id) = cmt.place.base { 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 b679fdfadc3a9..dd7a6f77acff5 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -160,6 +160,7 @@ fn never_loop_expr<'tcx>( | ExprKind::UnsafeBinderCast(_, 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::Use(expr, _) => never_loop_expr(cx, expr, local_labels, main_loop_id), ExprKind::MethodCall(_, receiver, es, _) => { never_loop_expr_all(cx, once(receiver).chain(es.iter()), local_labels, main_loop_id) }, 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 c27e930c99a5e..661b4b590d8fb 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 @@ -20,14 +20,14 @@ pub(super) fn check<'tcx>( _: &'tcx Expr<'_>, body: &'tcx Expr<'_>, _: &'tcx Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) { - fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext, msrv: &Msrv) { + fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>, ctxt: SyntaxContext, msrv: Msrv) { let mut app = Applicability::Unspecified; let vec_str = snippet_with_context(cx, vec.span, ctxt, "", &mut app).0; let item_str = snippet_with_context(cx, pushed_item.span, ctxt, "", &mut app).0; - let secondary_help = if msrv.meets(msrvs::REPEAT_N) + let secondary_help = if msrv.meets(cx, msrvs::REPEAT_N) && let Some(std_or_core) = std_or_core(cx) { format!("or `{vec_str}.extend({std_or_core}::iter::repeat_n({item_str}, SIZE))`") diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 3741286653929..b712b351d063c 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -21,7 +21,21 @@ declare_clippy_lint! { /// ### Example /// ```rust,ignore /// #[macro_use] - /// use some_macro; + /// extern crate some_crate; + /// + /// fn main() { + /// some_macro!(); + /// } + /// ``` + /// + /// Use instead: + /// + /// ```rust,ignore + /// use some_crate::some_macro; + /// + /// fn main() { + /// some_macro!(); + /// } /// ``` #[clippy::version = "1.44.0"] pub MACRO_USE_IMPORTS, @@ -84,7 +98,7 @@ impl LateLintPass<'_> for MacroUseImports { if cx.sess().opts.edition >= Edition::Edition2018 && let hir::ItemKind::Use(path, _kind) = &item.kind && let hir_id = item.hir_id() - && let attrs = cx.tcx.hir().attrs(hir_id) + && let attrs = cx.tcx.hir_attrs(hir_id) && let Some(mac_attr) = attrs.iter().find(|attr| attr.has_name(sym::macro_use)) && let Some(id) = path.res.iter().find_map(|res| match res { Res::Def(DefKind::Mod, id) => Some(id), @@ -94,7 +108,7 @@ impl LateLintPass<'_> for MacroUseImports { { for kid in cx.tcx.module_children(id) { if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res { - let span = mac_attr.span; + let span = mac_attr.span(); let def_path = cx.tcx.def_path_str(mac_id); self.imports.push((def_path, span, hir_id)); } @@ -103,11 +117,6 @@ impl LateLintPass<'_> for MacroUseImports { self.push_unique_macro_pat_ty(cx, item.span); } } - fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) { - if attr.span.from_expansion() { - self.push_unique_macro(cx, attr.span); - } - } fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { if expr.span.from_expansion() { self.push_unique_macro(cx, expr.span); diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 6f3a7d8cccc8f..abd1ac954cda8 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -62,6 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualAsyncFn { && let Some(closure_body) = desugared_async_block(cx, block) && let Node::Item(Item {vis_span, ..}) | Node::ImplItem(ImplItem {vis_span, ..}) = cx.tcx.hir_node_by_def_id(fn_def_id) + && !span.from_expansion() { let header_span = span.with_hi(ret_ty.span.hi()); diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index 17e25635ce105..39c4857b3e874 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -40,9 +40,7 @@ pub struct ManualBits { impl ManualBits { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -53,7 +51,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind && let BinOpKind::Mul = &bin_op.node && !expr.span.from_expansion() - && self.msrv.meets(msrvs::MANUAL_BITS) && let ctxt = expr.span.ctxt() && left_expr.span.ctxt() == ctxt && right_expr.span.ctxt() == ctxt @@ -61,6 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { && matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_)) && let ExprKind::Lit(lit) = &other_expr.kind && let LitKind::Int(Pu128(8), _) = lit.node + && self.msrv.meets(cx, msrvs::INTEGER_BITS) { let mut app = Applicability::MachineApplicable; let ty_snip = snippet_with_context(cx, real_ty_span, ctxt, "..", &mut app).0; @@ -77,8 +75,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits { ); } } - - extract_msrv_attr!(LateContext); } fn get_one_size_of_ty<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 484a7ba256bda..50c8331eebab4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -99,9 +99,7 @@ pub struct ManualClamp { impl ManualClamp { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -144,30 +142,28 @@ struct InputMinMax<'tcx> { impl<'tcx> LateLintPass<'tcx> for ManualClamp { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if !self.msrv.meets(msrvs::CLAMP) { - return; - } if !expr.span.from_expansion() && !is_in_const_context(cx) { let suggestion = is_if_elseif_else_pattern(cx, expr) .or_else(|| is_max_min_pattern(cx, expr)) .or_else(|| is_call_max_min_pattern(cx, expr)) .or_else(|| is_match_pattern(cx, expr)) .or_else(|| is_if_elseif_pattern(cx, expr)); - if let Some(suggestion) = suggestion { + if let Some(suggestion) = suggestion + && self.msrv.meets(cx, msrvs::CLAMP) + { maybe_emit_suggestion(cx, &suggestion); } } } fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) { - if !self.msrv.meets(msrvs::CLAMP) || is_in_const_context(cx) { + if is_in_const_context(cx) || !self.msrv.meets(cx, msrvs::CLAMP) { return; } for suggestion in is_two_if_pattern(cx, block) { maybe_emit_suggestion(cx, &suggestion); } } - extract_msrv_attr!(LateContext); } fn maybe_emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggestion<'tcx>) { diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs index 04357cdd8f663..9c1419175d55c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -49,9 +49,7 @@ pub struct ManualDivCeil { impl ManualDivCeil { #[must_use] pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -59,10 +57,6 @@ impl_lint_pass!(ManualDivCeil => [MANUAL_DIV_CEIL]); impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { - if !self.msrv.meets(msrvs::MANUAL_DIV_CEIL) { - return; - } - let mut applicability = Applicability::MachineApplicable; if let ExprKind::Binary(div_op, div_lhs, div_rhs) = expr.kind @@ -70,6 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { && check_int_ty_and_feature(cx, div_lhs) && check_int_ty_and_feature(cx, div_rhs) && let ExprKind::Binary(inner_op, inner_lhs, inner_rhs) = div_lhs.kind + && self.msrv.meets(cx, msrvs::MANUAL_DIV_CEIL) { // (x + (y - 1)) / y if let ExprKind::Binary(sub_op, sub_lhs, sub_rhs) = inner_rhs.kind @@ -122,8 +117,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualDivCeil { } } } - - extract_msrv_attr!(LateContext); } /// Checks if two expressions represent non-zero integer literals such that `small_expr + 1 == diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs index 2a5aa12d126cb..bd2785fea2709 100644 --- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs +++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs @@ -90,9 +90,7 @@ pub struct ManualFloatMethods { impl ManualFloatMethods { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -144,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { && !expr.span.in_external_macro(cx.sess().source_map()) && ( is_not_const(cx.tcx, cx.tcx.hir_enclosing_body_owner(expr.hir_id).into()) - || self.msrv.meets(msrvs::CONST_FLOAT_CLASSIFY) + || self.msrv.meets(cx, msrvs::CONST_FLOAT_CLASSIFY) ) && let [first, second, const_1, const_2] = exprs && let ecx = ConstEvalCtxt::new(cx) @@ -202,8 +200,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods { }); } } - - extract_msrv_attr!(LateContext); } fn is_infinity(constant: &Constant<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs index 7e092d11f1b47..f71264a93ca84 100644 --- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -53,9 +53,7 @@ pub struct ManualHashOne { impl ManualHashOne { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -98,7 +96,7 @@ impl LateLintPass<'_> for ManualHashOne { && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind && seg.ident.name.as_str() == "finish" - && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE) + && self.msrv.meets(cx, msrvs::BUILD_HASHER_HASH_ONE) { span_lint_hir_and_then( cx, @@ -129,6 +127,4 @@ impl LateLintPass<'_> for ManualHashOne { ); } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 38106277a88fe..faf01a276a131 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -64,9 +64,7 @@ pub struct ManualIsAsciiCheck { impl ManualIsAsciiCheck { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -91,11 +89,11 @@ enum CharRange { impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if !self.msrv.meets(msrvs::IS_ASCII_DIGIT) { + if !self.msrv.meets(cx, msrvs::IS_ASCII_DIGIT) { return; } - if is_in_const_context(cx) && !self.msrv.meets(msrvs::IS_ASCII_DIGIT_CONST) { + if is_in_const_context(cx) && !self.msrv.meets(cx, msrvs::IS_ASCII_DIGIT_CONST) { return; } @@ -119,8 +117,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { check_is_ascii(cx, expr.span, arg, &range, ty_sugg); } } - - extract_msrv_attr!(LateContext); } fn get_ty_sugg<'tcx>(cx: &LateContext<'tcx>, arg: &Expr<'_>) -> Option<(Span, Ty<'tcx>)> { diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 3643b8c4425ec..47939767212ef 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -53,8 +53,8 @@ impl<'tcx> QuestionMark { && local.ty.is_none() && init.span.eq_ctxt(stmt.span) && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) - && self.msrv.meets(msrvs::LET_ELSE) && !stmt.span.in_external_macro(cx.sess().source_map()) + && self.msrv.meets(cx, msrvs::LET_ELSE) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => { diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs index b7563a2508d0f..f54ccf2c87b0f 100644 --- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs +++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs @@ -39,9 +39,7 @@ pub struct ManualMainSeparatorStr { impl ManualMainSeparatorStr { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -55,10 +53,10 @@ impl LateLintPass<'_> for ManualMainSeparatorStr { && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind && let Res::Def(DefKind::Const, receiver_def_id) = path.res && is_trait_method(cx, target, sym::ToString) - && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) && cx.tcx.is_diagnostic_item(sym::path_main_separator, receiver_def_id) && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() && ty.is_str() + && self.msrv.meets(cx, msrvs::PATH_MAIN_SEPARATOR_STR) { span_lint_and_sugg( cx, @@ -71,6 +69,4 @@ impl LateLintPass<'_> for ManualMainSeparatorStr { ); } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index 00800231fe46e..64b07a5536b4d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -71,7 +71,7 @@ pub struct ManualNonExhaustive { impl ManualNonExhaustive { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: conf.msrv, constructed_enum_variants: FxHashSet::default(), potential_enums: Vec::new(), } @@ -82,18 +82,18 @@ impl_lint_pass!(ManualNonExhaustive => [MANUAL_NON_EXHAUSTIVE]); impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) || !cx.effective_visibilities.is_exported(item.owner_id.def_id) { + if !cx.effective_visibilities.is_exported(item.owner_id.def_id) || !self.msrv.meets(cx, msrvs::NON_EXHAUSTIVE) { return; } match item.kind { ItemKind::Enum(def, _) if def.variants.len() > 1 => { let iter = def.variants.iter().filter_map(|v| { - (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))) + (matches!(v.data, VariantData::Unit(_, _)) && is_doc_hidden(cx.tcx.hir_attrs(v.hir_id))) .then_some((v.def_id, v.span)) }); if let Ok((id, span)) = iter.exactly_one() - && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + && !attr::contains_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive) { self.potential_enums.push((item.owner_id.def_id, id, item.span, span)); } @@ -114,9 +114,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { "this seems like a manual implementation of the non-exhaustive pattern", |diag| { if let Some(non_exhaustive) = - attr::find_by_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive) + attr::find_by_name(cx.tcx.hir_attrs(item.hir_id()), sym::non_exhaustive) { - diag.span_note(non_exhaustive.span, "the struct is already non-exhaustive"); + diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive"); } else { let indent = snippet_indent(cx, item.span).unwrap_or_default(); diag.span_suggestion_verbose( @@ -171,6 +171,4 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive { ); } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs index e4360518b66e2..8dee29b2a0b5d 100644 --- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs +++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs @@ -1,5 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::msrvs::Msrv; use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -40,31 +41,21 @@ declare_clippy_lint! { } pub struct ManualOptionAsSlice { - msrv: msrvs::Msrv, + msrv: Msrv, } impl ManualOptionAsSlice { pub fn new(conf: &Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } impl_lint_pass!(ManualOptionAsSlice => [MANUAL_OPTION_AS_SLICE]); impl LateLintPass<'_> for ManualOptionAsSlice { - extract_msrv_attr!(LateContext); - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let span = expr.span; - if span.from_expansion() - || !self.msrv.meets(if clippy_utils::is_in_const_context(cx) { - msrvs::CONST_OPTION_AS_SLICE - } else { - msrvs::OPTION_AS_SLICE - }) - { + if span.from_expansion() { return; } match expr.kind { @@ -72,7 +63,7 @@ impl LateLintPass<'_> for ManualOptionAsSlice { if is_none_arm(cx, arm2) && check_arms(cx, arm2, arm1) || is_none_arm(cx, arm1) && check_arms(cx, arm1, arm2) { - check_as_ref(cx, scrutinee, span); + check_as_ref(cx, scrutinee, span, self.msrv); } }, ExprKind::If(cond, then, Some(other)) => { @@ -81,23 +72,23 @@ impl LateLintPass<'_> for ManualOptionAsSlice { && check_some_body(cx, binding, then) && is_empty_slice(cx, other.peel_blocks()) { - check_as_ref(cx, let_expr.init, span); + check_as_ref(cx, let_expr.init, span, self.msrv); } }, ExprKind::MethodCall(seg, callee, [], _) => { if seg.ident.name.as_str() == "unwrap_or_default" { - check_map(cx, callee, span); + check_map(cx, callee, span, self.msrv); } }, ExprKind::MethodCall(seg, callee, [or], _) => match seg.ident.name.as_str() { "unwrap_or" => { if is_empty_slice(cx, or) { - check_map(cx, callee, span); + check_map(cx, callee, span, self.msrv); } }, "unwrap_or_else" => { if returns_empty_slice(cx, or) { - check_map(cx, callee, span); + check_map(cx, callee, span, self.msrv); } }, _ => {}, @@ -105,12 +96,12 @@ impl LateLintPass<'_> for ManualOptionAsSlice { ExprKind::MethodCall(seg, callee, [or_else, map], _) => match seg.ident.name.as_str() { "map_or" => { if is_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) { - check_as_ref(cx, callee, span); + check_as_ref(cx, callee, span, self.msrv); } }, "map_or_else" => { if returns_empty_slice(cx, or_else) && is_slice_from_ref(cx, map) { - check_as_ref(cx, callee, span); + check_as_ref(cx, callee, span, self.msrv); } }, _ => {}, @@ -120,20 +111,28 @@ impl LateLintPass<'_> for ManualOptionAsSlice { } } -fn check_map(cx: &LateContext<'_>, map: &Expr<'_>, span: Span) { +fn check_map(cx: &LateContext<'_>, map: &Expr<'_>, span: Span, msrv: Msrv) { if let ExprKind::MethodCall(seg, callee, [mapping], _) = map.kind && seg.ident.name == sym::map && is_slice_from_ref(cx, mapping) { - check_as_ref(cx, callee, span); + check_as_ref(cx, callee, span, msrv); } } -fn check_as_ref(cx: &LateContext<'_>, expr: &Expr<'_>, span: Span) { +fn check_as_ref(cx: &LateContext<'_>, expr: &Expr<'_>, span: Span, msrv: Msrv) { if let ExprKind::MethodCall(seg, callee, [], _) = expr.kind && seg.ident.name == sym::as_ref && let ty::Adt(adtdef, ..) = cx.typeck_results().expr_ty(callee).kind() && cx.tcx.is_diagnostic_item(sym::Option, adtdef.did()) + && msrv.meets( + cx, + if clippy_utils::is_in_const_context(cx) { + msrvs::CONST_OPTION_AS_SLICE + } else { + msrvs::OPTION_AS_SLICE + }, + ) { if let Some(snippet) = clippy_utils::source::snippet_opt(cx, callee.span) { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs index 469b4b7cf89fb..41e07e26bff0a 100644 --- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs +++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs @@ -39,9 +39,7 @@ pub struct ManualRemEuclid { impl ManualRemEuclid { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -60,8 +58,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { && add_lhs.span.ctxt() == ctxt && add_rhs.span.ctxt() == ctxt && !expr.span.in_external_macro(cx.sess().source_map()) - && self.msrv.meets(msrvs::REM_EUCLID) - && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !is_in_const_context(cx)) && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs) && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs) && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind @@ -73,6 +69,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { && const2 == const3 && rem2_lhs.span.ctxt() == ctxt && rem2_rhs.span.ctxt() == ctxt + && self.msrv.meets(cx, msrvs::REM_EUCLID) + && (self.msrv.meets(cx, msrvs::REM_EUCLID_CONST) || !is_in_const_context(cx)) { // Apply only to params or locals with annotated types match cx.tcx.parent_hir_node(hir_id) { @@ -99,8 +97,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid { ); } } - - extract_msrv_attr!(LateContext); } // Checks if either the left or right expressions can be an unsigned int constant and returns that diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 0a4e756096e92..16dd1ad4e4784 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -50,9 +50,7 @@ pub struct ManualRetain { impl ManualRetain { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -66,13 +64,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualRetain { && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id) && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id) { - check_into_iter(cx, left_expr, target_expr, expr.span, &self.msrv); - check_iter(cx, left_expr, target_expr, expr.span, &self.msrv); - check_to_owned(cx, left_expr, target_expr, expr.span, &self.msrv); + check_into_iter(cx, left_expr, target_expr, expr.span, self.msrv); + check_iter(cx, left_expr, target_expr, expr.span, self.msrv); + check_to_owned(cx, left_expr, target_expr, expr.span, self.msrv); } } - - extract_msrv_attr!(LateContext); } fn check_into_iter( @@ -80,7 +76,7 @@ fn check_into_iter( left_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>, parent_expr_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { if let hir::ExprKind::MethodCall(_, into_iter_expr, [_], _) = &target_expr.kind && let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) @@ -123,7 +119,7 @@ fn check_iter( left_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>, parent_expr_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(copied_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) @@ -181,10 +177,9 @@ fn check_to_owned( left_expr: &hir::Expr<'_>, target_expr: &hir::Expr<'_>, parent_expr_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { - if msrv.meets(msrvs::STRING_RETAIN) - && let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind + if let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind && let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id) && cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id) && let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind @@ -200,6 +195,7 @@ fn check_to_owned( && let hir::ExprKind::Closure(closure) = closure_expr.kind && let filter_body = cx.tcx.hir_body(closure.body) && let [filter_params] = filter_body.params + && msrv.meets(cx, msrvs::STRING_RETAIN) { if let hir::PatKind::Ref(pat, _) = filter_params.pat.kind { make_span_lint_and_sugg( @@ -253,7 +249,7 @@ fn match_acceptable_sym(cx: &LateContext<'_>, collect_def_id: DefId) -> bool { .any(|&method| cx.tcx.is_diagnostic_item(method, collect_def_id)) } -fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv) -> bool { +fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: Msrv) -> bool { let ty = cx.typeck_results().expr_ty(expr).peel_refs(); let required = match get_type_diagnostic_name(cx, ty) { Some(sym::BinaryHeap) => msrvs::BINARY_HEAP_RETAIN, @@ -264,7 +260,7 @@ fn match_acceptable_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>, msrv: &Msrv Some(sym::Vec | sym::VecDeque) => return true, _ => return false, }; - msrv.meets(required) + msrv.meets(cx, required) } fn match_map_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index d69384a2cb702..9e911e61f1968 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -2,19 +2,21 @@ use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_with_applicability; use clippy_utils::usage::mutated_variables; use clippy_utils::{eq_expr_value, higher}; +use rustc_ast::BindingMode; use rustc_ast::ast::LitKind; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::intravisit::{Visitor, walk_expr}; -use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir::intravisit::{Visitor, walk_expr, walk_pat}; +use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, Node, PatKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext as _}; use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; +use rustc_span::{Symbol, sym}; use std::iter; declare_clippy_lint! { @@ -54,9 +56,7 @@ pub struct ManualStrip { impl ManualStrip { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -73,7 +73,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr) && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind && let ExprKind::Path(target_path) = &target_arg.kind - && self.msrv.meets(msrvs::STR_STRIP_PREFIX) && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id) { let strip_kind = if cx.tcx.is_diagnostic_item(sym::str_starts_with, method_def_id) { @@ -95,18 +94,37 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { return; } - let strippings = find_stripping(cx, strip_kind, target_res, pattern, then); - if !strippings.is_empty() { + let (strippings, bindings) = find_stripping(cx, strip_kind, target_res, pattern, then); + if !strippings.is_empty() && self.msrv.meets(cx, msrvs::STR_STRIP_PREFIX) { let kind_word = match strip_kind { StripKind::Prefix => "prefix", StripKind::Suffix => "suffix", }; let test_span = expr.span.until(then.span); + + // If the first use is a simple `let` statement, reuse its identifier in the `if let Some(…)` and + // remove the `let` statement as long as the identifier is never bound again within the lexical + // scope of interest. + let (ident_name, let_stmt_span, skip, mut app) = if let Node::LetStmt(let_stmt) = + cx.tcx.parent_hir_node(strippings[0].hir_id) + && let PatKind::Binding(BindingMode::NONE, _, ident, None) = &let_stmt.pat.kind + && bindings.get(&ident.name) == Some(&1) + { + ( + ident.name.as_str(), + Some(cx.sess().source_map().span_extend_while_whitespace(let_stmt.span)), + 1, + Applicability::MachineApplicable, + ) + } else { + ("", None, 0, Applicability::HasPlaceholders) + }; + span_lint_and_then( cx, MANUAL_STRIP, - strippings[0], + strippings[0].span, format!("stripping a {kind_word} manually"), |diag| { diag.span_note(test_span, format!("the {kind_word} was tested here")); @@ -115,22 +133,26 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { iter::once(( test_span, format!( - "if let Some() = {}.strip_{kind_word}({}) ", - snippet(cx, target_arg.span, ".."), - snippet(cx, pattern.span, "..") + "if let Some({ident_name}) = {}.strip_{kind_word}({}) ", + snippet_with_applicability(cx, target_arg.span, "_", &mut app), + snippet_with_applicability(cx, pattern.span, "_", &mut app) ), )) - .chain(strippings.into_iter().map(|span| (span, "".into()))) + .chain(let_stmt_span.map(|span| (span, String::new()))) + .chain( + strippings + .into_iter() + .skip(skip) + .map(|expr| (expr.span, ident_name.into())), + ) .collect(), - Applicability::HasPlaceholders, + app, ); }, ); } } } - - extract_msrv_attr!(LateContext); } // Returns `Some(arg)` if `expr` matches `arg.len()` and `None` otherwise. @@ -188,19 +210,21 @@ fn peel_ref<'a>(expr: &'a Expr<'_>) -> &'a Expr<'a> { /// Find expressions where `target` is stripped using the length of `pattern`. /// We'll suggest replacing these expressions with the result of the `strip_{prefix,suffix}` /// method. +/// Also, all bindings found during the visit are counted and returned. fn find_stripping<'tcx>( cx: &LateContext<'tcx>, strip_kind: StripKind, target: Res, pattern: &'tcx Expr<'_>, - expr: &'tcx Expr<'_>, -) -> Vec { + expr: &'tcx Expr<'tcx>, +) -> (Vec<&'tcx Expr<'tcx>>, FxHashMap) { struct StrippingFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, strip_kind: StripKind, target: Res, pattern: &'tcx Expr<'tcx>, - results: Vec, + results: Vec<&'tcx Expr<'tcx>>, + bindings: FxHashMap, } impl<'tcx> Visitor<'tcx> for StrippingFinder<'_, 'tcx> { @@ -215,7 +239,7 @@ fn find_stripping<'tcx>( match (self.strip_kind, start, end) { (StripKind::Prefix, Some(start), None) => { if eq_pattern_length(self.cx, self.pattern, start) { - self.results.push(ex.span); + self.results.push(ex); return; } }, @@ -232,7 +256,7 @@ fn find_stripping<'tcx>( && self.cx.qpath_res(left_path, left_arg.hir_id) == self.target && eq_pattern_length(self.cx, self.pattern, right) { - self.results.push(ex.span); + self.results.push(ex); return; } }, @@ -242,6 +266,13 @@ fn find_stripping<'tcx>( walk_expr(self, ex); } + + fn visit_pat(&mut self, pat: &'tcx rustc_hir::Pat<'tcx>) -> Self::Result { + if let PatKind::Binding(_, _, ident, _) = pat.kind { + *self.bindings.entry(ident.name).or_default() += 1; + } + walk_pat(self, pat); + } } let mut finder = StrippingFinder { @@ -250,7 +281,8 @@ fn find_stripping<'tcx>( target, pattern, results: vec![], + bindings: FxHashMap::default(), }; walk_expr(&mut finder, expr); - finder.results + (finder.results, finder.bindings) } 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 97e8423695d99..6f446bf956587 100644 --- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs @@ -14,7 +14,7 @@ use rustc_span::Span; use super::{COLLAPSIBLE_MATCH, pat_contains_disallowed_or}; -pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: &Msrv) { +pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], msrv: Msrv) { if let Some(els_arm) = arms.iter().rfind(|arm| arm_is_wild_like(cx, arm)) { for arm in arms { check_arm(cx, true, arm.pat, arm.body, arm.guard, Some(els_arm.body), msrv); @@ -27,7 +27,7 @@ pub(super) fn check_if_let<'tcx>( pat: &'tcx Pat<'_>, body: &'tcx Expr<'_>, else_expr: Option<&'tcx Expr<'_>>, - msrv: &Msrv, + msrv: Msrv, ) { check_arm(cx, false, pat, body, None, else_expr, msrv); } @@ -39,7 +39,7 @@ fn check_arm<'tcx>( outer_then_body: &'tcx Expr<'tcx>, outer_guard: Option<&'tcx Expr<'tcx>>, outer_else_body: Option<&'tcx Expr<'tcx>>, - msrv: &Msrv, + msrv: Msrv, ) { let inner_expr = peel_blocks_with_stmt(outer_then_body); if let Some(inner) = IfLetOrMatch::parse(cx, inner_expr) @@ -60,7 +60,7 @@ fn check_arm<'tcx>( // match expression must be a local binding // match { .. } && let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee)) - && !pat_contains_disallowed_or(inner_then_pat, msrv) + && !pat_contains_disallowed_or(cx, inner_then_pat, msrv) // the binding must come from the pattern of the containing match arm // .... => match { .. } && let (Some(binding_span), is_innermost_parent_pat_struct) diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs index 3deaaf96c1e8d..576e42a564c2b 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs @@ -1,7 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{indent_of, reindent_multiline}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::option_arg_ty; -use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks, span_contains_comment}; +use clippy_utils::{get_parent_expr, is_res_lang_ctor, path_res, peel_blocks, span_contains_comment}; use rustc_ast::BindingMode; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr}; @@ -132,13 +133,23 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok Applicability::MachineApplicable }; let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_par(); + let sugg = format!("{scrut}.{method}()"); + // If the expression being expanded is the `if …` part of an `else if …`, it must be blockified. + let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::If(_, _, Some(else_part)) = parent_expr.kind + && else_part.hir_id == expr.hir_id + { + reindent_multiline(&format!("{{\n {sugg}\n}}"), true, indent_of(cx, parent_expr.span)) + } else { + sugg + }; span_lint_and_sugg( cx, MANUAL_OK_ERR, expr.span, format!("manual implementation of `{method}`"), "replace with", - format!("{scrut}.{method}()"), + sugg, app, ); } 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 b69294d567d17..2bf7ec8ab7dde 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 @@ -117,7 +117,7 @@ fn lint<'tcx>( or_body_snippet: &str, indent: usize, ) { - let reindented_or_body = reindent_multiline(or_body_snippet.into(), true, Some(indent)); + let reindented_or_body = reindent_multiline(or_body_snippet, true, Some(indent)); let mut app = Applicability::MachineApplicable; let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par(); diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs index 2ad55d9bf1fdb..d0905733ab506 100644 --- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs +++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs @@ -4,8 +4,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, peel_mid_ty_refs_is_mutable, type_is_unsafe_function}; use clippy_utils::{ - CaptureKind, can_move_expr_to_closure, is_else_clause, is_lint_allowed, is_res_lang_ctor, path_res, - path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, + CaptureKind, can_move_expr_to_closure, expr_requires_coercion, is_else_clause, is_lint_allowed, is_res_lang_ctor, + path_res, path_to_local_id, peel_blocks, peel_hir_expr_refs, peel_hir_expr_while, }; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::Applicability; @@ -73,7 +73,7 @@ where } // `map` won't perform any adjustments. - if !cx.typeck_results().expr_adjustments(some_expr.expr).is_empty() { + if expr_requires_coercion(cx, expr) { return None; } @@ -99,7 +99,7 @@ where }); if let ExprKind::Path(QPath::Resolved(None, Path { res: Res::Local(l), .. })) = e.kind { match captures.get(l) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if binding_ref_mutability == Mutability::Mut => { return None; }, @@ -124,6 +124,12 @@ where }; let closure_expr_snip = some_expr.to_snippet_with_context(cx, expr_ctxt, &mut app); + let closure_body = if some_expr.needs_unsafe_block { + format!("unsafe {}", closure_expr_snip.blockify()) + } else { + closure_expr_snip.to_string() + }; + let body_str = if let PatKind::Binding(annotation, id, some_binding, None) = some_pat.kind { if !some_expr.needs_unsafe_block && let Some(func) = can_pass_as_func(cx, id, some_expr.expr) @@ -145,20 +151,12 @@ where "" }; - if some_expr.needs_unsafe_block { - format!("|{annotation}{some_binding}| unsafe {{ {closure_expr_snip} }}") - } else { - format!("|{annotation}{some_binding}| {closure_expr_snip}") - } + format!("|{annotation}{some_binding}| {closure_body}") } } else if !is_wild_none && explicit_ref.is_none() { // TODO: handle explicit reference annotations. let pat_snip = snippet_with_context(cx, some_pat.span, expr_ctxt, "..", &mut app).0; - if some_expr.needs_unsafe_block { - format!("|{pat_snip}| unsafe {{ {closure_expr_snip} }}") - } else { - format!("|{pat_snip}| {closure_expr_snip}") - } + format!("|{pat_snip}| {closure_body}") } else { // Refutable bindings and mixed reference annotations can't be handled by `map`. return None; 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 d697f427c7052..d29d1ea3e96d9 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 @@ -42,7 +42,7 @@ pub(super) fn check_match<'tcx>( cx, scrutinee, arms.iter() - .map(|arm| (cx.tcx.hir().attrs(arm.hir_id), Some(arm.pat), arm.body, arm.guard)), + .map(|arm| (cx.tcx.hir_attrs(arm.hir_id), Some(arm.pat), arm.body, arm.guard)), e, false, ) diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 41e4c75f843e5..250f17fa9025a 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -75,7 +75,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) { HirIdMapEntry::Occupied(entry) => return *entry.get() == b_id, } // the names technically don't have to match; this makes the lint more conservative - && cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id) + && cx.tcx.hir_name(a_id) == cx.tcx.hir_name(b_id) && cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b) && pat_contains_local(lhs.pat, a_id) && pat_contains_local(rhs.pat, b_id) diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 9ca914af281b6..35caa7d1f3a6d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -1014,7 +1014,7 @@ pub struct Matches { impl Matches { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: conf.msrv, infallible_destructuring_match_linted: false, } } @@ -1073,7 +1073,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source); } - collapsible_match::check_match(cx, arms, &self.msrv); + collapsible_match::check_match(cx, arms, self.msrv); if !from_expansion { // These don't depend on a relationship between multiple arms match_wild_err_arm::check(cx, ex, arms); @@ -1086,7 +1086,9 @@ impl<'tcx> LateLintPass<'tcx> for Matches { if !from_expansion && !contains_cfg_arm(cx, expr, ex, arms) { if source == MatchSource::Normal { - if !(self.msrv.meets(msrvs::MATCHES_MACRO) && match_like_matches::check_match(cx, expr, ex, arms)) { + if !(self.msrv.meets(cx, msrvs::MATCHES_MACRO) + && match_like_matches::check_match(cx, expr, ex, arms)) + { match_same_arms::check(cx, arms); } @@ -1120,7 +1122,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { needless_match::check_match(cx, ex, arms, expr); match_on_vec_items::check(cx, ex); match_str_case_mismatch::check(cx, ex, arms); - redundant_guards::check(cx, arms, &self.msrv); + redundant_guards::check(cx, arms, self.msrv); if !is_in_const_context(cx) { manual_unwrap_or::check_match(cx, expr, ex, arms); @@ -1138,11 +1140,11 @@ impl<'tcx> LateLintPass<'tcx> for Matches { match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr); } } else if let Some(if_let) = higher::IfLet::hir(cx, expr) { - collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv); + collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, self.msrv); significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else); if !from_expansion { if let Some(else_expr) = if_let.if_else { - if self.msrv.meets(msrvs::MATCHES_MACRO) { + if self.msrv.meets(cx, msrvs::MATCHES_MACRO) { match_like_matches::check_if_let( cx, expr, @@ -1208,8 +1210,6 @@ impl<'tcx> LateLintPass<'tcx> for Matches { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { rest_pat_in_fully_bound_struct::check(cx, pat); } - - extract_msrv_attr!(LateContext); } /// Checks if there are any arms with a `#[cfg(..)]` attribute. @@ -1274,16 +1274,12 @@ fn contains_cfg_arm(cx: &LateContext<'_>, e: &Expr<'_>, scrutinee: &Expr<'_>, ar } /// Checks if `pat` contains OR patterns that cannot be nested due to a too low MSRV. -fn pat_contains_disallowed_or(pat: &Pat<'_>, msrv: &Msrv) -> bool { - if msrv.meets(msrvs::OR_PATTERNS) { - return false; - } - - let mut result = false; +fn pat_contains_disallowed_or(cx: &LateContext<'_>, pat: &Pat<'_>, msrv: Msrv) -> bool { + let mut contains_or = false; pat.walk(|p| { let is_or = matches!(p.kind, PatKind::Or(_)); - result |= is_or; + contains_or |= is_or; !is_or }); - result + contains_or && !msrv.meets(cx, msrvs::OR_PATTERNS) } diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs index dfc0513add93f..ab53ad98572e4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs @@ -16,7 +16,7 @@ use std::ops::ControlFlow; use super::{REDUNDANT_GUARDS, pat_contains_disallowed_or}; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: &Msrv) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: Msrv) { for outer_arm in arms { let Some(guard) = outer_arm.guard else { continue; @@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: if let ExprKind::Match(scrutinee, [arm, _], MatchSource::Normal) = guard.kind && matching_root_macro_call(cx, guard.span, sym::matches_macro).is_some() && let Some(binding) = get_pat_binding(cx, scrutinee, outer_arm) - && !pat_contains_disallowed_or(arm.pat, msrv) + && !pat_contains_disallowed_or(cx, arm.pat, msrv) { let pat_span = match (arm.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, @@ -45,7 +45,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>], msrv: // `Some(x) if let Some(2) = x` else if let ExprKind::Let(let_expr) = guard.kind && let Some(binding) = get_pat_binding(cx, let_expr.init, outer_arm) - && !pat_contains_disallowed_or(let_expr.pat, msrv) + && !pat_contains_disallowed_or(cx, let_expr.pat, msrv) { let pat_span = match (let_expr.pat.kind, binding.byref_ident) { (PatKind::Ref(pat, _), Some(_)) => pat.span, diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 35f2e780d2e29..37bac561a6e06 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -199,7 +199,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { return false; } - let result = match ty.kind() { + match ty.kind() { rustc_middle::ty::Adt(adt, args) => { // if some field has significant drop, adt.all_fields() @@ -223,9 +223,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> { rustc_middle::ty::Tuple(tys) => tys.iter().any(|ty| self.has_sig_drop_attr_impl(ty)), rustc_middle::ty::Array(ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr_impl(*ty), _ => false, - }; - - result + } } } diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 41528c5dee3ae..a0919947b3fc7 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -8,7 +8,7 @@ use clippy_utils::{ is_default_equivalent, is_expr_used_or_unified, is_res_lang_ctor, path_res, peel_ref_operators, std_or_core, }; use rustc_errors::Applicability; -use rustc_hir::LangItem::OptionNone; +use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -43,6 +43,31 @@ declare_clippy_lint! { "replacing an `Option` with `None` instead of `take()`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `mem::replace()` on an `Option` with `Some(…)`. + /// + /// ### Why is this bad? + /// `Option` already has the method `replace()` for + /// taking its current value (Some(…) or None) and replacing it with + /// `Some(…)`. + /// + /// ### Example + /// ```no_run + /// let mut an_option = Some(0); + /// let replaced = std::mem::replace(&mut an_option, Some(1)); + /// ``` + /// Is better expressed with: + /// ```no_run + /// let mut an_option = Some(0); + /// let taken = an_option.replace(1); + /// ``` + #[clippy::version = "1.86.0"] + pub MEM_REPLACE_OPTION_WITH_SOME, + style, + "replacing an `Option` with `Some` instead of `replace()`" +} + declare_clippy_lint! { /// ### What it does /// Checks for `mem::replace(&mut _, mem::uninitialized())` @@ -101,28 +126,67 @@ declare_clippy_lint! { } impl_lint_pass!(MemReplace => - [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); + [MEM_REPLACE_OPTION_WITH_NONE, MEM_REPLACE_OPTION_WITH_SOME, MEM_REPLACE_WITH_UNINIT, MEM_REPLACE_WITH_DEFAULT]); -fn check_replace_option_with_none(cx: &LateContext<'_>, dest: &Expr<'_>, expr_span: Span) { - // Since this is a late pass (already type-checked), - // and we already know that the second argument is an - // `Option`, we do not need to check the first - // argument's type. All that's left is to get - // the replacee's expr after peeling off the `&mut` - let sugg_expr = peel_ref_operators(cx, dest); - let mut applicability = Applicability::MachineApplicable; - span_lint_and_sugg( - cx, - MEM_REPLACE_OPTION_WITH_NONE, - expr_span, - "replacing an `Option` with `None`", - "consider `Option::take()` instead", - format!( - "{}.take()", - Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par() - ), - applicability, - ); +fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) -> bool { + if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { + // Since this is a late pass (already type-checked), + // and we already know that the second argument is an + // `Option`, we do not need to check the first + // argument's type. All that's left is to get + // the replacee's expr after peeling off the `&mut` + let sugg_expr = peel_ref_operators(cx, dest); + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_NONE, + expr_span, + "replacing an `Option` with `None`", + "consider `Option::take()` instead", + format!( + "{}.take()", + Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par() + ), + applicability, + ); + true + } else { + false + } +} + +fn check_replace_option_with_some( + cx: &LateContext<'_>, + src: &Expr<'_>, + dest: &Expr<'_>, + expr_span: Span, + msrv: Msrv, +) -> bool { + if let ExprKind::Call(src_func, [src_arg]) = src.kind + && is_res_lang_ctor(cx, path_res(cx, src_func), OptionSome) + && msrv.meets(cx, msrvs::OPTION_REPLACE) + { + // We do not have to check for a `const` context here, because `core::mem::replace()` and + // `Option::replace()` have been const-stabilized simultaneously in version 1.83.0. + let sugg_expr = peel_ref_operators(cx, dest); + let mut applicability = Applicability::MachineApplicable; + span_lint_and_sugg( + cx, + MEM_REPLACE_OPTION_WITH_SOME, + expr_span, + "replacing an `Option` with `Some(..)`", + "consider `Option::replace()` instead", + format!( + "{}.replace({})", + Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "_", &mut applicability).maybe_par(), + snippet_with_applicability(cx, src_arg.span, "_", &mut applicability) + ), + applicability, + ); + true + } else { + false + } } fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { @@ -181,27 +245,35 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' } } -fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'_>, expr_span: Span) { - // disable lint for primitives - let expr_type = cx.typeck_results().expr_ty_adjusted(src); - if is_non_aggregate_primitive_type(expr_type) { - return; - } - if is_default_equivalent(cx, src) && !expr_span.in_external_macro(cx.tcx.sess.source_map()) { - let Some(top_crate) = std_or_core(cx) else { return }; +fn check_replace_with_default( + cx: &LateContext<'_>, + src: &Expr<'_>, + dest: &Expr<'_>, + expr: &Expr<'_>, + msrv: Msrv, +) -> bool { + if is_expr_used_or_unified(cx.tcx, expr) + // disable lint for primitives + && let expr_type = cx.typeck_results().expr_ty_adjusted(src) + && !is_non_aggregate_primitive_type(expr_type) + && is_default_equivalent(cx, src) + && !expr.span.in_external_macro(cx.tcx.sess.source_map()) + && let Some(top_crate) = std_or_core(cx) + && msrv.meets(cx, msrvs::MEM_TAKE) + { span_lint_and_then( cx, MEM_REPLACE_WITH_DEFAULT, - expr_span, + expr.span, format!( "replacing a value of type `T` with `T::default()` is better expressed using `{top_crate}::mem::take`" ), |diag| { - if !expr_span.from_expansion() { + if !expr.span.from_expansion() { let suggestion = format!("{top_crate}::mem::take({})", snippet(cx, dest.span, "")); diag.span_suggestion( - expr_span, + expr.span, "consider using", suggestion, Applicability::MachineApplicable, @@ -209,6 +281,9 @@ fn check_replace_with_default(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr< } }, ); + true + } else { + false } } @@ -218,9 +293,7 @@ pub struct MemReplace { impl MemReplace { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -233,13 +306,12 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { && cx.tcx.is_diagnostic_item(sym::mem_replace, def_id) { // Check that second argument is `Option::None` - if is_res_lang_ctor(cx, path_res(cx, src), OptionNone) { - check_replace_option_with_none(cx, dest, expr.span); - } else if self.msrv.meets(msrvs::MEM_TAKE) && is_expr_used_or_unified(cx.tcx, expr) { - check_replace_with_default(cx, src, dest, expr.span); + if !check_replace_option_with_none(cx, src, dest, expr.span) + && !check_replace_option_with_some(cx, src, dest, expr.span, self.msrv) + && !check_replace_with_default(cx, src, dest, expr, self.msrv) + { + check_replace_with_uninit(cx, src, dest, expr.span); } - check_replace_with_uninit(cx, src, dest, expr.span); } } - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs index 76bdbe55e2f3b..18568e3661fe5 100644 --- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs @@ -57,14 +57,13 @@ pub(super) fn check<'tcx>( }; let suggestion_source = reindent_multiline( - format!( + &format!( "std::path::Path::new({}) .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))", recv_source, ext_str.strip_prefix('.').unwrap() - ) - .into(), + ), true, Some(indent_of(cx, call_span).unwrap_or(0) + 4), ); diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs index 223a960b800e7..f50fb627b89a0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -10,16 +10,16 @@ use rustc_span::{Span, sym}; use super::CLONED_INSTEAD_OF_COPIED; -pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: &Msrv) { +pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, msrv: Msrv) { let recv_ty = cx.typeck_results().expr_ty_adjusted(recv); let inner_ty = match recv_ty.kind() { // `Option` -> `T` ty::Adt(adt, subst) - if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && msrv.meets(msrvs::OPTION_COPIED) => + if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && msrv.meets(cx, msrvs::OPTION_COPIED) => { subst.type_at(0) }, - _ if is_trait_method(cx, expr, sym::Iterator) && msrv.meets(msrvs::ITERATOR_COPIED) => { + _ if is_trait_method(cx, expr, sym::Iterator) && msrv.meets(cx, msrvs::ITERATOR_COPIED) => { match get_iterator_item_ty(cx, recv_ty) { // ::Item Some(ty) => ty, diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs index 208172980c9f5..e82211bbf3ef7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -1,8 +1,8 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::is_trait_method; +use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::implements_trait; +use clippy_utils::{is_mutable, is_trait_method, path_to_local}; use rustc_errors::Applicability; -use rustc_hir::Expr; +use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Instance; use rustc_span::{Span, sym}; @@ -28,14 +28,47 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id { - span_lint_and_sugg( + let mut sugg = vec![(call_span, String::from("next_back()"))]; + let mut dont_apply = false; + // if `self_expr` is a reference, it is mutable because it is used for `.last()` + if !(is_mutable(cx, self_expr) || self_type.is_ref()) { + if let Some(hir_id) = path_to_local(self_expr) + && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) + && let PatKind::Binding(_, _, ident, _) = pat.kind + { + sugg.push((ident.span.shrink_to_lo(), String::from("mut "))); + } else { + // If we can't make the binding mutable, make the suggestion `Unspecified` to prevent it from being + // automatically applied, and add a complementary help message. + dont_apply = true; + } + } + span_lint_and_then( cx, DOUBLE_ENDED_ITERATOR_LAST, - call_span, + expr.span, "called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator", - "try", - "next_back()".to_string(), - Applicability::MachineApplicable, + |diag| { + let expr_ty = cx.typeck_results().expr_ty(expr); + let droppable_elements = expr_ty.has_significant_drop(cx.tcx, cx.typing_env()); + diag.multipart_suggestion( + "try", + sugg, + if dont_apply { + Applicability::Unspecified + } else if droppable_elements { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }, + ); + if droppable_elements { + diag.note("this change will alter drop order which may be undesirable"); + } + if dont_apply { + diag.span_note(self_expr.span, "this must be made mutable to use `.next_back()`"); + } + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs index f2786efa44cb6..91ddaca07d8bb 100644 --- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs @@ -14,19 +14,16 @@ pub(super) fn check( recv: &rustc_hir::Expr<'_>, expect_span: Span, err_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) - // Test the version to make sure the lint can be showed (expect_err has been - // introduced in rust 1.17.0 : https://github.com/rust-lang/rust/pull/38982) - && msrv.meets(msrvs::EXPECT_ERR) - // Grabs the `Result` type && let result_type = cx.typeck_results().expr_ty(recv) // Tests if the T type in a `Result` is not None && let Some(data_type) = get_data_type(cx, result_type) // Tests if the T type in a `Result` implements debug && has_debug_impl(cx, data_type) + && msrv.meets(cx, msrvs::EXPECT_ERR) { span_lint_and_sugg( cx, 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 5b9df6c2bfdd2..ae300cd5fe56d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -12,7 +12,6 @@ use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_span::Span; use rustc_span::symbol::{Ident, Symbol, sym}; -use std::borrow::Cow; use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP}; @@ -302,7 +301,7 @@ pub(super) fn check( filter_span.with_hi(expr.span.hi()), "`filter` for `Some` followed by `unwrap`", "consider using `flatten` instead", - reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(), + reindent_multiline("flatten()", true, indent_of(cx, map_span)), Applicability::MachineApplicable, ); @@ -316,7 +315,7 @@ pub(super) fn check( filter_span.with_hi(expr.span.hi()), "`filter` for `Ok` followed by `unwrap`", "consider using `flatten` instead", - reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, map_span)).into_owned(), + reindent_multiline("flatten()", true, indent_of(cx, map_span)), Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs index 3f89e59314874..9f3c346042ff9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs @@ -14,10 +14,10 @@ pub(super) fn check<'tcx>( expr: &'tcx hir::Expr<'_>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) { if is_trait_method(cx, expr, sym::Iterator) { - if !msrv.meets(msrvs::ITERATOR_FIND_MAP) { + if !msrv.meets(cx, msrvs::ITERATOR_FIND_MAP) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs new file mode 100644 index 0000000000000..4659e9e163fe9 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/io_other_error.rs @@ -0,0 +1,37 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, QPath}; +use rustc_lint::LateContext; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, path: &Expr<'_>, args: &[Expr<'_>], msrv: Msrv) { + if let [error_kind, error] = args + && !expr.span.from_expansion() + && !error_kind.span.from_expansion() + && clippy_utils::is_expr_path_def_path(cx, path, &clippy_utils::paths::IO_ERROR_NEW) + && clippy_utils::is_expr_path_def_path( + cx, + clippy_utils::expr_or_init(cx, error_kind), + &clippy_utils::paths::IO_ERRORKIND_OTHER, + ) + && let ExprKind::Path(QPath::TypeRelative(_, new_segment)) = path.kind + && msrv.meets(cx, msrvs::IO_ERROR_OTHER) + { + span_lint_and_then( + cx, + super::IO_OTHER_ERROR, + expr.span, + "this can be `std::io::Error::other(_)`", + |diag| { + diag.multipart_suggestion_verbose( + "use `std::io::Error::other`", + vec![ + (new_segment.ident.span, "other".to_owned()), + (error_kind.span.until(error.span), String::new()), + ], + 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 d8bb9e377a0c8..9c32e9ac539d9 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 @@ -12,12 +12,8 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'_>, self_arg: &'tcx Expr<'_>, radix: &'tcx Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) { - if !msrv.meets(msrvs::IS_ASCII_DIGIT) { - return; - } - if !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_char() { return; } @@ -30,6 +26,10 @@ pub(super) fn check<'tcx>( }; let mut applicability = Applicability::MachineApplicable; + if !msrv.meets(cx, msrvs::IS_ASCII_DIGIT) { + return; + } + span_lint_and_sugg( cx, IS_DIGIT_ASCII_RADIX, 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 1c64f78678aeb..7c190e123b72e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs +++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs @@ -41,7 +41,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_ fn is_under_cfg(cx: &LateContext<'_>, id: HirId) -> bool { cx.tcx .hir_parent_id_iter(id) - .any(|id| cx.tcx.hir().attrs(id).iter().any(|attr| attr.has_name(sym::cfg))) + .any(|id| cx.tcx.hir_attrs(id).iter().any(|attr| attr.has_name(sym::cfg))) } /// Similar to [`clippy_utils::expr_or_init`], but does not go up the chain if the initialization 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 76a0c0061e529..bafabec7e0695 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs @@ -12,7 +12,6 @@ use rustc_hir as hir; use rustc_hir::QPath; use rustc_span::Span; use rustc_span::symbol::{Ident, Symbol, sym}; -use std::borrow::Cow; /// /// Returns true if the expression is a method call to `method_name` @@ -181,7 +180,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir filter_span.with_hi(expr.span.hi()), "`filter` for `is_ok` on iterator over `Result`s", "consider using `flatten` instead", - reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(), + reindent_multiline("flatten()", true, indent_of(cx, filter_span)), Applicability::HasPlaceholders, ), Some(FilterType::IsSome) => span_lint_and_sugg( @@ -190,7 +189,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_arg: &hir filter_span.with_hi(expr.span.hi()), "`filter` for `is_some` on iterator over `Option`", "consider using `flatten` instead", - reindent_multiline(Cow::Borrowed("flatten()"), true, indent_of(cx, filter_span)).into_owned(), + reindent_multiline("flatten()", true, indent_of(cx, filter_span)), Applicability::HasPlaceholders, ), } 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 518041177e928..94415fc91061e 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 @@ -20,9 +20,9 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'tcx>, // .iter().map(|(_, v_| v)) recv: &'tcx Expr<'tcx>, // hashmap m_arg: &'tcx Expr<'tcx>, // |(_, v)| v - msrv: &Msrv, + msrv: Msrv, ) { - if map_type == "into_iter" && !msrv.meets(msrvs::INTO_KEYS) { + if map_type == "into_iter" && !msrv.meets(cx, msrvs::INTO_KEYS) { return; } if !expr.span.from_expansion() 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 a80977459f21d..f51bdc78f8a51 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 @@ -147,6 +147,8 @@ impl<'tcx> Delegate<'tcx> for MoveDelegate { } } + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId, _: BorrowKind) {} fn mutate(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs index e1ebca0b09dfb..0274e31b4c338 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_c_str_literals.rs @@ -22,7 +22,7 @@ pub(super) fn check_as_ptr<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>, - msrv: &Msrv, + msrv: Msrv, ) { if let ExprKind::Lit(lit) = receiver.kind && let LitKind::ByteStr(_, StrStyle::Cooked) | LitKind::Str(_, StrStyle::Cooked) = lit.node @@ -32,7 +32,7 @@ pub(super) fn check_as_ptr<'tcx>( |parent| matches!(parent.kind, ExprKind::Call(func, _) if is_c_str_function(cx, func).is_some()), ) && let Some(sugg) = rewrite_as_cstr(cx, lit.span) - && msrv.meets(msrvs::C_STR_LITERALS) + && msrv.meets(cx, msrvs::C_STR_LITERALS) { span_lint_and_sugg( cx, @@ -65,11 +65,11 @@ fn is_c_str_function(cx: &LateContext<'_>, func: &Expr<'_>) -> Option { /// - `CStr::from_bytes_with_nul(..)` /// - `CStr::from_bytes_with_nul_unchecked(..)` /// - `CStr::from_ptr(..)` -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>], msrv: &Msrv) { +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>], msrv: Msrv) { if let Some(fn_name) = is_c_str_function(cx, func) && let [arg] = args && cx.tcx.sess.edition() >= Edition2021 - && msrv.meets(msrvs::C_STR_LITERALS) + && msrv.meets(cx, msrvs::C_STR_LITERALS) { match fn_name.as_str() { name @ ("from_bytes_with_nul" | "from_bytes_with_nul_unchecked") diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs new file mode 100644 index 0000000000000..8ba0f835d3ddc --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_contains.rs @@ -0,0 +1,113 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::peel_hir_pat_refs; +use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; +use rustc_ast::UnOp; +use rustc_errors::Applicability; +use rustc_hir::def::Res; +use rustc_hir::{BinOpKind, Body, Expr, ExprKind, HirId, QPath}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self}; +use rustc_span::source_map::Spanned; + +use super::MANUAL_CONTAINS; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, closure_arg: &Expr<'_>) { + let mut app = Applicability::MachineApplicable; + + if !expr.span.from_expansion() + // check if `iter().any()` can be replaced with `contains()` + && let ExprKind::Closure(closure) = closure_arg.kind + && let Body{params: [param],value} = cx.tcx.hir_body(closure.body) + && let ExprKind::Binary(op, lhs, rhs) = value.kind + && let (peeled_ref_pat, _) = peel_hir_pat_refs(param.pat) + && let Some((snip,snip_expr)) = can_replace_with_contains(cx, op, lhs, rhs, peeled_ref_pat.hir_id, &mut app) + && let ref_type = cx.typeck_results().expr_ty_adjusted(recv) + && let ty::Ref(_, inner_type, _) = ref_type.kind() + && let ty::Slice(slice_type) = inner_type.kind() + && *slice_type == cx.typeck_results().expr_ty(snip_expr) + { + span_lint_and_sugg( + cx, + MANUAL_CONTAINS, + expr.span, + "using `contains()` instead of `iter().any()` is more efficient", + "try", + format!( + "{}.contains({})", + snippet_with_applicability(cx, recv.span, "_", &mut app), + snip + ), + app, + ); + } +} + +enum EligibleArg { + IsClosureArg, + ContainsArg(String), +} + +fn try_get_eligible_arg<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, + closure_arg_id: HirId, + applicability: &mut Applicability, +) -> Option<(EligibleArg, &'tcx Expr<'tcx>)> { + let mut get_snippet = |expr: &Expr<'_>, needs_borrow: bool| { + let sugg = Sugg::hir_with_applicability(cx, expr, "_", applicability); + EligibleArg::ContainsArg((if needs_borrow { sugg.addr() } else { sugg }).to_string()) + }; + + match expr.kind { + ExprKind::Path(QPath::Resolved(_, path)) => { + if path.res == Res::Local(closure_arg_id) { + Some((EligibleArg::IsClosureArg, expr)) + } else { + Some((get_snippet(expr, true), expr)) + } + }, + ExprKind::Unary(UnOp::Deref, inner) => { + if let ExprKind::Path(QPath::Resolved(_, path)) = inner.kind { + if path.res == Res::Local(closure_arg_id) { + Some((EligibleArg::IsClosureArg, expr)) + } else { + Some((get_snippet(inner, false), expr)) + } + } else { + None + } + }, + _ => { + if switch_to_eager_eval(cx, expr) { + Some((get_snippet(expr, true), expr)) + } else { + None + } + }, + } +} + +fn can_replace_with_contains<'tcx>( + cx: &LateContext<'tcx>, + bin_op: Spanned, + left_expr: &'tcx Expr<'tcx>, + right_expr: &'tcx Expr<'tcx>, + closure_arg_id: HirId, + applicability: &mut Applicability, +) -> Option<(String, &'tcx Expr<'tcx>)> { + if bin_op.node != BinOpKind::Eq { + return None; + } + + let left_candidate = try_get_eligible_arg(cx, left_expr, closure_arg_id, applicability)?; + let right_candidate = try_get_eligible_arg(cx, right_expr, closure_arg_id, applicability)?; + match (left_candidate, right_candidate) { + ((EligibleArg::IsClosureArg, _), (EligibleArg::ContainsArg(snip), candidate_expr)) + | ((EligibleArg::ContainsArg(snip), candidate_expr), (EligibleArg::IsClosureArg, _)) => { + Some((snip, candidate_expr)) + }, + _ => None, + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs index 09ccb386a20bc..173ebcb7020b7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs @@ -14,14 +14,14 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::MANUAL_INSPECT; #[expect(clippy::too_many_lines)] -pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: &Msrv) { +pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name: &str, name_span: Span, msrv: Msrv) { if let ExprKind::Closure(c) = arg.kind && matches!(c.kind, ClosureKind::Closure) && let typeck = cx.typeck_results() && let Some(fn_id) = typeck.type_dependent_def_id(expr.hir_id) && (is_diag_trait_item(cx, fn_id, sym::Iterator) - || (msrv.meets(msrvs::OPTION_RESULT_INSPECT) - && (is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result)))) + || ((is_diag_item_method(cx, fn_id, sym::Option) || is_diag_item_method(cx, fn_id, sym::Result)) + && msrv.meets(cx, msrvs::OPTION_RESULT_INSPECT))) && let body = cx.tcx.hir_body(c.body) && let [param] = body.params && let PatKind::Binding(BindingMode(ByRef::No, Mutability::Not), arg_id, _, None) = param.pat.kind diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs index 90e502f244fa9..40aad03960c43 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_is_variant_and.rs @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>( map_recv: &'tcx rustc_hir::Expr<'_>, map_arg: &'tcx rustc_hir::Expr<'_>, map_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { // Don't lint if: @@ -36,7 +36,7 @@ pub(super) fn check<'tcx>( } // 4. msrv doesn't meet `OPTION_RESULT_IS_VARIANT_AND` - if !msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) { + if !msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND) { return; } diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs index 8265c93bfe9f7..c286c5faaed3e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_ok_or.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>( && let Some(err_arg_snippet) = err_arg.span.get_source_text(cx) && let Some(indent) = indent_of(cx, expr.span) { - let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str().into(), true, Some(indent + 4)); + let reindented_err_arg_snippet = reindent_multiline(err_arg_snippet.as_str(), true, Some(indent + 4)); span_lint_and_sugg( cx, MANUAL_OK_OR, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs b/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs index 6e09bf132aa14..83b57cca17bf1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_repeat_n.rs @@ -14,16 +14,16 @@ pub(super) fn check<'tcx>( expr: &'tcx Expr<'tcx>, repeat_expr: &Expr<'_>, take_arg: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) { - if msrv.meets(msrvs::REPEAT_N) - && !expr.span.from_expansion() + if !expr.span.from_expansion() && is_trait_method(cx, expr, sym::Iterator) && let ExprKind::Call(_, [repeat_arg]) = repeat_expr.kind && let Some(def_id) = fn_def_id(cx, repeat_expr) && cx.tcx.is_diagnostic_item(sym::iter_repeat, def_id) && !expr_use_ctxt(cx, expr).is_ty_unified && let Some(std_or_core) = std_or_core(cx) + && msrv.meets(cx, msrvs::REPEAT_N) { let mut app = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs index a56378b5b73ae..23dba47f60f40 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs @@ -17,10 +17,9 @@ pub(super) fn check<'tcx>( init: &Expr<'_>, acc: &Expr<'_>, fold_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { if !fold_span.in_external_macro(cx.sess().source_map()) - && msrv.meets(msrvs::ITERATOR_TRY_FOLD) && is_trait_method(cx, expr, sym::Iterator) && let init_ty = cx.typeck_results().expr_ty(init) && let Some(try_trait) = cx.tcx.lang_items().try_trait() @@ -29,6 +28,7 @@ pub(super) fn check<'tcx>( && let ExprKind::Path(qpath) = path.kind && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id) && let ExprKind::Closure(closure) = acc.kind + && msrv.meets(cx, msrvs::ITERATOR_TRY_FOLD) && !is_from_proc_macro(cx, expr) && let Some(args_snip) = closure .fn_arg_span 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 b2705e1ffc2d7..128b3695f48b7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs @@ -41,7 +41,7 @@ fn should_run_lint(cx: &LateContext<'_>, e: &hir::Expr<'_>, method_id: DefId) -> true } -pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: &Msrv) { +pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>, msrv: Msrv) { if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) && should_run_lint(cx, e, method_id) { @@ -169,10 +169,10 @@ fn lint_path(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) { ); } -fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: &Msrv) { +fn lint_explicit_closure(cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool, msrv: Msrv) { let mut applicability = Applicability::MachineApplicable; - let (message, sugg_method) = if is_copy && msrv.meets(msrvs::ITERATOR_COPIED) { + let (message, sugg_method) = if is_copy && msrv.meets(cx, msrvs::ITERATOR_COPIED) { ("you are using an explicit closure for copying elements", "copied") } else { ("you are using an explicit closure for cloning elements", "cloned") diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs index 428da0cf107e5..df5a0de3392b0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs @@ -19,13 +19,13 @@ pub(super) fn check<'tcx>( recv: &'tcx hir::Expr<'_>, map_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) -> bool { // lint if the caller of `map()` is an `Option` or a `Result`. let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option); let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result); - if is_result && !msrv.meets(msrvs::RESULT_MAP_OR_ELSE) { + if is_result && !msrv.meets(cx, msrvs::RESULT_MAP_OR_ELSE) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs index 35dd7c082c907..6cf0936c598fa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs +++ b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs @@ -62,7 +62,7 @@ pub(super) fn check( ex: &Expr<'_>, receiver: &Expr<'_>, arg: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, method_call_span: Span, ) { let mut applicability = Applicability::MaybeIncorrect; @@ -82,7 +82,7 @@ pub(super) fn check( let use_take; if eager_or_lazy::switch_to_eager_eval(cx, body_expr) { - if msrv.meets(msrvs::REPEAT_N) { + if msrv.meets(cx, msrvs::REPEAT_N) { method_to_use_name = "repeat_n"; let body_snippet = snippet_with_applicability(cx, body_expr.span, "..", &mut applicability); new_span = (arg.span, format!("{body_snippet}, {count}")); @@ -93,7 +93,7 @@ pub(super) fn check( new_span = (arg.span, body_snippet.to_string()); use_take = true; } - } else if msrv.meets(msrvs::REPEAT_WITH) { + } else if msrv.meets(cx, msrvs::REPEAT_WITH) { method_to_use_name = "repeat_with"; new_span = (param.span, String::new()); use_take = true; diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index b58e8ba32e78b..7dde21d3edb13 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -36,6 +36,7 @@ mod implicit_clone; mod inefficient_to_string; mod inspect_for_each; mod into_iter_on_ref; +mod io_other_error; mod is_digit_ascii_radix; mod is_empty; mod iter_cloned_collect; @@ -54,6 +55,7 @@ mod iter_with_drain; mod iterator_step_by_zero; mod join_absolute_paths; mod manual_c_str_literals; +mod manual_contains; mod manual_inspect; mod manual_is_variant_and; mod manual_next_back; @@ -82,7 +84,6 @@ mod ok_expect; mod open_options; mod option_as_ref_cloned; mod option_as_ref_deref; -mod option_map_or_err_ok; mod option_map_or_none; mod option_map_unwrap_or; mod or_fun_call; @@ -114,6 +115,7 @@ mod suspicious_map; mod suspicious_splitn; mod suspicious_to_owned; mod type_id_on_box; +mod unbuffered_bytes; mod uninit_assumed_init; mod unit_hash; mod unnecessary_fallible_conversions; @@ -2642,7 +2644,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.49.0"] pub MANUAL_OK_OR, - pedantic, + style, "finds patterns that can be encoded more concisely with `Option::ok_or`" } @@ -3784,31 +3786,6 @@ declare_clippy_lint! { "calls to `Path::join` which will overwrite the original path" } -declare_clippy_lint! { - /// ### What it does - /// Checks for usage of `_.map_or(Err(_), Ok)`. - /// - /// ### Why is this bad? - /// Readability, this can be written more concisely as - /// `_.ok_or(_)`. - /// - /// ### Example - /// ```no_run - /// # let opt = Some(1); - /// opt.map_or(Err("error"), Ok); - /// ``` - /// - /// Use instead: - /// ```no_run - /// # let opt = Some(1); - /// opt.ok_or("error"); - /// ``` - #[clippy::version = "1.76.0"] - pub OPTION_MAP_OR_ERR_OK, - style, - "using `Option.map_or(Err(_), Ok)`, which is more succinctly expressed as `Option.ok_or(_)`" -} - declare_clippy_lint! { /// ### What it does /// Checks for iterators of `Result`s using `.filter(Result::is_ok).map(Result::unwrap)` that may @@ -4433,11 +4410,88 @@ declare_clippy_lint! { "using `Option::and_then` or `Result::and_then` to chain a computation that returns an `Option` or a `Result`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for calls to `Read::bytes` on types which don't implement `BufRead`. + /// + /// ### Why is this bad? + /// The default implementation calls `read` for each byte, which can be very inefficient for data that’s not in memory, such as `File`. + /// + /// ### Example + /// ```no_run + /// use std::io::Read; + /// use std::fs::File; + /// let file = File::open("./bytes.txt").unwrap(); + /// file.bytes(); + /// ``` + /// Use instead: + /// ```no_run + /// use std::io::{BufReader, Read}; + /// use std::fs::File; + /// let file = BufReader::new(std::fs::File::open("./bytes.txt").unwrap()); + /// file.bytes(); + /// ``` + #[clippy::version = "1.86.0"] + pub UNBUFFERED_BYTES, + perf, + "calling .bytes() is very inefficient when data is not in memory" +} + +declare_clippy_lint! { + /// ### What it does + /// Checks for usage of `iter().any()` on slices when it can be replaced with `contains()` and suggests doing so. + /// + /// ### Why is this bad? + /// `contains()` is more concise and idiomatic, sometimes more fast. + /// + /// ### Example + /// ```no_run + /// fn foo(values: &[u8]) -> bool { + /// values.iter().any(|&v| v == 10) + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn foo(values: &[u8]) -> bool { + /// values.contains(&10) + /// } + /// ``` + #[clippy::version = "1.86.0"] + pub MANUAL_CONTAINS, + perf, + "unnecessary `iter().any()` on slices that can be replaced with `contains()`" +} + +declare_clippy_lint! { + /// This lint warns on calling `io::Error::new(..)` with a kind of + /// `io::ErrorKind::Other`. + /// + /// ### Why is this bad? + /// Since Rust 1.74, there's the `io::Error::other(_)` shortcut. + /// + /// ### Example + /// ```no_run + /// use std::io; + /// let _ = io::Error::new(io::ErrorKind::Other, "bad".to_string()); + /// ``` + /// Use instead: + /// ```no_run + /// let _ = std::io::Error::other("bad".to_string()); + /// ``` + #[clippy::version = "1.86.0"] + pub IO_OTHER_ERROR, + style, + "calling `std::io::Error::new(std::io::ErrorKind::Other, _)`" +} + +#[expect(clippy::struct_excessive_bools)] pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, allow_expect_in_tests: bool, allow_unwrap_in_tests: bool, + allow_expect_in_consts: bool, + allow_unwrap_in_consts: bool, allowed_dotfiles: FxHashSet<&'static str>, format_args: FormatArgsStorage, } @@ -4449,9 +4503,11 @@ impl Methods { Self { avoid_breaking_exported_api: conf.avoid_breaking_exported_api, - msrv: conf.msrv.clone(), + msrv: conf.msrv, allow_expect_in_tests: conf.allow_expect_in_tests, allow_unwrap_in_tests: conf.allow_unwrap_in_tests, + allow_expect_in_consts: conf.allow_expect_in_consts, + allow_unwrap_in_consts: conf.allow_unwrap_in_consts, allowed_dotfiles, format_args, } @@ -4580,7 +4636,6 @@ impl_lint_pass!(Methods => [ WAKER_CLONE_WAKE, UNNECESSARY_FALLIBLE_CONVERSIONS, JOIN_ABSOLUTE_PATHS, - OPTION_MAP_OR_ERR_OK, RESULT_FILTER_MAP, ITER_FILTER_IS_SOME, ITER_FILTER_IS_OK, @@ -4603,6 +4658,9 @@ impl_lint_pass!(Methods => [ MANUAL_REPEAT_N, SLICED_STRING_AS_BYTES, RETURN_AND_THEN, + UNBUFFERED_BYTES, + MANUAL_CONTAINS, + IO_OTHER_ERROR, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4630,8 +4688,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { 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); - useless_nonzero_new_unchecked::check(cx, expr, func, args, &self.msrv); + manual_c_str_literals::check(cx, expr, func, args, self.msrv); + useless_nonzero_new_unchecked::check(cx, expr, func, args, self.msrv); + io_other_error::check(cx, expr, func, args, self.msrv); }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; @@ -4650,7 +4709,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args); single_char_add_str::check(cx, expr, receiver, args); into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver); - unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, &self.msrv); + unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv); }, ExprKind::Binary(op, lhs, rhs) if op.node == hir::BinOpKind::Eq || op.node == hir::BinOpKind::Ne => { let mut info = BinaryExprInfo { @@ -4672,7 +4731,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } let name = impl_item.ident.name.as_str(); let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; - let item = cx.tcx.hir().expect_item(parent); + let item = cx.tcx.hir_expect_item(parent); let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })); @@ -4796,8 +4855,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { ); } } - - extract_msrv_attr!(LateContext); } impl Methods { @@ -4855,11 +4912,14 @@ impl Methods { && let body = cx.tcx.hir_body(arg.body) && let [param] = body.params => { - string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv); + string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), self.msrv); }, Some(("map", _, [map_arg], _, map_call_span)) => { map_all_any_identity::check(cx, expr, recv, map_call_span, map_arg, call_span, arg, "any"); }, + Some(("iter", iter_recv, ..)) => { + manual_contains::check(cx, expr, iter_recv, arg); + }, _ => {}, } }, @@ -4876,11 +4936,12 @@ impl Methods { sliced_string_as_bytes::check(cx, expr, recv); }, ("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv), - ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, &self.msrv), + ("as_ptr", []) => manual_c_str_literals::check_as_ptr(cx, expr, recv, self.msrv), ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv), ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv), + ("bytes", []) => unbuffered_bytes::check(cx, expr, recv), ("cloned", []) => { - cloned_instead_of_copied::check(cx, expr, recv, span, &self.msrv); + cloned_instead_of_copied::check(cx, expr, recv, span, self.msrv); option_as_ref_cloned::check(cx, recv, span); }, ("collect", []) if is_trait_method(cx, expr, sym::Iterator) => { @@ -4894,7 +4955,7 @@ impl Methods { format_collect::check(cx, expr, m_arg, m_ident_span); }, Some(("take", take_self_arg, [take_arg], _, _)) => { - if self.msrv.meets(msrvs::STR_REPEAT) { + if self.msrv.meets(cx, msrvs::STR_REPEAT) { manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); } }, @@ -4933,19 +4994,20 @@ impl Methods { if let ExprKind::MethodCall(.., span) = expr.kind { case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg); } - path_ends_with_ext::check(cx, recv, arg, expr, &self.msrv, &self.allowed_dotfiles); + path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles); }, ("expect", [_]) => { match method_call(recv) { Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv), Some(("err", recv, [], err_span, _)) => { - err_expect::check(cx, expr, recv, span, err_span, &self.msrv); + err_expect::check(cx, expr, recv, span, err_span, self.msrv); }, _ => unwrap_expect_used::check( cx, expr, recv, false, + self.allow_expect_in_consts, self.allow_expect_in_tests, unwrap_expect_used::Variant::Expect, ), @@ -4959,6 +5021,7 @@ impl Methods { expr, recv, true, + self.allow_expect_in_consts, self.allow_expect_in_tests, unwrap_expect_used::Variant::Expect, ); @@ -4979,7 +5042,7 @@ impl Methods { false, ); } - if self.msrv.meets(msrvs::ITER_FLATTEN) { + if self.msrv.meets(cx, msrvs::ITER_FLATTEN) { // use the sourcemap to get the span of the closure iter_filter::check(cx, expr, arg, span); } @@ -5027,7 +5090,7 @@ impl Methods { _ => {}, }, ("fold", [init, acc]) => { - manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv); + manual_try_fold::check(cx, expr, init, acc, call_span, self.msrv); unnecessary_fold::check(cx, expr, init, acc, span); }, ("for_each", [arg]) => { @@ -5068,7 +5131,7 @@ impl Methods { is_empty::check(cx, expr, recv); }, ("is_file", []) => filetype_is_file::check(cx, expr, recv), - ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, &self.msrv), + ("is_digit", [radix]) => is_digit_ascii_radix::check(cx, expr, recv, radix, self.msrv), ("is_none", []) => check_is_some_is_none(cx, expr, recv, call_span, false), ("is_some", []) => check_is_some_is_none(cx, expr, recv, call_span, true), ("iter" | "iter_mut" | "into_iter", []) => { @@ -5105,11 +5168,11 @@ impl Methods { (name @ ("map" | "map_err"), [m_arg]) => { if name == "map" { unused_enumerate_index::check(cx, expr, recv, m_arg); - map_clone::check(cx, expr, recv, m_arg, &self.msrv); - map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, &self.msrv, span); + map_clone::check(cx, expr, recv, m_arg, self.msrv); + map_with_unused_argument_over_ranges::check(cx, expr, recv, m_arg, self.msrv, span); match method_call(recv) { Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => { - iter_kv_map::check(cx, map_name, expr, recv2, m_arg, &self.msrv); + iter_kv_map::check(cx, map_name, expr, recv2, m_arg, self.msrv); }, Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check( cx, @@ -5126,8 +5189,8 @@ impl Methods { } if let Some((name, recv2, args, span2, _)) = method_call(recv) { match (name, args) { - ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv), - ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv), + ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, self.msrv), + ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, self.msrv), ("filter", [f_arg]) => { filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); }, @@ -5138,7 +5201,7 @@ impl Methods { } } map_identity::check(cx, expr, recv, m_arg, name, span); - manual_inspect::check(cx, expr, m_arg, name, span, &self.msrv); + manual_inspect::check(cx, expr, m_arg, name, span, self.msrv); crate::useless_conversion::check_function_application(cx, expr, recv, m_arg); }, ("map_break" | "map_continue", [m_arg]) => { @@ -5147,8 +5210,7 @@ impl Methods { ("map_or", [def, map]) => { option_map_or_none::check(cx, expr, recv, def, map); manual_ok_or::check(cx, expr, recv, def, map); - option_map_or_err_ok::check(cx, expr, recv, def, map); - unnecessary_map_or::check(cx, expr, recv, def, map, span, &self.msrv); + unnecessary_map_or::check(cx, expr, recv, def, map, span, self.msrv); }, ("map_or_else", [def, map]) => { result_map_or_else_none::check(cx, expr, recv, def, map); @@ -5166,7 +5228,7 @@ impl Methods { false, ), ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg), - ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv), + ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, self.msrv), ("iter", []) => iter_next_slice::check(cx, expr, recv2), ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), ("skip_while", [_]) => skip_while_next::check(cx, expr), @@ -5222,7 +5284,7 @@ impl Methods { no_effect_replace::check(cx, expr, arg1, arg2); // Check for repeated `str::replace` calls to perform `collapsible_str_replace` lint - if self.msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY) + if self.msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY) && name == "replace" && let Some(("replace", ..)) = method_call(recv) { @@ -5233,10 +5295,10 @@ impl Methods { vec_resize_to_zero::check(cx, expr, count_arg, default_arg, span); }, ("seek", [arg]) => { - if self.msrv.meets(msrvs::SEEK_FROM_CURRENT) { + if self.msrv.meets(cx, msrvs::SEEK_FROM_CURRENT) { seek_from_current::check(cx, expr, recv, arg); } - if self.msrv.meets(msrvs::SEEK_REWIND) { + if self.msrv.meets(cx, msrvs::SEEK_REWIND) { seek_to_start_instead_of_rewind::check(cx, expr, recv, arg, span); } }, @@ -5270,7 +5332,7 @@ impl Methods { ("splitn" | "rsplitn", [count_arg, pat_arg]) => { if let Some(Constant::Int(count)) = ConstEvalCtxt::new(cx).eval(count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); - str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv); + str_splitn::check(cx, name, expr, recv, pat_arg, count, self.msrv); } }, ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { @@ -5281,7 +5343,7 @@ impl Methods { ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("take", [arg]) => { iter_out_of_bounds::check_take(cx, expr, recv, arg); - manual_repeat_n::check(cx, expr, recv, arg, &self.msrv); + manual_repeat_n::check(cx, expr, recv, arg, self.msrv); if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) { iter_overeager_cloned::check( cx, @@ -5295,7 +5357,7 @@ impl Methods { }, ("take", []) => needless_option_take::check(cx, expr, recv), ("then", [arg]) => { - if !self.msrv.meets(msrvs::BOOL_THEN_SOME) { + if !self.msrv.meets(cx, msrvs::BOOL_THEN_SOME) { return; } unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some"); @@ -5333,6 +5395,7 @@ impl Methods { expr, recv, false, + self.allow_unwrap_in_consts, self.allow_unwrap_in_tests, unwrap_expect_used::Variant::Unwrap, ); @@ -5344,6 +5407,7 @@ impl Methods { expr, recv, true, + self.allow_unwrap_in_consts, self.allow_unwrap_in_tests, unwrap_expect_used::Variant::Unwrap, ); @@ -5354,10 +5418,10 @@ impl Methods { manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, Some(("map", m_recv, [m_arg], span, _)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv); + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv); }, Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { - obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method); + obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or"); }, _ => {}, } @@ -5365,7 +5429,7 @@ impl Methods { }, ("unwrap_or_default", []) => { if let Some(("map", m_recv, [arg], span, _)) = method_call(recv) { - manual_is_variant_and::check(cx, expr, m_recv, arg, span, &self.msrv); + manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv); } unnecessary_literal_unwrap::check(cx, expr, recv, name, args); }, @@ -5375,7 +5439,10 @@ impl Methods { ("unwrap_or_else", [u_arg]) => { match method_call(recv) { Some(("map", recv, [map_arg], _, _)) - if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {}, + if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {}, + Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => { + obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or_else"); + }, _ => { unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or"); }, diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs index e0905374ddaa4..9a5ffdeaf4e8e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,6 +1,7 @@ use super::OBFUSCATED_IF_ELSE; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::eager_or_lazy::switch_to_eager_eval; +use clippy_utils::get_parent_expr; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; use rustc_errors::Applicability; @@ -15,6 +16,7 @@ pub(super) fn check<'tcx>( then_arg: &'tcx hir::Expr<'_>, unwrap_arg: &'tcx hir::Expr<'_>, then_method_name: &str, + unwrap_method_name: &str, ) { let recv_ty = cx.typeck_results().expr_ty(then_recv); @@ -31,16 +33,40 @@ pub(super) fn check<'tcx>( snippet_with_applicability(cx, body.value.span, "..", &mut applicability) }, "then_some" => snippet_with_applicability(cx, then_arg.span, "..", &mut applicability), - _ => String::new().into(), + _ => return, + }; + + // FIXME: Add `unwrap_or_else` symbol + let els = match unwrap_method_name { + "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability), + "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.kind => { + let body = cx.tcx.hir_body(closure.body); + snippet_with_applicability(cx, body.value.span, "..", &mut applicability) + }, + "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.kind => { + snippet_with_applicability(cx, unwrap_arg.span, "_", &mut applicability) + "()" + }, + _ => return, }; let sugg = format!( "if {} {{ {} }} else {{ {} }}", Sugg::hir_with_applicability(cx, then_recv, "..", &mut applicability), if_then, - snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability) + els ); + // To be parsed as an expression, the `if { … } else { … }` as the left operand of a binary operator + // requires parentheses. + let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) + && let ExprKind::Binary(_, left, _) = parent_expr.kind + && left.hir_id == expr.hir_id + { + format!("({sugg})") + } else { + sugg + }; + span_lint_and_sugg( cx, OBFUSCATED_IF_ELSE, 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 469fcccbe4f60..63ee922acfa0d 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 @@ -18,12 +18,8 @@ pub(super) fn check( as_ref_recv: &hir::Expr<'_>, map_arg: &hir::Expr<'_>, is_mut: bool, - msrv: &Msrv, + msrv: Msrv, ) { - if !msrv.meets(msrvs::OPTION_AS_DEREF) { - return; - } - let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not); let option_ty = cx.typeck_results().expr_ty(as_ref_recv); @@ -93,7 +89,7 @@ pub(super) fn check( _ => false, }; - if is_deref { + if is_deref && msrv.meets(cx, msrvs::OPTION_AS_DEREF) { let current_method = if is_mut { format!(".as_mut().map({})", snippet(cx, map_arg.span, "..")) } else { diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs deleted file mode 100644 index 4e424d4c066a6..0000000000000 --- a/src/tools/clippy/clippy_lints/src/methods/option_map_or_err_ok.rs +++ /dev/null @@ -1,41 +0,0 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{is_res_lang_ctor, path_res}; -use rustc_errors::Applicability; -use rustc_hir::LangItem::{ResultErr, ResultOk}; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::LateContext; -use rustc_span::symbol::sym; - -use super::OPTION_MAP_OR_ERR_OK; - -pub(super) fn check<'tcx>( - cx: &LateContext<'tcx>, - expr: &'tcx Expr<'tcx>, - recv: &'tcx Expr<'_>, - or_expr: &'tcx Expr<'_>, - map_expr: &'tcx Expr<'_>, -) { - // We check that it's called on an `Option` type. - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) - // We check that first we pass an `Err`. - && let ExprKind::Call(call, &[arg]) = or_expr.kind - && is_res_lang_ctor(cx, path_res(cx, call), ResultErr) - // And finally we check that it is mapped as `Ok`. - && is_res_lang_ctor(cx, path_res(cx, map_expr), ResultOk) - { - let msg = "called `map_or(Err(_), Ok)` on an `Option` value"; - let self_snippet = snippet(cx, recv.span, ".."); - let err_snippet = snippet(cx, arg.span, ".."); - span_lint_and_sugg( - cx, - OPTION_MAP_OR_ERR_OK, - expr.span, - msg, - "consider using `ok_or`", - format!("{self_snippet}.ok_or({err_snippet})"), - 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 b1107d8cc72fe..4ba8e01090427 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 @@ -24,7 +24,7 @@ pub(super) fn check<'tcx>( unwrap_recv: &rustc_hir::Expr<'_>, unwrap_arg: &'tcx rustc_hir::Expr<'_>, map_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { // lint if the caller of `map()` is an `Option` if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) { @@ -71,9 +71,9 @@ pub(super) fn check<'tcx>( } // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead - let suggest_is_some_and = msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) - && matches!(&unwrap_arg.kind, ExprKind::Lit(lit) - if matches!(lit.node, rustc_ast::LitKind::Bool(false))); + let suggest_is_some_and = matches!(&unwrap_arg.kind, ExprKind::Lit(lit) + if matches!(lit.node, rustc_ast::LitKind::Bool(false))) + && msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND); let mut applicability = Applicability::MachineApplicable; // get snippet for unwrap_or() 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 69f933fee68f2..c03420a5143e6 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 @@ -104,7 +104,7 @@ pub(super) fn check<'tcx>( if (is_new(fun) && output_type_implements_default(fun)) || match call_expr { Some(call_expr) => is_default_equivalent(cx, call_expr), - None => is_default_equivalent_call(cx, fun) || closure_body_returns_empty_to_string(cx, fun), + None => is_default_equivalent_call(cx, fun, None) || closure_body_returns_empty_to_string(cx, fun), } { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs index 2d3007e50b81c..38d9c5f16778e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t "calling `push` with '/' or '\\' (file system root) will overwrite the previous path definition", "try", format!("\"{}\"", pushed_path_lit.trim_start_matches(['/', '\\'])), - Applicability::MachineApplicable, + Applicability::MaybeIncorrect, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs index b3811a335e1a0..d3f513e7abd27 100644 --- a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs +++ b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs @@ -20,7 +20,7 @@ pub(super) fn check( recv: &Expr<'_>, path: &Expr<'_>, expr: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, allowed_dotfiles: &FxHashSet<&'static str>, ) { if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::Path) @@ -33,7 +33,7 @@ pub(super) fn check( && path.chars().all(char::is_alphanumeric) { let mut sugg = snippet(cx, recv.span, "..").into_owned(); - if msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) { + if msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND) { let _ = write!(sugg, r#".extension().is_some_and(|ext| ext == "{path}")"#); } else { let _ = write!(sugg, r#".extension().map_or(false, |ext| ext == "{path}")"#); 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 f4d206c5307c1..3a5e321720865 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 @@ -1,6 +1,7 @@ -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::{SpanlessEq, higher, is_integer_const, is_trait_method}; +use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_span::sym; @@ -20,14 +21,14 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &' && let ExprKind::Path(QPath::Resolved(_, len_path)) = len_recv.kind && SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments) { - span_lint( + span_lint_and_sugg( cx, RANGE_ZIP_WITH_LEN, expr.span, - format!( - "it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, recv.span, "_") - ), + "using `.zip()` with a range and `.len()`", + "try", + format!("{}.iter().enumerate()", snippet(cx, recv.span, "_")), + Applicability::MachineApplicable, ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs index 82e66a0500a8f..c9251c1b84979 100644 --- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs +++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs @@ -1,11 +1,10 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::paths::STDIN; +use clippy_utils::get_parent_expr; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, match_def_path}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -34,7 +33,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool { pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) { if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def() - && match_def_path(cx, recv_adt.did(), &STDIN) + && cx.tcx.is_diagnostic_item(sym::Stdin, recv_adt.did()) && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind && let Res::Local(local_id) = path.res { diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs index 68ffa81a27810..e8861935d4216 100644 --- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs @@ -60,7 +60,7 @@ pub(super) fn check<'tcx>( "let {} = {}?;\n{}", arg_snip, recv_snip, - reindent_multiline(inner.into(), false, indent_of(cx, expr.span)) + reindent_multiline(inner, false, indent_of(cx, expr.span)) ); span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability); 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 8389c2e3f9826..4ccefb7ec9d77 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -23,7 +23,7 @@ pub(super) fn check( self_arg: &Expr<'_>, pat_arg: &Expr<'_>, count: u128, - msrv: &Msrv, + msrv: Msrv, ) { if count < 2 || !cx.typeck_results().expr_ty_adjusted(self_arg).peel_refs().is_str() { return; @@ -33,7 +33,7 @@ pub(super) fn check( IterUsageKind::Nth(n) => count > n + 1, IterUsageKind::NextTuple => count > 2, }; - let manual = count == 2 && msrv.meets(msrvs::STR_SPLIT_ONCE); + let manual = count == 2 && msrv.meets(cx, msrvs::STR_SPLIT_ONCE); match parse_iter_usage(cx, expr.span.ctxt(), cx.tcx.hir_parent_iter(expr.hir_id)) { Some(usage) if needless(usage.kind) => lint_needless(cx, method_name, expr, self_arg, pat_arg), diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs index cb719b34b1f0c..f0f9d30d3000a 100644 --- a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs +++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs @@ -17,10 +17,9 @@ pub(super) fn check<'tcx>( recv: &Expr<'_>, param: &'tcx Param<'tcx>, body: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) { - if msrv.meets(msrvs::MATCHES_MACRO) - && is_trait_method(cx, expr, sym::Iterator) + if is_trait_method(cx, expr, sym::Iterator) && let PatKind::Binding(_, arg, _, _) = param.pat.kind && let ExprKind::Lit(lit_kind) = recv.kind && let LitKind::Str(val, _) = lit_kind.node @@ -33,6 +32,7 @@ pub(super) fn check<'tcx>( (false, true) => lhs, _ => return, } + && msrv.meets(cx, msrvs::MATCHES_MACRO) && !is_from_proc_macro(cx, expr) && let Some(scrutinee_snip) = scrutinee.span.get_source_text(cx) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unbuffered_bytes.rs b/src/tools/clippy/clippy_lints/src/methods/unbuffered_bytes.rs new file mode 100644 index 0000000000000..dd5566f8c8baf --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/unbuffered_bytes.rs @@ -0,0 +1,25 @@ +use super::UNBUFFERED_BYTES; +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_trait_method; +use clippy_utils::ty::implements_trait; +use rustc_hir as hir; +use rustc_lint::LateContext; +use rustc_span::sym; + +pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) { + // Lint if the `.bytes()` call is from the `Read` trait and the implementor is not buffered. + if is_trait_method(cx, expr, sym::IoRead) + && let Some(buf_read) = cx.tcx.get_diagnostic_item(sym::IoBufRead) + && let ty = cx.typeck_results().expr_ty_adjusted(recv) + && !implements_trait(cx, ty, buf_read, &[]) + { + span_lint_and_help( + cx, + UNBUFFERED_BYTES, + expr.span, + "calling .bytes() is very inefficient when data is not in memory", + None, + "consider using `BufReader`", + ); + } +} 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 00690aca6d134..fa3a29e366709 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 @@ -98,10 +98,7 @@ pub(super) fn check( ]), ("None", "unwrap_or_else", _) => match args[0].kind { hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![ - ( - expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), - String::new(), - ), + (expr.span.with_hi(cx.tcx.hir_body(*body).value.span.lo()), String::new()), (expr.span.with_lo(args[0].span.hi()), String::new()), ]), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs index 5f88a7fd31f2f..d7bd522ddab94 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs @@ -4,7 +4,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::eager_or_lazy::switch_to_eager_eval; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::{Sugg, make_binop}; -use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; +use clippy_utils::ty::{get_type_diagnostic_name, implements_trait, is_copy}; use clippy_utils::visitors::is_local_used; use clippy_utils::{get_parent_expr, is_from_proc_macro, path_to_local_id}; use rustc_ast::LitKind::Bool; @@ -42,7 +42,7 @@ pub(super) fn check<'a>( def: &Expr<'_>, map: &Expr<'_>, method_span: Span, - msrv: &Msrv, + msrv: Msrv, ) { let ExprKind::Lit(def_kind) = def.kind else { return; @@ -81,9 +81,11 @@ pub(super) fn check<'a>( && (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id)) && !is_local_used(cx, non_binding_location, hir_id) && let typeck_results = cx.typeck_results() - && typeck_results.expr_ty(l) == typeck_results.expr_ty(r) + && let l_ty = typeck_results.expr_ty(l) + && l_ty == typeck_results.expr_ty(r) && let Some(partial_eq) = cx.tcx.get_diagnostic_item(sym::PartialEq) && implements_trait(cx, recv_ty, partial_eq, &[recv_ty.into()]) + && is_copy(cx, l_ty) { let wrap = variant.variant_name(); @@ -117,14 +119,14 @@ pub(super) fn check<'a>( .into_string(); (vec![(expr.span, sugg)], "a standard comparison", app) - } else if !def_bool && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND) { + } else if !def_bool && msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND) { let suggested_name = variant.method_name(); ( vec![(method_span, suggested_name.into()), (ext_def_span, String::default())], suggested_name, Applicability::MachineApplicable, ) - } else if def_bool && matches!(variant, Variant::Some) && msrv.meets(msrvs::IS_NONE_OR) { + } else if def_bool && matches!(variant, Variant::Some) && msrv.meets(cx, msrvs::IS_NONE_OR) { ( vec![(method_span, "is_none_or".into()), (ext_def_span, String::default())], "is_none_or", 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 ea134c0570537..a71b3659fd245 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 @@ -31,7 +31,7 @@ pub fn check<'tcx>( method_name: Symbol, receiver: &'tcx Expr<'_>, args: &'tcx [Expr<'_>], - msrv: &Msrv, + msrv: Msrv, ) { if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) && args.is_empty() @@ -207,7 +207,7 @@ fn check_into_iter_call_arg( expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) -> bool { if let Some(parent) = get_parent_expr(cx, expr) && let Some(callee_def_id) = fn_def_id(cx, parent) @@ -224,7 +224,7 @@ fn check_into_iter_call_arg( return true; } - let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(msrvs::ITERATOR_COPIED) { + let cloned_or_copied = if is_copy(cx, item_ty) && msrv.meets(cx, msrvs::ITERATOR_COPIED) { "copied" } else { "cloned" 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 5b0bd0f716ab2..027215e3b4d7b 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 @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{is_never_like, is_type_diagnostic_item}; -use clippy_utils::{is_in_test, is_lint_allowed}; +use clippy_utils::{is_in_test, is_inside_always_const_context, is_lint_allowed}; use rustc_hir::Expr; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; @@ -39,6 +39,7 @@ pub(super) fn check( expr: &Expr<'_>, recv: &Expr<'_>, is_err: bool, + allow_unwrap_in_consts: bool, allow_unwrap_in_tests: bool, variant: Variant, ) { @@ -65,6 +66,10 @@ pub(super) fn check( return; } + if allow_unwrap_in_consts && is_inside_always_const_context(cx.tcx, expr.hir_id) { + return; + } + span_lint_and_then( cx, variant.lint(), 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 19152362fb5fc..0cbf6004be3a0 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::{should_call_clone_as_function, walk_ptrs_ty_depth}; +use clippy_utils::ty::{implements_trait, 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, peel_blocks, strip_pat_refs, }; @@ -55,12 +55,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty); let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty); if base_rcv_ty == base_res_ty && rcv_depth >= res_depth { - // allow the `as_ref` or `as_mut` if it is followed by another method call - if let Some(parent) = get_parent_expr(cx, expr) - && let hir::ExprKind::MethodCall(segment, ..) = parent.kind - && segment.ident.span != expr.span - { - return; + if let Some(parent) = get_parent_expr(cx, expr) { + // allow the `as_ref` or `as_mut` if it is followed by another method call + if let hir::ExprKind::MethodCall(segment, ..) = parent.kind + && segment.ident.span != expr.span + { + return; + } + + // allow the `as_ref` or `as_mut` if they belong to a closure that changes + // the number of references + if matches!(parent.kind, hir::ExprKind::Closure(..)) && rcv_depth != res_depth { + return; + } } let mut applicability = Applicability::MachineApplicable; @@ -94,6 +101,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str, && 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) + // https://github.com/rust-lang/rust-clippy/issues/12357 + && let Some(clone_trait) = cx.tcx.lang_items().clone_trait() + && implements_trait(cx, cx.typeck_results().expr_ty(recvr), clone_trait, &[]) { lint_as_ref_clone(cx, expr.span.with_hi(parent.span.hi()), recvr, call_name); } diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs index 0bd50429c09db..22df1f3f485e1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs +++ b/src/tools/clippy/clippy_lints/src/methods/useless_nonzero_new_unchecked.rs @@ -10,13 +10,13 @@ use rustc_span::sym; use super::USELESS_NONZERO_NEW_UNCHECKED; -pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, func: &Expr<'tcx>, args: &[Expr<'_>], msrv: &Msrv) { - if msrv.meets(msrvs::CONST_UNWRAP) - && let ExprKind::Path(QPath::TypeRelative(ty, segment)) = func.kind +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, func: &Expr<'tcx>, args: &[Expr<'_>], msrv: Msrv) { + if let ExprKind::Path(QPath::TypeRelative(ty, segment)) = func.kind && segment.ident.name == sym::new_unchecked && let [init_arg] = args && is_inside_always_const_context(cx.tcx, expr.hir_id) && is_type_diagnostic_item(cx, cx.typeck_results().node_type(ty.hir_id), sym::NonZero) + && msrv.meets(cx, msrvs::CONST_UNWRAP) { let mut app = Applicability::MachineApplicable; let ty_str = snippet_with_applicability(cx, ty.span, "_", &mut app); 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 e5801124db48e..00ea9bba0d194 100644 --- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs +++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs @@ -121,8 +121,7 @@ impl Visitor<'_> for IdentVisitor<'_, '_> { // Check whether the node is part of a `use` statement. We don't want to emit a warning if the user // has no control over the type. let usenode = opt_as_use_node(node).or_else(|| { - cx - .tcx + cx.tcx .hir_parent_iter(hir_id) .find_map(|(_, node)| opt_as_use_node(node)) }); diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index fca416d9e64c7..693d1a8dd7643 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -7,7 +7,6 @@ use clippy_utils::{ }; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::intravisit::FnKind; use rustc_hir::{ BinOpKind, BindingMode, Body, ByRef, Expr, ExprKind, FnDecl, Mutability, PatKind, QPath, Stmt, StmtKind, @@ -286,7 +285,8 @@ fn used_underscore_items<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if name.starts_with('_') && !name.starts_with("__") && !definition_span.from_expansion() - && def_id.krate == LOCAL_CRATE + && def_id.is_local() + && !cx.tcx.is_foreign_item(def_id) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 8d751c2c0acb8..38a19dd2999bb 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,9 +1,9 @@ - use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, is_in_test, trait_ref_of_method}; +use rustc_abi::ExternAbi; use rustc_errors::Applicability; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; @@ -13,7 +13,6 @@ use rustc_middle::ty; use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; -use rustc_abi::ExternAbi; declare_clippy_lint! { /// ### What it does @@ -81,9 +80,7 @@ pub struct MissingConstForFn { impl MissingConstForFn { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -102,10 +99,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { return; } - if !self.msrv.meets(msrvs::CONST_IF_MATCH) { - return; - } - if span.in_external_macro(cx.tcx.sess.source_map()) || is_entrypoint_fn(cx, def_id.to_def_id()) { return; } @@ -124,7 +117,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { .iter() .any(|param| matches!(param.kind, GenericParamKind::Const { .. })); - if already_const(header) || has_const_generic_params || !could_be_const_with_abi(&self.msrv, header.abi) + if already_const(header) + || has_const_generic_params + || !could_be_const_with_abi(cx, self.msrv, header.abi) { return; } @@ -153,13 +148,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } } + if !self.msrv.meets(cx, msrvs::CONST_IF_MATCH) { + return; + } + if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) { return; } let mir = cx.tcx.optimized_mir(def_id); - if let Ok(()) = is_min_const_fn(cx.tcx, mir, &self.msrv) + if let Ok(()) = is_min_const_fn(cx, mir, self.msrv) && let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) = cx.tcx.hir_node_by_def_id(def_id) { @@ -174,8 +173,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { }); } } - - extract_msrv_attr!(LateContext); } // We don't have to lint on something that's already `const` @@ -184,13 +181,13 @@ fn already_const(header: hir::FnHeader) -> bool { header.constness == Constness::Const } -fn could_be_const_with_abi(msrv: &Msrv, abi: ExternAbi) -> bool { +fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: Msrv, abi: ExternAbi) -> bool { match abi { ExternAbi::Rust => true, // `const extern "C"` was stabilized after 1.62.0 - ExternAbi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_C_FN), + ExternAbi::C { unwind: false } => msrv.meets(cx, msrvs::CONST_EXTERN_C_FN), // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled. - _ => msrv.meets(msrvs::CONST_EXTERN_FN), + _ => msrv.meets(cx, msrvs::CONST_EXTERN_FN), } } diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs index d4181c677afda..ea74940828a11 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs @@ -49,9 +49,7 @@ pub struct MissingConstForThreadLocal { impl MissingConstForThreadLocal { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -91,11 +89,11 @@ fn is_unreachable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } #[inline] -fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id::DefId, msrv: &Msrv) -> bool { +fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id::DefId, msrv: Msrv) -> bool { // Building MIR for `fn`s with unsatisfiable preds results in ICE. if !fn_has_unsatisfiable_preds(cx, defid) && let mir = cx.tcx.optimized_mir(defid) - && let Ok(()) = is_min_const_fn(cx.tcx, mir, msrv) + && let Ok(()) = is_min_const_fn(cx, mir, msrv) { return true; } @@ -113,8 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal { local_defid: rustc_span::def_id::LocalDefId, ) { let defid = local_defid.to_def_id(); - if self.msrv.meets(msrvs::THREAD_LOCAL_CONST_INIT) - && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false) + if is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false) // Some implementations of `thread_local!` include an initializer fn. // In the case of a const initializer, the init fn is also const, // so we can skip the lint in that case. This occurs only on some @@ -131,11 +128,12 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal { // https://github.com/rust-lang/rust-clippy/issues/12637 // we ensure that this is reachable before we check in mir && !is_unreachable(cx, ret_expr) - && initializer_can_be_made_const(cx, defid, &self.msrv) + && initializer_can_be_made_const(cx, defid, self.msrv) // we know that the function is const-qualifiable, so now // we need only to get the initializer expression to span-lint it. && let initializer_snippet = snippet(cx, ret_expr.span, "thread_local! { ... }") && initializer_snippet != "thread_local! { ... }" + && self.msrv.meets(cx, msrvs::THREAD_LOCAL_CONST_INIT) { span_lint_and_sugg( cx, @@ -148,6 +146,4 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal { ); } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 06e92985e6648..3470c266c4917 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -182,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_crate(&mut self, cx: &LateContext<'tcx>) { - let attrs = cx.tcx.hir().attrs(hir::CRATE_HIR_ID); + let attrs = cx.tcx.hir_attrs(hir::CRATE_HIR_ID); self.check_missing_docs_attrs(cx, CRATE_DEF_ID, attrs, cx.tcx.def_span(CRATE_DEF_ID), "the", "crate"); } @@ -217,14 +217,14 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { | hir::ItemKind::Union(..) => {}, hir::ItemKind::ExternCrate(..) | hir::ItemKind::ForeignMod { .. } - | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::GlobalAsm { .. } | hir::ItemKind::Impl { .. } | hir::ItemKind::Use(..) => note_prev_span_then_ret!(self.prev_span, it.span), } let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id()); - let attrs = cx.tcx.hir().attrs(it.hir_id()); + let attrs = cx.tcx.hir_attrs(it.hir_id()); if !is_from_proc_macro(cx, it) { self.check_missing_docs_attrs(cx, it.owner_id.def_id, attrs, it.span, article, desc); } @@ -234,7 +234,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id()); - let attrs = cx.tcx.hir().attrs(trait_item.hir_id()); + let attrs = cx.tcx.hir_attrs(trait_item.hir_id()); if !is_from_proc_macro(cx, trait_item) { self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, attrs, trait_item.span, article, desc); } @@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id()); - let attrs = cx.tcx.hir().attrs(impl_item.hir_id()); + let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); if !is_from_proc_macro(cx, impl_item) { self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, attrs, impl_item.span, article, desc); } @@ -261,7 +261,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { if !sf.is_positional() { - let attrs = cx.tcx.hir().attrs(sf.hir_id); + let attrs = cx.tcx.hir_attrs(sf.hir_id); if !is_from_proc_macro(cx, sf) { self.check_missing_docs_attrs(cx, sf.def_id, attrs, sf.span, "a", "struct field"); } @@ -270,7 +270,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { - let attrs = cx.tcx.hir().attrs(v.hir_id); + let attrs = cx.tcx.hir_attrs(v.hir_id); if !is_from_proc_macro(cx, v) { self.check_missing_docs_attrs(cx, v.def_id, attrs, v.span, "a", "variant"); } diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index fdc0930e957a0..2c578d816025f 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -98,7 +98,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { match it.kind { hir::ItemKind::Fn { .. } => { let desc = "a function"; - let attrs = cx.tcx.hir().attrs(it.hir_id()); + let attrs = cx.tcx.hir_attrs(it.hir_id()); check_missing_inline_attrs(cx, attrs, it.span, desc); }, hir::ItemKind::Trait(ref _is_auto, ref _unsafe, _generics, _bounds, trait_items) => { @@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { // an impl is not provided let desc = "a default trait method"; let item = cx.tcx.hir_trait_item(tit.id); - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); check_missing_inline_attrs(cx, attrs, item.span, desc); } }, @@ -128,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { | hir::ItemKind::Static(..) | hir::ItemKind::Struct(..) | hir::ItemKind::TraitAlias(..) - | hir::ItemKind::GlobalAsm(..) + | hir::ItemKind::GlobalAsm { .. } | hir::ItemKind::TyAlias(..) | hir::ItemKind::Union(..) | hir::ItemKind::ExternCrate(..) @@ -168,7 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline { } } - let attrs = cx.tcx.hir().attrs(impl_item.hir_id()); + let attrs = cx.tcx.hir_attrs(impl_item.hir_id()); check_missing_inline_attrs(cx, attrs, impl_item.span, desc); } } 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 a7452c8a3c84e..be728e6c8b74b 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 @@ -334,7 +334,7 @@ impl<'tcx> Visitor<'tcx> for ReadVisitor<'_, '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)), |diag| { diag.span_note( self.write_expr.span, diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index c382fb8fce1b2..2fd1049f42e10 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -54,8 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { ); } }, - ExprKind::MethodCall(path, receiver, arguments, _) => { - let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); + ExprKind::MethodCall(path, receiver, arguments, _) + if let Some(def_id) = cx.typeck_results().type_dependent_def_id(e.hir_id) => + { let args = cx.typeck_results().node_args(e.hir_id); let method_type = cx.tcx.type_of(def_id).instantiate(cx.tcx, args); check_arguments( 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 ea1d7e5d43829..f686cc912ddb0 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 @@ -72,7 +72,7 @@ impl NeedlessBorrowsForGenericArgs<'_> { pub fn new(conf: &'static Conf) -> Self { Self { possible_borrowers: Vec::new(), - msrv: conf.msrv.clone(), + msrv: conf.msrv, } } } @@ -114,7 +114,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { i, param_ty, expr, - &self.msrv, + self.msrv, ) && count != 0 { @@ -142,8 +142,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> { self.possible_borrowers.pop(); } } - - extract_msrv_attr!(LateContext); } fn path_has_args(p: &QPath<'_>) -> bool { @@ -172,7 +170,7 @@ fn needless_borrow_count<'tcx>( arg_index: usize, param_ty: ParamTy, mut expr: &Expr<'tcx>, - msrv: &Msrv, + msrv: Msrv, ) -> usize { let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait(); let sized_trait_def_id = cx.tcx.lang_items().sized_trait(); @@ -273,7 +271,7 @@ fn needless_borrow_count<'tcx>( && let ty::Param(param_ty) = trait_predicate.self_ty().kind() && let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack() && ty.is_array() - && !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) + && !msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) { return false; } diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs index 05b31fc84b9b2..b8601f77e2492 100644 --- a/src/tools/clippy/clippy_lints/src/needless_continue.rs +++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs @@ -356,7 +356,7 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin .iter() .map(|stmt| { let span = cx.sess().source_map().stmt_span(stmt.span, data.loop_block.span); - let snip = snippet_block(cx, span, "..", None).into_owned(); + let snip = snippet_block(cx, span, "..", None); snip.lines() .map(|line| format!("{}{line}", " ".repeat(indent))) .collect::>() diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs index 7eefb016aca98..c90019f6ee161 100644 --- a/src/tools/clippy/clippy_lints/src/needless_if.rs +++ b/src/tools/clippy/clippy_lints/src/needless_if.rs @@ -65,7 +65,7 @@ impl LateLintPass<'_> for NeedlessIf { stmt.span, "this `if` branch is empty", "you can remove it", - if cond.can_have_side_effects() || !cx.tcx.hir().attrs(stmt.hir_id).is_empty() { + if cond.can_have_side_effects() || !cx.tcx.hir_attrs(stmt.hir_id).is_empty() { // `{ foo }` or `{ foo } && bar` placed into a statement position would be // interpreted as a block statement, force it to be an expression if cond_snippet.starts_with('{') { diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs index 863a1f895c937..3efbed0c2365e 100644 --- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs +++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs @@ -261,7 +261,7 @@ fn check<'tcx>( binding_id: HirId, ) -> Option<()> { let usage = first_usage(cx, binding_id, local_stmt.hir_id, block)?; - let binding_name = cx.tcx.hir().opt_name(binding_id)?; + let binding_name = cx.tcx.hir_opt_name(binding_id)?; let let_snippet = local_snippet_without_semicolon(cx, local)?; match usage.expr.kind { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index 36a0738cbc95a..576bb27b254c9 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -5,6 +5,7 @@ use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_expr; use clippy_utils::{inherits_cfg, is_from_proc_macro, is_self}; use core::ops::ControlFlow; +use rustc_abi::ExternAbi; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::Applicability; use rustc_hir::intravisit::FnKind; @@ -20,7 +21,6 @@ use rustc_session::impl_lint_pass; use rustc_span::Span; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; -use rustc_abi::ExternAbi; declare_clippy_lint! { /// ### What it does @@ -147,7 +147,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { // We don't check unsafe functions. return; } - let attrs = cx.tcx.hir().attrs(hir_id); + let attrs = cx.tcx.hir_attrs(hir_id); if header.abi != ExternAbi::Rust || requires_exact_signature(attrs) { return; } @@ -396,6 +396,8 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> { } } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + #[allow(clippy::if_same_then_else)] fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) { self.prev_bind = None; diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 40c65d1ef9e86..7bee89086b80f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -5,6 +5,7 @@ use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{ implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item, }; +use rustc_abi::ExternAbi; use rustc_errors::{Applicability, Diag}; use rustc_hir::intravisit::FnKind; use rustc_hir::{ @@ -19,7 +20,6 @@ use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::symbol::kw; use rustc_span::{Span, sym}; -use rustc_abi::ExternAbi; use rustc_trait_selection::traits; use rustc_trait_selection::traits::misc::type_allowed_to_implement_copy; @@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { match kind { FnKind::ItemFn(.., header) => { - let attrs = cx.tcx.hir().attrs(hir_id); + let attrs = cx.tcx.hir_attrs(hir_id); if header.abi != ExternAbi::Rust || requires_exact_signature(attrs) { return; } @@ -326,6 +326,8 @@ impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt { self.move_common(cmt); } + fn use_cloned(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {} fn mutate(&mut self, _: &euv::PlaceWithHirId<'tcx>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs index b73b9083a9919..fe8a02c64c660 100644 --- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet, snippet_with_applicability}; +use rustc_abi::ExternAbi; use rustc_errors::Applicability; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::{BytePos, Pos}; -use rustc_abi::ExternAbi; declare_clippy_lint! { /// ### What it does @@ -40,7 +40,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { if let ItemKind::Fn { sig: fn_sig, .. } = &item.kind && !item.span.from_expansion() { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); let mut app = Applicability::MaybeIncorrect; let fn_snippet = snippet_with_applicability(cx, fn_sig.span.with_hi(item.ident.span.lo()), "..", &mut app); for attr in attrs { @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi { .span .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len())) .shrink_to_lo(); - let attr_snippet = snippet(cx, attr.span, ".."); + let attr_snippet = snippet(cx, attr.span(), ".."); span_lint_and_then( cx, 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 4007ca88a00e7..9b53608ae7f3c 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -180,7 +180,9 @@ impl<'tcx> NonCopyConst<'tcx> { fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool { // No branch that we check (yet) should continue if val isn't a branch - let Some(val) = val.try_to_branch() else { return false }; + let Some(branched_val) = val.try_to_branch() else { + return false; + }; match *ty.kind() { // the fact that we have to dig into every structs to search enums // leads us to the point checking `UnsafeCell` directly is the only option. @@ -188,11 +190,11 @@ impl<'tcx> NonCopyConst<'tcx> { // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the // contained value. ty::Adt(def, ..) if def.is_union() => false, - ty::Array(ty, _) => val + ty::Array(ty, _) => branched_val .iter() .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), ty::Adt(def, args) if def.is_enum() => { - let Some((&variant_valtree, fields)) = val.split_first() else { + let Some((&variant_valtree, fields)) = branched_val.split_first() else { return false; }; let variant_index = variant_valtree.unwrap_leaf(); @@ -208,14 +210,18 @@ impl<'tcx> NonCopyConst<'tcx> { ) .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty)) }, - ty::Adt(def, args) => val + ty::Adt(def, args) => branched_val .iter() .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args))) .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), - ty::Tuple(tys) => val + ty::Tuple(tys) => branched_val .iter() .zip(tys) .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)), + ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { + Ok(normalized_ty) if ty != normalized_ty => Self::is_value_unfrozen_raw_inner(cx, val, normalized_ty), + _ => false, + }, _ => false, } } @@ -345,7 +351,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) { if let ImplItemKind::Const(_, body_id) = &impl_item.kind { let item_def_id = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; - let item = cx.tcx.hir().expect_item(item_def_id); + let item = cx.tcx.hir_expect_item(item_def_id); match &item.kind { ItemKind::Impl(Impl { 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 1a3b43cbb10a5..c5873589b26f3 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -208,7 +208,8 @@ impl SimilarNamesNameVisitor<'_, '_, '_> { fn check_ident(&mut self, ident: Ident) { let interned_name = ident.name.as_str(); - if interned_name.chars().any(char::is_uppercase) { + // name can be empty if it comes from recovery + if interned_name.chars().any(char::is_uppercase) || interned_name.is_empty() { return; } if interned_name.chars().all(|c| c.is_ascii_digit() || c == '_') { diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs index 774a182d089f1..a82365f943181 100644 --- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs +++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::msrvs::Msrv; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::visitors::for_each_expr; -use clippy_utils::{def_path_def_ids, fn_def_id, path_def_id}; +use clippy_utils::{def_path_def_ids, fn_def_id, is_no_std_crate, path_def_id}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -75,7 +75,7 @@ impl NonStdLazyStatic { #[must_use] pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: conf.msrv, lazy_static_lazy_static: Vec::new(), once_cell_crate: Vec::new(), once_cell_sync_lazy: Vec::new(), @@ -89,23 +89,12 @@ impl NonStdLazyStatic { impl_lint_pass!(NonStdLazyStatic => [NON_STD_LAZY_STATICS]); -/// Return if current MSRV does not meet the requirement for `lazy_cell` feature, -/// or current context has `no_std` attribute. -macro_rules! ensure_prerequisite { - ($msrv:expr, $cx:ident) => { - if !$msrv.meets(clippy_utils::msrvs::LAZY_CELL) || clippy_utils::is_no_std_crate($cx) { - return; - } - }; +fn can_use_lazy_cell(cx: &LateContext<'_>, msrv: Msrv) -> bool { + msrv.meets(cx, msrvs::LAZY_CELL) && !is_no_std_crate(cx) } impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { - extract_msrv_attr!(LateContext); - fn check_crate(&mut self, cx: &LateContext<'hir>) { - // Do not lint if current crate does not support `LazyLock`. - ensure_prerequisite!(self.msrv, cx); - // Fetch def_ids for external paths self.lazy_static_lazy_static = def_path_def_ids(cx.tcx, &["lazy_static", "lazy_static"]).collect(); self.once_cell_sync_lazy = def_path_def_ids(cx.tcx, &["once_cell", "sync", "Lazy"]).collect(); @@ -123,11 +112,10 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { } fn check_item(&mut self, cx: &LateContext<'hir>, item: &Item<'hir>) { - ensure_prerequisite!(self.msrv, cx); - if let ItemKind::Static(..) = item.kind && let Some(macro_call) = clippy_utils::macros::root_macro_call(item.span) && self.lazy_static_lazy_static.contains(¯o_call.def_id) + && can_use_lazy_cell(cx, self.msrv) { span_lint( cx, @@ -142,14 +130,14 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { return; } - if let Some(lazy_info) = LazyInfo::from_item(self, cx, item) { + if let Some(lazy_info) = LazyInfo::from_item(self, cx, item) + && can_use_lazy_cell(cx, self.msrv) + { self.lazy_type_defs.insert(item.owner_id.to_def_id(), lazy_info); } } fn check_expr(&mut self, cx: &LateContext<'hir>, expr: &Expr<'hir>) { - ensure_prerequisite!(self.msrv, cx); - // All functions in the `FUNCTION_REPLACEMENTS` have only one args if let ExprKind::Call(callee, [arg]) = expr.kind && let Some(call_def_id) = fn_def_id(cx, expr) @@ -163,8 +151,6 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { } fn check_ty(&mut self, cx: &LateContext<'hir>, ty: &'hir rustc_hir::Ty<'hir, rustc_hir::AmbigArg>) { - ensure_prerequisite!(self.msrv, cx); - // Record if types from `once_cell` besides `sync::Lazy` are used. if let rustc_hir::TyKind::Path(qpath) = ty.peel_refs().kind && let Some(ty_def_id) = cx.qpath_res(&qpath, ty.hir_id).opt_def_id() @@ -178,8 +164,6 @@ impl<'hir> LateLintPass<'hir> for NonStdLazyStatic { } fn check_crate_post(&mut self, cx: &LateContext<'hir>) { - ensure_prerequisite!(self.msrv, cx); - if !self.uses_other_once_cell_types { for (_, lazy_info) in &self.lazy_type_defs { lazy_info.lint(cx, &self.sugg_map); diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs index 5737a91031db2..03b907ebdf4d8 100644 --- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs +++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs @@ -112,6 +112,7 @@ fn imm_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} @@ -137,6 +138,7 @@ fn mut_borrows_in_expr(cx: &LateContext<'_>, e: &hir::Expr<'_>) -> HirIdSet { } fn consume(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn mutate(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} fn fake_read(&mut self, _: &PlaceWithHirId<'_>, _: FakeReadCause, _: HirId) {} fn copy(&mut self, _: &PlaceWithHirId<'_>, _: HirId) {} diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs index 34f7dbea84e49..74e0a6333db0f 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs @@ -50,7 +50,7 @@ pub(crate) fn check<'tcx>( // format the suggestion let suggestion = format!( "{}.abs()", - sugg::make_assoc(AssocOp::Subtract, &sug_l, &sug_r).maybe_par() + sugg::make_assoc(AssocOp::Binary(BinOpKind::Sub), &sug_l, &sug_r).maybe_par() ); // spans the lint span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/operators/manual_midpoint.rs b/src/tools/clippy/clippy_lints/src/operators/manual_midpoint.rs new file mode 100644 index 0000000000000..81721a9f2af55 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/operators/manual_midpoint.rs @@ -0,0 +1,64 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sugg::Sugg; +use clippy_utils::{is_float_literal, is_integer_literal}; +use rustc_ast::BinOpKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty}; + +use super::MANUAL_MIDPOINT; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + op: BinOpKind, + left: &'tcx Expr<'_>, + right: &'tcx Expr<'_>, + msrv: Msrv, +) { + if !left.span.from_expansion() + && !right.span.from_expansion() + && op == BinOpKind::Div + && (is_integer_literal(right, 2) || is_float_literal(right, 2.0)) + && let Some((ll_expr, lr_expr)) = add_operands(left) + && add_operands(ll_expr).is_none() && add_operands(lr_expr).is_none() + && let left_ty = cx.typeck_results().expr_ty_adjusted(ll_expr) + && let right_ty = cx.typeck_results().expr_ty_adjusted(lr_expr) + && left_ty == right_ty + // Do not lint on `(_+1)/2` and `(1+_)/2`, it is likely a `div_ceil()` operation + && !is_integer_literal(ll_expr, 1) && !is_integer_literal(lr_expr, 1) + && is_midpoint_implemented(cx, left_ty, msrv) + { + let mut app = Applicability::MachineApplicable; + let left_sugg = Sugg::hir_with_context(cx, ll_expr, expr.span.ctxt(), "..", &mut app); + let right_sugg = Sugg::hir_with_context(cx, lr_expr, expr.span.ctxt(), "..", &mut app); + let sugg = format!("{left_ty}::midpoint({left_sugg}, {right_sugg})"); + span_lint_and_sugg( + cx, + MANUAL_MIDPOINT, + expr.span, + "manual implementation of `midpoint` which can overflow", + format!("use `{left_ty}::midpoint` instead"), + sugg, + app, + ); + } +} + +/// Return the left and right operands if `expr` represents an addition +fn add_operands<'e, 'tcx>(expr: &'e Expr<'tcx>) -> Option<(&'e Expr<'tcx>, &'e Expr<'tcx>)> { + match expr.kind { + ExprKind::Binary(op, left, right) if op.node == BinOpKind::Add => Some((left, right)), + _ => None, + } +} + +fn is_midpoint_implemented(cx: &LateContext<'_>, ty: Ty<'_>, msrv: Msrv) -> bool { + match ty.kind() { + ty::Uint(_) | ty::Float(_) => msrv.meets(cx, msrvs::UINT_FLOAT_MIDPOINT), + ty::Int(_) => msrv.meets(cx, msrvs::INT_MIDPOINT), + _ => false, + } +} diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 9ad32c2bd3963..80459945094ed 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -11,6 +11,7 @@ mod float_cmp; mod float_equality_without_abs; mod identity_op; mod integer_division; +mod manual_midpoint; mod misrefactored_assign_op; mod modulo_arithmetic; mod modulo_one; @@ -24,6 +25,7 @@ mod verbose_bit_mask; pub(crate) mod arithmetic_side_effects; use clippy_config::Conf; +use clippy_utils::msrvs::Msrv; use rustc_hir::{Body, Expr, ExprKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -834,10 +836,35 @@ declare_clippy_lint! { "explicit self-assignment" } +declare_clippy_lint! { + /// ### What it does + /// Checks for manual implementation of `midpoint`. + /// + /// ### Why is this bad? + /// Using `(x + y) / 2` might cause an overflow on the intermediate + /// addition result. + /// + /// ### Example + /// ```no_run + /// # let a: u32 = 0; + /// let c = (a + 10) / 2; + /// ``` + /// Use instead: + /// ```no_run + /// # let a: u32 = 0; + /// let c = u32::midpoint(a, 10); + /// ``` + #[clippy::version = "1.87.0"] + pub MANUAL_MIDPOINT, + pedantic, + "manual implementation of `midpoint` which can overflow" +} + pub struct Operators { arithmetic_context: numeric_arithmetic::Context, verbose_bit_mask_threshold: u64, modulo_arithmetic_allow_comparison_to_zero: bool, + msrv: Msrv, } impl Operators { pub fn new(conf: &'static Conf) -> Self { @@ -845,6 +872,7 @@ impl Operators { arithmetic_context: numeric_arithmetic::Context::default(), verbose_bit_mask_threshold: conf.verbose_bit_mask_threshold, modulo_arithmetic_allow_comparison_to_zero: conf.allow_comparison_to_zero, + msrv: conf.msrv, } } } @@ -876,6 +904,7 @@ impl_lint_pass!(Operators => [ NEEDLESS_BITWISE_BOOL, PTR_EQ, SELF_ASSIGNMENT, + MANUAL_MIDPOINT, ]); impl<'tcx> LateLintPass<'tcx> for Operators { @@ -893,6 +922,7 @@ impl<'tcx> LateLintPass<'tcx> for Operators { identity_op::check(cx, e, op.node, lhs, rhs); needless_bitwise_bool::check(cx, e, op.node, lhs, rhs); ptr_eq::check(cx, e, op.node, lhs, rhs); + manual_midpoint::check(cx, e, op.node, lhs, rhs, self.msrv); } self.arithmetic_context.check_binary(cx, e, op.node, lhs, rhs); bit_mask::check(cx, e, op.node, lhs, rhs); diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index cda99a362dcae..c261fd9bd9cb0 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -82,7 +82,7 @@ impl Context { } self.const_span = Some(body_span); }, - hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure => (), + hir::BodyOwnerKind::Fn | hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::GlobalAsm => (), } } diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs index c3c09946c27d1..378fed481f4fe 100644 --- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs +++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs @@ -181,7 +181,7 @@ fn in_impl<'tcx>( ) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> { if let Some(block) = get_enclosing_block(cx, e.hir_id) && let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id()) - && let item = cx.tcx.hir().expect_item(impl_def_id.expect_local()) + && let item = cx.tcx.hir_expect_item(impl_def_id.expect_local()) && let ItemKind::Impl(item) = &item.kind && let Some(of_trait) = &item.of_trait && let Some(seg) = of_trait.path.segments.last() @@ -200,7 +200,7 @@ fn in_impl<'tcx>( fn are_equal(cx: &LateContext<'_>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool { if let ty::Adt(adt_def, _) = middle_ty.kind() && let Some(local_did) = adt_def.did().as_local() - && let item = cx.tcx.hir().expect_item(local_did) + && let item = cx.tcx.hir_expect_item(local_did) && let middle_ty_id = item.owner_id.to_def_id() && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind && let Res::Def(_, hir_ty_id) = path.res 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 de9f055863cb2..75b18bc651e2a 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 @@ -177,7 +177,7 @@ fn try_get_option_occurrence<'tcx>( .then_some(()) .and_then(|()| none_captures.get(local_id)) }) { - Some(CaptureKind::Value | CaptureKind::Ref(Mutability::Mut)) => return None, + Some(CaptureKind::Value | CaptureKind::Use | CaptureKind::Ref(Mutability::Mut)) => return None, Some(CaptureKind::Ref(Mutability::Not)) if as_mut => return None, Some(CaptureKind::Ref(Mutability::Not)) | None => (), } diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs index c9bdeed660e20..39ae9967e0166 100644 --- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs +++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs @@ -1,11 +1,12 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; +use clippy_utils::is_in_test; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use clippy_utils::{is_in_test, match_def_path, paths}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; +use rustc_span::sym; pub struct PanicUnimplemented { allow_panic_in_tests: bool, @@ -137,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented { } else if let ExprKind::Call(func, [_]) = expr.kind && let ExprKind::Path(QPath::Resolved(None, expr_path)) = func.kind && let Res::Def(DefKind::Fn, def_id) = expr_path.res - && match_def_path(cx, def_id, &paths::PANIC_ANY) + && cx.tcx.is_diagnostic_item(sym::panic_any, def_id) { if cx.tcx.hir_is_inside_const_context(expr.hir_id) || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id) 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 73c31b83b51f6..320c0286bb7be 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 @@ -6,6 +6,7 @@ use clippy_utils::source::snippet; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{is_self, is_self_ty}; use core::ops::ControlFlow; +use rustc_abi::ExternAbi; use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -19,7 +20,6 @@ use rustc_middle::ty::{self, RegionKind, TyCtxt}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{Span, sym}; -use rustc_abi::ExternAbi; declare_clippy_lint! { /// ### What it does @@ -280,7 +280,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { if header.abi != ExternAbi::Rust { return; } - let attrs = cx.tcx.hir().attrs(hir_id); + let attrs = cx.tcx.hir_attrs(hir_id); for a in attrs { if let Some(meta_items) = a.meta_item_list() { if a.has_name(sym::proc_macro_derive) diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index ef4948a05b7f4..dae0709a5404a 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -4,6 +4,7 @@ use clippy_utils::sugg::Sugg; use clippy_utils::visitors::contains_unsafe_block; use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core}; use hir::LifetimeName; +use rustc_abi::ExternAbi; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::hir_id::{HirId, HirIdMap}; use rustc_hir::intravisit::{Visitor, walk_expr}; @@ -19,7 +20,6 @@ use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, Pre use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; use rustc_span::{Span, sym}; -use rustc_abi::ExternAbi; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::{fmt, iter}; diff --git a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs index db03657c9af43..fd21893232dbb 100644 --- a/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs +++ b/src/tools/clippy/clippy_lints/src/pub_underscore_fields.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for PubUnderscoreFields { // Only pertains to fields that start with an underscore, and are public. if field.ident.as_str().starts_with('_') && is_visible(field) // We ignore fields that have `#[doc(hidden)]`. - && !is_doc_hidden(cx.tcx.hir().attrs(field.hir_id)) + && !is_doc_hidden(cx.tcx.hir_attrs(field.hir_id)) // We ignore fields that are `PhantomData`. && !is_path_lang_item(cx, field.ty, LangItem::PhantomData) { diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index ffc3b86c502e3..4f5f3eb6c15a0 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -68,7 +68,7 @@ impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]); impl QuestionMark { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: conf.msrv, matches_behaviour: conf.matches_for_let_else, try_block_depth_stack: Vec::new(), inferred_ret_closure_stack: 0, @@ -543,5 +543,4 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark { .expect("blocks are always part of bodies and must have a depth") -= 1; } } - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 1b0c0a4956f7e..cc423eca74fbe 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -166,9 +166,7 @@ pub struct Ranges { impl Ranges { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -182,7 +180,7 @@ impl_lint_pass!(Ranges => [ impl<'tcx> LateLintPass<'tcx> for Ranges { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if let ExprKind::Binary(ref op, l, r) = expr.kind { - if self.msrv.meets(msrvs::RANGE_CONTAINS) { + if self.msrv.meets(cx, msrvs::RANGE_CONTAINS) { check_possible_range_contains(cx, op.node, l, r, expr, expr.span); } } @@ -191,7 +189,6 @@ impl<'tcx> LateLintPass<'tcx> for Ranges { check_inclusive_range_minus_one(cx, expr); check_reversed_empty_range(cx, expr); } - extract_msrv_attr!(LateContext); } fn check_possible_range_contains( diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 6bd68dd4109d4..49b522994fbf7 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -93,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { }, ), VecInitKind::WithExprCapacity(hir_id) => { - let e = cx.tcx.hir().expect_expr(hir_id); + let e = cx.tcx.hir_expect_expr(hir_id); span_lint_hir_and_then( cx, READ_ZERO_BYTE_VEC, diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs index a1b5a3aff3236..a3be16ed858ef 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_else.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs @@ -6,7 +6,6 @@ use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::Span; -use std::borrow::Cow; declare_clippy_lint! { /// ### What it does @@ -163,14 +162,9 @@ fn extract_else_block(mut block: &str) -> String { block.trim_end().to_string() } -fn make_sugg<'a>( - cx: &EarlyContext<'_>, - els_span: Span, - default: &'a str, - indent_relative_to: Option, -) -> Cow<'a, str> { +fn make_sugg(cx: &EarlyContext<'_>, els_span: Span, default: &str, indent_relative_to: Option) -> String { let extracted = extract_else_block(&snippet(cx, els_span, default)); let indent = indent_relative_to.and_then(|s| indent_of(cx, s)); - reindent_multiline(extracted.into(), false, indent) + reindent_multiline(&extracted, false, indent) } diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs index 707abc008a862..feefe10f57d77 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, MsrvStack}; use rustc_ast::ast::{Expr, ExprKind}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; @@ -36,13 +36,13 @@ declare_clippy_lint! { } pub struct RedundantFieldNames { - msrv: Msrv, + msrv: MsrvStack, } impl RedundantFieldNames { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: MsrvStack::new(conf.msrv), } } } @@ -80,5 +80,6 @@ impl EarlyLintPass for RedundantFieldNames { } } } - extract_msrv_attr!(EarlyContext); + + extract_msrv_attr!(); } diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs index f3ccc9e38f4d8..defb6684cffbe 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs @@ -123,6 +123,5 @@ fn find_binding(pat: &Pat<'_>, name: Ident) -> Option { /// Check if a rebinding of a local changes the effect of assignments to the binding. fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId, rebind: HirId) -> bool { // the binding is mutable and the rebinding is in a different scope than the original binding - mutability == Mutability::Mut - && cx.tcx.hir_get_enclosing_scope(bind) != cx.tcx.hir_get_enclosing_scope(rebind) + mutability == Mutability::Mut && cx.tcx.hir_get_enclosing_scope(bind) != cx.tcx.hir_get_enclosing_scope(rebind) } 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 06c854338066f..b4e1f70d1535b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, MsrvStack}; use clippy_utils::source::snippet; use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind}; use rustc_errors::Applicability; @@ -35,13 +35,13 @@ declare_clippy_lint! { } pub struct RedundantStaticLifetimes { - msrv: Msrv, + msrv: MsrvStack, } impl RedundantStaticLifetimes { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: MsrvStack::new(conf.msrv), } } } @@ -115,5 +115,5 @@ impl EarlyLintPass for RedundantStaticLifetimes { } } - extract_msrv_attr!(EarlyContext); + extract_msrv_attr!(); } 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 5dddf9263a359..8805687efccf1 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 @@ -1,15 +1,27 @@ +use clippy_config::Conf; use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::higher::VecArgs; use clippy_utils::macros::matching_root_macro_call; +use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet; use clippy_utils::{expr_or_init, fn_def_id, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; +use rustc_session::impl_lint_pass; use rustc_span::{Span, sym}; +pub struct RepeatVecWithCapacity { + msrv: Msrv, +} + +impl RepeatVecWithCapacity { + pub fn new(conf: &'static Conf) -> Self { + Self { msrv: conf.msrv } + } +} + declare_clippy_lint! { /// ### What it does /// Looks for patterns such as `vec![Vec::with_capacity(x); n]` or `iter::repeat(Vec::with_capacity(x))`. @@ -48,7 +60,7 @@ declare_clippy_lint! { "repeating a `Vec::with_capacity` expression which does not retain capacity" } -declare_lint_pass!(RepeatVecWithCapacity => [REPEAT_VEC_WITH_CAPACITY]); +impl_lint_pass!(RepeatVecWithCapacity => [REPEAT_VEC_WITH_CAPACITY]); fn emit_lint(cx: &LateContext<'_>, span: Span, kind: &str, note: &'static str, sugg_msg: &'static str, sugg: String) { span_lint_and_then( @@ -87,13 +99,14 @@ fn check_vec_macro(cx: &LateContext<'_>, expr: &Expr<'_>) { } /// Checks `iter::repeat(Vec::with_capacity(x))` -fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) { +fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { if !expr.span.from_expansion() && fn_def_id(cx, expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::iter_repeat, did)) && let ExprKind::Call(_, [repeat_expr]) = expr.kind && fn_def_id(cx, repeat_expr).is_some_and(|did| cx.tcx.is_diagnostic_item(sym::vec_with_capacity, did)) && !repeat_expr.span.from_expansion() && let Some(exec_context) = std_or_core(cx) + && msrv.meets(cx, msrvs::REPEAT_WITH) { emit_lint( cx, @@ -112,6 +125,6 @@ fn check_repeat_fn(cx: &LateContext<'_>, expr: &Expr<'_>) { impl LateLintPass<'_> for RepeatVecWithCapacity { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { check_vec_macro(cx, expr); - check_repeat_fn(cx, expr); + check_repeat_fn(cx, expr, self.msrv); } } diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index 5a25483c397c6..07ae92fa98439 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -74,7 +74,7 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa // We only show this warning for public exported methods. && cx.effective_visibilities.is_exported(fn_def) // We don't want to emit this lint if the `#[must_use]` attribute is already there. - && !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)) + && !cx.tcx.hir_attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use)) && cx.tcx.visibility(fn_def.to_def_id()).is_public() && let ret_ty = return_ty(cx, owner_id) && let self_arg = nth_arg(cx, owner_id, 0) diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 152739c2973b6..4cb73df8b488f 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::visitors::{Descend, for_each_expr}; +use clippy_utils::visitors::for_each_expr; use clippy_utils::{ binary_expr_needs_parentheses, fn_def_id, is_from_proc_macro, is_inside_let_else, is_res_lang_ctor, leaks_droppable_temporary_with_limited_lifetime, path_res, path_to_local_id, span_contains_cfg, @@ -21,6 +21,7 @@ use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, GenericArgKind, Ty}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; +use rustc_span::edition::Edition; use rustc_span::{BytePos, Pos, Span, sym}; use std::borrow::Cow; use std::fmt::Display; @@ -230,11 +231,11 @@ impl<'tcx> LateLintPass<'tcx> for Return { && let Some(stmt) = block.stmts.iter().last() && let StmtKind::Let(local) = &stmt.kind && local.ty.is_none() - && cx.tcx.hir().attrs(local.hir_id).is_empty() + && cx.tcx.hir_attrs(local.hir_id).is_empty() && let Some(initexpr) = &local.init && let PatKind::Binding(_, local_id, _, _) = local.pat.kind && path_to_local_id(retexpr, local_id) - && !last_statement_borrows(cx, initexpr) + && (cx.sess().edition() >= Edition::Edition2024 || !last_statement_borrows(cx, initexpr)) && !initexpr.span.in_external_macro(cx.sess().source_map()) && !retexpr.span.in_external_macro(cx.sess().source_map()) && !local.span.from_expansion() @@ -400,7 +401,7 @@ fn check_final_expr<'tcx>( // This allows the addition of attributes, like `#[allow]` (See: clippy#9361) // `#[expect(clippy::needless_return)]` needs to be handled separately to // actually fulfill the expectation (clippy::#12998) - match cx.tcx.hir().attrs(expr.hir_id) { + match cx.tcx.hir_attrs(expr.hir_id) { [] => {}, [attr] => { if matches!(Level::from_attr(attr), Some(Level::Expect(_))) @@ -482,7 +483,7 @@ fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { ControlFlow::Break(()) } else { - ControlFlow::Continue(Descend::from(!e.span.from_expansion())) + ControlFlow::Continue(()) } }) .is_some() 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 fc02c3a51716e..8b2d597b9e323 100644 --- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs +++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs @@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { } let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; - let item = cx.tcx.hir().expect_item(parent); + let item = cx.tcx.hir_expect_item(parent); let self_ty = cx.tcx.type_of(item.owner_id).instantiate_identity(); let ret_ty = return_ty(cx, impl_item.owner_id); diff --git a/src/tools/clippy/clippy_lints/src/single_option_map.rs b/src/tools/clippy/clippy_lints/src/single_option_map.rs new file mode 100644 index 0000000000000..1fb54950612a5 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/single_option_map.rs @@ -0,0 +1,91 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{path_res, peel_blocks}; +use rustc_hir::def::Res; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{Body, ExprKind, FnDecl, FnRetTy}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; +use rustc_span::{Span, sym}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for functions with method calls to `.map(_)` on an arg + /// of type `Option` as the outermost expression. + /// + /// ### Why is this bad? + /// Taking and returning an `Option` may require additional + /// `Some(_)` and `unwrap` if all you have is a `T`. + /// + /// ### Example + /// ```no_run + /// fn double(param: Option) -> Option { + /// param.map(|x| x * 2) + /// } + /// ``` + /// Use instead: + /// ```no_run + /// fn double(param: u32) -> u32 { + /// param * 2 + /// } + /// ``` + #[clippy::version = "1.86.0"] + pub SINGLE_OPTION_MAP, + nursery, + "Checks for functions with method calls to `.map(_)` on an arg of type `Option` as the outermost expression." +} + +declare_lint_pass!(SingleOptionMap => [SINGLE_OPTION_MAP]); + +impl<'tcx> LateLintPass<'tcx> for SingleOptionMap { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + span: Span, + _fn_def: LocalDefId, + ) { + if let FnRetTy::Return(_ret) = decl.output + && matches!(kind, FnKind::ItemFn(_, _, _) | FnKind::Method(_, _)) + { + let func_body = peel_blocks(body.value); + if let ExprKind::MethodCall(method_name, callee, args, _span) = func_body.kind + && method_name.ident.name == sym::map + && let callee_type = cx.typeck_results().expr_ty(callee) + && is_type_diagnostic_item(cx, callee_type, sym::Option) + && let ExprKind::Path(_path) = callee.kind + && let Res::Local(_id) = path_res(cx, callee) + && matches!(path_res(cx, callee), Res::Local(_id)) + && !matches!(args[0].kind, ExprKind::Path(_)) + { + if let ExprKind::Closure(closure) = args[0].kind { + let Body { params: [..], value } = cx.tcx.hir_body(closure.body); + if let ExprKind::Call(func, f_args) = value.kind + && matches!(func.kind, ExprKind::Path(_)) + && f_args.iter().all(|arg| matches!(arg.kind, ExprKind::Path(_))) + { + return; + } else if let ExprKind::MethodCall(_segment, receiver, method_args, _span) = value.kind + && matches!(receiver.kind, ExprKind::Path(_)) + && method_args.iter().all(|arg| matches!(arg.kind, ExprKind::Path(_))) + && method_args.iter().all(|arg| matches!(path_res(cx, arg), Res::Local(_))) + { + return; + } + } + + span_lint_and_help( + cx, + SINGLE_OPTION_MAP, + span, + "`fn` that only maps over argument", + None, + "move the `.map` to the caller or to an `_opt` function", + ); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs index b22c638fc3633..dc19236011bd4 100644 --- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs +++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs @@ -99,7 +99,7 @@ fn get_pointee_ty_and_count_expr<'tcx>( if let ExprKind::MethodCall(method_path, ptr_self, [.., count], _) = expr.kind // Find calls to copy_{from,to}{,_nonoverlapping} && let method_ident = method_path.ident.as_str() - && METHODS.iter().any(|m| *m == method_ident) + && METHODS.contains(&method_ident) // Get the pointee type && let ty::RawPtr(pointee_ty, _) = 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 59c13a1e2c533..d68ac8bab1286 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 @@ -99,7 +99,7 @@ impl StdReexports { pub fn new(conf: &'static Conf) -> Self { Self { prev_span: Span::default(), - msrv: conf.msrv.clone(), + msrv: conf.msrv, } } } @@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { if let Res::Def(_, def_id) = path.res && let Some(first_segment) = get_first_segment(path) - && is_stable(cx, def_id, &self.msrv) + && is_stable(cx, def_id, self.msrv) && !path.span.in_external_macro(cx.sess().source_map()) && !is_from_proc_macro(cx, &first_segment.ident) { @@ -153,8 +153,6 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { } } } - - extract_msrv_attr!(LateContext); } /// Returns the first named segment of a [`Path`]. @@ -174,7 +172,7 @@ fn get_first_segment<'tcx>(path: &Path<'tcx>) -> Option<&'tcx PathSegment<'tcx>> /// or now stable moves that were once unstable. /// /// Does not catch individually moved items -fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: &Msrv) -> bool { +fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: Msrv) -> bool { loop { if let Some(stability) = cx.tcx.lookup_stability(def_id) && let StabilityLevel::Stable { @@ -183,8 +181,8 @@ fn is_stable(cx: &LateContext<'_>, mut def_id: DefId, msrv: &Msrv) -> bool { } = stability.level { let stable = match since { - StableSince::Version(v) => msrv.meets(v), - StableSince::Current => msrv.current().is_none(), + StableSince::Version(v) => msrv.meets(cx, v), + StableSince::Current => msrv.current(cx).is_none(), StableSince::Err => false, }; diff --git a/src/tools/clippy/clippy_lints/src/string_patterns.rs b/src/tools/clippy/clippy_lints/src/string_patterns.rs index 694ad4f6347bb..5c95dfe834730 100644 --- a/src/tools/clippy/clippy_lints/src/string_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/string_patterns.rs @@ -77,9 +77,7 @@ pub struct StringPatterns { impl StringPatterns { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -136,7 +134,7 @@ fn get_char_span<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Optio } } -fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: &Msrv) { +fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr<'_>, msrv: Msrv) { if let ExprKind::Closure(closure) = method_arg.kind && let body = cx.tcx.hir_body(closure.body) && let Some(PatKind::Binding(_, binding, ..)) = body.params.first().map(|p| p.pat.kind) @@ -192,7 +190,7 @@ fn check_manual_pattern_char_comparison(cx: &LateContext<'_>, method_arg: &Expr< { return; } - if set_char_spans.len() > 1 && !msrv.meets(msrvs::PATTERN_TRAIT_CHAR_ARRAY) { + if set_char_spans.len() > 1 && !msrv.meets(cx, msrvs::PATTERN_TRAIT_CHAR_ARRAY) { return; } span_lint_and_then( @@ -238,9 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for StringPatterns { { check_single_char_pattern_lint(cx, arg); - check_manual_pattern_char_comparison(cx, arg, &self.msrv); + check_manual_pattern_char_comparison(cx, arg, self.msrv); } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index cbf7b126632e7..f961e1c4d1a36 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -95,7 +95,7 @@ impl TraitBounds { pub fn new(conf: &'static Conf) -> Self { Self { max_trait_bounds: conf.max_trait_bounds, - msrv: conf.msrv.clone(), + msrv: conf.msrv, } } } @@ -223,17 +223,15 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { } } } - - extract_msrv_attr!(LateContext); } impl TraitBounds { /// Is the given bound a `?Sized` bound, and is combining it (i.e. `T: X + ?Sized`) an error on /// this MSRV? See for details. fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool { - if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE) - && let GenericBound::Trait(tr) = bound + if let GenericBound::Trait(tr) = bound && let BoundPolarity::Maybe(_) = tr.modifiers.polarity + && !self.msrv.meets(cx, msrvs::MAYBE_BOUND_IN_WHERE) { cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id() } else { diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index 1cb0f837227df..f2da8d35cb4fc 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -49,7 +49,6 @@ declare_clippy_lint! { "transmutes that are confusing at best, undefined behavior at worst and always useless" } -// FIXME: Move this to `complexity` again, after #5343 is fixed declare_clippy_lint! { /// ### What it does /// Checks for transmutes to the original type of the object @@ -599,9 +598,7 @@ impl_lint_pass!(Transmute => [ ]); impl Transmute { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } impl<'tcx> LateLintPass<'tcx> for Transmute { @@ -633,16 +630,16 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { | crosspointer_transmute::check(cx, e, from_ty, to_ty) | 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) + | 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, &self.msrv) + | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg, self.msrv) | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg) - | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv) + | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv) | transmute_int_to_non_zero::check(cx, e, from_ty, to_ty, arg) - | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv) - | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context, &self.msrv) + | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv) + | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context, self.msrv) | (unsound_collection_transmute::check(cx, e, from_ty, to_ty) || transmute_undefined_repr::check(cx, e, from_ty, to_ty)) | (eager_transmute::check(cx, e, arg, from_ty, to_ty)); @@ -652,6 +649,4 @@ impl<'tcx> LateLintPass<'tcx> for Transmute { } } } - - extract_msrv_attr!(LateContext); } 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 f0b8abf9af664..f2c757952af38 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 @@ -17,11 +17,11 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, mut arg: &'tcx Expr<'_>, const_context: bool, - msrv: &Msrv, + msrv: Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Float(float_ty), ty::Int(_) | ty::Uint(_)) - if !const_context || msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) => + if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) => { span_lint_and_then( cx, 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 e5b9aea6423a0..aaa95396b4b4b 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 @@ -16,10 +16,10 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, const_context: bool, - msrv: &Msrv, + msrv: Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { - (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context || msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) => { + (ty::Int(_) | ty::Uint(_), ty::Float(_)) if !const_context || msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) => { span_lint_and_then( cx, TRANSMUTE_INT_TO_FLOAT, 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 6d828bad9b32d..d72be270b731f 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 @@ -16,14 +16,15 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, const_context: bool, - msrv: &Msrv, + msrv: Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::Int(_) | ty::Uint(_) | ty::Float(_), ty::Array(arr_ty, _)) => { if !matches!(arr_ty.kind(), ty::Uint(UintTy::U8)) { return false; } - if matches!(from_ty.kind(), ty::Float(_)) && const_context && !msrv.meets(msrvs::CONST_FLOAT_BITS_CONV) { + if matches!(from_ty.kind(), ty::Float(_)) && const_context && !msrv.meets(cx, msrvs::CONST_FLOAT_BITS_CONV) + { return false; } diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs index c4a2e20fa9d31..fcc763763bd2f 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>( from_ty: Ty<'tcx>, to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, - msrv: &Msrv, + msrv: Msrv, ) -> bool { match (from_ty.kind(), to_ty.kind()) { (ty::RawPtr(from_pointee_ty, from_mutbl), ty::RawPtr(to_pointee_ty, to_mutbl)) => { @@ -28,7 +28,7 @@ pub(super) fn check<'tcx>( if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) { if from_mutbl == to_mutbl && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) - && msrv.meets(msrvs::POINTER_CAST) + && msrv.meets(cx, msrvs::POINTER_CAST) { diag.span_suggestion_verbose( e.span, @@ -43,7 +43,7 @@ pub(super) fn check<'tcx>( _ => None, } && !from_pointee_ty.has_erased_regions() - && msrv.meets(msrvs::POINTER_CAST_CONSTNESS) + && msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) { diag.span_suggestion_verbose( e.span, 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 ef18633d945fa..45ee83c78ab67 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 @@ -17,7 +17,7 @@ pub(super) fn check<'tcx>( to_ty: Ty<'tcx>, arg: &'tcx Expr<'_>, path: &'tcx Path<'_>, - msrv: &Msrv, + msrv: Msrv, ) -> bool { match (&from_ty.kind(), &to_ty.kind()) { (ty::RawPtr(from_ptr_ty, _), ty::Ref(_, to_ref_ty, mutbl)) => { @@ -37,7 +37,7 @@ pub(super) fn check<'tcx>( let sugg = if let Some(ty) = get_explicit_type(path) { let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app); - if msrv.meets(msrvs::POINTER_CAST) { + if msrv.meets(cx, msrvs::POINTER_CAST) { format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par()) } else if from_ptr_ty.has_erased_regions() { sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string() @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>( } } else if *from_ptr_ty == *to_ref_ty { if from_ptr_ty.has_erased_regions() { - if msrv.meets(msrvs::POINTER_CAST) { + if msrv.meets(cx, msrvs::POINTER_CAST) { format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par()) } else { sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}"))) diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs index c7aefc65f707f..95ce19975c7ec 100644 --- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs @@ -47,15 +47,13 @@ pub struct TupleArrayConversions { } impl TupleArrayConversions { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } impl LateLintPass<'_> for TupleArrayConversions { fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - if expr.span.in_external_macro(cx.sess().source_map()) || !self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) { + if expr.span.in_external_macro(cx.sess().source_map()) || !self.msrv.meets(cx, msrvs::TUPLE_ARRAY_CONVERSIONS) { return; } @@ -65,8 +63,6 @@ impl LateLintPass<'_> for TupleArrayConversions { _ => {}, } } - - extract_msrv_attr!(LateContext); } fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) { diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index 71e6e75c1bd3a..151a6f67437c0 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -2,6 +2,7 @@ mod borrowed_box; mod box_collection; mod linked_list; mod option_option; +mod owned_cow; mod rc_buffer; mod rc_mutex; mod redundant_allocation; @@ -355,13 +356,63 @@ declare_clippy_lint! { "usage of `Rc>`" } +declare_clippy_lint! { + /// ### What it does + /// Detects needlessly owned `Cow` types. + /// + /// ### Why is this bad? + /// The borrowed types are usually more flexible, in that e.g. a + /// `Cow<'_, str>` can accept both `&str` and `String` while + /// `Cow<'_, String>` can only accept `&String` and `String`. In + /// particular, `&str` is more general, because it allows for string + /// literals while `&String` can only be borrowed from a heap-owned + /// `String`). + /// + /// ### Known Problems + /// The lint does not check for usage of the type. There may be external + /// interfaces that require the use of an owned type. + /// + /// At least the `CString` type also has a different API than `CStr`: The + /// former has an `as_bytes` method which the latter calls `to_bytes`. + /// There is no guarantee that other types won't gain additional methods + /// leading to a similar mismatch. + /// + /// In addition, the lint only checks for the known problematic types + /// `String`, `Vec<_>`, `CString`, `OsString` and `PathBuf`. Custom types + /// that implement `ToOwned` will not be detected. + /// + /// ### Example + /// ```no_run + /// let wrogn: std::borrow::Cow<'_, Vec>; + /// ``` + /// Use instead: + /// ```no_run + /// let right: std::borrow::Cow<'_, [u8]>; + /// ``` + #[clippy::version = "1.85.0"] + pub OWNED_COW, + style, + "needlessly owned Cow type" +} + pub struct Types { vec_box_size_threshold: u64, type_complexity_threshold: u64, avoid_breaking_exported_api: bool, } -impl_lint_pass!(Types => [BOX_COLLECTION, VEC_BOX, OPTION_OPTION, LINKEDLIST, BORROWED_BOX, REDUNDANT_ALLOCATION, RC_BUFFER, RC_MUTEX, TYPE_COMPLEXITY]); +impl_lint_pass!(Types => [ + BOX_COLLECTION, + VEC_BOX, + OPTION_OPTION, + LINKEDLIST, + BORROWED_BOX, + REDUNDANT_ALLOCATION, + RC_BUFFER, + RC_MUTEX, + TYPE_COMPLEXITY, + OWNED_COW +]); impl<'tcx> LateLintPass<'tcx> for Types { fn check_fn( @@ -373,11 +424,10 @@ impl<'tcx> LateLintPass<'tcx> for Types { _: Span, def_id: LocalDefId, ) { - let is_in_trait_impl = if let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id( - cx.tcx - .hir_get_parent_item(cx.tcx.local_def_id_to_hir_id(def_id)) - .def_id, - ) { + let is_in_trait_impl = if let hir::Node::Item(item) = cx + .tcx + .hir_node_by_def_id(cx.tcx.hir_get_parent_item(cx.tcx.local_def_id_to_hir_id(def_id)).def_id) + { matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) } else { false @@ -560,6 +610,7 @@ impl Types { triggered |= option_option::check(cx, hir_ty, qpath, def_id); triggered |= linked_list::check(cx, hir_ty, def_id); triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id); + triggered |= owned_cow::check(cx, qpath, def_id); if triggered { return; @@ -611,6 +662,14 @@ impl Types { QPath::LangItem(..) => {}, } }, + TyKind::Path(ref qpath) => { + let res = cx.qpath_res(qpath, hir_ty.hir_id); + if let Some(def_id) = res.opt_def_id() + && self.is_type_change_allowed(context) + { + owned_cow::check(cx, qpath, def_id); + } + }, TyKind::Ref(lt, ref mut_ty) => { context.is_nested_call = true; if !borrowed_box::check(cx, hir_ty, lt, mut_ty) { diff --git a/src/tools/clippy/clippy_lints/src/types/owned_cow.rs b/src/tools/clippy/clippy_lints/src/types/owned_cow.rs new file mode 100644 index 0000000000000..8933994d18558 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/types/owned_cow.rs @@ -0,0 +1,66 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_opt; +use rustc_errors::Applicability; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir}; +use rustc_lint::LateContext; +use rustc_span::{Span, sym}; + +pub(super) fn check(cx: &LateContext<'_>, qpath: &hir::QPath<'_>, def_id: DefId) -> bool { + if cx.tcx.is_diagnostic_item(sym::Cow, def_id) + && let hir::QPath::Resolved(_, path) = qpath + && let [.., last_seg] = path.segments + && let Some(args) = last_seg.args + && let [_lt, carg] = args.args + && let hir::GenericArg::Type(cty) = carg + && let Some((span, repl)) = replacement(cx, cty.as_unambig_ty()) + { + span_lint_and_sugg( + cx, + super::OWNED_COW, + span, + "needlessly owned Cow type", + "use", + repl, + Applicability::Unspecified, + ); + return true; + } + false +} + +fn replacement(cx: &LateContext<'_>, cty: &hir::Ty<'_>) -> Option<(Span, String)> { + if clippy_utils::is_path_lang_item(cx, cty, hir::LangItem::String) { + return Some((cty.span, "str".into())); + } + if clippy_utils::is_path_diagnostic_item(cx, cty, sym::Vec) { + return if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = cty.kind + && let [.., last_seg] = path.segments + && let Some(args) = last_seg.args + && let [t, ..] = args.args + && let Some(snip) = snippet_opt(cx, t.span()) + { + Some((cty.span, format!("[{snip}]"))) + } else { + None + }; + } + if clippy_utils::is_path_diagnostic_item(cx, cty, sym::cstring_type) { + return Some(( + cty.span, + (if clippy_utils::is_no_std_crate(cx) { + "core::ffi::CStr" + } else { + "std::ffi::CStr" + }) + .into(), + )); + } + // Neither OsString nor PathBuf are available outside std + for (diag, repl) in [(sym::OsString, "std::ffi::OsStr"), (sym::PathBuf, "std::path::Path")] { + if clippy_utils::is_path_diagnostic_item(cx, cty, diag) { + return Some((cty.span, repl.into())); + } + } + None +} 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 93abf95e35773..be533ca915ed4 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -1,5 +1,5 @@ -use std::sync::Arc; use std::ops::ControlFlow; +use std::sync::Arc; use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_then; @@ -429,10 +429,9 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool { fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Span { span.to(cx .tcx - .hir() - .attrs(hir_id) + .hir_attrs(hir_id) .iter() - .fold(span, |acc, attr| acc.to(attr.span))) + .fold(span, |acc, attr| acc.to(attr.span()))) } enum HasSafetyComment { 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 47d6fe7db7667..019ae16ca8591 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 @@ -177,7 +177,7 @@ fn fmt_stmts_and_call( stmts_and_call.push(call_snippet_with_replacements); stmts_and_call = stmts_and_call .into_iter() - .map(|v| reindent_multiline(v.into(), true, Some(call_expr_indent)).into_owned()) + .map(|v| reindent_multiline(&v, true, Some(call_expr_indent))) .collect(); let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); @@ -185,8 +185,7 @@ fn fmt_stmts_and_call( let parent_node = cx.tcx.parent_hir_node(call_expr.hir_id); if !matches!(parent_node, Node::Block(_)) && !matches!(parent_node, Node::Stmt(_)) { let block_indent = call_expr_indent + 4; - stmts_and_call_snippet = - reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned(); + stmts_and_call_snippet = reindent_multiline(&stmts_and_call_snippet, true, Some(block_indent)); stmts_and_call_snippet = format!( "{{\n{}{}\n{}}}", " ".repeat(block_indent), diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs index 1df229c330eb3..5792b6b3178d7 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; -use clippy_utils::{get_parent_expr, path_to_local}; -use rustc_hir::{BindingMode, Expr, ExprField, ExprKind, Node, PatKind, Path, QPath, StructTailExpr, UnOp}; +use clippy_utils::{get_parent_expr, is_mutable, path_to_local}; +use rustc_hir::{Expr, ExprField, ExprKind, Path, QPath, StructTailExpr, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -157,16 +157,6 @@ fn same_path_in_all_fields<'tcx>( } } -fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let Some(hir_id) = path_to_local(expr) - && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) - { - matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..)) - } else { - true - } -} - fn check_references(cx: &LateContext<'_>, expr_a: &Expr<'_>, expr_b: &Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr_a) && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) 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 8923484bb58f0..f43715d6752e3 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -3,7 +3,7 @@ use clippy_config::Conf; use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::msrvs::{self, MsrvStack}; use clippy_utils::over; use rustc_ast::PatKind::*; use rustc_ast::mut_visit::*; @@ -48,13 +48,13 @@ declare_clippy_lint! { } pub struct UnnestedOrPatterns { - msrv: Msrv, + msrv: MsrvStack, } impl UnnestedOrPatterns { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: MsrvStack::new(conf.msrv), } } } @@ -88,7 +88,7 @@ impl EarlyLintPass for UnnestedOrPatterns { } } - extract_msrv_attr!(EarlyContext); + extract_msrv_attr!(); } fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) { diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index 2c6c75693166f..582aa6e6001e8 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -57,7 +57,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { return; } let parent = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id; - let parent_item = cx.tcx.hir().expect_item(parent); + let parent_item = cx.tcx.hir_expect_item(parent); let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let contains_todo = |cx, body: &'_ Body<'_>| -> bool { clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { diff --git a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs index f83415834351f..2577f1ceaa2c0 100644 --- a/src/tools/clippy/clippy_lints/src/unused_trait_names.rs +++ b/src/tools/clippy/clippy_lints/src/unused_trait_names.rs @@ -51,9 +51,7 @@ pub struct UnusedTraitNames { impl UnusedTraitNames { pub fn new(conf: &'static Conf) -> Self { - Self { - msrv: conf.msrv.clone(), - } + Self { msrv: conf.msrv } } } @@ -61,8 +59,7 @@ impl_lint_pass!(UnusedTraitNames => [UNUSED_TRAIT_NAMES]); impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if self.msrv.meets(msrvs::UNDERSCORE_IMPORTS) - && !item.span.in_external_macro(cx.sess().source_map()) + if !item.span.in_external_macro(cx.sess().source_map()) && let ItemKind::Use(path, UseKind::Single) = item.kind // Ignore imports that already use Underscore && item.ident.name != kw::Underscore @@ -74,6 +71,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { && cx.tcx.visibility(item.owner_id.def_id) == Visibility::Restricted(module.to_def_id()) && let Some(last_segment) = path.segments.last() && let Some(snip) = snippet_opt(cx, last_segment.ident.span) + && self.msrv.meets(cx, msrvs::UNDERSCORE_IMPORTS) && !is_from_proc_macro(cx, &last_segment.ident) { let complete_span = last_segment.ident.span.to(item.ident.span); @@ -88,6 +86,4 @@ impl<'tcx> LateLintPass<'tcx> for UnusedTraitNames { ); } } - - extract_msrv_attr!(LateContext); } diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index 76b9bbbd32fde..b466a8e127a94 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -230,6 +230,8 @@ impl<'tcx> Delegate<'tcx> for MutationVisitor<'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn fake_read(&mut self, _: &PlaceWithHirId<'tcx>, _: FakeReadCause, _: HirId) {} } @@ -316,7 +318,7 @@ impl<'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'_, 'tcx> { { if call_to_unwrap == unwrappable.safe_to_unwrap { let is_entire_condition = unwrappable.is_entire_condition; - let unwrappable_variable_name = self.cx.tcx.hir().name(unwrappable.local_id); + let unwrappable_variable_name = self.cx.tcx.hir_name(unwrappable.local_id); let suggested_pattern = if call_to_unwrap { unwrappable.kind.success_variant_pattern() } else { diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index 47ce2243aa092..743f54ca993a9 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -2,7 +2,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::ty::same_type_and_consts; +use clippy_utils::ty::{same_type_and_consts, ty_from_hir_ty}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{CtorOf, DefKind, Res}; @@ -12,7 +12,6 @@ use rustc_hir::{ self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind, HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind, }; -use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty as MiddleTy; use rustc_session::impl_lint_pass; @@ -63,7 +62,7 @@ pub struct UseSelf { impl UseSelf { pub fn new(conf: &'static Conf) -> Self { Self { - msrv: conf.msrv.clone(), + msrv: conf.msrv, stack: Vec::new(), } } @@ -73,7 +72,6 @@ impl UseSelf { enum StackItem { Check { impl_id: LocalDefId, - in_body: u32, types_to_skip: FxHashSet, }, NoCheck, @@ -96,8 +94,8 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { .as_ref() .is_none_or(|params| params.parenthesized == GenericArgsParentheses::No) && !item.span.from_expansion() + // expensive, should be last check && !is_from_proc_macro(cx, item) - // expensive, should be last check { // Self cannot be used inside const generic parameters let types_to_skip = generics @@ -117,7 +115,6 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { .collect(); StackItem::Check { impl_id: item.owner_id.def_id, - in_body: 0, types_to_skip, } } else { @@ -131,6 +128,11 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { + // Checking items of `impl Self` blocks in which macro expands into. + if impl_item.span.from_expansion() { + self.stack.push(StackItem::NoCheck); + return; + } // We want to skip types in trait `impl`s that aren't declared as `Self` in the trait // declaration. The collection of those types is all this method implementation does. if let ImplItemKind::Fn(FnSig { decl, .. }, ..) = impl_item.kind @@ -186,27 +188,18 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { } } - fn check_body(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) { - // `lower_ty` cannot be called in `Body`s or it will panic (sometimes). But in bodies - // we can use `cx.typeck_results.node_type(..)` to get the `ty::Ty` from a `hir::Ty`. - // However the `node_type()` method can *only* be called in bodies. - if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() { - *in_body = in_body.saturating_add(1); - } - } - - fn check_body_post(&mut self, _: &LateContext<'_>, _: &hir::Body<'_>) { - if let Some(&mut StackItem::Check { ref mut in_body, .. }) = self.stack.last_mut() { - *in_body = in_body.saturating_sub(1); + fn check_impl_item_post(&mut self, _: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) { + if impl_item.span.from_expansion() + && let Some(StackItem::NoCheck) = self.stack.last() + { + self.stack.pop(); } } fn check_ty(&mut self, cx: &LateContext<'tcx>, hir_ty: &Ty<'tcx, AmbigArg>) { if !hir_ty.span.from_expansion() - && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) && let Some(&StackItem::Check { impl_id, - in_body, ref types_to_skip, }) = self.stack.last() && let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind @@ -215,18 +208,14 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } | Res::Def(DefKind::TyParam, _) ) && !types_to_skip.contains(&hir_ty.hir_id) - && let ty = if in_body > 0 { - cx.typeck_results().node_type(hir_ty.hir_id) - } else { - // We don't care about ignoring infer vars here - lower_ty(cx.tcx, hir_ty.as_unambig_ty()) - } + && let ty = ty_from_hir_ty(cx, hir_ty.as_unambig_ty()) && let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity() && same_type_and_consts(ty, impl_ty) // Ensure the type we encounter and the one from the impl have the same lifetime parameters. It may be that // the lifetime parameters of `ty` are elided (`impl<'a> Foo<'a> { fn new() -> Self { Foo{..} } }`, in // which case we must still trigger the lint. && (has_no_lifetime(ty) || same_lifetimes(ty, impl_ty)) + && self.msrv.meets(cx, msrvs::TYPE_ALIAS_ENUM_VARIANTS) { span_lint(cx, hir_ty.span); } @@ -234,9 +223,9 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if !expr.span.from_expansion() - && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last() && cx.typeck_results().expr_ty(expr) == cx.tcx.type_of(impl_id).instantiate_identity() + && self.msrv.meets(cx, msrvs::TYPE_ALIAS_ENUM_VARIANTS) { } else { return; @@ -255,19 +244,17 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf { fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) { if !pat.span.from_expansion() - && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS) && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last() // get the path from the pattern && let PatKind::Expr(&PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) | PatKind::TupleStruct(QPath::Resolved(_, path), _, _) | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind && cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity() + && self.msrv.meets(cx, msrvs::TYPE_ALIAS_ENUM_VARIANTS) { check_path(cx, path); } } - - extract_msrv_attr!(LateContext); } #[derive(Default)] diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 5fc166438e84a..4309cd2c9abdf 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -426,6 +426,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Tup({elements})"); self.slice(elements, |e| self.expr(e)); }, + ExprKind::Use(expr, _) => { + bind!(self, expr); + kind!("Use({expr})"); + self.expr(expr); + }, ExprKind::Binary(op, left, right) => { bind!(self, op, left, right); kind!("Binary({op}, {left}, {right})"); @@ -488,6 +493,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }) => { let capture_clause = match capture_clause { CaptureBy::Value { .. } => "Value { .. }", + CaptureBy::Use { .. } => "Use { .. }", CaptureBy::Ref => "Ref", }; @@ -787,7 +793,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { } fn has_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - let attrs = cx.tcx.hir().attrs(hir_id); + let attrs = cx.tcx.hir_attrs(hir_id); get_attr(cx.sess(), attrs, "author").count() > 0 } diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs index b108951978f30..9910be9bc2853 100644 --- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs +++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs @@ -59,6 +59,6 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir { } fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool { - let attrs = cx.tcx.hir().attrs(hir_id); + let attrs = cx.tcx.hir_attrs(hir_id); get_attr(cx.sess(), attrs, "dump").count() > 0 } 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 d6f10f1e4b801..16d51fa09025a 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 @@ -247,9 +247,9 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' /// This function extracts the version value of a `clippy::version` attribute if the given value has /// one pub(super) fn extract_clippy_version_value(cx: &LateContext<'_>, item: &'_ Item<'_>) -> Option { - let attrs = cx.tcx.hir().attrs(item.hir_id()); + let attrs = cx.tcx.hir_attrs(item.hir_id()); attrs.iter().find_map(|attr| { - if let hir::AttrKind::Normal(attr_kind) = &attr.kind + if let hir::Attribute::Unparsed(attr_kind) = &attr // Identify attribute && let [tool_name, attr_name] = &attr_kind.path.segments[..] && tool_name.name == sym::clippy @@ -278,6 +278,6 @@ impl<'tcx> Visitor<'tcx> for LintCollector<'_, 'tcx> { } fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { - self.cx.tcx.hir() + self.cx.tcx } } 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 6869224615303..558acacb97245 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 @@ -30,8 +30,7 @@ impl LateLintPass<'_> for MsrvAttrImpl { .tcx .impl_trait_ref(item.owner_id) .map(EarlyBinder::instantiate_identity) - && let is_late_pass = match_def_path(cx, trait_ref.def_id, &paths::LATE_LINT_PASS) - && (is_late_pass || match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS)) + && match_def_path(cx, trait_ref.def_id, &paths::EARLY_LINT_PASS) && let ty::Adt(self_ty_def, _) = trait_ref.self_ty().kind() && self_ty_def.is_struct() && self_ty_def.all_fields().any(|f| { @@ -40,20 +39,18 @@ impl LateLintPass<'_> for MsrvAttrImpl { .instantiate_identity() .walk() .filter(|t| matches!(t.unpack(), GenericArgKind::Type(_))) - .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV)) + .any(|t| match_type(cx, t.expect_ty(), &paths::MSRV_STACK)) }) && !items.iter().any(|item| item.ident.name.as_str() == "check_attributes") { - let context = if is_late_pass { "LateContext" } else { "EarlyContext" }; - let lint_pass = if is_late_pass { "LateLintPass" } else { "EarlyLintPass" }; let span = cx.sess().source_map().span_through_char(item.span, '{'); span_lint_and_sugg( 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!("{}\n extract_msrv_attr!({context});", snippet(cx, span, "..")), + "`extract_msrv_attr!` macro missing from `EarlyLintPass` implementation", + "add `extract_msrv_attr!()` to the `EarlyLintPass` implementation", + format!("{}\n extract_msrv_attr!();", snippet(cx, span, "..")), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 03c667846b611..3346b15dae9ca 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -27,7 +27,7 @@ impl UselessVec { pub fn new(conf: &'static Conf) -> Self { Self { too_large_for_stack: conf.too_large_for_stack, - msrv: conf.msrv.clone(), + msrv: conf.msrv, span_to_lint_map: BTreeMap::new(), allow_in_test: conf.allow_useless_vec_in_tests, } @@ -111,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { }, // search for `for _ in vec![...]` Node::Expr(Expr { span, .. }) - if span.is_desugaring(DesugaringKind::ForLoop) && self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR) => + if span.is_desugaring(DesugaringKind::ForLoop) && self.msrv.meets(cx, msrvs::ARRAY_INTO_ITERATOR) => { let suggest_slice = suggest_type(expr); self.check_vec_macro(cx, &vec_args, callsite, expr.hir_id, suggest_slice); @@ -149,8 +149,6 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec { } } } - - extract_msrv_attr!(LateContext); } impl UselessVec { diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index 4c9a7f0e16de6..f6948be7f67aa 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item}; +use clippy_utils::ty::{is_normalizable, is_type_diagnostic_item, ty_from_hir_ty}; use rustc_hir::{self as hir, AmbigArg, HirId, ItemKind, Node}; -use rustc_hir_analysis::lower_ty; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{self, Ty, TypeVisitableExt}; +use rustc_middle::ty::{self, TypeVisitableExt}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -82,15 +81,3 @@ fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool { } false } - -fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { - cx.maybe_typeck_results() - .and_then(|results| { - if results.hir_owner == hir_ty.hir_id.owner { - results.node_type_opt(hir_ty.hir_id) - } else { - None - } - }) - .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty)) -} diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs index 9bd00b1e5c8cc..7667db469689e 100644 --- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs +++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs @@ -1,6 +1,6 @@ use ControlFlow::{Break, Continue}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{fn_def_id, get_enclosing_block, match_any_def_paths, match_def_path, path_to_local_id, paths}; +use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id}; use rustc_ast::Mutability; use rustc_ast::visit::visit_opt; use rustc_errors::Applicability; @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Call(..) | ExprKind::MethodCall(..) = expr.kind && let Some(child_adt) = cx.typeck_results().expr_ty(expr).ty_adt_def() - && match_def_path(cx, child_adt.did(), &paths::CHILD) + && cx.tcx.is_diagnostic_item(sym::Child, child_adt.did()) { match cx.tcx.parent_hir_node(expr.hir_id) { Node::LetStmt(local) @@ -178,8 +178,8 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { Node::Expr(expr) if let ExprKind::AddrOf(_, Mutability::Not, _) = expr.kind => {}, Node::Expr(expr) if let Some(fn_did) = fn_def_id(self.cx, expr) - && match_any_def_paths(self.cx, fn_did, &[&paths::CHILD_ID, &paths::CHILD_KILL]).is_some() => { - }, + && (self.cx.tcx.is_diagnostic_item(sym::child_id, fn_did) + || self.cx.tcx.is_diagnostic_item(sym::child_kill, fn_did)) => {}, // Conservatively assume that all other kinds of nodes call `.wait()` somehow. _ => return Break(MaybeWait(ex.span)), @@ -353,7 +353,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, spawn_expr: &'tcx Expr<'tcx>, cause: Caus /// Checks if the given expression exits the process. fn is_exit_expression(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { fn_def_id(cx, expr).is_some_and(|fn_did| { - cx.tcx.is_diagnostic_item(sym::process_exit, fn_did) || match_def_path(cx, fn_did, &paths::ABORT) + cx.tcx.is_diagnostic_item(sym::process_exit, fn_did) || cx.tcx.is_diagnostic_item(sym::process_abort, fn_did) }) } diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 68b7e1592e2ea..ba4bb1d177c57 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "clippy_utils" # begin autogenerated version -version = "0.1.86" +version = "0.1.87" # end autogenerated version edition = "2024" description = "Helpful tools for writing lints, provided as they are used in Clippy" diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 41f3b1cbd5079..5dd31b52f8800 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: ``` -nightly-2025-02-06 +nightly-2025-02-27 ``` diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index ab5f97199ce33..707312a97f3bc 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -364,6 +364,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { generics: lg, contract: lc, body: lb, + define_opaque: _, }), Fn(box ast::Fn { defaultness: rd, @@ -371,6 +372,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { generics: rg, contract: rc, body: rb, + define_opaque: _, }), ) => { eq_defaultness(*ld, *rd) @@ -502,6 +504,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { generics: lg, contract: lc, body: lb, + define_opaque: _, }), Fn(box ast::Fn { defaultness: rd, @@ -509,6 +512,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { generics: rg, contract: rc, body: rb, + define_opaque: _, }), ) => { eq_defaultness(*ld, *rd) @@ -567,6 +571,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { generics: lg, contract: lc, body: lb, + define_opaque: _, }), Fn(box ast::Fn { defaultness: rd, @@ -574,6 +579,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { generics: rg, contract: rc, body: rb, + define_opaque: _, }), ) => { eq_defaultness(*ld, *rd) @@ -682,19 +688,20 @@ pub fn eq_generics(l: &Generics, r: &Generics) -> bool { pub fn eq_where_predicate(l: &WherePredicate, r: &WherePredicate) -> bool { use WherePredicateKind::*; - match (&l.kind, &r.kind) { - (BoundPredicate(l), BoundPredicate(r)) => { - over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { - eq_generic_param(l, r) - }) && eq_ty(&l.bounded_ty, &r.bounded_ty) - && over(&l.bounds, &r.bounds, eq_generic_bound) - }, - (RegionPredicate(l), RegionPredicate(r)) => { - eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, eq_generic_bound) - }, - (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty), - _ => false, - } + over(&l.attrs, &r.attrs, eq_attr) + && match (&l.kind, &r.kind) { + (BoundPredicate(l), BoundPredicate(r)) => { + over(&l.bound_generic_params, &r.bound_generic_params, |l, r| { + eq_generic_param(l, r) + }) && eq_ty(&l.bounded_ty, &r.bounded_ty) + && over(&l.bounds, &r.bounds, eq_generic_bound) + }, + (RegionPredicate(l), RegionPredicate(r)) => { + eq_id(l.lifetime.ident, r.lifetime.ident) && over(&l.bounds, &r.bounds, eq_generic_bound) + }, + (EqPredicate(l), EqPredicate(r)) => eq_ty(&l.lhs_ty, &r.lhs_ty) && eq_ty(&l.rhs_ty, &r.rhs_ty), + _ => false, + } } pub fn eq_use_tree(l: &UseTree, r: &UseTree) -> bool { diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index aaea8d71efbef..4543a20cc2cd4 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -291,6 +291,7 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS ExprKind::ConstBlock(_) | ExprKind::Array(_) | ExprKind::Tup(_) + | ExprKind::Use(..) | ExprKind::Lit(_) | ExprKind::Cast(..) | ExprKind::Type(..) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 9ee30094d608c..9938e64d24264 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -393,6 +393,7 @@ impl HirEqInterExpr<'_, '_, '_> { && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), + (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr), (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt), (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re), @@ -425,6 +426,7 @@ impl HirEqInterExpr<'_, '_, '_> { | &ExprKind::Ret(..) | &ExprKind::Struct(..) | &ExprKind::Tup(..) + | &ExprKind::Use(..) | &ExprKind::Type(..) | &ExprKind::Unary(..) | &ExprKind::Yield(..) @@ -968,7 +970,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(out_expr); } }, - InlineAsmOperand::Const { anon_const } | InlineAsmOperand::SymFn { anon_const } => { + InlineAsmOperand::SymFn { expr } => { + self.hash_expr(expr); + }, + InlineAsmOperand::Const { anon_const } => { self.hash_body(anon_const.body); }, InlineAsmOperand::SymStatic { path, def_id: _ } => self.hash_qpath(path), @@ -1050,6 +1055,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Tup(tup) => { self.hash_exprs(tup); }, + ExprKind::Use(expr, _) => { + self.hash_expr(expr); + }, ExprKind::Unary(lop, le) => { std::mem::discriminant(&lop).hash(&mut self.s); self.hash_expr(le); @@ -1105,14 +1113,9 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_ty_pat(&mut self, pat: &TyPat<'_>) { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { - TyPatKind::Range(s, e, i) => { - if let Some(s) = s { - self.hash_const_arg(s); - } - if let Some(e) = e { - self.hash_const_arg(e); - } - std::mem::discriminant(&i).hash(&mut self.s); + TyPatKind::Range(s, e) => { + self.hash_const_arg(s); + self.hash_const_arg(e); }, TyPatKind::Err(_) => {}, } diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 40ddd75b7fad1..80613a51c1400 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -31,7 +31,6 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_abi; extern crate rustc_ast; -extern crate rustc_ast_pretty; extern crate rustc_attr_parsing; extern crate rustc_const_eval; extern crate rustc_data_structures; @@ -40,6 +39,7 @@ extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; +extern crate rustc_hir_analysis; extern crate rustc_hir_typeck; extern crate rustc_index; extern crate rustc_infer; @@ -92,7 +92,9 @@ use std::iter::{once, repeat_n}; use std::sync::{Mutex, MutexGuard, OnceLock}; use itertools::Itertools; +use rustc_abi::Integer; use rustc_ast::ast::{self, LitKind, RangeLimits}; +use rustc_attr_parsing::{AttributeKind, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::packed::Pu128; use rustc_data_structures::unhash::UnhashMap; @@ -106,24 +108,24 @@ use rustc_hir::{ self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat, - PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, + PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::place::PlaceBase; +use rustc_middle::mir::{AggregateKind, Operand, RETURN_PLACE, Rvalue, StatementKind, TerminatorKind}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ self as rustc_ty, Binder, BorrowKind, ClosureKind, EarlyBinder, FloatTy, GenericArgKind, GenericArgsRef, IntTy, Ty, - TyCtxt, TypeVisitableExt, UintTy, UpvarCapture, + TyCtxt, TypeFlags, TypeVisitableExt, UintTy, UpvarCapture, }; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::{Ident, Symbol, kw}; use rustc_span::{InnerSpan, Span, sym}; -use rustc_abi::Integer; use visitors::{Visitable, for_each_unconsumed_temporary}; use crate::consts::{ConstEvalCtxt, Constant, mir_to_const}; @@ -134,24 +136,13 @@ use rustc_middle::hir::nested_filter; #[macro_export] macro_rules! extract_msrv_attr { - (LateContext) => { - fn check_attributes(&mut self, cx: &rustc_lint::LateContext<'_>, attrs: &[rustc_hir::Attribute]) { + () => { + fn check_attributes(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::ast::Attribute]) { let sess = rustc_lint::LintContext::sess(cx); self.msrv.check_attributes(sess, attrs); } - fn check_attributes_post(&mut self, cx: &rustc_lint::LateContext<'_>, attrs: &[rustc_hir::Attribute]) { - let sess = rustc_lint::LintContext::sess(cx); - self.msrv.check_attributes_post(sess, attrs); - } - }; - (EarlyContext) => { - fn check_attributes(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) { - let sess = rustc_lint::LintContext::sess(cx); - self.msrv.check_attributes(sess, attrs); - } - - fn check_attributes_post(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) { + fn check_attributes_post(&mut self, cx: &rustc_lint::EarlyContext<'_>, attrs: &[rustc_ast::ast::Attribute]) { let sess = rustc_lint::LintContext::sess(cx); self.msrv.check_attributes_post(sess, attrs); } @@ -914,22 +905,101 @@ 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 { +pub fn is_default_equivalent_call( + cx: &LateContext<'_>, + repl_func: &Expr<'_>, + whole_call_expr: Option<&Expr<'_>>, +) -> bool { 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)) { - true - } else { - false + return true; + } + + // Get the type of the whole method call expression, find the exact method definition, look at + // its body and check if it is similar to the corresponding `Default::default()` body. + let Some(e) = whole_call_expr else { return false }; + let Some(default_fn_def_id) = cx.tcx.get_diagnostic_item(sym::default_fn) else { + return false; + }; + let Some(ty) = cx.tcx.typeck(e.hir_id.owner.def_id).expr_ty_adjusted_opt(e) else { + return false; + }; + let args = rustc_ty::GenericArgs::for_item(cx.tcx, default_fn_def_id, |param, _| { + if let rustc_ty::GenericParamDefKind::Lifetime = param.kind { + cx.tcx.lifetimes.re_erased.into() + } else if param.index == 0 && param.name == kw::SelfUpper { + ty.into() + } else { + param.to_error(cx.tcx) + } + }); + let instance = rustc_ty::Instance::try_resolve(cx.tcx, cx.typing_env(), default_fn_def_id, args); + + let Ok(Some(instance)) = instance else { return false }; + if let rustc_ty::InstanceKind::Item(def) = instance.def + && !cx.tcx.is_mir_available(def) + { + return false; } + let ExprKind::Path(ref repl_func_qpath) = repl_func.kind else { + return false; + }; + let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id() else { + return false; + }; + + // Get the MIR Body for the `::default()` function. + // If it is a value or call (either fn or ctor), we compare its `DefId` against the one for the + // resolution of the expression we had in the path. This lets us identify, for example, that + // the body of ` as Default>::default()` is a `Vec::new()`, and the field was being + // initialized to `Vec::new()` as well. + let body = cx.tcx.instance_mir(instance.def); + for block_data in body.basic_blocks.iter() { + if block_data.statements.len() == 1 + && let StatementKind::Assign(assign) = &block_data.statements[0].kind + && assign.0.local == RETURN_PLACE + && let Rvalue::Aggregate(kind, _places) = &assign.1 + && let AggregateKind::Adt(did, variant_index, _, _, _) = &**kind + && let def = cx.tcx.adt_def(did) + && let variant = &def.variant(*variant_index) + && variant.fields.is_empty() + && let Some((_, did)) = variant.ctor + && did == repl_def_id + { + return true; + } else if block_data.statements.is_empty() + && let Some(term) = &block_data.terminator + { + match &term.kind { + TerminatorKind::Call { + func: Operand::Constant(c), + .. + } if let rustc_ty::FnDef(did, _args) = c.ty().kind() + && *did == repl_def_id => + { + return true; + }, + TerminatorKind::TailCall { + func: Operand::Constant(c), + .. + } if let rustc_ty::FnDef(did, _args) = c.ty().kind() + && *did == repl_def_id => + { + return true; + }, + _ => {}, + } + } + } + false } -/// Returns true if the expr is equal to `Default::default()` of it's type when evaluated. +/// Returns true if the expr is equal to `Default::default()` of its type when evaluated. /// -/// It doesn't cover all cases, for example indirect function calls (some of std -/// functions are supported) but it is the best we have. +/// It doesn't cover all cases, like struct literals, but it is a close approximation. pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { match &e.kind { ExprKind::Lit(lit) => match lit.node { @@ -950,7 +1020,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { false } }, - ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func), + ExprKind::Call(repl_func, []) => is_default_equivalent_call(cx, repl_func, Some(e)), ExprKind::Call(from_func, [arg]) => is_default_equivalent_from(cx, from_func, arg), ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone), ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])), @@ -1059,6 +1129,7 @@ pub fn can_move_expr_to_closure_no_visit<'tcx>( #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CaptureKind { Value, + Use, Ref(Mutability), } impl CaptureKind { @@ -1071,6 +1142,7 @@ impl std::ops::BitOr for CaptureKind { fn bitor(self, rhs: Self) -> Self::Output { match (self, rhs) { (CaptureKind::Value, _) | (_, CaptureKind::Value) => CaptureKind::Value, + (CaptureKind::Use, _) | (_, CaptureKind::Use) => CaptureKind::Use, (CaptureKind::Ref(Mutability::Mut), CaptureKind::Ref(_)) | (CaptureKind::Ref(_), CaptureKind::Ref(Mutability::Mut)) => CaptureKind::Ref(Mutability::Mut), (CaptureKind::Ref(Mutability::Not), CaptureKind::Ref(Mutability::Not)) => CaptureKind::Ref(Mutability::Not), @@ -1094,7 +1166,6 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { pat.each_binding_or_first(&mut |_, id, span, _| match cx .typeck_results() .extract_binding_mode(cx.sess(), id, span) - .unwrap() .0 { ByRef::No if !is_copy(cx, cx.typeck_results().node_type(id)) => { @@ -1151,7 +1222,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { }, ExprKind::Let(let_expr) => { let mutability = match pat_capture_kind(cx, let_expr.pat) { - CaptureKind::Value => Mutability::Not, + CaptureKind::Value | CaptureKind::Use => Mutability::Not, CaptureKind::Ref(m) => m, }; return CaptureKind::Ref(mutability); @@ -1160,7 +1231,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { let mut mutability = Mutability::Not; for capture in arms.iter().map(|arm| pat_capture_kind(cx, arm.pat)) { match capture { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, CaptureKind::Ref(Mutability::Mut) => mutability = Mutability::Mut, CaptureKind::Ref(Mutability::Not) => (), } @@ -1170,7 +1241,7 @@ pub fn capture_local_usage(cx: &LateContext<'_>, e: &Expr<'_>) -> CaptureKind { _ => break, }, Node::LetStmt(l) => match pat_capture_kind(cx, l.pat) { - CaptureKind::Value => break, + CaptureKind::Value | CaptureKind::Use => break, capture @ CaptureKind::Ref(_) => return capture, }, _ => break, @@ -1225,6 +1296,7 @@ pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<' if !self.locals.contains(&local_id) { let capture = match capture.info.capture_kind { UpvarCapture::ByValue => CaptureKind::Value, + UpvarCapture::ByUse => CaptureKind::Use, UpvarCapture::ByRef(kind) => match kind { BorrowKind::Immutable => CaptureKind::Ref(Mutability::Not), BorrowKind::UniqueImmutable | BorrowKind::Mutable => { @@ -1420,6 +1492,10 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio | Node::ImplItem(&ImplItem { kind: ImplItemKind::Fn(_, eid), .. + }) + | Node::TraitItem(&TraitItem { + kind: TraitItemKind::Fn(_, TraitFn::Provided(eid)), + .. }) => match cx.tcx.hir_body(eid).value.kind { ExprKind::Block(block, _) => Some(block), _ => None, @@ -1666,6 +1742,17 @@ pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { false } +/// Checks whether the given expression is a constant literal of the given value. +pub fn is_float_literal(expr: &Expr<'_>, value: f64) -> bool { + if let ExprKind::Lit(spanned) = expr.kind + && let LitKind::Float(v, _) = spanned.node + { + v.as_str().parse() == Ok(value) + } else { + false + } +} + /// Returns `true` if the given `Expr` has been coerced before. /// /// Examples of coercions can be found in the Nomicon at @@ -1949,15 +2036,14 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool { } pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool { - has_attr(cx.tcx.hir().attrs(hir_id), sym::repr) + find_attr!(cx.tcx.hir_attrs(hir_id), AttributeKind::Repr(..)) } pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool { - let map = &tcx.hir(); let mut prev_enclosing_node = None; let mut enclosing_node = node; while Some(enclosing_node) != prev_enclosing_node { - if has_attr(map.attrs(enclosing_node), symbol) { + if has_attr(tcx.hir_attrs(enclosing_node), symbol) { return true; } prev_enclosing_node = Some(enclosing_node); @@ -1970,12 +2056,11 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool /// Checks if the given HIR node is inside an `impl` block with the `automatically_derived` /// attribute. pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { - tcx - .hir_parent_owner_iter(id) + tcx.hir_parent_owner_iter(id) .filter(|(_, node)| matches!(node, OwnerNode::Item(item) if matches!(item.kind, ItemKind::Impl(_)))) .any(|(id, _)| { has_attr( - tcx.hir().attrs(tcx.local_def_id_to_hir_id(id.def_id)), + tcx.hir_attrs(tcx.local_def_id_to_hir_id(id.def_id)), sym::automatically_derived, ) }) @@ -2258,16 +2343,14 @@ pub fn std_or_core(cx: &LateContext<'_>) -> Option<&'static str> { pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool { cx.tcx - .hir() - .attrs(hir::CRATE_HIR_ID) + .hir_attrs(hir::CRATE_HIR_ID) .iter() .any(|attr| attr.name_or_empty() == sym::no_std) } pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { cx.tcx - .hir() - .attrs(hir::CRATE_HIR_ID) + .hir_attrs(hir::CRATE_HIR_ID) .iter() .any(|attr| attr.name_or_empty() == sym::no_core) } @@ -2557,8 +2640,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym // We could also check for the type name `test::TestDescAndFn` if let Res::Def(DefKind::Struct, _) = path.res { let has_test_marker = tcx - .hir() - .attrs(item.hir_id()) + .hir_attrs(item.hir_id()) .iter() .any(|a| a.has_name(sym::rustc_test_marker)); if has_test_marker { @@ -2602,7 +2684,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: 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: HirId) -> bool { - tcx.hir().attrs(id).iter().any(|attr| { + tcx.hir_attrs(id).iter().any(|attr| { if attr.has_name(sym::cfg) && let Some(items) = attr.meta_item_list() && let [item] = &*items @@ -2617,9 +2699,7 @@ pub fn is_cfg_test(tcx: TyCtxt<'_>, id: HirId) -> bool { /// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied 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)) + tcx.hir_parent_id_iter(id).any(|parent_id| is_cfg_test(tcx, parent_id)) } /// Checks if the node is in a `#[test]` function or has any parent node marked `#[cfg(test)]` @@ -2629,12 +2709,10 @@ pub fn is_in_test(tcx: TyCtxt<'_>, hir_id: HirId) -> bool { /// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied. pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - let hir = tcx.hir(); - tcx.has_attr(def_id, sym::cfg) || tcx .hir_parent_iter(tcx.local_def_id_to_hir_id(def_id)) - .flat_map(|(parent_id, _)| hir.attrs(parent_id)) + .flat_map(|(parent_id, _)| tcx.hir_attrs(parent_id)) .any(|attr| attr.has_name(sym::cfg)) } @@ -3408,7 +3486,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::c ::d::sym refers to // e::f::sym:: :: // result should be super::super::super::super::e::f - if let DefPathData::TypeNs(s) = l { + if let DefPathData::TypeNs(Some(s)) = l { path.push(s.to_string()); } if let DefPathData::TypeNs(_) = r { @@ -3419,7 +3497,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // a::b::sym:: :: refers to // c::d::e ::f::sym // when looking at `f` - Left(DefPathData::TypeNs(sym)) => path.push(sym.to_string()), + Left(DefPathData::TypeNs(Some(sym))) => path.push(sym.to_string()), // consider: // a::b::c ::d::sym refers to // e::f::sym:: :: @@ -3433,7 +3511,7 @@ fn maybe_get_relative_path(from: &DefPath, to: &DefPath, max_super: usize) -> St // `super` chain would be too long, just use the absolute path instead once(String::from("crate")) .chain(to.data.iter().filter_map(|el| { - if let DefPathData::TypeNs(sym) = el.data { + if let DefPathData::TypeNs(Some(sym)) = el.data { Some(sym.to_string()) } else { None @@ -3503,3 +3581,114 @@ pub fn leaks_droppable_temporary_with_limited_lifetime<'tcx>(cx: &LateContext<'t }) .is_break() } + +/// Returns true if the specified `expr` requires coercion, +/// meaning that it either has a coercion or propagates a coercion from one of its sub expressions. +/// +/// Similar to [`is_adjusted`], this not only checks if an expression's type was adjusted, +/// but also going through extra steps to see if it fits the description of [coercion sites]. +/// +/// You should used this when you want to avoid suggesting replacing an expression that is currently +/// a coercion site or coercion propagating expression with one that is not. +/// +/// [coercion sites]: https://doc.rust-lang.org/stable/reference/type-coercions.html#coercion-sites +pub fn expr_requires_coercion<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> bool { + let expr_ty_is_adjusted = cx + .typeck_results() + .expr_adjustments(expr) + .iter() + // ignore `NeverToAny` adjustments, such as `panic!` call. + .any(|adj| !matches!(adj.kind, Adjust::NeverToAny)); + if expr_ty_is_adjusted { + return true; + } + + // Identify coercion sites and recursively check if those sites + // actually have type adjustments. + match expr.kind { + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) if let Some(def_id) = fn_def_id(cx, expr) => { + let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity(); + + if !fn_sig.output().skip_binder().has_type_flags(TypeFlags::HAS_TY_PARAM) { + return false; + } + + let self_arg_count = usize::from(matches!(expr.kind, ExprKind::MethodCall(..))); + let mut args_with_ty_param = { + fn_sig + .inputs() + .skip_binder() + .iter() + .skip(self_arg_count) + .zip(args) + .filter_map(|(arg_ty, arg)| { + if arg_ty.has_type_flags(TypeFlags::HAS_TY_PARAM) { + Some(arg) + } else { + None + } + }) + }; + args_with_ty_param.any(|arg| expr_requires_coercion(cx, arg)) + }, + // Struct/union initialization. + ExprKind::Struct(qpath, _, _) => { + let res = cx.typeck_results().qpath_res(qpath, expr.hir_id); + if let Some((_, v_def)) = adt_and_variant_of_res(cx, res) { + let rustc_ty::Adt(_, generic_args) = cx.typeck_results().expr_ty_adjusted(expr).kind() else { + // This should never happen, but when it does, not linting is the better option. + return true; + }; + v_def + .fields + .iter() + .any(|field| field.ty(cx.tcx, generic_args).has_type_flags(TypeFlags::HAS_TY_PARAM)) + } else { + false + } + }, + // Function results, including the final line of a block or a `return` expression. + ExprKind::Block( + &Block { + expr: Some(ret_expr), .. + }, + _, + ) + | ExprKind::Ret(Some(ret_expr)) => expr_requires_coercion(cx, ret_expr), + + // ===== Coercion-propagation expressions ===== + ExprKind::Array(elems) | ExprKind::Tup(elems) => elems.iter().any(|elem| expr_requires_coercion(cx, elem)), + // Array but with repeating syntax. + ExprKind::Repeat(rep_elem, _) => expr_requires_coercion(cx, rep_elem), + // Others that may contain coercion sites. + ExprKind::If(_, then, maybe_else) => { + expr_requires_coercion(cx, then) || maybe_else.is_some_and(|e| expr_requires_coercion(cx, e)) + }, + ExprKind::Match(_, arms, _) => arms + .iter() + .map(|arm| arm.body) + .any(|body| expr_requires_coercion(cx, body)), + _ => false, + } +} + +/// Returns `true` if `expr` designates a mutable static, a mutable local binding, or an expression +/// that can be owned. +pub fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + if let Some(hir_id) = path_to_local(expr) + && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) + { + matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..)) + } else if let ExprKind::Path(p) = &expr.kind + && let Some(mutability) = cx + .qpath_res(p, expr.hir_id) + .opt_def_id() + .and_then(|id| cx.tcx.static_mutability(id)) + { + mutability == Mutability::Mut + } else if let ExprKind::Field(parent, _) = expr.kind { + is_mutable(cx, parent) + } else { + true + } +} diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 9ce0fd8318f1d..1a457bc7f2141 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -1,6 +1,6 @@ #![allow(clippy::similar_names)] // `expr` and `expn` -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use crate::get_unique_attr; use crate::visitors::{Descend, for_each_expr_without_closures}; @@ -8,7 +8,6 @@ use crate::visitors::{Descend, for_each_expr_without_closures}; use arrayvec::ArrayVec; use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::OnceLock; use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_span::def_id::DefId; @@ -30,6 +29,8 @@ const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[ sym::print_macro, sym::println_macro, sym::std_panic_macro, + sym::todo_macro, + sym::unimplemented_macro, sym::write_macro, sym::writeln_macro, ]; diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index 605764cef89fe..db07b6404169e 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -6,7 +6,7 @@ use rustc_index::bit_set::DenseBitSet; use rustc_lint::LateContext; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{self, Mutability}; -use rustc_middle::ty::visit::TypeVisitor; +use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_dataflow::impls::MaybeStorageLive; use rustc_mir_dataflow::{Analysis, ResultsCursor}; diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 24f73b9df2684..0316de172de7f 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -1,11 +1,14 @@ +use rustc_ast::Attribute; use rustc_ast::attr::AttributeExt; use rustc_attr_parsing::{RustcVersion, parse_version}; +use rustc_lint::LateContext; use rustc_session::Session; use rustc_span::{Symbol, sym}; use serde::Deserialize; -use smallvec::{SmallVec, smallvec}; -use std::fmt; +use smallvec::SmallVec; +use std::iter::once; +use std::sync::atomic::{AtomicBool, Ordering}; macro_rules! msrv_aliases { ($($major:literal,$minor:literal,$patch:literal { @@ -19,6 +22,8 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { + 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT } + 1,85,0 { UINT_FLOAT_MIDPOINT } 1,84,0 { CONST_OPTION_AS_SLICE } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } 1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP } @@ -27,7 +32,7 @@ msrv_aliases! { 1,77,0 { C_STR_LITERALS } 1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT } 1,75,0 { OPTION_AS_SLICE } - 1,74,0 { REPR_RUST } + 1,74,0 { REPR_RUST, IO_ERROR_OTHER } 1,73,0 { MANUAL_DIV_CEIL } 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE } 1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN } @@ -37,10 +42,11 @@ msrv_aliases! { 1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN } 1,59,0 { THREAD_LOCAL_CONST_INIT } 1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF } + 1,57,0 { MAP_WHILE } 1,56,0 { CONST_FN_UNION } 1,55,0 { SEEK_REWIND } 1,54,0 { INTO_KEYS } - 1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } + 1,53,0 { OR_PATTERNS, INTEGER_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR } 1,52,0 { STR_SPLIT_ONCE, REM_EUCLID_CONST } 1,51,0 { BORROW_AS_PTR, SEEK_FROM_CURRENT, UNSIGNED_ABS } 1,50,0 { BOOL_THEN, CLAMP, SLICE_FILL } @@ -57,6 +63,7 @@ msrv_aliases! { 1,35,0 { OPTION_COPIED, RANGE_CONTAINS } 1,34,0 { TRY_FROM } 1,33,0 { UNDERSCORE_IMPORTS } + 1,31,0 { OPTION_REPLACE } 1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES } 1,29,0 { ITER_FLATTEN } 1,28,0 { FROM_BOOL, REPEAT_WITH } @@ -69,21 +76,15 @@ msrv_aliases! { 1,15,0 { MAYBE_BOUND_IN_WHERE } } -/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]` -#[derive(Debug, Clone)] -pub struct Msrv { - stack: SmallVec<[RustcVersion; 2]>, -} +/// `#[clippy::msrv]` attributes are rarely used outside of Clippy's test suite, as a basic +/// optimization we can skip traversing the HIR in [`Msrv::meets`] if we never saw an MSRV attribute +/// during the early lint passes +static SEEN_MSRV_ATTR: AtomicBool = AtomicBool::new(false); -impl fmt::Display for Msrv { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(msrv) = self.current() { - write!(f, "{msrv}") - } else { - f.write_str("1.0.0") - } - } -} +/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]` in late +/// lint passes, use [`MsrvStack`] for early passes +#[derive(Copy, Clone, Debug, Default)] +pub struct Msrv(Option); impl<'de> Deserialize<'de> for Msrv { fn deserialize(deserializer: D) -> Result @@ -92,14 +93,36 @@ impl<'de> Deserialize<'de> for Msrv { { let v = String::deserialize(deserializer)?; parse_version(Symbol::intern(&v)) - .map(|v| Msrv { stack: smallvec![v] }) + .map(|v| Self(Some(v))) .ok_or_else(|| serde::de::Error::custom("not a valid Rust version")) } } impl Msrv { - pub fn empty() -> Msrv { - Msrv { stack: SmallVec::new() } + /// Returns the MSRV at the current node + /// + /// If the crate being linted uses an `#[clippy::msrv]` attribute this will search the parent + /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations + pub fn current(self, cx: &LateContext<'_>) -> Option { + if SEEN_MSRV_ATTR.load(Ordering::Relaxed) { + let start = cx.last_node_with_lint_attrs; + if let Some(msrv_attr) = once(start) + .chain(cx.tcx.hir_parent_id_iter(start)) + .find_map(|id| parse_attrs(cx.tcx.sess, cx.tcx.hir_attrs(id))) + { + return Some(msrv_attr); + } + } + + self.0 + } + + /// Checks if a required version from [this module](self) is met at the current node + /// + /// If the crate being linted uses an `#[clippy::msrv]` attribute this will search the parent + /// nodes for that attribute, prefer to run this check after cheaper pattern matching operations + pub fn meets(self, cx: &LateContext<'_>, required: RustcVersion) -> bool { + self.current(cx).is_none_or(|msrv| msrv >= required) } pub fn read_cargo(&mut self, sess: &Session) { @@ -107,8 +130,8 @@ impl Msrv { .ok() .and_then(|v| parse_version(Symbol::intern(&v))); - match (self.current(), cargo_msrv) { - (None, Some(cargo_msrv)) => self.stack = smallvec![cargo_msrv], + match (self.0, cargo_msrv) { + (None, Some(cargo_msrv)) => self.0 = Some(cargo_msrv), (Some(clippy_msrv), Some(cargo_msrv)) => { if clippy_msrv != cargo_msrv { sess.dcx().warn(format!( @@ -119,6 +142,21 @@ impl Msrv { _ => {}, } } +} + +/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]` in early +/// lint passes, use [`Msrv`] for late passes +#[derive(Debug, Clone)] +pub struct MsrvStack { + stack: SmallVec<[RustcVersion; 2]>, +} + +impl MsrvStack { + pub fn new(initial: Msrv) -> Self { + Self { + stack: SmallVec::from_iter(initial.0), + } + } pub fn current(&self) -> Option { self.stack.last().copied() @@ -128,42 +166,43 @@ impl Msrv { self.current().is_none_or(|msrv| msrv >= required) } - fn parse_attr(sess: &Session, attrs: &[impl AttributeExt]) -> Option { - let sym_msrv = Symbol::intern("msrv"); - let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); + pub fn check_attributes(&mut self, sess: &Session, attrs: &[Attribute]) { + if let Some(version) = parse_attrs(sess, attrs) { + SEEN_MSRV_ATTR.store(true, Ordering::Relaxed); + self.stack.push(version); + } + } - if let Some(msrv_attr) = msrv_attrs.next() { - if let Some(duplicate) = msrv_attrs.next_back() { - sess.dcx() - .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") - .with_span_note(msrv_attr.span(), "first definition found here") - .emit(); - } + pub fn check_attributes_post(&mut self, sess: &Session, attrs: &[Attribute]) { + if parse_attrs(sess, attrs).is_some() { + self.stack.pop(); + } + } +} - if let Some(msrv) = msrv_attr.value_str() { - if let Some(version) = parse_version(msrv) { - return Some(version); - } +fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option { + let sym_msrv = Symbol::intern("msrv"); + let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv])); - sess.dcx() - .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version")); - } else { - sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute"); - } + if let Some(msrv_attr) = msrv_attrs.next() { + if let Some(duplicate) = msrv_attrs.next_back() { + sess.dcx() + .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") + .with_span_note(msrv_attr.span(), "first definition found here") + .emit(); } - None - } + if let Some(msrv) = msrv_attr.value_str() { + if let Some(version) = parse_version(msrv) { + return Some(version); + } - pub fn check_attributes(&mut self, sess: &Session, attrs: &[impl AttributeExt]) { - if let Some(version) = Self::parse_attr(sess, attrs) { - self.stack.push(version); + sess.dcx() + .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version")); + } else { + sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute"); } } - pub fn check_attributes_post(&mut self, sess: &Session, attrs: &[impl AttributeExt]) { - if Self::parse_attr(sess, attrs).is_some() { - self.stack.pop(); - } - } + None } diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index f15fffc09e8d9..51d06ad9b1aa5 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -19,7 +19,6 @@ pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"]; pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"]; pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"]; pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"]; -pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"]; pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"]; pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"]; pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"]; @@ -28,16 +27,12 @@ pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"]; pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"]; // Paths in `core`/`alloc`/`std`. This should be avoided and cleaned up by adding diagnostic items. -pub const ABORT: [&str; 3] = ["std", "process", "abort"]; -pub const CHILD: [&str; 3] = ["std", "process", "Child"]; -pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"]; -pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"]; -pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"]; pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "", "is_ascii"]; -pub const STDIN: [&str; 4] = ["std", "io", "stdio", "Stdin"]; +pub const IO_ERROR_NEW: [&str; 5] = ["std", "io", "error", "Error", "new"]; +pub const IO_ERRORKIND_OTHER: [&str; 5] = ["std", "io", "error", "ErrorKind", "Other"]; // Paths in clippy itself -pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"]; +pub const MSRV_STACK: [&str; 3] = ["clippy_utils", "msrvs", "MsrvStack"]; // Paths in external crates #[expect(clippy::invalid_paths)] // internal lints do not know about all external crates diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index c7890f33f27ee..8e6f4d4a317eb 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::Obligation; +use rustc_lint::LateContext; use rustc_middle::mir::{ Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, @@ -25,16 +26,16 @@ use std::borrow::Cow; type McfResult = Result<(), (Span, Cow<'static, str>)>; -pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) -> McfResult { +pub fn is_min_const_fn<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, msrv: Msrv) -> McfResult { let def_id = body.source.def_id(); for local in &body.local_decls { - check_ty(tcx, local.ty, local.source_info.span, msrv)?; + check_ty(cx, local.ty, local.source_info.span, msrv)?; } // impl trait is gone in MIR, so check the return type manually check_ty( - tcx, - tcx.fn_sig(def_id).instantiate_identity().output().skip_binder(), + cx, + cx.tcx.fn_sig(def_id).instantiate_identity().output().skip_binder(), body.local_decls.iter().next().unwrap().source_info.span, msrv, )?; @@ -43,16 +44,16 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv) // Cleanup blocks are ignored entirely by const eval, so we can too: // https://github.com/rust-lang/rust/blob/1dea922ea6e74f99a0e97de5cdb8174e4dea0444/compiler/rustc_const_eval/src/transform/check_consts/check.rs#L382 if !bb.is_cleanup { - check_terminator(tcx, body, bb.terminator(), msrv)?; + check_terminator(cx, body, bb.terminator(), msrv)?; for stmt in &bb.statements { - check_statement(tcx, body, def_id, stmt, msrv)?; + check_statement(cx, body, def_id, stmt, msrv)?; } } } Ok(()) } -fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, msrv: &Msrv) -> McfResult { +fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span, msrv: Msrv) -> McfResult { for arg in ty.walk() { let ty = match arg.unpack() { GenericArgKind::Type(ty) => ty, @@ -63,7 +64,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, msrv: &Msrv) -> M }; match ty.kind() { - ty::Ref(_, _, hir::Mutability::Mut) if !msrv.meets(msrvs::CONST_MUT_REFS) => { + ty::Ref(_, _, hir::Mutability::Mut) if !msrv.meets(cx, msrvs::CONST_MUT_REFS) => { return Err((span, "mutable references in const fn are unstable".into())); }, ty::Alias(ty::Opaque, ..) => return Err((span, "`impl Trait` in const fn is unstable".into())), @@ -82,7 +83,7 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, msrv: &Msrv) -> M )); }, ty::ExistentialPredicate::Trait(trait_ref) => { - if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { + if Some(trait_ref.def_id) != cx.tcx.lang_items().sized_trait() { return Err(( span, "trait bounds other than `Sized` \ @@ -101,19 +102,19 @@ fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, msrv: &Msrv) -> M } fn check_rvalue<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &LateContext<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span, - msrv: &Msrv, + msrv: Msrv, ) -> McfResult { match rvalue { Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => { - check_place(tcx, *place, span, body, msrv) + check_place(cx, *place, span, body, msrv) }, - Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv), + Rvalue::CopyForDeref(place) => check_place(cx, *place, span, body, msrv), Rvalue::Repeat(operand, _) | Rvalue::Use(operand) | Rvalue::WrapUnsafeBinder(operand, _) @@ -128,7 +129,7 @@ fn check_rvalue<'tcx>( | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer, _), operand, _, - ) => check_operand(tcx, operand, span, body, msrv), + ) => check_operand(cx, operand, span, body, msrv), Rvalue::Cast( CastKind::PointerCoercion( PointerCoercion::UnsafeFnPointer @@ -144,9 +145,11 @@ fn check_rvalue<'tcx>( // We cannot allow this for now. return Err((span, "unsizing casts are only allowed for references right now".into())); }; - let unsized_ty = tcx.struct_tail_for_codegen(pointee_ty, ty::TypingEnv::post_analysis(tcx, def_id)); + let unsized_ty = cx + .tcx + .struct_tail_for_codegen(pointee_ty, ty::TypingEnv::post_analysis(cx.tcx, def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind() { - check_operand(tcx, op, span, body, msrv)?; + check_operand(cx, op, span, body, msrv)?; // Casting/coercing things to slices is fine. Ok(()) } else { @@ -167,9 +170,9 @@ fn check_rvalue<'tcx>( )), // binops are fine on integers Rvalue::BinaryOp(_, box (lhs, rhs)) => { - check_operand(tcx, lhs, span, body, msrv)?; - check_operand(tcx, rhs, span, body, msrv)?; - let ty = lhs.ty(body, tcx); + check_operand(cx, lhs, span, body, msrv)?; + check_operand(cx, rhs, span, body, msrv)?; + let ty = lhs.ty(body, cx.tcx); if ty.is_integral() || ty.is_bool() || ty.is_char() { Ok(()) } else { @@ -185,16 +188,16 @@ fn check_rvalue<'tcx>( ) | Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { - let ty = operand.ty(body, tcx); + let ty = operand.ty(body, cx.tcx); if ty.is_integral() || ty.is_bool() { - check_operand(tcx, operand, span, body, msrv) + check_operand(cx, operand, span, body, msrv) } else { Err((span, "only int and `bool` operations are stable in const fn".into())) } }, Rvalue::Aggregate(_, operands) => { for operand in operands { - check_operand(tcx, operand, span, body, msrv)?; + check_operand(cx, operand, span, body, msrv)?; } Ok(()) }, @@ -202,33 +205,33 @@ fn check_rvalue<'tcx>( } fn check_statement<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &LateContext<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>, - msrv: &Msrv, + msrv: Msrv, ) -> McfResult { let span = statement.source_info.span; match &statement.kind { StatementKind::Assign(box (place, rval)) => { - check_place(tcx, *place, span, body, msrv)?; - check_rvalue(tcx, body, def_id, rval, span, msrv) + check_place(cx, *place, span, body, msrv)?; + check_rvalue(cx, body, def_id, rval, span, msrv) }, - StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body, msrv), + StatementKind::FakeRead(box (_, place)) => check_place(cx, *place, span, body, msrv), // just an assignment StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => { - check_place(tcx, **place, span, body, msrv) + check_place(cx, **place, span, body, msrv) }, - StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body, msrv), + StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(cx, op, span, body, msrv), StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping( rustc_middle::mir::CopyNonOverlapping { dst, src, count }, )) => { - check_operand(tcx, dst, span, body, msrv)?; - check_operand(tcx, src, span, body, msrv)?; - check_operand(tcx, count, span, body, msrv) + check_operand(cx, dst, span, body, msrv)?; + check_operand(cx, src, span, body, msrv)?; + check_operand(cx, count, span, body, msrv) }, // These are all NOPs StatementKind::StorageLive(_) @@ -244,16 +247,16 @@ fn check_statement<'tcx>( } fn check_operand<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &LateContext<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>, - msrv: &Msrv, + msrv: Msrv, ) -> McfResult { match operand { Operand::Move(place) => { if !place.projection.as_ref().is_empty() - && !is_ty_const_destruct(tcx, place.ty(&body.local_decls, tcx).ty, body) + && !is_ty_const_destruct(cx.tcx, place.ty(&body.local_decls, cx.tcx).ty, body) { return Err(( span, @@ -261,29 +264,35 @@ fn check_operand<'tcx>( )); } - check_place(tcx, *place, span, body, msrv) + check_place(cx, *place, span, body, msrv) }, - Operand::Copy(place) => check_place(tcx, *place, span, body, msrv), - Operand::Constant(c) => match c.check_static_ptr(tcx) { + Operand::Copy(place) => check_place(cx, *place, span, body, msrv), + Operand::Constant(c) => match c.check_static_ptr(cx.tcx) { Some(_) => Err((span, "cannot access `static` items in const fn".into())), None => Ok(()), }, } } -fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>, msrv: &Msrv) -> McfResult { +fn check_place<'tcx>( + cx: &LateContext<'tcx>, + place: Place<'tcx>, + span: Span, + body: &Body<'tcx>, + msrv: Msrv, +) -> McfResult { for (base, elem) in place.as_ref().iter_projections() { match elem { ProjectionElem::Field(..) => { - if base.ty(body, tcx).ty.is_union() && !msrv.meets(msrvs::CONST_FN_UNION) { + if base.ty(body, cx.tcx).ty.is_union() && !msrv.meets(cx, msrvs::CONST_FN_UNION) { return Err((span, "accessing union fields is unstable".into())); } }, - ProjectionElem::Deref => match base.ty(body, tcx).ty.kind() { + ProjectionElem::Deref => match base.ty(body, cx.tcx).ty.kind() { ty::RawPtr(_, hir::Mutability::Mut) => { return Err((span, "dereferencing raw mut pointer in const fn is unstable".into())); }, - ty::RawPtr(_, hir::Mutability::Not) if !msrv.meets(msrvs::CONST_RAW_PTR_DEREF) => { + ty::RawPtr(_, hir::Mutability::Not) if !msrv.meets(cx, msrvs::CONST_RAW_PTR_DEREF) => { return Err((span, "dereferencing raw const pointer in const fn is unstable".into())); }, _ => (), @@ -302,10 +311,10 @@ fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &B } fn check_terminator<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &LateContext<'tcx>, body: &Body<'tcx>, terminator: &Terminator<'tcx>, - msrv: &Msrv, + msrv: Msrv, ) -> McfResult { let span = terminator.source_info.span; match &terminator.kind { @@ -317,7 +326,7 @@ fn check_terminator<'tcx>( | TerminatorKind::UnwindTerminate(_) | TerminatorKind::Unreachable => Ok(()), TerminatorKind::Drop { place, .. } => { - if !is_ty_const_destruct(tcx, place.ty(&body.local_decls, tcx).ty, body) { + if !is_ty_const_destruct(cx.tcx, place.ty(&body.local_decls, cx.tcx).ty, body) { return Err(( span, "cannot drop locals with a non constant destructor in const fn".into(), @@ -325,7 +334,7 @@ fn check_terminator<'tcx>( } Ok(()) }, - TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body, msrv), + TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(cx, discr, span, body, msrv), TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => { Err((span, "const fn coroutines are unstable".into())) }, @@ -339,9 +348,9 @@ fn check_terminator<'tcx>( fn_span: _, } | TerminatorKind::TailCall { func, args, fn_span: _ } => { - let fn_ty = func.ty(body, tcx); + let fn_ty = func.ty(body, cx.tcx); if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { - if !is_stable_const_fn(tcx, fn_def_id, msrv) { + if !is_stable_const_fn(cx, fn_def_id, msrv) { return Err(( span, format!( @@ -356,17 +365,17 @@ fn check_terminator<'tcx>( // within const fns. `transmute` is allowed in all other const contexts. // This won't really scale to more intrinsics or functions. Let's allow const // transmutes in const fn before we add more hacks to this. - if tcx.is_intrinsic(fn_def_id, sym::transmute) { + if cx.tcx.is_intrinsic(fn_def_id, sym::transmute) { return Err(( span, "can only call `transmute` from const items, not `const fn`".into(), )); } - check_operand(tcx, func, span, body, msrv)?; + check_operand(cx, func, span, body, msrv)?; for arg in args { - check_operand(tcx, &arg.node, span, body, msrv)?; + check_operand(cx, &arg.node, span, body, msrv)?; } Ok(()) } else { @@ -379,14 +388,14 @@ fn check_terminator<'tcx>( msg: _, target: _, unwind: _, - } => check_operand(tcx, cond, span, body, msrv), + } => check_operand(cx, cond, span, body, msrv), TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())), } } -fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { - tcx.is_const_fn(def_id) - && tcx.lookup_const_stability(def_id).is_none_or(|const_stab| { +fn is_stable_const_fn(cx: &LateContext<'_>, def_id: DefId, msrv: Msrv) -> bool { + cx.tcx.is_const_fn(def_id) + && cx.tcx.lookup_const_stability(def_id).is_none_or(|const_stab| { if let rustc_attr_parsing::StabilityLevel::Stable { since, .. } = const_stab.level { // Checking MSRV is manually necessary because `rustc` has no such concept. This entire // function could be removed if `rustc` provided a MSRV-aware version of `is_stable_const_fn`. @@ -398,10 +407,10 @@ fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool { StableSince::Err => return false, }; - msrv.meets(const_stab_rust_version) + msrv.meets(cx, const_stab_rust_version) } else { // Unstable const fn, check if the feature is enabled. - tcx.features().enabled(const_stab.feature) && msrv.current().is_none() + cx.tcx.features().enabled(const_stab.feature) && msrv.current(cx).is_none() } }) } diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index c6a038f7e0cf3..80066e9702d34 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -294,7 +294,7 @@ impl SourceFileRange { } } -/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. +/// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block` with no label. pub fn expr_block( sess: &impl HasSession, expr: &Expr<'_>, @@ -305,10 +305,10 @@ pub fn expr_block( ) -> String { let (code, from_macro) = snippet_block_with_context(sess, expr.span, outer, default, indent_relative_to, app); if !from_macro - && let ExprKind::Block(block, _) = expr.kind + && let ExprKind::Block(block, None) = expr.kind && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) { - format!("{code}") + code } else { // FIXME: add extra indent for the unsafe blocks: // original code: unsafe { ... } @@ -421,11 +421,10 @@ pub fn position_before_rarrow(s: &str) -> Option { } /// Reindent a multiline string with possibility of ignoring the first line. -#[expect(clippy::needless_pass_by_value)] -pub fn reindent_multiline(s: Cow<'_, str>, ignore_first: bool, indent: Option) -> Cow<'_, str> { - let s_space = reindent_multiline_inner(&s, ignore_first, indent, ' '); +pub fn reindent_multiline(s: &str, ignore_first: bool, indent: Option) -> String { + let s_space = reindent_multiline_inner(s, ignore_first, indent, ' '); let s_tab = reindent_multiline_inner(&s_space, ignore_first, indent, '\t'); - reindent_multiline_inner(&s_tab, ignore_first, indent, ' ').into() + reindent_multiline_inner(&s_tab, ignore_first, indent, ' ') } fn reindent_multiline_inner(s: &str, ignore_first: bool, indent: Option, ch: char) -> String { @@ -553,42 +552,37 @@ pub fn snippet_opt(sess: &impl HasSession, span: Span) -> Option { /// } // aligned with `if` /// ``` /// Note that the first line of the snippet always has 0 indentation. -pub fn snippet_block<'a>( - sess: &impl HasSession, - span: Span, - default: &'a str, - indent_relative_to: Option, -) -> Cow<'a, str> { +pub fn snippet_block(sess: &impl HasSession, span: Span, default: &str, indent_relative_to: Option) -> String { let snip = snippet(sess, span, default); let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); - reindent_multiline(snip, true, indent) + reindent_multiline(&snip, true, indent) } /// Same as `snippet_block`, but adapts the applicability level by the rules of /// `snippet_with_applicability`. -pub fn snippet_block_with_applicability<'a>( +pub fn snippet_block_with_applicability( sess: &impl HasSession, span: Span, - default: &'a str, + default: &str, indent_relative_to: Option, applicability: &mut Applicability, -) -> Cow<'a, str> { +) -> String { let snip = snippet_with_applicability(sess, span, default, applicability); let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); - reindent_multiline(snip, true, indent) + reindent_multiline(&snip, true, indent) } -pub fn snippet_block_with_context<'a>( +pub fn snippet_block_with_context( sess: &impl HasSession, span: Span, outer: SyntaxContext, - default: &'a str, + default: &str, indent_relative_to: Option, app: &mut Applicability, -) -> (Cow<'a, str>, bool) { +) -> (String, bool) { let (snip, from_macro) = snippet_with_context(sess, span, outer, default, app); let indent = indent_relative_to.and_then(|s| indent_of(sess, s)); - (reindent_multiline(snip, true, indent), from_macro) + (reindent_multiline(&snip, true, indent), from_macro) } /// Same as `snippet_with_applicability`, but first walks the span up to the given context. @@ -749,11 +743,11 @@ mod test { #[test] fn test_reindent_multiline_single_line() { - assert_eq!("", reindent_multiline("".into(), false, None)); - assert_eq!("...", reindent_multiline("...".into(), false, None)); - assert_eq!("...", reindent_multiline(" ...".into(), false, None)); - assert_eq!("...", reindent_multiline("\t...".into(), false, None)); - assert_eq!("...", reindent_multiline("\t\t...".into(), false, None)); + assert_eq!("", reindent_multiline("", false, None)); + assert_eq!("...", reindent_multiline("...", false, None)); + assert_eq!("...", reindent_multiline(" ...", false, None)); + assert_eq!("...", reindent_multiline("\t...", false, None)); + assert_eq!("...", reindent_multiline("\t\t...", false, None)); } #[test] @@ -768,7 +762,7 @@ mod test { y } else { z - }".into(), false, None)); + }", false, None)); assert_eq!("\ if x { \ty @@ -778,7 +772,7 @@ mod test { \ty } else { \tz - }".into(), false, None)); + }", false, None)); } #[test] @@ -795,7 +789,7 @@ mod test { } else { z - }".into(), false, None)); + }", false, None)); } #[test] @@ -811,6 +805,6 @@ mod test { y } else { z - }".into(), true, Some(8))); + }", true, Some(8))); } } diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index d5e0e2e3436e2..9cc66593dcc3f 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -5,8 +5,7 @@ use crate::source::{snippet, snippet_opt, snippet_with_applicability, snippet_wi use crate::ty::expr_sig; use crate::{get_parent_expr_for_hir, higher}; use rustc_ast::util::parser::AssocOp; -use rustc_ast::{ast, token}; -use rustc_ast_pretty::pprust::token_kind_to_string; +use rustc_ast::ast; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind}; @@ -114,10 +113,7 @@ impl<'a> Sugg<'a> { /// function variants of `Sugg`, since these use different snippet functions. fn hir_from_snippet(expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>) -> Self { if let Some(range) = higher::Range::hir(expr) { - let op = match range.limits { - ast::RangeLimits::HalfOpen => AssocOp::DotDot, - ast::RangeLimits::Closed => AssocOp::DotDotEq, - }; + let op = AssocOp::Range(range.limits); let start = range.start.map_or("".into(), |expr| get_snippet(expr.span)); let end = range.end.map_or("".into(), |expr| get_snippet(expr.span)); @@ -151,6 +147,7 @@ impl<'a> Sugg<'a> { | ExprKind::Become(..) | ExprKind::Struct(..) | ExprKind::Tup(..) + | ExprKind::Use(..) | ExprKind::Err(_) | ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(get_snippet(expr.span)), ExprKind::DropTemps(inner) => Self::hir_from_snippet(inner, get_snippet), @@ -158,16 +155,16 @@ impl<'a> Sugg<'a> { Sugg::BinOp(AssocOp::Assign, get_snippet(lhs.span), get_snippet(rhs.span)) }, ExprKind::AssignOp(op, lhs, rhs) => { - Sugg::BinOp(hirbinop2assignop(op), get_snippet(lhs.span), get_snippet(rhs.span)) + Sugg::BinOp(AssocOp::AssignOp(op.node), get_snippet(lhs.span), get_snippet(rhs.span)) }, ExprKind::Binary(op, lhs, rhs) => Sugg::BinOp( - AssocOp::from_ast_binop(op.node), + AssocOp::Binary(op.node), get_snippet(lhs.span), get_snippet(rhs.span), ), ExprKind::Cast(lhs, ty) | //FIXME(chenyukang), remove this after type ascription is removed from AST - ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), + ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::Cast, get_snippet(lhs.span), get_snippet(ty.span)), } } @@ -179,8 +176,6 @@ impl<'a> Sugg<'a> { ctxt: SyntaxContext, app: &mut Applicability, ) -> Self { - use rustc_ast::ast::RangeLimits; - let mut snippet = |span: Span| snippet_with_context(cx, span, ctxt, default, app).0; match expr.kind { @@ -223,19 +218,15 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Try(..) | ast::ExprKind::TryBlock(..) | ast::ExprKind::Tup(..) + | ast::ExprKind::Use(..) | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) | ast::ExprKind::Err(_) | ast::ExprKind::Dummy | ast::ExprKind::UnsafeBinderCast(..) => Sugg::NonParen(snippet(expr.span)), - ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( - AssocOp::DotDot, - lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), - rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), - ), - ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::Closed) => Sugg::BinOp( - AssocOp::DotDotEq, + ast::ExprKind::Range(ref lhs, ref rhs, limits) => Sugg::BinOp( + AssocOp::Range(limits), lhs.as_ref().map_or("".into(), |lhs| snippet(lhs.span)), rhs.as_ref().map_or("".into(), |rhs| snippet(rhs.span)), ), @@ -245,19 +236,19 @@ impl<'a> Sugg<'a> { snippet(rhs.span), ), ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => Sugg::BinOp( - astbinop2assignop(op), + AssocOp::AssignOp(op.node), snippet(lhs.span), snippet(rhs.span), ), ast::ExprKind::Binary(op, ref lhs, ref rhs) => Sugg::BinOp( - AssocOp::from_ast_binop(op.node), + AssocOp::Binary(op.node), snippet(lhs.span), snippet(rhs.span), ), ast::ExprKind::Cast(ref lhs, ref ty) | //FIXME(chenyukang), remove this after type ascription is removed from AST ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( - AssocOp::As, + AssocOp::Cast, snippet(lhs.span), snippet(ty.span), ), @@ -276,7 +267,7 @@ impl<'a> Sugg<'a> { /// Convenience method to create the ` as ` suggestion. pub fn as_ty(self, rhs: R) -> Sugg<'static> { - make_assoc(AssocOp::As, &self, &Sugg::NonParen(rhs.to_string().into())) + make_assoc(AssocOp::Cast, &self, &Sugg::NonParen(rhs.to_string().into())) } /// Convenience method to create the `&` suggestion. @@ -327,11 +318,8 @@ impl<'a> Sugg<'a> { /// Convenience method to create the `..` or `...` /// suggestion. - pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> { - match limit { - ast::RangeLimits::HalfOpen => make_assoc(AssocOp::DotDot, &self, end), - ast::RangeLimits::Closed => make_assoc(AssocOp::DotDotEq, &self, end), - } + pub fn range(self, end: &Self, limits: ast::RangeLimits) -> Sugg<'static> { + make_assoc(AssocOp::Range(limits), &self, end) } /// Adds parentheses to any expression that might need them. Suitable to the @@ -367,33 +355,11 @@ impl<'a> Sugg<'a> { /// Generates a string from the operator and both sides. fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { match op { - AssocOp::Add - | AssocOp::Subtract - | AssocOp::Multiply - | AssocOp::Divide - | AssocOp::Modulus - | AssocOp::LAnd - | AssocOp::LOr - | AssocOp::BitXor - | AssocOp::BitAnd - | AssocOp::BitOr - | AssocOp::ShiftLeft - | AssocOp::ShiftRight - | AssocOp::Equal - | AssocOp::Less - | AssocOp::LessEqual - | AssocOp::NotEqual - | AssocOp::Greater - | AssocOp::GreaterEqual => { - format!("{lhs} {} {rhs}", op.to_ast_binop().expect("Those are AST ops").as_str()) - }, + AssocOp::Binary(op) => format!("{lhs} {} {rhs}", op.as_str()), AssocOp::Assign => format!("{lhs} = {rhs}"), - AssocOp::AssignOp(op) => { - format!("{lhs} {}= {rhs}", token_kind_to_string(&token::BinOp(op))) - }, - AssocOp::As => format!("{lhs} as {rhs}"), - AssocOp::DotDot => format!("{lhs}..{rhs}"), - AssocOp::DotDotEq => format!("{lhs}..={rhs}"), + AssocOp::AssignOp(op) => format!("{lhs} {}= {rhs}", op.as_str()), + AssocOp::Cast => format!("{lhs} as {rhs}"), + AssocOp::Range(limits) => format!("{lhs}{}{rhs}", limits.as_str()), } } @@ -468,7 +434,7 @@ impl Neg for Sugg<'_> { type Output = Sugg<'static>; fn neg(self) -> Sugg<'static> { match &self { - Self::BinOp(AssocOp::As, ..) => Sugg::MaybeParen(format!("-({self})").into()), + Self::BinOp(AssocOp::Cast, ..) => Sugg::MaybeParen(format!("-({self})").into()), _ => make_unop("-", self), } } @@ -477,16 +443,17 @@ impl Neg for Sugg<'_> { impl<'a> Not for Sugg<'a> { type Output = Sugg<'a>; fn not(self) -> Sugg<'a> { - use AssocOp::{Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual}; + use AssocOp::Binary; + use ast::BinOpKind::{Eq, Gt, Ge, Lt, Le, Ne}; if let Sugg::BinOp(op, lhs, rhs) = self { let to_op = match op { - Equal => NotEqual, - NotEqual => Equal, - Less => GreaterEqual, - GreaterEqual => Less, - Greater => LessEqual, - LessEqual => Greater, + Binary(Eq) => Binary(Ne), + Binary(Ne) => Binary(Eq), + Binary(Lt) => Binary(Ge), + Binary(Ge) => Binary(Lt), + Binary(Gt) => Binary(Le), + Binary(Le) => Binary(Gt), _ => return make_unop("!", Sugg::BinOp(op, lhs, rhs)), }; Sugg::BinOp(to_op, lhs, rhs) @@ -538,7 +505,7 @@ pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> { pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> { /// Returns `true` if the operator is a shift operator `<<` or `>>`. fn is_shift(op: AssocOp) -> bool { - matches!(op, AssocOp::ShiftLeft | AssocOp::ShiftRight) + matches!(op, AssocOp::Binary(ast::BinOpKind::Shl | ast::BinOpKind::Shr)) } /// Returns `true` if the operator is an arithmetic operator @@ -546,7 +513,13 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> fn is_arith(op: AssocOp) -> bool { matches!( op, - AssocOp::Add | AssocOp::Subtract | AssocOp::Multiply | AssocOp::Divide | AssocOp::Modulus + AssocOp::Binary( + ast::BinOpKind::Add + | ast::BinOpKind::Sub + | ast::BinOpKind::Mul + | ast::BinOpKind::Div + | ast::BinOpKind::Rem + ) ) } @@ -578,9 +551,9 @@ pub fn make_assoc(op: AssocOp, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> Sugg::BinOp(op, lhs.into(), rhs.into()) } -/// Convenience wrapper around `make_assoc` and `AssocOp::from_ast_binop`. +/// Convenience wrapper around `make_assoc` and `AssocOp::Binary`. pub fn make_binop(op: ast::BinOpKind, lhs: &Sugg<'_>, rhs: &Sugg<'_>) -> Sugg<'static> { - make_assoc(AssocOp::from_ast_binop(op), lhs, rhs) + make_assoc(AssocOp::Binary(op), lhs, rhs) } #[derive(PartialEq, Eq, Clone, Copy)] @@ -605,69 +578,19 @@ enum Associativity { /// associative. #[must_use] fn associativity(op: AssocOp) -> Associativity { - use rustc_ast::util::parser::AssocOp::{ - Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd, - LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract, + use rustc_ast::util::parser::AssocOp::{Assign, AssignOp, Binary, Cast, Range}; + use ast::BinOpKind::{ + Add, BitAnd, BitOr, BitXor, Div, Eq, Gt, Ge, And, Or, Lt, Le, Rem, Mul, Ne, Shl, Shr, Sub, }; match op { Assign | AssignOp(_) => Associativity::Right, - Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As => Associativity::Both, - Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight - | Subtract => Associativity::Left, - DotDot | DotDotEq => Associativity::None, + Binary(Add | BitAnd | BitOr | BitXor | And | Or | Mul) | Cast => Associativity::Both, + Binary(Div | Eq | Gt | Ge | Lt | Le | Rem | Ne | Shl | Shr | Sub) => Associativity::Left, + Range(_) => Associativity::None, } } -/// Converts a `hir::BinOp` to the corresponding assigning binary operator. -fn hirbinop2assignop(op: hir::BinOp) -> AssocOp { - use rustc_ast::token::BinOpToken::{And, Caret, Minus, Or, Percent, Plus, Shl, Shr, Slash, Star}; - - AssocOp::AssignOp(match op.node { - hir::BinOpKind::Add => Plus, - hir::BinOpKind::BitAnd => And, - hir::BinOpKind::BitOr => Or, - hir::BinOpKind::BitXor => Caret, - hir::BinOpKind::Div => Slash, - hir::BinOpKind::Mul => Star, - hir::BinOpKind::Rem => Percent, - hir::BinOpKind::Shl => Shl, - hir::BinOpKind::Shr => Shr, - hir::BinOpKind::Sub => Minus, - - hir::BinOpKind::And - | hir::BinOpKind::Eq - | hir::BinOpKind::Ge - | hir::BinOpKind::Gt - | hir::BinOpKind::Le - | hir::BinOpKind::Lt - | hir::BinOpKind::Ne - | hir::BinOpKind::Or => panic!("This operator does not exist"), - }) -} - -/// Converts an `ast::BinOp` to the corresponding assigning binary operator. -fn astbinop2assignop(op: ast::BinOp) -> AssocOp { - use rustc_ast::ast::BinOpKind::{ - Add, And, BitAnd, BitOr, BitXor, Div, Eq, Ge, Gt, Le, Lt, Mul, Ne, Or, Rem, Shl, Shr, Sub, - }; - use rustc_ast::token::BinOpToken; - - AssocOp::AssignOp(match op.node { - Add => BinOpToken::Plus, - BitAnd => BinOpToken::And, - BitOr => BinOpToken::Or, - BitXor => BinOpToken::Caret, - Div => BinOpToken::Slash, - Mul => BinOpToken::Star, - Rem => BinOpToken::Percent, - Shl => BinOpToken::Shl, - Shr => BinOpToken::Shr, - Sub => BinOpToken::Minus, - And | Eq | Ge | Gt | Le | Lt | Ne | Or => panic!("This operator does not exist"), - }) -} - /// Returns the indentation before `span` if there are nothing but `[ \t]` /// before it on its line. fn indentation(cx: &T, span: Span) -> Option { @@ -914,6 +837,8 @@ impl<'tcx> DerefDelegate<'_, 'tcx> { impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) { if let PlaceBase::Local(id) = cmt.place.base { let map = self.cx.tcx.hir(); @@ -922,7 +847,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { let mut start_snip = snippet_with_applicability(self.cx, start_span, "..", &mut self.applicability); // identifier referring to the variable currently triggered (i.e.: `fp`) - let ident_str = map.name(id).to_string(); + let ident_str = self.cx.tcx.hir_name(id).to_string(); // full identifier that includes projection (i.e.: `fp.field`) let ident_str_with_proj = snippet(self.cx, span, "..").to_string(); @@ -951,7 +876,7 @@ impl<'tcx> Delegate<'tcx> for DerefDelegate<'_, 'tcx> { // item is used in a call // i.e.: `Call`: `|x| please(x)` or `MethodCall`: `|x| [1, 2, 3].contains(x)` ExprKind::Call(_, call_args) | ExprKind::MethodCall(_, _, call_args, _) => { - let expr = self.cx.tcx.hir().expect_expr(cmt.hir_id); + let expr = self.cx.tcx.hir_expect_expr(cmt.hir_id); let arg_ty_kind = self.cx.typeck_results().expr_ty(expr).kind(); if matches!(arg_ty_kind, ty::Ref(_, _, Mutability::Not)) { diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 8eef6a7f57edb..6fdf4c244f8d8 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -11,6 +11,7 @@ use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, FnDecl, LangItem, TyKind}; +use rustc_hir_analysis::lower_ty; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; @@ -36,6 +37,19 @@ use crate::{def_path_def_ids, match_def_path, path_res}; mod type_certainty; pub use type_certainty::expr_type_is_certain; +/// Lower a [`hir::Ty`] to a [`rustc_middle::ty::Ty`]. +pub fn ty_from_hir_ty<'tcx>(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { + cx.maybe_typeck_results() + .and_then(|results| { + if results.hir_owner == hir_ty.hir_id.owner { + results.node_type_opt(hir_ty.hir_id) + } else { + None + } + }) + .unwrap_or_else(|| lower_ty(cx.tcx, hir_ty)) +} + /// Checks if the given type implements copy. pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { cx.type_is_copy_modulo_regions(ty) @@ -351,20 +365,26 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// 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: ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) + is_normalizable_helper(cx, param_env, ty, 0, &mut FxHashMap::default()) } fn is_normalizable_helper<'tcx>( cx: &LateContext<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>, + depth: usize, cache: &mut FxHashMap, bool>, ) -> bool { if let Some(&cached_result) = cache.get(&ty) { return cached_result; } - // prevent recursive loops, false-negative is better than endless loop leading to stack overflow - cache.insert(ty, false); + if !cx.tcx.recursion_limit().value_within_limit(depth) { + return false; + } + // Prevent recursive loops by answering `true` to recursive requests with the same + // type. This will be adjusted when the outermost call analyzes all the type + // components. + cache.insert(ty, true); let infcx = cx.tcx.infer_ctxt().build(cx.typing_mode()); let cause = ObligationCause::dummy(); let result = if infcx.at(&cause, param_env).query_normalize(ty).is_ok() { @@ -373,11 +393,11 @@ fn is_normalizable_helper<'tcx>( variant .fields .iter() - .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), cache)) + .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, args), depth + 1, cache)) }), _ => ty.walk().all(|generic_arg| match generic_arg.unpack() { GenericArgKind::Type(inner_ty) if inner_ty != ty => { - is_normalizable_helper(cx, param_env, inner_ty, cache) + is_normalizable_helper(cx, param_env, inner_ty, depth + 1, cache) }, _ => true, // if inner_ty == ty, we've already checked it }), @@ -1227,6 +1247,10 @@ impl<'tcx> InteriorMut<'tcx> { .find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args))) } }, + ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { + Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain(cx, normalized_ty), + _ => None, + }, _ => None, }; diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 3bf518f7fe706..a079fd940c009 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -66,6 +66,8 @@ impl MutVarsDelegate { impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {} + fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if bk == ty::BorrowKind::Mutable { self.update(cmt); diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 2ac0efd7e392d..63dd00f2de0fb 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -648,6 +648,9 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( helper(typeck, true, arg, f)?; } }, + ExprKind::Use(expr, _) => { + helper(typeck, true, expr, f)?; + }, ExprKind::Index(borrowed, consumed, _) | ExprKind::Assign(borrowed, consumed, _) | ExprKind::AssignOp(_, borrowed, consumed) => { diff --git a/src/tools/clippy/lintcheck/src/input.rs b/src/tools/clippy/lintcheck/src/input.rs index 3383d50fa02c7..83eb0a577d6b9 100644 --- a/src/tools/clippy/lintcheck/src/input.rs +++ b/src/tools/clippy/lintcheck/src/input.rs @@ -288,11 +288,11 @@ impl CrateWithSource { // as a result of this filter. let dest_crate_root = PathBuf::from(LINTCHECK_SOURCES).join(name); if dest_crate_root.exists() { - println!("Deleting existing directory at {dest_crate_root:?}"); + println!("Deleting existing directory at `{}`", dest_crate_root.display()); fs::remove_dir_all(&dest_crate_root).unwrap(); } - println!("Copying {path:?} to {dest_crate_root:?}"); + println!("Copying `{}` to `{}`", path.display(), dest_crate_root.display()); for entry in WalkDir::new(path).into_iter().filter_entry(|e| !is_cache_dir(e)) { let entry = entry.unwrap(); diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index ab760287e83ae..a4931499c8028 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-02-06" +channel = "nightly-2025-02-27" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/rustc_tools_util/Cargo.toml b/src/tools/clippy/rustc_tools_util/Cargo.toml index cba0256394823..716b1ed61443b 100644 --- a/src/tools/clippy/rustc_tools_util/Cargo.toml +++ b/src/tools/clippy/rustc_tools_util/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "rustc_tools_util" -version = "0.4.0" +version = "0.4.2" description = "small helper to generate version information for git packages" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" license = "MIT OR Apache-2.0" keywords = ["rustc", "tool", "git", "version", "hash"] categories = ["development-tools"] -edition = "2024" +edition = "2021" # Keep this, for this crate's MSRV to stay low [dependencies] diff --git a/src/tools/clippy/rustc_tools_util/README.md b/src/tools/clippy/rustc_tools_util/README.md index 1b11dfe06191c..ff4ca6f830e6e 100644 --- a/src/tools/clippy/rustc_tools_util/README.md +++ b/src/tools/clippy/rustc_tools_util/README.md @@ -13,10 +13,10 @@ build = "build.rs" List rustc_tools_util as regular AND build dependency. ````toml [dependencies] -rustc_tools_util = "0.4.0" +rustc_tools_util = "0.4.2" [build-dependencies] -rustc_tools_util = "0.4.0" +rustc_tools_util = "0.4.2" ```` In `build.rs`, generate the data in your `main()` diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs index 16be02f4a40f4..423154a69fa0b 100644 --- a/src/tools/clippy/rustc_tools_util/src/lib.rs +++ b/src/tools/clippy/rustc_tools_util/src/lib.rs @@ -28,9 +28,8 @@ macro_rules! get_version_info { }}; } -/// This macro can be used in `build.rs` to automatically set the needed -/// environment values, namely `GIT_HASH`, `COMMIT_DATE` and -/// `RUSTC_RELEASE_CHANNEL` +/// This macro can be used in `build.rs` to automatically set the needed environment values, namely +/// `GIT_HASH`, `COMMIT_DATE` and `RUSTC_RELEASE_CHANNEL` #[macro_export] macro_rules! setup_version_info { () => {{ @@ -43,7 +42,11 @@ macro_rules! setup_version_info { "cargo:rustc-env=COMMIT_DATE={}", $crate::get_commit_date().unwrap_or_default() ); - println!("cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", $crate::get_channel()); + let compiler_version = $crate::get_compiler_version(); + println!( + "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", + $crate::get_channel(compiler_version) + ); }}; } @@ -87,16 +90,17 @@ impl std::fmt::Debug for VersionInfo { "VersionInfo {{ crate_name: \"{}\", major: {}, minor: {}, patch: {}", self.crate_name, self.major, self.minor, self.patch, )?; - if self.commit_hash.is_some() { - write!( - f, - ", commit_hash: \"{}\", commit_date: \"{}\" }}", - self.commit_hash.clone().unwrap_or_default().trim(), - self.commit_date.clone().unwrap_or_default().trim() - )?; - } else { - write!(f, " }}")?; + if let Some(ref commit_hash) = self.commit_hash { + write!(f, ", commit_hash: \"{}\"", commit_hash.trim(),)?; + } + if let Some(ref commit_date) = self.commit_date { + write!(f, ", commit_date: \"{}\"", commit_date.trim())?; } + if let Some(ref host_compiler) = self.host_compiler { + write!(f, ", host_compiler: \"{}\"", host_compiler.trim())?; + } + + write!(f, " }}")?; Ok(()) } @@ -152,22 +156,27 @@ pub fn get_commit_date() -> Option { } #[must_use] -pub fn get_channel() -> String { +pub fn get_compiler_version() -> Option { + get_output("rustc", &["-V"]) +} + +#[must_use] +pub fn get_channel(compiler_version: Option) -> String { if let Ok(channel) = std::env::var("CFG_RELEASE_CHANNEL") { return channel; } // if that failed, try to ask rustc -V, do some parsing and find out - if let Some(rustc_output) = get_output("rustc", &["-V"]) { + if let Some(rustc_output) = compiler_version { if rustc_output.contains("beta") { return String::from("beta"); - } else if rustc_output.contains("stable") { - return String::from("stable"); + } else if rustc_output.contains("nightly") { + return String::from("nightly"); } } - // default to nightly - String::from("nightly") + // default to stable + String::from("stable") } #[cfg(test)] @@ -179,17 +188,19 @@ mod test { let vi = get_version_info!(); assert_eq!(vi.major, 0); assert_eq!(vi.minor, 4); - assert_eq!(vi.patch, 0); + assert_eq!(vi.patch, 2); assert_eq!(vi.crate_name, "rustc_tools_util"); // hard to make positive tests for these since they will always change assert!(vi.commit_hash.is_none()); assert!(vi.commit_date.is_none()); + + assert!(vi.host_compiler.is_none()); } #[test] fn test_display_local() { let vi = get_version_info!(); - assert_eq!(vi.to_string(), "rustc_tools_util 0.4.0"); + assert_eq!(vi.to_string(), "rustc_tools_util 0.4.2"); } #[test] @@ -198,7 +209,7 @@ mod test { let s = format!("{vi:?}"); assert_eq!( s, - "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 4, patch: 0 }" + "VersionInfo { crate_name: \"rustc_tools_util\", major: 0, minor: 4, patch: 2 }" ); } } diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index d1b1a1d232329..f44cf7a7c25a0 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -139,7 +139,7 @@ impl TestContext { } } - fn base_config(&self, test_dir: &str) -> Config { + fn base_config(&self, test_dir: &str, mandatory_annotations: bool) -> Config { let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())); let mut config = Config { output_conflict_handling: OutputConflictHandling::Error, @@ -153,7 +153,11 @@ impl TestContext { }; let defaults = config.comment_defaults.base(); defaults.exit_status = None.into(); - defaults.require_annotations = None.into(); + if mandatory_annotations { + defaults.require_annotations = Some(Spanned::dummy(true)).into(); + } else { + defaults.require_annotations = None.into(); + } defaults.diagnostic_code_prefix = Some(Spanned::dummy("clippy::".into())).into(); defaults.set_custom("rustfix", RustfixMode::Everything); if let Some(collector) = self.diagnostic_collector.clone() { @@ -197,7 +201,7 @@ impl TestContext { } fn run_ui(cx: &TestContext) { - let mut config = cx.base_config("ui"); + let mut config = cx.base_config("ui", true); config .program .envs @@ -216,7 +220,7 @@ fn run_internal_tests(cx: &TestContext) { if !RUN_INTERNAL_TESTS { return; } - let mut config = cx.base_config("ui-internal"); + let mut config = cx.base_config("ui-internal", false); config.bless_command = Some("cargo uitest --features internal -- -- --bless".into()); ui_test::run_tests_generic( @@ -229,7 +233,7 @@ fn run_internal_tests(cx: &TestContext) { } fn run_ui_toml(cx: &TestContext) { - let mut config = cx.base_config("ui-toml"); + let mut config = cx.base_config("ui-toml", true); config .comment_defaults @@ -259,7 +263,7 @@ fn run_ui_cargo(cx: &TestContext) { return; } - let mut config = cx.base_config("ui-cargo"); + let mut config = cx.base_config("ui-cargo", false); config.program.input_file_flag = CommandBuilder::cargo().input_file_flag; config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag; config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()]; @@ -379,13 +383,15 @@ fn ui_cargo_toml_metadata() { .map(|component| component.as_os_str().to_string_lossy().replace('-', "_")) .any(|s| *s == name) || path.starts_with(&cargo_common_metadata_path), - "{path:?} has incorrect package name" + "`{}` has incorrect package name", + path.display(), ); let publish = package.get("publish").and_then(toml::Value::as_bool).unwrap_or(true); assert!( !publish || publish_exceptions.contains(&path.parent().unwrap().to_path_buf()), - "{path:?} lacks `publish = false`" + "`{}` lacks `publish = false`", + path.display(), ); } } diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr index 4fe7f6f7a9edb..059427d8ee0f8 100644 --- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr +++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr @@ -11,8 +11,9 @@ error: lint group `rust_2018_idioms` has the same priority (0) as a lint = note: `#[deny(clippy::lint_groups_priority)]` on by default help: to have lints override the group set `rust_2018_idioms` to a lower priority | -7 | rust_2018_idioms = { level = "warn", priority = -1 } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +7 - rust_2018_idioms = "warn" +7 + rust_2018_idioms = { level = "warn", priority = -1 } + | error: lint group `unused` has the same priority (0) as a lint --> Cargo.toml:10:1 @@ -27,7 +28,7 @@ error: lint group `unused` has the same priority (0) as a lint help: to have lints override the group set `unused` to a lower priority | 10 | unused = { level = "deny", priority = -1 } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + | +++++++++++++++ error: lint group `pedantic` has the same priority (-1) as a lint --> Cargo.toml:15:1 @@ -40,8 +41,9 @@ error: lint group `pedantic` has the same priority (-1) as a lint = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `pedantic` to a lower priority | -15 | pedantic = { level = "warn", priority = -2 } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +15 - pedantic = { level = "warn", priority = -1 } +15 + pedantic = { level = "warn", priority = -2 } + | error: lint group `rust_2018_idioms` has the same priority (0) as a lint --> Cargo.toml:19:1 @@ -54,8 +56,9 @@ error: lint group `rust_2018_idioms` has the same priority (0) as a lint = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `rust_2018_idioms` to a lower priority | -19 | rust_2018_idioms = { level = "warn", priority = -1 } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +19 - rust_2018_idioms = "warn" +19 + rust_2018_idioms = { level = "warn", priority = -1 } + | error: lint group `pedantic` has the same priority (0) as a lint --> Cargo.toml:23:1 @@ -68,7 +71,8 @@ error: lint group `pedantic` has the same priority (0) as a lint = note: the order of the lints in the table is ignored by Cargo help: to have lints override the group set `pedantic` to a lower priority | -23 | pedantic = { level = "warn", priority = -1 } - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +23 - pedantic = "warn" +23 + pedantic = { level = "warn", priority = -1 } + | error: could not compile `fail` (lib) due to 5 previous errors diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index ae5d8ef1d0b59..801b0f340de93 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -14,7 +14,7 @@ note: rustc running on note: compiler flags: -Z ui-testing -Z deduplicate-diagnostics=no query stack during panic: -#0 [early_lint_checks] perform lints prior to macro expansion +#0 [early_lint_checks] perform lints prior to AST lowering #1 [hir_crate] getting the crate HIR ... and 3 other queries... use `env RUST_BACKTRACE=1` to see the full query stack note: Clippy version: foo diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed index 928596d080913..7011ef518f20f 100644 --- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed +++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed @@ -9,7 +9,7 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_session; use clippy_utils::extract_msrv_attr; -use clippy_utils::msrvs::Msrv; +use clippy_utils::msrvs::MsrvStack; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -20,18 +20,13 @@ declare_lint! { } struct Pass { - msrv: Msrv, + msrv: MsrvStack, } impl_lint_pass!(Pass => [TEST_LINT]); -impl LateLintPass<'_> for Pass { - extract_msrv_attr!(LateContext); - fn check_expr(&mut self, _: &LateContext<'_>, _: &Expr<'_>) {} -} - impl EarlyLintPass for Pass { - extract_msrv_attr!(EarlyContext); + extract_msrv_attr!(); fn check_expr(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Expr) {} } diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs index 50b28648ccc9f..323061decd23c 100644 --- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs +++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs @@ -9,7 +9,7 @@ extern crate rustc_middle; #[macro_use] extern crate rustc_session; use clippy_utils::extract_msrv_attr; -use clippy_utils::msrvs::Msrv; +use clippy_utils::msrvs::MsrvStack; use rustc_hir::Expr; use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; @@ -20,15 +20,11 @@ declare_lint! { } struct Pass { - msrv: Msrv, + msrv: MsrvStack, } impl_lint_pass!(Pass => [TEST_LINT]); -impl LateLintPass<'_> for Pass { - fn check_expr(&mut self, _: &LateContext<'_>, _: &Expr<'_>) {} -} - impl EarlyLintPass for Pass { fn check_expr(&mut self, _: &EarlyContext<'_>, _: &rustc_ast::Expr) {} } diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr index aa649c627a164..0a7636313eff2 100644 --- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr +++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr @@ -1,8 +1,8 @@ -error: `extract_msrv_attr!` macro missing from `LateLintPass` implementation +error: `extract_msrv_attr!` macro missing from `EarlyLintPass` implementation --> tests/ui-internal/invalid_msrv_attr_impl.rs:28:1 | -LL | impl LateLintPass<'_> for Pass { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl EarlyLintPass for Pass { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> tests/ui-internal/invalid_msrv_attr_impl.rs:1:9 @@ -10,23 +10,11 @@ note: the lint level is defined here LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::missing_msrv_attr_impl)]` implied by `#[deny(clippy::internal)]` -help: add `extract_msrv_attr!(LateContext)` to the `LateLintPass` implementation - | -LL + impl LateLintPass<'_> for Pass { -LL + extract_msrv_attr!(LateContext); - | - -error: `extract_msrv_attr!` macro missing from `EarlyLintPass` implementation - --> tests/ui-internal/invalid_msrv_attr_impl.rs:32:1 - | -LL | impl EarlyLintPass for Pass { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: add `extract_msrv_attr!(EarlyContext)` to the `EarlyLintPass` implementation +help: add `extract_msrv_attr!()` to the `EarlyLintPass` implementation | -LL + impl EarlyLintPass for Pass { -LL + extract_msrv_attr!(EarlyContext); +LL ~ impl EarlyLintPass for Pass { +LL + extract_msrv_attr!(); | -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr index 6fc495f018080..b946514454aa4 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.default.stderr @@ -1,11 +1,11 @@ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:15:13 + --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:16:13 | LL | let _ = ::m1::m2::X; | ^^^^^^^^^^^ | note: the lint level is defined here - --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:6:9 + --> tests/ui-toml/absolute_paths/absolute_paths_2015.rs:7:9 | LL | #![deny(clippy::absolute_paths)] | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.rs index 033c47809191c..86981f979556d 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.rs +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths_2015.rs @@ -1,6 +1,7 @@ //@revisions: default allow_crates //@[default]rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/default //@[allow_crates]rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/absolute_paths/allow_crates +//@[allow_crates]check-pass //@edition:2015 #![deny(clippy::absolute_paths)] diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed index c04543da94b95..e12a94a4b2050 100644 --- a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed +++ b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed @@ -7,8 +7,14 @@ fn main() { let local_opt: Option = Some(3); println!("val='{local_i32}'"); + //~^ uninlined_format_args println!("Hello x is {local_f64:.local_i32$}"); + //~^ uninlined_format_args + //~| print_literal println!("Hello {local_i32} is {local_f64:.*}", 5); + //~^ uninlined_format_args println!("Hello {local_i32} is {local_f64:.*}", 5); + //~^ uninlined_format_args println!("{local_i32}, {}", local_opt.unwrap()); + //~^ uninlined_format_args } diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs index 813830d80b830..ad5aec133e914 100644 --- a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs +++ b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs @@ -7,8 +7,14 @@ fn main() { let local_opt: Option = Some(3); println!("val='{}'", local_i32); + //~^ uninlined_format_args println!("Hello {} is {:.*}", "x", local_i32, local_f64); + //~^ uninlined_format_args + //~| print_literal println!("Hello {} is {:.*}", local_i32, 5, local_f64); + //~^ uninlined_format_args println!("Hello {} is {2:.*}", local_i32, 5, local_f64); + //~^ uninlined_format_args println!("{}, {}", local_i32, local_opt.unwrap()); + //~^ uninlined_format_args } diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr index 73ef620bd12eb..3ffe61b8ed725 100644 --- a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr +++ b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.stderr @@ -13,7 +13,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:10:5 + --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:11:5 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + println!("Hello {} is {local_f64:.local_i32$}", "x"); | error: literal with an empty format string - --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:10:35 + --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:11:35 | LL | println!("Hello {} is {:.*}", "x", local_i32, local_f64); | ^^^ @@ -39,7 +39,7 @@ LL + println!("Hello x is {:.*}", local_i32, local_f64); | error: variables can be used directly in the `format!` string - --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:11:5 + --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:14:5 | LL | println!("Hello {} is {:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:12:5 + --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:16:5 | LL | println!("Hello {} is {2:.*}", local_i32, 5, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL + println!("Hello {local_i32} is {local_f64:.*}", 5); | error: variables can be used directly in the `format!` string - --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:13:5 + --> tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs:18:5 | LL | println!("{}, {}", local_i32, local_opt.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs index e9bcc30c15e0a..05eb40506db49 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs @@ -5,6 +5,11 @@ //@[bad_conf_1] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/bad_conf_1 //@[bad_conf_2] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/bad_conf_2 //@[bad_conf_3] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/bad_conf_3 +//@[default] check-pass +//@[default_exp] check-pass +//@[bad_conf_1] error-in-other-file: +//@[bad_conf_2] error-in-other-file: +//@[bad_conf_3] error-in-other-file: #![allow(dead_code)] #![warn(clippy::arbitrary_source_item_ordering)] diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good_var_1.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good_var_1.rs index 0fccbd4790bc2..fb2d2e64bceaf 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good_var_1.rs +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good_var_1.rs @@ -1,6 +1,7 @@ //@aux-build:../../ui/auxiliary/proc_macros.rs //@revisions: var_1 //@[var_1] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/var_1 +//@check-pass #![allow(dead_code)] #![warn(clippy::arbitrary_source_item_ordering)] diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr index ee2868869deb5..3605952bddc9b 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.default.stderr @@ -1,11 +1,11 @@ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:21:14 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:22:14 | LL | use std::rc::Weak; | ^^^^ | note: should be placed before `SNAKE_CASE` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:19:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:20:7 | LL | const SNAKE_CASE: &str = "zzzzzzzz"; | ^^^^^^^^^^ @@ -13,18 +13,18 @@ LL | const SNAKE_CASE: &str = "zzzzzzzz"; = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:64:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:67:1 | LL | / impl CloneSelf for StructOrdered { +LL | | LL | | fn clone_self(&self) -> Self { LL | | Self { -LL | | a: true, ... | LL | | } | |_^ | note: should be placed before the following item - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:54:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:57:1 | LL | / impl Default for StructOrdered { LL | | fn default() -> Self { @@ -35,55 +35,54 @@ LL | | } | |_^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:136:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:145:7 | LL | const ZIS_SHOULD_BE_REALLY_EARLY: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `TraitUnorderedItemKinds` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:124:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:132:7 | LL | trait TraitUnorderedItemKinds { | ^^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:151:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:163:1 | LL | impl BasicEmptyTrait for StructOrdered {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before the following item - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:138:1 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:148:1 | LL | / impl TraitUnordered for StructUnordered { LL | | const A: bool = false; LL | | const C: bool = false; LL | | const B: bool = false; ... | -LL | | fn b() {} LL | | } | |_^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:170:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:184:5 | LL | mod this_is_in_the_wrong_position { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `main` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:165:4 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:179:4 | LL | fn main() { | ^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:178:7 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:194:7 | LL | const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `ZisShouldBeBeforeZeMainFn` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:176:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:192:8 | LL | struct ZisShouldBeBeforeZeMainFn; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -101,121 +100,121 @@ LL | const BEFORE: i8 = 0; | ^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:38:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:40:5 | LL | B, | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:37:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:39:5 | LL | C, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:88:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:92:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:87:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:91:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:96:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:101:5 | LL | b: bool, | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:95:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:100:5 | LL | c: bool, | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:115:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:114:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:11 | LL | const C: bool; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:121:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:128:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:120:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:127:8 | LL | fn c(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:127:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:135:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:125:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:133:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:141:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:151:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:140:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:150:11 | LL | const C: bool = false; | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:147:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:158:8 | LL | fn b() {} | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:146:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:157:8 | LL | fn c() {} | ^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:156:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:169:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:154:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:167:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:172:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:187:11 | LL | const A: i8 = 1; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:171:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs:186:11 | LL | const C: i8 = 0; | ^ diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs index 2765bf935b7ce..9e65a9cca0da1 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed.rs @@ -10,6 +10,7 @@ mod i_am_just_right { const BEFORE: i8 = 0; const AFTER: i8 = 0; + //~^ arbitrary_source_item_ordering } // Use statements should not be linted internally - this is normally auto-sorted using rustfmt. @@ -19,6 +20,7 @@ use std::sync::{Arc, Barrier, RwLock}; const SNAKE_CASE: &str = "zzzzzzzz"; use std::rc::Weak; +//~^ arbitrary_source_item_ordering trait BasicEmptyTrait {} @@ -36,6 +38,7 @@ enum EnumUnordered { A, C, B, + //~^ arbitrary_source_item_ordering } #[allow(clippy::arbitrary_source_item_ordering)] @@ -62,6 +65,7 @@ impl Default for StructOrdered { } impl CloneSelf for StructOrdered { + //~^ arbitrary_source_item_ordering fn clone_self(&self) -> Self { Self { a: true, @@ -86,6 +90,7 @@ struct StructUnordered { a: bool, c: bool, b: bool, + //~^ arbitrary_source_item_ordering d: bool, } @@ -94,6 +99,7 @@ struct StructUnorderedGeneric { a: bool, c: bool, b: bool, + //~^ arbitrary_source_item_ordering d: bool, } @@ -113,18 +119,21 @@ trait TraitUnordered { const A: bool; const C: bool; const B: bool; + //~^ arbitrary_source_item_ordering type SomeType; fn a(); fn c(); fn b(); + //~^ arbitrary_source_item_ordering } trait TraitUnorderedItemKinds { type SomeType; const A: bool; + //~^ arbitrary_source_item_ordering const B: bool; const C: bool; @@ -134,26 +143,31 @@ trait TraitUnorderedItemKinds { } const ZIS_SHOULD_BE_REALLY_EARLY: () = (); +//~^ arbitrary_source_item_ordering impl TraitUnordered for StructUnordered { const A: bool = false; const C: bool = false; const B: bool = false; + //~^ arbitrary_source_item_ordering type SomeType = (); fn a() {} fn c() {} fn b() {} + //~^ arbitrary_source_item_ordering } // Trait impls should be located just after the type they implement it for. impl BasicEmptyTrait for StructOrdered {} +//~^ arbitrary_source_item_ordering impl TraitUnorderedItemKinds for StructUnordered { type SomeType = (); const A: bool = false; + //~^ arbitrary_source_item_ordering const B: bool = false; const C: bool = false; @@ -168,14 +182,17 @@ fn main() { /// Note that the linting pass is stopped before recursing into this module. mod this_is_in_the_wrong_position { + //~^ arbitrary_source_item_ordering const C: i8 = 0; const A: i8 = 1; + //~^ arbitrary_source_item_ordering } #[derive(Default, std::clone::Clone)] struct ZisShouldBeBeforeZeMainFn; const ZIS_SHOULD_BE_EVEN_EARLIER: () = (); +//~^ arbitrary_source_item_ordering #[cfg(test)] mod test { diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs index 44902336573cc..96b2fb16f8f52 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs @@ -103,20 +103,24 @@ impl TraitUnordered for StructUnordered { fn a() {} fn c() {} fn b() {} + //~^ arbitrary_source_item_ordering type SomeType = (); const A: bool = false; const C: bool = false; const B: bool = false; + //~^ arbitrary_source_item_ordering } impl TraitUnorderedItemKinds for StructUnordered { const A: bool = false; type SomeType = (); + //~^ arbitrary_source_item_ordering fn a() {} + //~^ arbitrary_source_item_ordering } struct StructUnorderedGeneric { @@ -143,20 +147,24 @@ trait TraitUnordered { fn a(); fn c(); fn b(); + //~^ arbitrary_source_item_ordering type SomeType; const A: bool; const C: bool; const B: bool; + //~^ arbitrary_source_item_ordering } trait TraitUnorderedItemKinds { const A: bool; type SomeType; + //~^ arbitrary_source_item_ordering fn a(); + //~^ arbitrary_source_item_ordering } #[derive(std::clone::Clone, Default)] diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.var_1.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.var_1.stderr index f31f7f68c17e7..730f12c38a0d3 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.var_1.stderr +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.var_1.stderr @@ -13,85 +13,85 @@ LL | fn c() {} = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:111:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:112:11 | LL | const B: bool = false; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:110:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:111:11 | LL | const C: bool = false; | ^ error: incorrect ordering of impl items (defined order: [Fn, Type, Const]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:117:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:119:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ | note: should be placed before `A` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:115:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:117:5 | LL | const A: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of impl items (defined order: [Fn, Type, Const]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:119:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:122:5 | LL | fn a() {} | ^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:117:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:119:5 | LL | type SomeType = (); | ^^^^^^^^^^^^^^^^^^^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:145:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:149:8 | LL | fn b(); | ^ | note: should be placed before `c` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:144:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:148:8 | LL | fn c(); | ^ error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:151:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:156:11 | LL | const B: bool; | ^ | note: should be placed before `C` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:150:11 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:155:11 | LL | const C: bool; | ^ error: incorrect ordering of trait items (defined order: [Fn, Type, Const]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:157:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:163:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ | note: should be placed before `A` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:155:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:161:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ error: incorrect ordering of trait items (defined order: [Fn, Type, Const]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:159:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:166:5 | LL | fn a(); | ^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:157:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_mixed_var_1.rs:163:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_enum.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_enum.rs index e8002c4a1633e..4e8ed5e550a33 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_enum.rs +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_enum.rs @@ -20,6 +20,7 @@ enum EnumOrdered { enum EnumUnordered { B, A, + //~^ arbitrary_source_item_ordering } trait TraitUnordered { diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.only_impl.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.only_impl.stderr index 40348ecbdae1a..77596ba23946d 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.only_impl.stderr +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.only_impl.stderr @@ -13,7 +13,7 @@ LL | fn b() {} = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:45:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:46:5 | LL | type SomeType = i8; | ^^^^^^^^^^^^^^^^^^^ @@ -25,13 +25,13 @@ LL | fn a() {} | ^^^^^^^^^ error: incorrect ordering of impl items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:47:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:49:5 | LL | const A: bool = true; | ^^^^^^^^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:45:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs:46:5 | LL | type SomeType = i8; | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs index bd969c865b5ac..56e2e188be6aa 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_impl.rs @@ -41,10 +41,13 @@ trait TraitUnordered { impl BasicTrait for StructUnordered { fn b() {} fn a() {} + //~^ arbitrary_source_item_ordering type SomeType = i8; + //~^ arbitrary_source_item_ordering const A: bool = true; + //~^ arbitrary_source_item_ordering } trait TraitUnorderedItemKinds { diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.only_trait.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.only_trait.stderr index 9b86ebd48e3da..3d903330be8f5 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.only_trait.stderr +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.only_trait.stderr @@ -13,25 +13,25 @@ LL | const B: bool; = help: to override `-D warnings` add `#[allow(clippy::arbitrary_source_item_ordering)]` error: incorrect ordering of items (must be alphabetically ordered) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:37:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:38:8 | LL | fn a(); | ^ | note: should be placed before `b` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:36:8 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:37:8 | LL | fn b(); | ^ error: incorrect ordering of trait items (defined order: [Const, Type, Fn]) - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:43:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:45:5 | LL | const A: bool; | ^^^^^^^^^^^^^^ | note: should be placed before `SomeType` - --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:41:5 + --> tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs:43:5 | LL | type SomeType; | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs index 979a52ecb1007..d885a20ca50ab 100644 --- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs +++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_only_trait.rs @@ -30,17 +30,20 @@ enum EnumUnordered { trait TraitUnordered { const B: bool; const A: bool; + //~^ arbitrary_source_item_ordering type SomeType; fn b(); fn a(); + //~^ arbitrary_source_item_ordering } trait TraitUnorderedItemKinds { type SomeType; const A: bool; + //~^ arbitrary_source_item_ordering fn a(); } diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs index 33f7c8ba80424..01a84a526c09c 100644 --- a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs +++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs @@ -67,6 +67,7 @@ fn lhs_and_rhs_are_equal() { let _ = Bar + Bar; // not on the list let _ = Baz + Baz; + //~^ arithmetic_side_effects } fn lhs_is_different() { @@ -78,13 +79,16 @@ fn lhs_is_different() { let _ = 1i32 + Bar; // not on the list let _ = 1i32 + Baz; + //~^ arithmetic_side_effects // not on the list let _ = 1i64 + Foo; + //~^ arithmetic_side_effects // is implicitly on the list let _ = 1i64 + Bar; // not on the list let _ = 1i64 + Baz; + //~^ arithmetic_side_effects } fn rhs_is_different() { @@ -96,13 +100,16 @@ fn rhs_is_different() { let _ = Bar + 1i32; // not on the list let _ = Baz + 1i32; + //~^ arithmetic_side_effects // not on the list let _ = Foo + 1i64; + //~^ arithmetic_side_effects // is implicitly on the list let _ = Bar + 1i64; // not on the list let _ = Baz + 1i64; + //~^ arithmetic_side_effects } fn unary() { @@ -112,8 +119,10 @@ fn unary() { let _ = -Foo; // not on the list let _ = -Bar; + //~^ arithmetic_side_effects // not on the list let _ = -Baz; + //~^ arithmetic_side_effects } fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr index 3c5216023b543..93efcc01c88f0 100644 --- a/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr +++ b/src/tools/clippy/tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.stderr @@ -8,49 +8,49 @@ LL | let _ = Baz + Baz; = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:80:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:81:13 | LL | let _ = 1i32 + Baz; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:83:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:85:13 | LL | let _ = 1i64 + Foo; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:87:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:90:13 | LL | let _ = 1i64 + Baz; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:98:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:102:13 | LL | let _ = Baz + 1i32; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:101:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:106:13 | LL | let _ = Foo + 1i64; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:105:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:111:13 | LL | let _ = Baz + 1i64; | ^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:114:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:121:13 | LL | let _ = -Bar; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:116:13 + --> tests/ui-toml/arithmetic_side_effects_allowed/arithmetic_side_effects_allowed.rs:124:13 | LL | let _ = -Baz; | ^^^^ diff --git a/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.rs b/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.rs index d36159e126392..b8652137378e6 100644 --- a/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.rs +++ b/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.rs @@ -2,9 +2,11 @@ #![warn(clippy::large_const_arrays, clippy::large_stack_arrays)] //@no-rustfix const ABOVE: [u8; 11] = [0; 11]; +//~^ large_const_arrays const BELOW: [u8; 10] = [0; 10]; fn main() { let above = [0u8; 11]; + //~^ large_stack_arrays let below = [0u8; 10]; } diff --git a/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr b/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr index 41cb85b67df8f..c962e80940763 100644 --- a/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr +++ b/src/tools/clippy/tests/ui-toml/array_size_threshold/array_size_threshold.stderr @@ -10,7 +10,7 @@ LL | const ABOVE: [u8; 11] = [0; 11]; = help: to override `-D warnings` add `#[allow(clippy::large_const_arrays)]` error: allocating a local array larger than 10 bytes - --> tests/ui-toml/array_size_threshold/array_size_threshold.rs:8:17 + --> tests/ui-toml/array_size_threshold/array_size_threshold.rs:9:17 | LL | let above = [0u8; 11]; | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs index 868cf00a8d469..6a9a49324db90 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs @@ -3,11 +3,13 @@ use std::net::Ipv4Addr; async fn bad() -> u32 { let _x = String::from("hello"); + //~^ await_holding_invalid_type baz().await } async fn bad_reason() -> u32 { let x = Ipv4Addr::new(127, 0, 0, 1); + //~^ await_holding_invalid_type let y = baz().await; let _x = x; y @@ -31,6 +33,7 @@ async fn baz() -> u32 { fn block_bad() -> impl std::future::Future { async move { let _x = String::from("hi!"); + //~^ await_holding_invalid_type baz().await } } diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index 39b8634be109a..deb7f49db9e11 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -9,13 +9,13 @@ LL | let _x = String::from("hello"); = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` error: holding a disallowed type across an await point `std::net::Ipv4Addr` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:10:9 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:11:9 | LL | let x = Ipv4Addr::new(127, 0, 0, 1); | ^ error: holding a disallowed type across an await point `std::string::String` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:33:13 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:35:13 | LL | let _x = String::from("hi!"); | ^^ diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs new file mode 100644 index 0000000000000..b5a1f3def61e4 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.rs @@ -0,0 +1,2 @@ +//@error-in-other-file: +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr new file mode 100644 index 0000000000000..86e30409af068 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr @@ -0,0 +1,11 @@ +error: error reading Clippy's configuration file: replacement not allowed for this configuration + --> $DIR/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml:1:31 + | +LL | await-holding-invalid-types = [ + | _______________________________^ +LL | | { path = "std::string::String", replacement = "std::net::Ipv4Addr" }, +LL | | ] + | |_^ + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml new file mode 100644 index 0000000000000..f6bc59672ed73 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml @@ -0,0 +1,3 @@ +await-holding-invalid-types = [ + { path = "std::string::String", replacement = "std::net::Ipv4Addr" }, +] diff --git a/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs index 79c7cef6ce1b9..0514419fd189a 100644 --- a/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs +++ b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs @@ -1,4 +1,5 @@ //@compile-flags: --crate-name borrow_interior_mutable_const_ignore +//@check-pass #![warn(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const)] diff --git a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.default.stderr b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.default.stderr new file mode 100644 index 0000000000000..2a6170b0bcdc5 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.default.stderr @@ -0,0 +1,11 @@ +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0` + --> tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.rs:14:5 + | +LL | sleep(Duration::new(1, 0)) + | ^^^^^ + | + = note: `-D clippy::incompatible-msrv` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr new file mode 100644 index 0000000000000..8a85d38fba3c2 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.enabled.stderr @@ -0,0 +1,23 @@ +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0` + --> tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.rs:14:5 + | +LL | sleep(Duration::new(1, 0)) + | ^^^^^ + | + = note: `-D clippy::incompatible-msrv` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]` + +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0` + --> tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.rs:20:5 + | +LL | sleep(Duration::new(1, 0)); + | ^^^^^ + +error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0` + --> tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.rs:28:9 + | +LL | sleep(Duration::new(1, 0)); + | ^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.rs b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.rs new file mode 100644 index 0000000000000..fed5f350b7223 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/check_incompatible_msrv_in_tests.rs @@ -0,0 +1,31 @@ +//@compile-flags: --test +//@revisions: default enabled +//@[enabled] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/check_incompatible_msrv_in_tests/enabled +//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/check_incompatible_msrv_in_tests/default + +#![warn(clippy::incompatible_msrv)] +#![feature(custom_inner_attributes)] +#![clippy::msrv = "1.3.0"] + +use std::thread::sleep; +use std::time::Duration; + +fn main() { + sleep(Duration::new(1, 0)) + //~^ incompatible_msrv +} + +#[test] +fn test() { + sleep(Duration::new(1, 0)); + //~[enabled]^ incompatible_msrv +} + +#[cfg(test)] +mod tests { + use super::*; + fn helper() { + sleep(Duration::new(1, 0)); + //~[enabled]^ incompatible_msrv + } +} diff --git a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/default/clippy.toml b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/default/clippy.toml new file mode 100644 index 0000000000000..1d13759aceb79 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/default/clippy.toml @@ -0,0 +1 @@ +# default config has check-incompatible-msrv-in-tests as false diff --git a/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/enabled/clippy.toml b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/enabled/clippy.toml new file mode 100644 index 0000000000000..c56af6c821863 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/check_incompatible_msrv_in_tests/enabled/clippy.toml @@ -0,0 +1 @@ +check-incompatible-msrv-in-tests = true diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs index 7f1c512d7c97b..ecb43dc34a8a0 100644 --- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs +++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs @@ -4,6 +4,7 @@ fn main() {} #[warn(clippy::cognitive_complexity)] fn cognitive_complexity() { + //~^ cognitive_complexity let x = vec![1, 2, 3]; for i in x { if i == 1 { diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed index d42b29ba21a63..a914145593248 100644 --- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed +++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.fixed @@ -4,20 +4,27 @@ fn foo(n: u32) -> u32 { if let Some(n) = n.checked_sub(4) { n } else { n } + //~^ dbg_macro } fn factorial(n: u32) -> u32 { if n <= 1 { + //~^ dbg_macro 1 + //~^ dbg_macro } else { n * factorial(n - 1) + //~^ dbg_macro } } fn main() { 42; + //~^ dbg_macro foo(3) + factorial(4); + //~^ dbg_macro (1, 2, 3, 4, 5); + //~^ dbg_macro } #[test] diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs index bd189b1576f96..6565f2e3cf7c6 100644 --- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs +++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs @@ -4,20 +4,27 @@ fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } + //~^ dbg_macro } fn factorial(n: u32) -> u32 { if dbg!(n <= 1) { + //~^ dbg_macro dbg!(1) + //~^ dbg_macro } else { dbg!(n * factorial(n - 1)) + //~^ dbg_macro } } fn main() { dbg!(42); + //~^ dbg_macro foo(3) + dbg!(factorial(4)); + //~^ dbg_macro dbg!(1, 2, 3, 4, 5); + //~^ dbg_macro } #[test] diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr index f0d7104a57dd0..4587d28c3f346 100644 --- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.stderr @@ -13,7 +13,7 @@ LL + if let Some(n) = n.checked_sub(4) { n } else { n } | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:10:8 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:11:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + if n <= 1 { | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:11:9 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:13:9 | LL | dbg!(1) | ^^^^^^^ @@ -37,7 +37,7 @@ LL + 1 | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:13:9 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:16:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:18:5 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:22:5 | LL | dbg!(42); | ^^^^^^^^ @@ -61,7 +61,7 @@ LL + 42; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:19:14 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:24:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + foo(3) + factorial(4); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui-toml/dbg_macro/dbg_macro.rs:20:5 + --> tests/ui-toml/dbg_macro/dbg_macro.rs:26:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs index 6385cf4f852fc..49ffc7a939dea 100644 --- a/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs +++ b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs @@ -1,4 +1,5 @@ //@compile-flags: --crate-name declare_interior_mutable_const_ignore +//@check-pass #![warn(clippy::declare_interior_mutable_const)] #![allow(clippy::borrow_interior_mutable_const)] diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs index e63a99e74cbbe..cfe19606ef4a8 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs @@ -11,38 +11,54 @@ use serde::Serialize; fn main() { println!("one"); + //~^ disallowed_macros println!("two"); + //~^ disallowed_macros cfg!(unix); + //~^ disallowed_macros vec![1, 2, 3]; + //~^ disallowed_macros #[derive(Serialize)] + //~^ disallowed_macros struct Derive; let _ = macros::expr!(); + //~^ disallowed_macros macros::stmt!(); + //~^ disallowed_macros let macros::pat!() = 1; + //~^ disallowed_macros let _: macros::ty!() = ""; + //~^ disallowed_macros macros::item!(); + //~^ disallowed_macros let _ = macros::binop!(1); + //~^ disallowed_macros eprintln!("allowed"); } macros::attr! { +//~^ disallowed_macros struct S; } impl S { macros::item!(); + //~^ disallowed_macros } trait Y { macros::item!(); + //~^ disallowed_macros } impl Y for S { macros::item!(); + //~^ disallowed_macros } #[derive(Derive)] +//~^ disallowed_macros struct Foo; diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr index 6a6c6168a1f59..589995fa87d91 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr +++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.stderr @@ -1,5 +1,5 @@ error: use of a disallowed macro `serde::Serialize` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:18:14 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:22:14 | LL | #[derive(Serialize)] | ^^^^^^^^^ @@ -9,15 +9,16 @@ LL | #[derive(Serialize)] = help: to override `-D warnings` add `#[allow(clippy::disallowed_macros)]` error: use of a disallowed macro `macros::attr` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:31:1 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:42:1 | LL | / macros::attr! { +LL | | LL | | struct S; LL | | } | |_^ error: use of a disallowed macro `proc_macros::Derive` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:47:10 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:62:10 | LL | #[derive(Derive)] | ^^^^^^ @@ -29,73 +30,73 @@ LL | println!("one"); | ^^^^^^^^^^^^^^^ error: use of a disallowed macro `std::println` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:14:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:15:5 | LL | println!("two"); | ^^^^^^^^^^^^^^^ error: use of a disallowed macro `std::cfg` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:15:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:17:5 | LL | cfg!(unix); | ^^^^^^^^^^ error: use of a disallowed macro `std::vec` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:16:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:19:5 | LL | vec![1, 2, 3]; | ^^^^^^^^^^^^^ error: use of a disallowed macro `macros::expr` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:21:13 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:26:13 | LL | let _ = macros::expr!(); | ^^^^^^^^^^^^^^^ error: use of a disallowed macro `macros::stmt` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:22:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:28:5 | LL | macros::stmt!(); | ^^^^^^^^^^^^^^^ error: use of a disallowed macro `macros::pat` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:23:9 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:30:9 | LL | let macros::pat!() = 1; | ^^^^^^^^^^^^^^ error: use of a disallowed macro `macros::ty` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:24:12 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:32:12 | LL | let _: macros::ty!() = ""; | ^^^^^^^^^^^^^ error: use of a disallowed macro `macros::item` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:25:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:34:5 | LL | macros::item!(); | ^^^^^^^^^^^^^^^ error: use of a disallowed macro `macros::binop` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:26:13 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:36:13 | LL | let _ = macros::binop!(1); | ^^^^^^^^^^^^^^^^^ error: use of a disallowed macro `macros::item` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:36:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:48:5 | LL | macros::item!(); | ^^^^^^^^^^^^^^^ error: use of a disallowed macro `macros::item` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:40:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:53:5 | LL | macros::item!(); | ^^^^^^^^^^^^^^^ error: use of a disallowed macro `macros::item` - --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:44:5 + --> tests/ui-toml/disallowed_macros/disallowed_macros.rs:58:5 | LL | macros::item!(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs index 61ae8de8e3357..ea7e31a119dca 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -3,8 +3,10 @@ fn main() { // `foo` is part of the default configuration let foo = "bar"; + //~^ disallowed_names // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; + //~^ disallowed_names // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; } diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr index e6481c9cc63b5..6b7a3fbd8c8d0 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr @@ -8,7 +8,7 @@ LL | let foo = "bar"; = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `ducks` - --> tests/ui-toml/disallowed_names_append/disallowed_names.rs:7:9 + --> tests/ui-toml/disallowed_names_append/disallowed_names.rs:8:9 | LL | let ducks = ["quack", "quack"]; | ^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs index 61ae8de8e3357..dd79795d76a2a 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -5,6 +5,7 @@ fn main() { let foo = "bar"; // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; + //~^ disallowed_names // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; } diff --git a/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.fixed b/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.fixed index f16e138da2be8..e295712e85f41 100644 --- a/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.fixed +++ b/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.fixed @@ -7,6 +7,7 @@ fn allowed_name() {} fn default_name() {} /// `TestItemThingyOfCoolness` might sound cool but is not on the list and should be linted. +//~^ doc_markdown fn unknown_name() {} fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.rs b/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.rs index 327a592e9cadc..192652a7f65b2 100644 --- a/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.rs +++ b/src/tools/clippy/tests/ui-toml/doc_valid_idents_append/doc_markdown.rs @@ -7,6 +7,7 @@ fn allowed_name() {} fn default_name() {} /// TestItemThingyOfCoolness might sound cool but is not on the list and should be linted. +//~^ doc_markdown fn unknown_name() {} fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.fixed b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.fixed index af6ec675e81b6..48a6f5fe61e6c 100644 --- a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.fixed +++ b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.fixed @@ -4,9 +4,12 @@ fn allowed_name() {} /// `OAuth` and `LaTeX` are inside Clippy's default list. +//~^ doc_markdown +//~| doc_markdown fn default_name() {} /// `TestItemThingyOfCoolness` might sound cool but is not on the list and should be linted. +//~^ doc_markdown fn unknown_name() {} fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.rs b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.rs index 327a592e9cadc..f700c1ab03360 100644 --- a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.rs +++ b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.rs @@ -4,9 +4,12 @@ fn allowed_name() {} /// OAuth and LaTeX are inside Clippy's default list. +//~^ doc_markdown +//~| doc_markdown fn default_name() {} /// TestItemThingyOfCoolness might sound cool but is not on the list and should be linted. +//~^ doc_markdown fn unknown_name() {} fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr index 9f2d7cf54e0de..e06b958a1b37d 100644 --- a/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr +++ b/src/tools/clippy/tests/ui-toml/doc_valid_idents_replace/doc_markdown.stderr @@ -25,7 +25,7 @@ LL + /// OAuth and `LaTeX` are inside Clippy's default list. | error: item in documentation is missing backticks - --> tests/ui-toml/doc_valid_idents_replace/doc_markdown.rs:9:5 + --> tests/ui-toml/doc_valid_idents_replace/doc_markdown.rs:11:5 | LL | /// TestItemThingyOfCoolness might sound cool but is not on the list and should be linted. | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs index f328e4d9d04c3..b5a1f3def61e4 100644 --- a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs +++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated/duplicated_keys.rs @@ -1 +1,2 @@ +//@error-in-other-file: fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs index f328e4d9d04c3..b5a1f3def61e4 100644 --- a/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs +++ b/src/tools/clippy/tests/ui-toml/duplicated_keys_deprecated_2/duplicated_keys.rs @@ -1 +1,2 @@ +//@error-in-other-file: fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs index 858aab528a91a..205cd8ba4ee88 100644 --- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs +++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.rs @@ -23,6 +23,7 @@ static X: u32 = { let y = { let z = { let w = { 3 }; + //~^ excessive_nesting w }; z @@ -69,6 +70,7 @@ impl A { struct C; impl C { + //~^ excessive_nesting pub fn c() {} } } @@ -83,6 +85,7 @@ trait Lol { fn bb() { fn cc() { let x = { 1 }; // not a warning, but cc is + //~^ excessive_nesting } let x = { 1 }; // warning @@ -100,6 +103,7 @@ pub mod a { pub mod c { pub mod d { pub mod e { + //~^ excessive_nesting pub mod f {} } // not here } // only warning should be here @@ -113,13 +117,17 @@ fn main() { let a = A; a_but_not({{{{{{{{0}}}}}}}}); + //~^ excessive_nesting a.a({{{{{{{{{0}}}}}}}}}); + //~^ excessive_nesting (0, {{{{{{{1}}}}}}}); + //~^ excessive_nesting if true { if true { if true { if true { + //~^ excessive_nesting if true { } @@ -132,6 +140,7 @@ fn main() { let x = (|| { let y = (|| { let z = (|| { + //~^ excessive_nesting let w = { 3 }; w })(); @@ -151,38 +160,64 @@ fn main() { // this is a mess, but that's intentional let mut y = 1; y += {{{{{5}}}}}; + //~^ excessive_nesting let z = y + {{{{{{{{{5}}}}}}}}}; + //~^ excessive_nesting [0, {{{{{{{{{{0}}}}}}}}}}]; + //~^ excessive_nesting let mut xx = [0; {{{{{{{{100}}}}}}}}]; + //~^ excessive_nesting xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}]; + //~^ excessive_nesting &mut {{{{{{{{{{y}}}}}}}}}}; + //~^ excessive_nesting for i in {{{{xx}}}} {{{{{{{{}}}}}}}} + //~^ excessive_nesting + //~| excessive_nesting while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} + //~^ excessive_nesting + //~| excessive_nesting while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} + //~^ excessive_nesting + //~| excessive_nesting let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} }; + //~^ excessive_nesting {{{{1;}}}}..{{{{{{3}}}}}}; + //~^ excessive_nesting + //~| excessive_nesting {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; + //~^ excessive_nesting + //~| excessive_nesting ..{{{{{{{5}}}}}}}; + //~^ excessive_nesting ..={{{{{3}}}}}; + //~^ excessive_nesting {{{{{1;}}}}}..; + //~^ excessive_nesting loop { break {{{{1}}}} }; + //~^ excessive_nesting loop {{{{{{}}}}}} + //~^ excessive_nesting match {{{{{{true}}}}}} { + //~^ excessive_nesting true => {{{{}}}}, + //~^ excessive_nesting false => {{{{}}}}, + //~^ excessive_nesting } { { { { + //~^ excessive_nesting println!("warning! :)"); } } @@ -192,10 +227,12 @@ fn main() { async fn b() -> u32 { async fn c() -> u32 {{{{{{{0}}}}}}} + //~^ excessive_nesting c().await } async fn a() { {{{{b().await}}}}; + //~^ excessive_nesting } diff --git a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr index 9cf6fc66757d0..bc2c4b8612ecd 100644 --- a/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr +++ b/src/tools/clippy/tests/ui-toml/excessive_nesting/excessive_nesting.stderr @@ -9,9 +9,10 @@ LL | let w = { 3 }; = help: to override `-D warnings` add `#[allow(clippy::excessive_nesting)]` error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:71:17 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:72:17 | LL | / impl C { +LL | | LL | | pub fn c() {} LL | | } | |_________________^ @@ -19,7 +20,7 @@ LL | | } = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:85:25 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:87:25 | LL | let x = { 1 }; // not a warning, but cc is | ^^^^^ @@ -27,9 +28,10 @@ LL | let x = { 1 }; // not a warning, but cc is = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:102:17 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:105:17 | LL | / pub mod e { +LL | | LL | | pub mod f {} LL | | } // not here | |_________________^ @@ -37,7 +39,7 @@ LL | | } // not here = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:115:18 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:119:18 | LL | a_but_not({{{{{{{{0}}}}}}}}); | ^^^^^^^^^^^ @@ -45,7 +47,7 @@ LL | a_but_not({{{{{{{{0}}}}}}}}); = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:116:12 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:121:12 | LL | a.a({{{{{{{{{0}}}}}}}}}); | ^^^^^^^^^^^^^ @@ -53,7 +55,7 @@ LL | a.a({{{{{{{{{0}}}}}}}}}); = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:117:12 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:123:12 | LL | (0, {{{{{{{1}}}}}}}); | ^^^^^^^^^ @@ -61,10 +63,11 @@ LL | (0, {{{{{{{1}}}}}}}); = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:122:25 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:129:25 | LL | if true { | _________________________^ +LL | | LL | | if true { ... | LL | | } @@ -73,10 +76,11 @@ LL | | } = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:134:29 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:142:29 | LL | let z = (|| { | _____________________________^ +LL | | LL | | let w = { 3 }; LL | | w LL | | })(); @@ -85,7 +89,7 @@ LL | | })(); = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:153:13 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:13 | LL | y += {{{{{5}}}}}; | ^^^^^ @@ -93,7 +97,7 @@ LL | y += {{{{{5}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:154:20 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:20 | LL | let z = y + {{{{{{{{{5}}}}}}}}}; | ^^^^^^^^^^^^^ @@ -101,7 +105,7 @@ LL | let z = y + {{{{{{{{{5}}}}}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:155:12 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:12 | LL | [0, {{{{{{{{{{0}}}}}}}}}}]; | ^^^^^^^^^^^^^^^ @@ -109,7 +113,7 @@ LL | [0, {{{{{{{{{{0}}}}}}}}}}]; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:156:25 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:25 | LL | let mut xx = [0; {{{{{{{{100}}}}}}}}]; | ^^^^^^^^^^^^^ @@ -117,7 +121,7 @@ LL | let mut xx = [0; {{{{{{{{100}}}}}}}}]; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:157:11 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:11 | LL | xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +129,7 @@ LL | xx[{{{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}}}]; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:158:13 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:172:13 | LL | &mut {{{{{{{{{{y}}}}}}}}}}; | ^^^^^^^^^^^^^^^ @@ -133,7 +137,7 @@ LL | &mut {{{{{{{{{{y}}}}}}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:17 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:17 | LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}} | ^^^^ @@ -141,7 +145,7 @@ LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:160:28 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:28 | LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}} | ^^^^^^^^^^ @@ -149,7 +153,7 @@ LL | for i in {{{{xx}}}} {{{{{{{{}}}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:28 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:179:28 | LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} | ^^^^^^^^^^^^^ @@ -157,7 +161,7 @@ LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:162:48 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:179:48 | LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} | ^^^^^^^^ @@ -165,7 +169,7 @@ LL | while let Some(i) = {{{{{{Some(1)}}}}}} {{{{{{{}}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:14 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:183:14 | LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} | ^^^^^^^^^^^^^^ @@ -173,7 +177,7 @@ LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:164:35 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:183:35 | LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} | ^^^^^^^^^^^^ @@ -181,7 +185,7 @@ LL | while {{{{{{{{true}}}}}}}} {{{{{{{{{}}}}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:166:23 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:187:23 | LL | let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +193,7 @@ LL | let d = D { d: {{{{{{{{{{{{{{{{{{{{{{{3}}}}}}}}}}}}}}}}}}}}}}} }; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:8 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:190:8 | LL | {{{{1;}}}}..{{{{{{3}}}}}}; | ^^^^ @@ -197,7 +201,7 @@ LL | {{{{1;}}}}..{{{{{{3}}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:168:20 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:190:20 | LL | {{{{1;}}}}..{{{{{{3}}}}}}; | ^^^^^^^ @@ -205,7 +209,7 @@ LL | {{{{1;}}}}..{{{{{{3}}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:8 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:193:8 | LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; | ^^^^ @@ -213,7 +217,7 @@ LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:169:21 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:193:21 | LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,7 +225,7 @@ LL | {{{{1;}}}}..={{{{{{{{{{{{{{{{{{{{{{{{{{6}}}}}}}}}}}}}}}}}}}}}}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:170:10 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:196:10 | LL | ..{{{{{{{5}}}}}}}; | ^^^^^^^^^ @@ -229,7 +233,7 @@ LL | ..{{{{{{{5}}}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:171:11 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:198:11 | LL | ..={{{{{3}}}}}; | ^^^^^ @@ -237,7 +241,7 @@ LL | ..={{{{{3}}}}}; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:172:8 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:200:8 | LL | {{{{{1;}}}}}..; | ^^^^^^ @@ -245,7 +249,7 @@ LL | {{{{{1;}}}}}..; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:174:20 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:203:20 | LL | loop { break {{{{1}}}} }; | ^^^^^ @@ -253,7 +257,7 @@ LL | loop { break {{{{1}}}} }; = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:175:13 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:205:13 | LL | loop {{{{{{}}}}}} | ^^^^^^ @@ -261,7 +265,7 @@ LL | loop {{{{{{}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:177:14 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:208:14 | LL | match {{{{{{true}}}}}} { | ^^^^^^^^^^ @@ -269,7 +273,7 @@ LL | match {{{{{{true}}}}}} { = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:178:20 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:210:20 | LL | true => {{{{}}}}, | ^^ @@ -277,7 +281,7 @@ LL | true => {{{{}}}}, = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:179:21 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:212:21 | LL | false => {{{{}}}}, | ^^ @@ -285,9 +289,10 @@ LL | false => {{{{}}}}, = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:185:17 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:219:17 | LL | / { +LL | | LL | | println!("warning! :)"); LL | | } | |_________________^ @@ -295,7 +300,7 @@ LL | | } = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:194:28 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:229:28 | LL | async fn c() -> u32 {{{{{{{0}}}}}}} | ^^^^^^^^^ @@ -303,7 +308,7 @@ LL | async fn c() -> u32 {{{{{{{0}}}}}}} = help: try refactoring your code to minimize nesting error: this block is too nested - --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:200:8 + --> tests/ui-toml/excessive_nesting/excessive_nesting.rs:236:8 | LL | {{{{b().await}}}}; | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/expect_used/clippy.toml b/src/tools/clippy/tests/ui-toml/expect_used/clippy.toml index 6933b8164195a..895de8357cf76 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/expect_used/clippy.toml @@ -1 +1,2 @@ +allow-expect-in-consts = false allow-expect-in-tests = true diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs index 206788e19f025..9955c9b6baa1d 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs +++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs @@ -1,20 +1,31 @@ //@compile-flags: --test +//@no-rustfix #![warn(clippy::expect_used)] #![allow(clippy::unnecessary_literal_unwrap)] fn expect_option() { let opt = Some(0); let _ = opt.expect(""); + //~^ expect_used } fn expect_result() { let res: Result = Ok(0); let _ = res.expect(""); + //~^ expect_used } fn main() { expect_option(); expect_result(); + + const SOME: Option = Some(3); + const UNWRAPPED: i32 = SOME.expect("Not three?"); + //~^ expect_used + const { + SOME.expect("Still not three?"); + //~^ expect_used + } } #[test] diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr index 81691f8ac6c0a..3bb471e6dfcc8 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr +++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr @@ -1,5 +1,5 @@ error: used `expect()` on an `Option` value - --> tests/ui-toml/expect_used/expect_used.rs:7:13 + --> tests/ui-toml/expect_used/expect_used.rs:8:13 | LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ @@ -9,12 +9,28 @@ LL | let _ = opt.expect(""); = help: to override `-D warnings` add `#[allow(clippy::expect_used)]` error: used `expect()` on a `Result` value - --> tests/ui-toml/expect_used/expect_used.rs:12:13 + --> tests/ui-toml/expect_used/expect_used.rs:14:13 | LL | let _ = res.expect(""); | ^^^^^^^^^^^^^^ | = note: if this value is an `Err`, it will panic -error: aborting due to 2 previous errors +error: used `expect()` on an `Option` value + --> tests/ui-toml/expect_used/expect_used.rs:23:28 + | +LL | const UNWRAPPED: i32 = SOME.expect("Not three?"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: used `expect()` on an `Option` value + --> tests/ui-toml/expect_used/expect_used.rs:26:9 + | +LL | SOME.expect("Still not three?"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs b/src/tools/clippy/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs index 5655232455cb7..1256c93c0fa1e 100644 --- a/src/tools/clippy/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs +++ b/src/tools/clippy/tests/ui-toml/extra_unused_type_parameters/extra_unused_type_parameters.rs @@ -1,3 +1,4 @@ +//@check-pass pub struct S; impl S { diff --git a/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.rs b/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.rs index 42897b389edfc..af8b8a7991ab7 100644 --- a/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.rs +++ b/src/tools/clippy/tests/ui-toml/fn_params_excessive_bools/test.rs @@ -2,5 +2,6 @@ fn f(_: bool) {} fn g(_: bool, _: bool) {} +//~^ fn_params_excessive_bools fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs index 4ac0378544c7d..09d76a9b26573 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.rs @@ -17,18 +17,21 @@ fn many_comments_but_one_line_of_code() { // This should be considered two and a fail. fn too_many_lines() { + //~^ too_many_lines println!("This is bad."); println!("This is bad."); } // This should only fail once (#7517). async fn async_too_many_lines() { + //~^ too_many_lines println!("This is bad."); println!("This is bad."); } // This should fail only once, without failing on the closure. fn closure_too_many_lines() { + //~^ too_many_lines let _ = { println!("This is bad."); println!("This is bad."); @@ -51,6 +54,7 @@ fn comment_after_code() { // This should fail since it is technically two lines. #[rustfmt::skip] fn comment_before_code() { +//~^ too_many_lines let _ = "test"; /* This comment extends to the front of the code but this line should still count. */ let _ = 5; diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr index cb188a868c447..14a49cb76c1ce 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr @@ -2,6 +2,7 @@ error: this function has too many lines (2/1) --> tests/ui-toml/functions_maxlines/test.rs:19:1 | LL | / fn too_many_lines() { +LL | | LL | | println!("This is bad."); LL | | println!("This is bad."); LL | | } @@ -11,18 +12,20 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]` error: this function has too many lines (4/1) - --> tests/ui-toml/functions_maxlines/test.rs:25:1 + --> tests/ui-toml/functions_maxlines/test.rs:26:1 | LL | / async fn async_too_many_lines() { +LL | | LL | | println!("This is bad."); LL | | println!("This is bad."); LL | | } | |_^ error: this function has too many lines (4/1) - --> tests/ui-toml/functions_maxlines/test.rs:31:1 + --> tests/ui-toml/functions_maxlines/test.rs:33:1 | LL | / fn closure_too_many_lines() { +LL | | LL | | let _ = { LL | | println!("This is bad."); LL | | println!("This is bad."); @@ -31,9 +34,10 @@ LL | | } | |_^ error: this function has too many lines (2/1) - --> tests/ui-toml/functions_maxlines/test.rs:53:1 + --> tests/ui-toml/functions_maxlines/test.rs:56:1 | LL | / fn comment_before_code() { +LL | | LL | | let _ = "test"; LL | | /* This comment extends to the front of LL | | the code but this line should still count. */ let _ = 5; diff --git a/src/tools/clippy/tests/ui-toml/good_toml_no_false_negatives/conf_no_false_negatives.rs b/src/tools/clippy/tests/ui-toml/good_toml_no_false_negatives/conf_no_false_negatives.rs index f328e4d9d04c3..9763a09778016 100644 --- a/src/tools/clippy/tests/ui-toml/good_toml_no_false_negatives/conf_no_false_negatives.rs +++ b/src/tools/clippy/tests/ui-toml/good_toml_no_false_negatives/conf_no_false_negatives.rs @@ -1 +1,2 @@ +//@check-pass fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs index 4882416c414ac..e953a2a4e90bc 100644 --- a/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs +++ b/src/tools/clippy/tests/ui-toml/ifs_same_cond/ifs_same_cond.rs @@ -13,6 +13,7 @@ fn issue10272() { if x.get() { } else if !x.take() { } else if x.get() { + //~^ ifs_same_cond } else { } } diff --git a/src/tools/clippy/tests/ui-toml/indexing_slicing/indexing_slicing.rs b/src/tools/clippy/tests/ui-toml/indexing_slicing/indexing_slicing.rs index 0a0da88ea1fad..dd741be91d293 100644 --- a/src/tools/clippy/tests/ui-toml/indexing_slicing/indexing_slicing.rs +++ b/src/tools/clippy/tests/ui-toml/indexing_slicing/indexing_slicing.rs @@ -6,6 +6,7 @@ fn main() { let x = [1, 2, 3, 4]; let index: usize = 1; &x[index..]; + //~^ indexing_slicing } #[cfg(test)] diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs index 2ae673a6def08..d6b0a30179208 100644 --- a/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs +++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes/item_name_repetitions.rs @@ -7,6 +7,7 @@ pub mod foo { // this line should produce a warning: pub fn to_foo() {} + //~^ module_name_repetitions // but this line shouldn't pub fn bar_foo() {} diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs index dbd61992c0d6b..347430f3d2f97 100644 --- a/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs +++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/allowed_prefixes_extend/item_name_repetitions.rs @@ -7,6 +7,7 @@ pub mod foo { // this line should produce a warning: pub fn something_foo() {} + //~^ module_name_repetitions // but none of the following should: pub fn bar_foo() {} diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs index b633dcbd19e44..f05e2410f7e24 100644 --- a/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs +++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs @@ -1,3 +1,5 @@ +//@check-pass + struct Data {} enum Actions {} diff --git a/src/tools/clippy/tests/ui-toml/large_futures/large_futures.fixed b/src/tools/clippy/tests/ui-toml/large_futures/large_futures.fixed index 7dea9fb95b4bb..17d6553a283bd 100644 --- a/src/tools/clippy/tests/ui-toml/large_futures/large_futures.fixed +++ b/src/tools/clippy/tests/ui-toml/large_futures/large_futures.fixed @@ -16,6 +16,7 @@ pub async fn should_not_warn() { pub async fn bar() { Box::pin(should_warn()).await; + //~^ large_futures async { let x = [0u8; 1024]; diff --git a/src/tools/clippy/tests/ui-toml/large_futures/large_futures.rs b/src/tools/clippy/tests/ui-toml/large_futures/large_futures.rs index 4158df8b5ff55..bc601227e5629 100644 --- a/src/tools/clippy/tests/ui-toml/large_futures/large_futures.rs +++ b/src/tools/clippy/tests/ui-toml/large_futures/large_futures.rs @@ -16,6 +16,7 @@ pub async fn should_not_warn() { pub async fn bar() { should_warn().await; + //~^ large_futures async { let x = [0u8; 1024]; diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs index 184c6d17ba41e..685ef1689e72f 100644 --- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs +++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs @@ -2,7 +2,7 @@ #![allow(clippy::literal_string_with_formatting_args)] // Good -const GOOD_INCLUDE_BYTES: &[u8; 68] = include_bytes!("../../ui/author.rs"); +const GOOD_INCLUDE_BYTES: &[u8; 84] = include_bytes!("../../ui/author.rs"); const GOOD_INCLUDE_STR: &str = include_str!("../../ui/author.rs"); #[allow(clippy::large_include_file)] diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr index 82b926cc53ba2..c9f0e661dbd18 100644 --- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr +++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr @@ -1,26 +1,26 @@ error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:14:43 + --> tests/ui-toml/large_include_file/large_include_file.rs:19:1 | -LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[doc = include_str!("too_big.txt")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the configuration allows a maximum size of 600 bytes = note: `-D clippy::large-include-file` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::large_include_file)]` error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:16:35 + --> tests/ui-toml/large_include_file/large_include_file.rs:14:43 | -LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the configuration allows a maximum size of 600 bytes error: attempted to include a large file - --> tests/ui-toml/large_include_file/large_include_file.rs:19:1 + --> tests/ui-toml/large_include_file/large_include_file.rs:16:35 | -LL | #[doc = include_str!("too_big.txt")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: the configuration allows a maximum size of 600 bytes diff --git a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed index f013153f51662..2d76824128bfe 100644 --- a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed +++ b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.fixed @@ -17,7 +17,9 @@ fn main() { // due to clippy::inconsistent-digit-grouping let _fail1 = 100_200_300.123_456_789; + //~^ inconsistent_digit_grouping // fail due to the integer part let _fail2 = 100_200_300.300_200_100; + //~^ unreadable_literal } diff --git a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs index bd5110138c8c5..b42e31085217f 100644 --- a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs +++ b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.rs @@ -17,7 +17,9 @@ fn main() { // due to clippy::inconsistent-digit-grouping let _fail1 = 100_200_300.123456789; + //~^ inconsistent_digit_grouping // fail due to the integer part let _fail2 = 100200300.300200100; + //~^ unreadable_literal } diff --git a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr index 766722d35ab71..c4e164c67ed89 100644 --- a/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr +++ b/src/tools/clippy/tests/ui-toml/lint_decimal_readability/test.stderr @@ -8,7 +8,7 @@ LL | let _fail1 = 100_200_300.123456789; = help: to override `-D warnings` add `#[allow(clippy::inconsistent_digit_grouping)]` error: long literal lacking separators - --> tests/ui-toml/lint_decimal_readability/test.rs:22:18 + --> tests/ui-toml/lint_decimal_readability/test.rs:23:18 | LL | let _fail2 = 100200300.300200100; | ^^^^^^^^^^^^^^^^^^^ help: consider: `100_200_300.300_200_100` diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs index 3dafea56514db..2465fe45645f1 100644 --- a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs +++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs @@ -17,7 +17,7 @@ macro_rules! allow_works { macro_rules! simple { ($v:expr) => { unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe dbg!($v); } }; @@ -28,7 +28,7 @@ macro_rules! simple { macro_rules! raw_symbol { ($r#mod:expr, $r#unsafe:expr) => { unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $r#mod; } $r#unsafe; @@ -40,7 +40,7 @@ macro_rules! multilevel_unsafe { ($v:expr) => { unsafe { unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $v; } } @@ -65,7 +65,7 @@ macro_rules! in_function_with_unsafe { unsafe { fn f() { unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $v; } } @@ -93,7 +93,7 @@ macro_rules! const_generic_in_struct { const M: i32 = { 1; unsafe { $inside_unsafe } - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe }, const N: i32 = { $outside_unsafe }, >; @@ -108,7 +108,7 @@ macro_rules! fn_with_const_generic { fn f() { $outside_unsafe; unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $inside_unsafe; } } @@ -120,7 +120,7 @@ macro_rules! fn_with_const_generic { macro_rules! variables { ($inside_unsafe:expr, $outside_unsafe:expr) => { unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $inside_unsafe; let inside_unsafe = 1; inside_unsafe; @@ -135,7 +135,7 @@ macro_rules! variables { macro_rules! multiple_matchers { ($inside_unsafe:expr, $outside_unsafe:expr) => { unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $inside_unsafe; } $outside_unsafe; @@ -144,7 +144,7 @@ macro_rules! multiple_matchers { $( $v; unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $x; } );+ @@ -156,11 +156,11 @@ macro_rules! multiple_unsafe_blocks { ($w:expr, $x:expr, $y:expr) => { $w; unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $x; } unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $x; $y; } @@ -169,7 +169,7 @@ macro_rules! multiple_unsafe_blocks { pub macro macro2_0($v:expr) { unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $v; } } @@ -220,7 +220,7 @@ macro_rules! unsafe_from_root_ctxt { macro_rules! nested_macro_helper { ($v:expr) => {{ unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe $v; } }}; @@ -230,7 +230,7 @@ macro_rules! nested_macro_helper { macro_rules! nested_macros { ($v:expr, $v2:expr) => {{ unsafe { - //~^ ERROR: this macro expands metavariables in an unsafe block + //~^ macro_metavars_in_unsafe nested_macro_helper!($v); $v; } @@ -243,6 +243,7 @@ pub mod issue13219 { ($e:expr) => { // Metavariable in a block tail expression unsafe { $e } + //~^ macro_metavars_in_unsafe }; } pub fn f(p: *const i32) -> i32 { diff --git a/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.rs b/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.rs index ded3c72c3e042..385e23d69bcd0 100644 --- a/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.rs +++ b/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.rs @@ -4,19 +4,27 @@ extern crate extern_types; use extern_types::{Aaa, LONGER, M, N as W}; +//~^ min_ident_chars pub const N: u32 = 0; +//~^ min_ident_chars pub const LONG: u32 = 32; struct Owo { Uwu: u128, aaa: Aaa, + //~^ min_ident_chars } fn main() { let wha = 1; let vvv = 1; + //~^ min_ident_chars let uuu = 1; + //~^ min_ident_chars let (mut a, mut b) = (1, 2); + //~^ min_ident_chars + //~| min_ident_chars for i in 0..1000 {} + //~^ min_ident_chars } diff --git a/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr b/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr index 63a057aca279a..be795f4daff24 100644 --- a/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr +++ b/src/tools/clippy/tests/ui-toml/min_ident_chars/min_ident_chars.stderr @@ -8,43 +8,43 @@ LL | use extern_types::{Aaa, LONGER, M, N as W}; = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]` error: this ident is too short (1 <= 3) - --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:8:11 + --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:9:11 | LL | pub const N: u32 = 0; | ^ error: this ident is too short (3 <= 3) - --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:13:5 + --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:15:5 | LL | aaa: Aaa, | ^^^ error: this ident is too short (3 <= 3) - --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:18:9 + --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:21:9 | LL | let vvv = 1; | ^^^ error: this ident is too short (3 <= 3) - --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:19:9 + --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:23:9 | LL | let uuu = 1; | ^^^ error: this ident is too short (1 <= 3) - --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:20:14 + --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:25:14 | LL | let (mut a, mut b) = (1, 2); | ^ error: this ident is too short (1 <= 3) - --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:20:21 + --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:25:21 | LL | let (mut a, mut b) = (1, 2); | ^ error: this ident is too short (1 <= 3) - --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:21:9 + --> tests/ui-toml/min_ident_chars/min_ident_chars.rs:28:9 | LL | for i in 0..1000 {} | ^ diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed index 497f783087a10..685f77b7efe82 100644 --- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed +++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.fixed @@ -72,6 +72,7 @@ fn check_index_refutable_slice() { fn map_clone_suggest_copied() { // This should still trigger the lint but suggest `cloned()` instead of `copied()` let _: Option = Some(&16).cloned(); + //~^ map_clone } fn borrow_as_ptr() { diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs index 6e7874108a34c..0bf073af89032 100644 --- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs +++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs @@ -72,6 +72,7 @@ fn check_index_refutable_slice() { fn map_clone_suggest_copied() { // This should still trigger the lint but suggest `cloned()` instead of `copied()` let _: Option = Some(&16).map(|b| *b); + //~^ map_clone } fn borrow_as_ptr() { diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed index a6072111dc061..3e882f496985c 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.fixed @@ -3,14 +3,20 @@ use std::alloc as colla; use std::option::Option as Maybe; use std::process::{Child as Kid, exit as goodbye}; +//~^ missing_enforced_import_renames use std::thread::sleep as thread_sleep; +//~^ missing_enforced_import_renames #[rustfmt::skip] use std::{ any::{type_name as ident, Any}, + //~^ missing_enforced_import_renames clone as foo, + //~^ missing_enforced_import_renames sync :: Mutex as StdMutie, + //~^ missing_enforced_import_renames }; fn main() { use std::collections::BTreeMap as Map; + //~^ missing_enforced_import_renames } diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs index c2b61aab5b3c4..32255af5117f9 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs @@ -3,14 +3,20 @@ use std::alloc as colla; use std::option::Option as Maybe; use std::process::{Child as Kid, exit as wrong_exit}; +//~^ missing_enforced_import_renames use std::thread::sleep; +//~^ missing_enforced_import_renames #[rustfmt::skip] use std::{ any::{type_name, Any}, + //~^ missing_enforced_import_renames clone, + //~^ missing_enforced_import_renames sync :: Mutex, + //~^ missing_enforced_import_renames }; fn main() { use std::collections::BTreeMap as OopsWrongRename; + //~^ missing_enforced_import_renames } diff --git a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr index d3bb07ec47fd3..982b144eb8722 100644 --- a/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr +++ b/src/tools/clippy/tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.stderr @@ -8,31 +8,31 @@ LL | use std::process::{Child as Kid, exit as wrong_exit}; = help: to override `-D warnings` add `#[allow(clippy::missing_enforced_import_renames)]` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:6:1 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:7:1 | LL | use std::thread::sleep; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::thread::sleep as thread_sleep` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:9:11 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:11:11 | LL | any::{type_name, Any}, | ^^^^^^^^^ help: try: `type_name as ident` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:10:5 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:13:5 | LL | clone, | ^^^^^ help: try: `clone as foo` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:11:5 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:15:5 | LL | sync :: Mutex, | ^^^^^^^^^^^^^ help: try: `sync :: Mutex as StdMutie` error: this import should be renamed - --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:15:5 + --> tests/ui-toml/missing_enforced_import_rename/conf_missing_enforced_import_rename.rs:20:5 | LL | use std::collections::BTreeMap as OopsWrongRename; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `use std::collections::BTreeMap as Map` diff --git a/src/tools/clippy/tests/ui-toml/module_inception/module_inception.rs b/src/tools/clippy/tests/ui-toml/module_inception/module_inception.rs index cd495c884a43a..94866a7e81bfc 100644 --- a/src/tools/clippy/tests/ui-toml/module_inception/module_inception.rs +++ b/src/tools/clippy/tests/ui-toml/module_inception/module_inception.rs @@ -4,11 +4,13 @@ pub mod foo2 { pub mod bar2 { pub mod bar2 { + //~^ module_inception pub mod foo2 {} } pub mod foo2 {} } pub mod foo2 { + //~^ module_inception pub mod bar2 {} } } diff --git a/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr b/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr index 75e78c829226d..efef1d0102337 100644 --- a/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr +++ b/src/tools/clippy/tests/ui-toml/module_inception/module_inception.stderr @@ -2,6 +2,7 @@ error: module has the same name as its containing module --> tests/ui-toml/module_inception/module_inception.rs:6:9 | LL | / pub mod bar2 { +LL | | LL | | pub mod foo2 {} LL | | } | |_________^ @@ -10,9 +11,10 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::module_inception)]` error: module has the same name as its containing module - --> tests/ui-toml/module_inception/module_inception.rs:11:5 + --> tests/ui-toml/module_inception/module_inception.rs:12:5 | LL | / pub mod foo2 { +LL | | LL | | pub mod bar2 {} LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs index 27d27564baf34..7e42f095cbbaf 100644 --- a/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs +++ b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs @@ -4,7 +4,11 @@ fn main() { let a = -1; let b = 2; let c = a % b == 0; + //~^ modulo_arithmetic let c = a % b != 0; + //~^ modulo_arithmetic let c = 0 == a % b; + //~^ modulo_arithmetic let c = 0 != a % b; + //~^ modulo_arithmetic } diff --git a/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr index 8d01b66522c61..02286f66f4d19 100644 --- a/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr +++ b/src/tools/clippy/tests/ui-toml/modulo_arithmetic/modulo_arithmetic.stderr @@ -10,7 +10,7 @@ LL | let c = a % b == 0; = help: to override `-D warnings` add `#[allow(clippy::modulo_arithmetic)]` error: you are using modulo operator on types that might have different signs - --> tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs:7:13 + --> tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs:8:13 | LL | let c = a % b != 0; | ^^^^^ @@ -19,7 +19,7 @@ LL | let c = a % b != 0; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs:8:18 + --> tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs:10:18 | LL | let c = 0 == a % b; | ^^^^^ @@ -28,7 +28,7 @@ LL | let c = 0 == a % b; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs:9:18 + --> tests/ui-toml/modulo_arithmetic/modulo_arithmetic.rs:12:18 | LL | let c = 0 != a % b; | ^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs index 3a8e3741e20c2..b23c2340b7d63 100644 --- a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs +++ b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs @@ -1,4 +1,5 @@ //@compile-flags: --crate-name mut_key +//@check-pass #![warn(clippy::mutable_key_type)] diff --git a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed index fd20bdff6e258..6b386046efa7c 100644 --- a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed +++ b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.fixed @@ -4,6 +4,9 @@ fn main() { r#"\aaa"#; r#"\aaa"#; + //~^ needless_raw_string_hashes r#"Hello "world"!"#; + //~^ needless_raw_string_hashes r####" "### "## "# "####; + //~^ needless_raw_string_hashes } diff --git a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs index 3c6c246370068..f928e590d45c7 100644 --- a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs +++ b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs @@ -4,6 +4,9 @@ fn main() { r#"\aaa"#; r##"\aaa"##; + //~^ needless_raw_string_hashes r##"Hello "world"!"##; + //~^ needless_raw_string_hashes r######" "### "## "# "######; + //~^ needless_raw_string_hashes } diff --git a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr index 421ad66e4c968..43d02837c6cc8 100644 --- a/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr +++ b/src/tools/clippy/tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.stderr @@ -13,7 +13,7 @@ LL + r#"\aaa"#; | error: unnecessary hashes around raw string literal - --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:7:5 + --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:8:5 | LL | r##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + r#"Hello "world"!"#; | error: unnecessary hashes around raw string literal - --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:8:5 + --> tests/ui-toml/needless_raw_string_hashes_one_allowed/needless_raw_string_hashes.rs:10:5 | LL | r######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed index 673106f0b12d9..8da607ec65842 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -16,6 +16,7 @@ proc_macro_derive::foo_bar!(); macro_rules! test { () => { vec![0, 0, 0] + //~^ nonstandard_macro_braces }; } @@ -41,10 +42,15 @@ macro_rules! printlnfoo { #[rustfmt::skip] fn main() { let _ = vec![1, 2, 3]; + //~^ nonstandard_macro_braces let _ = format!("ugh {} stop being such a good compiler", "hello"); + //~^ nonstandard_macro_braces let _ = matches!({}, ()); + //~^ nonstandard_macro_braces let _ = quote!{let x = 1;}; + //~^ nonstandard_macro_braces let _ = quote::quote!{match match match}; + //~^ nonstandard_macro_braces let _ = test!(); // trigger when macro def is inside our own crate let _ = vec![1,2,3]; @@ -54,8 +60,10 @@ fn main() { let _ = test2!["{}{}{}", 1, 2, 3]; let _: type_pos![usize] = vec![]; + //~^ nonstandard_macro_braces eprint!["test if user config overrides defaults"]; + //~^ nonstandard_macro_braces printlnfoo!["test if printlnfoo is triggered by println"]; } diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index b9c69037be073..e35844a209fa5 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -16,6 +16,7 @@ proc_macro_derive::foo_bar!(); macro_rules! test { () => { vec!{0, 0, 0} + //~^ nonstandard_macro_braces }; } @@ -41,10 +42,15 @@ macro_rules! printlnfoo { #[rustfmt::skip] fn main() { let _ = vec! {1, 2, 3}; + //~^ nonstandard_macro_braces let _ = format!["ugh {} stop being such a good compiler", "hello"]; + //~^ nonstandard_macro_braces let _ = matches!{{}, ()}; + //~^ nonstandard_macro_braces let _ = quote!(let x = 1;); + //~^ nonstandard_macro_braces let _ = quote::quote!(match match match); + //~^ nonstandard_macro_braces let _ = test!(); // trigger when macro def is inside our own crate let _ = vec![1,2,3]; @@ -54,8 +60,10 @@ fn main() { let _ = test2!["{}{}{}", 1, 2, 3]; let _: type_pos!(usize) = vec![]; + //~^ nonstandard_macro_braces eprint!("test if user config overrides defaults"); + //~^ nonstandard_macro_braces printlnfoo!["test if printlnfoo is triggered by println"]; } diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr index c2c76e444cfe0..fda6addc7aa35 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.stderr @@ -1,5 +1,5 @@ error: use of irregular braces for `vec!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:43:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:44:13 | LL | let _ = vec! {1, 2, 3}; | ^^^^^^^^^^^^^^ help: consider writing: `vec![1, 2, 3]` @@ -8,25 +8,25 @@ LL | let _ = vec! {1, 2, 3}; = help: to override `-D warnings` add `#[allow(clippy::nonstandard_macro_braces)]` error: use of irregular braces for `format!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:44:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:46:13 | LL | let _ = format!["ugh {} stop being such a good compiler", "hello"]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `format!("ugh {} stop being such a good compiler", "hello")` error: use of irregular braces for `matches!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:45:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:48:13 | LL | let _ = matches!{{}, ()}; | ^^^^^^^^^^^^^^^^ help: consider writing: `matches!({}, ())` error: use of irregular braces for `quote!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:46:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:50:13 | LL | let _ = quote!(let x = 1;); | ^^^^^^^^^^^^^^^^^^ help: consider writing: `quote!{let x = 1;}` error: use of irregular braces for `quote::quote!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:47:13 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:52:13 | LL | let _ = quote::quote!(match match match); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `quote::quote!{match match match}` @@ -43,13 +43,13 @@ LL | let _ = test!(); // trigger when macro def is inside our own crate = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error: use of irregular braces for `type_pos!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:56:12 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:62:12 | LL | let _: type_pos!(usize) = vec![]; | ^^^^^^^^^^^^^^^^ help: consider writing: `type_pos![usize]` error: use of irregular braces for `eprint!` macro - --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:58:5 + --> tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs:65:5 | LL | eprint!("test if user config overrides defaults"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `eprint!["test if user config overrides defaults"]` diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.rs b/src/tools/clippy/tests/ui-toml/panic/panic.rs index b6264c950e450..7bdc896453d82 100644 --- a/src/tools/clippy/tests/ui-toml/panic/panic.rs +++ b/src/tools/clippy/tests/ui-toml/panic/panic.rs @@ -10,11 +10,13 @@ fn main() { match a { Enam::A => {}, _ => panic!(""), + //~^ panic } } fn issue_13292() { panic_any("should lint") + //~^ panic } #[test] diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.stderr b/src/tools/clippy/tests/ui-toml/panic/panic.stderr index a034207d919fe..5dfecfe51ddb2 100644 --- a/src/tools/clippy/tests/ui-toml/panic/panic.stderr +++ b/src/tools/clippy/tests/ui-toml/panic/panic.stderr @@ -8,7 +8,7 @@ LL | _ => panic!(""), = help: to override `-D warnings` add `#[allow(clippy::panic)]` error: `panic_any` should not be present in production code - --> tests/ui-toml/panic/panic.rs:17:5 + --> tests/ui-toml/panic/panic.rs:18:5 | LL | panic_any("should lint") | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/path_ends_with_ext/path_ends_with_ext.rs b/src/tools/clippy/tests/ui-toml/path_ends_with_ext/path_ends_with_ext.rs index a34b15f4ac9ab..455623cec43ef 100644 --- a/src/tools/clippy/tests/ui-toml/path_ends_with_ext/path_ends_with_ext.rs +++ b/src/tools/clippy/tests/ui-toml/path_ends_with_ext/path_ends_with_ext.rs @@ -1,3 +1,5 @@ +//@check-pass + #![warn(clippy::path_ends_with_ext)] use std::path::Path; diff --git a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs index 3a8b30cca36a6..74f3ba7e7fa90 100644 --- a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs +++ b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs @@ -4,7 +4,9 @@ fn foo(n: u32) { print!("{n}"); + //~^ print_stdout eprint!("{n}"); + //~^ print_stderr } #[test] diff --git a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr index fea11107c7ca5..835af7ef8c72a 100644 --- a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr +++ b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.stderr @@ -8,7 +8,7 @@ LL | print!("{n}"); = help: to override `-D warnings` add `#[allow(clippy::print_stdout)]` error: use of `eprint!` - --> tests/ui-toml/print_macro/print_macro.rs:7:5 + --> tests/ui-toml/print_macro/print_macro.rs:8:5 | LL | eprint!("{n}"); | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs index cd53f5044599e..6a1d2b51abc8f 100644 --- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs +++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs @@ -11,9 +11,11 @@ mod my_mod { /// some docs pub(crate) fn crate_with_docs() {} pub(crate) fn crate_no_docs() {} + //~^ missing_docs_in_private_items /// some docs pub(super) fn super_with_docs() {} pub(super) fn super_no_docs() {} + //~^ missing_docs_in_private_items mod my_sub { /// some docs @@ -22,6 +24,7 @@ mod my_mod { /// some docs pub(crate) fn sub_crate_with_docs() {} pub(crate) fn sub_crate_no_docs() {} + //~^ missing_docs_in_private_items /// some docs pub(super) fn sub_super_with_docs() {} pub(super) fn sub_super_no_docs() {} @@ -32,15 +35,18 @@ mod my_mod { /// some docs pub(crate) crate_field_with_docs: (), pub(crate) crate_field_no_docs: (), + //~^ missing_docs_in_private_items /// some docs priv_field_with_docs: (), priv_field_no_docs: (), } pub(crate) struct CrateStructNoDocs { + //~^ missing_docs_in_private_items /// some docs pub(crate) crate_field_with_docs: (), pub(crate) crate_field_no_docs: (), + //~^ missing_docs_in_private_items /// some docs priv_field_with_docs: (), priv_field_no_docs: (), @@ -50,6 +56,7 @@ mod my_mod { /// some docs type CrateTypedefWithDocs = String; type CrateTypedefNoDocs = String; +//~^ missing_docs_in_private_items /// some docs pub type PubTypedefWithDocs = String; pub type PubTypedefNoDocs = String; diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr index 9cf79fccb60bb..0d70276de42d3 100644 --- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr +++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr @@ -8,43 +8,43 @@ LL | pub(crate) fn crate_no_docs() {} = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:16:5 + --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:17:5 | LL | pub(super) fn super_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:24:9 + --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:26:9 | LL | pub(crate) fn sub_crate_no_docs() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:34:9 + --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:37:9 | LL | pub(crate) crate_field_no_docs: (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:40:5 + --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:44:5 | LL | / pub(crate) struct CrateStructNoDocs { +LL | | LL | | /// some docs LL | | pub(crate) crate_field_with_docs: (), -LL | | pub(crate) crate_field_no_docs: (), ... | LL | | priv_field_no_docs: (), LL | | } | |_____^ error: missing documentation for a struct field - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:43:9 + --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:48:9 | LL | pub(crate) crate_field_no_docs: (), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a type alias - --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:52:1 + --> tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs:58:1 | LL | type CrateTypedefNoDocs = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr index dd1035e53fa98..335ff403d0621 100644 --- a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr +++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.all_pub_fields.stderr @@ -9,7 +9,7 @@ LL | pub _b: u8, = help: to override `-D warnings` add `#[allow(clippy::pub_underscore_fields)]` error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:23:13 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:24:13 | LL | pub(in crate::inner) _f: Option<()>, | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pub(in crate::inner) _f: Option<()>, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:27:13 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:29:13 | LL | pub _g: String, | ^^^^^^ @@ -25,7 +25,7 @@ LL | pub _g: String, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:34:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:37:9 | LL | pub _a: usize, | ^^^^^^ @@ -33,7 +33,7 @@ LL | pub _a: usize, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:41:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:45:9 | LL | pub _c: i64, | ^^^^^^ @@ -41,7 +41,7 @@ LL | pub _c: i64, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:44:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:49:9 | LL | pub _e: Option, | ^^^^^^ @@ -49,7 +49,7 @@ LL | pub _e: Option, = help: consider removing the underscore, or making the field private error: field marked as public but also inferred as unused because it's prefixed with `_` - --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:57:9 + --> tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs:63:9 | LL | pub(crate) _b: Option, | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs index 4ee8dbb883470..2c1d3cf236478 100644 --- a/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs +++ b/src/tools/clippy/tests/ui-toml/pub_underscore_fields/pub_underscore_fields.rs @@ -13,6 +13,7 @@ pub mod inner { pub struct PubSuper { pub(super) a: usize, pub _b: u8, + //~^ pub_underscore_fields _c: i32, pub _mark: marker::PhantomData, } @@ -21,10 +22,12 @@ pub mod inner { pub struct PubModVisibility { pub(in crate::inner) e: bool, pub(in crate::inner) _f: Option<()>, + //~[all_pub_fields]^ pub_underscore_fields } struct PrivateStructPubField { pub _g: String, + //~[all_pub_fields]^ pub_underscore_fields } } } @@ -32,6 +35,7 @@ pub mod inner { fn main() { pub struct StructWithOneViolation { pub _a: usize, + //~[all_pub_fields]^ pub_underscore_fields } // should handle structs with multiple violations @@ -39,9 +43,11 @@ fn main() { a: u8, _b: usize, pub _c: i64, + //~[all_pub_fields]^ pub_underscore_fields #[doc(hidden)] pub d: String, pub _e: Option, + //~[all_pub_fields]^ pub_underscore_fields } // shouldn't warn on anonymous fields @@ -55,6 +61,7 @@ fn main() { pub struct PubCrate { pub(crate) a: String, pub(crate) _b: Option, + //~[all_pub_fields]^ pub_underscore_fields } // shouldn't warn on fields named pub diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr index de9f17520ff71..7fdaa4420450a 100644 --- a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr @@ -20,13 +20,13 @@ LL | fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `exten | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the default name: `val` error: renamed function parameter of trait impl - --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31 + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:57:31 | LL | fn hash(&self, states: &mut H) { | ^^^^^^ help: consider using the default name: `state` error: renamed function parameters of trait impl - --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30 + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:61:30 | LL | fn hash_slice(date: &[Self], states: &mut H) { | ^^^^ ^^^^^^ @@ -38,7 +38,7 @@ LL + fn hash_slice(data: &[Self], state: &mut H) { | error: renamed function parameter of trait impl - --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:80:18 + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:82:18 | LL | fn add(self, b: B) -> C { | ^ help: consider using the default name: `rhs` diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr index bdc4eeaad80f4..d670026b54113 100644 --- a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr @@ -14,13 +14,13 @@ LL | fn ne(&self, rhs: &Self) -> bool { | ^^^ help: consider using the default name: `other` error: renamed function parameter of trait impl - --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31 + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:57:31 | LL | fn hash(&self, states: &mut H) { | ^^^^^^ help: consider using the default name: `state` error: renamed function parameters of trait impl - --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30 + --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:61:30 | LL | fn hash_slice(date: &[Self], states: &mut H) { | ^^^^ ^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs index f3eb910abbd67..26ca1d8609477 100644 --- a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs +++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs @@ -28,11 +28,11 @@ impl std::convert::From for String { } impl PartialEq for B { fn eq(&self, rhs: &Self) -> bool { - //~^ ERROR: renamed function parameter of trait impl + //~^ renamed_function_params self.0 == rhs.0 } fn ne(&self, rhs: &Self) -> bool { - //~^ ERROR: renamed function parameter of trait impl + //~^ renamed_function_params self.0 != rhs.0 } } @@ -46,6 +46,8 @@ trait MyTrait { impl MyTrait for B { fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `extend` + // + //~[default]^^ renamed_function_params fn bar(_a: u8, _: u8) {} fn baz(self, val: u8) {} fn quz(&self, val: u8) {} @@ -53,11 +55,11 @@ impl MyTrait for B { impl Hash for B { fn hash(&self, states: &mut H) { - //~^ ERROR: renamed function parameter of trait impl + //~^ renamed_function_params self.0.hash(states); } fn hash_slice(date: &[Self], states: &mut H) { - //~^ ERROR: renamed function parameters of trait impl + //~^ renamed_function_params for d in date { d.hash(states); } @@ -78,6 +80,7 @@ enum C { impl std::ops::Add for C { type Output = C; fn add(self, b: B) -> C { + //~[default]^ renamed_function_params // only lint in `extend` C::B(b.0) } diff --git a/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/clippy.toml b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/clippy.toml new file mode 100644 index 0000000000000..a08a2f00f5065 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/clippy.toml @@ -0,0 +1,3 @@ +disallowed-types = [ + { path = "std::string::String", replacement = "wrapper::String" }, +] diff --git a/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.fixed b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.fixed new file mode 100644 index 0000000000000..f0dab64d78c69 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.fixed @@ -0,0 +1,17 @@ +#![warn(clippy::disallowed_types)] + +#[allow(clippy::disallowed_types)] +mod wrapper { + pub struct String(std::string::String); + + impl From<&str> for String { + fn from(value: &str) -> Self { + Self(std::string::String::from(value)) + } + } +} + +fn main() { + let _ = wrapper::String::from("x"); + //~^ disallowed_types +} diff --git a/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs new file mode 100644 index 0000000000000..2585e6f90fc4c --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs @@ -0,0 +1,17 @@ +#![warn(clippy::disallowed_types)] + +#[allow(clippy::disallowed_types)] +mod wrapper { + pub struct String(std::string::String); + + impl From<&str> for String { + fn from(value: &str) -> Self { + Self(std::string::String::from(value)) + } + } +} + +fn main() { + let _ = String::from("x"); + //~^ disallowed_types +} diff --git a/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.stderr b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.stderr new file mode 100644 index 0000000000000..bb63e6970a16a --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.stderr @@ -0,0 +1,11 @@ +error: use of a disallowed type `std::string::String` + --> tests/ui-toml/replaceable_disallowed_types/replaceable_disallowed_types.rs:15:13 + | +LL | let _ = String::from("x"); + | ^^^^^^ help: use: `wrapper::String` + | + = note: `-D clippy::disallowed-types` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed index 306cd23c8239a..33f490fad6e8d 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed @@ -40,12 +40,15 @@ fn main() { unsafe { unit_fn_block() }; { unit_fn_block() }; + //~^ semicolon_outside_block unsafe { unit_fn_block() }; + //~^ semicolon_outside_block { unit_fn_block(); }; unsafe { unit_fn_block(); }; { + //~^ semicolon_inside_block unit_fn_block(); unit_fn_block(); } @@ -60,6 +63,7 @@ fn main() { { m!(()) }; { m!(()) }; + //~^ semicolon_outside_block { m!(()); }; m!(0); m!(1); diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs index b9f012cfbb0dc..8e650979e6c9d 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs @@ -40,12 +40,15 @@ fn main() { unsafe { unit_fn_block() }; { unit_fn_block(); } + //~^ semicolon_outside_block unsafe { unit_fn_block(); } + //~^ semicolon_outside_block { unit_fn_block(); }; unsafe { unit_fn_block(); }; { + //~^ semicolon_inside_block unit_fn_block(); unit_fn_block() }; @@ -60,6 +63,7 @@ fn main() { { m!(()) }; { m!(()); } + //~^ semicolon_outside_block { m!(()); }; m!(0); m!(1); diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr index 7d7749b282f0c..c2aad39b6832a 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr @@ -13,7 +13,7 @@ LL + { unit_fn_block() }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui-toml/semicolon_block/both.rs:43:5 + --> tests/ui-toml/semicolon_block/both.rs:44:5 | LL | unsafe { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,9 +25,10 @@ LL + unsafe { unit_fn_block() }; | error: consider moving the `;` inside the block for consistent formatting - --> tests/ui-toml/semicolon_block/both.rs:48:5 + --> tests/ui-toml/semicolon_block/both.rs:50:5 | LL | / { +LL | | LL | | unit_fn_block(); LL | | unit_fn_block() LL | | }; @@ -42,7 +43,7 @@ LL ~ } | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui-toml/semicolon_block/both.rs:62:5 + --> tests/ui-toml/semicolon_block/both.rs:65:5 | LL | { m!(()); } | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed index 5b7f8e00c7a00..7b1af090e9334 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed @@ -45,6 +45,7 @@ fn main() { unsafe { unit_fn_block(); }; { + //~^ semicolon_inside_block unit_fn_block(); unit_fn_block(); } diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs index 3a81661cd16f5..e243d4514da28 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs @@ -45,6 +45,7 @@ fn main() { unsafe { unit_fn_block(); }; { + //~^ semicolon_inside_block unit_fn_block(); unit_fn_block() }; diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr index b1638e40206d9..4d4e43f6b9c1f 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr @@ -2,6 +2,7 @@ error: consider moving the `;` inside the block for consistent formatting --> tests/ui-toml/semicolon_block/semicolon_inside_block.rs:47:5 | LL | / { +LL | | LL | | unit_fn_block(); LL | | unit_fn_block() LL | | }; diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed index 14604eaea7e42..f6aa49fc88682 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed @@ -39,7 +39,9 @@ fn main() { unsafe { unit_fn_block() }; { unit_fn_block() }; + //~^ semicolon_outside_block unsafe { unit_fn_block() }; + //~^ semicolon_outside_block { unit_fn_block(); }; unsafe { unit_fn_block(); }; @@ -59,6 +61,7 @@ fn main() { { m!(()) }; { m!(()) }; + //~^ semicolon_outside_block { m!(()); }; m!(0); m!(1); diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs index c767201469ab6..0d25a29627fb7 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs @@ -39,7 +39,9 @@ fn main() { unsafe { unit_fn_block() }; { unit_fn_block(); } + //~^ semicolon_outside_block unsafe { unit_fn_block(); } + //~^ semicolon_outside_block { unit_fn_block(); }; unsafe { unit_fn_block(); }; @@ -59,6 +61,7 @@ fn main() { { m!(()) }; { m!(()); } + //~^ semicolon_outside_block { m!(()); }; m!(0); m!(1); diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr index 7bcb63a6abbb1..18400da07a899 100644 --- a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr @@ -13,7 +13,7 @@ LL + { unit_fn_block() }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui-toml/semicolon_block/semicolon_outside_block.rs:42:5 + --> tests/ui-toml/semicolon_block/semicolon_outside_block.rs:43:5 | LL | unsafe { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + unsafe { unit_fn_block() }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui-toml/semicolon_block/semicolon_outside_block.rs:61:5 + --> tests/ui-toml/semicolon_block/semicolon_outside_block.rs:63:5 | LL | { m!(()); } | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs index 90c2439dc34f4..08a8e1186d5cb 100644 --- a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs +++ b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs @@ -9,6 +9,7 @@ pub struct NoGeneric { } unsafe impl Send for NoGeneric {} +//~^ non_send_fields_in_send_ty pub struct MultiField { field1: T, @@ -17,6 +18,7 @@ pub struct MultiField { } unsafe impl Send for MultiField {} +//~^ non_send_fields_in_send_ty pub enum MyOption { MySome(T), @@ -24,6 +26,7 @@ pub enum MyOption { } unsafe impl Send for MyOption {} +//~^ non_send_fields_in_send_ty // All fields are disallowed when raw pointer heuristic is off extern "C" { @@ -39,5 +42,6 @@ pub struct HeuristicTest { } unsafe impl Send for HeuristicTest {} +//~^ non_send_fields_in_send_ty fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr index bd1b75458fd13..cdb4a2f445133 100644 --- a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr +++ b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.stderr @@ -14,75 +14,75 @@ LL | rc_is_not_send: Rc, = help: to override `-D warnings` add `#[allow(clippy::non_send_fields_in_send_ty)]` error: some fields in `MultiField` are not safe to be sent to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:19:1 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:20:1 | LL | unsafe impl Send for MultiField {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `field1` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:14:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:15:5 | LL | field1: T, | ^^^^^^^^^ = help: add `T: Send` bound in `Send` impl note: it is not safe to send field `field2` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:15:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:16:5 | LL | field2: T, | ^^^^^^^^^ = help: add `T: Send` bound in `Send` impl note: it is not safe to send field `field3` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:16:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:17:5 | LL | field3: T, | ^^^^^^^^^ = help: add `T: Send` bound in `Send` impl error: some fields in `MyOption` are not safe to be sent to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:26:1 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:28:1 | LL | unsafe impl Send for MyOption {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `0` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:22:12 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:24:12 | LL | MySome(T), | ^ = help: add `T: Send` bound in `Send` impl error: some fields in `HeuristicTest` are not safe to be sent to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:41:1 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:44:1 | LL | unsafe impl Send for HeuristicTest {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: it is not safe to send field `field1` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:34:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:37:5 | LL | field1: Vec<*const NonSend>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` note: it is not safe to send field `field2` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:35:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:38:5 | LL | field2: [*const NonSend; 3], | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` note: it is not safe to send field `field3` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:36:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:39:5 | LL | field3: (*const NonSend, *const NonSend, *const NonSend), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` note: it is not safe to send field `field4` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:37:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:40:5 | LL | field4: (*const NonSend, Rc), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: use a thread-safe type that implements `Send` note: it is not safe to send field `field5` to another thread - --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:38:5 + --> tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs:41:5 | LL | field5: Vec>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.rs b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.rs index 32dd80246fab4..590cd6eeaa47b 100644 --- a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.rs +++ b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.rs @@ -1,6 +1,7 @@ #![warn(clippy::struct_excessive_bools)] struct S { + //~^ struct_excessive_bools a: bool, } diff --git a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr index ddf8ec0e52175..d70c76055df86 100644 --- a/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr +++ b/src/tools/clippy/tests/ui-toml/struct_excessive_bools/test.stderr @@ -2,6 +2,7 @@ error: more than 0 bools in a struct --> tests/ui-toml/struct_excessive_bools/test.rs:3:1 | LL | / struct S { +LL | | LL | | a: bool, LL | | } | |_^ diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs index 4613a74b85d83..b077b848837a8 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.rs @@ -25,6 +25,7 @@ fn main() { let x = [1, 2, 3, 4]; let index: usize = 1; x[index]; + //~^ indexing_slicing x[4]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. x[1 << 3]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. @@ -40,15 +41,20 @@ fn main() { let v = vec![0; 5]; v[0]; + //~^ indexing_slicing v[10]; + //~^ indexing_slicing v[1 << 3]; + //~^ indexing_slicing const N: usize = 15; // Out of bounds const M: usize = 3; // In bounds x[N]; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. x[M]; // Ok, should not produce stderr. v[N]; + //~^ indexing_slicing v[M]; + //~^ indexing_slicing } /// An opaque integer representation diff --git a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr index 120f5c35cb036..4c78a6b924cfa 100644 --- a/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr +++ b/src/tools/clippy/tests/ui-toml/suppress_lint_in_const/test.stderr @@ -9,7 +9,7 @@ LL | x[index]; = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:42:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 | LL | v[0]; | ^^^^ @@ -17,7 +17,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:43:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:45:5 | LL | v[10]; | ^^^^^ @@ -25,7 +25,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:44:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:47:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:50:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:54:5 | LL | v[N]; | ^^^^ @@ -41,7 +41,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui-toml/suppress_lint_in_const/test.rs:51:5 + --> tests/ui-toml/suppress_lint_in_const/test.rs:56:5 | LL | v[M]; | ^^^^ diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs index 2f86b3eda4c52..6555e4291959c 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs @@ -4,17 +4,24 @@ #![warn(clippy::disallowed_names)] fn test(toto: ()) {} +//~^ disallowed_names fn main() { let toto = 42; + //~^ disallowed_names let tata = 42; + //~^ disallowed_names let titi = 42; + //~^ disallowed_names let tatab = 42; let tatatataic = 42; match (42, Some(1337), Some(0)) { (toto, Some(tata), titi @ Some(_)) => (), + //~^ disallowed_names + //~| disallowed_names + //~| disallowed_names _ => (), } } diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr index 6cd0f9b0d7cb9..9096ffca27962 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr @@ -8,37 +8,37 @@ LL | fn test(toto: ()) {} = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `toto` - --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:9:9 + --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:10:9 | LL | let toto = 42; | ^^^^ error: use of a disallowed/placeholder name `tata` - --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:10:9 + --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:12:9 | LL | let tata = 42; | ^^^^ error: use of a disallowed/placeholder name `titi` - --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:11:9 + --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:14:9 | LL | let titi = 42; | ^^^^ error: use of a disallowed/placeholder name `toto` - --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:17:10 + --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:21:10 | LL | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ error: use of a disallowed/placeholder name `tata` - --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:17:21 + --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:21:21 | LL | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ error: use of a disallowed/placeholder name `titi` - --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:17:28 + --> tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs:21:28 | LL | (toto, Some(tata), titi @ Some(_)) => (), | ^^^^ diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 17fceae017801..dd170d6baf857 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -1,5 +1,3 @@ -//@compile-flags: --crate-name conf_disallowed_methods - #![allow(clippy::needless_raw_strings)] #![warn(clippy::disallowed_methods)] #![allow(clippy::useless_vec)] @@ -33,30 +31,44 @@ mod local_mod { fn main() { let re = Regex::new(r"ab.*c").unwrap(); + //~^ disallowed_methods re.is_match("abc"); + //~^ disallowed_methods let mut a = vec![1, 2, 3, 4]; a.iter().sum::(); + //~^ disallowed_methods a.sort_unstable(); + //~^ disallowed_methods // FIXME(f16_f128): add a clamp test once the function is available let _ = 2.0f32.clamp(3.0f32, 4.0f32); + //~^ disallowed_methods let _ = 2.0f64.clamp(3.0f64, 4.0f64); let indirect: fn(&str) -> Result = Regex::new; + //~^ disallowed_methods let re = indirect(".").unwrap(); let in_call = Box::new(f32::clamp); + //~^ disallowed_methods let in_method_call = ["^", "$"].into_iter().map(Regex::new); + //~^ disallowed_methods // resolve ambiguity between `futures::stream::select_all` the module and the function let same_name_as_module = select_all(vec![empty::<()>()]); + //~^ disallowed_methods local_fn(); + //~^ disallowed_methods local_mod::f(); + //~^ disallowed_methods let s = Struct; s.method(); + //~^ disallowed_methods s.provided_method(); + //~^ disallowed_methods s.implemented_method(); + //~^ disallowed_methods } diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr index e77b2b959497f..f7dda81eb936e 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr @@ -1,5 +1,5 @@ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:14 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:33:14 | LL | let re = Regex::new(r"ab.*c").unwrap(); | ^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | let re = Regex::new(r"ab.*c").unwrap(); = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` error: use of a disallowed method `regex::Regex::is_match` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:36:8 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:35:8 | LL | re.is_match("abc"); | ^^^^^^^^ @@ -22,67 +22,67 @@ LL | a.iter().sum::(); | ^^^ error: use of a disallowed method `slice::sort_unstable` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:41:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:42:7 | LL | a.sort_unstable(); | ^^^^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:44:20 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:46:20 | LL | let _ = 2.0f32.clamp(3.0f32, 4.0f32); | ^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:47:61 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:61 | LL | let indirect: fn(&str) -> Result = Regex::new; | ^^^^^^^^^^ error: use of a disallowed method `f32::clamp` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:50:28 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:28 | LL | let in_call = Box::new(f32::clamp); | ^^^^^^^^^^ error: use of a disallowed method `regex::Regex::new` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:51:53 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:53 | LL | let in_method_call = ["^", "$"].into_iter().map(Regex::new); | ^^^^^^^^^^ error: use of a disallowed method `futures::stream::select_all` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:54:31 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:31 | LL | let same_name_as_module = select_all(vec![empty::<()>()]); | ^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_fn` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:56:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:63:5 | LL | local_fn(); | ^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::local_mod::f` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:57:5 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:65:5 | LL | local_mod::f(); | ^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Struct::method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:59:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:68:7 | LL | s.method(); | ^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::provided_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:60:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:70:7 | LL | s.provided_method(); | ^^^^^^^^^^^^^^^ error: use of a disallowed method `conf_disallowed_methods::Trait::implemented_method` - --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:61:7 + --> tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs:72:7 | LL | s.implemented_method(); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs index f02bd07cfe7bf..82c9abe8beb42 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs @@ -5,40 +5,61 @@ extern crate syn; use std::sync as foo; use std::sync::atomic::AtomicU32; +//~^ disallowed_types use std::time::Instant as Sneaky; +//~^ disallowed_types struct HashMap; fn bad_return_type() -> fn() -> Sneaky { + //~^ disallowed_types todo!() } fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {} +//~^ disallowed_types +//~| disallowed_types fn trait_obj(_: &dyn std::io::Read) {} +//~^ disallowed_types fn full_and_single_path_prim(_: usize, _: bool) {} +//~^ disallowed_types +//~| disallowed_types fn const_generics() {} +//~^ disallowed_types struct GenArg([u8; U]); +//~^ disallowed_types static BAD: foo::atomic::AtomicPtr<()> = foo::atomic::AtomicPtr::new(std::ptr::null_mut()); fn ip(_: std::net::Ipv4Addr) {} +//~^ disallowed_types fn listener(_: std::net::TcpListener) {} +//~^ disallowed_types #[allow(clippy::diverging_sub_expression)] fn main() { let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); + //~^ disallowed_types + //~| disallowed_types let _ = Sneaky::now(); + //~^ disallowed_types let _ = foo::atomic::AtomicU32::new(0); + //~^ disallowed_types static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1); + //~^ disallowed_types + //~| disallowed_types let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default(); + //~^ disallowed_types let _ = syn::Ident::new("", todo!()); + //~^ disallowed_types let _ = HashMap; let _: usize = 64_usize; + //~^ disallowed_types } mod useless_attribute { diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr index 322cde15526a6..18bc36ca1e33b 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.stderr @@ -8,61 +8,61 @@ LL | use std::sync::atomic::AtomicU32; = help: to override `-D warnings` add `#[allow(clippy::disallowed_types)]` error: use of a disallowed type `std::time::Instant` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:8:1 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:9:1 | LL | use std::time::Instant as Sneaky; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `std::time::Instant` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:12:33 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:14:33 | LL | fn bad_return_type() -> fn() -> Sneaky { | ^^^^^^ error: use of a disallowed type `std::time::Instant` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:16:28 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:19:28 | LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {} | ^^^^^^ error: use of a disallowed type `std::sync::atomic::AtomicU32` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:16:39 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:19:39 | LL | fn bad_arg_type(_: impl Fn(Sneaky) -> foo::atomic::AtomicU32) {} | ^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `std::io::Read` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:18:22 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:23:22 | LL | fn trait_obj(_: &dyn std::io::Read) {} | ^^^^^^^^^^^^^ error: use of a disallowed type `std::primitive::usize` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:20:33 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:26:33 | LL | fn full_and_single_path_prim(_: usize, _: bool) {} | ^^^^^ error: use of a disallowed type `bool` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:20:43 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:26:43 | LL | fn full_and_single_path_prim(_: usize, _: bool) {} | ^^^^ error: use of a disallowed type `std::primitive::usize` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:22:28 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:30:28 | LL | fn const_generics() {} | ^^^^^ error: use of a disallowed type `std::primitive::usize` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:24:24 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:33:24 | LL | struct GenArg([u8; U]); | ^^^^^ error: use of a disallowed type `std::net::Ipv4Addr` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:28:10 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:38:10 | LL | fn ip(_: std::net::Ipv4Addr) {} | ^^^^^^^^^^^^^^^^^^ @@ -70,61 +70,61 @@ LL | fn ip(_: std::net::Ipv4Addr) {} = note: no IPv4 allowed error: use of a disallowed type `std::net::TcpListener` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:30:16 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:41:16 | LL | fn listener(_: std::net::TcpListener) {} | ^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `std::collections::HashMap` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:34:48 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:46:48 | LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `std::collections::HashMap` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:34:12 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:46:12 | LL | let _: std::collections::HashMap<(), ()> = std::collections::HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `std::time::Instant` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:35:13 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:49:13 | LL | let _ = Sneaky::now(); | ^^^^^^ error: use of a disallowed type `std::sync::atomic::AtomicU32` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:36:13 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:51:13 | LL | let _ = foo::atomic::AtomicU32::new(0); | ^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `std::sync::atomic::AtomicU32` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:37:17 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:53:17 | LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `std::sync::atomic::AtomicU32` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:37:48 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:53:48 | LL | static FOO: std::sync::atomic::AtomicU32 = foo::atomic::AtomicU32::new(1); | ^^^^^^^^^^^^^^^^^^^^^^ error: use of a disallowed type `syn::TypePath` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:38:43 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:56:43 | LL | let _: std::collections::BTreeMap<(), syn::TypePath> = Default::default(); | ^^^^^^^^^^^^^ error: use of a disallowed type `proc_macro2::Ident` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:39:13 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:58:13 | LL | let _ = syn::Ident::new("", todo!()); | ^^^^^^^^^^ error: use of a disallowed type `std::primitive::usize` - --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:41:12 + --> tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs:61:12 | LL | let _: usize = 64_usize; | ^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed index 8092e40ff9f19..d44f5fb84bd5b 100644 --- a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed +++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.fixed @@ -16,9 +16,11 @@ fn main() { let z = 1; Foo { x, y, z: z }; + //~^ inconsistent_struct_constructor Foo { x, + //~^ inconsistent_struct_constructor z: z, ..Default::default() }; @@ -35,6 +37,7 @@ mod field_attributes { BodyVisitor { macro_unsafe_blocks: Vec::new(), #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning + //~^ inconsistent_struct_constructor expn_depth: if condition { 1 } else { 0 }, }; } @@ -53,6 +56,7 @@ mod cfgs_between_fields { } let s = S { a: 3, + //~^ inconsistent_struct_constructor b: 2, #[cfg(all())] c: 1, @@ -70,6 +74,7 @@ mod cfgs_between_fields { } let s = S { a: 3, + //~^ inconsistent_struct_constructor #[cfg(any())] c: 1, b: 2, diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs index cd1aff9665282..77ac2b4e7c119 100644 --- a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs +++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs @@ -16,9 +16,11 @@ fn main() { let z = 1; Foo { y, x, z: z }; + //~^ inconsistent_struct_constructor Foo { z: z, + //~^ inconsistent_struct_constructor x, ..Default::default() }; @@ -34,6 +36,7 @@ mod field_attributes { fn check_body(condition: bool) { BodyVisitor { #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning + //~^ inconsistent_struct_constructor expn_depth: if condition { 1 } else { 0 }, macro_unsafe_blocks: Vec::new(), }; @@ -53,6 +56,7 @@ mod cfgs_between_fields { } let s = S { d: 0, + //~^ inconsistent_struct_constructor #[cfg(all())] c: 1, b: 2, @@ -70,6 +74,7 @@ mod cfgs_between_fields { } let s = S { d: 0, + //~^ inconsistent_struct_constructor #[cfg(any())] c: 1, b: 2, diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr index d2533960b84c1..be85fa5744805 100644 --- a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.stderr @@ -8,22 +8,25 @@ LL | Foo { y, x, z: z }; = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]` error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:21:9 + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:22:9 | LL | / z: z, +LL | | LL | | x, | |_________^ | help: if the field evaluation order doesn't matter, try | LL ~ x, +LL + LL ~ z: z, | error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:36:13 + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:38:13 | LL | / #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning +LL | | LL | | expn_depth: if condition { 1 } else { 0 }, LL | | macro_unsafe_blocks: Vec::new(), | |___________________________________________^ @@ -32,13 +35,15 @@ help: if the field evaluation order doesn't matter, try | LL ~ macro_unsafe_blocks: Vec::new(), LL + #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning +LL + LL ~ expn_depth: if condition { 1 } else { 0 }, | error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:55:13 + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:58:13 | LL | / d: 0, +LL | | LL | | #[cfg(all())] LL | | c: 1, LL | | b: 2, @@ -48,6 +53,7 @@ LL | | a: 3, help: if the field evaluation order doesn't matter, try | LL ~ a: 3, +LL + LL + b: 2, LL + #[cfg(all())] LL + c: 1, @@ -55,9 +61,10 @@ LL ~ d: 0, | error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:72:13 + --> tests/ui-toml/toml_inconsistent_struct_constructor/conf_inconsistent_struct_constructor.rs:76:13 | LL | / d: 0, +LL | | LL | | #[cfg(any())] LL | | c: 1, LL | | b: 2, @@ -67,6 +74,7 @@ LL | | a: 3, help: if the field evaluation order doesn't matter, try | LL ~ a: 3, +LL + LL + #[cfg(any())] LL + c: 1, LL + b: 2, diff --git a/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/clippy.toml new file mode 100644 index 0000000000000..dc393f1355b53 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/clippy.toml @@ -0,0 +1,4 @@ +disallowed-methods = [ + { path = "replaceable_disallowed_methods::bad", replacement = "good" }, + { path = "replaceable_disallowed_methods::questionable", replacement = "good", reason = "a better function exists" }, +] diff --git a/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.fixed b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.fixed new file mode 100644 index 0000000000000..df28e0bc94bec --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.fixed @@ -0,0 +1,10 @@ +fn bad() {} +fn questionable() {} +fn good() {} + +fn main() { + good(); + //~^ disallowed_methods + good(); + //~^ disallowed_methods +} diff --git a/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs new file mode 100644 index 0000000000000..9257f0e3e1a7d --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs @@ -0,0 +1,10 @@ +fn bad() {} +fn questionable() {} +fn good() {} + +fn main() { + bad(); + //~^ disallowed_methods + questionable(); + //~^ disallowed_methods +} diff --git a/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.stderr b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.stderr new file mode 100644 index 0000000000000..6f70b4ae6a9e2 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.stderr @@ -0,0 +1,17 @@ +error: use of a disallowed method `replaceable_disallowed_methods::bad` + --> tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs:6:5 + | +LL | bad(); + | ^^^ help: use: `good` + | + = note: `-D clippy::disallowed-methods` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]` + +error: use of a disallowed method `replaceable_disallowed_methods::questionable` + --> tests/ui-toml/toml_replaceable_disallowed_methods/replaceable_disallowed_methods.rs:8:5 + | +LL | questionable(); + | ^^^^^^^^^^^^ help: a better function exists: `good` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs index 145a2ce441d39..46f21eef9740c 100644 --- a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs +++ b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs @@ -13,6 +13,8 @@ struct Bar(u32); fn good(a: &mut u32, b: u32, c: &Bar, d: &u32) {} fn bad(x: &u16, y: &Foo) {} +//~^ trivially_copy_pass_by_ref +//~| trivially_copy_pass_by_ref fn main() { let (mut a, b, c, d, x, y) = (0, 0, Bar(0), 0, 0, Foo(0)); diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index 49139b60a9f43..8d02924c9d93f 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1,4 +1,6 @@ //@no-rustfix -//@error-in-other-file: unknown field `foobar`, expected one of +//@error-in-other-file: unknown field +//@error-in-other-file: error reading Clippy +//@error-in-other-file: error reading Clippy fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index 01e9f5c26a37e..acfe739277cc7 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -5,6 +5,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests allow-mixed-uninlined-format-args @@ -13,6 +14,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect allow-print-in-tests allow-private-module-inception allow-renamed-params-for + allow-unwrap-in-consts allow-unwrap-in-tests allow-useless-vec-in-tests allowed-dotfiles @@ -29,6 +31,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect await-holding-invalid-types blacklisted-names cargo-ignore-publish + check-incompatible-msrv-in-tests check-private-items cognitive-complexity-threshold cyclomatic-complexity-threshold @@ -94,6 +97,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests allow-mixed-uninlined-format-args @@ -102,6 +106,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect allow-print-in-tests allow-private-module-inception allow-renamed-params-for + allow-unwrap-in-consts allow-unwrap-in-tests allow-useless-vec-in-tests allowed-dotfiles @@ -118,6 +123,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect await-holding-invalid-types blacklisted-names cargo-ignore-publish + check-incompatible-msrv-in-tests check-private-items cognitive-complexity-threshold cyclomatic-complexity-threshold @@ -183,6 +189,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni accept-comment-above-statement allow-comparison-to-zero allow-dbg-in-tests + allow-expect-in-consts allow-expect-in-tests allow-indexing-slicing-in-tests allow-mixed-uninlined-format-args @@ -191,6 +198,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni allow-print-in-tests allow-private-module-inception allow-renamed-params-for + allow-unwrap-in-consts allow-unwrap-in-tests allow-useless-vec-in-tests allowed-dotfiles @@ -207,6 +215,7 @@ error: error reading Clippy's configuration file: unknown field `allow_mixed_uni await-holding-invalid-types blacklisted-names cargo-ignore-publish + check-incompatible-msrv-in-tests check-private-items cognitive-complexity-threshold cyclomatic-complexity-threshold diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr index 9677beeb2c24a..32ed78151d237 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.default.stderr @@ -9,7 +9,7 @@ LL | /* Safety: */ unsafe {} = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:286:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:293:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:291:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:299:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:311:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:305:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:315:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:327:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:321:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +117,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:333:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:349:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +133,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:360:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +141,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:365:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:373:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:361:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:381:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:382:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:415:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:439:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:421:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:446:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:493:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:498:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:503:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +241,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant item has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:478:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:5 | LL | // SAFETY: | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:487:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:518:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:528:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,24 +279,23 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:543:5 | LL | / let _ = { +LL | | LL | | if unsafe { true } { -LL | | todo!(); -LL | | } else { ... | LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:5 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -304,7 +303,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:549:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr index 0eccdd4280086..83a6986addf26 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.disabled.stderr @@ -9,7 +9,7 @@ LL | /* Safety: */ unsafe {} = help: to override `-D warnings` add `#[allow(clippy::undocumented_unsafe_blocks)]` error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:274:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:275:5 | LL | unsafe {} | ^^^^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:14 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:29 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:29 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:278:48 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:280:48 | LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; | ^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:18 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:18 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:282:37 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:287:37 | LL | let _ = (42, unsafe {}, "test", unsafe {}); | ^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = (42, unsafe {}, "test", unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:286:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:293:14 | LL | let _ = *unsafe { &42 }; | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = *unsafe { &42 }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:291:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:299:19 | LL | let _ = match unsafe {} { | ^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = match unsafe {} { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:297:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:306:14 | LL | let _ = &unsafe {}; | ^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _ = &unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:301:14 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:311:14 | LL | let _ = [unsafe {}; 5]; | ^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = [unsafe {}; 5]; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:305:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:316:13 | LL | let _ = unsafe {}; | ^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _ = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:315:8 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:327:8 | LL | t!(unsafe {}); | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL | t!(unsafe {}); = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:321:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:334:13 | LL | unsafe {} | ^^^^^^^^^ @@ -117,7 +117,7 @@ LL | t!(); = note: this error originates in the macro `t` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:329:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 | LL | unsafe {} // SAFETY: | ^^^^^^^^^ @@ -125,7 +125,7 @@ LL | unsafe {} // SAFETY: = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:333:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:349:5 | LL | unsafe { | ^^^^^^^^ @@ -133,7 +133,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:343:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:360:5 | LL | unsafe {}; | ^^^^^^^^^ @@ -141,7 +141,7 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:347:20 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:365:20 | LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:354:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:373:5 | LL | unsafe impl A for () {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | unsafe impl A for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:361:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:381:9 | LL | unsafe impl B for (u32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL | unsafe impl B for (u32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:382:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:403:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -189,7 +189,7 @@ LL | no_safety_comment!(()); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:415:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:439:5 | LL | unsafe impl T for (i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -197,7 +197,7 @@ LL | unsafe impl T for (i32) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:407:13 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:429:13 | LL | unsafe impl T for $t {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL | no_safety_comment!(u32); = note: this error originates in the macro `no_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:421:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:446:5 | LL | unsafe impl T for (bool) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | unsafe impl T for (bool) {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:467:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:493:5 | LL | unsafe impl NoComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL | unsafe impl NoComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:471:19 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:498:19 | LL | /* SAFETY: */ unsafe impl InlineComment for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +233,7 @@ LL | /* SAFETY: */ unsafe impl InlineComment for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:475:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:503:5 | LL | unsafe impl TrailingComment for () {} // SAFETY: | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,13 +241,13 @@ LL | unsafe impl TrailingComment for () {} // SAFETY: = help: consider adding a safety comment on the preceding line error: constant item has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:479:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 | LL | const BIG_NUMBER: i32 = 1000000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:478:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:507:5 | LL | // SAFETY: | ^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:480:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:5 | LL | unsafe impl Interference for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +263,7 @@ LL | unsafe impl Interference for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:487:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:518:5 | LL | unsafe impl ImplInFn for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | unsafe impl ImplInFn for () {} = help: consider adding a safety comment on the preceding line error: unsafe impl missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:496:1 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:528:1 | LL | unsafe impl CrateRoot for () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | unsafe impl CrateRoot for () {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:506:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:539:9 | LL | unsafe {}; | ^^^^^^^^^ @@ -287,24 +287,23 @@ LL | unsafe {}; = help: consider adding a safety comment on the preceding line error: statement has unnecessary safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:509:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:543:5 | LL | / let _ = { +LL | | LL | | if unsafe { true } { -LL | | todo!(); -LL | | } else { ... | LL | | }; | |______^ | help: consider removing the safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:508:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:542:5 | LL | // SAFETY: this is more than one level away, so it should warn | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:510:12 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:12 | LL | if unsafe { true } { | ^^^^^^^^^^^^^^^ @@ -312,7 +311,7 @@ LL | if unsafe { true } { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:513:23 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:549:23 | LL | let bar = unsafe {}; | ^^^^^^^^^ @@ -320,7 +319,7 @@ LL | let bar = unsafe {}; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:531:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:568:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +327,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:535:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:573:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -336,7 +335,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:539:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:578:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -344,7 +343,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:545:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:585:5 | LL | unsafe {} | ^^^^^^^^^ @@ -352,7 +351,7 @@ LL | unsafe {} = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:549:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:590:5 | LL | unsafe { | ^^^^^^^^ @@ -360,7 +359,7 @@ LL | unsafe { = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:556:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:598:9 | LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -368,7 +367,7 @@ LL | unsafe { a_function_with_a_very_long_name_to_break_the_line() }; = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:561:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:604:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +375,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:567:9 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:611:9 | LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -384,7 +383,7 @@ LL | unsafe { a_const_function_with_a_very_long_name_to_break_the_line() = help: consider adding a safety comment on the preceding line error: unsafe block missing a safety comment - --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:572:5 + --> tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs:617:5 | LL | unsafe {} | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs index 02170e1f74026..6a3fda3df5c38 100644 --- a/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/tests/ui-toml/undocumented_unsafe_blocks/undocumented_unsafe_blocks.rs @@ -268,41 +268,53 @@ fn in_closure(x: *const u32) { #[rustfmt::skip] fn inline_block_comment() { /* Safety: */ unsafe {} + //~^ undocumented_unsafe_blocks } fn no_comment() { unsafe {} + //~^ undocumented_unsafe_blocks } fn no_comment_array() { let _ = [unsafe { 14 }, unsafe { 15 }, 42, unsafe { 16 }]; + //~^ undocumented_unsafe_blocks + //~| undocumented_unsafe_blocks + //~| undocumented_unsafe_blocks } fn no_comment_tuple() { let _ = (42, unsafe {}, "test", unsafe {}); + //~^ undocumented_unsafe_blocks + //~| undocumented_unsafe_blocks } fn no_comment_unary() { let _ = *unsafe { &42 }; + //~^ undocumented_unsafe_blocks } #[allow(clippy::match_single_binding)] fn no_comment_match() { let _ = match unsafe {} { + //~^ undocumented_unsafe_blocks _ => {}, }; } fn no_comment_addr_of() { let _ = &unsafe {}; + //~^ undocumented_unsafe_blocks } fn no_comment_repeat() { let _ = [unsafe {}; 5]; + //~^ undocumented_unsafe_blocks } fn local_no_comment() { let _ = unsafe {}; + //~^ undocumented_unsafe_blocks } fn no_comment_macro_call() { @@ -313,12 +325,14 @@ fn no_comment_macro_call() { } t!(unsafe {}); + //~^ undocumented_unsafe_blocks } fn no_comment_macro_def() { macro_rules! t { () => { unsafe {} + //~^ undocumented_unsafe_blocks }; } @@ -327,10 +341,13 @@ fn no_comment_macro_def() { fn trailing_comment() { unsafe {} // SAFETY: + // + //~^^ undocumented_unsafe_blocks } fn internal_comment() { unsafe { + //~^ undocumented_unsafe_blocks // SAFETY: } } @@ -341,10 +358,12 @@ fn interference() { let _ = 42; unsafe {}; + //~^ undocumented_unsafe_blocks } pub fn print_binary_tree() { println!("{}", unsafe { String::from_utf8_unchecked(vec![]) }); + //~^ undocumented_unsafe_blocks } mod unsafe_impl_smoke_test { @@ -352,6 +371,7 @@ mod unsafe_impl_smoke_test { // error: no safety comment unsafe impl A for () {} + //~^ undocumented_unsafe_blocks // Safety: ok unsafe impl A for (i32) {} @@ -359,6 +379,7 @@ mod unsafe_impl_smoke_test { mod sub_mod { // error: unsafe impl B for (u32) {} + //~^ undocumented_unsafe_blocks unsafe trait B {} } @@ -380,6 +401,7 @@ mod unsafe_impl_from_macro { macro_rules! no_safety_comment { ($t:ty) => { unsafe impl T for $t {} + //~^ undocumented_unsafe_blocks }; } @@ -405,6 +427,8 @@ mod unsafe_impl_macro_and_not_macro { macro_rules! no_safety_comment { ($t:ty) => { unsafe impl T for $t {} + //~^ undocumented_unsafe_blocks + //~| undocumented_unsafe_blocks }; } @@ -413,12 +437,14 @@ mod unsafe_impl_macro_and_not_macro { // error unsafe impl T for (i32) {} + //~^ undocumented_unsafe_blocks // ok no_safety_comment!(u32); // error unsafe impl T for (bool) {} + //~^ undocumented_unsafe_blocks } #[rustfmt::skip] @@ -465,19 +491,24 @@ mod unsafe_impl_invalid_comment { unsafe trait NoComment {} unsafe impl NoComment for () {} + //~^ undocumented_unsafe_blocks unsafe trait InlineComment {} /* SAFETY: */ unsafe impl InlineComment for () {} + //~^ undocumented_unsafe_blocks unsafe trait TrailingComment {} unsafe impl TrailingComment for () {} // SAFETY: + //~^ undocumented_unsafe_blocks unsafe trait Interference {} // SAFETY: const BIG_NUMBER: i32 = 1000000; + //~^ unnecessary_safety_comment unsafe impl Interference for () {} + //~^ undocumented_unsafe_blocks } unsafe trait ImplInFn {} @@ -485,6 +516,7 @@ unsafe trait ImplInFn {} fn impl_in_fn() { // error unsafe impl ImplInFn for () {} + //~^ undocumented_unsafe_blocks // SAFETY: ok unsafe impl ImplInFn for (i32) {} @@ -494,6 +526,7 @@ unsafe trait CrateRoot {} // error unsafe impl CrateRoot for () {} +//~^ undocumented_unsafe_blocks // SAFETY: ok unsafe impl CrateRoot for (i32) {} @@ -504,13 +537,17 @@ fn nested_block_separation_issue_9142() { // we need this comment to avoid rustfmt putting // it all on one line unsafe {}; + //~[disabled]^ undocumented_unsafe_blocks // SAFETY: this is more than one level away, so it should warn let _ = { + //~^ unnecessary_safety_comment if unsafe { true } { + //~^ undocumented_unsafe_blocks todo!(); } else { let bar = unsafe {}; + //~^ undocumented_unsafe_blocks todo!(); bar } @@ -529,24 +566,29 @@ fn separate_line_from_let_issue_10832() { // SAFETY: fail ONLY if `accept-comment-above-statement = false` let _some_variable_with_a_very_long_name_to_break_the_line = unsafe { a_function_with_a_very_long_name_to_break_the_line() }; + //~[disabled]^ undocumented_unsafe_blocks // SAFETY: fail ONLY if `accept-comment-above-statement = false` const _SOME_CONST_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + //~[disabled]^ undocumented_unsafe_blocks // SAFETY: fail ONLY if `accept-comment-above-statement = false` static _SOME_STATIC_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + //~[disabled]^ undocumented_unsafe_blocks } fn above_expr_attribute_issue_8679() { // SAFETY: fail ONLY if `accept-comment-above-attribute = false` #[allow(unsafe_code)] unsafe {} + //~[disabled]^ undocumented_unsafe_blocks // SAFETY: fail ONLY if `accept-comment-above-attribute = false` #[expect(unsafe_code, reason = "totally safe")] unsafe { + //~[disabled]^ undocumented_unsafe_blocks *std::ptr::null::() }; @@ -554,22 +596,26 @@ fn above_expr_attribute_issue_8679() { #[allow(unsafe_code)] let _some_variable_with_a_very_long_name_to_break_the_line = unsafe { a_function_with_a_very_long_name_to_break_the_line() }; + //~[disabled]^ undocumented_unsafe_blocks // SAFETY: fail ONLY if `accept-comment-above-attribute = false` #[allow(unsafe_code)] const _SOME_CONST_WITH_A_VERY_LONG_NAME_TO_BREAK_THE_LINE: u32 = unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + //~[disabled]^ undocumented_unsafe_blocks // SAFETY: fail ONLY if `accept-comment-above-attribute = false` #[allow(unsafe_code)] #[allow(non_upper_case_globals)] static _some_static_with_a_very_long_name_to_break_the_line: u32 = unsafe { a_const_function_with_a_very_long_name_to_break_the_line() }; + //~[disabled]^ undocumented_unsafe_blocks // SAFETY: #[allow(unsafe_code)] // This shouldn't work either unsafe {} + //~[disabled]^ undocumented_unsafe_blocks } mod issue_11246 { diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/clippy.toml b/src/tools/clippy/tests/ui-toml/unwrap_used/clippy.toml index 154626ef4e81f..6fd1eb6f8d0d4 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/clippy.toml @@ -1 +1,2 @@ +allow-unwrap-in-consts = false allow-unwrap-in-tests = true diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed index cdb8fa0454cd4..9b4eaa208eb26 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.fixed @@ -36,23 +36,45 @@ fn main() { { // Test `get().unwrap()` let _ = &boxed_slice[1]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_slice[0]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_vec[0]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_vecdeque[0]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_hashmap[&1]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_btreemap[&1]; + //~^ get_unwrap + //~| unwrap_used #[allow(clippy::unwrap_used)] let _ = false_positive.get(0).unwrap(); // Test with deref let _: u8 = boxed_slice[1]; + //~^ get_unwrap + //~| unwrap_used } { // Test `get_mut().unwrap()` boxed_slice[0] = 1; + //~^ get_unwrap + //~| unwrap_used some_slice[0] = 1; + //~^ get_unwrap + //~| unwrap_used some_vec[0] = 1; + //~^ get_unwrap + //~| unwrap_used some_vecdeque[0] = 1; + //~^ get_unwrap + //~| unwrap_used // Check false positives #[allow(clippy::unwrap_used)] { @@ -65,7 +87,11 @@ fn main() { { // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()` let _ = some_vec[0..1].to_vec(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vec[0..1].to_vec(); + //~^ get_unwrap + //~| unwrap_used } } @@ -73,6 +99,7 @@ fn main() { fn test() { let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); let _ = &boxed_slice[1]; + //~^ get_unwrap } #[cfg(test)] @@ -92,5 +119,6 @@ mod issue9612 { let _a: u8 = 5.try_into().expect(""); // should still warn let _ = &Box::new([0])[1]; + //~^ get_unwrap } } diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs index e53d53db5f7a4..4845efa687333 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -36,23 +36,45 @@ fn main() { { // Test `get().unwrap()` let _ = boxed_slice.get(1).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_slice.get(0).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vec.get(0).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vecdeque.get(0).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_hashmap.get(&1).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_btreemap.get(&1).unwrap(); + //~^ get_unwrap + //~| unwrap_used #[allow(clippy::unwrap_used)] let _ = false_positive.get(0).unwrap(); // Test with deref let _: u8 = *boxed_slice.get(1).unwrap(); + //~^ get_unwrap + //~| unwrap_used } { // Test `get_mut().unwrap()` *boxed_slice.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used *some_slice.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used *some_vec.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used *some_vecdeque.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used // Check false positives #[allow(clippy::unwrap_used)] { @@ -65,7 +87,11 @@ fn main() { { // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()` let _ = some_vec.get(0..1).unwrap().to_vec(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vec.get_mut(0..1).unwrap().to_vec(); + //~^ get_unwrap + //~| unwrap_used } } @@ -73,6 +99,7 @@ fn main() { fn test() { let boxed_slice: Box<[u8]> = Box::new([0, 1, 2, 3]); let _ = boxed_slice.get(1).unwrap(); + //~^ get_unwrap } #[cfg(test)] @@ -92,5 +119,6 @@ mod issue9612 { let _a: u8 = 5.try_into().expect(""); // should still warn let _ = Box::new([0]).get(1).unwrap(); + //~^ get_unwrap } } diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr index 2aff276a4a12e..135e35323fdb8 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.stderr @@ -24,7 +24,7 @@ LL | let _ = boxed_slice.get(1).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` error: called `.get().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + let _ = &some_slice[0]; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:39:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | let _ = some_slice.get(0).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec - --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:44:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL + let _ = &some_vec[0]; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:40:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:44:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | let _ = some_vec.get(0).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque - --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -78,7 +78,7 @@ LL + let _ = &some_vecdeque[0]; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:41:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap - --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:50:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL + let _ = &some_hashmap[&1]; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:42:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:50:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap - --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + let _ = &some_btreemap[&1]; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:43:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:21 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:59:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -141,7 +141,7 @@ LL + let _: u8 = boxed_slice[1]; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:47:22 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:59:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:9 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:66:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL + boxed_slice[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:52:10 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:66:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -171,7 +171,7 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:9 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:69:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -183,7 +183,7 @@ LL + some_slice[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:53:10 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:69:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -192,7 +192,7 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec - --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:9 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:72:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +204,7 @@ LL + some_vec[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:54:10 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:72:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -213,7 +213,7 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque - --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:9 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:75:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -225,7 +225,7 @@ LL + some_vecdeque[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:55:10 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:75:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -234,7 +234,7 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec - --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:89:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -246,7 +246,7 @@ LL + let _ = some_vec[0..1].to_vec(); | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:67:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:89:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -255,7 +255,7 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec - --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:92:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -267,7 +267,7 @@ LL + let _ = some_vec[0..1].to_vec(); | error: used `unwrap()` on an `Option` value - --> tests/ui-toml/unwrap_used/unwrap_used.rs:68:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:92:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +276,7 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:75:13 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:101:13 | LL | let _ = boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +288,7 @@ LL + let _ = &boxed_slice[1]; | error: called `.get().unwrap()` on a slice - --> tests/ui-toml/unwrap_used/unwrap_used.rs:94:17 + --> tests/ui-toml/unwrap_used/unwrap_used.rs:121:17 | LL | let _ = Box::new([0]).get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used_const.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used_const.rs new file mode 100644 index 0000000000000..c7d8e8c1ffb5b --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used_const.rs @@ -0,0 +1,11 @@ +#![warn(clippy::unwrap_used)] + +fn main() { + const SOME: Option = Some(3); + const UNWRAPPED: i32 = SOME.unwrap(); + //~^ ERROR: used `unwrap()` on an `Option` value + const { + SOME.unwrap(); + //~^ ERROR: used `unwrap()` on an `Option` value + } +} diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used_const.stderr b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used_const.stderr new file mode 100644 index 0000000000000..362b41bc1bfff --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used_const.stderr @@ -0,0 +1,22 @@ +error: used `unwrap()` on an `Option` value + --> tests/ui-toml/unwrap_used/unwrap_used_const.rs:5:28 + | +LL | const UNWRAPPED: i32 = SOME.unwrap(); + | ^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message + = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` + +error: used `unwrap()` on an `Option` value + --> tests/ui-toml/unwrap_used/unwrap_used_const.rs:8:9 + | +LL | SOME.unwrap(); + | ^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + = help: consider using `expect()` to provide a better panic message + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.fixed b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.fixed index afb889f157f0c..4f1f9ca072739 100644 --- a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.fixed +++ b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.fixed @@ -1,24 +1,35 @@ #![warn(clippy::upper_case_acronyms)] struct HttpResponse; // not linted by default, but with cfg option +//~^ upper_case_acronyms struct CString; // not linted enum Flags { Ns, // not linted + //~^ upper_case_acronyms Cwr, + //~^ upper_case_acronyms Ece, + //~^ upper_case_acronyms Urg, + //~^ upper_case_acronyms Ack, + //~^ upper_case_acronyms Psh, + //~^ upper_case_acronyms Rst, + //~^ upper_case_acronyms Syn, + //~^ upper_case_acronyms Fin, + //~^ upper_case_acronyms } // linted with cfg option, beware that lint suggests `GccllvmSomething` instead of // `GccLlvmSomething` struct GccllvmSomething; +//~^ upper_case_acronyms // don't warn on public items pub struct MIXEDCapital; @@ -36,7 +47,9 @@ pub enum ParseError { // private, do lint here enum ParseErrorPrivate { Wasd(u8), + //~^ upper_case_acronyms WasdMixed(String), + //~^ upper_case_acronyms Utf8(std::string::FromUtf8Error), Parse(T, String), } diff --git a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs index 1a5cf1b1947c5..da522aadfdd7a 100644 --- a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs +++ b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs @@ -1,24 +1,35 @@ #![warn(clippy::upper_case_acronyms)] struct HTTPResponse; // not linted by default, but with cfg option +//~^ upper_case_acronyms struct CString; // not linted enum Flags { NS, // not linted + //~^ upper_case_acronyms CWR, + //~^ upper_case_acronyms ECE, + //~^ upper_case_acronyms URG, + //~^ upper_case_acronyms ACK, + //~^ upper_case_acronyms PSH, + //~^ upper_case_acronyms RST, + //~^ upper_case_acronyms SYN, + //~^ upper_case_acronyms FIN, + //~^ upper_case_acronyms } // linted with cfg option, beware that lint suggests `GccllvmSomething` instead of // `GccLlvmSomething` struct GCCLLVMSomething; +//~^ upper_case_acronyms // don't warn on public items pub struct MIXEDCapital; @@ -36,7 +47,9 @@ pub enum ParseError { // private, do lint here enum ParseErrorPrivate { WASD(u8), + //~^ upper_case_acronyms WASDMixed(String), + //~^ upper_case_acronyms Utf8(std::string::FromUtf8Error), Parse(T, String), } diff --git a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr index 88917603ff8ce..e1706b7472c0e 100644 --- a/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr +++ b/src/tools/clippy/tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.stderr @@ -8,73 +8,73 @@ LL | struct HTTPResponse; // not linted by default, but with cfg option = help: to override `-D warnings` add `#[allow(clippy::upper_case_acronyms)]` error: name `NS` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:8:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:9:5 | LL | NS, // not linted | ^^ help: consider making the acronym lowercase, except the initial letter (notice the capitalization): `Ns` error: name `CWR` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:9:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:11:5 | LL | CWR, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Cwr` error: name `ECE` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:10:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:13:5 | LL | ECE, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Ece` error: name `URG` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:11:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:15:5 | LL | URG, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Urg` error: name `ACK` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:12:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:17:5 | LL | ACK, | ^^^ help: consider making the acronym lowercase, except the initial letter (notice the capitalization): `Ack` error: name `PSH` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:13:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:19:5 | LL | PSH, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Psh` error: name `RST` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:14:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:21:5 | LL | RST, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Rst` error: name `SYN` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:15:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:23:5 | LL | SYN, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Syn` error: name `FIN` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:16:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:25:5 | LL | FIN, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Fin` error: name `GCCLLVMSomething` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:21:8 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:31:8 | LL | struct GCCLLVMSomething; | ^^^^^^^^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `GccllvmSomething` error: name `WASD` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:38:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:49:5 | LL | WASD(u8), | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Wasd` error: name `WASDMixed` contains a capitalized acronym - --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:39:5 + --> tests/ui-toml/upper_case_acronyms_aggressive/upper_case_acronyms.rs:51:5 | LL | WASDMixed(String), | ^^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `WasdMixed` diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed index 08323a0dcc90f..6181abc6ea576 100644 --- a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed +++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.fixed @@ -6,6 +6,7 @@ fn foo(_: &[u32]) {} fn main() { foo(&[1_u32]); + //~^ useless_vec } #[test] diff --git a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs index 1f4b27c53429d..bffdcc59752bf 100644 --- a/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs +++ b/src/tools/clippy/tests/ui-toml/useless_vec/useless_vec.rs @@ -6,6 +6,7 @@ fn foo(_: &[u32]) {} fn main() { foo(&vec![1_u32]); + //~^ useless_vec } #[test] diff --git a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.fixed b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.fixed index bb4936401ceba..423c761f1b17f 100644 --- a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.fixed +++ b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.fixed @@ -7,10 +7,13 @@ struct C { } struct Foo(Vec); +//~^ vec_box struct Bar(Vec); +//~^ vec_box struct Quux(Vec>); struct Baz(Vec>); struct BarBaz(Vec>); struct FooBarBaz(Vec); +//~^ vec_box fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.rs b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.rs index 4c46deb585b6c..fd9a13430021a 100644 --- a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.rs +++ b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.rs @@ -7,10 +7,13 @@ struct C { } struct Foo(Vec>); +//~^ vec_box struct Bar(Vec>); +//~^ vec_box struct Quux(Vec>); struct Baz(Vec>); struct BarBaz(Vec>); struct FooBarBaz(Vec>); +//~^ vec_box fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr index 8c0750d866639..b80b9492c3cae 100644 --- a/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr +++ b/src/tools/clippy/tests/ui-toml/vec_box_sized/test.stderr @@ -8,13 +8,13 @@ LL | struct Foo(Vec>); = help: to override `-D warnings` add `#[allow(clippy::vec_box)]` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui-toml/vec_box_sized/test.rs:10:12 + --> tests/ui-toml/vec_box_sized/test.rs:11:12 | LL | struct Bar(Vec>); | ^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui-toml/vec_box_sized/test.rs:14:18 + --> tests/ui-toml/vec_box_sized/test.rs:16:18 | LL | struct FooBarBaz(Vec>); | ^^^^^^^^^^^ help: try: `Vec` diff --git a/src/tools/clippy/tests/ui-toml/zero_single_char_names/zero_single_char_names.rs b/src/tools/clippy/tests/ui-toml/zero_single_char_names/zero_single_char_names.rs index 22aaa242b9b9d..d335b12d41ec9 100644 --- a/src/tools/clippy/tests/ui-toml/zero_single_char_names/zero_single_char_names.rs +++ b/src/tools/clippy/tests/ui-toml/zero_single_char_names/zero_single_char_names.rs @@ -1,3 +1,4 @@ +//@check-pass #![warn(clippy::many_single_char_names)] fn main() {} diff --git a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs index 60f2ba4abcff3..793961d30f0d6 100644 --- a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs +++ b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.rs @@ -12,46 +12,64 @@ fn main() { const Z: u32 = 0; let u: u32 = 42; u <= 0; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u <= Z; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u < Z; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + Z >= u; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + Z > u; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u > u32::MAX; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u >= u32::MAX; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u32::MAX < u; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u32::MAX <= u; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + 1-1 > u; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u >= !0; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u <= 12 - 2*6; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + let i: i8 = 0; i < -127 - 1; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + i8::MAX >= i; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + 3-7 < i32::MIN; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + let b = false; b >= true; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + false > b; - //~^ ERROR: this comparison involving the minimum or maximum element for this type con + //~^ absurd_extreme_comparisons + u > 0; // ok // this is handled by clippy::unit_cmp () < {}; - //~^ ERROR: <-comparison of unit values detected. This will always be false - //~| NOTE: `#[deny(clippy::unit_cmp)]` on by default + //~^ unit_cmp + + } use std::cmp::{Ordering, PartialEq, PartialOrd}; diff --git a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr index f98114c0000a6..6df50c15e8cd2 100644 --- a/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr +++ b/src/tools/clippy/tests/ui/absurd-extreme-comparisons.stderr @@ -9,7 +9,7 @@ LL | u <= 0; = help: to override `-D warnings` add `#[allow(clippy::absurd_extreme_comparisons)]` error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:16:5 + --> tests/ui/absurd-extreme-comparisons.rs:17:5 | LL | u <= Z; | ^^^^^^ @@ -17,7 +17,7 @@ LL | u <= Z; = help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == Z` instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:18:5 + --> tests/ui/absurd-extreme-comparisons.rs:20:5 | LL | u < Z; | ^^^^^ @@ -25,7 +25,7 @@ LL | u < Z; = help: because `Z` is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:20:5 + --> tests/ui/absurd-extreme-comparisons.rs:23:5 | LL | Z >= u; | ^^^^^^ @@ -33,7 +33,7 @@ LL | Z >= u; = help: because `Z` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `Z == u` instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:22:5 + --> tests/ui/absurd-extreme-comparisons.rs:26:5 | LL | Z > u; | ^^^^^ @@ -41,7 +41,7 @@ LL | Z > u; = help: because `Z` is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:24:5 + --> tests/ui/absurd-extreme-comparisons.rs:29:5 | LL | u > u32::MAX; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | u > u32::MAX; = help: because `u32::MAX` is the maximum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:26:5 + --> tests/ui/absurd-extreme-comparisons.rs:32:5 | LL | u >= u32::MAX; | ^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | u >= u32::MAX; = help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == u32::MAX` instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:28:5 + --> tests/ui/absurd-extreme-comparisons.rs:35:5 | LL | u32::MAX < u; | ^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | u32::MAX < u; = help: because `u32::MAX` is the maximum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:30:5 + --> tests/ui/absurd-extreme-comparisons.rs:38:5 | LL | u32::MAX <= u; | ^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | u32::MAX <= u; = help: because `u32::MAX` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u32::MAX == u` instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:32:5 + --> tests/ui/absurd-extreme-comparisons.rs:41:5 | LL | 1-1 > u; | ^^^^^^^ @@ -81,7 +81,7 @@ LL | 1-1 > u; = help: because `1-1` is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:34:5 + --> tests/ui/absurd-extreme-comparisons.rs:44:5 | LL | u >= !0; | ^^^^^^^ @@ -89,7 +89,7 @@ LL | u >= !0; = help: because `!0` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `u == !0` instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:36:5 + --> tests/ui/absurd-extreme-comparisons.rs:47:5 | LL | u <= 12 - 2*6; | ^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | u <= 12 - 2*6; = help: because `12 - 2*6` is the minimum value for this type, the case where the two sides are not equal never occurs, consider using `u == 12 - 2*6` instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:39:5 + --> tests/ui/absurd-extreme-comparisons.rs:51:5 | LL | i < -127 - 1; | ^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | i < -127 - 1; = help: because `-127 - 1` is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:41:5 + --> tests/ui/absurd-extreme-comparisons.rs:54:5 | LL | i8::MAX >= i; | ^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | i8::MAX >= i; = help: because `i8::MAX` is the maximum value for this type, this comparison is always true error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:43:5 + --> tests/ui/absurd-extreme-comparisons.rs:57:5 | LL | 3-7 < i32::MIN; | ^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | 3-7 < i32::MIN; = help: because `i32::MIN` is the minimum value for this type, this comparison is always false error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:46:5 + --> tests/ui/absurd-extreme-comparisons.rs:61:5 | LL | b >= true; | ^^^^^^^^^ @@ -129,7 +129,7 @@ LL | b >= true; = help: because `true` is the maximum value for this type, the case where the two sides are not equal never occurs, consider using `b == true` instead error: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false - --> tests/ui/absurd-extreme-comparisons.rs:48:5 + --> tests/ui/absurd-extreme-comparisons.rs:64:5 | LL | false > b; | ^^^^^^^^^ @@ -137,7 +137,7 @@ LL | false > b; = help: because `false` is the minimum value for this type, this comparison is always false error: <-comparison of unit values detected. This will always be false - --> tests/ui/absurd-extreme-comparisons.rs:52:5 + --> tests/ui/absurd-extreme-comparisons.rs:69:5 | LL | () < {}; | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed index 8f6c962e2f5b4..56a98cca3404c 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.fixed +++ b/src/tools/clippy/tests/ui/allow_attributes.fixed @@ -11,6 +11,7 @@ use proc_macros::{external, with_span}; // Should lint #[expect(dead_code)] +//~^ allow_attributes struct T1; struct T2; // Should not lint @@ -20,6 +21,7 @@ struct T3; struct T4; // `panic = "unwind"` should always be true #[cfg_attr(panic = "unwind", expect(dead_code))] +//~^ allow_attributes struct CfgT; #[allow(clippy::allow_attributes, unused)] @@ -51,6 +53,7 @@ fn ignore_inner_attr() { #[clippy::msrv = "1.81"] fn msrv_1_81() { #[expect(unused)] + //~^ allow_attributes let x = 1; } diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs index cb6c4dcf71587..65a0a6b5a108c 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.rs +++ b/src/tools/clippy/tests/ui/allow_attributes.rs @@ -11,6 +11,7 @@ use proc_macros::{external, with_span}; // Should lint #[allow(dead_code)] +//~^ allow_attributes struct T1; struct T2; // Should not lint @@ -20,6 +21,7 @@ struct T3; struct T4; // `panic = "unwind"` should always be true #[cfg_attr(panic = "unwind", allow(dead_code))] +//~^ allow_attributes struct CfgT; #[allow(clippy::allow_attributes, unused)] @@ -51,6 +53,7 @@ fn ignore_inner_attr() { #[clippy::msrv = "1.81"] fn msrv_1_81() { #[allow(unused)] + //~^ allow_attributes let x = 1; } diff --git a/src/tools/clippy/tests/ui/allow_attributes.stderr b/src/tools/clippy/tests/ui/allow_attributes.stderr index 5a4ff287acd29..dd5fb21ffeaf5 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes.stderr @@ -8,13 +8,13 @@ LL | #[allow(dead_code)] = help: to override `-D warnings` add `#[allow(clippy::allow_attributes)]` error: #[allow] attribute found - --> tests/ui/allow_attributes.rs:22:30 + --> tests/ui/allow_attributes.rs:23:30 | LL | #[cfg_attr(panic = "unwind", allow(dead_code))] | ^^^^^ help: replace it with: `expect` error: #[allow] attribute found - --> tests/ui/allow_attributes.rs:53:7 + --> tests/ui/allow_attributes.rs:55:7 | LL | #[allow(unused)] | ^^^^^ help: replace it with: `expect` diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs index 334e7ddd9d233..ea89511ebb46d 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.rs @@ -1,14 +1,18 @@ //@aux-build:proc_macros.rs #![deny(clippy::allow_attributes_without_reason)] #![allow(unfulfilled_lint_expectations, clippy::duplicated_attributes)] +//~^ allow_attributes_without_reason extern crate proc_macros; use proc_macros::{external, with_span}; // These should trigger the lint #[allow(dead_code)] +//~^ allow_attributes_without_reason #[allow(dead_code, deprecated)] +//~^ allow_attributes_without_reason #[expect(dead_code)] +//~^ allow_attributes_without_reason // These should be fine #[allow(dead_code, reason = "This should be allowed")] #[warn(dyn_drop, reason = "Warnings can also have reasons")] @@ -44,6 +48,7 @@ pub fn trigger_fp_result() -> Result<(), &'static str> { #[clippy::msrv = "1.81"] fn msrv_1_81() { #[allow(unused)] + //~^ allow_attributes_without_reason let _ = 1; } diff --git a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr index 9c1ac5af91b06..07e74839b7696 100644 --- a/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr +++ b/src/tools/clippy/tests/ui/allow_attributes_without_reason.stderr @@ -12,7 +12,7 @@ LL | #![deny(clippy::allow_attributes_without_reason)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:9:1 + --> tests/ui/allow_attributes_without_reason.rs:10:1 | LL | #[allow(dead_code)] | ^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | #[allow(dead_code)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:10:1 + --> tests/ui/allow_attributes_without_reason.rs:12:1 | LL | #[allow(dead_code, deprecated)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | #[allow(dead_code, deprecated)] = help: try adding a reason at the end with `, reason = ".."` error: `expect` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:11:1 + --> tests/ui/allow_attributes_without_reason.rs:14:1 | LL | #[expect(dead_code)] | ^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | #[expect(dead_code)] = help: try adding a reason at the end with `, reason = ".."` error: `allow` attribute without specifying a reason - --> tests/ui/allow_attributes_without_reason.rs:46:5 + --> tests/ui/allow_attributes_without_reason.rs:50:5 | LL | #[allow(unused)] | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/almost_complete_range.fixed b/src/tools/clippy/tests/ui/almost_complete_range.fixed index 6c2b2f117437d..7591508b83508 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.fixed +++ b/src/tools/clippy/tests/ui/almost_complete_range.fixed @@ -15,8 +15,11 @@ fn main() { #[rustfmt::skip] { let _ = ('a') ..='z'; + //~^ almost_complete_range let _ = 'A' ..= ('Z'); + //~^ almost_complete_range let _ = ((('0'))) ..= ('9'); + //~^ almost_complete_range } let _ = 'b'..'z'; @@ -24,21 +27,30 @@ fn main() { let _ = '1'..'9'; let _ = (b'a')..=(b'z'); + //~^ almost_complete_range let _ = b'A'..=b'Z'; + //~^ almost_complete_range let _ = b'0'..=b'9'; + //~^ almost_complete_range let _ = b'b'..b'z'; let _ = b'B'..b'Z'; let _ = b'1'..b'9'; let _ = inline!('a')..='z'; + //~^ almost_complete_range let _ = inline!('A')..='Z'; + //~^ almost_complete_range let _ = inline!('0')..='9'; + //~^ almost_complete_range let _ = match 0u8 { b'a'..=b'z' if true => 1, + //~^ almost_complete_range b'A'..=b'Z' if true => 2, + //~^ almost_complete_range b'0'..=b'9' if true => 3, + //~^ almost_complete_range b'b'..b'z' => 4, b'B'..b'Z' => 5, b'1'..b'9' => 6, @@ -47,8 +59,11 @@ fn main() { let _ = match 'x' { 'a'..='z' if true => 1, + //~^ almost_complete_range 'A'..='Z' if true => 2, + //~^ almost_complete_range '0'..='9' if true => 3, + //~^ almost_complete_range 'b'..'z' => 4, 'B'..'Z' => 5, '1'..'9' => 6, @@ -62,8 +77,11 @@ fn main() { ); inline!( let _ = 'a'..='z'; + //~^ almost_complete_range let _ = 'A'..='Z'; + //~^ almost_complete_range let _ = '0'..='9'; + //~^ almost_complete_range ); } @@ -71,8 +89,11 @@ fn main() { fn _under_msrv() { let _ = match 'a' { 'a'...'z' => 1, + //~^ almost_complete_range 'A'...'Z' => 2, + //~^ almost_complete_range '0'...'9' => 3, + //~^ almost_complete_range _ => 4, }; } @@ -80,12 +101,18 @@ fn _under_msrv() { #[clippy::msrv = "1.26"] fn _meets_msrv() { let _ = 'a'..='z'; + //~^ almost_complete_range let _ = 'A'..='Z'; + //~^ almost_complete_range let _ = '0'..='9'; + //~^ almost_complete_range let _ = match 'a' { 'a'..='z' => 1, + //~^ almost_complete_range 'A'..='Z' => 1, + //~^ almost_complete_range '0'..='9' => 3, + //~^ almost_complete_range _ => 4, }; } diff --git a/src/tools/clippy/tests/ui/almost_complete_range.rs b/src/tools/clippy/tests/ui/almost_complete_range.rs index 813668a530966..907f70bd8156b 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.rs +++ b/src/tools/clippy/tests/ui/almost_complete_range.rs @@ -15,8 +15,11 @@ fn main() { #[rustfmt::skip] { let _ = ('a') ..'z'; + //~^ almost_complete_range let _ = 'A' .. ('Z'); + //~^ almost_complete_range let _ = ((('0'))) .. ('9'); + //~^ almost_complete_range } let _ = 'b'..'z'; @@ -24,21 +27,30 @@ fn main() { let _ = '1'..'9'; let _ = (b'a')..(b'z'); + //~^ almost_complete_range let _ = b'A'..b'Z'; + //~^ almost_complete_range let _ = b'0'..b'9'; + //~^ almost_complete_range let _ = b'b'..b'z'; let _ = b'B'..b'Z'; let _ = b'1'..b'9'; let _ = inline!('a')..'z'; + //~^ almost_complete_range let _ = inline!('A')..'Z'; + //~^ almost_complete_range let _ = inline!('0')..'9'; + //~^ almost_complete_range let _ = match 0u8 { b'a'..b'z' if true => 1, + //~^ almost_complete_range b'A'..b'Z' if true => 2, + //~^ almost_complete_range b'0'..b'9' if true => 3, + //~^ almost_complete_range b'b'..b'z' => 4, b'B'..b'Z' => 5, b'1'..b'9' => 6, @@ -47,8 +59,11 @@ fn main() { let _ = match 'x' { 'a'..'z' if true => 1, + //~^ almost_complete_range 'A'..'Z' if true => 2, + //~^ almost_complete_range '0'..'9' if true => 3, + //~^ almost_complete_range 'b'..'z' => 4, 'B'..'Z' => 5, '1'..'9' => 6, @@ -62,8 +77,11 @@ fn main() { ); inline!( let _ = 'a'..'z'; + //~^ almost_complete_range let _ = 'A'..'Z'; + //~^ almost_complete_range let _ = '0'..'9'; + //~^ almost_complete_range ); } @@ -71,8 +89,11 @@ fn main() { fn _under_msrv() { let _ = match 'a' { 'a'..'z' => 1, + //~^ almost_complete_range 'A'..'Z' => 2, + //~^ almost_complete_range '0'..'9' => 3, + //~^ almost_complete_range _ => 4, }; } @@ -80,12 +101,18 @@ fn _under_msrv() { #[clippy::msrv = "1.26"] fn _meets_msrv() { let _ = 'a'..'z'; + //~^ almost_complete_range let _ = 'A'..'Z'; + //~^ almost_complete_range let _ = '0'..'9'; + //~^ almost_complete_range let _ = match 'a' { 'a'..'z' => 1, + //~^ almost_complete_range 'A'..'Z' => 1, + //~^ almost_complete_range '0'..'9' => 3, + //~^ almost_complete_range _ => 4, }; } diff --git a/src/tools/clippy/tests/ui/almost_complete_range.stderr b/src/tools/clippy/tests/ui/almost_complete_range.stderr index bfc2beb07d857..217df7f4883f5 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.stderr +++ b/src/tools/clippy/tests/ui/almost_complete_range.stderr @@ -10,7 +10,7 @@ LL | let _ = ('a') ..'z'; = help: to override `-D warnings` add `#[allow(clippy::almost_complete_range)]` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:18:17 + --> tests/ui/almost_complete_range.rs:19:17 | LL | let _ = 'A' .. ('Z'); | ^^^^--^^^^^^ @@ -18,7 +18,7 @@ LL | let _ = 'A' .. ('Z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:19:17 + --> tests/ui/almost_complete_range.rs:21:17 | LL | let _ = ((('0'))) .. ('9'); | ^^^^^^^^^^--^^^^^^ @@ -26,7 +26,7 @@ LL | let _ = ((('0'))) .. ('9'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:26:13 + --> tests/ui/almost_complete_range.rs:29:13 | LL | let _ = (b'a')..(b'z'); | ^^^^^^--^^^^^^ @@ -34,7 +34,7 @@ LL | let _ = (b'a')..(b'z'); | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:27:13 + --> tests/ui/almost_complete_range.rs:31:13 | LL | let _ = b'A'..b'Z'; | ^^^^--^^^^ @@ -42,7 +42,7 @@ LL | let _ = b'A'..b'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:28:13 + --> tests/ui/almost_complete_range.rs:33:13 | LL | let _ = b'0'..b'9'; | ^^^^--^^^^ @@ -50,7 +50,7 @@ LL | let _ = b'0'..b'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:34:13 + --> tests/ui/almost_complete_range.rs:40:13 | LL | let _ = inline!('a')..'z'; | ^^^^^^^^^^^^--^^^ @@ -58,7 +58,7 @@ LL | let _ = inline!('a')..'z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:35:13 + --> tests/ui/almost_complete_range.rs:42:13 | LL | let _ = inline!('A')..'Z'; | ^^^^^^^^^^^^--^^^ @@ -66,7 +66,7 @@ LL | let _ = inline!('A')..'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:36:13 + --> tests/ui/almost_complete_range.rs:44:13 | LL | let _ = inline!('0')..'9'; | ^^^^^^^^^^^^--^^^ @@ -74,7 +74,7 @@ LL | let _ = inline!('0')..'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:39:9 + --> tests/ui/almost_complete_range.rs:48:9 | LL | b'a'..b'z' if true => 1, | ^^^^--^^^^ @@ -82,7 +82,7 @@ LL | b'a'..b'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:40:9 + --> tests/ui/almost_complete_range.rs:50:9 | LL | b'A'..b'Z' if true => 2, | ^^^^--^^^^ @@ -90,7 +90,7 @@ LL | b'A'..b'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:41:9 + --> tests/ui/almost_complete_range.rs:52:9 | LL | b'0'..b'9' if true => 3, | ^^^^--^^^^ @@ -98,7 +98,7 @@ LL | b'0'..b'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:49:9 + --> tests/ui/almost_complete_range.rs:61:9 | LL | 'a'..'z' if true => 1, | ^^^--^^^ @@ -106,7 +106,7 @@ LL | 'a'..'z' if true => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:50:9 + --> tests/ui/almost_complete_range.rs:63:9 | LL | 'A'..'Z' if true => 2, | ^^^--^^^ @@ -114,7 +114,7 @@ LL | 'A'..'Z' if true => 2, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:51:9 + --> tests/ui/almost_complete_range.rs:65:9 | LL | '0'..'9' if true => 3, | ^^^--^^^ @@ -122,7 +122,7 @@ LL | '0'..'9' if true => 3, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:64:17 + --> tests/ui/almost_complete_range.rs:79:17 | LL | let _ = 'a'..'z'; | ^^^--^^^ @@ -132,7 +132,7 @@ LL | let _ = 'a'..'z'; = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:65:17 + --> tests/ui/almost_complete_range.rs:81:17 | LL | let _ = 'A'..'Z'; | ^^^--^^^ @@ -142,7 +142,7 @@ LL | let _ = 'A'..'Z'; = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:66:17 + --> tests/ui/almost_complete_range.rs:83:17 | LL | let _ = '0'..'9'; | ^^^--^^^ @@ -152,7 +152,7 @@ LL | let _ = '0'..'9'; = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:73:9 + --> tests/ui/almost_complete_range.rs:91:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -160,7 +160,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `...` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:74:9 + --> tests/ui/almost_complete_range.rs:93:9 | LL | 'A'..'Z' => 2, | ^^^--^^^ @@ -168,7 +168,7 @@ LL | 'A'..'Z' => 2, | help: use an inclusive range: `...` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:75:9 + --> tests/ui/almost_complete_range.rs:95:9 | LL | '0'..'9' => 3, | ^^^--^^^ @@ -176,7 +176,7 @@ LL | '0'..'9' => 3, | help: use an inclusive range: `...` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:82:13 + --> tests/ui/almost_complete_range.rs:103:13 | LL | let _ = 'a'..'z'; | ^^^--^^^ @@ -184,7 +184,7 @@ LL | let _ = 'a'..'z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:83:13 + --> tests/ui/almost_complete_range.rs:105:13 | LL | let _ = 'A'..'Z'; | ^^^--^^^ @@ -192,7 +192,7 @@ LL | let _ = 'A'..'Z'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:84:13 + --> tests/ui/almost_complete_range.rs:107:13 | LL | let _ = '0'..'9'; | ^^^--^^^ @@ -200,7 +200,7 @@ LL | let _ = '0'..'9'; | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:86:9 + --> tests/ui/almost_complete_range.rs:110:9 | LL | 'a'..'z' => 1, | ^^^--^^^ @@ -208,7 +208,7 @@ LL | 'a'..'z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:87:9 + --> tests/ui/almost_complete_range.rs:112:9 | LL | 'A'..'Z' => 1, | ^^^--^^^ @@ -216,7 +216,7 @@ LL | 'A'..'Z' => 1, | help: use an inclusive range: `..=` error: almost complete ascii range - --> tests/ui/almost_complete_range.rs:88:9 + --> tests/ui/almost_complete_range.rs:114:9 | LL | '0'..'9' => 3, | ^^^--^^^ diff --git a/src/tools/clippy/tests/ui/approx_const.rs b/src/tools/clippy/tests/ui/approx_const.rs index 3c4ed03678941..6461666be8f5c 100644 --- a/src/tools/clippy/tests/ui/approx_const.rs +++ b/src/tools/clippy/tests/ui/approx_const.rs @@ -1,86 +1,109 @@ #[warn(clippy::approx_constant)] fn main() { let my_e = 2.7182; - //~^ ERROR: approximate value of `f{32, 64}::consts::E` found + //~^ approx_constant + let almost_e = 2.718; - //~^ ERROR: approximate value of `f{32, 64}::consts::E` found + //~^ approx_constant + let no_e = 2.71; let my_1_frac_pi = 0.3183; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_1_PI` found + //~^ approx_constant + let no_1_frac_pi = 0.31; let my_frac_1_sqrt_2 = 0.70710678; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found + //~^ approx_constant + let almost_frac_1_sqrt_2 = 0.70711; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found + //~^ approx_constant + let my_frac_1_sqrt_2 = 0.707; let my_frac_2_pi = 0.63661977; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_2_PI` found + //~^ approx_constant + let no_frac_2_pi = 0.636; let my_frac_2_sq_pi = 1.128379; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found + //~^ approx_constant + let no_frac_2_sq_pi = 1.128; let my_frac_pi_2 = 1.57079632679; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_2` found + //~^ approx_constant + let no_frac_pi_2 = 1.5705; let my_frac_pi_3 = 1.04719755119; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_3` found + //~^ approx_constant + let no_frac_pi_3 = 1.047; let my_frac_pi_4 = 0.785398163397; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_4` found + //~^ approx_constant + let no_frac_pi_4 = 0.785; let my_frac_pi_6 = 0.523598775598; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_6` found + //~^ approx_constant + let no_frac_pi_6 = 0.523; let my_frac_pi_8 = 0.3926990816987; - //~^ ERROR: approximate value of `f{32, 64}::consts::FRAC_PI_8` found + //~^ approx_constant + let no_frac_pi_8 = 0.392; let my_ln_10 = 2.302585092994046; - //~^ ERROR: approximate value of `f{32, 64}::consts::LN_10` found + //~^ approx_constant + let no_ln_10 = 2.303; let my_ln_2 = 0.6931471805599453; - //~^ ERROR: approximate value of `f{32, 64}::consts::LN_2` found + //~^ approx_constant + let no_ln_2 = 0.693; let my_log10_e = 0.4342944819032518; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG10_E` found + //~^ approx_constant + let no_log10_e = 0.434; let my_log2_e = 1.4426950408889634; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_E` found + //~^ approx_constant + let no_log2_e = 1.442; let log2_10 = 3.321928094887362; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found + //~^ approx_constant + let no_log2_10 = 3.321; let log10_2 = 0.301029995663981; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG10_2` found + //~^ approx_constant + let no_log10_2 = 0.301; let my_pi = 3.1415; - //~^ ERROR: approximate value of `f{32, 64}::consts::PI` found + //~^ approx_constant + let almost_pi = 3.14; - //~^ ERROR: approximate value of `f{32, 64}::consts::PI` found + //~^ approx_constant + let no_pi = 3.15; let my_sq2 = 1.4142; - //~^ ERROR: approximate value of `f{32, 64}::consts::SQRT_2` found + //~^ approx_constant + let no_sq2 = 1.414; let my_tau = 6.2832; - //~^ ERROR: approximate value of `f{32, 64}::consts::TAU` found + //~^ approx_constant + let almost_tau = 6.28; - //~^ ERROR: approximate value of `f{32, 64}::consts::TAU` found + //~^ approx_constant + let no_tau = 6.3; } diff --git a/src/tools/clippy/tests/ui/approx_const.stderr b/src/tools/clippy/tests/ui/approx_const.stderr index 5e82d51edf208..f7bda0468cbdc 100644 --- a/src/tools/clippy/tests/ui/approx_const.stderr +++ b/src/tools/clippy/tests/ui/approx_const.stderr @@ -9,7 +9,7 @@ LL | let my_e = 2.7182; = help: to override `-D warnings` add `#[allow(clippy::approx_constant)]` error: approximate value of `f{32, 64}::consts::E` found - --> tests/ui/approx_const.rs:5:20 + --> tests/ui/approx_const.rs:6:20 | LL | let almost_e = 2.718; | ^^^^^ @@ -17,7 +17,7 @@ LL | let almost_e = 2.718; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_1_PI` found - --> tests/ui/approx_const.rs:9:24 + --> tests/ui/approx_const.rs:11:24 | LL | let my_1_frac_pi = 0.3183; | ^^^^^^ @@ -25,7 +25,7 @@ LL | let my_1_frac_pi = 0.3183; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found - --> tests/ui/approx_const.rs:13:28 + --> tests/ui/approx_const.rs:16:28 | LL | let my_frac_1_sqrt_2 = 0.70710678; | ^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let my_frac_1_sqrt_2 = 0.70710678; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_1_SQRT_2` found - --> tests/ui/approx_const.rs:15:32 + --> tests/ui/approx_const.rs:19:32 | LL | let almost_frac_1_sqrt_2 = 0.70711; | ^^^^^^^ @@ -41,7 +41,7 @@ LL | let almost_frac_1_sqrt_2 = 0.70711; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_2_PI` found - --> tests/ui/approx_const.rs:19:24 + --> tests/ui/approx_const.rs:24:24 | LL | let my_frac_2_pi = 0.63661977; | ^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let my_frac_2_pi = 0.63661977; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_2_SQRT_PI` found - --> tests/ui/approx_const.rs:23:27 + --> tests/ui/approx_const.rs:29:27 | LL | let my_frac_2_sq_pi = 1.128379; | ^^^^^^^^ @@ -57,7 +57,7 @@ LL | let my_frac_2_sq_pi = 1.128379; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_PI_2` found - --> tests/ui/approx_const.rs:27:24 + --> tests/ui/approx_const.rs:34:24 | LL | let my_frac_pi_2 = 1.57079632679; | ^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let my_frac_pi_2 = 1.57079632679; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_PI_3` found - --> tests/ui/approx_const.rs:31:24 + --> tests/ui/approx_const.rs:39:24 | LL | let my_frac_pi_3 = 1.04719755119; | ^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let my_frac_pi_3 = 1.04719755119; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_PI_4` found - --> tests/ui/approx_const.rs:35:24 + --> tests/ui/approx_const.rs:44:24 | LL | let my_frac_pi_4 = 0.785398163397; | ^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let my_frac_pi_4 = 0.785398163397; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_PI_6` found - --> tests/ui/approx_const.rs:39:24 + --> tests/ui/approx_const.rs:49:24 | LL | let my_frac_pi_6 = 0.523598775598; | ^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let my_frac_pi_6 = 0.523598775598; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::FRAC_PI_8` found - --> tests/ui/approx_const.rs:43:24 + --> tests/ui/approx_const.rs:54:24 | LL | let my_frac_pi_8 = 0.3926990816987; | ^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let my_frac_pi_8 = 0.3926990816987; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LN_10` found - --> tests/ui/approx_const.rs:47:20 + --> tests/ui/approx_const.rs:59:20 | LL | let my_ln_10 = 2.302585092994046; | ^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | let my_ln_10 = 2.302585092994046; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LN_2` found - --> tests/ui/approx_const.rs:51:19 + --> tests/ui/approx_const.rs:64:19 | LL | let my_ln_2 = 0.6931471805599453; | ^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | let my_ln_2 = 0.6931471805599453; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG10_E` found - --> tests/ui/approx_const.rs:55:22 + --> tests/ui/approx_const.rs:69:22 | LL | let my_log10_e = 0.4342944819032518; | ^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | let my_log10_e = 0.4342944819032518; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG2_E` found - --> tests/ui/approx_const.rs:59:21 + --> tests/ui/approx_const.rs:74:21 | LL | let my_log2_e = 1.4426950408889634; | ^^^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | let my_log2_e = 1.4426950408889634; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG2_10` found - --> tests/ui/approx_const.rs:63:19 + --> tests/ui/approx_const.rs:79:19 | LL | let log2_10 = 3.321928094887362; | ^^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | let log2_10 = 3.321928094887362; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::LOG10_2` found - --> tests/ui/approx_const.rs:67:19 + --> tests/ui/approx_const.rs:84:19 | LL | let log10_2 = 0.301029995663981; | ^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | let log10_2 = 0.301029995663981; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::PI` found - --> tests/ui/approx_const.rs:71:17 + --> tests/ui/approx_const.rs:89:17 | LL | let my_pi = 3.1415; | ^^^^^^ @@ -153,7 +153,7 @@ LL | let my_pi = 3.1415; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::PI` found - --> tests/ui/approx_const.rs:73:21 + --> tests/ui/approx_const.rs:92:21 | LL | let almost_pi = 3.14; | ^^^^ @@ -161,7 +161,7 @@ LL | let almost_pi = 3.14; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::SQRT_2` found - --> tests/ui/approx_const.rs:77:18 + --> tests/ui/approx_const.rs:97:18 | LL | let my_sq2 = 1.4142; | ^^^^^^ @@ -169,7 +169,7 @@ LL | let my_sq2 = 1.4142; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::TAU` found - --> tests/ui/approx_const.rs:81:18 + --> tests/ui/approx_const.rs:102:18 | LL | let my_tau = 6.2832; | ^^^^^^ @@ -177,7 +177,7 @@ LL | let my_tau = 6.2832; = help: consider using the constant directly error: approximate value of `f{32, 64}::consts::TAU` found - --> tests/ui/approx_const.rs:83:22 + --> tests/ui/approx_const.rs:105:22 | LL | let almost_tau = 6.28; | ^^^^ diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs index c287480bb1fd5..07025ccc42fd1 100644 --- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs +++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.rs @@ -33,9 +33,12 @@ fn main() { let _ = Arc::new(42); let _ = Arc::new(RefCell::new(42)); + //~^ arc_with_non_send_sync let mutex = Mutex::new(1); let _ = Arc::new(mutex.lock().unwrap()); + //~^ arc_with_non_send_sync let _ = Arc::new(&42 as *const i32); + //~^ arc_with_non_send_sync } diff --git a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr index da363a3ebdd98..5556b0df88c91 100644 --- a/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr +++ b/src/tools/clippy/tests/ui/arc_with_non_send_sync.stderr @@ -11,7 +11,7 @@ LL | let _ = Arc::new(RefCell::new(42)); = help: to override `-D warnings` add `#[allow(clippy::arc_with_non_send_sync)]` error: usage of an `Arc` that is not `Send` and `Sync` - --> tests/ui/arc_with_non_send_sync.rs:38:13 + --> tests/ui/arc_with_non_send_sync.rs:39:13 | LL | let _ = Arc::new(mutex.lock().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | let _ = Arc::new(mutex.lock().unwrap()); = help: otherwise make `MutexGuard<'_, i32>` `Send` and `Sync` or consider a wrapper type such as `Mutex` error: usage of an `Arc` that is not `Send` and `Sync` - --> tests/ui/arc_with_non_send_sync.rs:40:13 + --> tests/ui/arc_with_non_send_sync.rs:42:13 | LL | let _ = Arc::new(&42 as *const i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index f09106773c7ee..21be2af201f07 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -164,13 +164,16 @@ pub fn association_with_structures_should_not_trigger_the_lint() { pub fn hard_coded_allowed() { let _ = 1f16 + 1f16; + //~^ arithmetic_side_effects let _ = 1f32 + 1f32; let _ = 1f64 + 1f64; let _ = 1f128 + 1f128; + //~^ arithmetic_side_effects let _ = Saturating(0u32) + Saturating(0u32); let _ = String::new() + ""; let _ = String::new() + &String::new(); + //~^ arithmetic_side_effects let _ = Wrapping(0u32) + Wrapping(0u32); let saturating: Saturating = Saturating(0u32); @@ -306,117 +309,221 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() { // Assign _n += 1; + //~^ arithmetic_side_effects _n += &1; + //~^ arithmetic_side_effects _n -= 1; + //~^ arithmetic_side_effects _n -= &1; + //~^ arithmetic_side_effects _n /= 0; + //~^ arithmetic_side_effects _n /= &0; + //~^ arithmetic_side_effects _n %= 0; + //~^ arithmetic_side_effects _n %= &0; + //~^ arithmetic_side_effects _n *= 2; + //~^ arithmetic_side_effects _n *= &2; + //~^ arithmetic_side_effects _n += -1; + //~^ arithmetic_side_effects _n += &-1; + //~^ arithmetic_side_effects _n -= -1; + //~^ arithmetic_side_effects _n -= &-1; + //~^ arithmetic_side_effects _n /= -0; + //~^ arithmetic_side_effects _n /= &-0; + //~^ arithmetic_side_effects _n %= -0; + //~^ arithmetic_side_effects _n %= &-0; + //~^ arithmetic_side_effects _n *= -2; + //~^ arithmetic_side_effects _n *= &-2; + //~^ arithmetic_side_effects _custom += Custom; + //~^ arithmetic_side_effects _custom += &Custom; + //~^ arithmetic_side_effects _custom -= Custom; + //~^ arithmetic_side_effects _custom -= &Custom; + //~^ arithmetic_side_effects _custom /= Custom; + //~^ arithmetic_side_effects _custom /= &Custom; + //~^ arithmetic_side_effects _custom %= Custom; + //~^ arithmetic_side_effects _custom %= &Custom; + //~^ arithmetic_side_effects _custom *= Custom; + //~^ arithmetic_side_effects _custom *= &Custom; + //~^ arithmetic_side_effects _custom >>= Custom; + //~^ arithmetic_side_effects _custom >>= &Custom; + //~^ arithmetic_side_effects _custom <<= Custom; + //~^ arithmetic_side_effects _custom <<= &Custom; + //~^ arithmetic_side_effects _custom += -Custom; + //~^ arithmetic_side_effects _custom += &-Custom; + //~^ arithmetic_side_effects _custom -= -Custom; + //~^ arithmetic_side_effects _custom -= &-Custom; + //~^ arithmetic_side_effects _custom /= -Custom; + //~^ arithmetic_side_effects _custom /= &-Custom; + //~^ arithmetic_side_effects _custom %= -Custom; + //~^ arithmetic_side_effects _custom %= &-Custom; + //~^ arithmetic_side_effects _custom *= -Custom; + //~^ arithmetic_side_effects _custom *= &-Custom; + //~^ arithmetic_side_effects _custom >>= -Custom; + //~^ arithmetic_side_effects _custom >>= &-Custom; + //~^ arithmetic_side_effects _custom <<= -Custom; + //~^ arithmetic_side_effects _custom <<= &-Custom; + //~^ arithmetic_side_effects // Binary _n = _n + 1; + //~^ arithmetic_side_effects _n = _n + &1; + //~^ arithmetic_side_effects _n = 1 + _n; + //~^ arithmetic_side_effects _n = &1 + _n; + //~^ arithmetic_side_effects _n = _n - 1; + //~^ arithmetic_side_effects _n = _n - &1; + //~^ arithmetic_side_effects _n = 1 - _n; + //~^ arithmetic_side_effects _n = &1 - _n; + //~^ arithmetic_side_effects _n = _n / 0; + //~^ arithmetic_side_effects _n = _n / &0; + //~^ arithmetic_side_effects _n = _n % 0; + //~^ arithmetic_side_effects _n = _n % &0; + //~^ arithmetic_side_effects _n = _n * 2; + //~^ arithmetic_side_effects _n = _n * &2; + //~^ arithmetic_side_effects _n = 2 * _n; + //~^ arithmetic_side_effects _n = &2 * _n; + //~^ arithmetic_side_effects _n = 23 + &85; + //~^ arithmetic_side_effects _n = &23 + 85; + //~^ arithmetic_side_effects _n = &23 + &85; + //~^ arithmetic_side_effects _custom = _custom + _custom; + //~^ arithmetic_side_effects _custom = _custom + &_custom; + //~^ arithmetic_side_effects _custom = Custom + _custom; + //~^ arithmetic_side_effects _custom = &Custom + _custom; + //~^ arithmetic_side_effects _custom = _custom - Custom; + //~^ arithmetic_side_effects _custom = _custom - &Custom; + //~^ arithmetic_side_effects _custom = Custom - _custom; + //~^ arithmetic_side_effects _custom = &Custom - _custom; + //~^ arithmetic_side_effects _custom = _custom / Custom; + //~^ arithmetic_side_effects _custom = _custom / &Custom; + //~^ arithmetic_side_effects _custom = _custom % Custom; + //~^ arithmetic_side_effects _custom = _custom % &Custom; + //~^ arithmetic_side_effects _custom = _custom * Custom; + //~^ arithmetic_side_effects _custom = _custom * &Custom; + //~^ arithmetic_side_effects _custom = Custom * _custom; + //~^ arithmetic_side_effects _custom = &Custom * _custom; + //~^ arithmetic_side_effects _custom = Custom + &Custom; + //~^ arithmetic_side_effects _custom = &Custom + Custom; + //~^ arithmetic_side_effects _custom = &Custom + &Custom; + //~^ arithmetic_side_effects _custom = _custom >> _custom; + //~^ arithmetic_side_effects _custom = _custom >> &_custom; + //~^ arithmetic_side_effects _custom = Custom << _custom; + //~^ arithmetic_side_effects _custom = &Custom << _custom; + //~^ arithmetic_side_effects // Method _n.saturating_div(0); + //~^ arithmetic_side_effects _n.wrapping_div(0); + //~^ arithmetic_side_effects _n.wrapping_rem(0); + //~^ arithmetic_side_effects _n.wrapping_rem_euclid(0); + //~^ arithmetic_side_effects _n.saturating_div(_n); + //~^ arithmetic_side_effects _n.wrapping_div(_n); + //~^ arithmetic_side_effects _n.wrapping_rem(_n); + //~^ arithmetic_side_effects _n.wrapping_rem_euclid(_n); + //~^ arithmetic_side_effects _n.saturating_div(*Box::new(_n)); + //~^ arithmetic_side_effects // Unary _n = -_n; + //~^ arithmetic_side_effects _n = -&_n; + //~^ arithmetic_side_effects _custom = -_custom; + //~^ arithmetic_side_effects _custom = -&_custom; + //~^ arithmetic_side_effects _ = -*Box::new(_n); + //~^ arithmetic_side_effects } // Copied and pasted from the `integer_arithmetic` lint for comparison. @@ -426,10 +533,15 @@ pub fn integer_arithmetic() { let mut var2 = -1i32; 1 + i; + //~^ arithmetic_side_effects i * 2; + //~^ arithmetic_side_effects 1 % i / 2; + //~^ arithmetic_side_effects i - 2 + 2 - i; + //~^ arithmetic_side_effects -i; + //~^ arithmetic_side_effects i >> 1; i << 1; @@ -441,18 +553,27 @@ pub fn integer_arithmetic() { i ^ 1; i += 1; + //~^ arithmetic_side_effects i -= 1; + //~^ arithmetic_side_effects i *= 2; + //~^ arithmetic_side_effects i /= 2; i /= 0; + //~^ arithmetic_side_effects i /= -1; i /= var1; + //~^ arithmetic_side_effects i /= var2; + //~^ arithmetic_side_effects i %= 2; i %= 0; + //~^ arithmetic_side_effects i %= -1; i %= var1; + //~^ arithmetic_side_effects i %= var2; + //~^ arithmetic_side_effects i <<= 3; i >>= 2; @@ -463,6 +584,7 @@ pub fn integer_arithmetic() { pub fn issue_10583(a: u16) -> u16 { 10 / a + //~^ arithmetic_side_effects } pub fn issue_10767() { @@ -517,10 +639,12 @@ pub fn issue_11392() { pub fn issue_11393() { fn example_div(x: Wrapping, maybe_zero: Wrapping) -> Wrapping { x / maybe_zero + //~^ arithmetic_side_effects } fn example_rem(x: Wrapping, maybe_zero: Wrapping) -> Wrapping { x % maybe_zero + //~^ arithmetic_side_effects } let [x, maybe_zero] = [1, 0].map(Wrapping); @@ -532,17 +656,21 @@ pub fn issue_12318() { use core::ops::{AddAssign, DivAssign, MulAssign, RemAssign, SubAssign}; let mut one: i32 = 1; one.add_assign(1); + //~^ arithmetic_side_effects one.div_assign(1); one.mul_assign(1); one.rem_assign(1); one.sub_assign(1); + //~^ arithmetic_side_effects } pub fn explicit_methods() { use core::ops::Add; let one: i32 = 1; one.add(&one); + //~^ arithmetic_side_effects Box::new(one).add(one); + //~^ arithmetic_side_effects } fn main() {} diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 9b4cfb83fbb29..e15fb612be5e5 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -8,763 +8,763 @@ LL | let _ = 1f16 + 1f16; = help: to override `-D warnings` add `#[allow(clippy::arithmetic_side_effects)]` error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:169:13 + --> tests/ui/arithmetic_side_effects.rs:170:13 | LL | let _ = 1f128 + 1f128; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:173:13 + --> tests/ui/arithmetic_side_effects.rs:175:13 | LL | let _ = String::new() + &String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:308:5 + --> tests/ui/arithmetic_side_effects.rs:311:5 | LL | _n += 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:309:5 + --> tests/ui/arithmetic_side_effects.rs:313:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:310:5 + --> tests/ui/arithmetic_side_effects.rs:315:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:311:5 + --> tests/ui/arithmetic_side_effects.rs:317:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:312:5 + --> tests/ui/arithmetic_side_effects.rs:319:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:313:5 + --> tests/ui/arithmetic_side_effects.rs:321:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:314:5 + --> tests/ui/arithmetic_side_effects.rs:323:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:315:5 + --> tests/ui/arithmetic_side_effects.rs:325:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:316:5 + --> tests/ui/arithmetic_side_effects.rs:327:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:317:5 + --> tests/ui/arithmetic_side_effects.rs:329:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:318:5 + --> tests/ui/arithmetic_side_effects.rs:331:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:319:5 + --> tests/ui/arithmetic_side_effects.rs:333:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:320:5 + --> tests/ui/arithmetic_side_effects.rs:335:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:321:5 + --> tests/ui/arithmetic_side_effects.rs:337:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:322:5 + --> tests/ui/arithmetic_side_effects.rs:339:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:323:5 + --> tests/ui/arithmetic_side_effects.rs:341:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:324:5 + --> tests/ui/arithmetic_side_effects.rs:343:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:325:5 + --> tests/ui/arithmetic_side_effects.rs:345:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:326:5 + --> tests/ui/arithmetic_side_effects.rs:347:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:327:5 + --> tests/ui/arithmetic_side_effects.rs:349:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:328:5 + --> tests/ui/arithmetic_side_effects.rs:351:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:329:5 + --> tests/ui/arithmetic_side_effects.rs:353:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:330:5 + --> tests/ui/arithmetic_side_effects.rs:355:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:331:5 + --> tests/ui/arithmetic_side_effects.rs:357:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:332:5 + --> tests/ui/arithmetic_side_effects.rs:359:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:333:5 + --> tests/ui/arithmetic_side_effects.rs:361:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:334:5 + --> tests/ui/arithmetic_side_effects.rs:363:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:335:5 + --> tests/ui/arithmetic_side_effects.rs:365:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:336:5 + --> tests/ui/arithmetic_side_effects.rs:367:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:337:5 + --> tests/ui/arithmetic_side_effects.rs:369:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:338:5 + --> tests/ui/arithmetic_side_effects.rs:371:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:339:5 + --> tests/ui/arithmetic_side_effects.rs:373:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:340:5 + --> tests/ui/arithmetic_side_effects.rs:375:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:341:5 + --> tests/ui/arithmetic_side_effects.rs:377:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:342:5 + --> tests/ui/arithmetic_side_effects.rs:379:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:343:5 + --> tests/ui/arithmetic_side_effects.rs:381:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:344:5 + --> tests/ui/arithmetic_side_effects.rs:383:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:345:5 + --> tests/ui/arithmetic_side_effects.rs:385:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:346:5 + --> tests/ui/arithmetic_side_effects.rs:387:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:347:5 + --> tests/ui/arithmetic_side_effects.rs:389:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:348:5 + --> tests/ui/arithmetic_side_effects.rs:391:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:349:5 + --> tests/ui/arithmetic_side_effects.rs:393:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:350:5 + --> tests/ui/arithmetic_side_effects.rs:395:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:351:5 + --> tests/ui/arithmetic_side_effects.rs:397:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:352:5 + --> tests/ui/arithmetic_side_effects.rs:399:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:353:5 + --> tests/ui/arithmetic_side_effects.rs:401:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:354:5 + --> tests/ui/arithmetic_side_effects.rs:403:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:355:5 + --> tests/ui/arithmetic_side_effects.rs:405:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:358:10 + --> tests/ui/arithmetic_side_effects.rs:409:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:359:10 + --> tests/ui/arithmetic_side_effects.rs:411:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:360:10 + --> tests/ui/arithmetic_side_effects.rs:413:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:361:10 + --> tests/ui/arithmetic_side_effects.rs:415:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:362:10 + --> tests/ui/arithmetic_side_effects.rs:417:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:363:10 + --> tests/ui/arithmetic_side_effects.rs:419:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:364:10 + --> tests/ui/arithmetic_side_effects.rs:421:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:365:10 + --> tests/ui/arithmetic_side_effects.rs:423:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:366:10 + --> tests/ui/arithmetic_side_effects.rs:425:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:367:10 + --> tests/ui/arithmetic_side_effects.rs:427:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:368:10 + --> tests/ui/arithmetic_side_effects.rs:429:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:369:10 + --> tests/ui/arithmetic_side_effects.rs:431:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:370:10 + --> tests/ui/arithmetic_side_effects.rs:433:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:371:10 + --> tests/ui/arithmetic_side_effects.rs:435:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:372:10 + --> tests/ui/arithmetic_side_effects.rs:437:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:373:10 + --> tests/ui/arithmetic_side_effects.rs:439:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:374:10 + --> tests/ui/arithmetic_side_effects.rs:441:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:375:10 + --> tests/ui/arithmetic_side_effects.rs:443:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:376:10 + --> tests/ui/arithmetic_side_effects.rs:445:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:377:15 + --> tests/ui/arithmetic_side_effects.rs:447:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:378:15 + --> tests/ui/arithmetic_side_effects.rs:449:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:379:15 + --> tests/ui/arithmetic_side_effects.rs:451:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:380:15 + --> tests/ui/arithmetic_side_effects.rs:453:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:381:15 + --> tests/ui/arithmetic_side_effects.rs:455:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:382:15 + --> tests/ui/arithmetic_side_effects.rs:457:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:383:15 + --> tests/ui/arithmetic_side_effects.rs:459:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:384:15 + --> tests/ui/arithmetic_side_effects.rs:461:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:385:15 + --> tests/ui/arithmetic_side_effects.rs:463:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:386:15 + --> tests/ui/arithmetic_side_effects.rs:465:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:387:15 + --> tests/ui/arithmetic_side_effects.rs:467:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:388:15 + --> tests/ui/arithmetic_side_effects.rs:469:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:389:15 + --> tests/ui/arithmetic_side_effects.rs:471:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:390:15 + --> tests/ui/arithmetic_side_effects.rs:473:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:391:15 + --> tests/ui/arithmetic_side_effects.rs:475:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:392:15 + --> tests/ui/arithmetic_side_effects.rs:477:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:393:15 + --> tests/ui/arithmetic_side_effects.rs:479:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:394:15 + --> tests/ui/arithmetic_side_effects.rs:481:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:395:15 + --> tests/ui/arithmetic_side_effects.rs:483:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:396:15 + --> tests/ui/arithmetic_side_effects.rs:485:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:397:15 + --> tests/ui/arithmetic_side_effects.rs:487:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:398:15 + --> tests/ui/arithmetic_side_effects.rs:489:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:399:15 + --> tests/ui/arithmetic_side_effects.rs:491:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:402:23 + --> tests/ui/arithmetic_side_effects.rs:495:23 | LL | _n.saturating_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:403:21 + --> tests/ui/arithmetic_side_effects.rs:497:21 | LL | _n.wrapping_div(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:404:21 + --> tests/ui/arithmetic_side_effects.rs:499:21 | LL | _n.wrapping_rem(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:405:28 + --> tests/ui/arithmetic_side_effects.rs:501:28 | LL | _n.wrapping_rem_euclid(0); | ^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:407:23 + --> tests/ui/arithmetic_side_effects.rs:504:23 | LL | _n.saturating_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:408:21 + --> tests/ui/arithmetic_side_effects.rs:506:21 | LL | _n.wrapping_div(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:409:21 + --> tests/ui/arithmetic_side_effects.rs:508:21 | LL | _n.wrapping_rem(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:410:28 + --> tests/ui/arithmetic_side_effects.rs:510:28 | LL | _n.wrapping_rem_euclid(_n); | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:412:23 + --> tests/ui/arithmetic_side_effects.rs:513:23 | LL | _n.saturating_div(*Box::new(_n)); | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:415:10 + --> tests/ui/arithmetic_side_effects.rs:517:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:416:10 + --> tests/ui/arithmetic_side_effects.rs:519:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:417:15 + --> tests/ui/arithmetic_side_effects.rs:521:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:418:15 + --> tests/ui/arithmetic_side_effects.rs:523:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:419:9 + --> tests/ui/arithmetic_side_effects.rs:525:9 | LL | _ = -*Box::new(_n); | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:428:5 + --> tests/ui/arithmetic_side_effects.rs:535:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:429:5 + --> tests/ui/arithmetic_side_effects.rs:537:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:430:5 + --> tests/ui/arithmetic_side_effects.rs:539:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:431:5 + --> tests/ui/arithmetic_side_effects.rs:541:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:432:5 + --> tests/ui/arithmetic_side_effects.rs:543:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:443:5 + --> tests/ui/arithmetic_side_effects.rs:555:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:444:5 + --> tests/ui/arithmetic_side_effects.rs:557:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:445:5 + --> tests/ui/arithmetic_side_effects.rs:559:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:447:5 + --> tests/ui/arithmetic_side_effects.rs:562:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:449:5 + --> tests/ui/arithmetic_side_effects.rs:565:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:450:5 + --> tests/ui/arithmetic_side_effects.rs:567:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:452:5 + --> tests/ui/arithmetic_side_effects.rs:570:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:454:5 + --> tests/ui/arithmetic_side_effects.rs:573:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:455:5 + --> tests/ui/arithmetic_side_effects.rs:575:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:465:5 + --> tests/ui/arithmetic_side_effects.rs:586:5 | LL | 10 / a | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:519:9 + --> tests/ui/arithmetic_side_effects.rs:641:9 | LL | x / maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:523:9 + --> tests/ui/arithmetic_side_effects.rs:646:9 | LL | x % maybe_zero | ^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:534:5 + --> tests/ui/arithmetic_side_effects.rs:658:5 | LL | one.add_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:538:5 + --> tests/ui/arithmetic_side_effects.rs:663:5 | LL | one.sub_assign(1); | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:544:5 + --> tests/ui/arithmetic_side_effects.rs:670:5 | LL | one.add(&one); | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> tests/ui/arithmetic_side_effects.rs:545:5 + --> tests/ui/arithmetic_side_effects.rs:672:5 | LL | Box::new(one).add(one); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/as_conversions.rs b/src/tools/clippy/tests/ui/as_conversions.rs index 8499c0ac5a0f8..fba8913a2097b 100644 --- a/src/tools/clippy/tests/ui/as_conversions.rs +++ b/src/tools/clippy/tests/ui/as_conversions.rs @@ -7,9 +7,11 @@ extern crate proc_macros; use proc_macros::{external, with_span}; fn main() { - let i = 0u32 as u64; + let i = 0u32 as u64; //~ as_conversions let j = &i as *const u64 as *mut u64; + //~^ as_conversions + //~| as_conversions external!(0u32 as u64); } diff --git a/src/tools/clippy/tests/ui/as_pointer_underscore.fixed b/src/tools/clippy/tests/ui/as_pointer_underscore.fixed index db06486ecb048..93daae6bc668f 100644 --- a/src/tools/clippy/tests/ui/as_pointer_underscore.fixed +++ b/src/tools/clippy/tests/ui/as_pointer_underscore.fixed @@ -6,10 +6,10 @@ struct S; fn f(s: &S) -> usize { &s as *const &S as usize - //~^ ERROR: using inferred pointer cast + //~^ as_pointer_underscore } fn g(s: &mut S) -> usize { s as *mut S as usize - //~^ ERROR: using inferred pointer cast + //~^ as_pointer_underscore } diff --git a/src/tools/clippy/tests/ui/as_pointer_underscore.rs b/src/tools/clippy/tests/ui/as_pointer_underscore.rs index 955c702ccc998..56f1a89352557 100644 --- a/src/tools/clippy/tests/ui/as_pointer_underscore.rs +++ b/src/tools/clippy/tests/ui/as_pointer_underscore.rs @@ -6,10 +6,10 @@ struct S; fn f(s: &S) -> usize { &s as *const _ as usize - //~^ ERROR: using inferred pointer cast + //~^ as_pointer_underscore } fn g(s: &mut S) -> usize { s as *mut _ as usize - //~^ ERROR: using inferred pointer cast + //~^ as_pointer_underscore } diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs index 9e862320f4efe..baf7279adc4a4 100644 --- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs @@ -20,10 +20,11 @@ impl Covariant { fn main() { let mut string = String::new(); let _ = string.as_ptr() as *mut u8; - //~^ ERROR: casting the result of `as_ptr` to *mut u8 - //~| NOTE: `-D clippy::as-ptr-cast-mut` implied by `-D warnings` + //~^ as_ptr_cast_mut + let _: *mut i8 = string.as_ptr() as *mut _; - //~^ ERROR: casting the result of `as_ptr` to *mut i8 + //~^ as_ptr_cast_mut + let _ = string.as_ptr() as *const i8; let _ = string.as_mut_ptr(); let _ = string.as_mut_ptr() as *mut u8; diff --git a/src/tools/clippy/tests/ui/as_underscore.fixed b/src/tools/clippy/tests/ui/as_underscore.fixed index c7f26e64cce78..ca2a7f0432868 100644 --- a/src/tools/clippy/tests/ui/as_underscore.fixed +++ b/src/tools/clippy/tests/ui/as_underscore.fixed @@ -5,7 +5,9 @@ fn foo(_n: usize) {} fn main() { let n: u16 = 256; foo(n as usize); + //~^ as_underscore let n = 0_u128; let _n: u8 = n as u8; + //~^ as_underscore } diff --git a/src/tools/clippy/tests/ui/as_underscore.rs b/src/tools/clippy/tests/ui/as_underscore.rs index 70f3b386631c4..df500c4c4df1e 100644 --- a/src/tools/clippy/tests/ui/as_underscore.rs +++ b/src/tools/clippy/tests/ui/as_underscore.rs @@ -5,7 +5,9 @@ fn foo(_n: usize) {} fn main() { let n: u16 = 256; foo(n as _); + //~^ as_underscore let n = 0_u128; let _n: u8 = n as _; + //~^ as_underscore } diff --git a/src/tools/clippy/tests/ui/as_underscore.stderr b/src/tools/clippy/tests/ui/as_underscore.stderr index dba56a2a8af38..02c10feb78eb0 100644 --- a/src/tools/clippy/tests/ui/as_underscore.stderr +++ b/src/tools/clippy/tests/ui/as_underscore.stderr @@ -10,7 +10,7 @@ LL | foo(n as _); = help: to override `-D warnings` add `#[allow(clippy::as_underscore)]` error: using `as _` conversion - --> tests/ui/as_underscore.rs:10:18 + --> tests/ui/as_underscore.rs:11:18 | LL | let _n: u8 = n as _; | ^^^^^- diff --git a/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs b/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs index a7d29cc239e53..edcd5247f18ce 100644 --- a/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs +++ b/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs @@ -1,5 +1,6 @@ //@ignore-target: i686 x86 //@needs-asm-support +//@check-pass #[warn(clippy::inline_asm_x86_intel_syntax)] #[warn(clippy::inline_asm_x86_att_syntax)] diff --git a/src/tools/clippy/tests/ui/asm_syntax_x86.rs b/src/tools/clippy/tests/ui/asm_syntax_x86.rs index 5ceaceb7527b3..4e91f27cd3189 100644 --- a/src/tools/clippy/tests/ui/asm_syntax_x86.rs +++ b/src/tools/clippy/tests/ui/asm_syntax_x86.rs @@ -6,19 +6,24 @@ mod warn_intel { pub(super) unsafe fn use_asm() { asm!(""); - //~^ ERROR: Intel x86 assembly syntax used + //~^ inline_asm_x86_intel_syntax + asm!("", options()); - //~^ ERROR: Intel x86 assembly syntax used + //~^ inline_asm_x86_intel_syntax + asm!("", options(nostack)); - //~^ ERROR: Intel x86 assembly syntax used + //~^ inline_asm_x86_intel_syntax + asm!("", options(att_syntax)); asm!("", options(nostack, att_syntax)); } global_asm!(""); - //~^ ERROR: Intel x86 assembly syntax used + //~^ inline_asm_x86_intel_syntax + global_asm!("", options()); - //~^ ERROR: Intel x86 assembly syntax used + //~^ inline_asm_x86_intel_syntax + global_asm!("", options(att_syntax)); } @@ -31,15 +36,16 @@ mod warn_att { asm!("", options()); asm!("", options(nostack)); asm!("", options(att_syntax)); - //~^ ERROR: AT&T x86 assembly syntax used + //~^ inline_asm_x86_att_syntax + asm!("", options(nostack, att_syntax)); - //~^ ERROR: AT&T x86 assembly syntax used + //~^ inline_asm_x86_att_syntax } global_asm!(""); global_asm!("", options()); global_asm!("", options(att_syntax)); - //~^ ERROR: AT&T x86 assembly syntax used + //~^ inline_asm_x86_att_syntax } fn main() { diff --git a/src/tools/clippy/tests/ui/asm_syntax_x86.stderr b/src/tools/clippy/tests/ui/asm_syntax_x86.stderr index 1911ef66e2391..2dcd955f03479 100644 --- a/src/tools/clippy/tests/ui/asm_syntax_x86.stderr +++ b/src/tools/clippy/tests/ui/asm_syntax_x86.stderr @@ -9,7 +9,7 @@ LL | asm!(""); = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_intel_syntax)]` error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:10:9 + --> tests/ui/asm_syntax_x86.rs:11:9 | LL | asm!("", options()); | ^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | asm!("", options()); = help: use AT&T x86 assembly syntax error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:12:9 + --> tests/ui/asm_syntax_x86.rs:14:9 | LL | asm!("", options(nostack)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | asm!("", options(nostack)); = help: use AT&T x86 assembly syntax error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:18:5 + --> tests/ui/asm_syntax_x86.rs:21:5 | LL | global_asm!(""); | ^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | global_asm!(""); = help: use AT&T x86 assembly syntax error: Intel x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:20:5 + --> tests/ui/asm_syntax_x86.rs:24:5 | LL | global_asm!("", options()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | global_asm!("", options()); = help: use AT&T x86 assembly syntax error: AT&T x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:33:9 + --> tests/ui/asm_syntax_x86.rs:38:9 | LL | asm!("", options(att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | asm!("", options(att_syntax)); = help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_att_syntax)]` error: AT&T x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:35:9 + --> tests/ui/asm_syntax_x86.rs:41:9 | LL | asm!("", options(nostack, att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL | asm!("", options(nostack, att_syntax)); = help: use Intel x86 assembly syntax error: AT&T x86 assembly syntax used - --> tests/ui/asm_syntax_x86.rs:41:5 + --> tests/ui/asm_syntax_x86.rs:47:5 | LL | global_asm!("", options(att_syntax)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs index 957154e60dece..c2516c5414753 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.rs +++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs @@ -8,30 +8,35 @@ macro_rules! assert_const { } fn main() { assert!(true); - //~^ ERROR: `assert!(true)` will be optimized out by the compiler + //~^ assertions_on_constants + assert!(false); - //~^ ERROR: `assert!(false)` should probably be replaced + //~^ assertions_on_constants + assert!(true, "true message"); - //~^ ERROR: `assert!(true)` will be optimized out by the compiler + //~^ assertions_on_constants + assert!(false, "false message"); - //~^ ERROR: `assert!(false, ..)` should probably be replaced + //~^ assertions_on_constants let msg = "panic message"; assert!(false, "{}", msg.to_uppercase()); - //~^ ERROR: `assert!(false, ..)` should probably be replaced + //~^ assertions_on_constants const B: bool = true; assert!(B); - //~^ ERROR: `assert!(true)` will be optimized out by the compiler + //~^ assertions_on_constants const C: bool = false; assert!(C); - //~^ ERROR: `assert!(false)` should probably be replaced + //~^ assertions_on_constants + assert!(C, "C message"); - //~^ ERROR: `assert!(false, ..)` should probably be replaced + //~^ assertions_on_constants debug_assert!(true); - //~^ ERROR: `debug_assert!(true)` will be optimized out by the compiler + //~^ assertions_on_constants + // Don't lint this, since there is no better way for expressing "Only panic in debug mode". debug_assert!(false); // #3948 assert_const!(3); @@ -47,10 +52,10 @@ fn main() { assert!(!CFG_FLAG); const _: () = assert!(true); - //~^ ERROR: `assert!(true)` will be optimized out by the compiler + //~^ assertions_on_constants assert!(8 == (7 + 1)); - //~^ ERROR: `assert!(true)` will be optimized out by the compiler + //~^ assertions_on_constants // Don't lint if the value is dependent on a defined constant: const N: usize = 1024; @@ -59,6 +64,7 @@ fn main() { const _: () = { assert!(true); - //~^ ERROR: `assert!(true)` will be optimized out by the compiler + //~^ assertions_on_constants + assert!(8 == (7 + 1)); }; diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr index e164a999c43ee..8b7440ec4832c 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr @@ -9,7 +9,7 @@ LL | assert!(true); = help: to override `-D warnings` add `#[allow(clippy::assertions_on_constants)]` error: `assert!(false)` should probably be replaced - --> tests/ui/assertions_on_constants.rs:12:5 + --> tests/ui/assertions_on_constants.rs:13:5 | LL | assert!(false); | ^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | assert!(false); = help: use `panic!()` or `unreachable!()` error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:14:5 + --> tests/ui/assertions_on_constants.rs:16:5 | LL | assert!(true, "true message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | assert!(true, "true message"); = help: remove it error: `assert!(false, ..)` should probably be replaced - --> tests/ui/assertions_on_constants.rs:16:5 + --> tests/ui/assertions_on_constants.rs:19:5 | LL | assert!(false, "false message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | assert!(false, "false message"); = help: use `panic!(..)` or `unreachable!(..)` error: `assert!(false, ..)` should probably be replaced - --> tests/ui/assertions_on_constants.rs:20:5 + --> tests/ui/assertions_on_constants.rs:23:5 | LL | assert!(false, "{}", msg.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | assert!(false, "{}", msg.to_uppercase()); = help: use `panic!(..)` or `unreachable!(..)` error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:24:5 + --> tests/ui/assertions_on_constants.rs:27:5 | LL | assert!(B); | ^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | assert!(B); = help: remove it error: `assert!(false)` should probably be replaced - --> tests/ui/assertions_on_constants.rs:28:5 + --> tests/ui/assertions_on_constants.rs:31:5 | LL | assert!(C); | ^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | assert!(C); = help: use `panic!()` or `unreachable!()` error: `assert!(false, ..)` should probably be replaced - --> tests/ui/assertions_on_constants.rs:30:5 + --> tests/ui/assertions_on_constants.rs:34:5 | LL | assert!(C, "C message"); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | assert!(C, "C message"); = help: use `panic!(..)` or `unreachable!(..)` error: `debug_assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:33:5 + --> tests/ui/assertions_on_constants.rs:37:5 | LL | debug_assert!(true); | ^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | debug_assert!(true); = help: remove it error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:49:19 + --> tests/ui/assertions_on_constants.rs:54:19 | LL | const _: () = assert!(true); | ^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | const _: () = assert!(true); = help: remove it error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:52:5 + --> tests/ui/assertions_on_constants.rs:57:5 | LL | assert!(8 == (7 + 1)); | ^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | assert!(8 == (7 + 1)); = help: remove it error: `assert!(true)` will be optimized out by the compiler - --> tests/ui/assertions_on_constants.rs:61:5 + --> tests/ui/assertions_on_constants.rs:66:5 | LL | assert!(true); | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed index 14d9b8b99d5e5..09c1a8d0ed1d5 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed @@ -22,6 +22,7 @@ fn main() { let r: Result = Ok(Foo); debug_assert!(r.is_ok()); r.unwrap(); + //~^ assertions_on_result_states // test ok with non-debug error type let r: Result = Ok(Foo); @@ -40,9 +41,11 @@ fn main() { Ok(Foo) } get_ok().unwrap(); + //~^ assertions_on_result_states // test macro ok get_ok_macro!().unwrap(); + //~^ assertions_on_result_states // test ok that shouldn't be moved let r: Result = Ok(CopyFoo); @@ -56,12 +59,14 @@ fn main() { // test ok that is copied let r: Result = Ok(CopyFoo); r.unwrap(); + //~^ assertions_on_result_states r.unwrap(); // test reference to ok let r: Result = Ok(CopyFoo); fn test_ref_copy_ok(r: &Result) { r.unwrap(); + //~^ assertions_on_result_states } test_ref_copy_ok(&r); r.unwrap(); @@ -70,6 +75,7 @@ fn main() { let r: Result = Err(Foo); debug_assert!(r.is_err()); r.unwrap_err(); + //~^ assertions_on_result_states // test err with non-debug value type let r: Result = Err(Foo); @@ -80,4 +86,5 @@ fn main() { fn issue9450() { let res: Result = Ok(1); res.unwrap_err(); + //~^ assertions_on_result_states } diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs index ac1911d87c93a..c63c2502b5377 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.rs @@ -22,6 +22,7 @@ fn main() { let r: Result = Ok(Foo); debug_assert!(r.is_ok()); assert!(r.is_ok()); + //~^ assertions_on_result_states // test ok with non-debug error type let r: Result = Ok(Foo); @@ -40,9 +41,11 @@ fn main() { Ok(Foo) } assert!(get_ok().is_ok()); + //~^ assertions_on_result_states // test macro ok assert!(get_ok_macro!().is_ok()); + //~^ assertions_on_result_states // test ok that shouldn't be moved let r: Result = Ok(CopyFoo); @@ -56,12 +59,14 @@ fn main() { // test ok that is copied let r: Result = Ok(CopyFoo); assert!(r.is_ok()); + //~^ assertions_on_result_states r.unwrap(); // test reference to ok let r: Result = Ok(CopyFoo); fn test_ref_copy_ok(r: &Result) { assert!(r.is_ok()); + //~^ assertions_on_result_states } test_ref_copy_ok(&r); r.unwrap(); @@ -70,6 +75,7 @@ fn main() { let r: Result = Err(Foo); debug_assert!(r.is_err()); assert!(r.is_err()); + //~^ assertions_on_result_states // test err with non-debug value type let r: Result = Err(Foo); @@ -80,4 +86,5 @@ fn main() { fn issue9450() { let res: Result = Ok(1); assert!(res.is_err()) + //~^ assertions_on_result_states } diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr index a2bddc7025a97..3bf811588c696 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr @@ -8,37 +8,37 @@ LL | assert!(r.is_ok()); = help: to override `-D warnings` add `#[allow(clippy::assertions_on_result_states)]` error: called `assert!` with `Result::is_ok` - --> tests/ui/assertions_on_result_states.rs:42:5 + --> tests/ui/assertions_on_result_states.rs:43:5 | LL | assert!(get_ok().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()` error: called `assert!` with `Result::is_ok` - --> tests/ui/assertions_on_result_states.rs:45:5 + --> tests/ui/assertions_on_result_states.rs:47:5 | LL | assert!(get_ok_macro!().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()` error: called `assert!` with `Result::is_ok` - --> tests/ui/assertions_on_result_states.rs:58:5 + --> tests/ui/assertions_on_result_states.rs:61:5 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_ok` - --> tests/ui/assertions_on_result_states.rs:64:9 + --> tests/ui/assertions_on_result_states.rs:68:9 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_err` - --> tests/ui/assertions_on_result_states.rs:72:5 + --> tests/ui/assertions_on_result_states.rs:77:5 | LL | assert!(r.is_err()); | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` error: called `assert!` with `Result::is_err` - --> tests/ui/assertions_on_result_states.rs:82:5 + --> tests/ui/assertions_on_result_states.rs:88:5 | LL | assert!(res.is_err()) | ^^^^^^^^^^^^^^^^^^^^^ help: replace with: `res.unwrap_err();` diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index 2bd0807f42628..18f0e04a8807e 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -5,25 +5,36 @@ use core::num::Wrapping; fn main() { let mut a = 5; a += 1; + //~^ assign_op_pattern a += 1; + //~^ assign_op_pattern a -= 1; + //~^ assign_op_pattern a *= 99; + //~^ assign_op_pattern a *= 42; + //~^ assign_op_pattern a /= 2; + //~^ assign_op_pattern a %= 5; + //~^ assign_op_pattern a &= 1; + //~^ assign_op_pattern a = 1 - a; a = 5 / a; a = 42 % a; a = 6 << a; let mut s = String::new(); s += "bla"; + //~^ assign_op_pattern // Issue #9180 let mut a = Wrapping(0u32); a += Wrapping(1u32); + //~^ assign_op_pattern let mut v = vec![0u32, 1u32]; v[0] += v[1]; + //~^ assign_op_pattern let mut v = vec![Wrapping(0u32), Wrapping(1u32)]; v[0] = v[0] + v[1]; let _ = || v[0] = v[0] + v[1]; diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs index be3491a44c7eb..8b05c74d86040 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -5,25 +5,36 @@ use core::num::Wrapping; fn main() { let mut a = 5; a = a + 1; + //~^ assign_op_pattern a = 1 + a; + //~^ assign_op_pattern a = a - 1; + //~^ assign_op_pattern a = a * 99; + //~^ assign_op_pattern a = 42 * a; + //~^ assign_op_pattern a = a / 2; + //~^ assign_op_pattern a = a % 5; + //~^ assign_op_pattern a = a & 1; + //~^ assign_op_pattern a = 1 - a; a = 5 / a; a = 42 % a; a = 6 << a; let mut s = String::new(); s = s + "bla"; + //~^ assign_op_pattern // Issue #9180 let mut a = Wrapping(0u32); a = a + Wrapping(1u32); + //~^ assign_op_pattern let mut v = vec![0u32, 1u32]; v[0] = v[0] + v[1]; + //~^ assign_op_pattern let mut v = vec![Wrapping(0u32), Wrapping(1u32)]; v[0] = v[0] + v[1]; let _ = || v[0] = v[0] + v[1]; diff --git a/src/tools/clippy/tests/ui/assign_ops.stderr b/src/tools/clippy/tests/ui/assign_ops.stderr index 4975ac5911fdd..17f216ee4a071 100644 --- a/src/tools/clippy/tests/ui/assign_ops.stderr +++ b/src/tools/clippy/tests/ui/assign_ops.stderr @@ -8,61 +8,61 @@ LL | a = a + 1; = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:8:5 + --> tests/ui/assign_ops.rs:9:5 | LL | a = 1 + a; | ^^^^^^^^^ help: replace it with: `a += 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:9:5 + --> tests/ui/assign_ops.rs:11:5 | LL | a = a - 1; | ^^^^^^^^^ help: replace it with: `a -= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:10:5 + --> tests/ui/assign_ops.rs:13:5 | LL | a = a * 99; | ^^^^^^^^^^ help: replace it with: `a *= 99` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:11:5 + --> tests/ui/assign_ops.rs:15:5 | LL | a = 42 * a; | ^^^^^^^^^^ help: replace it with: `a *= 42` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:12:5 + --> tests/ui/assign_ops.rs:17:5 | LL | a = a / 2; | ^^^^^^^^^ help: replace it with: `a /= 2` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:13:5 + --> tests/ui/assign_ops.rs:19:5 | LL | a = a % 5; | ^^^^^^^^^ help: replace it with: `a %= 5` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:14:5 + --> tests/ui/assign_ops.rs:21:5 | LL | a = a & 1; | ^^^^^^^^^ help: replace it with: `a &= 1` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:20:5 + --> tests/ui/assign_ops.rs:28:5 | LL | s = s + "bla"; | ^^^^^^^^^^^^^ help: replace it with: `s += "bla"` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:24:5 + --> tests/ui/assign_ops.rs:33:5 | LL | a = a + Wrapping(1u32); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a += Wrapping(1u32)` error: manual implementation of an assign operation - --> tests/ui/assign_ops.rs:26:5 + --> tests/ui/assign_ops.rs:36:5 | LL | v[0] = v[0] + v[1]; | ^^^^^^^^^^^^^^^^^^ help: replace it with: `v[0] += v[1]` diff --git a/src/tools/clippy/tests/ui/assign_ops2.rs b/src/tools/clippy/tests/ui/assign_ops2.rs index a53556425849b..51867fa6962cf 100644 --- a/src/tools/clippy/tests/ui/assign_ops2.rs +++ b/src/tools/clippy/tests/ui/assign_ops2.rs @@ -6,24 +6,32 @@ fn main() { let mut a = 5; a += a + 1; - //~^ ERROR: variable appears on both sides of an assignment operation - //~| NOTE: `-D clippy::misrefactored-assign-op` implied by `-D warnings` + //~^ misrefactored_assign_op + a += 1 + a; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a -= a - 1; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a *= a * 99; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a *= 42 * a; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a /= a / 2; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a %= a % 5; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a &= a & 1; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a *= a * a; - //~^ ERROR: variable appears on both sides of an assignment operation + //~^ misrefactored_assign_op + a = a * a * a; a = a * 42 * a; a = a * 2 + a; @@ -61,8 +69,7 @@ fn cow_add_assign() { // this can be linted buf = buf + cows.clone(); - //~^ ERROR: manual implementation of an assign operation - //~| NOTE: `-D clippy::assign-op-pattern` implied by `-D warnings` + //~^ assign_op_pattern // this should not as cow Add is not commutative buf = cows + buf; diff --git a/src/tools/clippy/tests/ui/assign_ops2.stderr b/src/tools/clippy/tests/ui/assign_ops2.stderr index 09b101b216a50..d9ecd3f8b230c 100644 --- a/src/tools/clippy/tests/ui/assign_ops2.stderr +++ b/src/tools/clippy/tests/ui/assign_ops2.stderr @@ -35,7 +35,7 @@ LL + a = a + 1 + a; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:13:5 + --> tests/ui/assign_ops2.rs:14:5 | LL | a -= a - 1; | ^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + a = a - (a - 1); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:15:5 + --> tests/ui/assign_ops2.rs:17:5 | LL | a *= a * 99; | ^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL + a = a * a * 99; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:17:5 + --> tests/ui/assign_ops2.rs:20:5 | LL | a *= 42 * a; | ^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL + a = a * 42 * a; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:19:5 + --> tests/ui/assign_ops2.rs:23:5 | LL | a /= a / 2; | ^^^^^^^^^^ @@ -103,7 +103,7 @@ LL + a = a / (a / 2); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:21:5 + --> tests/ui/assign_ops2.rs:26:5 | LL | a %= a % 5; | ^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + a = a % (a % 5); | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:23:5 + --> tests/ui/assign_ops2.rs:29:5 | LL | a &= a & 1; | ^^^^^^^^^^ @@ -137,7 +137,7 @@ LL + a = a & a & 1; | error: variable appears on both sides of an assignment operation - --> tests/ui/assign_ops2.rs:25:5 + --> tests/ui/assign_ops2.rs:32:5 | LL | a *= a * a; | ^^^^^^^^^^ @@ -154,7 +154,7 @@ LL + a = a * a * a; | error: manual implementation of an assign operation - --> tests/ui/assign_ops2.rs:63:5 + --> tests/ui/assign_ops2.rs:71:5 | LL | buf = buf + cows.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `buf += cows.clone()` diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed index 09732d1a50ce0..9e44008e6fabc 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.fixed +++ b/src/tools/clippy/tests/ui/assigning_clones.fixed @@ -23,60 +23,73 @@ impl Clone for HasCloneFrom { fn clone_method_rhs_val(mut_thing: &mut HasCloneFrom, value_thing: HasCloneFrom) { mut_thing.clone_from(&value_thing); + //~^ assigning_clones } fn clone_method_rhs_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { mut_thing.clone_from(ref_thing); + //~^ assigning_clones } fn clone_method_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { mut_thing.clone_from(ref_thing); + //~^ assigning_clones } fn clone_function_lhs_mut_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { Clone::clone_from(mut_thing, ref_thing); + //~^ assigning_clones } fn clone_function_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { Clone::clone_from(&mut mut_thing, ref_thing); + //~^ assigning_clones } fn clone_function_through_trait(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { Clone::clone_from(mut_thing, ref_thing); + //~^ assigning_clones } fn clone_function_through_type(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { Clone::clone_from(mut_thing, ref_thing); + //~^ assigning_clones } fn clone_function_fully_qualified(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { Clone::clone_from(mut_thing, ref_thing); + //~^ assigning_clones } fn clone_method_lhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { // These parens should be kept as necessary for a receiver (mut_thing + &mut HasCloneFrom).clone_from(ref_thing); + //~^ assigning_clones } fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { // These parens should be removed since they are not needed in a function argument mut_thing.clone_from(ref_thing + ref_thing); + //~^ assigning_clones } fn clone_method_macro() { let mut s = String::from(""); s.clone_from(&format!("{} {}", "hello", "world")); + //~^ assigning_clones } fn clone_function_macro() { let mut s = String::from(""); Clone::clone_from(&mut s, &format!("{} {}", "hello", "world")); + //~^ assigning_clones } fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom { let mut a = HasCloneFrom; for _ in 1..10 { a.clone_from(&b); + //~^ assigning_clones } a } @@ -148,6 +161,7 @@ fn ignore_generic_clone(a: &mut T, b: &T) { #[clippy::msrv = "1.62"] fn msrv_1_62(mut a: String, b: String, c: &str) { a.clone_from(&b); + //~^ assigning_clones // Should not be linted, as clone_into wasn't stabilized until 1.63 a = c.to_owned(); } @@ -155,7 +169,9 @@ fn msrv_1_62(mut a: String, b: String, c: &str) { #[clippy::msrv = "1.63"] fn msrv_1_63(mut a: String, b: String, c: &str) { a.clone_from(&b); + //~^ assigning_clones c.clone_into(&mut a); + //~^ assigning_clones } macro_rules! clone_inside { @@ -186,35 +202,43 @@ impl Clone for AvoidRecursiveCloneFrom { // Deref handling fn clone_into_deref_method(mut a: DerefWrapper, b: HasCloneFrom) { (*a).clone_from(&b); + //~^ assigning_clones } fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone, b: HasCloneFrom) { (*a).clone_from(&b); + //~^ assigning_clones } fn clone_into_box_method(mut a: Box, b: HasCloneFrom) { (*a).clone_from(&b); + //~^ assigning_clones } fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone, b: DerefWrapperWithClone) { a.clone_from(&b); + //~^ assigning_clones } fn clone_into_deref_function(mut a: DerefWrapper, b: HasCloneFrom) { Clone::clone_from(&mut *a, &b); + //~^ assigning_clones } fn clone_into_box_function(mut a: Box, b: HasCloneFrom) { Clone::clone_from(&mut *a, &b); + //~^ assigning_clones } // ToOwned fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { ref_str.clone_into(mut_string); + //~^ assigning_clones } fn owned_method_val(mut mut_string: String, ref_str: &str) { ref_str.clone_into(&mut mut_string); + //~^ assigning_clones } struct HasDeref { @@ -236,28 +260,34 @@ impl DerefMut for HasDeref { fn owned_method_box(mut_box_string: &mut Box, ref_str: &str) { ref_str.clone_into(&mut (*mut_box_string)); + //~^ assigning_clones } fn owned_method_deref(mut_box_string: &mut HasDeref, ref_str: &str) { ref_str.clone_into(&mut (*mut_box_string)); + //~^ assigning_clones } fn owned_function_mut_ref(mut_thing: &mut String, ref_str: &str) { ToOwned::clone_into(ref_str, mut_thing); + //~^ assigning_clones } fn owned_function_val(mut mut_thing: String, ref_str: &str) { ToOwned::clone_into(ref_str, &mut mut_thing); + //~^ assigning_clones } fn owned_method_macro() { let mut s = String::from(""); format!("{} {}", "hello", "world").clone_into(&mut s); + //~^ assigning_clones } fn owned_function_macro() { let mut s = String::from(""); ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s); + //~^ assigning_clones } struct FakeToOwned; diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs index 6be25ae17a55d..8ae8abfed367a 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.rs +++ b/src/tools/clippy/tests/ui/assigning_clones.rs @@ -23,60 +23,73 @@ impl Clone for HasCloneFrom { fn clone_method_rhs_val(mut_thing: &mut HasCloneFrom, value_thing: HasCloneFrom) { *mut_thing = value_thing.clone(); + //~^ assigning_clones } fn clone_method_rhs_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { *mut_thing = ref_thing.clone(); + //~^ assigning_clones } fn clone_method_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { mut_thing = ref_thing.clone(); + //~^ assigning_clones } fn clone_function_lhs_mut_ref(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { *mut_thing = Clone::clone(ref_thing); + //~^ assigning_clones } fn clone_function_lhs_val(mut mut_thing: HasCloneFrom, ref_thing: &HasCloneFrom) { mut_thing = Clone::clone(ref_thing); + //~^ assigning_clones } fn clone_function_through_trait(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { *mut_thing = Clone::clone(ref_thing); + //~^ assigning_clones } fn clone_function_through_type(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { *mut_thing = HasCloneFrom::clone(ref_thing); + //~^ assigning_clones } fn clone_function_fully_qualified(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { *mut_thing = ::clone(ref_thing); + //~^ assigning_clones } fn clone_method_lhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { // These parens should be kept as necessary for a receiver *(mut_thing + &mut HasCloneFrom) = ref_thing.clone(); + //~^ assigning_clones } fn clone_method_rhs_complex(mut_thing: &mut HasCloneFrom, ref_thing: &HasCloneFrom) { // These parens should be removed since they are not needed in a function argument *mut_thing = (ref_thing + ref_thing).clone(); + //~^ assigning_clones } fn clone_method_macro() { let mut s = String::from(""); s = format!("{} {}", "hello", "world").clone(); + //~^ assigning_clones } fn clone_function_macro() { let mut s = String::from(""); s = Clone::clone(&format!("{} {}", "hello", "world")); + //~^ assigning_clones } fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom { let mut a = HasCloneFrom; for _ in 1..10 { a = b.clone(); + //~^ assigning_clones } a } @@ -148,6 +161,7 @@ fn ignore_generic_clone(a: &mut T, b: &T) { #[clippy::msrv = "1.62"] fn msrv_1_62(mut a: String, b: String, c: &str) { a = b.clone(); + //~^ assigning_clones // Should not be linted, as clone_into wasn't stabilized until 1.63 a = c.to_owned(); } @@ -155,7 +169,9 @@ fn msrv_1_62(mut a: String, b: String, c: &str) { #[clippy::msrv = "1.63"] fn msrv_1_63(mut a: String, b: String, c: &str) { a = b.clone(); + //~^ assigning_clones a = c.to_owned(); + //~^ assigning_clones } macro_rules! clone_inside { @@ -186,35 +202,43 @@ impl Clone for AvoidRecursiveCloneFrom { // Deref handling fn clone_into_deref_method(mut a: DerefWrapper, b: HasCloneFrom) { *a = b.clone(); + //~^ assigning_clones } fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone, b: HasCloneFrom) { *a = b.clone(); + //~^ assigning_clones } fn clone_into_box_method(mut a: Box, b: HasCloneFrom) { *a = b.clone(); + //~^ assigning_clones } fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone, b: DerefWrapperWithClone) { *a = b.clone(); + //~^ assigning_clones } fn clone_into_deref_function(mut a: DerefWrapper, b: HasCloneFrom) { *a = Clone::clone(&b); + //~^ assigning_clones } fn clone_into_box_function(mut a: Box, b: HasCloneFrom) { *a = Clone::clone(&b); + //~^ assigning_clones } // ToOwned fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { *mut_string = ref_str.to_owned(); + //~^ assigning_clones } fn owned_method_val(mut mut_string: String, ref_str: &str) { mut_string = ref_str.to_owned(); + //~^ assigning_clones } struct HasDeref { @@ -236,28 +260,34 @@ impl DerefMut for HasDeref { fn owned_method_box(mut_box_string: &mut Box, ref_str: &str) { **mut_box_string = ref_str.to_owned(); + //~^ assigning_clones } fn owned_method_deref(mut_box_string: &mut HasDeref, ref_str: &str) { **mut_box_string = ref_str.to_owned(); + //~^ assigning_clones } fn owned_function_mut_ref(mut_thing: &mut String, ref_str: &str) { *mut_thing = ToOwned::to_owned(ref_str); + //~^ assigning_clones } fn owned_function_val(mut mut_thing: String, ref_str: &str) { mut_thing = ToOwned::to_owned(ref_str); + //~^ assigning_clones } fn owned_method_macro() { let mut s = String::from(""); s = format!("{} {}", "hello", "world").to_owned(); + //~^ assigning_clones } fn owned_function_macro() { let mut s = String::from(""); s = ToOwned::to_owned(&format!("{} {}", "hello", "world")); + //~^ assigning_clones } struct FakeToOwned; diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr index 19724a6d4ec2f..2714d599b28af 100644 --- a/src/tools/clippy/tests/ui/assigning_clones.stderr +++ b/src/tools/clippy/tests/ui/assigning_clones.stderr @@ -8,175 +8,175 @@ LL | *mut_thing = value_thing.clone(); = help: to override `-D warnings` add `#[allow(clippy::assigning_clones)]` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:29:5 + --> tests/ui/assigning_clones.rs:30:5 | LL | *mut_thing = ref_thing.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:33:5 + --> tests/ui/assigning_clones.rs:35:5 | LL | mut_thing = ref_thing.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:37:5 + --> tests/ui/assigning_clones.rs:40:5 | LL | *mut_thing = Clone::clone(ref_thing); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:41:5 + --> tests/ui/assigning_clones.rs:45:5 | LL | mut_thing = Clone::clone(ref_thing); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut mut_thing, ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:45:5 + --> tests/ui/assigning_clones.rs:50:5 | LL | *mut_thing = Clone::clone(ref_thing); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:49:5 + --> tests/ui/assigning_clones.rs:55:5 | LL | *mut_thing = HasCloneFrom::clone(ref_thing); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:53:5 + --> tests/ui/assigning_clones.rs:60:5 | LL | *mut_thing = ::clone(ref_thing); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(mut_thing, ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:58:5 + --> tests/ui/assigning_clones.rs:66:5 | LL | *(mut_thing + &mut HasCloneFrom) = ref_thing.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `(mut_thing + &mut HasCloneFrom).clone_from(ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:63:5 + --> tests/ui/assigning_clones.rs:72:5 | LL | *mut_thing = (ref_thing + ref_thing).clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing + ref_thing)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:68:5 + --> tests/ui/assigning_clones.rs:78:5 | LL | s = format!("{} {}", "hello", "world").clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `s.clone_from(&format!("{} {}", "hello", "world"))` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:73:5 + --> tests/ui/assigning_clones.rs:84:5 | LL | s = Clone::clone(&format!("{} {}", "hello", "world")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"))` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:79:9 + --> tests/ui/assigning_clones.rs:91:9 | LL | a = b.clone(); | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:150:5 + --> tests/ui/assigning_clones.rs:163:5 | LL | a = b.clone(); | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:157:5 + --> tests/ui/assigning_clones.rs:171:5 | LL | a = b.clone(); | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:158:5 + --> tests/ui/assigning_clones.rs:173:5 | LL | a = c.to_owned(); | ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:188:5 + --> tests/ui/assigning_clones.rs:204:5 | LL | *a = b.clone(); | ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:192:5 + --> tests/ui/assigning_clones.rs:209:5 | LL | *a = b.clone(); | ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:196:5 + --> tests/ui/assigning_clones.rs:214:5 | LL | *a = b.clone(); | ^^^^^^^^^^^^^^ help: use `clone_from()`: `(*a).clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:200:5 + --> tests/ui/assigning_clones.rs:219:5 | LL | *a = b.clone(); | ^^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:204:5 + --> tests/ui/assigning_clones.rs:224:5 | LL | *a = Clone::clone(&b); | ^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut *a, &b)` error: assigning the result of `Clone::clone()` may be inefficient - --> tests/ui/assigning_clones.rs:208:5 + --> tests/ui/assigning_clones.rs:229:5 | LL | *a = Clone::clone(&b); | ^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut *a, &b)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:213:5 + --> tests/ui/assigning_clones.rs:235: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:217:5 + --> tests/ui/assigning_clones.rs:240: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:238:5 + --> tests/ui/assigning_clones.rs:262: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:242:5 + --> tests/ui/assigning_clones.rs:267: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:246:5 + --> tests/ui/assigning_clones.rs:272: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:250:5 + --> tests/ui/assigning_clones.rs:277:5 | LL | mut_thing = ToOwned::to_owned(ref_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:255:5 + --> tests/ui/assigning_clones.rs:283:5 | LL | s = format!("{} {}", "hello", "world").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `format!("{} {}", "hello", "world").clone_into(&mut s)` error: assigning the result of `ToOwned::to_owned()` may be inefficient - --> tests/ui/assigning_clones.rs:260:5 + --> tests/ui/assigning_clones.rs:289:5 | LL | s = ToOwned::to_owned(&format!("{} {}", "hello", "world")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s)` diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed index 48402164a827e..93c573d30863e 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.fixed +++ b/src/tools/clippy/tests/ui/async_yields_async.fixed @@ -38,9 +38,11 @@ fn main() { 3 }.await }; + //~^^^^ async_yields_async let _i = async { CustomFutureType.await }; + //~^^ async_yields_async let _i = async || { 3 }; @@ -49,10 +51,13 @@ fn main() { 3 }.await }; + //~^^^^ async_yields_async let _k = async || { CustomFutureType.await }; + //~^^ async_yields_async let _l = async || CustomFutureType.await; + //~^ async_yields_async let _m = async || { println!("I'm bored"); // Some more stuff @@ -60,6 +65,7 @@ fn main() { // Finally something to await CustomFutureType.await }; + //~^^ async_yields_async let _n = async || custom_future_type_ctor(); let _o = async || f(); } diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs index 8ad016b6bb4e0..166d522e1c04c 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.rs +++ b/src/tools/clippy/tests/ui/async_yields_async.rs @@ -38,9 +38,11 @@ fn main() { 3 } }; + //~^^^^ async_yields_async let _i = async { CustomFutureType }; + //~^^ async_yields_async let _i = async || { 3 }; @@ -49,10 +51,13 @@ fn main() { 3 } }; + //~^^^^ async_yields_async let _k = async || { CustomFutureType }; + //~^^ async_yields_async let _l = async || CustomFutureType; + //~^ async_yields_async let _m = async || { println!("I'm bored"); // Some more stuff @@ -60,6 +65,7 @@ fn main() { // Finally something to await CustomFutureType }; + //~^^ async_yields_async let _n = async || custom_future_type_ctor(); let _o = async || f(); } diff --git a/src/tools/clippy/tests/ui/async_yields_async.stderr b/src/tools/clippy/tests/ui/async_yields_async.stderr index 8c023d0d61f4a..17a35076fa3f1 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.stderr +++ b/src/tools/clippy/tests/ui/async_yields_async.stderr @@ -20,7 +20,7 @@ LL ~ }.await | error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:42:9 + --> tests/ui/async_yields_async.rs:43:9 | LL | let _i = async { | ____________________- @@ -33,7 +33,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:48:9 + --> tests/ui/async_yields_async.rs:50:9 | LL | let _j = async || { | ________________________- @@ -52,7 +52,7 @@ LL ~ }.await | error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:53:9 + --> tests/ui/async_yields_async.rs:56:9 | LL | let _k = async || { | _______________________- @@ -65,7 +65,7 @@ LL | | }; | |_____- outer async construct error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:55:23 + --> tests/ui/async_yields_async.rs:59:23 | LL | let _l = async || CustomFutureType; | ^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | let _l = async || CustomFutureType; | help: consider awaiting this value: `CustomFutureType.await` error: an async construct yields a type which is itself awaitable - --> tests/ui/async_yields_async.rs:61:9 + --> tests/ui/async_yields_async.rs:66:9 | LL | let _m = async || { | _______________________- diff --git a/src/tools/clippy/tests/ui/attrs.rs b/src/tools/clippy/tests/ui/attrs.rs index da96eabede17c..f60c71837d5e9 100644 --- a/src/tools/clippy/tests/ui/attrs.rs +++ b/src/tools/clippy/tests/ui/attrs.rs @@ -3,8 +3,7 @@ #![allow(clippy::missing_docs_in_private_items, clippy::panic, clippy::unreachable)] #[inline(always)] -//~^ ERROR: you have declared `#[inline(always)]` on `test_attr_lint`. This is usually a b -//~| NOTE: `-D clippy::inline-always` implied by `-D warnings` +//~^ inline_always fn test_attr_lint() { assert!(true) } @@ -25,12 +24,11 @@ fn empty_and_false_positive_stmt() { } #[deprecated(since = "forever")] -//~^ ERROR: the since field must contain a semver-compliant version -//~| NOTE: `-D clippy::deprecated-semver` implied by `-D warnings` +//~^ deprecated_semver pub const SOME_CONST: u8 = 42; #[deprecated(since = "1")] -//~^ ERROR: the since field must contain a semver-compliant version +//~^ deprecated_semver pub const ANOTHER_CONST: u8 = 23; #[deprecated(since = "0.1.1")] diff --git a/src/tools/clippy/tests/ui/attrs.stderr b/src/tools/clippy/tests/ui/attrs.stderr index a7fdceaba6f39..85b318cc0fdb7 100644 --- a/src/tools/clippy/tests/ui/attrs.stderr +++ b/src/tools/clippy/tests/ui/attrs.stderr @@ -1,5 +1,5 @@ error: the since field must contain a semver-compliant version - --> tests/ui/attrs.rs:27:14 + --> tests/ui/attrs.rs:26:14 | LL | #[deprecated(since = "forever")] | ^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #[deprecated(since = "forever")] = help: to override `-D warnings` add `#[allow(clippy::deprecated_semver)]` error: the since field must contain a semver-compliant version - --> tests/ui/attrs.rs:32:14 + --> tests/ui/attrs.rs:30:14 | LL | #[deprecated(since = "1")] | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/author.rs b/src/tools/clippy/tests/ui/author.rs index 0a1be35689670..faab114852fb8 100644 --- a/src/tools/clippy/tests/ui/author.rs +++ b/src/tools/clippy/tests/ui/author.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn main() { #[clippy::author] let x: char = 0x45 as char; diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui/author/blocks.rs index e9db611a2aa90..73e921e4c75d5 100644 --- a/src/tools/clippy/tests/ui/author/blocks.rs +++ b/src/tools/clippy/tests/ui/author/blocks.rs @@ -1,3 +1,4 @@ +//@ check-pass //@edition:2018 #![allow(redundant_semicolons, clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/author/call.rs b/src/tools/clippy/tests/ui/author/call.rs index e99c3c41dc4e1..8d48eb7bd3e37 100644 --- a/src/tools/clippy/tests/ui/author/call.rs +++ b/src/tools/clippy/tests/ui/author/call.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn main() { #[clippy::author] let _ = ::std::cmp::min(3, 4); diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui/author/if.rs index 946088ab34619..59bc9f5bfa5c2 100644 --- a/src/tools/clippy/tests/ui/author/if.rs +++ b/src/tools/clippy/tests/ui/author/if.rs @@ -1,3 +1,5 @@ +//@ check-pass + #[allow(clippy::all)] fn main() { diff --git a/src/tools/clippy/tests/ui/author/issue_3849.rs b/src/tools/clippy/tests/ui/author/issue_3849.rs index 5f65746d71f23..dbd63b21af296 100644 --- a/src/tools/clippy/tests/ui/author/issue_3849.rs +++ b/src/tools/clippy/tests/ui/author/issue_3849.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code)] #![allow(clippy::zero_ptr)] #![allow(clippy::transmute_ptr_to_ref)] diff --git a/src/tools/clippy/tests/ui/author/loop.rs b/src/tools/clippy/tests/ui/author/loop.rs index ff5b610011795..dcf6fbd720279 100644 --- a/src/tools/clippy/tests/ui/author/loop.rs +++ b/src/tools/clippy/tests/ui/author/loop.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(stmt_expr_attributes)] #![allow( clippy::never_loop, diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui/author/macro_in_closure.rs index 444e6a12165d2..8a02f38fad87b 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_closure.rs +++ b/src/tools/clippy/tests/ui/author/macro_in_closure.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn main() { #[clippy::author] let print_text = |x| println!("{}", x); diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui/author/macro_in_loop.rs index 8a520501f8dd4..84ffe416e839b 100644 --- a/src/tools/clippy/tests/ui/author/macro_in_loop.rs +++ b/src/tools/clippy/tests/ui/author/macro_in_loop.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(stmt_expr_attributes)] fn main() { diff --git a/src/tools/clippy/tests/ui/author/matches.rs b/src/tools/clippy/tests/ui/author/matches.rs index 674e07ec2d3da..e80d9c51023a7 100644 --- a/src/tools/clippy/tests/ui/author/matches.rs +++ b/src/tools/clippy/tests/ui/author/matches.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::let_and_return)] fn main() { diff --git a/src/tools/clippy/tests/ui/author/repeat.rs b/src/tools/clippy/tests/ui/author/repeat.rs index d8e9d589e689e..872f99844a01e 100644 --- a/src/tools/clippy/tests/ui/author/repeat.rs +++ b/src/tools/clippy/tests/ui/author/repeat.rs @@ -1,3 +1,5 @@ +//@ check-pass + #[allow(clippy::no_effect)] fn main() { #[clippy::author] diff --git a/src/tools/clippy/tests/ui/author/struct.rs b/src/tools/clippy/tests/ui/author/struct.rs index a99bdfc131379..73db44b733195 100644 --- a/src/tools/clippy/tests/ui/author/struct.rs +++ b/src/tools/clippy/tests/ui/author/struct.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow( clippy::unnecessary_operation, clippy::single_match, diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs index b0c92d8c1f6e6..e1db2e387497e 100644 --- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs +++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.rs @@ -4,13 +4,15 @@ use std::cell::RefCell; async fn bad(x: &RefCell) -> u32 { let b = x.borrow(); - //~^ ERROR: this `RefCell` reference is held across an await point + //~^ await_holding_refcell_ref + baz().await } async fn bad_mut(x: &RefCell) -> u32 { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an await point + //~^ await_holding_refcell_ref + baz().await } @@ -32,7 +34,7 @@ async fn also_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an await point + //~^ await_holding_refcell_ref let second = baz().await; @@ -45,7 +47,7 @@ async fn less_bad(x: &RefCell) -> u32 { let first = baz().await; let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an await point + //~^ await_holding_refcell_ref let second = baz().await; @@ -61,7 +63,8 @@ async fn not_good(x: &RefCell) -> u32 { let second = { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an await point + //~^ await_holding_refcell_ref + baz().await }; @@ -74,7 +77,8 @@ async fn not_good(x: &RefCell) -> u32 { fn block_bad(x: &RefCell) -> impl std::future::Future + '_ { async move { let b = x.borrow_mut(); - //~^ ERROR: this `RefCell` reference is held across an await point + //~^ await_holding_refcell_ref + baz().await } } diff --git a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr index 6c7209c9ff9e7..ed8aa747bd076 100644 --- a/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr +++ b/src/tools/clippy/tests/ui/await_holding_refcell_ref.stderr @@ -6,7 +6,7 @@ LL | let b = x.borrow(); | = help: ensure the reference is dropped before calling `await` note: these are all the await points this reference is held through - --> tests/ui/await_holding_refcell_ref.rs:8:11 + --> tests/ui/await_holding_refcell_ref.rs:9:11 | LL | baz().await | ^^^^^ @@ -14,27 +14,27 @@ LL | baz().await = help: to override `-D warnings` add `#[allow(clippy::await_holding_refcell_ref)]` error: this `RefCell` reference is held across an await point - --> tests/ui/await_holding_refcell_ref.rs:12:9 + --> tests/ui/await_holding_refcell_ref.rs:13:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` note: these are all the await points this reference is held through - --> tests/ui/await_holding_refcell_ref.rs:14:11 + --> tests/ui/await_holding_refcell_ref.rs:16:11 | LL | baz().await | ^^^^^ error: this `RefCell` reference is held across an await point - --> tests/ui/await_holding_refcell_ref.rs:34:9 + --> tests/ui/await_holding_refcell_ref.rs:36:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` note: these are all the await points this reference is held through - --> tests/ui/await_holding_refcell_ref.rs:37:24 + --> tests/ui/await_holding_refcell_ref.rs:39:24 | LL | let second = baz().await; | ^^^^^ @@ -43,40 +43,40 @@ LL | let third = baz().await; | ^^^^^ error: this `RefCell` reference is held across an await point - --> tests/ui/await_holding_refcell_ref.rs:47:9 + --> tests/ui/await_holding_refcell_ref.rs:49:9 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` note: these are all the await points this reference is held through - --> tests/ui/await_holding_refcell_ref.rs:50:24 + --> tests/ui/await_holding_refcell_ref.rs:52:24 | LL | let second = baz().await; | ^^^^^ error: this `RefCell` reference is held across an await point - --> tests/ui/await_holding_refcell_ref.rs:63:13 + --> tests/ui/await_holding_refcell_ref.rs:65:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` note: these are all the await points this reference is held through - --> tests/ui/await_holding_refcell_ref.rs:65:15 + --> tests/ui/await_holding_refcell_ref.rs:68:15 | LL | baz().await | ^^^^^ error: this `RefCell` reference is held across an await point - --> tests/ui/await_holding_refcell_ref.rs:76:13 + --> tests/ui/await_holding_refcell_ref.rs:79:13 | LL | let b = x.borrow_mut(); | ^ | = help: ensure the reference is dropped before calling `await` note: these are all the await points this reference is held through - --> tests/ui/await_holding_refcell_ref.rs:78:15 + --> tests/ui/await_holding_refcell_ref.rs:82:15 | LL | baz().await | ^^^^^ diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.fixed b/src/tools/clippy/tests/ui/bind_instead_of_map.fixed index 910cec2f203dc..80e010e2dfd74 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map.fixed +++ b/src/tools/clippy/tests/ui/bind_instead_of_map.fixed @@ -6,13 +6,16 @@ pub fn main() { let x = Some(5); // the easiest cases let _ = x; + //~^ bind_instead_of_map let _ = x.map(|o| o + 1); + //~^ bind_instead_of_map // and an easy counter-example let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); // Different type let x: Result = Ok(1); let _ = x; + //~^ bind_instead_of_map } pub fn foo() -> Option { diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.rs b/src/tools/clippy/tests/ui/bind_instead_of_map.rs index 6d66f659ba78b..09aa8480cbd9e 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map.rs +++ b/src/tools/clippy/tests/ui/bind_instead_of_map.rs @@ -6,13 +6,16 @@ pub fn main() { let x = Some(5); // the easiest cases let _ = x.and_then(Some); + //~^ bind_instead_of_map let _ = x.and_then(|o| Some(o + 1)); + //~^ bind_instead_of_map // and an easy counter-example let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); // Different type let x: Result = Ok(1); let _ = x.and_then(Ok); + //~^ bind_instead_of_map } pub fn foo() -> Option { diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map.stderr index 57e0e4fb84752..08f85fb58549c 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map.stderr +++ b/src/tools/clippy/tests/ui/bind_instead_of_map.stderr @@ -11,13 +11,13 @@ LL | #![deny(clippy::bind_instead_of_map)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> tests/ui/bind_instead_of_map.rs:9:13 + --> tests/ui/bind_instead_of_map.rs:10:13 | LL | let _ = x.and_then(|o| Some(o + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.map(|o| o + 1)` error: using `Result.and_then(Ok)`, which is a no-op - --> tests/ui/bind_instead_of_map.rs:15:13 + --> tests/ui/bind_instead_of_map.rs:17:13 | LL | let _ = x.and_then(Ok); | ^^^^^^^^^^^^^^ help: use the expression directly: `x` diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed index 8c77039b3c017..b61ce97fe8e63 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed @@ -3,12 +3,15 @@ pub fn main() { let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); + //~^ bind_instead_of_map let _ = Some("42").and_then(|s| if s.len() < 42 { None } else { Some(s.len()) }); let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); + //~^ bind_instead_of_map let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Err(()) } else { Ok(s.len()) }); let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } else { s.len() }); + //~^ bind_instead_of_map let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Ok(()) } else { Err(s.len()) }); hard_example(); @@ -17,6 +20,7 @@ pub fn main() { fn hard_example() { Some("42").map(|s| { + //~^ bind_instead_of_map if { if s == "43" { return 43; @@ -58,4 +62,5 @@ macro_rules! m { fn macro_example() { let _ = Some("").and_then(|s| if s.len() == 20 { m!() } else { Some(20) }); let _ = Some("").map(|s| if s.len() == 20 { m!() } else { Some(20) }); + //~^ bind_instead_of_map } diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs index 44257f3a46984..37f406def1972 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs @@ -3,12 +3,15 @@ pub fn main() { let _ = Some("42").and_then(|s| if s.len() < 42 { Some(0) } else { Some(s.len()) }); + //~^ bind_instead_of_map let _ = Some("42").and_then(|s| if s.len() < 42 { None } else { Some(s.len()) }); let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) }); + //~^ bind_instead_of_map let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Err(()) } else { Ok(s.len()) }); let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) }); + //~^ bind_instead_of_map let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Ok(()) } else { Err(s.len()) }); hard_example(); @@ -17,6 +20,7 @@ pub fn main() { fn hard_example() { Some("42").and_then(|s| { + //~^ bind_instead_of_map if { if s == "43" { return Some(43); @@ -58,4 +62,5 @@ macro_rules! m { fn macro_example() { let _ = Some("").and_then(|s| if s.len() == 20 { m!() } else { Some(20) }); let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) }); + //~^ bind_instead_of_map } diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr index 7c5882d4296ed..3ae11422357c0 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.stderr @@ -16,7 +16,7 @@ LL + let _ = Some("42").map(|s| if s.len() < 42 { 0 } else { s.len() }); | error: using `Result.and_then(|x| Ok(y))`, which is more succinctly expressed as `map(|x| y)` - --> tests/ui/bind_instead_of_map_multipart.rs:8:13 + --> tests/ui/bind_instead_of_map_multipart.rs:9:13 | LL | let _ = Ok::<_, ()>("42").and_then(|s| if s.len() < 42 { Ok(0) } else { Ok(s.len()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL + let _ = Ok::<_, ()>("42").map(|s| if s.len() < 42 { 0 } else { s.len() | error: using `Result.or_else(|x| Err(y))`, which is more succinctly expressed as `map_err(|x| y)` - --> tests/ui/bind_instead_of_map_multipart.rs:11:13 + --> tests/ui/bind_instead_of_map_multipart.rs:13:13 | LL | let _ = Err::<(), _>("42").or_else(|s| if s.len() < 42 { Err(s.len() + 20) } else { Err(s.len()) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,12 +40,12 @@ LL + let _ = Err::<(), _>("42").map_err(|s| if s.len() < 42 { s.len() + 20 } | error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> tests/ui/bind_instead_of_map_multipart.rs:19:5 + --> tests/ui/bind_instead_of_map_multipart.rs:22:5 | LL | / Some("42").and_then(|s| { +LL | | LL | | if { LL | | if s == "43" { -LL | | return Some(43); ... | LL | | }); | |______^ @@ -53,6 +53,7 @@ LL | | }); help: use `map` instead | LL ~ Some("42").map(|s| { +LL | LL | if { LL | if s == "43" { LL ~ return 43; @@ -79,7 +80,7 @@ LL ~ _ => 1, | error: using `Option.and_then(|x| Some(y))`, which is more succinctly expressed as `map(|x| y)` - --> tests/ui/bind_instead_of_map_multipart.rs:60:13 + --> tests/ui/bind_instead_of_map_multipart.rs:64:13 | LL | let _ = Some("").and_then(|s| if s.len() == 20 { Some(m!()) } else { Some(Some(20)) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/bit_masks.rs b/src/tools/clippy/tests/ui/bit_masks.rs index 8e1d066c25e49..87dcdb3084d00 100644 --- a/src/tools/clippy/tests/ui/bit_masks.rs +++ b/src/tools/clippy/tests/ui/bit_masks.rs @@ -12,27 +12,29 @@ fn main() { let x = 5; x & 0 == 0; - //~^ ERROR: &-masking with zero - //~| NOTE: `-D clippy::bad-bit-mask` implied by `-D warnings` - //~| ERROR: this operation will always return zero. This is likely not the intended ou - //~| NOTE: `#[deny(clippy::erasing_op)]` on by default + //~^ bad_bit_mask + //~| erasing_op + x & 1 == 1; //ok, distinguishes bit 0 x & 1 == 0; //ok, compared with zero x & 2 == 1; - //~^ ERROR: incompatible bit mask: `_ & 2` can never be equal to `1` + //~^ bad_bit_mask + x | 0 == 0; //ok, equals x == 0 (maybe warn?) x | 1 == 3; //ok, equals x == 2 || x == 3 x | 3 == 3; //ok, equals x <= 3 x | 3 == 2; - //~^ ERROR: incompatible bit mask: `_ | 3` can never be equal to `2` + //~^ bad_bit_mask x & 1 > 1; - //~^ ERROR: incompatible bit mask: `_ & 1` will never be higher than `1` + //~^ bad_bit_mask + x & 2 > 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 x & 2 < 1; // ok, distinguishes x & 2 == 2 from x & 2 == 0 x | 1 > 1; // ok (if a bit silly), equals x > 1 x | 2 > 1; - //~^ ERROR: incompatible bit mask: `_ | 2` will always be higher than `1` + //~^ bad_bit_mask + x | 2 <= 2; // ok (if a bit silly), equals x <= 2 x & 192 == 128; // ok, tests for bit 7 and not bit 6 @@ -40,22 +42,26 @@ fn main() { // this also now works with constants x & THREE_BITS == 8; - //~^ ERROR: incompatible bit mask: `_ & 7` can never be equal to `8` + //~^ bad_bit_mask + x | EVEN_MORE_REDIRECTION < 7; - //~^ ERROR: incompatible bit mask: `_ | 7` will never be lower than `7` + //~^ bad_bit_mask 0 & x == 0; - //~^ ERROR: &-masking with zero - //~| ERROR: this operation will always return zero. This is likely not the intended ou + //~^ bad_bit_mask + //~| erasing_op + 1 | x > 1; // and should now also match uncommon usage 1 < 2 | x; - //~^ ERROR: incompatible bit mask: `_ | 2` will always be higher than `1` + //~^ bad_bit_mask + 2 == 3 | x; - //~^ ERROR: incompatible bit mask: `_ | 3` can never be equal to `2` + //~^ bad_bit_mask + 1 == x & 2; - //~^ ERROR: incompatible bit mask: `_ & 2` can never be equal to `1` + //~^ bad_bit_mask x | 1 > 2; // no error, because we allowed ineffective bit masks ineffective(); @@ -67,14 +73,16 @@ fn ineffective() { let x = 5; x | 1 > 3; - //~^ ERROR: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared d - //~| NOTE: `-D clippy::ineffective-bit-mask` implied by `-D warnings` + //~^ ineffective_bit_mask + x | 1 < 4; - //~^ ERROR: ineffective bit mask: `x | 1` compared to `4`, is the same as x compared d + //~^ ineffective_bit_mask + x | 1 <= 3; - //~^ ERROR: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared d + //~^ ineffective_bit_mask + x | 1 >= 8; - //~^ ERROR: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared d + //~^ ineffective_bit_mask x | 1 > 2; // not an error (yet), better written as x >= 2 x | 1 >= 7; // not an error (yet), better written as x >= 6 diff --git a/src/tools/clippy/tests/ui/bit_masks.stderr b/src/tools/clippy/tests/ui/bit_masks.stderr index 004f6ad94841b..666ad671edee6 100644 --- a/src/tools/clippy/tests/ui/bit_masks.stderr +++ b/src/tools/clippy/tests/ui/bit_masks.stderr @@ -16,7 +16,7 @@ LL | x & 0 == 0; = note: `#[deny(clippy::erasing_op)]` on by default error: incompatible bit mask: `_ & 2` can never be equal to `1` - --> tests/ui/bit_masks.rs:21:5 + --> tests/ui/bit_masks.rs:20:5 | LL | x & 2 == 1; | ^^^^^^^^^^ @@ -34,55 +34,55 @@ LL | x & 1 > 1; | ^^^^^^^^^ error: incompatible bit mask: `_ | 2` will always be higher than `1` - --> tests/ui/bit_masks.rs:34:5 + --> tests/ui/bit_masks.rs:35:5 | LL | x | 2 > 1; | ^^^^^^^^^ error: incompatible bit mask: `_ & 7` can never be equal to `8` - --> tests/ui/bit_masks.rs:42:5 + --> tests/ui/bit_masks.rs:44:5 | LL | x & THREE_BITS == 8; | ^^^^^^^^^^^^^^^^^^^ error: incompatible bit mask: `_ | 7` will never be lower than `7` - --> tests/ui/bit_masks.rs:44:5 + --> tests/ui/bit_masks.rs:47:5 | LL | x | EVEN_MORE_REDIRECTION < 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: &-masking with zero - --> tests/ui/bit_masks.rs:47:5 + --> tests/ui/bit_masks.rs:50:5 | LL | 0 & x == 0; | ^^^^^^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> tests/ui/bit_masks.rs:47:5 + --> tests/ui/bit_masks.rs:50:5 | LL | 0 & x == 0; | ^^^^^ error: incompatible bit mask: `_ | 2` will always be higher than `1` - --> tests/ui/bit_masks.rs:53:5 + --> tests/ui/bit_masks.rs:57:5 | LL | 1 < 2 | x; | ^^^^^^^^^ error: incompatible bit mask: `_ | 3` can never be equal to `2` - --> tests/ui/bit_masks.rs:55:5 + --> tests/ui/bit_masks.rs:60:5 | LL | 2 == 3 | x; | ^^^^^^^^^^ error: incompatible bit mask: `_ & 2` can never be equal to `1` - --> tests/ui/bit_masks.rs:57:5 + --> tests/ui/bit_masks.rs:63:5 | LL | 1 == x & 2; | ^^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly - --> tests/ui/bit_masks.rs:69:5 + --> tests/ui/bit_masks.rs:75:5 | LL | x | 1 > 3; | ^^^^^^^^^ @@ -91,19 +91,19 @@ LL | x | 1 > 3; = help: to override `-D warnings` add `#[allow(clippy::ineffective_bit_mask)]` error: ineffective bit mask: `x | 1` compared to `4`, is the same as x compared directly - --> tests/ui/bit_masks.rs:72:5 + --> tests/ui/bit_masks.rs:78:5 | LL | x | 1 < 4; | ^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `3`, is the same as x compared directly - --> tests/ui/bit_masks.rs:74:5 + --> tests/ui/bit_masks.rs:81:5 | LL | x | 1 <= 3; | ^^^^^^^^^^ error: ineffective bit mask: `x | 1` compared to `8`, is the same as x compared directly - --> tests/ui/bit_masks.rs:76:5 + --> tests/ui/bit_masks.rs:84:5 | LL | x | 1 >= 8; | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs index 2bfaadf8df94e..de699309b16d1 100644 --- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs @@ -1,13 +1,14 @@ //@compile-flags: -W clippy::restriction +//@error-in-other-file: restriction #![warn(clippy::blanket_clippy_restriction_lints)] //! Test that the whole restriction group is not enabled #![warn(clippy::restriction)] -//~^ ERROR: `clippy::restriction` is not meant to be enabled as a group +//~^ blanket_clippy_restriction_lints #![deny(clippy::restriction)] -//~^ ERROR: `clippy::restriction` is not meant to be enabled as a group +//~^ blanket_clippy_restriction_lints #![forbid(clippy::restriction)] -//~^ ERROR: `clippy::restriction` is not meant to be enabled as a group +//~^ blanket_clippy_restriction_lints fn main() {} diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr index 1bad259b09a36..ff3a7cfc3931b 100644 --- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr +++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.stderr @@ -6,7 +6,7 @@ error: `clippy::restriction` is not meant to be enabled as a group = help: to override `-D warnings` add `#[allow(clippy::blanket_clippy_restriction_lints)]` error: `clippy::restriction` is not meant to be enabled as a group - --> tests/ui/blanket_clippy_restriction_lints.rs:6:9 + --> tests/ui/blanket_clippy_restriction_lints.rs:7:9 | LL | #![warn(clippy::restriction)] | ^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL | #![warn(clippy::restriction)] = help: enable the restriction lints you need individually error: `clippy::restriction` is not meant to be enabled as a group - --> tests/ui/blanket_clippy_restriction_lints.rs:8:9 + --> tests/ui/blanket_clippy_restriction_lints.rs:9:9 | LL | #![deny(clippy::restriction)] | ^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | #![deny(clippy::restriction)] = help: enable the restriction lints you need individually error: `clippy::restriction` is not meant to be enabled as a group - --> tests/ui/blanket_clippy_restriction_lints.rs:10:11 + --> tests/ui/blanket_clippy_restriction_lints.rs:11:11 | LL | #![forbid(clippy::restriction)] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index af8e65270d091..df375e370573c 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -46,6 +46,7 @@ fn condition_has_block_with_single_expression() -> i32 { fn condition_is_normal() -> i32 { let x = 3; if x == 3 { 6 } else { 10 } + //~^ nonminimal_bool } fn condition_is_unsafe_block() { diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index 6adae951a2901..1d9c9dd424603 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -46,6 +46,7 @@ fn condition_has_block_with_single_expression() -> i32 { fn condition_is_normal() -> i32 { let x = 3; if true && x == 3 { 6 } else { 10 } + //~^ nonminimal_bool } fn condition_is_unsafe_block() { diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr index a55e1efb575ea..da21344a84289 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr @@ -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:75:5 + --> tests/ui/blocks_in_conditions.rs:76:5 | LL | / match { LL | | diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed index b05166a055ee3..721d8b2c2dcd2 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed @@ -85,65 +85,90 @@ fn main() { assert_eq!("a".len(), 1); assert!(!"a".is_empty()); + //~^ bool_assert_comparison assert!("".is_empty()); + //~^ bool_assert_comparison assert!("".is_empty()); + //~^ bool_assert_comparison assert_eq!(a!(), b!()); assert_eq!(a!(), "".is_empty()); assert_eq!("".is_empty(), b!()); assert_eq!(a, true); assert!(b); + //~^ bool_assert_comparison assert_ne!("a".len(), 1); assert!("a".is_empty()); + //~^ bool_assert_comparison assert!(!"".is_empty()); + //~^ bool_assert_comparison assert!(!"".is_empty()); + //~^ bool_assert_comparison assert_ne!(a!(), b!()); assert_ne!(a!(), "".is_empty()); assert_ne!("".is_empty(), b!()); assert_ne!(a, true); assert!(!b); + //~^ bool_assert_comparison debug_assert_eq!("a".len(), 1); debug_assert!(!"a".is_empty()); + //~^ bool_assert_comparison debug_assert!("".is_empty()); + //~^ bool_assert_comparison debug_assert!("".is_empty()); + //~^ bool_assert_comparison debug_assert_eq!(a!(), b!()); debug_assert_eq!(a!(), "".is_empty()); debug_assert_eq!("".is_empty(), b!()); debug_assert_eq!(a, true); debug_assert!(b); + //~^ bool_assert_comparison debug_assert_ne!("a".len(), 1); debug_assert!("a".is_empty()); + //~^ bool_assert_comparison debug_assert!(!"".is_empty()); + //~^ bool_assert_comparison debug_assert!(!"".is_empty()); + //~^ bool_assert_comparison debug_assert_ne!(a!(), b!()); debug_assert_ne!(a!(), "".is_empty()); debug_assert_ne!("".is_empty(), b!()); debug_assert_ne!(a, true); debug_assert!(!b); + //~^ bool_assert_comparison // assert with error messages assert_eq!("a".len(), 1, "tadam {}", 1); assert_eq!("a".len(), 1, "tadam {}", true); assert!(!"a".is_empty(), "tadam {}", 1); + //~^ bool_assert_comparison assert!(!"a".is_empty(), "tadam {}", true); + //~^ bool_assert_comparison assert!(!"a".is_empty(), "tadam {}", true); + //~^ bool_assert_comparison assert_eq!(a, true, "tadam {}", false); debug_assert_eq!("a".len(), 1, "tadam {}", 1); debug_assert_eq!("a".len(), 1, "tadam {}", true); debug_assert!(!"a".is_empty(), "tadam {}", 1); + //~^ bool_assert_comparison debug_assert!(!"a".is_empty(), "tadam {}", true); + //~^ bool_assert_comparison debug_assert!(!"a".is_empty(), "tadam {}", true); + //~^ bool_assert_comparison debug_assert_eq!(a, true, "tadam {}", false); assert!(a!()); + //~^ bool_assert_comparison assert!(b!()); + //~^ bool_assert_comparison use debug_assert_eq as renamed; renamed!(a, true); debug_assert!(b); + //~^ bool_assert_comparison let non_copy = NonCopy; assert_eq!(non_copy, true); @@ -158,12 +183,20 @@ fn main() { in_macro!(a); assert!("".is_empty()); + //~^ bool_assert_comparison assert!("".is_empty()); + //~^ bool_assert_comparison assert!(!"requires negation".is_empty()); + //~^ bool_assert_comparison assert!(!"requires negation".is_empty()); + //~^ bool_assert_comparison debug_assert!("".is_empty()); + //~^ bool_assert_comparison debug_assert!("".is_empty()); + //~^ bool_assert_comparison debug_assert!(!"requires negation".is_empty()); + //~^ bool_assert_comparison debug_assert!(!"requires negation".is_empty()); + //~^ bool_assert_comparison } diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.rs b/src/tools/clippy/tests/ui/bool_assert_comparison.rs index dc51fcf1d36b9..5ab4f475b063d 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.rs +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.rs @@ -85,65 +85,90 @@ fn main() { assert_eq!("a".len(), 1); assert_eq!("a".is_empty(), false); + //~^ bool_assert_comparison assert_eq!("".is_empty(), true); + //~^ bool_assert_comparison assert_eq!(true, "".is_empty()); + //~^ bool_assert_comparison assert_eq!(a!(), b!()); assert_eq!(a!(), "".is_empty()); assert_eq!("".is_empty(), b!()); assert_eq!(a, true); assert_eq!(b, true); + //~^ bool_assert_comparison assert_ne!("a".len(), 1); assert_ne!("a".is_empty(), false); + //~^ bool_assert_comparison assert_ne!("".is_empty(), true); + //~^ bool_assert_comparison assert_ne!(true, "".is_empty()); + //~^ bool_assert_comparison assert_ne!(a!(), b!()); assert_ne!(a!(), "".is_empty()); assert_ne!("".is_empty(), b!()); assert_ne!(a, true); assert_ne!(b, true); + //~^ bool_assert_comparison debug_assert_eq!("a".len(), 1); debug_assert_eq!("a".is_empty(), false); + //~^ bool_assert_comparison debug_assert_eq!("".is_empty(), true); + //~^ bool_assert_comparison debug_assert_eq!(true, "".is_empty()); + //~^ bool_assert_comparison debug_assert_eq!(a!(), b!()); debug_assert_eq!(a!(), "".is_empty()); debug_assert_eq!("".is_empty(), b!()); debug_assert_eq!(a, true); debug_assert_eq!(b, true); + //~^ bool_assert_comparison debug_assert_ne!("a".len(), 1); debug_assert_ne!("a".is_empty(), false); + //~^ bool_assert_comparison debug_assert_ne!("".is_empty(), true); + //~^ bool_assert_comparison debug_assert_ne!(true, "".is_empty()); + //~^ bool_assert_comparison debug_assert_ne!(a!(), b!()); debug_assert_ne!(a!(), "".is_empty()); debug_assert_ne!("".is_empty(), b!()); debug_assert_ne!(a, true); debug_assert_ne!(b, true); + //~^ bool_assert_comparison // assert with error messages assert_eq!("a".len(), 1, "tadam {}", 1); assert_eq!("a".len(), 1, "tadam {}", true); assert_eq!("a".is_empty(), false, "tadam {}", 1); + //~^ bool_assert_comparison assert_eq!("a".is_empty(), false, "tadam {}", true); + //~^ bool_assert_comparison assert_eq!(false, "a".is_empty(), "tadam {}", true); + //~^ bool_assert_comparison assert_eq!(a, true, "tadam {}", false); debug_assert_eq!("a".len(), 1, "tadam {}", 1); debug_assert_eq!("a".len(), 1, "tadam {}", true); debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); + //~^ bool_assert_comparison debug_assert_eq!("a".is_empty(), false, "tadam {}", true); + //~^ bool_assert_comparison debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); + //~^ bool_assert_comparison debug_assert_eq!(a, true, "tadam {}", false); assert_eq!(a!(), true); + //~^ bool_assert_comparison assert_eq!(true, b!()); + //~^ bool_assert_comparison use debug_assert_eq as renamed; renamed!(a, true); renamed!(b, true); + //~^ bool_assert_comparison let non_copy = NonCopy; assert_eq!(non_copy, true); @@ -158,12 +183,20 @@ fn main() { in_macro!(a); assert_eq!("".is_empty(), true); + //~^ bool_assert_comparison assert_ne!("".is_empty(), false); + //~^ bool_assert_comparison assert_ne!("requires negation".is_empty(), true); + //~^ bool_assert_comparison assert_eq!("requires negation".is_empty(), false); + //~^ bool_assert_comparison debug_assert_eq!("".is_empty(), true); + //~^ bool_assert_comparison debug_assert_ne!("".is_empty(), false); + //~^ bool_assert_comparison debug_assert_ne!("requires negation".is_empty(), true); + //~^ bool_assert_comparison debug_assert_eq!("requires negation".is_empty(), false); + //~^ bool_assert_comparison } diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr index 41183c61ee01d..a1d0af5436176 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr @@ -13,7 +13,7 @@ LL + assert!(!"a".is_empty()); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:88:5 + --> tests/ui/bool_assert_comparison.rs:89:5 | LL | assert_eq!("".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + assert!("".is_empty()); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:89:5 + --> tests/ui/bool_assert_comparison.rs:91:5 | LL | assert_eq!(true, "".is_empty()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + assert!("".is_empty()); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:94:5 + --> tests/ui/bool_assert_comparison.rs:97:5 | LL | assert_eq!(b, true); | ^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + assert!(b); | error: used `assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:97:5 + --> tests/ui/bool_assert_comparison.rs:101:5 | LL | assert_ne!("a".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + assert!("a".is_empty()); | error: used `assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:98:5 + --> tests/ui/bool_assert_comparison.rs:103:5 | LL | assert_ne!("".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + assert!(!"".is_empty()); | error: used `assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:99:5 + --> tests/ui/bool_assert_comparison.rs:105:5 | LL | assert_ne!(true, "".is_empty()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + assert!(!"".is_empty()); | error: used `assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:104:5 + --> tests/ui/bool_assert_comparison.rs:111:5 | LL | assert_ne!(b, true); | ^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + assert!(!b); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:107:5 + --> tests/ui/bool_assert_comparison.rs:115:5 | LL | debug_assert_eq!("a".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + debug_assert!(!"a".is_empty()); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:108:5 + --> tests/ui/bool_assert_comparison.rs:117:5 | LL | debug_assert_eq!("".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + debug_assert!("".is_empty()); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:109:5 + --> tests/ui/bool_assert_comparison.rs:119:5 | LL | debug_assert_eq!(true, "".is_empty()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + debug_assert!("".is_empty()); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:114:5 + --> tests/ui/bool_assert_comparison.rs:125:5 | LL | debug_assert_eq!(b, true); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + debug_assert!(b); | error: used `debug_assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:117:5 + --> tests/ui/bool_assert_comparison.rs:129:5 | LL | debug_assert_ne!("a".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + debug_assert!("a".is_empty()); | error: used `debug_assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:118:5 + --> tests/ui/bool_assert_comparison.rs:131:5 | LL | debug_assert_ne!("".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + debug_assert!(!"".is_empty()); | error: used `debug_assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:119:5 + --> tests/ui/bool_assert_comparison.rs:133:5 | LL | debug_assert_ne!(true, "".is_empty()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + debug_assert!(!"".is_empty()); | error: used `debug_assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:124:5 + --> tests/ui/bool_assert_comparison.rs:139:5 | LL | debug_assert_ne!(b, true); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + debug_assert!(!b); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:129:5 + --> tests/ui/bool_assert_comparison.rs:145:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + assert!(!"a".is_empty(), "tadam {}", 1); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:130:5 + --> tests/ui/bool_assert_comparison.rs:147:5 | LL | assert_eq!("a".is_empty(), false, "tadam {}", true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + assert!(!"a".is_empty(), "tadam {}", true); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:131:5 + --> tests/ui/bool_assert_comparison.rs:149:5 | LL | assert_eq!(false, "a".is_empty(), "tadam {}", true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + assert!(!"a".is_empty(), "tadam {}", true); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:136:5 + --> tests/ui/bool_assert_comparison.rs:155:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + debug_assert!(!"a".is_empty(), "tadam {}", 1); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:137:5 + --> tests/ui/bool_assert_comparison.rs:157:5 | LL | debug_assert_eq!("a".is_empty(), false, "tadam {}", true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL + debug_assert!(!"a".is_empty(), "tadam {}", true); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:138:5 + --> tests/ui/bool_assert_comparison.rs:159:5 | LL | debug_assert_eq!(false, "a".is_empty(), "tadam {}", true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL + debug_assert!(!"a".is_empty(), "tadam {}", true); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:141:5 + --> tests/ui/bool_assert_comparison.rs:163:5 | LL | assert_eq!(a!(), true); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + assert!(a!()); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:142:5 + --> tests/ui/bool_assert_comparison.rs:165:5 | LL | assert_eq!(true, b!()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -289,7 +289,7 @@ LL + assert!(b!()); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:146:5 + --> tests/ui/bool_assert_comparison.rs:170:5 | LL | renamed!(b, true); | ^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL + debug_assert!(b); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:160:5 + --> tests/ui/bool_assert_comparison.rs:185:5 | LL | assert_eq!("".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + assert!("".is_empty()); | error: used `assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:161:5 + --> tests/ui/bool_assert_comparison.rs:187:5 | LL | assert_ne!("".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + assert!("".is_empty()); | error: used `assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:162:5 + --> tests/ui/bool_assert_comparison.rs:189:5 | LL | assert_ne!("requires negation".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + assert!(!"requires negation".is_empty()); | error: used `assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:163:5 + --> tests/ui/bool_assert_comparison.rs:191:5 | LL | assert_eq!("requires negation".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + assert!(!"requires negation".is_empty()); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:165:5 + --> tests/ui/bool_assert_comparison.rs:194:5 | LL | debug_assert_eq!("".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,7 +361,7 @@ LL + debug_assert!("".is_empty()); | error: used `debug_assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:166:5 + --> tests/ui/bool_assert_comparison.rs:196:5 | LL | debug_assert_ne!("".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL + debug_assert!("".is_empty()); | error: used `debug_assert_ne!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:167:5 + --> tests/ui/bool_assert_comparison.rs:198:5 | LL | debug_assert_ne!("requires negation".is_empty(), true); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -385,7 +385,7 @@ LL + debug_assert!(!"requires negation".is_empty()); | error: used `debug_assert_eq!` with a literal bool - --> tests/ui/bool_assert_comparison.rs:168:5 + --> tests/ui/bool_assert_comparison.rs:200:5 | LL | debug_assert_eq!("requires negation".is_empty(), false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed index 3db91eec8fa75..166abbe549c3d 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.fixed +++ b/src/tools/clippy/tests/ui/bool_comparison.fixed @@ -5,72 +5,86 @@ fn main() { let x = true; if x { + //~^ bool_comparison "yes" } else { "no" }; if !x { + //~^ bool_comparison "yes" } else { "no" }; if x { + //~^ bool_comparison "yes" } else { "no" }; if !x { + //~^ bool_comparison "yes" } else { "no" }; if !x { + //~^ bool_comparison "yes" } else { "no" }; if x { + //~^ bool_comparison "yes" } else { "no" }; if !x { + //~^ bool_comparison "yes" } else { "no" }; if x { + //~^ bool_comparison "yes" } else { "no" }; if !x { + //~^ bool_comparison "yes" } else { "no" }; if x { + //~^ bool_comparison "yes" } else { "no" }; if x { + //~^ bool_comparison "yes" } else { "no" }; if !x { + //~^ bool_comparison "yes" } else { "no" }; let y = true; if !x & y { + //~^ bool_comparison "yes" } else { "no" }; if x & !y { + //~^ bool_comparison "yes" } else { "no" @@ -119,12 +133,16 @@ fn issue4983() { let b = false; if a != b {}; + //~^ bool_comparison if a != b {}; + //~^ bool_comparison if a == b {}; if !a == !b {}; if b != a {}; + //~^ bool_comparison if b != a {}; + //~^ bool_comparison if b == a {}; if !b == !a {}; } @@ -149,9 +167,13 @@ fn issue3973() { // lint, could be simplified if !m!(func) {} + //~^ bool_comparison if !m!(func) {} + //~^ bool_comparison if m!(func) {} + //~^ bool_comparison if m!(func) {} + //~^ bool_comparison // no lint with a variable let is_debug = false; @@ -169,8 +191,11 @@ fn issue3973() { #[allow(clippy::unnecessary_cast)] fn issue9907() { let _ = (1 >= 2) as usize; + //~^ bool_comparison let _ = (!m!(func)) as usize; + //~^ bool_comparison // This is not part of the issue, but an unexpected found when fixing the issue, // the provided span was inside of macro rather than the macro callsite. let _ = ((1 < 2) != m!(func)) as usize; + //~^ bool_comparison } diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs index fbcfb1cee7bf2..7265c2b4c5a6f 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.rs +++ b/src/tools/clippy/tests/ui/bool_comparison.rs @@ -5,72 +5,86 @@ fn main() { let x = true; if x == true { + //~^ bool_comparison "yes" } else { "no" }; if x == false { + //~^ bool_comparison "yes" } else { "no" }; if true == x { + //~^ bool_comparison "yes" } else { "no" }; if false == x { + //~^ bool_comparison "yes" } else { "no" }; if x != true { + //~^ bool_comparison "yes" } else { "no" }; if x != false { + //~^ bool_comparison "yes" } else { "no" }; if true != x { + //~^ bool_comparison "yes" } else { "no" }; if false != x { + //~^ bool_comparison "yes" } else { "no" }; if x < true { + //~^ bool_comparison "yes" } else { "no" }; if false < x { + //~^ bool_comparison "yes" } else { "no" }; if x > false { + //~^ bool_comparison "yes" } else { "no" }; if true > x { + //~^ bool_comparison "yes" } else { "no" }; let y = true; if x < y { + //~^ bool_comparison "yes" } else { "no" }; if x > y { + //~^ bool_comparison "yes" } else { "no" @@ -119,12 +133,16 @@ fn issue4983() { let b = false; if a == !b {}; + //~^ bool_comparison if !a == b {}; + //~^ bool_comparison if a == b {}; if !a == !b {}; if b == !a {}; + //~^ bool_comparison if !b == a {}; + //~^ bool_comparison if b == a {}; if !b == !a {}; } @@ -149,9 +167,13 @@ fn issue3973() { // lint, could be simplified if false == m!(func) {} + //~^ bool_comparison if m!(func) == false {} + //~^ bool_comparison if true == m!(func) {} + //~^ bool_comparison if m!(func) == true {} + //~^ bool_comparison // no lint with a variable let is_debug = false; @@ -169,8 +191,11 @@ fn issue3973() { #[allow(clippy::unnecessary_cast)] fn issue9907() { let _ = ((1 < 2) == false) as usize; + //~^ bool_comparison let _ = (false == m!(func)) as usize; + //~^ bool_comparison // This is not part of the issue, but an unexpected found when fixing the issue, // the provided span was inside of macro rather than the macro callsite. let _ = ((1 < 2) == !m!(func)) as usize; + //~^ bool_comparison } diff --git a/src/tools/clippy/tests/ui/bool_comparison.stderr b/src/tools/clippy/tests/ui/bool_comparison.stderr index 7c8b906221fa9..ddbb9ff78edb3 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.stderr +++ b/src/tools/clippy/tests/ui/bool_comparison.stderr @@ -8,145 +8,145 @@ LL | if x == true { = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:12:8 + --> tests/ui/bool_comparison.rs:13:8 | LL | if x == false { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> tests/ui/bool_comparison.rs:17:8 + --> tests/ui/bool_comparison.rs:19:8 | LL | if true == x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:22:8 + --> tests/ui/bool_comparison.rs:25:8 | LL | if false == x { | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:27:8 + --> tests/ui/bool_comparison.rs:31:8 | LL | if x != true { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> tests/ui/bool_comparison.rs:32:8 + --> tests/ui/bool_comparison.rs:37:8 | LL | if x != false { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: inequality checks against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:37:8 + --> tests/ui/bool_comparison.rs:43:8 | LL | if true != x { | ^^^^^^^^^ help: try simplifying it as shown: `!x` error: inequality checks against false are unnecessary - --> tests/ui/bool_comparison.rs:42:8 + --> tests/ui/bool_comparison.rs:49:8 | LL | if false != x { | ^^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:47:8 + --> tests/ui/bool_comparison.rs:55:8 | LL | if x < true { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: greater than checks against false are unnecessary - --> tests/ui/bool_comparison.rs:52:8 + --> tests/ui/bool_comparison.rs:61:8 | LL | if false < x { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: greater than checks against false are unnecessary - --> tests/ui/bool_comparison.rs:57:8 + --> tests/ui/bool_comparison.rs:67:8 | LL | if x > false { | ^^^^^^^^^ help: try simplifying it as shown: `x` error: less than comparison against true can be replaced by a negation - --> tests/ui/bool_comparison.rs:62:8 + --> tests/ui/bool_comparison.rs:73:8 | LL | if true > x { | ^^^^^^^^ help: try simplifying it as shown: `!x` error: order comparisons between booleans can be simplified - --> tests/ui/bool_comparison.rs:68:8 + --> tests/ui/bool_comparison.rs:80:8 | LL | if x < y { | ^^^^^ help: try simplifying it as shown: `!x & y` error: order comparisons between booleans can be simplified - --> tests/ui/bool_comparison.rs:73:8 + --> tests/ui/bool_comparison.rs:86:8 | LL | if x > y { | ^^^^^ help: try simplifying it as shown: `x & !y` error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:121:8 + --> tests/ui/bool_comparison.rs:135:8 | LL | if a == !b {}; | ^^^^^^^ help: try simplifying it as shown: `a != b` error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:122:8 + --> tests/ui/bool_comparison.rs:137:8 | LL | if !a == b {}; | ^^^^^^^ help: try simplifying it as shown: `a != b` error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:126:8 + --> tests/ui/bool_comparison.rs:142:8 | LL | if b == !a {}; | ^^^^^^^ help: try simplifying it as shown: `b != a` error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:127:8 + --> tests/ui/bool_comparison.rs:144:8 | LL | if !b == a {}; | ^^^^^^^ help: try simplifying it as shown: `b != a` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:151:8 + --> tests/ui/bool_comparison.rs:169:8 | LL | if false == m!(func) {} | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:152:8 + --> tests/ui/bool_comparison.rs:171:8 | LL | if m!(func) == false {} | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` error: equality checks against true are unnecessary - --> tests/ui/bool_comparison.rs:153:8 + --> tests/ui/bool_comparison.rs:173:8 | LL | if true == m!(func) {} | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` error: equality checks against true are unnecessary - --> tests/ui/bool_comparison.rs:154:8 + --> tests/ui/bool_comparison.rs:175:8 | LL | if m!(func) == true {} | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `m!(func)` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:171:14 + --> tests/ui/bool_comparison.rs:193:14 | LL | let _ = ((1 < 2) == false) as usize; | ^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `1 >= 2` error: equality checks against false can be replaced by a negation - --> tests/ui/bool_comparison.rs:172:14 + --> tests/ui/bool_comparison.rs:195:14 | LL | let _ = (false == m!(func)) as usize; | ^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `!m!(func)` error: this comparison might be written more concisely - --> tests/ui/bool_comparison.rs:175:14 + --> tests/ui/bool_comparison.rs:199:14 | LL | let _ = ((1 < 2) == !m!(func)) as usize; | ^^^^^^^^^^^^^^^^^^^^ help: try simplifying it as shown: `(1 < 2) != m!(func)` diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed index f7dad28b0369a..0080801d46b78 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed @@ -88,6 +88,7 @@ fn main() { // Lint returns and type inference fn some_fn(a: bool) -> u8 { u8::from(a) + //~^ bool_to_int_with_if } fn side_effect() {} diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs index d22871d2c8f2e..72c7e2c71c560 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs @@ -12,31 +12,37 @@ fn main() { // Should lint // precedence if a { + //~^ bool_to_int_with_if 1 } else { 0 }; if a { + //~^ bool_to_int_with_if 0 } else { 1 }; if !a { + //~^ bool_to_int_with_if 1 } else { 0 }; if a || b { + //~^ bool_to_int_with_if 1 } else { 0 }; if cond(a, b) { + //~^ bool_to_int_with_if 1 } else { 0 }; if x + y < 4 { + //~^ bool_to_int_with_if 1 } else { 0 @@ -46,6 +52,7 @@ fn main() { if a { 123 } else if b { + //~^ bool_to_int_with_if 1 } else { 0 @@ -55,6 +62,7 @@ fn main() { if a { 123 } else if b { + //~^ bool_to_int_with_if 0 } else { 1 @@ -120,6 +128,7 @@ fn main() { // Lint returns and type inference fn some_fn(a: bool) -> u8 { if a { 1 } else { 0 } + //~^ bool_to_int_with_if } fn side_effect() {} diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr index 1e4a843071a1c..415e80f8d73d1 100644 --- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr +++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr @@ -2,6 +2,7 @@ error: boolean to int conversion using if --> tests/ui/bool_to_int_with_if.rs:14:5 | LL | / if a { +LL | | LL | | 1 LL | | } else { LL | | 0 @@ -13,9 +14,10 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::bool_to_int_with_if)]` error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:19:5 + --> tests/ui/bool_to_int_with_if.rs:20:5 | LL | / if a { +LL | | LL | | 0 LL | | } else { LL | | 1 @@ -25,9 +27,10 @@ LL | | }; = note: `!a as i32` or `(!a).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:24:5 + --> tests/ui/bool_to_int_with_if.rs:26:5 | LL | / if !a { +LL | | LL | | 1 LL | | } else { LL | | 0 @@ -37,9 +40,10 @@ LL | | }; = note: `!a as i32` or `(!a).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:29:5 + --> tests/ui/bool_to_int_with_if.rs:32:5 | LL | / if a || b { +LL | | LL | | 1 LL | | } else { LL | | 0 @@ -49,9 +53,10 @@ LL | | }; = note: `(a || b) as i32` or `(a || b).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:34:5 + --> tests/ui/bool_to_int_with_if.rs:38:5 | LL | / if cond(a, b) { +LL | | LL | | 1 LL | | } else { LL | | 0 @@ -61,9 +66,10 @@ LL | | }; = note: `cond(a, b) as i32` or `cond(a, b).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:39:5 + --> tests/ui/bool_to_int_with_if.rs:44:5 | LL | / if x + y < 4 { +LL | | LL | | 1 LL | | } else { LL | | 0 @@ -73,10 +79,11 @@ LL | | }; = note: `(x + y < 4) as i32` or `(x + y < 4).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:48:12 + --> tests/ui/bool_to_int_with_if.rs:54:12 | LL | } else if b { | ____________^ +LL | | LL | | 1 LL | | } else { LL | | 0 @@ -86,10 +93,11 @@ LL | | }; = note: `b as i32` or `b.into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:57:12 + --> tests/ui/bool_to_int_with_if.rs:64:12 | LL | } else if b { | ____________^ +LL | | LL | | 0 LL | | } else { LL | | 1 @@ -99,7 +107,7 @@ LL | | }; = note: `!b as i32` or `(!b).into()` can also be valid options error: boolean to int conversion using if - --> tests/ui/bool_to_int_with_if.rs:122:5 + --> tests/ui/bool_to_int_with_if.rs:130:5 | LL | if a { 1 } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` diff --git a/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.fixed index 2950b158deb64..b7ee4c6165a78 100644 --- a/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.fixed @@ -7,5 +7,7 @@ fn f(_: T) {} fn main() { let mut val = 0; f(&raw const val); + //~^ borrow_as_ptr f(&raw mut val); + //~^ borrow_as_ptr } diff --git a/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.rs index 19eb8f2923374..d16ed5aa7b291 100644 --- a/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.rs +++ b/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.rs @@ -7,5 +7,7 @@ fn f(_: T) {} fn main() { let mut val = 0; f(&val as *const _); + //~^ borrow_as_ptr f(&mut val as *mut i32); + //~^ borrow_as_ptr } diff --git a/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.stderr index 82a27af303c21..e02f3d8bed97b 100644 --- a/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/borrow_and_ref_as_ptr.stderr @@ -8,7 +8,7 @@ LL | f(&val as *const _); = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer - --> tests/ui/borrow_and_ref_as_ptr.rs:10:7 + --> tests/ui/borrow_and_ref_as_ptr.rs:11:7 | LL | f(&mut val as *mut i32); | ^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut val` diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed index 5365f3dd443c6..3dca06fce4b8d 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed @@ -9,6 +9,7 @@ fn a() -> i32 { fn main() { let val = 1; let _p = std::ptr::addr_of!(val); + //~^ borrow_as_ptr let _p = &0 as *const i32; let _p = &a() as *const i32; let vec = vec![1]; @@ -16,12 +17,15 @@ fn main() { let mut val_mut = 1; let _p_mut = std::ptr::addr_of_mut!(val_mut); + //~^ borrow_as_ptr let mut x: [i32; 2] = [42, 43]; let _raw = std::ptr::addr_of_mut!(x[1]).wrapping_offset(-1); + //~^ borrow_as_ptr } fn issue_13882() { let mut x: [i32; 2] = [42, 43]; let _raw = (&raw mut x[1]).wrapping_offset(-1); + //~^ borrow_as_ptr } diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs index 261894f1341c4..3559dc23d0185 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs @@ -9,6 +9,7 @@ fn a() -> i32 { fn main() { let val = 1; let _p = &val as *const i32; + //~^ borrow_as_ptr let _p = &0 as *const i32; let _p = &a() as *const i32; let vec = vec![1]; @@ -16,12 +17,15 @@ fn main() { let mut val_mut = 1; let _p_mut = &mut val_mut as *mut i32; + //~^ borrow_as_ptr let mut x: [i32; 2] = [42, 43]; let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); + //~^ borrow_as_ptr } fn issue_13882() { let mut x: [i32; 2] = [42, 43]; let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); + //~^ borrow_as_ptr } diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr index 4595fa4f2487a..4a9f2ed4aa003 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr @@ -8,19 +8,19 @@ LL | let _p = &val as *const i32; = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:18:18 + --> tests/ui/borrow_as_ptr.rs:19:18 | LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:21:16 + --> tests/ui/borrow_as_ptr.rs:23:16 | LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:26:17 + --> tests/ui/borrow_as_ptr.rs:29:17 | LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]` diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed index 26c6a5033d162..8972fc0a5e0d3 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed @@ -6,8 +6,10 @@ pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let val = 1; let _p = core::ptr::addr_of!(val); + //~^ borrow_as_ptr let mut val_mut = 1; let _p_mut = core::ptr::addr_of_mut!(val_mut); + //~^ borrow_as_ptr 0 } diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs index d8d8b4c380ce5..6b4c732dc56e8 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs @@ -6,8 +6,10 @@ pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let val = 1; let _p = &val as *const i32; + //~^ borrow_as_ptr let mut val_mut = 1; let _p_mut = &mut val_mut as *mut i32; + //~^ borrow_as_ptr 0 } diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr index 488e0bd96776f..6012577559d0d 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr @@ -8,7 +8,7 @@ LL | let _p = &val as *const i32; = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr_no_std.rs:11:18 + --> tests/ui/borrow_as_ptr_no_std.rs:12:18 | LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)` diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.fixed index d6842e60a3e9f..7fbb942b5bc7b 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.fixed @@ -9,6 +9,7 @@ fn a() -> i32 { fn main() { let val = 1; let _p = &raw const val; + //~^ borrow_as_ptr let _p = &0 as *const i32; let _p = &a() as *const i32; let vec = vec![1]; @@ -16,4 +17,5 @@ fn main() { let mut val_mut = 1; let _p_mut = &raw mut val_mut; + //~^ borrow_as_ptr } diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.rs index 3c9daed18f15a..9cbf2e5c266d0 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.rs @@ -9,6 +9,7 @@ fn a() -> i32 { fn main() { let val = 1; let _p = &val as *const i32; + //~^ borrow_as_ptr let _p = &0 as *const i32; let _p = &a() as *const i32; let vec = vec![1]; @@ -16,4 +17,5 @@ fn main() { let mut val_mut = 1; let _p_mut = &mut val_mut as *mut i32; + //~^ borrow_as_ptr } diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.stderr index 5611fcae8d4b1..e5c8aec779860 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_raw_ref.stderr @@ -8,7 +8,7 @@ LL | let _p = &val as *const i32; = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr_raw_ref.rs:18:18 + --> tests/ui/borrow_as_ptr_raw_ref.rs:19:18 | LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut val_mut` diff --git a/src/tools/clippy/tests/ui/borrow_box.fixed b/src/tools/clippy/tests/ui/borrow_box.fixed index 08ea60583ea40..e6e7f74af7cf6 100644 --- a/src/tools/clippy/tests/ui/borrow_box.fixed +++ b/src/tools/clippy/tests/ui/borrow_box.fixed @@ -23,17 +23,17 @@ pub fn test1(foo: &mut Box) { pub fn test2() { let foo: &bool; - //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + //~^ borrowed_box } struct Test3<'a> { foo: &'a bool, - //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + //~^ borrowed_box } trait Test4 { fn test4(a: &bool); - //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + //~^ borrowed_box } use std::any::Any; @@ -94,24 +94,28 @@ pub fn test13(boxed_slice: &mut Box<[i32]>) { // The suggestion should include proper parentheses to avoid a syntax error. pub fn test14(_display: &dyn Display) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test15(_display: &(dyn Display + Send)) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test16<'a>(_display: &'a (dyn Display + 'a)) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box pub fn test17(_display: &impl Display) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test18(_display: &(impl Display + Send)) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test19<'a>(_display: &'a (impl Display + 'a)) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box // This exists only to check what happens when parentheses are already present. // Even though the current implementation doesn't put extra parentheses, // it's fine that unnecessary parentheses appear in the future for some reason. pub fn test20(_display: &(dyn Display + Send)) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box #[allow(clippy::borrowed_box)] trait Trait { diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs index b55de1701daa8..43cf809306b30 100644 --- a/src/tools/clippy/tests/ui/borrow_box.rs +++ b/src/tools/clippy/tests/ui/borrow_box.rs @@ -23,17 +23,17 @@ pub fn test1(foo: &mut Box) { pub fn test2() { let foo: &Box; - //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + //~^ borrowed_box } struct Test3<'a> { foo: &'a Box, - //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + //~^ borrowed_box } trait Test4 { fn test4(a: &Box); - //~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` + //~^ borrowed_box } use std::any::Any; @@ -94,24 +94,28 @@ pub fn test13(boxed_slice: &mut Box<[i32]>) { // The suggestion should include proper parentheses to avoid a syntax error. pub fn test14(_display: &Box) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test15(_display: &Box) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test16<'a>(_display: &'a Box) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box pub fn test17(_display: &Box) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test18(_display: &Box) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box + pub fn test19<'a>(_display: &'a Box) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box // This exists only to check what happens when parentheses are already present. // Even though the current implementation doesn't put extra parentheses, // it's fine that unnecessary parentheses appear in the future for some reason. pub fn test20(_display: &Box<(dyn Display + Send)>) {} -//~^ ERROR: you seem to be trying to use `&Box`. Consider using just `&T` +//~^ borrowed_box #[allow(clippy::borrowed_box)] trait Trait { diff --git a/src/tools/clippy/tests/ui/borrow_box.stderr b/src/tools/clippy/tests/ui/borrow_box.stderr index 6f80f86c3b3d4..dbe3757dd4357 100644 --- a/src/tools/clippy/tests/ui/borrow_box.stderr +++ b/src/tools/clippy/tests/ui/borrow_box.stderr @@ -29,37 +29,37 @@ LL | pub fn test14(_display: &Box) {} | ^^^^^^^^^^^^^^^^^ help: try: `&dyn Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:98:25 + --> tests/ui/borrow_box.rs:99:25 | LL | pub fn test15(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:100:29 + --> tests/ui/borrow_box.rs:102:29 | LL | pub fn test16<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (dyn Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:103:25 + --> tests/ui/borrow_box.rs:105:25 | LL | pub fn test17(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^ help: try: `&impl Display` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:105:25 + --> tests/ui/borrow_box.rs:108:25 | LL | pub fn test18(_display: &Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(impl Display + Send)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:107:29 + --> tests/ui/borrow_box.rs:111:29 | LL | pub fn test19<'a>(_display: &'a Box) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&'a (impl Display + 'a)` error: you seem to be trying to use `&Box`. Consider using just `&T` - --> tests/ui/borrow_box.rs:113:25 + --> tests/ui/borrow_box.rs:117:25 | LL | pub fn test20(_display: &Box<(dyn Display + Send)>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&(dyn Display + Send)` diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed index 22e984c46d248..17c224f10bfea 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed @@ -11,8 +11,10 @@ mod should_lint { fn one_help() { let a = &12; let b = a; + //~^ borrow_deref_ref let b = &mut bar(&12); + //~^ borrow_deref_ref } fn bar(x: &u32) -> &u32 { @@ -67,6 +69,8 @@ mod false_negative { let x = &12; let addr_x = &x as *const _ as usize; let addr_y = &x as *const _ as usize; // assert ok + // + //~^^ borrow_deref_ref // let addr_y = &x as *const _ as usize; // assert fail assert_ne!(addr_x, addr_y); } diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs index 61d89193f42f2..130ed2903dc61 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs @@ -11,8 +11,10 @@ mod should_lint { fn one_help() { let a = &12; let b = &*a; + //~^ borrow_deref_ref let b = &mut &*bar(&12); + //~^ borrow_deref_ref } fn bar(x: &u32) -> &u32 { @@ -67,6 +69,8 @@ mod false_negative { let x = &12; let addr_x = &x as *const _ as usize; let addr_y = &&*x as *const _ as usize; // assert ok + // + //~^^ borrow_deref_ref // let addr_y = &x as *const _ as usize; // assert fail assert_ne!(addr_x, addr_y); } diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr index 7fa43ef49cf72..f5868aa874900 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr @@ -8,13 +8,13 @@ LL | let b = &*a; = help: to override `-D warnings` add `#[allow(clippy::borrow_deref_ref)]` error: deref on an immutable reference - --> tests/ui/borrow_deref_ref.rs:15:22 + --> tests/ui/borrow_deref_ref.rs:16:22 | LL | let b = &mut &*bar(&12); | ^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `bar(&12)` error: deref on an immutable reference - --> tests/ui/borrow_deref_ref.rs:69:23 + --> tests/ui/borrow_deref_ref.rs:71:23 | LL | let addr_y = &&*x as *const _ as usize; // assert ok | ^^^ help: if you would like to reborrow, try removing `&*`: `x` diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.rs b/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.rs index be98873395978..f05a90d2c1fa8 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.rs +++ b/src/tools/clippy/tests/ui/borrow_deref_ref_unfixable.rs @@ -7,7 +7,6 @@ mod should_lint { fn two_helps() { let s = &String::new(); let x: &str = &*s; - //~^ ERROR: deref on an immutable reference - //~| NOTE: `-D clippy::borrow-deref-ref` implied by `-D warnings` + //~^ borrow_deref_ref } } diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs index a49d53fbbd380..fa729b62d7f51 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs @@ -62,14 +62,20 @@ mod issue12979 { const CELL_REF: StaticRef<(UnsafeCell,)> = unsafe { StaticRef::new(std::ptr::null()) }; fn main() { - ATOMIC.store(1, Ordering::SeqCst); //~ ERROR: interior mutability - assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR: interior mutability + ATOMIC.store(1, Ordering::SeqCst); + //~^ borrow_interior_mutable_const + assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); + //~^ borrow_interior_mutable_const let _once = ONCE_INIT; - let _once_ref = &ONCE_INIT; //~ ERROR: interior mutability - let _once_ref_2 = &&ONCE_INIT; //~ ERROR: interior mutability - let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR: interior mutability - let _once_mut = &mut ONCE_INIT; //~ ERROR: interior mutability + let _once_ref = &ONCE_INIT; + //~^ borrow_interior_mutable_const + let _once_ref_2 = &&ONCE_INIT; + //~^ borrow_interior_mutable_const + let _once_ref_4 = &&&&ONCE_INIT; + //~^ borrow_interior_mutable_const + let _once_mut = &mut ONCE_INIT; + //~^ borrow_interior_mutable_const let _atomic_into_inner = ATOMIC.into_inner(); // these should be all fine. let _twice = (ONCE_INIT, ONCE_INIT); @@ -80,22 +86,30 @@ fn main() { let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0]; // referencing projection is still bad. - let _ = &ATOMIC_TUPLE; //~ ERROR: interior mutability - let _ = &ATOMIC_TUPLE.0; //~ ERROR: interior mutability - let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR: interior mutability - let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR: interior mutability - let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR: interior mutability + let _ = &ATOMIC_TUPLE; + //~^ borrow_interior_mutable_const + let _ = &ATOMIC_TUPLE.0; + //~^ borrow_interior_mutable_const + let _ = &(&&&&ATOMIC_TUPLE).0; + //~^ borrow_interior_mutable_const + let _ = &ATOMIC_TUPLE.0[0]; + //~^ borrow_interior_mutable_const + let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); + //~^ borrow_interior_mutable_const let _ = &ATOMIC_TUPLE.2; let _ = (&&&&ATOMIC_TUPLE).0; let _ = (&&&&ATOMIC_TUPLE).2; let _ = ATOMIC_TUPLE.0; - let _ = ATOMIC_TUPLE.0[0]; //~ ERROR: interior mutability + let _ = ATOMIC_TUPLE.0[0]; + //~^ borrow_interior_mutable_const let _ = ATOMIC_TUPLE.1.into_iter(); let _ = ATOMIC_TUPLE.2; let _ = &{ ATOMIC_TUPLE }; - CELL.set(2); //~ ERROR: interior mutability - assert_eq!(CELL.get(), 6); //~ ERROR: interior mutability + CELL.set(2); + //~^ borrow_interior_mutable_const + assert_eq!(CELL.get(), 6); + //~^ borrow_interior_mutable_const assert_eq!(INTEGER, 8); assert!(STRING.is_empty()); diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr index 4cefcc28008d7..decea153f7173 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr @@ -12,7 +12,7 @@ LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:66:16 + --> tests/ui/borrow_interior_mutable_const/others.rs:67:16 | LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); | ^^^^^^ @@ -20,7 +20,7 @@ LL | assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:69:22 + --> tests/ui/borrow_interior_mutable_const/others.rs:71:22 | LL | let _once_ref = &ONCE_INIT; | ^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _once_ref = &ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:70:25 + --> tests/ui/borrow_interior_mutable_const/others.rs:73:25 | LL | let _once_ref_2 = &&ONCE_INIT; | ^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _once_ref_2 = &&ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:71:27 + --> tests/ui/borrow_interior_mutable_const/others.rs:75:27 | LL | let _once_ref_4 = &&&&ONCE_INIT; | ^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _once_ref_4 = &&&&ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:72:26 + --> tests/ui/borrow_interior_mutable_const/others.rs:77:26 | LL | let _once_mut = &mut ONCE_INIT; | ^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _once_mut = &mut ONCE_INIT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:83:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:89:14 | LL | let _ = &ATOMIC_TUPLE; | ^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _ = &ATOMIC_TUPLE; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:84:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:91:14 | LL | let _ = &ATOMIC_TUPLE.0; | ^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _ = &ATOMIC_TUPLE.0; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:85:19 + --> tests/ui/borrow_interior_mutable_const/others.rs:93:19 | LL | let _ = &(&&&&ATOMIC_TUPLE).0; | ^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | let _ = &(&&&&ATOMIC_TUPLE).0; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:86:14 + --> tests/ui/borrow_interior_mutable_const/others.rs:95:14 | LL | let _ = &ATOMIC_TUPLE.0[0]; | ^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | let _ = &ATOMIC_TUPLE.0[0]; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:87:13 + --> tests/ui/borrow_interior_mutable_const/others.rs:97:13 | LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); | ^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:92:13 + --> tests/ui/borrow_interior_mutable_const/others.rs:103:13 | LL | let _ = ATOMIC_TUPLE.0[0]; | ^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | let _ = ATOMIC_TUPLE.0[0]; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:97:5 + --> tests/ui/borrow_interior_mutable_const/others.rs:109:5 | LL | CELL.set(2); | ^^^^ @@ -108,7 +108,7 @@ LL | CELL.set(2); = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/others.rs:98:16 + --> tests/ui/borrow_interior_mutable_const/others.rs:111:16 | LL | assert_eq!(CELL.get(), 6); | ^^^^ diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs new file mode 100644 index 0000000000000..bbe5538fbe123 --- /dev/null +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.rs @@ -0,0 +1,42 @@ +#![deny(clippy::borrow_interior_mutable_const)] +#![deny(clippy::declare_interior_mutable_const)] + +// Inspired by https://github.com/rust-lang/rust/pull/130543#issuecomment-2364828139 + +use std::cell::UnsafeCell; + +trait Trait { + type Assoc; +} + +type Assoc = ::Assoc; + +impl Trait for u8 { + type Assoc = UnsafeCell; +} + +impl Trait for () { + type Assoc = (); +} + +enum MaybeMutable { + Mutable(Assoc), + Immutable(Assoc<()>), +} + +const CELL: Assoc = UnsafeCell::new(0); //~ ERROR: interior mutable +const UNIT: Assoc<()> = (); +const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); //~ ERROR: interior mutable +const IMMUTABLE: MaybeMutable = MaybeMutable::Immutable(UNIT); + +fn print_ref(t: &T) { + let p: *const T = t; + println!("{p:p}") +} + +fn main() { + print_ref(&CELL); //~ ERROR: interior mutability + print_ref(&UNIT); + print_ref(&MUTABLE); //~ ERROR: interior mutability + print_ref(&IMMUTABLE); +} diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr new file mode 100644 index 0000000000000..eabaf66560ada --- /dev/null +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/projections.stderr @@ -0,0 +1,44 @@ +error: a `const` item should not be interior mutable + --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1 + | +LL | const CELL: Assoc = UnsafeCell::new(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` +note: the lint level is defined here + --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9 + | +LL | #![deny(clippy::declare_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item should not be interior mutable + --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1 + | +LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + +error: a `const` item with interior mutability should not be borrowed + --> tests/ui/borrow_interior_mutable_const/projections.rs:38:16 + | +LL | print_ref(&CELL); + | ^^^^ + | + = help: assign this const to a local or static variable, and use the variable here +note: the lint level is defined here + --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9 + | +LL | #![deny(clippy::borrow_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: a `const` item with interior mutability should not be borrowed + --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16 + | +LL | print_ref(&MUTABLE); + | ^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs index 5570e7cd6d2ee..c4878dbe57b29 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.rs @@ -12,7 +12,8 @@ trait ConcreteTypes { const STRING: String; fn function() { - let _ = &Self::ATOMIC; //~ ERROR: interior mutability + let _ = &Self::ATOMIC; + //~^ borrow_interior_mutable_const let _ = &Self::STRING; } } @@ -23,7 +24,8 @@ impl ConcreteTypes for u64 { fn function() { // Lint this again since implementers can choose not to borrow it. - let _ = &Self::ATOMIC; //~ ERROR: interior mutability + let _ = &Self::ATOMIC; + //~^ borrow_interior_mutable_const let _ = &Self::STRING; } } @@ -48,7 +50,8 @@ impl GenericTypes for Vec { fn function() { let _ = &Self::TO_REMAIN_GENERIC; - let _ = &Self::TO_BE_CONCRETE; //~ ERROR: interior mutability + let _ = &Self::TO_BE_CONCRETE; + //~^ borrow_interior_mutable_const } } @@ -83,8 +86,10 @@ impl AssocTypes for Vec { fn function() { let _ = &Self::TO_BE_FROZEN; - let _ = &Self::TO_BE_UNFROZEN; //~ ERROR: interior mutability - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ ERROR: interior mutability + let _ = &Self::TO_BE_UNFROZEN; + //~^ borrow_interior_mutable_const + let _ = &Self::WRAPPED_TO_BE_UNFROZEN; + //~^ borrow_interior_mutable_const let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM; } } @@ -106,7 +111,8 @@ where fn function() { let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ ERROR: interior mutability + let _ = &Self::BOUNDED; + //~^ borrow_interior_mutable_const } } @@ -119,7 +125,8 @@ where fn function() { let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ ERROR: interior mutability + let _ = &Self::BOUNDED; + //~^ borrow_interior_mutable_const } } @@ -148,8 +155,10 @@ impl SelfType for AtomicUsize { const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); fn function() { - let _ = &Self::SELF; //~ ERROR: interior mutability - let _ = &Self::WRAPPED_SELF; //~ ERROR: interior mutability + let _ = &Self::SELF; + //~^ borrow_interior_mutable_const + let _ = &Self::WRAPPED_SELF; + //~^ borrow_interior_mutable_const } } @@ -158,8 +167,10 @@ trait BothOfCellAndGeneric { const INDIRECT: Cell<*const T>; fn function() { - let _ = &Self::DIRECT; //~ ERROR: interior mutability - let _ = &Self::INDIRECT; //~ ERROR: interior mutability + let _ = &Self::DIRECT; + //~^ borrow_interior_mutable_const + let _ = &Self::INDIRECT; + //~^ borrow_interior_mutable_const } } @@ -168,8 +179,10 @@ impl BothOfCellAndGeneric for Vec { const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); fn function() { - let _ = &Self::DIRECT; //~ ERROR: interior mutability - let _ = &Self::INDIRECT; //~ ERROR: interior mutability + let _ = &Self::DIRECT; + //~^ borrow_interior_mutable_const + let _ = &Self::INDIRECT; + //~^ borrow_interior_mutable_const } } @@ -188,15 +201,19 @@ where const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); fn function() { - let _ = &Self::ATOMIC; //~ ERROR: interior mutability + let _ = &Self::ATOMIC; + //~^ borrow_interior_mutable_const let _ = &Self::COW; let _ = &Self::GENERIC_TYPE; let _ = &Self::ASSOC_TYPE; - let _ = &Self::BOUNDED_ASSOC_TYPE; //~ ERROR: interior mutability + let _ = &Self::BOUNDED_ASSOC_TYPE; + //~^ borrow_interior_mutable_const } } fn main() { - u64::ATOMIC.store(5, Ordering::SeqCst); //~ ERROR: interior mutability - assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ ERROR: interior mutability + u64::ATOMIC.store(5, Ordering::SeqCst); + //~^ borrow_interior_mutable_const + assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); + //~^ borrow_interior_mutable_const } diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr index 8602b46b0dcfe..cad68ca9260cb 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -12,7 +12,7 @@ LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:26:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:27:18 | LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | let _ = &Self::ATOMIC; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:51:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:53:18 | LL | let _ = &Self::TO_BE_CONCRETE; | ^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _ = &Self::TO_BE_CONCRETE; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:86:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:89:18 | LL | let _ = &Self::TO_BE_UNFROZEN; | ^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _ = &Self::TO_BE_UNFROZEN; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:87:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:91:18 | LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:109:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:114:18 | LL | let _ = &Self::BOUNDED; | ^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = &Self::BOUNDED; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:122:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:128:18 | LL | let _ = &Self::BOUNDED; | ^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _ = &Self::BOUNDED; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:151:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:158:18 | LL | let _ = &Self::SELF; | ^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _ = &Self::SELF; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:152:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:160:18 | LL | let _ = &Self::WRAPPED_SELF; | ^^^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | let _ = &Self::WRAPPED_SELF; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:161:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:170:18 | LL | let _ = &Self::DIRECT; | ^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | let _ = &Self::DIRECT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:162:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18 | LL | let _ = &Self::INDIRECT; | ^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | let _ = &Self::INDIRECT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:171:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:182:18 | LL | let _ = &Self::DIRECT; | ^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | let _ = &Self::DIRECT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:184:18 | LL | let _ = &Self::INDIRECT; | ^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | let _ = &Self::INDIRECT; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:191:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:204:18 | LL | let _ = &Self::ATOMIC; | ^^^^^^^^^^^^ @@ -116,7 +116,7 @@ LL | let _ = &Self::ATOMIC; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:195:18 + --> tests/ui/borrow_interior_mutable_const/traits.rs:209:18 | LL | let _ = &Self::BOUNDED_ASSOC_TYPE; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +124,7 @@ LL | let _ = &Self::BOUNDED_ASSOC_TYPE; = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:200:5 + --> tests/ui/borrow_interior_mutable_const/traits.rs:215:5 | LL | u64::ATOMIC.store(5, Ordering::SeqCst); | ^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | u64::ATOMIC.store(5, Ordering::SeqCst); = help: assign this const to a local or static variable, and use the variable here error: a `const` item with interior mutability should not be borrowed - --> tests/ui/borrow_interior_mutable_const/traits.rs:201:16 + --> tests/ui/borrow_interior_mutable_const/traits.rs:217:16 | LL | assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/box_collection.rs b/src/tools/clippy/tests/ui/box_collection.rs index 499625ea9c31a..0f7d3c74ddd07 100644 --- a/src/tools/clippy/tests/ui/box_collection.rs +++ b/src/tools/clippy/tests/ui/box_collection.rs @@ -19,7 +19,7 @@ fn test_macro() { } fn test1(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `Vec<..>` +//~^ box_collection fn test2(foo: Box)>) { // pass if #31 is fixed @@ -27,28 +27,28 @@ fn test2(foo: Box)>) { } fn test3(foo: Box) {} -//~^ ERROR: you seem to be trying to use `Box`. Consider using just `String` +//~^ box_collection fn test4(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `HashMap< +//~^ box_collection fn test5(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `HashSet< +//~^ box_collection fn test6(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `VecDequ +//~^ box_collection fn test7(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `Linke +//~^ box_collection fn test8(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `BTreeMa +//~^ box_collection fn test9(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `BTreeSe +//~^ box_collection fn test10(foo: Box>) {} -//~^ ERROR: you seem to be trying to use `Box>`. Consider using just `Binar +//~^ box_collection fn test_local_not_linted() { let _: Box>; diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index 1f2f57c2507db..80000f5de4fd3 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -32,14 +32,22 @@ macro_rules! box_new { fn main() { let string1: Box = Box::default(); + //~^ box_default let string2: Box = Box::default(); + //~^ box_default let impl1: Box = Box::default(); + //~^ box_default let vec: Box> = Box::default(); + //~^ box_default let byte: Box = Box::default(); + //~^ box_default let vec2: Box> = Box::default(); + //~^ box_default let vec3: Box> = Box::default(); + //~^ box_default let plain_default = Box::default(); + //~^ box_default let _: Box = plain_default; let _: Box = Box::new(default!()); @@ -57,6 +65,7 @@ fn main() { let vec4: Box<_> = Box::new(Vec::from([false; 0])); let more = ret_ty_fn(); call_ty_fn(Box::default()); + //~^ box_default issue_10381(); // `Box::>::default()` would be valid here, but not `Box::default()` or @@ -84,6 +93,7 @@ impl X { fn same_generic_param() { Self::x(Box::default()); + //~^ box_default } } diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index addfebc24f58c..4681016d7cd38 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -32,14 +32,22 @@ macro_rules! box_new { fn main() { let string1: Box = Box::new(Default::default()); + //~^ box_default let string2: Box = Box::new(String::new()); + //~^ box_default let impl1: Box = Box::new(Default::default()); + //~^ box_default let vec: Box> = Box::new(Vec::new()); + //~^ box_default let byte: Box = Box::new(u8::default()); + //~^ box_default let vec2: Box> = Box::new(vec![]); + //~^ box_default let vec3: Box> = Box::new(Vec::from([])); + //~^ box_default let plain_default = Box::new(Default::default()); + //~^ box_default let _: Box = plain_default; let _: Box = Box::new(default!()); @@ -57,6 +65,7 @@ fn main() { let vec4: Box<_> = Box::new(Vec::from([false; 0])); let more = ret_ty_fn(); call_ty_fn(Box::new(u8::default())); + //~^ box_default issue_10381(); // `Box::>::default()` would be valid here, but not `Box::default()` or @@ -84,6 +93,7 @@ impl X { fn same_generic_param() { Self::x(Box::new(T::default())); + //~^ box_default } } diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index 39fd0d29bbf9a..f63d97665b342 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -8,55 +8,55 @@ LL | let string1: Box = Box::new(Default::default()); = help: to override `-D warnings` add `#[allow(clippy::box_default)]` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:35:32 + --> tests/ui/box_default.rs:36:32 | LL | let string2: Box = Box::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:36:41 + --> tests/ui/box_default.rs:38:41 | LL | let impl1: Box = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:37:29 + --> tests/ui/box_default.rs:40:29 | LL | let vec: Box> = Box::new(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:38:25 + --> tests/ui/box_default.rs:42:25 | LL | let byte: Box = Box::new(u8::default()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:39:45 + --> tests/ui/box_default.rs:44:45 | LL | let vec2: Box> = Box::new(vec![]); | ^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:40:32 + --> tests/ui/box_default.rs:46:32 | LL | let vec3: Box> = Box::new(Vec::from([])); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:42:25 + --> tests/ui/box_default.rs:49:25 | LL | let plain_default = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:59:16 + --> tests/ui/box_default.rs:67:16 | LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> tests/ui/box_default.rs:86:17 + --> tests/ui/box_default.rs:95:17 | LL | Self::x(Box::new(T::default())); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` diff --git a/src/tools/clippy/tests/ui/box_default_no_std.rs b/src/tools/clippy/tests/ui/box_default_no_std.rs index edb701fcd084d..2881caf0c185a 100644 --- a/src/tools/clippy/tests/ui/box_default_no_std.rs +++ b/src/tools/clippy/tests/ui/box_default_no_std.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::box_default)] #![no_std] #![crate_type = "lib"] diff --git a/src/tools/clippy/tests/ui/boxed_local.rs b/src/tools/clippy/tests/ui/boxed_local.rs index 4f361f5162be4..3fb685aa36c11 100644 --- a/src/tools/clippy/tests/ui/boxed_local.rs +++ b/src/tools/clippy/tests/ui/boxed_local.rs @@ -38,8 +38,8 @@ fn warn_call() { } fn warn_arg(x: Box) { - //~^ ERROR: local variable doesn't need to be boxed here - //~| NOTE: `-D clippy::boxed-local` implied by `-D warnings` + //~^ boxed_local + x.foo(); } @@ -121,7 +121,7 @@ pub struct PeekableSeekable { } pub fn new(_needs_name: Box>) -> () {} -//~^ ERROR: local variable doesn't need to be boxed here +//~^ boxed_local /// Regression for #916, #1123 /// @@ -187,7 +187,8 @@ mod issue4804 { // warn on `x: Box` fn default_impl_x(self: Box, x: Box) -> u32 { - //~^ ERROR: local variable doesn't need to be boxed here + //~^ boxed_local + 4 } } @@ -195,7 +196,7 @@ mod issue4804 { trait WarnTrait { // warn on `x: Box` fn foo(x: Box) {} - //~^ ERROR: local variable doesn't need to be boxed here + //~^ boxed_local } } diff --git a/src/tools/clippy/tests/ui/boxed_local.stderr b/src/tools/clippy/tests/ui/boxed_local.stderr index 08fe375afb235..81ebc4fde4985 100644 --- a/src/tools/clippy/tests/ui/boxed_local.stderr +++ b/src/tools/clippy/tests/ui/boxed_local.stderr @@ -20,7 +20,7 @@ LL | fn default_impl_x(self: Box, x: Box) -> u32 { | ^ error: local variable doesn't need to be boxed here - --> tests/ui/boxed_local.rs:197:16 + --> tests/ui/boxed_local.rs:198:16 | LL | fn foo(x: Box) {} | ^ diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/false_positives.rs b/src/tools/clippy/tests/ui/branches_sharing_code/false_positives.rs index 5e3a1a29693f5..49496e631fb19 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/false_positives.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/false_positives.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code)] #![deny(clippy::if_same_then_else, clippy::branches_sharing_code)] diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs index 549908b8770e3..06472a4f5d572 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs @@ -33,8 +33,8 @@ fn simple_examples() { // The rest is self contained and moveable => Only lint the rest let result = false; - //~^ ERROR: all if blocks contain the same code at the end - //~| NOTE: the end suggestion probably needs some adjustments to use the expressio + //~^ branches_sharing_code + println!("Block end!"); result }; @@ -53,7 +53,7 @@ fn simple_examples() { } else { println!("This is also eq with the else block"); println!("Same end of block"); - //~^ ERROR: all if blocks contain the same code at the end + //~^ branches_sharing_code } // Use of outer scope value @@ -71,7 +71,7 @@ fn simple_examples() { println!("I'm a local because I use the value `z`: `{}`", z); println!( - //~^ ERROR: all if blocks contain the same code at the end + //~^ branches_sharing_code "I'm moveable because I know: `outer_scope_value`: '{}'", outer_scope_value ); @@ -84,7 +84,7 @@ fn simple_examples() { println!("Hello World"); } else { println!("Hello World"); - //~^ ERROR: all if blocks contain the same code at the end + //~^ branches_sharing_code } } } @@ -101,7 +101,8 @@ fn simple_but_suggestion_is_invalid() { println!("{}", later_used_value); } else { let later_used_value = "A string value"; - //~^ ERROR: all if blocks contain the same code at the end + //~^ branches_sharing_code + println!("{}", later_used_value); // I'm expecting a note about this } @@ -115,7 +116,8 @@ fn simple_but_suggestion_is_invalid() { println!("Separator print statement"); let simple_examples = "I now identify as a &str :)"; - //~^ ERROR: all if blocks contain the same code at the end + //~^ branches_sharing_code + println!("This is the new simple_example: {}", simple_examples); } simple_examples(); @@ -181,8 +183,7 @@ fn added_note_for_expression_use() -> u32 { } else { let _ = 6; x << 2 - //~^ ERROR: all if blocks contain the same code at the end - //~| NOTE: the end suggestion probably needs some adjustments to use the expressio + //~^ branches_sharing_code }; if x == 9 { @@ -190,8 +191,7 @@ fn added_note_for_expression_use() -> u32 { } else { let _ = 17; x * 4 - //~^ ERROR: all if blocks contain the same code at the end - //~| NOTE: the end suggestion probably needs some adjustments to use the expressio + //~^ branches_sharing_code } } @@ -204,7 +204,8 @@ fn test_suggestion_with_weird_formatting() { // The error message still looks weird tbh but this is the best I can do // for weird formatting if x == 17 { b = 1; a = 0x99; } else { a = 0x99; } - //~^ ERROR: all if blocks contain the same code at the end + //~^ branches_sharing_code + } fn fp_test() { diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr index 36b1777397320..648a99c65ed22 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr @@ -20,7 +20,7 @@ help: consider moving these statements after the if LL ~ } LL + let result = false; LL + -LL + +LL + LL + println!("Block end!"); LL ~ result; | @@ -79,6 +79,7 @@ error: all if blocks contain the same code at the end | LL | / let later_used_value = "A string value"; LL | | +LL | | LL | | println!("{}", later_used_value); LL | | // I'm expecting a note about this LL | | } @@ -90,14 +91,16 @@ help: consider moving these statements after the if LL ~ } LL + let later_used_value = "A string value"; LL + +LL + LL + println!("{}", later_used_value); | error: all if blocks contain the same code at the end - --> tests/ui/branches_sharing_code/shared_at_bottom.rs:117:5 + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:118:5 | LL | / let simple_examples = "I now identify as a &str :)"; LL | | +LL | | LL | | println!("This is the new simple_example: {}", simple_examples); LL | | } | |_____^ @@ -108,14 +111,15 @@ help: consider moving these statements after the if LL ~ } LL + let simple_examples = "I now identify as a &str :)"; LL + +LL + LL + println!("This is the new simple_example: {}", simple_examples); | error: all if blocks contain the same code at the end - --> tests/ui/branches_sharing_code/shared_at_bottom.rs:183:5 + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:185:5 | LL | / x << 2 -... | +LL | | LL | | }; | |_____^ | @@ -127,10 +131,10 @@ LL ~ x << 2; | error: all if blocks contain the same code at the end - --> tests/ui/branches_sharing_code/shared_at_bottom.rs:192:5 + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:193:5 | LL | / x * 4 -... | +LL | | LL | | } | |_____^ | diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs index 9af81f6f7cdda..694c67d4c85b3 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs @@ -9,16 +9,17 @@ fn simple_examples() { // Simple if true { + //~^ branches_sharing_code println!("Hello World!"); println!("I'm branch nr: 1"); } else { println!("Hello World!"); println!("I'm branch nr: 2"); } - //~^^^^^^^ ERROR: all if blocks contain the same code at the start // Else if if x == 0 { + //~^ branches_sharing_code let y = 9; println!("The value y was set to: `{}`", y); let _z = y; @@ -37,11 +38,11 @@ fn simple_examples() { println!("Ha, Pascal allows you to start the array where you want") } - //~^^^^^^^^^^^^^^^^^^^ ERROR: all if blocks contain the same code at the start // Return a value let _ = if x == 7 { - //~^ ERROR: all if blocks contain the same code at the start + //~^ branches_sharing_code + let y = 16; println!("What can I say except: \"you're welcome?\""); let _ = y; @@ -60,6 +61,7 @@ fn simple_but_suggestion_is_invalid() { // Can't be automatically moved because used_value_name is getting used again let used_value_name = 19; if x == 10 { + //~^ branches_sharing_code let used_value_name = "Different type"; println!("Str: {}", used_value_name); let _ = 1; @@ -68,14 +70,15 @@ fn simple_but_suggestion_is_invalid() { println!("Str: {}", used_value_name); let _ = 2; } - //~^^^^^^^^^ ERROR: all if blocks contain the same code at the start + let _ = used_value_name; // This can be automatically moved as `can_be_overridden` is not used again let can_be_overridden = 8; let _ = can_be_overridden; if x == 11 { - //~^ ERROR: all if blocks contain the same code at the start + //~^ branches_sharing_code + let can_be_overridden = "Move me"; println!("I'm also moveable"); let _ = 111; @@ -92,7 +95,8 @@ fn check_if_same_than_else_mask() { #[allow(clippy::if_same_then_else)] if x == 2020 { - //~^ ERROR: all if blocks contain the same code at the start + //~^ branches_sharing_code + println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint."); println!("Because `IF_SAME_THEN_ELSE` is allowed here"); } else { @@ -105,7 +109,7 @@ fn check_if_same_than_else_mask() { } else { println!("This should trigger `IS_SAME_THAN_ELSE` as usual"); } - //~^^^^^ ERROR: this `if` has identical blocks + //~^^^^^ if_same_then_else } #[allow(clippy::vec_init_then_push)] diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr index 0d4e19be1f523..d28e9c7af2967 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr @@ -2,6 +2,7 @@ error: all if blocks contain the same code at the start --> tests/ui/branches_sharing_code/shared_at_top.rs:11:5 | LL | / if true { +LL | | LL | | println!("Hello World!"); | |_________________________________^ | @@ -20,6 +21,7 @@ error: all if blocks contain the same code at the start --> tests/ui/branches_sharing_code/shared_at_top.rs:21:5 | LL | / if x == 0 { +LL | | LL | | let y = 9; LL | | println!("The value y was set to: `{}`", y); LL | | let _z = y; @@ -38,7 +40,7 @@ error: all if blocks contain the same code at the start --> tests/ui/branches_sharing_code/shared_at_top.rs:43:5 | LL | / let _ = if x == 7 { -LL | | +... | LL | | let y = 16; | |___________________^ | @@ -49,9 +51,10 @@ LL + let _ = if x == 7 { | error: all if blocks contain the same code at the start - --> tests/ui/branches_sharing_code/shared_at_top.rs:62:5 + --> tests/ui/branches_sharing_code/shared_at_top.rs:63:5 | LL | / if x == 10 { +LL | | LL | | let used_value_name = "Different type"; LL | | println!("Str: {}", used_value_name); | |_____________________________________________^ @@ -65,10 +68,11 @@ LL + if x == 10 { | error: all if blocks contain the same code at the start - --> tests/ui/branches_sharing_code/shared_at_top.rs:77:5 + --> tests/ui/branches_sharing_code/shared_at_top.rs:79:5 | LL | / if x == 11 { LL | | +LL | | LL | | let can_be_overridden = "Move me"; LL | | println!("I'm also moveable"); | |______________________________________^ @@ -82,10 +86,11 @@ LL + if x == 11 { | error: all if blocks contain the same code at the start - --> tests/ui/branches_sharing_code/shared_at_top.rs:94:5 + --> tests/ui/branches_sharing_code/shared_at_top.rs:97:5 | LL | / if x == 2020 { LL | | +LL | | LL | | println!("This should trigger the `SHARED_CODE_IN_IF_BLOCKS` lint."); LL | | println!("Because `IF_SAME_THEN_ELSE` is allowed here"); | |________________________________________________________________^ @@ -98,7 +103,7 @@ LL + if x == 2020 { | error: this `if` has identical blocks - --> tests/ui/branches_sharing_code/shared_at_top.rs:103:18 + --> tests/ui/branches_sharing_code/shared_at_top.rs:107:18 | LL | if x == 2019 { | __________________^ @@ -107,7 +112,7 @@ LL | | } else { | |_____^ | note: same as this - --> tests/ui/branches_sharing_code/shared_at_top.rs:105:12 + --> tests/ui/branches_sharing_code/shared_at_top.rs:109:12 | LL | } else { | ____________^ diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs index 36620ee1a9bf0..75334f70f1f62 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs @@ -15,7 +15,8 @@ fn overlapping_eq_regions() { // Overlap with separator if x == 7 { - //~^ ERROR: all if blocks contain the same code at both the start and the end + //~^ branches_sharing_code + let t = 7; let _overlap_start = t * 2; let _overlap_end = 2 * t; @@ -32,7 +33,8 @@ fn overlapping_eq_regions() { // Overlap with separator if x == 99 { - //~^ ERROR: all if blocks contain the same code at both the start and the end + //~^ branches_sharing_code + let r = 7; let _overlap_start = r; let _overlap_middle = r * r; @@ -62,7 +64,8 @@ fn complexer_example() { let x = 8; let y = 9; if (x > 7 && y < 13) || (x + y) % 2 == 1 { - //~^ ERROR: all if blocks contain the same code at both the start and the end + //~^ branches_sharing_code + let a = 0xcafe; let b = 0xffff00ff; let e_id = gen_id(a, b); @@ -96,7 +99,8 @@ fn added_note_for_expression_use() -> u32 { let x = 9; let _ = if x == 7 { - //~^ ERROR: all if blocks contain the same code at both the start and the end + //~^ branches_sharing_code + let _ = 19; let _splitter = 6; @@ -109,7 +113,8 @@ fn added_note_for_expression_use() -> u32 { }; if x == 9 { - //~^ ERROR: all if blocks contain the same code at both the start and the end + //~^ branches_sharing_code + let _ = 17; let _splitter = 6; diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr index b79307f96778a..2200ab450890c 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr @@ -3,13 +3,14 @@ error: all if blocks contain the same code at both the start and the end | LL | / if x == 7 { LL | | +LL | | LL | | let t = 7; LL | | let _overlap_start = t * 2; LL | | let _overlap_end = 2 * t; | |_________________________________^ | note: this code is shared at the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:30:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:31:5 | LL | / let _u = 9; LL | | } @@ -33,17 +34,18 @@ LL + let _u = 9; | error: all if blocks contain the same code at both the start and the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:34:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:35:5 | LL | / if x == 99 { LL | | +LL | | LL | | let r = 7; LL | | let _overlap_start = r; LL | | let _overlap_middle = r * r; | |____________________________________^ | note: this code is shared at the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:46:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:48:5 | LL | / let _overlap_end = r * r * r; LL | | let z = "end"; @@ -65,17 +67,18 @@ LL + let z = "end"; | error: all if blocks contain the same code at both the start and the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:64:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:66:5 | LL | / if (x > 7 && y < 13) || (x + y) % 2 == 1 { LL | | +LL | | LL | | let a = 0xcafe; LL | | let b = 0xffff00ff; LL | | let e_id = gen_id(a, b); | |________________________________^ | note: this code is shared at the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:85:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:88:5 | LL | / let pack = DataPack { LL | | id: e_id, @@ -105,15 +108,15 @@ LL + process_data(pack); | error: all if blocks contain the same code at both the start and the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:98:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:101:5 | LL | / let _ = if x == 7 { -LL | | +... | LL | | let _ = 19; | |___________________^ | note: this code is shared at the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:108:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:112:5 | LL | / x << 2 LL | | }; @@ -131,15 +134,15 @@ LL ~ x << 2; | error: all if blocks contain the same code at both the start and the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:111:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:115:5 | LL | / if x == 9 { -LL | | +... | LL | | let _ = 17; | |___________________^ | note: this code is shared at the end - --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:121:5 + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:126:5 | LL | / x * 4 LL | | } diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs index b63819d7c3932..d72c5eef87adc 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/valid_if_blocks.rs @@ -109,7 +109,7 @@ fn valid_examples() { if false { } else { } - //~^^^ ERROR: this `if` has identical blocks + //~^^^ if_same_then_else } /// This makes sure that the `if_same_then_else` masks the `shared_code_in_if_blocks` lint @@ -127,11 +127,11 @@ fn trigger_other_lint() { println!("How are u today?"); let _ = "This is a string"; } - //~^^^^^^^^^ ERROR: this `if` has identical blocks + //~^^^^^^^^^ if_same_then_else // Only same expression let _ = if x == 6 { 7 } else { 7 }; - //~^ ERROR: this `if` has identical blocks + //~^ if_same_then_else // Same in else if block let _ = if x == 67 { @@ -146,7 +146,7 @@ fn trigger_other_lint() { if y == 90 { "=^.^=" } else { ":D" } }; - //~^^^^^^^^^ ERROR: this `if` has identical blocks + //~^^^^^^^^^ if_same_then_else if x == 0 { println!("I'm single"); @@ -155,7 +155,7 @@ fn trigger_other_lint() { } else { println!("I'm a doppelgänger"); } - //~^^^^^ ERROR: this `if` has identical blocks + //~^^^^^ if_same_then_else } fn main() {} diff --git a/src/tools/clippy/tests/ui/builtin_type_shadow.rs b/src/tools/clippy/tests/ui/builtin_type_shadow.rs index c5addd53434c9..eda22b7c38efe 100644 --- a/src/tools/clippy/tests/ui/builtin_type_shadow.rs +++ b/src/tools/clippy/tests/ui/builtin_type_shadow.rs @@ -2,8 +2,8 @@ #![allow(non_camel_case_types)] fn foo(a: u32) -> u32 { - 42 - //~^ ERROR: mismatched types + //~^ builtin_type_shadow + 42 //~ ERROR: mismatched type } fn main() {} diff --git a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr index 033204af9255f..a62b41d5c2712 100644 --- a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr +++ b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr @@ -8,12 +8,13 @@ LL | fn foo(a: u32) -> u32 { = help: to override `-D warnings` add `#[allow(clippy::builtin_type_shadow)]` error[E0308]: mismatched types - --> tests/ui/builtin_type_shadow.rs:5:5 + --> tests/ui/builtin_type_shadow.rs:6:5 | LL | fn foo(a: u32) -> u32 { | --- --- expected `u32` because of return type | | | expected this type parameter +LL | LL | 42 | ^^ expected type parameter `u32`, found integer | diff --git a/src/tools/clippy/tests/ui/byte_char_slices.fixed b/src/tools/clippy/tests/ui/byte_char_slices.fixed index d1db58f9363e9..b0c1b1f034b4d 100644 --- a/src/tools/clippy/tests/ui/byte_char_slices.fixed +++ b/src/tools/clippy/tests/ui/byte_char_slices.fixed @@ -3,11 +3,16 @@ fn main() { let bad = b"abc"; + //~^ byte_char_slices let quotes = b"\"Hi"; + //~^ byte_char_slices let quotes = b"'Sup"; + //~^ byte_char_slices let escapes = b"\x42Esc"; + //~^ byte_char_slices let good = &[b'a', 0x42]; let good = [b'a', b'a']; + //~^ useless_vec let good: u8 = [b'a', b'c'].into_iter().sum(); } diff --git a/src/tools/clippy/tests/ui/byte_char_slices.rs b/src/tools/clippy/tests/ui/byte_char_slices.rs index 18648fffceb40..0d6953dda97e7 100644 --- a/src/tools/clippy/tests/ui/byte_char_slices.rs +++ b/src/tools/clippy/tests/ui/byte_char_slices.rs @@ -3,11 +3,16 @@ fn main() { let bad = &[b'a', b'b', b'c']; + //~^ byte_char_slices let quotes = &[b'"', b'H', b'i']; + //~^ byte_char_slices let quotes = &[b'\'', b'S', b'u', b'p']; + //~^ byte_char_slices let escapes = &[b'\x42', b'E', b's', b'c']; + //~^ byte_char_slices let good = &[b'a', 0x42]; let good = vec![b'a', b'a']; + //~^ useless_vec let good: u8 = [b'a', b'c'].into_iter().sum(); } diff --git a/src/tools/clippy/tests/ui/byte_char_slices.stderr b/src/tools/clippy/tests/ui/byte_char_slices.stderr index 4e2b5d8a7329a..2556aa9c0f76b 100644 --- a/src/tools/clippy/tests/ui/byte_char_slices.stderr +++ b/src/tools/clippy/tests/ui/byte_char_slices.stderr @@ -8,25 +8,25 @@ LL | let bad = &[b'a', b'b', b'c']; = help: to override `-D warnings` add `#[allow(clippy::byte_char_slices)]` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:6:18 + --> tests/ui/byte_char_slices.rs:7:18 | LL | let quotes = &[b'"', b'H', b'i']; | ^^^^^^^^^^^^^^^^^^^ help: try: `b"\"Hi"` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:7:18 + --> tests/ui/byte_char_slices.rs:9:18 | LL | let quotes = &[b'\'', b'S', b'u', b'p']; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"'Sup"` error: can be more succinctly written as a byte str - --> tests/ui/byte_char_slices.rs:8:19 + --> tests/ui/byte_char_slices.rs:11:19 | LL | let escapes = &[b'\x42', b'E', b's', b'c']; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b"\x42Esc"` error: useless use of `vec!` - --> tests/ui/byte_char_slices.rs:11:16 + --> tests/ui/byte_char_slices.rs:15:16 | LL | let good = vec![b'a', b'a']; | ^^^^^^^^^^^^^^^^ help: you can use an array directly: `[b'a', b'a']` diff --git a/src/tools/clippy/tests/ui/bytecount.rs b/src/tools/clippy/tests/ui/bytecount.rs index f3b02fda8a81e..f03f99177d54e 100644 --- a/src/tools/clippy/tests/ui/bytecount.rs +++ b/src/tools/clippy/tests/ui/bytecount.rs @@ -8,11 +8,11 @@ fn main() { // naive byte count let _ = x.iter().filter(|&&a| a == 0).count(); - //~^ ERROR: you appear to be counting bytes the naive way + //~^ naive_bytecount // naive byte count let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); - //~^ ERROR: you appear to be counting bytes the naive way + //~^ naive_bytecount // not an equality count, OK. let _ = x.iter().filter(|a| **a > 0).count(); @@ -30,7 +30,7 @@ fn main() { // naive byte count let _ = x.iter().filter(|a| b + 1 == **a).count(); - //~^ ERROR: you appear to be counting bytes the naive way + //~^ naive_bytecount let y = vec![0_u16; 3]; diff --git a/src/tools/clippy/tests/ui/bytes_count_to_len.fixed b/src/tools/clippy/tests/ui/bytes_count_to_len.fixed index d20af22535a00..aa0484a83110c 100644 --- a/src/tools/clippy/tests/ui/bytes_count_to_len.fixed +++ b/src/tools/clippy/tests/ui/bytes_count_to_len.fixed @@ -1,19 +1,23 @@ #![warn(clippy::bytes_count_to_len)] use std::fs::File; -use std::io::Read; +use std::io::{BufReader, Read}; fn main() { // should fix, because type is String let _ = String::from("foo").len(); + //~^ bytes_count_to_len let s1 = String::from("foo"); let _ = s1.len(); + //~^ bytes_count_to_len // should fix, because type is &str let _ = "foo".len(); + //~^ bytes_count_to_len let s2 = "foo"; let _ = s2.len(); + //~^ bytes_count_to_len // make sure using count() normally doesn't trigger warning let vector = [0, 1, 2]; @@ -26,8 +30,8 @@ fn main() { bytes.bytes().count(); // The type is File, so should not fix - let _ = File::open("foobar").unwrap().bytes().count(); + let _ = BufReader::new(File::open("foobar").unwrap()).bytes().count(); - let f = File::open("foobar").unwrap(); + let f = BufReader::new(File::open("foobar").unwrap()); let _ = f.bytes().count(); } diff --git a/src/tools/clippy/tests/ui/bytes_count_to_len.rs b/src/tools/clippy/tests/ui/bytes_count_to_len.rs index 340e6b412556b..7e38858bf7830 100644 --- a/src/tools/clippy/tests/ui/bytes_count_to_len.rs +++ b/src/tools/clippy/tests/ui/bytes_count_to_len.rs @@ -1,19 +1,23 @@ #![warn(clippy::bytes_count_to_len)] use std::fs::File; -use std::io::Read; +use std::io::{BufReader, Read}; fn main() { // should fix, because type is String let _ = String::from("foo").bytes().count(); + //~^ bytes_count_to_len let s1 = String::from("foo"); let _ = s1.bytes().count(); + //~^ bytes_count_to_len // should fix, because type is &str let _ = "foo".bytes().count(); + //~^ bytes_count_to_len let s2 = "foo"; let _ = s2.bytes().count(); + //~^ bytes_count_to_len // make sure using count() normally doesn't trigger warning let vector = [0, 1, 2]; @@ -26,8 +30,8 @@ fn main() { bytes.bytes().count(); // The type is File, so should not fix - let _ = File::open("foobar").unwrap().bytes().count(); + let _ = BufReader::new(File::open("foobar").unwrap()).bytes().count(); - let f = File::open("foobar").unwrap(); + let f = BufReader::new(File::open("foobar").unwrap()); let _ = f.bytes().count(); } diff --git a/src/tools/clippy/tests/ui/bytes_count_to_len.stderr b/src/tools/clippy/tests/ui/bytes_count_to_len.stderr index b80f3af18f780..999da9ca1365b 100644 --- a/src/tools/clippy/tests/ui/bytes_count_to_len.stderr +++ b/src/tools/clippy/tests/ui/bytes_count_to_len.stderr @@ -8,19 +8,19 @@ LL | let _ = String::from("foo").bytes().count(); = help: to override `-D warnings` add `#[allow(clippy::bytes_count_to_len)]` error: using long and hard to read `.bytes().count()` - --> tests/ui/bytes_count_to_len.rs:10:13 + --> tests/ui/bytes_count_to_len.rs:11:13 | LL | let _ = s1.bytes().count(); | ^^^^^^^^^^^^^^^^^^ help: consider calling `.len()` instead: `s1.len()` error: using long and hard to read `.bytes().count()` - --> tests/ui/bytes_count_to_len.rs:13:13 + --> tests/ui/bytes_count_to_len.rs:15:13 | LL | let _ = "foo".bytes().count(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.len()` instead: `"foo".len()` error: using long and hard to read `.bytes().count()` - --> tests/ui/bytes_count_to_len.rs:16:13 + --> tests/ui/bytes_count_to_len.rs:19:13 | LL | let _ = s2.bytes().count(); | ^^^^^^^^^^^^^^^^^^ help: consider calling `.len()` instead: `s2.len()` diff --git a/src/tools/clippy/tests/ui/bytes_nth.fixed b/src/tools/clippy/tests/ui/bytes_nth.fixed index da35fcb55e5a6..6f4c2e7116e97 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.fixed +++ b/src/tools/clippy/tests/ui/bytes_nth.fixed @@ -5,6 +5,9 @@ fn main() { let s = String::from("String"); let _ = s.as_bytes().get(3).copied(); + //~^ bytes_nth let _ = &s.as_bytes()[3]; + //~^ bytes_nth let _ = s[..].as_bytes().get(3).copied(); + //~^ bytes_nth } diff --git a/src/tools/clippy/tests/ui/bytes_nth.rs b/src/tools/clippy/tests/ui/bytes_nth.rs index 5dbe84ecec8b7..27655bebb2648 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.rs +++ b/src/tools/clippy/tests/ui/bytes_nth.rs @@ -5,6 +5,9 @@ fn main() { let s = String::from("String"); let _ = s.bytes().nth(3); + //~^ bytes_nth let _ = &s.bytes().nth(3).unwrap(); + //~^ bytes_nth let _ = s[..].bytes().nth(3); + //~^ bytes_nth } diff --git a/src/tools/clippy/tests/ui/bytes_nth.stderr b/src/tools/clippy/tests/ui/bytes_nth.stderr index c5f341cb37f6c..c421839ff3f53 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.stderr +++ b/src/tools/clippy/tests/ui/bytes_nth.stderr @@ -8,13 +8,13 @@ LL | let _ = s.bytes().nth(3); = help: to override `-D warnings` add `#[allow(clippy::bytes_nth)]` error: called `.bytes().nth().unwrap()` on a `String` - --> tests/ui/bytes_nth.rs:8:14 + --> tests/ui/bytes_nth.rs:9:14 | LL | let _ = &s.bytes().nth(3).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.as_bytes()[3]` error: called `.bytes().nth()` on a `str` - --> tests/ui/bytes_nth.rs:9:13 + --> tests/ui/bytes_nth.rs:11:13 | LL | let _ = s[..].bytes().nth(3); | ^^^^^^^^^^^^^^^^^^^^ help: try: `s[..].as_bytes().get(3).copied()` diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed index c4d77f24f1261..bf7635fdf09bf 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -14,6 +14,7 @@ fn is_rust_file(filename: &str) -> bool { std::path::Path::new(filename) .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) + //~^ case_sensitive_file_extension_comparisons } fn main() { @@ -21,15 +22,18 @@ fn main() { let _ = std::path::Path::new(&String::new()) .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + //~^ case_sensitive_file_extension_comparisons let _ = std::path::Path::new("str") .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + //~^ case_sensitive_file_extension_comparisons // The fixup should preserve the indentation level { let _ = std::path::Path::new("str") .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); + //~^ case_sensitive_file_extension_comparisons } // The test struct should not trigger the lint failure with .ext12 @@ -39,9 +43,11 @@ fn main() { let _ = std::path::Path::new(&String::new()) .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + //~^ case_sensitive_file_extension_comparisons let _ = std::path::Path::new("str") .extension() .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); + //~^ case_sensitive_file_extension_comparisons // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase let _ = String::new().to_lowercase().ends_with(".EXT12"); diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs index 690e93c2639a2..0c4070a42d4b0 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -12,16 +12,20 @@ impl TestStruct { #[allow(dead_code)] fn is_rust_file(filename: &str) -> bool { filename.ends_with(".rs") + //~^ case_sensitive_file_extension_comparisons } fn main() { // std::string::String and &str should trigger the lint failure with .ext12 let _ = String::new().ends_with(".ext12"); + //~^ case_sensitive_file_extension_comparisons let _ = "str".ends_with(".ext12"); + //~^ case_sensitive_file_extension_comparisons // The fixup should preserve the indentation level { let _ = "str".ends_with(".ext12"); + //~^ case_sensitive_file_extension_comparisons } // The test struct should not trigger the lint failure with .ext12 @@ -29,7 +33,9 @@ fn main() { // std::string::String and &str should trigger the lint failure with .EXT12 let _ = String::new().ends_with(".EXT12"); + //~^ case_sensitive_file_extension_comparisons let _ = "str".ends_with(".EXT12"); + //~^ case_sensitive_file_extension_comparisons // Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase let _ = String::new().to_lowercase().ends_with(".EXT12"); diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr index e21815f251b7d..e035534d26996 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr @@ -15,7 +15,7 @@ LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs")) | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13 | LL | let _ = String::new().ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:22:13 | LL | let _ = "str".ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:24:17 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:27:17 | LL | let _ = "str".ends_with(".ext12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:35:13 | LL | let _ = String::new().ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12")); | error: case-sensitive file extension comparison - --> tests/ui/case_sensitive_file_extension_comparisons.rs:32:13 + --> tests/ui/case_sensitive_file_extension_comparisons.rs:37:13 | LL | let _ = "str".ends_with(".EXT12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast.rs b/src/tools/clippy/tests/ui/cast.rs index 0de53a75c6236..88c2549f4dc50 100644 --- a/src/tools/clippy/tests/ui/cast.rs +++ b/src/tools/clippy/tests/ui/cast.rs @@ -23,101 +23,127 @@ fn main() { // Test clippy::cast_precision_loss let x0 = 1i32; x0 as f32; - //~^ ERROR: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, - //~| NOTE: `-D clippy::cast-precision-loss` implied by `-D warnings` + //~^ cast_precision_loss + let x1 = 1i64; x1 as f32; - //~^ ERROR: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, + //~^ cast_precision_loss + x1 as f64; - //~^ ERROR: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, + //~^ cast_precision_loss + let x2 = 1u32; x2 as f32; - //~^ ERROR: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, + //~^ cast_precision_loss + let x3 = 1u64; x3 as f32; - //~^ ERROR: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, + //~^ cast_precision_loss + x3 as f64; - //~^ ERROR: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, + //~^ cast_precision_loss + // Test clippy::cast_possible_truncation 1f32 as i32; - //~^ ERROR: casting `f32` to `i32` may truncate the value + //~^ cast_possible_truncation + 1f32 as u32; - //~^ ERROR: casting `f32` to `u32` may truncate the value - //~| ERROR: casting `f32` to `u32` may lose the sign of the value - //~| NOTE: `-D clippy::cast-sign-loss` implied by `-D warnings` + //~^ cast_possible_truncation + //~| cast_sign_loss + 1f64 as f32; - //~^ ERROR: casting `f64` to `f32` may truncate the value + //~^ cast_possible_truncation + 1i32 as i8; - //~^ ERROR: casting `i32` to `i8` may truncate the value + //~^ cast_possible_truncation + 1i32 as u8; - //~^ ERROR: casting `i32` to `u8` may truncate the value + //~^ cast_possible_truncation + 1f64 as isize; - //~^ ERROR: casting `f64` to `isize` may truncate the value + //~^ cast_possible_truncation + 1f64 as usize; - //~^ ERROR: casting `f64` to `usize` may truncate the value - //~| ERROR: casting `f64` to `usize` may lose the sign of the value + //~^ cast_possible_truncation + //~| cast_sign_loss + 1f32 as u32 as u16; - //~^ ERROR: casting `u32` to `u16` may truncate the value - //~| ERROR: casting `f32` to `u32` may truncate the value - //~| ERROR: casting `f32` to `u32` may lose the sign of the value + //~^ cast_possible_truncation + //~| cast_possible_truncation + //~| cast_sign_loss + { let _x: i8 = 1i32 as _; - //~^ ERROR: casting `i32` to `i8` may truncate the value + //~^ cast_possible_truncation + 1f32 as i32; - //~^ ERROR: casting `f32` to `i32` may truncate the value + //~^ cast_possible_truncation + 1f64 as i32; - //~^ ERROR: casting `f64` to `i32` may truncate the value + //~^ cast_possible_truncation + 1f32 as u8; - //~^ ERROR: casting `f32` to `u8` may truncate the value - //~| ERROR: casting `f32` to `u8` may lose the sign of the value + //~^ cast_possible_truncation + //~| cast_sign_loss } // Test clippy::cast_possible_wrap 1u8 as i8; - //~^ ERROR: casting `u8` to `i8` may wrap around the value - //~| NOTE: `-D clippy::cast-possible-wrap` implied by `-D warnings` + //~^ cast_possible_wrap + 1u16 as i16; - //~^ ERROR: casting `u16` to `i16` may wrap around the value + //~^ cast_possible_wrap + 1u32 as i32; - //~^ ERROR: casting `u32` to `i32` may wrap around the value + //~^ cast_possible_wrap + 1u64 as i64; - //~^ ERROR: casting `u64` to `i64` may wrap around the value + //~^ cast_possible_wrap + 1usize as isize; - //~^ ERROR: casting `usize` to `isize` may wrap around the value + //~^ cast_possible_wrap + // should not wrap, usize is never 8 bits 1usize as i8; - //~^ ERROR: casting `usize` to `i8` may truncate the value + //~^ cast_possible_truncation + // wraps on 16 bit ptr size 1usize as i16; - //~^ ERROR: casting `usize` to `i16` may truncate the value - //~| ERROR: casting `usize` to `i16` may wrap around the value on targets with 16-bit - //~| NOTE: `usize` and `isize` may be as small as 16 bits on some platforms + //~^ cast_possible_truncation + //~| cast_possible_wrap + // wraps on 32 bit ptr size 1usize as i32; - //~^ ERROR: casting `usize` to `i32` may truncate the value on targets with 64-bit wid - //~| ERROR: casting `usize` to `i32` may wrap around the value on targets with 32-bit + //~^ cast_possible_truncation + //~| cast_possible_wrap + // wraps on 64 bit ptr size 1usize as i64; - //~^ ERROR: casting `usize` to `i64` may wrap around the value on targets with 64-bit + //~^ cast_possible_wrap + // should not wrap, isize is never 8 bits 1u8 as isize; // wraps on 16 bit ptr size 1u16 as isize; - //~^ ERROR: casting `u16` to `isize` may wrap around the value on targets with 16-bit - //~| NOTE: `usize` and `isize` may be as small as 16 bits on some platforms + //~^ cast_possible_wrap + // wraps on 32 bit ptr size 1u32 as isize; - //~^ ERROR: casting `u32` to `isize` may wrap around the value on targets with 32-bit + //~^ cast_possible_wrap + // wraps on 64 bit ptr size 1u64 as isize; - //~^ ERROR: casting `u64` to `isize` may truncate the value on targets with 32-bit wid - //~| ERROR: casting `u64` to `isize` may wrap around the value on targets with 64-bit + //~^ cast_possible_truncation + //~| cast_possible_wrap + // Test clippy::cast_sign_loss 1i32 as u32; -1i32 as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + 1isize as usize; -1isize as usize; - //~^ ERROR: casting `isize` to `usize` may lose the sign of the value + //~^ cast_sign_loss + 0i8 as u8; i8::MAX as u8; i16::MAX as u16; @@ -128,11 +154,14 @@ fn main() { (-1i8).saturating_abs() as u8; // abs() can return a negative value in release builds (i8::MIN).abs() as u8; - //~^ ERROR: casting `i8` to `u8` may lose the sign of the value + //~^ cast_sign_loss + (-1i16).saturating_abs() as u16; (-1i32).saturating_abs() as u32; (-1i64).abs() as u64; + //~^ cast_sign_loss (-1isize).abs() as usize; + //~^ cast_sign_loss (-1i8).checked_abs().unwrap() as u8; (i8::MIN).checked_abs().unwrap() as u8; @@ -140,6 +169,7 @@ fn main() { (-1i32).checked_abs().unwrap() as u32; // SAFETY: -1 is a small number which will always return Some (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; + //~^ cast_sign_loss (-1isize).checked_abs().expect("-1 is a small number") as usize; (-1i8).isqrt() as u8; @@ -155,6 +185,7 @@ fn main() { (-1i32).checked_isqrt().unwrap() as u32; // SAFETY: -1 is a small number which will always return Some (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; + //~^ cast_sign_loss (-1isize).checked_isqrt().expect("-1 is a small number") as usize; (-1i8).rem_euclid(1i8) as u8; @@ -206,7 +237,7 @@ fn main() { // Test for signed min // should be linted because signed (-99999999999i64).min(1) as i8; - //~^ ERROR: casting `i64` to `i8` may truncate the value + //~^ cast_possible_truncation // Test for various operations that remove enough bits for the result to fit (999999u64 & 1) as u8; @@ -220,7 +251,7 @@ fn main() { 999999u64.clamp(0, 255) as u8; // should still be linted 999999u64.clamp(0, 256) as u8; - //~^ ERROR: casting `u64` to `u8` may truncate the value + //~^ cast_possible_truncation #[derive(Clone, Copy)] enum E1 { @@ -243,10 +274,11 @@ fn main() { impl E2 { fn test(self) { let _ = self as u8; - //~^ ERROR: casting `main::E2` to `u8` may truncate the value + //~^ cast_possible_truncation + let _ = Self::B as u8; - //~^ ERROR: casting `main::E2::B` to `u8` will truncate the value - //~| NOTE: `-D clippy::cast-enum-truncation` implied by `-D warnings` + //~^ cast_enum_truncation + // Don't lint. `255..=256` fits in i16 let _ = self as i16; // Don't lint. @@ -287,9 +319,11 @@ fn main() { impl E5 { fn test(self) { let _ = self as i8; - //~^ ERROR: casting `main::E5` to `i8` may truncate the value + //~^ cast_possible_truncation + let _ = Self::A as i8; - //~^ ERROR: casting `main::E5::A` to `i8` will truncate the value + //~^ cast_enum_truncation + // Don't lint. `-129..=127` fits in i16 let _ = self as i16; // Don't lint. @@ -306,7 +340,8 @@ fn main() { impl E6 { fn test(self) { let _ = self as i16; - //~^ ERROR: casting `main::E6` to `i16` may truncate the value + //~^ cast_possible_truncation + // Don't lint. `2^16-1` fits in u16 let _ = Self::A as u16; // Don't lint. `2^16-1..=2^16` fits in u32 @@ -325,7 +360,8 @@ fn main() { impl E7 { fn test(self) { let _ = self as usize; - //~^ ERROR: casting `main::E7` to `usize` may truncate the value on targets wi + //~^ cast_possible_truncation + // Don't lint. let _ = Self::A as usize; // Don't lint. `2^32-1..=2^32` fits in u64 @@ -372,7 +408,8 @@ fn main() { impl E10 { fn test(self) { let _ = self as u16; - //~^ ERROR: casting `main::E10` to `u16` may truncate the value + //~^ cast_possible_truncation + // Don't lint. let _ = Self::B as u32; // Don't lint. @@ -383,11 +420,13 @@ fn main() { fn avoid_subtract_overflow(q: u32) { let c = (q >> 16) as u8; - //~^ ERROR: casting `u32` to `u8` may truncate the value + //~^ cast_possible_truncation + c as usize; let c = (q / 1000) as u8; - //~^ ERROR: casting `u32` to `u8` may truncate the value + //~^ cast_possible_truncation + c as usize; } @@ -399,70 +438,93 @@ fn issue11642() { fn square(x: i16) -> u32 { let x = x as i32; (x * x) as u32; + //~^ cast_sign_loss x.pow(2) as u32; (-2_i32).saturating_pow(2) as u32 } let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; + //~^ cast_sign_loss (2_i32).checked_pow(3).unwrap() as u32; + //~^ cast_sign_loss (-2_i32).pow(3) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss (3_i32 % 2) as u32; (3_i32 % -2) as u32; (-5_i32 % 2) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (-5_i32 % -2) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (2_i32 >> 1) as u32; (-2_i32 >> 1) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss let x: i32 = 10; (x * x) as u32; + //~^ cast_sign_loss (x * x * x) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss let y: i16 = -2; (y * y * y * y * -2) as u16; - //~^ ERROR: casting `i16` to `u16` may lose the sign of the value + //~^ cast_sign_loss + (y * y * y / y * 2) as u16; + //~^ cast_sign_loss (y * y / y * 2) as u16; - //~^ ERROR: casting `i16` to `u16` may lose the sign of the value + //~^ cast_sign_loss + (y / y * y * -2) as u16; - //~^ ERROR: casting `i16` to `u16` may lose the sign of the value + //~^ cast_sign_loss + //~| eq_op (y + y + y + -2) as u16; - //~^ ERROR: casting `i16` to `u16` may lose the sign of the value + //~^ cast_sign_loss + (y + y + y + 2) as u16; - //~^ ERROR: casting `i16` to `u16` may lose the sign of the value + //~^ cast_sign_loss let z: i16 = 2; (z + -2) as u16; - //~^ ERROR: casting `i16` to `u16` may lose the sign of the value + //~^ cast_sign_loss + (z + z + 2) as u16; + //~^ cast_sign_loss fn foo(a: i32, b: i32, c: i32) -> u32 { (a * a * b * b * c * c) as u32; + //~^ cast_sign_loss (a * b * c) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (a * -b * c) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (a * b * c * c) as u32; + //~^ cast_sign_loss (a * -2) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (a * b * c * -2) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (a / b) as u32; + //~^ cast_sign_loss (a / b * c) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (a / b + b * c) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + a.saturating_pow(3) as u32; - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss + (a.abs() * b.pow(2) / c.abs()) as u32 - //~^ ERROR: casting `i32` to `u32` may lose the sign of the value + //~^ cast_sign_loss } } @@ -470,8 +532,14 @@ fn issue11738() { macro_rules! m { () => { let _ = i32::MIN as u32; // cast_sign_loss + // + //~^^ cast_sign_loss let _ = u32::MAX as u8; // cast_possible_truncation + // + //~^^ cast_possible_truncation let _ = std::f64::consts::PI as f32; // cast_possible_truncation + // + //~^^ cast_possible_truncation let _ = 0i8 as i32; // cast_lossless }; } @@ -481,6 +549,8 @@ fn issue11738() { fn issue12506() -> usize { let bar: Result, u32> = Ok(Some(10)); bar.unwrap().unwrap() as usize + //~^ cast_possible_truncation + //~| cast_sign_loss } fn issue12721() { @@ -496,7 +566,8 @@ fn issue12721() { let _ = (999999 & (x() & 255)) as u8; (256 & 999999u64) as u8; - //~^ ERROR: casting `u64` to `u8` may truncate the value + //~^ cast_possible_truncation + (255 % 999999u64) as u8; - //~^ ERROR: casting `u64` to `u8` may truncate the value + //~^ cast_possible_truncation } diff --git a/src/tools/clippy/tests/ui/cast.stderr b/src/tools/clippy/tests/ui/cast.stderr index 901447c738ed3..4d03282f6676e 100644 --- a/src/tools/clippy/tests/ui/cast.stderr +++ b/src/tools/clippy/tests/ui/cast.stderr @@ -14,31 +14,31 @@ 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:31:5 + --> tests/ui/cast.rs:32: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:34:5 + --> tests/ui/cast.rs:36: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:37:5 + --> tests/ui/cast.rs:40: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:39:5 + --> tests/ui/cast.rs:43:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:42:5 + --> tests/ui/cast.rs:47: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:44:5 + --> tests/ui/cast.rs:50: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:44:5 + --> tests/ui/cast.rs:50: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:48:5 + --> tests/ui/cast.rs:54: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:50:5 + --> tests/ui/cast.rs:57:5 | LL | 1i32 as i8; | ^^^^^^^^^^ @@ -86,7 +86,7 @@ LL + i8::try_from(1i32); | error: casting `i32` to `u8` may truncate the value - --> tests/ui/cast.rs:52:5 + --> tests/ui/cast.rs:60:5 | LL | 1i32 as u8; | ^^^^^^^^^^ @@ -99,7 +99,7 @@ LL + u8::try_from(1i32); | error: casting `f64` to `isize` may truncate the value - --> tests/ui/cast.rs:54:5 + --> tests/ui/cast.rs:63:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ @@ -107,7 +107,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:56:5 + --> tests/ui/cast.rs:66:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ @@ -115,13 +115,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:56:5 + --> tests/ui/cast.rs:66:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u32` to `u16` may truncate the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:70:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL + u16::try_from(1f32 as u32); | error: casting `f32` to `u32` may truncate the value - --> tests/ui/cast.rs:59:5 + --> tests/ui/cast.rs:70:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ @@ -142,13 +142,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:59:5 + --> tests/ui/cast.rs:70:5 | LL | 1f32 as u32 as u16; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> tests/ui/cast.rs:64:22 + --> tests/ui/cast.rs:76:22 | LL | let _x: i8 = 1i32 as _; | ^^^^^^^^^ @@ -161,7 +161,7 @@ LL + let _x: i8 = 1i32.try_into(); | error: casting `f32` to `i32` may truncate the value - --> tests/ui/cast.rs:66:9 + --> tests/ui/cast.rs:79:9 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -169,7 +169,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:68:9 + --> tests/ui/cast.rs:82:9 | LL | 1f64 as i32; | ^^^^^^^^^^^ @@ -177,7 +177,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:70:9 + --> tests/ui/cast.rs:85:9 | LL | 1f32 as u8; | ^^^^^^^^^^ @@ -185,13 +185,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:70:9 + --> tests/ui/cast.rs:85:9 | LL | 1f32 as u8; | ^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> tests/ui/cast.rs:75:5 + --> tests/ui/cast.rs:90:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -200,31 +200,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:78:5 + --> tests/ui/cast.rs:93:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> tests/ui/cast.rs:80:5 + --> tests/ui/cast.rs:96:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> tests/ui/cast.rs:82:5 + --> tests/ui/cast.rs:99:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> tests/ui/cast.rs:84:5 + --> tests/ui/cast.rs:102:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `usize` to `i8` may truncate the value - --> tests/ui/cast.rs:87:5 + --> tests/ui/cast.rs:106:5 | LL | 1usize as i8; | ^^^^^^^^^^^^ @@ -237,7 +237,7 @@ LL + i8::try_from(1usize); | error: casting `usize` to `i16` may truncate the value - --> tests/ui/cast.rs:90:5 + --> tests/ui/cast.rs:110:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -250,7 +250,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:90:5 + --> tests/ui/cast.rs:110:5 | LL | 1usize as i16; | ^^^^^^^^^^^^^ @@ -259,7 +259,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:95:5 + --> tests/ui/cast.rs:115:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -272,19 +272,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:95:5 + --> tests/ui/cast.rs:115: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:99:5 + --> tests/ui/cast.rs:120: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:104:5 + --> tests/ui/cast.rs:126:5 | LL | 1u16 as isize; | ^^^^^^^^^^^^^ @@ -293,13 +293,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:108:5 + --> tests/ui/cast.rs:130: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:111:5 + --> tests/ui/cast.rs:134:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -312,55 +312,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:111:5 + --> tests/ui/cast.rs:134:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:116:5 + --> tests/ui/cast.rs:140:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:119:5 + --> tests/ui/cast.rs:144:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i8` to `u8` may lose the sign of the value - --> tests/ui/cast.rs:130:5 + --> tests/ui/cast.rs:156:5 | LL | (i8::MIN).abs() as u8; | ^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:134:5 + --> tests/ui/cast.rs:161:5 | LL | (-1i64).abs() as u64; | ^^^^^^^^^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:135:5 + --> tests/ui/cast.rs:163:5 | LL | (-1isize).abs() as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `u64` may lose the sign of the value - --> tests/ui/cast.rs:142:5 + --> tests/ui/cast.rs:171: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:157:5 + --> tests/ui/cast.rs:187:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> tests/ui/cast.rs:208:5 + --> tests/ui/cast.rs:239:5 | LL | (-99999999999i64).min(1) as i8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL + i8::try_from((-99999999999i64).min(1)); | error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:222:5 + --> tests/ui/cast.rs:253:5 | LL | 999999u64.clamp(0, 256) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -386,7 +386,7 @@ LL + u8::try_from(999999u64.clamp(0, 256)); | error: casting `main::E2` to `u8` may truncate the value - --> tests/ui/cast.rs:245:21 + --> tests/ui/cast.rs:276:21 | LL | let _ = self as u8; | ^^^^^^^^^^ @@ -399,7 +399,7 @@ LL + let _ = u8::try_from(self); | error: casting `main::E2::B` to `u8` will truncate the value - --> tests/ui/cast.rs:247:21 + --> tests/ui/cast.rs:279:21 | LL | let _ = Self::B as u8; | ^^^^^^^^^^^^^ @@ -408,7 +408,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:289:21 + --> tests/ui/cast.rs:321:21 | LL | let _ = self as i8; | ^^^^^^^^^^ @@ -421,13 +421,13 @@ LL + let _ = i8::try_from(self); | error: casting `main::E5::A` to `i8` will truncate the value - --> tests/ui/cast.rs:291:21 + --> tests/ui/cast.rs:324:21 | LL | let _ = Self::A as i8; | ^^^^^^^^^^^^^ error: casting `main::E6` to `i16` may truncate the value - --> tests/ui/cast.rs:308:21 + --> tests/ui/cast.rs:342:21 | LL | let _ = self as i16; | ^^^^^^^^^^^ @@ -440,7 +440,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:327:21 + --> tests/ui/cast.rs:362:21 | LL | let _ = self as usize; | ^^^^^^^^^^^^^ @@ -453,7 +453,7 @@ LL + let _ = usize::try_from(self); | error: casting `main::E10` to `u16` may truncate the value - --> tests/ui/cast.rs:374:21 + --> tests/ui/cast.rs:410:21 | LL | let _ = self as u16; | ^^^^^^^^^^^ @@ -466,7 +466,7 @@ LL + let _ = u16::try_from(self); | error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:385:13 + --> tests/ui/cast.rs:422:13 | LL | let c = (q >> 16) as u8; | ^^^^^^^^^^^^^^^ @@ -479,7 +479,7 @@ LL + let c = u8::try_from(q >> 16); | error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:389:13 + --> tests/ui/cast.rs:427:13 | LL | let c = (q / 1000) as u8; | ^^^^^^^^^^^^^^^^ @@ -492,85 +492,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:401:9 + --> tests/ui/cast.rs:440:9 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:406:32 + --> tests/ui/cast.rs:446: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:408:5 + --> tests/ui/cast.rs:449: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:409:5 + --> tests/ui/cast.rs:451:5 | LL | (-2_i32).pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:414:5 + --> tests/ui/cast.rs:456:5 | LL | (-5_i32 % 2) as u32; | ^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:416:5 + --> tests/ui/cast.rs:459:5 | LL | (-5_i32 % -2) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:419:5 + --> tests/ui/cast.rs:463:5 | LL | (-2_i32 >> 1) as u32; | ^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:423:5 + --> tests/ui/cast.rs:467:5 | LL | (x * x) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:424:5 + --> tests/ui/cast.rs:469:5 | LL | (x * x * x) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:428:5 + --> tests/ui/cast.rs:473: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:430:5 + --> tests/ui/cast.rs:476: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:431:5 + --> tests/ui/cast.rs:478:5 | LL | (y * y / y * 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:433:5 + --> tests/ui/cast.rs:481:5 | LL | (y / y * y * -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/cast.rs:433:6 + --> tests/ui/cast.rs:481:6 | LL | (y / y * y * -2) as u16; | ^^^^^ @@ -578,97 +578,97 @@ 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:436:5 + --> tests/ui/cast.rs:485:5 | LL | (y + y + y + -2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:438:5 + --> tests/ui/cast.rs:488:5 | LL | (y + y + y + 2) as u16; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:442:5 + --> tests/ui/cast.rs:492:5 | LL | (z + -2) as u16; | ^^^^^^^^^^^^^^^ error: casting `i16` to `u16` may lose the sign of the value - --> tests/ui/cast.rs:444:5 + --> tests/ui/cast.rs:495:5 | LL | (z + z + 2) as u16; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:447:9 + --> tests/ui/cast.rs:499: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:448:9 + --> tests/ui/cast.rs:501:9 | LL | (a * b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:450:9 + --> tests/ui/cast.rs:504: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:507:9 | LL | (a * b * c * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:453:9 + --> tests/ui/cast.rs:509:9 | LL | (a * -2) as u32; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:455:9 + --> tests/ui/cast.rs:512:9 | LL | (a * b * c * -2) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:457:9 + --> tests/ui/cast.rs:515:9 | LL | (a / b) as u32; | ^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:458:9 + --> tests/ui/cast.rs:517:9 | LL | (a / b * c) as u32; | ^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:460:9 + --> tests/ui/cast.rs:520:9 | LL | (a / b + b * c) as u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:462:9 + --> tests/ui/cast.rs:523:9 | LL | a.saturating_pow(3) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:464:9 + --> tests/ui/cast.rs:526:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> tests/ui/cast.rs:472:21 + --> tests/ui/cast.rs:534:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss | ^^^^^^^^^^^^^^^ @@ -679,7 +679,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `u32` to `u8` may truncate the value - --> tests/ui/cast.rs:473:21 + --> tests/ui/cast.rs:537:21 | LL | let _ = u32::MAX as u8; // cast_possible_truncation | ^^^^^^^^^^^^^^ @@ -696,7 +696,7 @@ LL + let _ = u8::try_from(u32::MAX); // cast_possible_truncation | error: casting `f64` to `f32` may truncate the value - --> tests/ui/cast.rs:474:21 + --> tests/ui/cast.rs:540:21 | LL | let _ = std::f64::consts::PI as f32; // cast_possible_truncation | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -708,7 +708,7 @@ LL | m!(); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast.rs:483:5 + --> tests/ui/cast.rs:551:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -721,13 +721,13 @@ LL + usize::try_from(bar.unwrap().unwrap()) | error: casting `i64` to `usize` may lose the sign of the value - --> tests/ui/cast.rs:483:5 + --> tests/ui/cast.rs:551:5 | LL | bar.unwrap().unwrap() as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:498:5 + --> tests/ui/cast.rs:568:5 | LL | (256 & 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -740,7 +740,7 @@ LL + u8::try_from(256 & 999999u64); | error: casting `u64` to `u8` may truncate the value - --> tests/ui/cast.rs:500:5 + --> tests/ui/cast.rs:571:5 | LL | (255 % 999999u64) as u8; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed index 6ca01b7cc3670..b55c22f5ca83c 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed @@ -4,30 +4,47 @@ fn main() { let x: i32 = -42; let y: u32 = x.unsigned_abs(); + //~^ cast_abs_to_unsigned println!("The absolute value of {} is {}", x, y); let a: i32 = -3; let _: usize = a.unsigned_abs() as usize; + //~^ cast_abs_to_unsigned let _: usize = a.unsigned_abs() as _; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as usize; + //~^ cast_abs_to_unsigned let a: i64 = -3; let _ = a.unsigned_abs() as usize; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u8; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u16; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u32; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs(); + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u128; + //~^ cast_abs_to_unsigned let a: isize = -3; let _ = a.unsigned_abs(); + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u8; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u16; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u32; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u64; + //~^ cast_abs_to_unsigned let _ = a.unsigned_abs() as u128; + //~^ cast_abs_to_unsigned let _ = (x as i64 - y as i64).unsigned_abs() as u32; + //~^ cast_abs_to_unsigned } #[clippy::msrv = "1.50"] @@ -40,4 +57,5 @@ fn msrv_1_50() { fn msrv_1_51() { let x: i32 = 10; assert_eq!(10u32, x.unsigned_abs()); + //~^ cast_abs_to_unsigned } diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs index 190a77c102326..466aa6aeb1fbb 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs @@ -4,30 +4,47 @@ fn main() { let x: i32 = -42; let y: u32 = x.abs() as u32; + //~^ cast_abs_to_unsigned println!("The absolute value of {} is {}", x, y); let a: i32 = -3; let _: usize = a.abs() as usize; + //~^ cast_abs_to_unsigned let _: usize = a.abs() as _; + //~^ cast_abs_to_unsigned let _ = a.abs() as usize; + //~^ cast_abs_to_unsigned let a: i64 = -3; let _ = a.abs() as usize; + //~^ cast_abs_to_unsigned let _ = a.abs() as u8; + //~^ cast_abs_to_unsigned let _ = a.abs() as u16; + //~^ cast_abs_to_unsigned let _ = a.abs() as u32; + //~^ cast_abs_to_unsigned let _ = a.abs() as u64; + //~^ cast_abs_to_unsigned let _ = a.abs() as u128; + //~^ cast_abs_to_unsigned let a: isize = -3; let _ = a.abs() as usize; + //~^ cast_abs_to_unsigned let _ = a.abs() as u8; + //~^ cast_abs_to_unsigned let _ = a.abs() as u16; + //~^ cast_abs_to_unsigned let _ = a.abs() as u32; + //~^ cast_abs_to_unsigned let _ = a.abs() as u64; + //~^ cast_abs_to_unsigned let _ = a.abs() as u128; + //~^ cast_abs_to_unsigned let _ = (x as i64 - y as i64).abs() as u32; + //~^ cast_abs_to_unsigned } #[clippy::msrv = "1.50"] @@ -40,4 +57,5 @@ fn msrv_1_50() { fn msrv_1_51() { let x: i32 = 10; assert_eq!(10u32, x.abs() as u32); + //~^ cast_abs_to_unsigned } diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr index 96e5c1724a51b..26220693969cb 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr @@ -8,103 +8,103 @@ LL | let y: u32 = x.abs() as u32; = help: to override `-D warnings` add `#[allow(clippy::cast_abs_to_unsigned)]` error: casting the result of `i32::abs()` to usize - --> tests/ui/cast_abs_to_unsigned.rs:10:20 + --> tests/ui/cast_abs_to_unsigned.rs:11:20 | LL | let _: usize = a.abs() as usize; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i32::abs()` to usize - --> tests/ui/cast_abs_to_unsigned.rs:11:20 + --> tests/ui/cast_abs_to_unsigned.rs:13:20 | LL | let _: usize = a.abs() as _; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i32::abs()` to usize - --> tests/ui/cast_abs_to_unsigned.rs:12:13 + --> tests/ui/cast_abs_to_unsigned.rs:15:13 | LL | let _ = a.abs() as usize; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to usize - --> tests/ui/cast_abs_to_unsigned.rs:15:13 + --> tests/ui/cast_abs_to_unsigned.rs:19:13 | LL | let _ = a.abs() as usize; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u8 - --> tests/ui/cast_abs_to_unsigned.rs:16:13 + --> tests/ui/cast_abs_to_unsigned.rs:21:13 | LL | let _ = a.abs() as u8; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u16 - --> tests/ui/cast_abs_to_unsigned.rs:17:13 + --> tests/ui/cast_abs_to_unsigned.rs:23:13 | LL | let _ = a.abs() as u16; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u32 - --> tests/ui/cast_abs_to_unsigned.rs:18:13 + --> tests/ui/cast_abs_to_unsigned.rs:25:13 | LL | let _ = a.abs() as u32; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u64 - --> tests/ui/cast_abs_to_unsigned.rs:19:13 + --> tests/ui/cast_abs_to_unsigned.rs:27:13 | LL | let _ = a.abs() as u64; | ^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u128 - --> tests/ui/cast_abs_to_unsigned.rs:20:13 + --> tests/ui/cast_abs_to_unsigned.rs:29:13 | LL | let _ = a.abs() as u128; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to usize - --> tests/ui/cast_abs_to_unsigned.rs:23:13 + --> tests/ui/cast_abs_to_unsigned.rs:33:13 | LL | let _ = a.abs() as usize; | ^^^^^^^^^^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u8 - --> tests/ui/cast_abs_to_unsigned.rs:24:13 + --> tests/ui/cast_abs_to_unsigned.rs:35:13 | LL | let _ = a.abs() as u8; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u16 - --> tests/ui/cast_abs_to_unsigned.rs:25:13 + --> tests/ui/cast_abs_to_unsigned.rs:37:13 | LL | let _ = a.abs() as u16; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u32 - --> tests/ui/cast_abs_to_unsigned.rs:26:13 + --> tests/ui/cast_abs_to_unsigned.rs:39:13 | LL | let _ = a.abs() as u32; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u64 - --> tests/ui/cast_abs_to_unsigned.rs:27:13 + --> tests/ui/cast_abs_to_unsigned.rs:41:13 | LL | let _ = a.abs() as u64; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `isize::abs()` to u128 - --> tests/ui/cast_abs_to_unsigned.rs:28:13 + --> tests/ui/cast_abs_to_unsigned.rs:43:13 | LL | let _ = a.abs() as u128; | ^^^^^^^ help: replace with: `a.unsigned_abs()` error: casting the result of `i64::abs()` to u32 - --> tests/ui/cast_abs_to_unsigned.rs:30:13 + --> tests/ui/cast_abs_to_unsigned.rs:46:13 | LL | let _ = (x as i64 - y as i64).abs() as u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()` error: casting the result of `i32::abs()` to u32 - --> tests/ui/cast_abs_to_unsigned.rs:42:23 + --> tests/ui/cast_abs_to_unsigned.rs:59:23 | LL | assert_eq!(10u32, x.abs() as u32); | ^^^^^^^^^^^^^^ help: replace with: `x.unsigned_abs()` diff --git a/src/tools/clippy/tests/ui/cast_alignment.rs b/src/tools/clippy/tests/ui/cast_alignment.rs index 72f5d4268cc1b..5773ffddb9176 100644 --- a/src/tools/clippy/tests/ui/cast_alignment.rs +++ b/src/tools/clippy/tests/ui/cast_alignment.rs @@ -17,16 +17,17 @@ fn main() { // cast to more-strictly-aligned type (&1u8 as *const u8) as *const u16; - //~^ ERROR: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) - //~| NOTE: `-D clippy::cast-ptr-alignment` implied by `-D warnings` + //~^ cast_ptr_alignment + (&mut 1u8 as *mut u8) as *mut u16; - //~^ ERROR: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 + //~^ cast_ptr_alignment // cast to more-strictly-aligned type, but with the `pointer::cast` function. (&1u8 as *const u8).cast::(); - //~^ ERROR: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) + //~^ cast_ptr_alignment + (&mut 1u8 as *mut u8).cast::(); - //~^ ERROR: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 + //~^ cast_ptr_alignment /* These should be ok */ diff --git a/src/tools/clippy/tests/ui/cast_alignment.stderr b/src/tools/clippy/tests/ui/cast_alignment.stderr index b32624f958fc2..6d9a81f0ecfd4 100644 --- a/src/tools/clippy/tests/ui/cast_alignment.stderr +++ b/src/tools/clippy/tests/ui/cast_alignment.stderr @@ -20,7 +20,7 @@ LL | (&1u8 as *const u8).cast::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes) - --> tests/ui/cast_alignment.rs:28:5 + --> tests/ui/cast_alignment.rs:29:5 | LL | (&mut 1u8 as *mut u8).cast::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_enum_constructor.rs b/src/tools/clippy/tests/ui/cast_enum_constructor.rs index 3226f487b3aff..eecf56f71a334 100644 --- a/src/tools/clippy/tests/ui/cast_enum_constructor.rs +++ b/src/tools/clippy/tests/ui/cast_enum_constructor.rs @@ -11,10 +11,11 @@ fn main() { } let _ = Foo::Y as usize; - //~^ ERROR: cast of an enum tuple constructor to an integer - //~| NOTE: `-D clippy::cast-enum-constructor` implied by `-D warnings` + //~^ cast_enum_constructor + let _ = Foo::Y as isize; - //~^ ERROR: cast of an enum tuple constructor to an integer + //~^ cast_enum_constructor + let _ = Foo::Y as fn(u32) -> Foo; let _ = Bar::X as usize; } diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed index 51a38a60cf6b2..21dc280a5864c 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed +++ b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed @@ -6,23 +6,37 @@ type U8 = u8; fn main() { // Test clippy::cast_lossless with casts to integer types let _ = u8::from(true); + //~^ cast_lossless let _ = u16::from(true); + //~^ cast_lossless let _ = u32::from(true); + //~^ cast_lossless let _ = u64::from(true); + //~^ cast_lossless let _ = u128::from(true); + //~^ cast_lossless let _ = usize::from(true); + //~^ cast_lossless let _ = i8::from(true); + //~^ cast_lossless let _ = i16::from(true); + //~^ cast_lossless let _ = i32::from(true); + //~^ cast_lossless let _ = i64::from(true); + //~^ cast_lossless let _ = i128::from(true); + //~^ cast_lossless let _ = isize::from(true); + //~^ cast_lossless // Test with an expression wrapped in parens let _ = u16::from(true | false); + //~^ cast_lossless let _ = U8::from(true); + //~^ cast_lossless } // The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const, @@ -51,4 +65,5 @@ fn msrv_1_27() { #[clippy::msrv = "1.28"] fn msrv_1_28() { let _ = u8::from(true); + //~^ cast_lossless } diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.rs b/src/tools/clippy/tests/ui/cast_lossless_bool.rs index cb307bd68e43e..d03badd9a7bc2 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_bool.rs +++ b/src/tools/clippy/tests/ui/cast_lossless_bool.rs @@ -6,23 +6,37 @@ type U8 = u8; fn main() { // Test clippy::cast_lossless with casts to integer types let _ = true as u8; + //~^ cast_lossless let _ = true as u16; + //~^ cast_lossless let _ = true as u32; + //~^ cast_lossless let _ = true as u64; + //~^ cast_lossless let _ = true as u128; + //~^ cast_lossless let _ = true as usize; + //~^ cast_lossless let _ = true as i8; + //~^ cast_lossless let _ = true as i16; + //~^ cast_lossless let _ = true as i32; + //~^ cast_lossless let _ = true as i64; + //~^ cast_lossless let _ = true as i128; + //~^ cast_lossless let _ = true as isize; + //~^ cast_lossless // Test with an expression wrapped in parens let _ = (true | false) as u16; + //~^ cast_lossless let _ = true as U8; + //~^ cast_lossless } // The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const, @@ -51,4 +65,5 @@ fn msrv_1_27() { #[clippy::msrv = "1.28"] fn msrv_1_28() { let _ = true as u8; + //~^ cast_lossless } diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr index 6899227176236..802eeaebbbdd1 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_bool.stderr +++ b/src/tools/clippy/tests/ui/cast_lossless_bool.stderr @@ -14,7 +14,7 @@ LL + let _ = u8::from(true); | error: casts from `bool` to `u16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:9:13 + --> tests/ui/cast_lossless_bool.rs:10:13 | LL | let _ = true as u16; | ^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL + let _ = u16::from(true); | error: casts from `bool` to `u32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:10:13 + --> tests/ui/cast_lossless_bool.rs:12:13 | LL | let _ = true as u32; | ^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let _ = u32::from(true); | error: casts from `bool` to `u64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:11:13 + --> tests/ui/cast_lossless_bool.rs:14:13 | LL | let _ = true as u64; | ^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL + let _ = u64::from(true); | error: casts from `bool` to `u128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:12:13 + --> tests/ui/cast_lossless_bool.rs:16:13 | LL | let _ = true as u128; | ^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL + let _ = u128::from(true); | error: casts from `bool` to `usize` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:13:13 + --> tests/ui/cast_lossless_bool.rs:18:13 | LL | let _ = true as usize; | ^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL + let _ = usize::from(true); | error: casts from `bool` to `i8` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:15:13 + --> tests/ui/cast_lossless_bool.rs:21:13 | LL | let _ = true as i8; | ^^^^^^^^^^ @@ -92,7 +92,7 @@ LL + let _ = i8::from(true); | error: casts from `bool` to `i16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:16:13 + --> tests/ui/cast_lossless_bool.rs:23:13 | LL | let _ = true as i16; | ^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL + let _ = i16::from(true); | error: casts from `bool` to `i32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:17:13 + --> tests/ui/cast_lossless_bool.rs:25:13 | LL | let _ = true as i32; | ^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL + let _ = i32::from(true); | error: casts from `bool` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:18:13 + --> tests/ui/cast_lossless_bool.rs:27:13 | LL | let _ = true as i64; | ^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL + let _ = i64::from(true); | error: casts from `bool` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:19:13 + --> tests/ui/cast_lossless_bool.rs:29:13 | LL | let _ = true as i128; | ^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL + let _ = i128::from(true); | error: casts from `bool` to `isize` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:20:13 + --> tests/ui/cast_lossless_bool.rs:31:13 | LL | let _ = true as isize; | ^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + let _ = isize::from(true); | error: casts from `bool` to `u16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:23:13 + --> tests/ui/cast_lossless_bool.rs:35:13 | LL | let _ = (true | false) as u16; | ^^^^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL + let _ = u16::from(true | false); | error: casts from `bool` to `u8` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:25:13 + --> tests/ui/cast_lossless_bool.rs:38:13 | LL | let _ = true as U8; | ^^^^^^^^^^ @@ -183,7 +183,7 @@ LL + let _ = U8::from(true); | error: casts from `bool` to `u8` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_bool.rs:53:13 + --> tests/ui/cast_lossless_bool.rs:67:13 | LL | let _ = true as u8; | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.fixed b/src/tools/clippy/tests/ui/cast_lossless_float.fixed index 163432631e137..6ddd5f10a2ca6 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.fixed +++ b/src/tools/clippy/tests/ui/cast_lossless_float.fixed @@ -10,25 +10,38 @@ fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; let _ = f32::from(x0); + //~^ cast_lossless let _ = f64::from(x0); + //~^ cast_lossless let _ = F32::from(x0); + //~^ cast_lossless let _ = F64::from(x0); + //~^ cast_lossless let x1 = 1u8; let _ = f32::from(x1); + //~^ cast_lossless let _ = f64::from(x1); + //~^ cast_lossless let x2 = 1i16; let _ = f32::from(x2); + //~^ cast_lossless let _ = f64::from(x2); + //~^ cast_lossless let x3 = 1u16; let _ = f32::from(x3); + //~^ cast_lossless let _ = f64::from(x3); + //~^ cast_lossless let x4 = 1i32; let _ = f64::from(x4); + //~^ cast_lossless let x5 = 1u32; let _ = f64::from(x5); + //~^ cast_lossless // Test with casts from floating-point types let _ = f64::from(1.0f32); + //~^ cast_lossless } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.rs b/src/tools/clippy/tests/ui/cast_lossless_float.rs index afb2a3d890ee9..fe5a905445383 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.rs +++ b/src/tools/clippy/tests/ui/cast_lossless_float.rs @@ -10,25 +10,38 @@ fn main() { // Test clippy::cast_lossless with casts to floating-point types let x0 = 1i8; let _ = x0 as f32; + //~^ cast_lossless let _ = x0 as f64; + //~^ cast_lossless let _ = x0 as F32; + //~^ cast_lossless let _ = x0 as F64; + //~^ cast_lossless let x1 = 1u8; let _ = x1 as f32; + //~^ cast_lossless let _ = x1 as f64; + //~^ cast_lossless let x2 = 1i16; let _ = x2 as f32; + //~^ cast_lossless let _ = x2 as f64; + //~^ cast_lossless let x3 = 1u16; let _ = x3 as f32; + //~^ cast_lossless let _ = x3 as f64; + //~^ cast_lossless let x4 = 1i32; let _ = x4 as f64; + //~^ cast_lossless let x5 = 1u32; let _ = x5 as f64; + //~^ cast_lossless // Test with casts from floating-point types let _ = 1.0f32 as f64; + //~^ cast_lossless } // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const, diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.stderr b/src/tools/clippy/tests/ui/cast_lossless_float.stderr index 3f405e3f402f4..35ae38b1d36a7 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.stderr +++ b/src/tools/clippy/tests/ui/cast_lossless_float.stderr @@ -14,7 +14,7 @@ LL + let _ = f32::from(x0); | error: casts from `i8` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:13:13 + --> tests/ui/cast_lossless_float.rs:14:13 | LL | let _ = x0 as f64; | ^^^^^^^^^ @@ -27,7 +27,7 @@ LL + let _ = f64::from(x0); | error: casts from `i8` to `f32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:14:13 + --> tests/ui/cast_lossless_float.rs:16:13 | LL | let _ = x0 as F32; | ^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let _ = F32::from(x0); | error: casts from `i8` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:15:13 + --> tests/ui/cast_lossless_float.rs:18:13 | LL | let _ = x0 as F64; | ^^^^^^^^^ @@ -53,7 +53,7 @@ LL + let _ = F64::from(x0); | error: casts from `u8` to `f32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:17:13 + --> tests/ui/cast_lossless_float.rs:21:13 | LL | let _ = x1 as f32; | ^^^^^^^^^ @@ -66,7 +66,7 @@ LL + let _ = f32::from(x1); | error: casts from `u8` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:18:13 + --> tests/ui/cast_lossless_float.rs:23:13 | LL | let _ = x1 as f64; | ^^^^^^^^^ @@ -79,7 +79,7 @@ LL + let _ = f64::from(x1); | error: casts from `i16` to `f32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:20:13 + --> tests/ui/cast_lossless_float.rs:26:13 | LL | let _ = x2 as f32; | ^^^^^^^^^ @@ -92,7 +92,7 @@ LL + let _ = f32::from(x2); | error: casts from `i16` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:21:13 + --> tests/ui/cast_lossless_float.rs:28:13 | LL | let _ = x2 as f64; | ^^^^^^^^^ @@ -105,7 +105,7 @@ LL + let _ = f64::from(x2); | error: casts from `u16` to `f32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:23:13 + --> tests/ui/cast_lossless_float.rs:31:13 | LL | let _ = x3 as f32; | ^^^^^^^^^ @@ -118,7 +118,7 @@ LL + let _ = f32::from(x3); | error: casts from `u16` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:24:13 + --> tests/ui/cast_lossless_float.rs:33:13 | LL | let _ = x3 as f64; | ^^^^^^^^^ @@ -131,7 +131,7 @@ LL + let _ = f64::from(x3); | error: casts from `i32` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:26:13 + --> tests/ui/cast_lossless_float.rs:36:13 | LL | let _ = x4 as f64; | ^^^^^^^^^ @@ -144,7 +144,7 @@ LL + let _ = f64::from(x4); | error: casts from `u32` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:28:13 + --> tests/ui/cast_lossless_float.rs:39:13 | LL | let _ = x5 as f64; | ^^^^^^^^^ @@ -157,7 +157,7 @@ LL + let _ = f64::from(x5); | error: casts from `f32` to `f64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_float.rs:31:13 + --> tests/ui/cast_lossless_float.rs:43:13 | LL | let _ = 1.0f32 as f64; | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed index cdb0656783688..2af2dbd1282df 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed +++ b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed @@ -7,66 +7,88 @@ fn main() { // Test clippy::cast_lossless with casts to integer types u16::from(0u8); //~^ cast_lossless + i16::from(0u8); //~^ cast_lossless + u32::from(0u8); //~^ cast_lossless + i32::from(0u8); //~^ cast_lossless + u64::from(0u8); //~^ cast_lossless + i64::from(0u8); //~^ cast_lossless + u128::from(0u8); //~^ cast_lossless + i128::from(0u8); //~^ cast_lossless u32::from(0u16); //~^ cast_lossless + i32::from(0u16); //~^ cast_lossless + u64::from(0u16); //~^ cast_lossless + i64::from(0u16); //~^ cast_lossless + u128::from(0u16); //~^ cast_lossless + i128::from(0u16); //~^ cast_lossless u64::from(0u32); //~^ cast_lossless + i64::from(0u32); //~^ cast_lossless + u128::from(0u32); //~^ cast_lossless + i128::from(0u32); //~^ cast_lossless u128::from(0u64); //~^ cast_lossless + i128::from(0u64); //~^ cast_lossless i16::from(0i8); //~^ cast_lossless + i32::from(0i8); //~^ cast_lossless + i64::from(0i8); //~^ cast_lossless + i128::from(0i8); //~^ cast_lossless i32::from(0i16); //~^ cast_lossless + i64::from(0i16); //~^ cast_lossless + i128::from(0i16); //~^ cast_lossless i64::from(0i32); //~^ cast_lossless + i128::from(0i32); //~^ cast_lossless @@ -82,10 +104,13 @@ fn main() { let _: u16 = 0u8.into(); //~^ cast_lossless + let _: i16 = (-1i8).into(); //~^ cast_lossless + let _: u16 = (1u8 + 2).into(); //~^ cast_lossless + let _: u32 = (1i8 as u16).into(); //~^ cast_lossless } @@ -123,6 +148,7 @@ fn issue11458() { let x = 10_u128; let _ = i32::from(sign_cast!(x, u8, i8)); //~^ cast_lossless + let _ = i32::from(sign_cast!(x, u8, i8) + 1); //~^ cast_lossless } @@ -146,6 +172,7 @@ fn ty_from_macro() { } let _ = ::from(0u8); + //~^ cast_lossless } const IN_CONST: u64 = 0u8 as u64; diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.rs b/src/tools/clippy/tests/ui/cast_lossless_integer.rs index 1f510b1a30363..c65b725bb7298 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_integer.rs +++ b/src/tools/clippy/tests/ui/cast_lossless_integer.rs @@ -7,66 +7,88 @@ fn main() { // Test clippy::cast_lossless with casts to integer types 0u8 as u16; //~^ cast_lossless + 0u8 as i16; //~^ cast_lossless + 0u8 as u32; //~^ cast_lossless + 0u8 as i32; //~^ cast_lossless + 0u8 as u64; //~^ cast_lossless + 0u8 as i64; //~^ cast_lossless + 0u8 as u128; //~^ cast_lossless + 0u8 as i128; //~^ cast_lossless 0u16 as u32; //~^ cast_lossless + 0u16 as i32; //~^ cast_lossless + 0u16 as u64; //~^ cast_lossless + 0u16 as i64; //~^ cast_lossless + 0u16 as u128; //~^ cast_lossless + 0u16 as i128; //~^ cast_lossless 0u32 as u64; //~^ cast_lossless + 0u32 as i64; //~^ cast_lossless + 0u32 as u128; //~^ cast_lossless + 0u32 as i128; //~^ cast_lossless 0u64 as u128; //~^ cast_lossless + 0u64 as i128; //~^ cast_lossless 0i8 as i16; //~^ cast_lossless + 0i8 as i32; //~^ cast_lossless + 0i8 as i64; //~^ cast_lossless + 0i8 as i128; //~^ cast_lossless 0i16 as i32; //~^ cast_lossless + 0i16 as i64; //~^ cast_lossless + 0i16 as i128; //~^ cast_lossless 0i32 as i64; //~^ cast_lossless + 0i32 as i128; //~^ cast_lossless @@ -82,10 +104,13 @@ fn main() { let _: u16 = 0u8 as _; //~^ cast_lossless + let _: i16 = -1i8 as _; //~^ cast_lossless + let _: u16 = (1u8 + 2) as _; //~^ cast_lossless + let _: u32 = 1i8 as u16 as _; //~^ cast_lossless } @@ -123,6 +148,7 @@ fn issue11458() { let x = 10_u128; let _ = sign_cast!(x, u8, i8) as i32; //~^ cast_lossless + let _ = (sign_cast!(x, u8, i8) + 1) as i32; //~^ cast_lossless } @@ -146,6 +172,7 @@ fn ty_from_macro() { } let _ = 0u8 as ty!(); + //~^ cast_lossless } const IN_CONST: u64 = 0u8 as u64; diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.stderr b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr index d2580913bb549..9852eca712793 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_integer.stderr +++ b/src/tools/clippy/tests/ui/cast_lossless_integer.stderr @@ -14,7 +14,7 @@ LL + u16::from(0u8); | error: casts from `u8` to `i16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:10:5 + --> tests/ui/cast_lossless_integer.rs:11:5 | LL | 0u8 as i16; | ^^^^^^^^^^ @@ -27,7 +27,7 @@ LL + i16::from(0u8); | error: casts from `u8` to `u32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:12:5 + --> tests/ui/cast_lossless_integer.rs:14:5 | LL | 0u8 as u32; | ^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + u32::from(0u8); | error: casts from `u8` to `i32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:14:5 + --> tests/ui/cast_lossless_integer.rs:17:5 | LL | 0u8 as i32; | ^^^^^^^^^^ @@ -53,7 +53,7 @@ LL + i32::from(0u8); | error: casts from `u8` to `u64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:16:5 + --> tests/ui/cast_lossless_integer.rs:20:5 | LL | 0u8 as u64; | ^^^^^^^^^^ @@ -66,7 +66,7 @@ LL + u64::from(0u8); | error: casts from `u8` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:18:5 + --> tests/ui/cast_lossless_integer.rs:23:5 | LL | 0u8 as i64; | ^^^^^^^^^^ @@ -79,7 +79,7 @@ LL + i64::from(0u8); | error: casts from `u8` to `u128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:20:5 + --> tests/ui/cast_lossless_integer.rs:26:5 | LL | 0u8 as u128; | ^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL + u128::from(0u8); | error: casts from `u8` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:22:5 + --> tests/ui/cast_lossless_integer.rs:29:5 | LL | 0u8 as i128; | ^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL + i128::from(0u8); | error: casts from `u16` to `u32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:25:5 + --> tests/ui/cast_lossless_integer.rs:32:5 | LL | 0u16 as u32; | ^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL + u32::from(0u16); | error: casts from `u16` to `i32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:27:5 + --> tests/ui/cast_lossless_integer.rs:35:5 | LL | 0u16 as i32; | ^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL + i32::from(0u16); | error: casts from `u16` to `u64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:29:5 + --> tests/ui/cast_lossless_integer.rs:38:5 | LL | 0u16 as u64; | ^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL + u64::from(0u16); | error: casts from `u16` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:31:5 + --> tests/ui/cast_lossless_integer.rs:41:5 | LL | 0u16 as i64; | ^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + i64::from(0u16); | error: casts from `u16` to `u128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:33:5 + --> tests/ui/cast_lossless_integer.rs:44:5 | LL | 0u16 as u128; | ^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL + u128::from(0u16); | error: casts from `u16` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:35:5 + --> tests/ui/cast_lossless_integer.rs:47:5 | LL | 0u16 as i128; | ^^^^^^^^^^^^ @@ -183,7 +183,7 @@ LL + i128::from(0u16); | error: casts from `u32` to `u64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:38:5 + --> tests/ui/cast_lossless_integer.rs:50:5 | LL | 0u32 as u64; | ^^^^^^^^^^^ @@ -196,7 +196,7 @@ LL + u64::from(0u32); | error: casts from `u32` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:40:5 + --> tests/ui/cast_lossless_integer.rs:53:5 | LL | 0u32 as i64; | ^^^^^^^^^^^ @@ -209,7 +209,7 @@ LL + i64::from(0u32); | error: casts from `u32` to `u128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:42:5 + --> tests/ui/cast_lossless_integer.rs:56:5 | LL | 0u32 as u128; | ^^^^^^^^^^^^ @@ -222,7 +222,7 @@ LL + u128::from(0u32); | error: casts from `u32` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:44:5 + --> tests/ui/cast_lossless_integer.rs:59:5 | LL | 0u32 as i128; | ^^^^^^^^^^^^ @@ -235,7 +235,7 @@ LL + i128::from(0u32); | error: casts from `u64` to `u128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:47:5 + --> tests/ui/cast_lossless_integer.rs:62:5 | LL | 0u64 as u128; | ^^^^^^^^^^^^ @@ -248,7 +248,7 @@ LL + u128::from(0u64); | error: casts from `u64` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:49:5 + --> tests/ui/cast_lossless_integer.rs:65:5 | LL | 0u64 as i128; | ^^^^^^^^^^^^ @@ -261,7 +261,7 @@ LL + i128::from(0u64); | error: casts from `i8` to `i16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:52:5 + --> tests/ui/cast_lossless_integer.rs:68:5 | LL | 0i8 as i16; | ^^^^^^^^^^ @@ -274,7 +274,7 @@ LL + i16::from(0i8); | error: casts from `i8` to `i32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:54:5 + --> tests/ui/cast_lossless_integer.rs:71:5 | LL | 0i8 as i32; | ^^^^^^^^^^ @@ -287,7 +287,7 @@ LL + i32::from(0i8); | error: casts from `i8` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:56:5 + --> tests/ui/cast_lossless_integer.rs:74:5 | LL | 0i8 as i64; | ^^^^^^^^^^ @@ -300,7 +300,7 @@ LL + i64::from(0i8); | error: casts from `i8` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:58:5 + --> tests/ui/cast_lossless_integer.rs:77:5 | LL | 0i8 as i128; | ^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + i128::from(0i8); | error: casts from `i16` to `i32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:61:5 + --> tests/ui/cast_lossless_integer.rs:80:5 | LL | 0i16 as i32; | ^^^^^^^^^^^ @@ -326,7 +326,7 @@ LL + i32::from(0i16); | error: casts from `i16` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:63:5 + --> tests/ui/cast_lossless_integer.rs:83:5 | LL | 0i16 as i64; | ^^^^^^^^^^^ @@ -339,7 +339,7 @@ LL + i64::from(0i16); | error: casts from `i16` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:65:5 + --> tests/ui/cast_lossless_integer.rs:86:5 | LL | 0i16 as i128; | ^^^^^^^^^^^^ @@ -352,7 +352,7 @@ LL + i128::from(0i16); | error: casts from `i32` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:68:5 + --> tests/ui/cast_lossless_integer.rs:89:5 | LL | 0i32 as i64; | ^^^^^^^^^^^ @@ -365,7 +365,7 @@ LL + i64::from(0i32); | error: casts from `i32` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:70:5 + --> tests/ui/cast_lossless_integer.rs:92:5 | LL | 0i32 as i128; | ^^^^^^^^^^^^ @@ -378,7 +378,7 @@ LL + i128::from(0i32); | error: casts from `i64` to `i128` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:73:5 + --> tests/ui/cast_lossless_integer.rs:95:5 | LL | 0i64 as i128; | ^^^^^^^^^^^^ @@ -391,7 +391,7 @@ LL + i128::from(0i64); | error: casts from `u8` to `u16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:77:13 + --> tests/ui/cast_lossless_integer.rs:99:13 | LL | let _ = (1u8 + 1u8) as u16; | ^^^^^^^^^^^^^^^^^^ @@ -404,7 +404,7 @@ LL + let _ = u16::from(1u8 + 1u8); | error: casts from `i8` to `i64` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:80:13 + --> tests/ui/cast_lossless_integer.rs:102:13 | LL | let _ = 1i8 as I64Alias; | ^^^^^^^^^^^^^^^ @@ -417,7 +417,7 @@ LL + let _ = I64Alias::from(1i8); | error: casts from `u8` to `u16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:83:18 + --> tests/ui/cast_lossless_integer.rs:105:18 | LL | let _: u16 = 0u8 as _; | ^^^^^^^^ @@ -430,7 +430,7 @@ LL + let _: u16 = 0u8.into(); | error: casts from `i8` to `i16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:85:18 + --> tests/ui/cast_lossless_integer.rs:108:18 | LL | let _: i16 = -1i8 as _; | ^^^^^^^^^ @@ -443,7 +443,7 @@ LL + let _: i16 = (-1i8).into(); | error: casts from `u8` to `u16` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:87:18 + --> tests/ui/cast_lossless_integer.rs:111:18 | LL | let _: u16 = (1u8 + 2) as _; | ^^^^^^^^^^^^^^ @@ -456,7 +456,7 @@ LL + let _: u16 = (1u8 + 2).into(); | error: casts from `u16` to `u32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:89:18 + --> tests/ui/cast_lossless_integer.rs:114:18 | LL | let _: u32 = 1i8 as u16 as _; | ^^^^^^^^^^^^^^^ @@ -469,7 +469,7 @@ LL + let _: u32 = (1i8 as u16).into(); | error: casts from `i8` to `i32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:124:13 + --> tests/ui/cast_lossless_integer.rs:149:13 | LL | let _ = sign_cast!(x, u8, i8) as i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -482,7 +482,7 @@ LL + let _ = i32::from(sign_cast!(x, u8, i8)); | error: casts from `i8` to `i32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:126:13 + --> tests/ui/cast_lossless_integer.rs:152:13 | LL | let _ = (sign_cast!(x, u8, i8) + 1) as i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -495,7 +495,7 @@ LL + let _ = i32::from(sign_cast!(x, u8, i8) + 1); | error: casts from `u8` to `u32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:133:13 + --> tests/ui/cast_lossless_integer.rs:159:13 | LL | 1u8 as u32 | ^^^^^^^^^^ @@ -512,7 +512,7 @@ LL + u32::from(1u8) | error: casts from `u8` to `u32` can be expressed infallibly using `From` - --> tests/ui/cast_lossless_integer.rs:148:13 + --> tests/ui/cast_lossless_integer.rs:174:13 | LL | let _ = 0u8 as ty!(); | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.rs b/src/tools/clippy/tests/ui/cast_nan_to_int.rs index aee38da9a159c..72e61b3542e20 100644 --- a/src/tools/clippy/tests/ui/cast_nan_to_int.rs +++ b/src/tools/clippy/tests/ui/cast_nan_to_int.rs @@ -5,24 +5,22 @@ fn main() { let _ = (0.0_f32 / -0.0) as usize; - //~^ ERROR: casting a known NaN to usize - //~| NOTE: this always evaluates to 0 + //~^ cast_nan_to_int + let _ = (f64::INFINITY * -0.0) as usize; - //~^ ERROR: casting a known NaN to usize - //~| NOTE: this always evaluates to 0 + //~^ cast_nan_to_int + let _ = (0.0 * f32::INFINITY) as usize; - //~^ ERROR: casting a known NaN to usize - //~| NOTE: this always evaluates to 0 + //~^ cast_nan_to_int let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize; - //~^ ERROR: casting a known NaN to usize - //~| NOTE: this always evaluates to 0 + //~^ cast_nan_to_int + let _ = (f32::INFINITY - f32::INFINITY) as usize; - //~^ ERROR: casting a known NaN to usize - //~| NOTE: this always evaluates to 0 + //~^ cast_nan_to_int + let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize; - //~^ ERROR: casting a known NaN to usize - //~| NOTE: this always evaluates to 0 + //~^ cast_nan_to_int // those won't be linted: let _ = (1.0_f32 / 0.0) as usize; diff --git a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr index 3aeb2d5452514..15ca3876ea18f 100644 --- a/src/tools/clippy/tests/ui/cast_nan_to_int.stderr +++ b/src/tools/clippy/tests/ui/cast_nan_to_int.stderr @@ -25,7 +25,7 @@ LL | let _ = (0.0 * f32::INFINITY) as usize; = note: this always evaluates to 0 error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:17:13 + --> tests/ui/cast_nan_to_int.rs:16:13 | LL | let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = (f64::INFINITY + f64::NEG_INFINITY) as usize; = note: this always evaluates to 0 error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:20:13 + --> tests/ui/cast_nan_to_int.rs:19:13 | LL | let _ = (f32::INFINITY - f32::INFINITY) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = (f32::INFINITY - f32::INFINITY) as usize; = note: this always evaluates to 0 error: casting a known NaN to usize - --> tests/ui/cast_nan_to_int.rs:23:13 + --> tests/ui/cast_nan_to_int.rs:22:13 | LL | let _ = (f32::INFINITY / f32::NEG_INFINITY) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed index e78bd66c3cb55..bddcb0ebf64e6 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed @@ -6,18 +6,25 @@ fn main() { let ptr: *const u8 = vec.as_ptr(); let mptr = vec.as_mut_ptr(); let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts { use core::slice; let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts use slice as one; let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts } { use std::slice; let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts use slice as one; let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); + //~^ cast_slice_from_raw_parts } } diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs index c3d8c7bee9893..0a1eb276d5e9e 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs @@ -6,18 +6,25 @@ fn main() { let ptr: *const u8 = vec.as_ptr(); let mptr = vec.as_mut_ptr(); let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] }; + //~^ cast_slice_from_raw_parts let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; + //~^ cast_slice_from_raw_parts let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts { use core::slice; let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts use slice as one; let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts } { use std::slice; let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts use slice as one; let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; + //~^ cast_slice_from_raw_parts } } diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr index 2aedd320a4289..60794a988db7d 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.stderr @@ -8,37 +8,37 @@ LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *co = help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]` error: casting the result of `from_raw_parts_mut` to *mut [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:9:35 + --> tests/ui/cast_raw_slice_pointer_cast.rs:10:35 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:10:26 + --> tests/ui/cast_raw_slice_pointer_cast.rs:12:26 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:13:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:16:30 | LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:15:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:19:30 | LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:19:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:24:30 | LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:21:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:27:30 | LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` diff --git a/src/tools/clippy/tests/ui/cast_size.32bit.stderr b/src/tools/clippy/tests/ui/cast_size.32bit.stderr index 8ff3464676c3f..cb1620e36a267 100644 --- a/src/tools/clippy/tests/ui/cast_size.32bit.stderr +++ b/src/tools/clippy/tests/ui/cast_size.32bit.stderr @@ -1,5 +1,5 @@ error: casting `isize` to `i8` may truncate the value - --> tests/ui/cast_size.rs:15:5 + --> tests/ui/cast_size.rs:17:5 | LL | 1isize as i8; | ^^^^^^^^^^^^ @@ -9,11 +9,12 @@ LL | 1isize as i8; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_truncation)]` help: ... or use `try_from` and handle the error accordingly | -LL | i8::try_from(1isize); - | ~~~~~~~~~~~~~~~~~~~~ +LL - 1isize as i8; +LL + i8::try_from(1isize); + | error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:21:5 + --> tests/ui/cast_size.rs:24:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -22,25 +23,25 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:22:5 + --> tests/ui/cast_size.rs:26:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:23:5 + --> tests/ui/cast_size.rs:28:5 | LL | x0 as f64; | ^^^^^^^^^ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:24:5 + --> tests/ui/cast_size.rs:30:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:35:5 | LL | 1isize as i32; | ^^^^^^^^^^^^^ @@ -48,11 +49,12 @@ LL | 1isize as i32; = 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 | i32::try_from(1isize); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1isize as i32; +LL + i32::try_from(1isize); + | error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:29:5 + --> tests/ui/cast_size.rs:37:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ @@ -60,11 +62,12 @@ LL | 1isize as u32; = 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 | u32::try_from(1isize); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1isize as u32; +LL + u32::try_from(1isize); + | error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:30:5 + --> tests/ui/cast_size.rs:39:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ @@ -72,11 +75,12 @@ LL | 1usize as u32; = 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 | u32::try_from(1usize); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1usize as u32; +LL + u32::try_from(1usize); + | error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:31:5 + --> tests/ui/cast_size.rs:41:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -84,11 +88,12 @@ LL | 1usize as i32; = 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 | i32::try_from(1usize); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1usize as i32; +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_size.rs:31:5 + --> tests/ui/cast_size.rs:41:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -97,7 +102,7 @@ LL | 1usize as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:32:5 + --> tests/ui/cast_size.rs:44:5 | LL | 1i64 as isize; | ^^^^^^^^^^^^^ @@ -105,11 +110,12 @@ LL | 1i64 as isize; = 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 | isize::try_from(1i64); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1i64 as isize; +LL + isize::try_from(1i64); + | error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:33:5 + --> tests/ui/cast_size.rs:46:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ @@ -117,11 +123,12 @@ LL | 1i64 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(1i64); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1i64 as usize; +LL + usize::try_from(1i64); + | error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:34:5 + --> tests/ui/cast_size.rs:48:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -129,17 +136,18 @@ LL | 1u64 as isize; = 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 | isize::try_from(1u64); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1u64 as isize; +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_size.rs:34:5 + --> tests/ui/cast_size.rs:48:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:35:5 + --> tests/ui/cast_size.rs:51:5 | LL | 1u64 as usize; | ^^^^^^^^^^^^^ @@ -147,29 +155,30 @@ LL | 1u64 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(1u64); - | ~~~~~~~~~~~~~~~~~~~~~ +LL - 1u64 as usize; +LL + usize::try_from(1u64); + | error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:36:5 + --> tests/ui/cast_size.rs:53:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ 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_size.rs:43:5 + --> tests/ui/cast_size.rs:61:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:44:5 + --> tests/ui/cast_size.rs:63:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: literal out of range for `usize` - --> tests/ui/cast_size.rs:44:5 + --> tests/ui/cast_size.rs:63:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_size.64bit.stderr b/src/tools/clippy/tests/ui/cast_size.64bit.stderr index 6b9919f8a1055..b6000a52abb34 100644 --- a/src/tools/clippy/tests/ui/cast_size.64bit.stderr +++ b/src/tools/clippy/tests/ui/cast_size.64bit.stderr @@ -1,5 +1,5 @@ error: casting `isize` to `i8` may truncate the value - --> tests/ui/cast_size.rs:15:5 + --> tests/ui/cast_size.rs:17:5 | LL | 1isize as i8; | ^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL + i8::try_from(1isize); | error: casting `isize` to `f32` causes a loss of precision (`isize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:21:5 + --> tests/ui/cast_size.rs:24:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -23,25 +23,25 @@ LL | x0 as f32; = help: to override `-D warnings` add `#[allow(clippy::cast_precision_loss)]` error: casting `usize` to `f32` causes a loss of precision (`usize` is 32 or 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> tests/ui/cast_size.rs:22:5 + --> tests/ui/cast_size.rs:26:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:23:5 + --> tests/ui/cast_size.rs:28:5 | LL | x0 as f64; | ^^^^^^^^^ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:24:5 + --> tests/ui/cast_size.rs:30:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:28:5 + --> tests/ui/cast_size.rs:35:5 | LL | 1isize as i32; | ^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL + i32::try_from(1isize); | error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:29:5 + --> tests/ui/cast_size.rs:37:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL + u32::try_from(1isize); | error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:30:5 + --> tests/ui/cast_size.rs:39:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL + u32::try_from(1usize); | error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers - --> tests/ui/cast_size.rs:31:5 + --> tests/ui/cast_size.rs:41:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ 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_size.rs:31:5 + --> tests/ui/cast_size.rs:41:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ @@ -102,7 +102,7 @@ LL | 1usize as i32; = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` error: casting `i64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:32:5 + --> tests/ui/cast_size.rs:44:5 | LL | 1i64 as isize; | ^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL + isize::try_from(1i64); | error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:33:5 + --> tests/ui/cast_size.rs:46:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ @@ -128,7 +128,7 @@ LL + usize::try_from(1i64); | error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:34:5 + --> tests/ui/cast_size.rs:48:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ @@ -141,13 +141,13 @@ 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_size.rs:34:5 + --> tests/ui/cast_size.rs:48:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:35:5 + --> tests/ui/cast_size.rs:51:5 | LL | 1u64 as usize; | ^^^^^^^^^^^^^ @@ -160,19 +160,19 @@ LL + usize::try_from(1u64); | error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers - --> tests/ui/cast_size.rs:36:5 + --> tests/ui/cast_size.rs:53:5 | LL | 1u32 as isize; | ^^^^^^^^^^^^^ 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_size.rs:43:5 + --> tests/ui/cast_size.rs:61:5 | LL | 999_999_999 as f32; | ^^^^^^^^^^^^^^^^^^ error: casting `usize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`usize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> tests/ui/cast_size.rs:44:5 + --> tests/ui/cast_size.rs:63:5 | LL | 9_999_999_999_999_999usize as f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs index d0ed8e57d7ae5..e924018088674 100644 --- a/src/tools/clippy/tests/ui/cast_size.rs +++ b/src/tools/clippy/tests/ui/cast_size.rs @@ -1,4 +1,6 @@ -//@stderr-per-bitwidth +//@revisions: 32bit 64bit +//@[32bit]ignore-bitwidth: 64 +//@[64bit]ignore-bitwidth: 32 //@no-rustfix #![warn( @@ -13,27 +15,43 @@ fn main() { // Casting from *size 1isize as i8; + //~^ cast_possible_truncation let x0 = 1isize; let x1 = 1usize; // FIXME(f16_f128): enable f16 and f128 conversions once const eval supports them // x0 as f16; // x1 as f16; x0 as f32; + //~^ cast_precision_loss x1 as f32; + //~^ cast_precision_loss x0 as f64; + //~^ cast_precision_loss x1 as f64; + //~^ cast_precision_loss // x0 as f128; // x1 as f128; 1isize as i32; + //~^ cast_possible_truncation 1isize as u32; + //~^ cast_possible_truncation 1usize as u32; + //~^ cast_possible_truncation 1usize as i32; + //~^ cast_possible_truncation + //~| cast_possible_wrap 1i64 as isize; + //~^ cast_possible_truncation 1i64 as usize; + //~^ cast_possible_truncation 1u64 as isize; + //~^ cast_possible_truncation + //~| cast_possible_wrap 1u64 as usize; + //~^ cast_possible_truncation 1u32 as isize; + //~^ cast_possible_wrap 1u32 as usize; // Should not trigger any lint 1i32 as isize; // Neither should this 1i32 as usize; @@ -41,6 +59,9 @@ fn main() { // Big integer literal to float // 999_999 as f16; 999_999_999 as f32; + //~^ cast_precision_loss 9_999_999_999_999_999usize as f64; + //~^ cast_precision_loss + //~[32bit]^^ ERROR: literal out of range for `usize` // 999_999_999_999_999_999_999_999_999_999u128 as f128; } diff --git a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs index d8101030a8a2d..518ed77ab2200 100644 --- a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs +++ b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs @@ -8,14 +8,14 @@ fn main() { // Because it's separate, it does not check the cast back to something of the same size let a = r_x as *const [i32]; let b = a as *const [u8]; - //~^ ERROR: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (eleme - //~| NOTE: `#[deny(clippy::cast_slice_different_sizes)]` on by default + //~^ cast_slice_different_sizes + let c = b as *const [u32]; - //~^ ERROR: casting between raw pointers to `[u8]` (element size 1) and `[u32]` (eleme + //~^ cast_slice_different_sizes // loses data let loss = r_x as *const [i32] as *const [u8]; - //~^ ERROR: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (eleme + //~^ cast_slice_different_sizes // Cast back to same size but different type loses no data, just type conversion // This is weird code but there's no reason for this lint specifically to fire *twice* on it @@ -23,9 +23,11 @@ fn main() { // Check casting through blocks is detected let loss_block_1 = { r_x as *const [i32] } as *const [u8]; - //~^ ERROR: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (eleme + //~^ cast_slice_different_sizes + let loss_block_2 = { - //~^ ERROR: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (eleme + //~^ cast_slice_different_sizes + let _ = (); r_x as *const [i32] } as *const [u8]; @@ -43,7 +45,8 @@ fn main() { // Check that the result of a long chain of casts is detected let long_chain_loss = r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8]; - //~^ ERROR: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (eleme + //~^ cast_slice_different_sizes + let long_chain_restore = r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8] as *const [u32]; } @@ -59,40 +62,47 @@ fn foo2(x: *mut [u8]) -> *mut [u8] { // Test that casts as part of function returns work fn bar(x: *mut [u16]) -> *mut [u8] { - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element s + //~^ cast_slice_different_sizes + x as *mut [u8] } fn uwu(x: *mut [u16]) -> *mut [u8] { - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element s + //~^ cast_slice_different_sizes + x as *mut _ } fn bar2(x: *mut [u16]) -> *mut [u8] { - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element s + //~^ cast_slice_different_sizes + x as _ } // constify fn bar3(x: *mut [u16]) -> *const [u8] { - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element s + //~^ cast_slice_different_sizes + x as _ } // unconstify fn bar4(x: *const [u16]) -> *mut [u8] { - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element s + //~^ cast_slice_different_sizes + x as _ } // function returns plus blocks fn blocks(x: *mut [u16]) -> *mut [u8] { - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element s + //~^ cast_slice_different_sizes + ({ x }) as _ } fn more_blocks(x: *mut [u16]) -> *mut [u8] { - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element s + //~^ cast_slice_different_sizes + { ({ x }) as _ } - //~^ ERROR: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (eleme + //~^ cast_slice_different_sizes } diff --git a/src/tools/clippy/tests/ui/cast_slice_different_sizes.stderr b/src/tools/clippy/tests/ui/cast_slice_different_sizes.stderr index 625de4a8359ba..307d37ac2ea8a 100644 --- a/src/tools/clippy/tests/ui/cast_slice_different_sizes.stderr +++ b/src/tools/clippy/tests/ui/cast_slice_different_sizes.stderr @@ -25,11 +25,12 @@ LL | let loss_block_1 = { r_x as *const [i32] } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts({ r_x as *const [i32] } as *const u8, ..)` error: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:27:24 + --> tests/ui/cast_slice_different_sizes.rs:28:24 | LL | let loss_block_2 = { | ________________________^ LL | | +LL | | LL | | let _ = (); LL | | r_x as *const [i32] LL | | } as *const [u8]; @@ -39,90 +40,98 @@ help: replace with `ptr::slice_from_raw_parts` | LL ~ let loss_block_2 = core::ptr::slice_from_raw_parts({ LL + +LL + LL + let _ = (); LL + r_x as *const [i32] LL ~ } as *const u8, ..); | error: casting between raw pointers to `[i32]` (element size 4) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:45:27 + --> tests/ui/cast_slice_different_sizes.rs:47:27 | LL | let long_chain_loss = r_x as *const [i32] as *const [u32] as *const [u16] as *const [i8] as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(r_x as *const [i32] as *const u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:61:36 + --> tests/ui/cast_slice_different_sizes.rs:64:36 | LL | fn bar(x: *mut [u16]) -> *mut [u8] { | ____________________________________^ LL | | +LL | | LL | | x as *mut [u8] LL | | } | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:66:36 + --> tests/ui/cast_slice_different_sizes.rs:70:36 | LL | fn uwu(x: *mut [u16]) -> *mut [u8] { | ____________________________________^ LL | | +LL | | LL | | x as *mut _ LL | | } | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:71:37 + --> tests/ui/cast_slice_different_sizes.rs:76:37 | LL | fn bar2(x: *mut [u16]) -> *mut [u8] { | _____________________________________^ LL | | +LL | | LL | | x as _ LL | | } | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:77:39 + --> tests/ui/cast_slice_different_sizes.rs:83:39 | LL | fn bar3(x: *mut [u16]) -> *const [u8] { | _______________________________________^ LL | | +LL | | LL | | x as _ LL | | } | |_^ help: replace with `ptr::slice_from_raw_parts`: `core::ptr::slice_from_raw_parts(x as *const u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:83:39 + --> tests/ui/cast_slice_different_sizes.rs:90:39 | LL | fn bar4(x: *const [u16]) -> *mut [u8] { | _______________________________________^ LL | | +LL | | LL | | x as _ LL | | } | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(x as *mut u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:89:39 + --> tests/ui/cast_slice_different_sizes.rs:97:39 | LL | fn blocks(x: *mut [u16]) -> *mut [u8] { | _______________________________________^ LL | | +LL | | LL | | ({ x }) as _ LL | | } | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:94:44 + --> tests/ui/cast_slice_different_sizes.rs:103:44 | LL | fn more_blocks(x: *mut [u16]) -> *mut [u8] { | ____________________________________________^ LL | | +LL | | LL | | { ({ x }) as _ } LL | | LL | | } | |_^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)` error: casting between raw pointers to `[u16]` (element size 2) and `[u8]` (element size 1) does not adjust the count - --> tests/ui/cast_slice_different_sizes.rs:96:5 + --> tests/ui/cast_slice_different_sizes.rs:106:5 | LL | { ({ x }) as _ } | ^^^^^^^^^^^^^^^^ help: replace with `ptr::slice_from_raw_parts_mut`: `core::ptr::slice_from_raw_parts_mut(({ x }) as *mut u8, ..)` diff --git a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.fixed b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.fixed index 89815ffe9cbc1..f55920db55034 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.fixed +++ b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.fixed @@ -1,13 +1,20 @@ #![warn(clippy::deprecated_clippy_cfg_attr)] #![allow(clippy::non_minimal_cfg)] -#![cfg_attr(clippy, doc = "a")] //~ ERROR: `feature = "cargo-clippy"` was +#![cfg_attr(clippy, doc = "a")] +//~^ deprecated_clippy_cfg_attr -#[cfg_attr(clippy, derive(Debug))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg_attr(not(clippy), derive(Debug))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(clippy)] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(not(clippy))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(any(clippy))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(all(clippy))] //~ ERROR: `feature = "cargo-clippy"` was +#[cfg_attr(clippy, derive(Debug))] +//~^ deprecated_clippy_cfg_attr +#[cfg_attr(not(clippy), derive(Debug))] +//~^ deprecated_clippy_cfg_attr +#[cfg(clippy)] +//~^ deprecated_clippy_cfg_attr +#[cfg(not(clippy))] +//~^ deprecated_clippy_cfg_attr +#[cfg(any(clippy))] +//~^ deprecated_clippy_cfg_attr +#[cfg(all(clippy))] +//~^ deprecated_clippy_cfg_attr pub struct Bar; fn main() {} diff --git a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.rs b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.rs index 745f8957641ed..faf36d98f2b3f 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.rs +++ b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.rs @@ -1,13 +1,20 @@ #![warn(clippy::deprecated_clippy_cfg_attr)] #![allow(clippy::non_minimal_cfg)] -#![cfg_attr(feature = "cargo-clippy", doc = "a")] //~ ERROR: `feature = "cargo-clippy"` was +#![cfg_attr(feature = "cargo-clippy", doc = "a")] +//~^ deprecated_clippy_cfg_attr -#[cfg_attr(feature = "cargo-clippy", derive(Debug))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg_attr(not(feature = "cargo-clippy"), derive(Debug))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(feature = "cargo-clippy")] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(not(feature = "cargo-clippy"))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(any(feature = "cargo-clippy"))] //~ ERROR: `feature = "cargo-clippy"` was -#[cfg(all(feature = "cargo-clippy"))] //~ ERROR: `feature = "cargo-clippy"` was +#[cfg_attr(feature = "cargo-clippy", derive(Debug))] +//~^ deprecated_clippy_cfg_attr +#[cfg_attr(not(feature = "cargo-clippy"), derive(Debug))] +//~^ deprecated_clippy_cfg_attr +#[cfg(feature = "cargo-clippy")] +//~^ deprecated_clippy_cfg_attr +#[cfg(not(feature = "cargo-clippy"))] +//~^ deprecated_clippy_cfg_attr +#[cfg(any(feature = "cargo-clippy"))] +//~^ deprecated_clippy_cfg_attr +#[cfg(all(feature = "cargo-clippy"))] +//~^ deprecated_clippy_cfg_attr pub struct Bar; fn main() {} diff --git a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr index 0a358f1a68475..4f5c39b78415c 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr +++ b/src/tools/clippy/tests/ui/cfg_attr_cargo_clippy.stderr @@ -8,37 +8,37 @@ LL | #![cfg_attr(feature = "cargo-clippy", doc = "a")] = help: to override `-D warnings` add `#[allow(clippy::deprecated_clippy_cfg_attr)]` error: `feature = "cargo-clippy"` was replaced by `clippy` - --> tests/ui/cfg_attr_cargo_clippy.rs:5:12 + --> tests/ui/cfg_attr_cargo_clippy.rs:6:12 | LL | #[cfg_attr(feature = "cargo-clippy", derive(Debug))] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy` error: `feature = "cargo-clippy"` was replaced by `clippy` - --> tests/ui/cfg_attr_cargo_clippy.rs:6:16 + --> tests/ui/cfg_attr_cargo_clippy.rs:8:16 | LL | #[cfg_attr(not(feature = "cargo-clippy"), derive(Debug))] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy` error: `feature = "cargo-clippy"` was replaced by `clippy` - --> tests/ui/cfg_attr_cargo_clippy.rs:7:7 + --> tests/ui/cfg_attr_cargo_clippy.rs:10:7 | LL | #[cfg(feature = "cargo-clippy")] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy` error: `feature = "cargo-clippy"` was replaced by `clippy` - --> tests/ui/cfg_attr_cargo_clippy.rs:8:11 + --> tests/ui/cfg_attr_cargo_clippy.rs:12:11 | LL | #[cfg(not(feature = "cargo-clippy"))] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy` error: `feature = "cargo-clippy"` was replaced by `clippy` - --> tests/ui/cfg_attr_cargo_clippy.rs:9:11 + --> tests/ui/cfg_attr_cargo_clippy.rs:14:11 | LL | #[cfg(any(feature = "cargo-clippy"))] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy` error: `feature = "cargo-clippy"` was replaced by `clippy` - --> tests/ui/cfg_attr_cargo_clippy.rs:10:11 + --> tests/ui/cfg_attr_cargo_clippy.rs:16:11 | LL | #[cfg(all(feature = "cargo-clippy"))] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `clippy` diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed index 05d5b3d10eaf8..401476a9c1fe3 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed @@ -16,10 +16,12 @@ fn foo( fn skip_on_statements() { #[rustfmt::skip] + //~^ deprecated_cfg_attr 5+3; } #[rustfmt::skip] +//~^ deprecated_cfg_attr fn main() { foo::f(); } @@ -39,5 +41,6 @@ fn msrv_1_29() { #[clippy::msrv = "1.30"] fn msrv_1_30() { #[rustfmt::skip] + //~^ deprecated_cfg_attr 1+30; } diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs index bc29e20210e8a..3cf368129fd82 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs @@ -16,10 +16,12 @@ fn foo( fn skip_on_statements() { #[cfg_attr(rustfmt, rustfmt::skip)] + //~^ deprecated_cfg_attr 5+3; } #[cfg_attr(rustfmt, rustfmt_skip)] +//~^ deprecated_cfg_attr fn main() { foo::f(); } @@ -39,5 +41,6 @@ fn msrv_1_29() { #[clippy::msrv = "1.30"] fn msrv_1_30() { #[cfg_attr(rustfmt, rustfmt::skip)] + //~^ deprecated_cfg_attr 1+30; } diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr index 24b6ed1b0458d..d7825f854be55 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.stderr @@ -8,13 +8,13 @@ LL | #[cfg_attr(rustfmt, rustfmt::skip)] = help: to override `-D warnings` add `#[allow(clippy::deprecated_cfg_attr)]` error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes - --> tests/ui/cfg_attr_rustfmt.rs:22:1 + --> tests/ui/cfg_attr_rustfmt.rs:23:1 | LL | #[cfg_attr(rustfmt, rustfmt_skip)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]` error: `cfg_attr` is deprecated for rustfmt and got replaced by tool attributes - --> tests/ui/cfg_attr_rustfmt.rs:41:5 + --> tests/ui/cfg_attr_rustfmt.rs:43:5 | LL | #[cfg_attr(rustfmt, rustfmt::skip)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `#[rustfmt::skip]` diff --git a/src/tools/clippy/tests/ui/cfg_not_test.rs b/src/tools/clippy/tests/ui/cfg_not_test.rs index da3e29d289662..d93e16f3b1855 100644 --- a/src/tools/clippy/tests/ui/cfg_not_test.rs +++ b/src/tools/clippy/tests/ui/cfg_not_test.rs @@ -6,10 +6,12 @@ fn important_check() {} fn main() { // Statement #[cfg(not(test))] + //~^ cfg_not_test let answer = 42; // Expression #[cfg(not(test))] + //~^ cfg_not_test important_check(); // Make sure only not(test) are checked, not other attributes @@ -22,10 +24,13 @@ struct CfgNotTest; // Deeply nested `not(test)` #[cfg(not(test))] +//~^ cfg_not_test fn foo() {} #[cfg(all(debug_assertions, not(test)))] +//~^ cfg_not_test fn bar() {} #[cfg(not(any(not(debug_assertions), test)))] +//~^ cfg_not_test fn baz() {} #[cfg(test)] diff --git a/src/tools/clippy/tests/ui/cfg_not_test.stderr b/src/tools/clippy/tests/ui/cfg_not_test.stderr index c1bf626887afb..e452ef2b5ab6e 100644 --- a/src/tools/clippy/tests/ui/cfg_not_test.stderr +++ b/src/tools/clippy/tests/ui/cfg_not_test.stderr @@ -10,7 +10,7 @@ LL | #[cfg(not(test))] = help: to override `-D warnings` add `#[allow(clippy::cfg_not_test)]` error: code is excluded from test builds - --> tests/ui/cfg_not_test.rs:12:5 + --> tests/ui/cfg_not_test.rs:13:5 | LL | #[cfg(not(test))] | ^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | #[cfg(not(test))] = help: consider not excluding any code from test builds error: code is excluded from test builds - --> tests/ui/cfg_not_test.rs:24:1 + --> tests/ui/cfg_not_test.rs:26:1 | LL | #[cfg(not(test))] | ^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | #[cfg(not(test))] = help: consider not excluding any code from test builds error: code is excluded from test builds - --> tests/ui/cfg_not_test.rs:26:1 + --> tests/ui/cfg_not_test.rs:29:1 | LL | #[cfg(all(debug_assertions, not(test)))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | #[cfg(all(debug_assertions, not(test)))] = help: consider not excluding any code from test builds error: code is excluded from test builds - --> tests/ui/cfg_not_test.rs:28:1 + --> tests/ui/cfg_not_test.rs:32:1 | LL | #[cfg(not(any(not(debug_assertions), test)))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.rs b/src/tools/clippy/tests/ui/char_lit_as_u8.rs index 7bb3daf0f1e72..c8774c7f30916 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8.rs +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.rs @@ -3,6 +3,5 @@ fn main() { // no suggestion, since a byte literal won't work. let _ = '❤' as u8; - //~^ ERROR: casting a character literal to `u8` truncates - //~| NOTE: `char` is four bytes wide, but `u8` is a single byte + //~^ char_lit_as_u8 } diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed index 6f13078a3ae95..64aacedfd36a0 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed @@ -2,7 +2,11 @@ fn main() { let _ = b'a'; + //~^ char_lit_as_u8 let _ = b'\n'; + //~^ char_lit_as_u8 let _ = b'\0'; + //~^ char_lit_as_u8 let _ = b'\x01'; + //~^ char_lit_as_u8 } diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs index 7737eb5135fbb..a8f39e27605e5 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs @@ -2,7 +2,11 @@ fn main() { let _ = 'a' as u8; + //~^ char_lit_as_u8 let _ = '\n' as u8; + //~^ char_lit_as_u8 let _ = '\0' as u8; + //~^ char_lit_as_u8 let _ = '\x01' as u8; + //~^ char_lit_as_u8 } diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr index 4826aca42e1c3..158dfd6bed265 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr @@ -9,7 +9,7 @@ LL | let _ = 'a' as u8; = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:5:13 + --> tests/ui/char_lit_as_u8_suggestions.rs:6:13 | LL | let _ = '\n' as u8; | ^^^^^^^^^^ help: use a byte literal instead: `b'\n'` @@ -17,7 +17,7 @@ LL | let _ = '\n' as u8; = note: `char` is four bytes wide, but `u8` is a single byte error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:6:13 + --> tests/ui/char_lit_as_u8_suggestions.rs:8:13 | LL | let _ = '\0' as u8; | ^^^^^^^^^^ help: use a byte literal instead: `b'\0'` @@ -25,7 +25,7 @@ LL | let _ = '\0' as u8; = note: `char` is four bytes wide, but `u8` is a single byte error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:7:13 + --> tests/ui/char_lit_as_u8_suggestions.rs:10:13 | LL | let _ = '\x01' as u8; | ^^^^^^^^^^^^ help: use a byte literal instead: `b'\x01'` diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed index 1e8da33161414..279a5b6e1ff8b 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.fixed +++ b/src/tools/clippy/tests/ui/checked_conversions.fixed @@ -13,46 +13,62 @@ pub fn i64_to_u32(value: i64) { let _ = u32::try_from(value).is_ok(); + //~^ checked_conversions let _ = u32::try_from(value).is_ok(); + //~^ checked_conversions } pub fn i64_to_u16(value: i64) { let _ = u16::try_from(value).is_ok(); + //~^ checked_conversions let _ = u16::try_from(value).is_ok(); + //~^ checked_conversions } pub fn isize_to_u8(value: isize) { let _ = u8::try_from(value).is_ok(); + //~^ checked_conversions let _ = u8::try_from(value).is_ok(); + //~^ checked_conversions } // Signed to signed pub fn i64_to_i32(value: i64) { let _ = i32::try_from(value).is_ok(); + //~^ checked_conversions let _ = i32::try_from(value).is_ok(); + //~^ checked_conversions } pub fn i64_to_i16(value: i64) { let _ = i16::try_from(value).is_ok(); + //~^ checked_conversions let _ = i16::try_from(value).is_ok(); + //~^ checked_conversions } // Unsigned to X pub fn u32_to_i32(value: u32) { let _ = i32::try_from(value).is_ok(); + //~^ checked_conversions let _ = i32::try_from(value).is_ok(); + //~^ checked_conversions } pub fn usize_to_isize(value: usize) { let _ = isize::try_from(value).is_ok() && value as i32 == 5; + //~^ checked_conversions let _ = isize::try_from(value).is_ok() && value as i32 == 5; + //~^ checked_conversions } pub fn u32_to_u16(value: u32) { let _ = u16::try_from(value).is_ok() && value as i32 == 5; + //~^ checked_conversions let _ = u16::try_from(value).is_ok() && value as i32 == 5; + //~^ checked_conversions } // Negative tests @@ -86,6 +102,7 @@ fn msrv_1_33() { fn msrv_1_34() { let value: i64 = 34; let _ = u32::try_from(value).is_ok(); + //~^ checked_conversions } fn main() {} diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs index 67a9adc049ead..c339bc674bbb5 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.rs +++ b/src/tools/clippy/tests/ui/checked_conversions.rs @@ -13,46 +13,62 @@ pub fn i64_to_u32(value: i64) { let _ = value <= (u32::max_value() as i64) && value >= 0; + //~^ checked_conversions let _ = value <= (u32::MAX as i64) && value >= 0; + //~^ checked_conversions } pub fn i64_to_u16(value: i64) { let _ = value <= i64::from(u16::max_value()) && value >= 0; + //~^ checked_conversions let _ = value <= i64::from(u16::MAX) && value >= 0; + //~^ checked_conversions } pub fn isize_to_u8(value: isize) { let _ = value <= (u8::max_value() as isize) && value >= 0; + //~^ checked_conversions let _ = value <= (u8::MAX as isize) && value >= 0; + //~^ checked_conversions } // Signed to signed pub fn i64_to_i32(value: i64) { let _ = value <= (i32::max_value() as i64) && value >= (i32::min_value() as i64); + //~^ checked_conversions let _ = value <= (i32::MAX as i64) && value >= (i32::MIN as i64); + //~^ checked_conversions } pub fn i64_to_i16(value: i64) { let _ = value <= i64::from(i16::max_value()) && value >= i64::from(i16::min_value()); + //~^ checked_conversions let _ = value <= i64::from(i16::MAX) && value >= i64::from(i16::MIN); + //~^ checked_conversions } // Unsigned to X pub fn u32_to_i32(value: u32) { let _ = value <= i32::max_value() as u32; + //~^ checked_conversions let _ = value <= i32::MAX as u32; + //~^ checked_conversions } pub fn usize_to_isize(value: usize) { let _ = value <= isize::max_value() as usize && value as i32 == 5; + //~^ checked_conversions let _ = value <= isize::MAX as usize && value as i32 == 5; + //~^ checked_conversions } pub fn u32_to_u16(value: u32) { let _ = value <= u16::max_value() as u32 && value as i32 == 5; + //~^ checked_conversions let _ = value <= u16::MAX as u32 && value as i32 == 5; + //~^ checked_conversions } // Negative tests @@ -86,6 +102,7 @@ fn msrv_1_33() { fn msrv_1_34() { let value: i64 = 34; let _ = value <= (u32::MAX as i64) && value >= 0; + //~^ checked_conversions } fn main() {} diff --git a/src/tools/clippy/tests/ui/checked_conversions.stderr b/src/tools/clippy/tests/ui/checked_conversions.stderr index 453cd7fcf0169..3841b9d5a4ddd 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.stderr +++ b/src/tools/clippy/tests/ui/checked_conversions.stderr @@ -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:16:13 + --> tests/ui/checked_conversions.rs:17: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:20:13 + --> tests/ui/checked_conversions.rs:22: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:21:13 + --> tests/ui/checked_conversions.rs:24: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:25:13 + --> tests/ui/checked_conversions.rs:29: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:26:13 + --> tests/ui/checked_conversions.rs:31: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:32:13 + --> tests/ui/checked_conversions.rs:38: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:33:13 + --> tests/ui/checked_conversions.rs:40: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:37:13 + --> tests/ui/checked_conversions.rs:45: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:38:13 + --> tests/ui/checked_conversions.rs:47: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:44:13 + --> tests/ui/checked_conversions.rs:54: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:45:13 + --> tests/ui/checked_conversions.rs:56: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:49:13 + --> tests/ui/checked_conversions.rs:61: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:50:13 + --> tests/ui/checked_conversions.rs:63: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:54:13 + --> tests/ui/checked_conversions.rs:68: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:55:13 + --> tests/ui/checked_conversions.rs:70: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:88:13 + --> tests/ui/checked_conversions.rs:104: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/checked_unwrap/complex_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs index 323dae380633d..7d0bcc547a42b 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.rs @@ -11,16 +11,19 @@ fn test_complex_conditions() { if x.is_ok() && y.is_err() { // unnecessary x.unwrap(); - //~^ ERROR: called `unwrap` on `x` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // will panic x.unwrap_err(); - //~^ ERROR: this call to `unwrap_err()` will always panic + //~^ panicking_unwrap + // will panic y.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // unnecessary y.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `y` after checking its variant with `is_err` + //~^ unnecessary_unwrap } else { // not statically determinable whether any of the following will always succeed or always fail: x.unwrap(); @@ -36,37 +39,45 @@ fn test_complex_conditions() { } else { // will panic x.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // unnecessary x.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `x` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // will panic y.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // unnecessary y.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `y` after checking its variant with `is_ok` + //~^ unnecessary_unwrap } let z: Result<(), ()> = Ok(()); if x.is_ok() && !(y.is_ok() || z.is_err()) { // unnecessary x.unwrap(); - //~^ ERROR: called `unwrap` on `x` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // will panic x.unwrap_err(); - //~^ ERROR: this call to `unwrap_err()` will always panic + //~^ panicking_unwrap + // will panic y.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // unnecessary y.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `y` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // unnecessary z.unwrap(); - //~^ ERROR: called `unwrap` on `z` after checking its variant with `is_err` + //~^ unnecessary_unwrap + // will panic z.unwrap_err(); - //~^ ERROR: this call to `unwrap_err()` will always panic + //~^ panicking_unwrap } if x.is_ok() || !(y.is_ok() && z.is_err()) { // not statically determinable whether any of the following will always succeed or always fail: @@ -76,22 +87,27 @@ fn test_complex_conditions() { } else { // will panic x.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // unnecessary x.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `x` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // unnecessary y.unwrap(); - //~^ ERROR: called `unwrap` on `y` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // will panic y.unwrap_err(); - //~^ ERROR: this call to `unwrap_err()` will always panic + //~^ panicking_unwrap + // will panic z.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // unnecessary z.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `z` after checking its variant with `is_err` + //~^ unnecessary_unwrap } } diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr index aa72e8cce590f..d3905850c9702 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals.stderr @@ -15,7 +15,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:16:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:17:9 | LL | if x.is_ok() && y.is_err() { | --------- because of this check @@ -30,7 +30,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:19:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:21:9 | LL | if x.is_ok() && y.is_err() { | ---------- because of this check @@ -39,7 +39,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:22:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:25:9 | LL | if x.is_ok() && y.is_err() { | ---------- the check is happening here @@ -50,7 +50,7 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:38:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:41:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -59,7 +59,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:41:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:45:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -70,7 +70,7 @@ LL | x.unwrap_err(); = help: try using `if let` or `match` error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:44:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:49:9 | LL | if x.is_ok() || y.is_ok() { | --------- because of this check @@ -79,7 +79,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:47:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:53:9 | LL | if x.is_ok() || y.is_ok() { | --------- the check is happening here @@ -90,7 +90,7 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:53:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:59:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -101,7 +101,7 @@ LL | x.unwrap(); = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:56:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:63:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -110,7 +110,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:59:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:67:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- because of this check @@ -119,7 +119,7 @@ LL | y.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:62:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:71:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | --------- the check is happening here @@ -130,7 +130,7 @@ LL | y.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `z` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:65:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:75:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- the check is happening here @@ -141,7 +141,7 @@ LL | z.unwrap(); = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:68:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:79:9 | LL | if x.is_ok() && !(y.is_ok() || z.is_err()) { | ---------- because of this check @@ -150,7 +150,7 @@ LL | z.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:78:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:89:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -159,7 +159,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:81:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:93:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -170,7 +170,7 @@ LL | x.unwrap_err(); = help: try using `if let` or `match` error: called `unwrap` on `y` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/complex_conditionals.rs:84:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:97:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- the check is happening here @@ -181,7 +181,7 @@ LL | y.unwrap(); = help: try using `if let` or `match` error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:87:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:101:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | --------- because of this check @@ -190,7 +190,7 @@ LL | y.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/complex_conditionals.rs:90:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:105:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- because of this check @@ -199,7 +199,7 @@ LL | z.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `z` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/complex_conditionals.rs:93:9 + --> tests/ui/checked_unwrap/complex_conditionals.rs:109:9 | LL | if x.is_ok() || !(y.is_ok() && z.is_err()) { | ---------- the check is happening here diff --git a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs index 68923793dcdf9..145885702a9bc 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/complex_conditionals_nested.rs @@ -11,11 +11,11 @@ fn test_nested() { if x.is_some() { // unnecessary x.unwrap(); - //~^ ERROR: called `unwrap` on `x` after checking its variant with `is_some` + //~^ unnecessary_unwrap } else { // will panic x.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap } } } diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs index c3c8562edffba..4101897d38004 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.rs @@ -11,6 +11,7 @@ macro_rules! m { if $a.is_some() { // unnecessary $a.unwrap(); + //~^ unnecessary_unwrap } }; } @@ -44,26 +45,28 @@ fn main() { if x.is_some() { // unnecessary x.unwrap(); - //~^ ERROR: called `unwrap` on `x` after checking its variant with `is_some` + //~^ unnecessary_unwrap + // unnecessary x.expect("an error message"); - //~^ ERROR: called `expect` on `x` after checking its variant with `is_some` + //~^ unnecessary_unwrap } else { // will panic x.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // will panic x.expect("an error message"); - //~^ ERROR: this call to `expect()` will always panic + //~^ panicking_unwrap } if x.is_none() { // will panic x.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap } else { // unnecessary x.unwrap(); - //~^ ERROR: called `unwrap` on `x` after checking its variant with `is_none` + //~^ unnecessary_unwrap } m!(x); // ok @@ -76,38 +79,44 @@ fn main() { if x.is_ok() { // unnecessary x.unwrap(); - //~^ ERROR: called `unwrap` on `x` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // unnecessary x.expect("an error message"); - //~^ ERROR: called `expect` on `x` after checking its variant with `is_ok` + //~^ unnecessary_unwrap + // will panic x.unwrap_err(); - //~^ ERROR: this call to `unwrap_err()` will always panic + //~^ panicking_unwrap } else { // will panic x.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // will panic x.expect("an error message"); - //~^ ERROR: this call to `expect()` will always panic + //~^ panicking_unwrap + // unnecessary x.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `x` after checking its variant with `is_ok` + //~^ unnecessary_unwrap } if x.is_err() { // will panic x.unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap + // unnecessary x.unwrap_err(); - //~^ ERROR: called `unwrap_err` on `x` after checking its variant with `is_err` + //~^ unnecessary_unwrap } else { // unnecessary x.unwrap(); - //~^ ERROR: called `unwrap` on `x` after checking its variant with `is_err` + //~^ unnecessary_unwrap + // will panic x.unwrap_err(); - //~^ ERROR: this call to `unwrap_err()` will always panic + //~^ panicking_unwrap } if x.is_ok() { x = Err(()); @@ -132,38 +141,38 @@ fn issue11371() { if option.is_some() { option.as_ref().unwrap(); - //~^ ERROR: called `unwrap` on `option` after checking its variant with `is_some` + //~^ unnecessary_unwrap } else { option.as_ref().unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap } let result = Ok::<(), ()>(()); if result.is_ok() { result.as_ref().unwrap(); - //~^ ERROR: called `unwrap` on `result` after checking its variant with `is_ok` + //~^ unnecessary_unwrap } else { result.as_ref().unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap } let mut option = Some(()); if option.is_some() { option.as_mut().unwrap(); - //~^ ERROR: called `unwrap` on `option` after checking its variant with `is_some` + //~^ unnecessary_unwrap } else { option.as_mut().unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap } let mut result = Ok::<(), ()>(()); if result.is_ok() { result.as_mut().unwrap(); - //~^ ERROR: called `unwrap` on `result` after checking its variant with `is_ok` + //~^ unnecessary_unwrap } else { result.as_mut().unwrap(); - //~^ ERROR: this call to `unwrap()` will always panic + //~^ panicking_unwrap } // This should not lint. Statics are, at the time of writing, not linted on anyway, @@ -172,6 +181,7 @@ fn issue11371() { static mut X: Option = Some(123); unsafe { if X.is_some() { + //~^ ERROR: creating a shared reference X = None; X.unwrap(); } diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr index d92c03f488813..c17eaef2326b3 100644 --- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr +++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr @@ -1,5 +1,5 @@ error: called `unwrap` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:46:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:47:9 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` @@ -14,7 +14,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:49:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:51:9 | LL | if x.is_some() { | -------------- help: try: `if let Some() = x` @@ -23,7 +23,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:53:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:55:9 | LL | if x.is_some() { | ----------- because of this check @@ -38,7 +38,7 @@ LL | #![deny(clippy::panicking_unwrap, clippy::unnecessary_unwrap)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:56:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:59:9 | LL | if x.is_some() { | ----------- because of this check @@ -47,7 +47,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:61:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:64:9 | LL | if x.is_none() { | ----------- because of this check @@ -56,7 +56,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_none` - --> tests/ui/checked_unwrap/simple_conditionals.rs:65:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:68:9 | LL | if x.is_none() { | -------------- help: try: `if let Some() = x` @@ -79,7 +79,7 @@ LL | m!(x); = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) error: called `unwrap` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:78:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok() = x` @@ -88,7 +88,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `expect` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:81:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:85:9 | LL | if x.is_ok() { | ------------ help: try: `if let Ok() = x` @@ -97,7 +97,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:84:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:89:9 | LL | if x.is_ok() { | --------- because of this check @@ -106,7 +106,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:88:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:93:9 | LL | if x.is_ok() { | --------- because of this check @@ -115,7 +115,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `expect()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:91:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:97:9 | LL | if x.is_ok() { | --------- because of this check @@ -124,7 +124,7 @@ LL | x.expect("an error message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:94:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:101:9 | LL | if x.is_ok() { | ------------ help: try: `if let Err() = x` @@ -133,7 +133,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:99:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9 | LL | if x.is_err() { | ---------- because of this check @@ -142,7 +142,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: called `unwrap_err` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:102:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:110:9 | LL | if x.is_err() { | ------------- help: try: `if let Err() = x` @@ -151,7 +151,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `x` after checking its variant with `is_err` - --> tests/ui/checked_unwrap/simple_conditionals.rs:106:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:114:9 | LL | if x.is_err() { | ------------- help: try: `if let Ok() = x` @@ -160,7 +160,7 @@ LL | x.unwrap(); | ^^^^^^^^^^ error: this call to `unwrap_err()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:109:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:118:9 | LL | if x.is_err() { | ---------- because of this check @@ -169,7 +169,7 @@ LL | x.unwrap_err(); | ^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:134:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:143:9 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = &option` @@ -177,7 +177,7 @@ LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:137:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:146:9 | LL | if option.is_some() { | ---------------- because of this check @@ -186,7 +186,7 @@ LL | option.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:144:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = &result` @@ -194,7 +194,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:147:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:156:9 | LL | if result.is_ok() { | -------------- because of this check @@ -203,7 +203,7 @@ LL | result.as_ref().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `option` after checking its variant with `is_some` - --> tests/ui/checked_unwrap/simple_conditionals.rs:153:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9 | LL | if option.is_some() { | ------------------- help: try: `if let Some() = &mut option` @@ -211,7 +211,7 @@ LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:156:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:165:9 | LL | if option.is_some() { | ---------------- because of this check @@ -220,7 +220,7 @@ LL | option.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: called `unwrap` on `result` after checking its variant with `is_ok` - --> tests/ui/checked_unwrap/simple_conditionals.rs:162:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:171:9 | LL | if result.is_ok() { | ----------------- help: try: `if let Ok() = &mut result` @@ -228,7 +228,7 @@ LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this call to `unwrap()` will always panic - --> tests/ui/checked_unwrap/simple_conditionals.rs:165:9 + --> tests/ui/checked_unwrap/simple_conditionals.rs:174:9 | LL | if result.is_ok() { | -------------- because of this check @@ -237,7 +237,7 @@ LL | result.as_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: creating a shared reference to mutable static is discouraged - --> tests/ui/checked_unwrap/simple_conditionals.rs:174:12 + --> tests/ui/checked_unwrap/simple_conditionals.rs:183:12 | LL | if X.is_some() { | ^^^^^^^^^^^ shared reference to mutable static diff --git a/src/tools/clippy/tests/ui/clear_with_drain.fixed b/src/tools/clippy/tests/ui/clear_with_drain.fixed index 15777a4ea5b31..92fd86668b769 100644 --- a/src/tools/clippy/tests/ui/clear_with_drain.fixed +++ b/src/tools/clippy/tests/ui/clear_with_drain.fixed @@ -20,10 +20,12 @@ fn vec_range() { // Do lint let mut v = vec![1, 2, 3]; v.clear(); + //~^ clear_with_drain // Do lint let mut v = vec![1, 2, 3]; v.clear(); + //~^ clear_with_drain } fn vec_range_from() { @@ -43,10 +45,12 @@ fn vec_range_from() { // Do lint let mut v = vec![1, 2, 3]; v.clear(); + //~^ clear_with_drain // Do lint let mut v = vec![1, 2, 3]; v.clear(); + //~^ clear_with_drain } fn vec_range_full() { @@ -63,6 +67,7 @@ fn vec_range_full() { // Do lint let mut v = vec![1, 2, 3]; v.clear(); + //~^ clear_with_drain } fn vec_range_to() { @@ -80,6 +85,7 @@ fn vec_range_to() { // Do lint let mut v = vec![1, 2, 3]; v.clear(); + //~^ clear_with_drain } fn vec_partial_drains() { @@ -118,10 +124,12 @@ fn vec_deque_range() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); + //~^ clear_with_drain // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); + //~^ clear_with_drain } fn vec_deque_range_from() { @@ -141,10 +149,12 @@ fn vec_deque_range_from() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); + //~^ clear_with_drain // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); + //~^ clear_with_drain } fn vec_deque_range_full() { @@ -161,6 +171,7 @@ fn vec_deque_range_full() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); + //~^ clear_with_drain } fn vec_deque_range_to() { @@ -178,6 +189,7 @@ fn vec_deque_range_to() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.clear(); + //~^ clear_with_drain } fn vec_deque_partial_drains() { @@ -216,10 +228,12 @@ fn string_range() { // Do lint let mut s = String::from("Hello, world!"); s.clear(); + //~^ clear_with_drain // Do lint let mut s = String::from("Hello, world!"); s.clear(); + //~^ clear_with_drain } fn string_range_from() { @@ -239,10 +253,12 @@ fn string_range_from() { // Do lint let mut s = String::from("Hello, world!"); s.clear(); + //~^ clear_with_drain // Do lint let mut s = String::from("Hello, world!"); s.clear(); + //~^ clear_with_drain } fn string_range_full() { @@ -259,6 +275,7 @@ fn string_range_full() { // Do lint let mut s = String::from("Hello, world!"); s.clear(); + //~^ clear_with_drain } fn string_range_to() { @@ -276,6 +293,7 @@ fn string_range_to() { // Do lint let mut s = String::from("Hello, world!"); s.clear(); + //~^ clear_with_drain } fn string_partial_drains() { @@ -314,6 +332,7 @@ fn hash_set() { // Do lint let mut set = HashSet::from([1, 2, 3]); set.clear(); + //~^ clear_with_drain } fn hash_map() { @@ -333,6 +352,7 @@ fn hash_map() { // Do lint let mut map = HashMap::from([(1, "a"), (2, "b")]); map.clear(); + //~^ clear_with_drain } fn binary_heap() { @@ -352,6 +372,7 @@ fn binary_heap() { // Do lint let mut heap = BinaryHeap::from([1, 2]); heap.clear(); + //~^ clear_with_drain } fn main() {} diff --git a/src/tools/clippy/tests/ui/clear_with_drain.rs b/src/tools/clippy/tests/ui/clear_with_drain.rs index 1dea7235ef669..28122fcaeded8 100644 --- a/src/tools/clippy/tests/ui/clear_with_drain.rs +++ b/src/tools/clippy/tests/ui/clear_with_drain.rs @@ -20,10 +20,12 @@ fn vec_range() { // Do lint let mut v = vec![1, 2, 3]; v.drain(0..v.len()); + //~^ clear_with_drain // Do lint let mut v = vec![1, 2, 3]; v.drain(usize::MIN..v.len()); + //~^ clear_with_drain } fn vec_range_from() { @@ -43,10 +45,12 @@ fn vec_range_from() { // Do lint let mut v = vec![1, 2, 3]; v.drain(0..); + //~^ clear_with_drain // Do lint let mut v = vec![1, 2, 3]; v.drain(usize::MIN..); + //~^ clear_with_drain } fn vec_range_full() { @@ -63,6 +67,7 @@ fn vec_range_full() { // Do lint let mut v = vec![1, 2, 3]; v.drain(..); + //~^ clear_with_drain } fn vec_range_to() { @@ -80,6 +85,7 @@ fn vec_range_to() { // Do lint let mut v = vec![1, 2, 3]; v.drain(..v.len()); + //~^ clear_with_drain } fn vec_partial_drains() { @@ -118,10 +124,12 @@ fn vec_deque_range() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.drain(0..deque.len()); + //~^ clear_with_drain // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.drain(usize::MIN..deque.len()); + //~^ clear_with_drain } fn vec_deque_range_from() { @@ -141,10 +149,12 @@ fn vec_deque_range_from() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.drain(0..); + //~^ clear_with_drain // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.drain(usize::MIN..); + //~^ clear_with_drain } fn vec_deque_range_full() { @@ -161,6 +171,7 @@ fn vec_deque_range_full() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.drain(..); + //~^ clear_with_drain } fn vec_deque_range_to() { @@ -178,6 +189,7 @@ fn vec_deque_range_to() { // Do lint let mut deque = VecDeque::from([1, 2, 3]); deque.drain(..deque.len()); + //~^ clear_with_drain } fn vec_deque_partial_drains() { @@ -216,10 +228,12 @@ fn string_range() { // Do lint let mut s = String::from("Hello, world!"); s.drain(0..s.len()); + //~^ clear_with_drain // Do lint let mut s = String::from("Hello, world!"); s.drain(usize::MIN..s.len()); + //~^ clear_with_drain } fn string_range_from() { @@ -239,10 +253,12 @@ fn string_range_from() { // Do lint let mut s = String::from("Hello, world!"); s.drain(0..); + //~^ clear_with_drain // Do lint let mut s = String::from("Hello, world!"); s.drain(usize::MIN..); + //~^ clear_with_drain } fn string_range_full() { @@ -259,6 +275,7 @@ fn string_range_full() { // Do lint let mut s = String::from("Hello, world!"); s.drain(..); + //~^ clear_with_drain } fn string_range_to() { @@ -276,6 +293,7 @@ fn string_range_to() { // Do lint let mut s = String::from("Hello, world!"); s.drain(..s.len()); + //~^ clear_with_drain } fn string_partial_drains() { @@ -314,6 +332,7 @@ fn hash_set() { // Do lint let mut set = HashSet::from([1, 2, 3]); set.drain(); + //~^ clear_with_drain } fn hash_map() { @@ -333,6 +352,7 @@ fn hash_map() { // Do lint let mut map = HashMap::from([(1, "a"), (2, "b")]); map.drain(); + //~^ clear_with_drain } fn binary_heap() { @@ -352,6 +372,7 @@ fn binary_heap() { // Do lint let mut heap = BinaryHeap::from([1, 2]); heap.drain(); + //~^ clear_with_drain } fn main() {} diff --git a/src/tools/clippy/tests/ui/clear_with_drain.stderr b/src/tools/clippy/tests/ui/clear_with_drain.stderr index 3c7d22192dc77..0f060fa9dade6 100644 --- a/src/tools/clippy/tests/ui/clear_with_drain.stderr +++ b/src/tools/clippy/tests/ui/clear_with_drain.stderr @@ -8,121 +8,121 @@ LL | v.drain(0..v.len()); = help: to override `-D warnings` add `#[allow(clippy::clear_with_drain)]` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:26:7 + --> tests/ui/clear_with_drain.rs:27:7 | LL | v.drain(usize::MIN..v.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:45:7 + --> tests/ui/clear_with_drain.rs:47:7 | LL | v.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:49:7 + --> tests/ui/clear_with_drain.rs:52:7 | LL | v.drain(usize::MIN..); | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:65:7 + --> tests/ui/clear_with_drain.rs:69:7 | LL | v.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `Vec` - --> tests/ui/clear_with_drain.rs:82:7 + --> tests/ui/clear_with_drain.rs:87:7 | LL | v.drain(..v.len()); | ^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:120:11 + --> tests/ui/clear_with_drain.rs:126:11 | LL | deque.drain(0..deque.len()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:124:11 + --> tests/ui/clear_with_drain.rs:131:11 | LL | deque.drain(usize::MIN..deque.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:143:11 + --> tests/ui/clear_with_drain.rs:151:11 | LL | deque.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:147:11 + --> tests/ui/clear_with_drain.rs:156:11 | LL | deque.drain(usize::MIN..); | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:163:11 + --> tests/ui/clear_with_drain.rs:173:11 | LL | deque.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `VecDeque` - --> tests/ui/clear_with_drain.rs:180:11 + --> tests/ui/clear_with_drain.rs:191:11 | LL | deque.drain(..deque.len()); | ^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:218:7 + --> tests/ui/clear_with_drain.rs:230:7 | LL | s.drain(0..s.len()); | ^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:222:7 + --> tests/ui/clear_with_drain.rs:235:7 | LL | s.drain(usize::MIN..s.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:241:7 + --> tests/ui/clear_with_drain.rs:255:7 | LL | s.drain(0..); | ^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:245:7 + --> tests/ui/clear_with_drain.rs:260:7 | LL | s.drain(usize::MIN..); | ^^^^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:261:7 + --> tests/ui/clear_with_drain.rs:277:7 | LL | s.drain(..); | ^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `String` - --> tests/ui/clear_with_drain.rs:278:7 + --> tests/ui/clear_with_drain.rs:295:7 | LL | s.drain(..s.len()); | ^^^^^^^^^^^^^^^^ help: try: `clear()` error: `drain` used to clear a `HashSet` - --> tests/ui/clear_with_drain.rs:316:9 + --> tests/ui/clear_with_drain.rs:334:9 | LL | set.drain(); | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `HashMap` - --> tests/ui/clear_with_drain.rs:335:9 + --> tests/ui/clear_with_drain.rs:354:9 | LL | map.drain(); | ^^^^^^^ help: try: `clear()` error: `drain` used to clear a `BinaryHeap` - --> tests/ui/clear_with_drain.rs:354:10 + --> tests/ui/clear_with_drain.rs:374:10 | LL | heap.drain(); | ^^^^^^^ help: try: `clear()` diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed index 9d9a5bf20f438..2dd8af1525150 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.fixed +++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed @@ -21,16 +21,20 @@ fn is_ascii(ch: char) -> bool { fn clone_on_copy() -> Option<(i32)> { 42; + //~^ clone_on_copy vec![1].clone(); // ok, not a Copy type Some(vec![1]).clone(); // ok, not a Copy type *(&42); + //~^ clone_on_copy let rc = RefCell::new(0); *rc.borrow(); + //~^ clone_on_copy let x = 0u32; x.rotate_left(1); + //~^ clone_on_copy #[derive(Clone, Copy)] struct Foo; @@ -45,6 +49,7 @@ fn clone_on_copy() -> Option<(i32)> { ($e:expr) => {{ $e }}; } m!(42); + //~^ clone_on_copy struct Wrap([u32; 2]); impl core::ops::Deref for Wrap { @@ -55,6 +60,7 @@ fn clone_on_copy() -> Option<(i32)> { } let x = Wrap([0, 0]); (*x)[0]; + //~^ clone_on_copy let x = 42; let ref y = x.clone(); // ok, binds by reference @@ -65,13 +71,17 @@ fn clone_on_copy() -> Option<(i32)> { let _ = &x.clone(); // ok, getting a ref 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate is_ascii('z'); + //~^ clone_on_copy // Issue #5436 let mut vec = Vec::new(); vec.push(42); + //~^ clone_on_copy // Issue #9277 let opt: &Option = &None; let value = (*opt)?; // operator precedence needed (*opt)? + // + //~^^ clone_on_copy None } diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs index 305bc6816e1b6..a371afb04a78f 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.rs +++ b/src/tools/clippy/tests/ui/clone_on_copy.rs @@ -21,16 +21,20 @@ fn is_ascii(ch: char) -> bool { fn clone_on_copy() -> Option<(i32)> { 42.clone(); + //~^ clone_on_copy vec![1].clone(); // ok, not a Copy type Some(vec![1]).clone(); // ok, not a Copy type (&42).clone(); + //~^ clone_on_copy let rc = RefCell::new(0); rc.borrow().clone(); + //~^ clone_on_copy let x = 0u32; x.clone().rotate_left(1); + //~^ clone_on_copy #[derive(Clone, Copy)] struct Foo; @@ -45,6 +49,7 @@ fn clone_on_copy() -> Option<(i32)> { ($e:expr) => {{ $e }}; } m!(42).clone(); + //~^ clone_on_copy struct Wrap([u32; 2]); impl core::ops::Deref for Wrap { @@ -55,6 +60,7 @@ fn clone_on_copy() -> Option<(i32)> { } let x = Wrap([0, 0]); x.clone()[0]; + //~^ clone_on_copy let x = 42; let ref y = x.clone(); // ok, binds by reference @@ -65,13 +71,17 @@ fn clone_on_copy() -> Option<(i32)> { let _ = &x.clone(); // ok, getting a ref 'a'.clone().make_ascii_uppercase(); // ok, clone and then mutate is_ascii('z'.clone()); + //~^ clone_on_copy // Issue #5436 let mut vec = Vec::new(); vec.push(42.clone()); + //~^ clone_on_copy // Issue #9277 let opt: &Option = &None; let value = opt.clone()?; // operator precedence needed (*opt)? + // + //~^^ clone_on_copy None } diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr index 314fd13afca43..92cdd635d20a8 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.stderr +++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr @@ -8,49 +8,49 @@ LL | 42.clone(); = help: to override `-D warnings` add `#[allow(clippy::clone_on_copy)]` error: using `clone` on type `i32` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:27:5 + --> tests/ui/clone_on_copy.rs:28:5 | LL | (&42).clone(); | ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)` error: using `clone` on type `i32` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:30:5 + --> tests/ui/clone_on_copy.rs:32:5 | LL | rc.borrow().clone(); | ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()` error: using `clone` on type `u32` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:33:5 + --> tests/ui/clone_on_copy.rs:36:5 | LL | x.clone().rotate_left(1); | ^^^^^^^^^ help: try removing the `clone` call: `x` error: using `clone` on type `i32` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:47:5 + --> tests/ui/clone_on_copy.rs:51:5 | LL | m!(42).clone(); | ^^^^^^^^^^^^^^ help: try removing the `clone` call: `m!(42)` error: using `clone` on type `[u32; 2]` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:57:5 + --> tests/ui/clone_on_copy.rs:62:5 | LL | x.clone()[0]; | ^^^^^^^^^ help: try dereferencing it: `(*x)` error: using `clone` on type `char` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:67:14 + --> tests/ui/clone_on_copy.rs:73:14 | LL | is_ascii('z'.clone()); | ^^^^^^^^^^^ help: try removing the `clone` call: `'z'` error: using `clone` on type `i32` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:71:14 + --> tests/ui/clone_on_copy.rs:78:14 | LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` error: using `clone` on type `Option` which implements the `Copy` trait - --> tests/ui/clone_on_copy.rs:75:17 + --> tests/ui/clone_on_copy.rs:83:17 | LL | let value = opt.clone()?; // operator precedence needed (*opt)? | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)` diff --git a/src/tools/clippy/tests/ui/clone_on_copy_impl.rs b/src/tools/clippy/tests/ui/clone_on_copy_impl.rs index 2d03544ad8b6b..33375aead4d5d 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy_impl.rs +++ b/src/tools/clippy/tests/ui/clone_on_copy_impl.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::non_canonical_clone_impl)] use std::fmt; diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed index bc939bb3dbb9c..0a1a59ddf9b83 100644 --- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed +++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed @@ -5,10 +5,15 @@ fn main() { // yay let _ = [1].iter().copied(); + //~^ cloned_instead_of_copied let _ = vec!["hi"].iter().copied(); + //~^ cloned_instead_of_copied let _ = Some(&1).copied(); + //~^ cloned_instead_of_copied let _ = Box::new([1].iter()).copied(); + //~^ cloned_instead_of_copied let _ = Box::new(Some(&1)).copied(); + //~^ cloned_instead_of_copied // nay let _ = [String::new()].iter().cloned(); @@ -25,10 +30,15 @@ fn msrv_1_34() { fn msrv_1_35() { let _ = [1].iter().cloned(); let _ = Some(&1).copied(); // Option::copied needs 1.35 + // + //~^^ cloned_instead_of_copied } #[clippy::msrv = "1.36"] fn msrv_1_36() { let _ = [1].iter().copied(); // Iterator::copied needs 1.36 + // + //~^^ cloned_instead_of_copied let _ = Some(&1).copied(); + //~^ cloned_instead_of_copied } diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs index 27346adbfbf1b..c452dd007a1ed 100644 --- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs +++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs @@ -5,10 +5,15 @@ fn main() { // yay let _ = [1].iter().cloned(); + //~^ cloned_instead_of_copied let _ = vec!["hi"].iter().cloned(); + //~^ cloned_instead_of_copied let _ = Some(&1).cloned(); + //~^ cloned_instead_of_copied let _ = Box::new([1].iter()).cloned(); + //~^ cloned_instead_of_copied let _ = Box::new(Some(&1)).cloned(); + //~^ cloned_instead_of_copied // nay let _ = [String::new()].iter().cloned(); @@ -25,10 +30,15 @@ fn msrv_1_34() { fn msrv_1_35() { let _ = [1].iter().cloned(); let _ = Some(&1).cloned(); // Option::copied needs 1.35 + // + //~^^ cloned_instead_of_copied } #[clippy::msrv = "1.36"] fn msrv_1_36() { let _ = [1].iter().cloned(); // Iterator::copied needs 1.36 + // + //~^^ cloned_instead_of_copied let _ = Some(&1).cloned(); + //~^ cloned_instead_of_copied } diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr index ad857c4ef7d0f..bd741e41321bc 100644 --- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr +++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.stderr @@ -8,43 +8,43 @@ LL | let _ = [1].iter().cloned(); = help: to override `-D warnings` add `#[allow(clippy::cloned_instead_of_copied)]` error: used `cloned` where `copied` could be used instead - --> tests/ui/cloned_instead_of_copied.rs:8:31 + --> tests/ui/cloned_instead_of_copied.rs:9:31 | LL | let _ = vec!["hi"].iter().cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> tests/ui/cloned_instead_of_copied.rs:9:22 + --> tests/ui/cloned_instead_of_copied.rs:11:22 | LL | let _ = Some(&1).cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> tests/ui/cloned_instead_of_copied.rs:10:34 + --> tests/ui/cloned_instead_of_copied.rs:13:34 | LL | let _ = Box::new([1].iter()).cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> tests/ui/cloned_instead_of_copied.rs:11:32 + --> tests/ui/cloned_instead_of_copied.rs:15:32 | LL | let _ = Box::new(Some(&1)).cloned(); | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> tests/ui/cloned_instead_of_copied.rs:27:22 + --> tests/ui/cloned_instead_of_copied.rs:32:22 | LL | let _ = Some(&1).cloned(); // Option::copied needs 1.35 | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> tests/ui/cloned_instead_of_copied.rs:32:24 + --> tests/ui/cloned_instead_of_copied.rs:39:24 | LL | let _ = [1].iter().cloned(); // Iterator::copied needs 1.36 | ^^^^^^ help: try: `copied` error: used `cloned` where `copied` could be used instead - --> tests/ui/cloned_instead_of_copied.rs:33:22 + --> tests/ui/cloned_instead_of_copied.rs:42:22 | LL | let _ = Some(&1).cloned(); | ^^^^^^ help: try: `copied` diff --git a/src/tools/clippy/tests/ui/cmp_null.fixed b/src/tools/clippy/tests/ui/cmp_null.fixed index e5ab765bc8614..140ddb10aeb86 100644 --- a/src/tools/clippy/tests/ui/cmp_null.fixed +++ b/src/tools/clippy/tests/ui/cmp_null.fixed @@ -7,26 +7,29 @@ fn main() { let x = 0; let p: *const usize = &x; if p.is_null() { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method - //~| NOTE: `-D clippy::cmp-null` implied by `-D warnings` + //~^ cmp_null + println!("This is surprising!"); } if p.is_null() { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null + println!("This is surprising!"); } let mut y = 0; let mut m: *mut usize = &mut y; if m.is_null() { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null + println!("This is surprising, too!"); } if m.is_null() { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null + println!("This is surprising, too!"); } let _ = (x as *const ()).is_null(); - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null } diff --git a/src/tools/clippy/tests/ui/cmp_null.rs b/src/tools/clippy/tests/ui/cmp_null.rs index 257f7ba266277..16ed17765dace 100644 --- a/src/tools/clippy/tests/ui/cmp_null.rs +++ b/src/tools/clippy/tests/ui/cmp_null.rs @@ -7,26 +7,29 @@ fn main() { let x = 0; let p: *const usize = &x; if p == ptr::null() { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method - //~| NOTE: `-D clippy::cmp-null` implied by `-D warnings` + //~^ cmp_null + println!("This is surprising!"); } if ptr::null() == p { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null + println!("This is surprising!"); } let mut y = 0; let mut m: *mut usize = &mut y; if m == ptr::null_mut() { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null + println!("This is surprising, too!"); } if ptr::null_mut() == m { - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null + println!("This is surprising, too!"); } let _ = x as *const () == ptr::null(); - //~^ ERROR: comparing with null is better expressed by the `.is_null()` method + //~^ cmp_null } diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr index f3b35f3afba8b..6821846d0466d 100644 --- a/src/tools/clippy/tests/ui/cmp_null.stderr +++ b/src/tools/clippy/tests/ui/cmp_null.stderr @@ -14,19 +14,19 @@ LL | if ptr::null() == p { | ^^^^^^^^^^^^^^^^ help: try: `p.is_null()` error: comparing with null is better expressed by the `.is_null()` method - --> tests/ui/cmp_null.rs:21:8 + --> tests/ui/cmp_null.rs:22:8 | LL | if m == ptr::null_mut() { | ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()` error: comparing with null is better expressed by the `.is_null()` method - --> tests/ui/cmp_null.rs:25:8 + --> tests/ui/cmp_null.rs:27:8 | LL | if ptr::null_mut() == m { | ^^^^^^^^^^^^^^^^^^^^ help: try: `m.is_null()` error: comparing with null is better expressed by the `.is_null()` method - --> tests/ui/cmp_null.rs:30:13 + --> tests/ui/cmp_null.rs:33:13 | LL | let _ = x as *const () == ptr::null(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(x as *const ()).is_null()` diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed index 9fc70ab6f4a0a..8d543b0422009 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -44,7 +44,9 @@ mod borrowed_eq_owned { let borrowed = Borrowed {}; if borrowed == owned {} + //~^ cmp_owned if borrowed == owned {} + //~^ cmp_owned } } @@ -63,7 +65,9 @@ mod owned_eq_borrowed { let borrowed = Borrowed {}; if owned == borrowed {} + //~^ cmp_owned if owned == borrowed {} + //~^ cmp_owned } } @@ -90,7 +94,9 @@ mod issue_4874 { let borrowed = Borrowed {}; if borrowed == "Hi" {} + //~^ cmp_owned if borrowed == "Hi" {} + //~^ cmp_owned } } diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs index 5cd43ea1d4114..6da311c50ee7b 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -44,7 +44,9 @@ mod borrowed_eq_owned { let borrowed = Borrowed {}; if borrowed.to_owned() == owned {} + //~^ cmp_owned if owned == borrowed.to_owned() {} + //~^ cmp_owned } } @@ -63,7 +65,9 @@ mod owned_eq_borrowed { let borrowed = Borrowed {}; if owned == borrowed.to_owned() {} + //~^ cmp_owned if borrowed.to_owned() == owned {} + //~^ cmp_owned } } @@ -90,7 +94,9 @@ mod issue_4874 { let borrowed = Borrowed {}; if "Hi" == borrowed.to_string() {} + //~^ cmp_owned if borrowed.to_string() == "Hi" {} + //~^ cmp_owned } } diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr index e230d5f06bb05..1d2645d358f3e 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.stderr @@ -8,7 +8,7 @@ LL | if borrowed.to_owned() == owned {} = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:47:21 + --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:48:21 | LL | if owned == borrowed.to_owned() {} | ---------^^^^^^^^^^^^^^^^^^^ @@ -16,13 +16,13 @@ LL | if owned == borrowed.to_owned() {} | help: try: `borrowed == owned` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:65:21 + --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:67:21 | LL | if owned == borrowed.to_owned() {} | ^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:66:12 + --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:69:12 | LL | if borrowed.to_owned() == owned {} | ^^^^^^^^^^^^^^^^^^^--------- @@ -30,7 +30,7 @@ LL | if borrowed.to_owned() == owned {} | help: try: `owned == borrowed` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:92:20 + --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:96:20 | LL | if "Hi" == borrowed.to_string() {} | --------^^^^^^^^^^^^^^^^^^^^ @@ -38,7 +38,7 @@ LL | if "Hi" == borrowed.to_string() {} | help: try: `borrowed == "Hi"` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:93:12 + --> tests/ui/cmp_owned/asymmetric_partial_eq.rs:98:12 | LL | if borrowed.to_string() == "Hi" {} | ^^^^^^^^^^^^^^^^^^^^ help: try: `borrowed` diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed index 40d7b5e49fcdf..711fbca1c8d28 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed +++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed @@ -4,10 +4,12 @@ fn main() { let a = Foo; if a != "bar" { + //~^ cmp_owned println!("foo"); } if a != "bar" { + //~^ cmp_owned println!("foo"); } } diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs index 59a945668b2e0..ce86bb3f7b5c8 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs @@ -4,10 +4,12 @@ fn main() { let a = Foo; if a.to_string() != "bar" { + //~^ cmp_owned println!("foo"); } if "bar" != a.to_string() { + //~^ cmp_owned println!("foo"); } } diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr index cfb6978158b37..ca571837039d7 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr @@ -8,7 +8,7 @@ LL | if a.to_string() != "bar" { = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/comparison_flip.rs:10:17 + --> tests/ui/cmp_owned/comparison_flip.rs:11:17 | LL | if "bar" != a.to_string() { | ---------^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed index ab72e096cc7c7..eb01633a25fd5 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed @@ -3,8 +3,10 @@ fn main() { fn with_to_string(x: &str) { x != "foo"; + //~^ cmp_owned "foo" != x; + //~^ cmp_owned } let x = "oh"; @@ -12,14 +14,18 @@ fn main() { with_to_string(x); x != "foo"; + //~^ cmp_owned x != "foo"; + //~^ cmp_owned 42.to_string() == "42"; Foo == Foo; + //~^ cmp_owned "abc".chars().filter(|c| *c != 'X'); + //~^ cmp_owned "abc".chars().filter(|c| *c != 'X'); } diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs index cb5268734d32c..82409f27b129c 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs @@ -3,8 +3,10 @@ fn main() { fn with_to_string(x: &str) { x != "foo".to_string(); + //~^ cmp_owned "foo".to_string() != x; + //~^ cmp_owned } let x = "oh"; @@ -12,14 +14,18 @@ fn main() { with_to_string(x); x != "foo".to_owned(); + //~^ cmp_owned x != String::from("foo"); + //~^ cmp_owned 42.to_string() == "42"; Foo.to_owned() == Foo; + //~^ cmp_owned "abc".chars().filter(|c| c.to_owned() != 'X'); + //~^ cmp_owned "abc".chars().filter(|c| *c != 'X'); } diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr index 41448e0120039..ca2ab44847274 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr @@ -8,31 +8,31 @@ LL | x != "foo".to_string(); = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/with_suggestion.rs:7:9 + --> tests/ui/cmp_owned/with_suggestion.rs:8:9 | LL | "foo".to_string() != x; | ^^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/with_suggestion.rs:14:10 + --> tests/ui/cmp_owned/with_suggestion.rs:16:10 | LL | x != "foo".to_owned(); | ^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/with_suggestion.rs:16:10 + --> tests/ui/cmp_owned/with_suggestion.rs:19:10 | LL | x != String::from("foo"); | ^^^^^^^^^^^^^^^^^^^ help: try: `"foo"` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/with_suggestion.rs:20:5 + --> tests/ui/cmp_owned/with_suggestion.rs:24:5 | LL | Foo.to_owned() == Foo; | ^^^^^^^^^^^^^^ help: try: `Foo` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/with_suggestion.rs:22:30 + --> tests/ui/cmp_owned/with_suggestion.rs:27:30 | LL | "abc".chars().filter(|c| c.to_owned() != 'X'); | ^^^^^^^^^^^^ help: try: `*c` diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs index 913aab7274716..4e14c3054d9f7 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.rs @@ -5,13 +5,12 @@ fn main() { let x = &Baz; let y = &Baz; y.to_owned() == *x; - //~^ ERROR: this creates an owned instance just for comparison - //~| NOTE: `-D clippy::cmp-owned` implied by `-D warnings` + //~^ cmp_owned let x = &&Baz; let y = &Baz; y.to_owned() == **x; - //~^ ERROR: this creates an owned instance just for comparison + //~^ cmp_owned let x = 0u32; let y = U32Wrapper(x); @@ -23,7 +22,7 @@ struct Foo; impl PartialEq for Foo { fn eq(&self, other: &Self) -> bool { self.to_owned() == *other - //~^ ERROR: this creates an owned instance just for comparison + //~^ cmp_owned } } diff --git a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr index 13ca699b9fd3b..c8e2efab4915c 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr +++ b/src/tools/clippy/tests/ui/cmp_owned/without_suggestion.stderr @@ -8,13 +8,13 @@ LL | y.to_owned() == *x; = help: to override `-D warnings` add `#[allow(clippy::cmp_owned)]` error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/without_suggestion.rs:13:5 + --> tests/ui/cmp_owned/without_suggestion.rs:12:5 | LL | y.to_owned() == **x; | ^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating error: this creates an owned instance just for comparison - --> tests/ui/cmp_owned/without_suggestion.rs:25:9 + --> tests/ui/cmp_owned/without_suggestion.rs:24:9 | LL | self.to_owned() == *other | ^^^^^^^^^^^^^^^^^^^^^^^^^ try implementing the comparison without allocating diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.rs b/src/tools/clippy/tests/ui/cognitive_complexity.rs index e8fd063a98f24..2dbec955f63fe 100644 --- a/src/tools/clippy/tests/ui/cognitive_complexity.rs +++ b/src/tools/clippy/tests/ui/cognitive_complexity.rs @@ -4,7 +4,8 @@ #[rustfmt::skip] fn main() { -//~^ ERROR: the function has a cognitive complexity of (28/25) +//~^ cognitive_complexity + if true { println!("a"); } @@ -90,7 +91,8 @@ fn main() { #[clippy::cognitive_complexity = "1"] fn kaboom() { - //~^ ERROR: the function has a cognitive complexity of (7/1) + //~^ cognitive_complexity + let n = 0; 'a: for i in 0..20 { 'b: for j in i..20 { @@ -149,9 +151,10 @@ fn lots_of_short_circuits2() -> bool { #[clippy::cognitive_complexity = "1"] fn baa() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + let x = || match 99 { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity 0 => 0, 1 => 1, 2 => 2, @@ -169,7 +172,8 @@ fn baa() { #[clippy::cognitive_complexity = "1"] fn bar() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), _ => println!("bye"), @@ -181,7 +185,8 @@ fn bar() { /// Tests are usually complex but simple at the same time. `clippy::cognitive_complexity` used to /// give lots of false-positives in tests. fn dont_warn_on_tests() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), _ => println!("bye"), @@ -190,7 +195,8 @@ fn dont_warn_on_tests() { #[clippy::cognitive_complexity = "1"] fn barr() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -201,7 +207,8 @@ fn barr() { #[clippy::cognitive_complexity = "1"] fn barr2() { - //~^ ERROR: the function has a cognitive complexity of (3/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -218,7 +225,8 @@ fn barr2() { #[clippy::cognitive_complexity = "1"] fn barrr() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), 1 => panic!("bla"), @@ -229,7 +237,8 @@ fn barrr() { #[clippy::cognitive_complexity = "1"] fn barrr2() { - //~^ ERROR: the function has a cognitive complexity of (3/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), 1 => panic!("bla"), @@ -246,7 +255,8 @@ fn barrr2() { #[clippy::cognitive_complexity = "1"] fn barrrr() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -257,7 +267,8 @@ fn barrrr() { #[clippy::cognitive_complexity = "1"] fn barrrr2() { - //~^ ERROR: the function has a cognitive complexity of (3/1) + //~^ cognitive_complexity + match 99 { 0 => println!("hi"), 1 => println!("bla"), @@ -274,7 +285,8 @@ fn barrrr2() { #[clippy::cognitive_complexity = "1"] fn cake() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + if 4 == 5 { println!("yea"); } else { @@ -285,7 +297,8 @@ fn cake() { #[clippy::cognitive_complexity = "1"] pub fn read_file(input_path: &str) -> String { - //~^ ERROR: the function has a cognitive complexity of (4/1) + //~^ cognitive_complexity + use std::fs::File; use std::io::{Read, Write}; use std::path::Path; @@ -317,7 +330,8 @@ enum Void {} #[clippy::cognitive_complexity = "1"] fn void(void: Void) { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + if true { match void {} } @@ -369,7 +383,8 @@ fn early() -> Result { #[rustfmt::skip] #[clippy::cognitive_complexity = "1"] fn early_ret() -> i32 { -//~^ ERROR: the function has a cognitive complexity of (8/1) +//~^ cognitive_complexity + let a = if true { 42 } else { return 0; }; let a = if a < 99 { 42 } else { return 0; }; let a = if a < 99 { 42 } else { return 0; }; @@ -391,7 +406,8 @@ fn early_ret() -> i32 { #[clippy::cognitive_complexity = "1"] fn closures() { let x = |a: i32, b: i32| -> i32 { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + if true { println!("moo"); } @@ -405,7 +421,8 @@ struct Moo; #[clippy::cognitive_complexity = "1"] impl Moo { fn moo(&self) { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + if true { println!("moo"); } @@ -415,7 +432,8 @@ impl Moo { #[clippy::cognitive_complexity = "1"] mod issue9300 { async fn a() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + let a = 0; if a == 0 {} } @@ -423,7 +441,8 @@ mod issue9300 { pub struct S; impl S { pub async fn async_method() { - //~^ ERROR: the function has a cognitive complexity of (2/1) + //~^ cognitive_complexity + let a = 0; if a == 0 {} } diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.stderr b/src/tools/clippy/tests/ui/cognitive_complexity.stderr index 1e60247e5f584..52607b87c60ef 100644 --- a/src/tools/clippy/tests/ui/cognitive_complexity.stderr +++ b/src/tools/clippy/tests/ui/cognitive_complexity.stderr @@ -9,7 +9,7 @@ LL | fn main() { = help: to override `-D warnings` add `#[allow(clippy::cognitive_complexity)]` error: the function has a cognitive complexity of (7/1) - --> tests/ui/cognitive_complexity.rs:92:4 + --> tests/ui/cognitive_complexity.rs:93:4 | LL | fn kaboom() { | ^^^^^^ @@ -17,7 +17,7 @@ LL | fn kaboom() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:151:4 + --> tests/ui/cognitive_complexity.rs:153:4 | LL | fn baa() { | ^^^ @@ -25,7 +25,7 @@ LL | fn baa() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:153:13 + --> tests/ui/cognitive_complexity.rs:156:13 | LL | let x = || match 99 { | ^^ @@ -33,7 +33,7 @@ LL | let x = || match 99 { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:171:4 + --> tests/ui/cognitive_complexity.rs:174:4 | LL | fn bar() { | ^^^ @@ -41,7 +41,7 @@ LL | fn bar() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:183:4 + --> tests/ui/cognitive_complexity.rs:187:4 | LL | fn dont_warn_on_tests() { | ^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn dont_warn_on_tests() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:192:4 + --> tests/ui/cognitive_complexity.rs:197:4 | LL | fn barr() { | ^^^^ @@ -57,7 +57,7 @@ LL | fn barr() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (3/1) - --> tests/ui/cognitive_complexity.rs:203:4 + --> tests/ui/cognitive_complexity.rs:209:4 | LL | fn barr2() { | ^^^^^ @@ -65,7 +65,7 @@ LL | fn barr2() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:220:4 + --> tests/ui/cognitive_complexity.rs:227:4 | LL | fn barrr() { | ^^^^^ @@ -73,7 +73,7 @@ LL | fn barrr() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (3/1) - --> tests/ui/cognitive_complexity.rs:231:4 + --> tests/ui/cognitive_complexity.rs:239:4 | LL | fn barrr2() { | ^^^^^^ @@ -81,7 +81,7 @@ LL | fn barrr2() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:248:4 + --> tests/ui/cognitive_complexity.rs:257:4 | LL | fn barrrr() { | ^^^^^^ @@ -89,7 +89,7 @@ LL | fn barrrr() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (3/1) - --> tests/ui/cognitive_complexity.rs:259:4 + --> tests/ui/cognitive_complexity.rs:269:4 | LL | fn barrrr2() { | ^^^^^^^ @@ -97,7 +97,7 @@ LL | fn barrrr2() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:276:4 + --> tests/ui/cognitive_complexity.rs:287:4 | LL | fn cake() { | ^^^^ @@ -105,7 +105,7 @@ LL | fn cake() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (4/1) - --> tests/ui/cognitive_complexity.rs:287:8 + --> tests/ui/cognitive_complexity.rs:299:8 | LL | pub fn read_file(input_path: &str) -> String { | ^^^^^^^^^ @@ -113,7 +113,7 @@ LL | pub fn read_file(input_path: &str) -> String { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:319:4 + --> tests/ui/cognitive_complexity.rs:332:4 | LL | fn void(void: Void) { | ^^^^ @@ -121,7 +121,7 @@ LL | fn void(void: Void) { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (8/1) - --> tests/ui/cognitive_complexity.rs:371:4 + --> tests/ui/cognitive_complexity.rs:385:4 | LL | fn early_ret() -> i32 { | ^^^^^^^^^ @@ -129,7 +129,7 @@ LL | fn early_ret() -> i32 { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:393:13 + --> tests/ui/cognitive_complexity.rs:408:13 | LL | let x = |a: i32, b: i32| -> i32 { | ^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | let x = |a: i32, b: i32| -> i32 { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:407:8 + --> tests/ui/cognitive_complexity.rs:423:8 | LL | fn moo(&self) { | ^^^ @@ -145,7 +145,7 @@ LL | fn moo(&self) { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:417:14 + --> tests/ui/cognitive_complexity.rs:434:14 | LL | async fn a() { | ^ @@ -153,7 +153,7 @@ LL | async fn a() { = help: you could split it up into multiple smaller functions error: the function has a cognitive complexity of (2/1) - --> tests/ui/cognitive_complexity.rs:425:22 + --> tests/ui/cognitive_complexity.rs:443:22 | LL | pub async fn async_method() { | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs index 6f6e89983d2b7..a260fdee3cfd3 100644 --- a/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs +++ b/src/tools/clippy/tests/ui/cognitive_complexity_attr_used.rs @@ -7,7 +7,8 @@ fn main() { #[clippy::cognitive_complexity = "0"] fn kaboom() { - //~^ ERROR: the function has a cognitive complexity of (3/0) + //~^ cognitive_complexity + if 42 == 43 { panic!(); } else if "cake" == "lie" { diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed index c2d76146c641d..9f530ad670a0f 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed @@ -11,12 +11,14 @@ fn main() { } else if y == "world" { println!("world!") } + //~^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); } else if let Some(42) = Some(42) { println!("world!") } + //~^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); @@ -26,6 +28,7 @@ fn main() { else { println!("!") } + //~^^^^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); @@ -35,6 +38,7 @@ fn main() { else { println!("!") } + //~^^^^^^^^ collapsible_else_if if let Some(42) = Some(42) { print!("Hello "); @@ -44,6 +48,7 @@ fn main() { else { println!("!") } + //~^^^^^^^^ collapsible_else_if if let Some(42) = Some(42) { print!("Hello "); @@ -53,6 +58,7 @@ fn main() { else { println!("!") } + //~^^^^^^^^ collapsible_else_if if let Some(42) = Some(42) { print!("Hello "); @@ -62,6 +68,7 @@ fn main() { else { println!("!") } + //~^^^^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); @@ -77,4 +84,5 @@ fn main() { fn issue_7318() { if true { println!("I've been resolved!") }else if false {} + //~^^^ collapsible_else_if } diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs index 3579e46cd4479..2c646cd1d4da1 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs @@ -13,6 +13,7 @@ fn main() { println!("world!") } } + //~^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); @@ -21,6 +22,7 @@ fn main() { println!("world!") } } + //~^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); @@ -32,6 +34,7 @@ fn main() { println!("!") } } + //~^^^^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); @@ -43,6 +46,7 @@ fn main() { println!("!") } } + //~^^^^^^^^ collapsible_else_if if let Some(42) = Some(42) { print!("Hello "); @@ -54,6 +58,7 @@ fn main() { println!("!") } } + //~^^^^^^^^ collapsible_else_if if let Some(42) = Some(42) { print!("Hello "); @@ -65,6 +70,7 @@ fn main() { println!("!") } } + //~^^^^^^^^ collapsible_else_if if let Some(42) = Some(42) { print!("Hello "); @@ -76,6 +82,7 @@ fn main() { println!("!") } } + //~^^^^^^^^ collapsible_else_if if x == "hello" { print!("Hello "); @@ -93,4 +100,5 @@ fn issue_7318() { }else{ if false {} } + //~^^^ collapsible_else_if } diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.stderr b/src/tools/clippy/tests/ui/collapsible_else_if.stderr index 45566a78bd81d..7d80894cadbb4 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_else_if.stderr @@ -19,7 +19,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:19:12 + --> tests/ui/collapsible_else_if.rs:20:12 | LL | } else { | ____________^ @@ -37,7 +37,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:27:12 + --> tests/ui/collapsible_else_if.rs:29:12 | LL | } else { | ____________^ @@ -58,7 +58,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:38:12 + --> tests/ui/collapsible_else_if.rs:41:12 | LL | } else { | ____________^ @@ -79,7 +79,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:49:12 + --> tests/ui/collapsible_else_if.rs:53:12 | LL | } else { | ____________^ @@ -100,7 +100,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:60:12 + --> tests/ui/collapsible_else_if.rs:65:12 | LL | } else { | ____________^ @@ -121,7 +121,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:71:12 + --> tests/ui/collapsible_else_if.rs:77:12 | LL | } else { | ____________^ @@ -142,7 +142,7 @@ LL + } | error: this `else { if .. }` block can be collapsed - --> tests/ui/collapsible_else_if.rs:93:10 + --> tests/ui/collapsible_else_if.rs:100:10 | LL | }else{ | __________^ diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed index 44b0b6e739156..6e994018aef01 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_if.fixed @@ -15,26 +15,32 @@ fn main() { if x == "hello" && y == "world" { println!("Hello world!"); } + //~^^^^^ collapsible_if if (x == "hello" || x == "world") && (y == "world" || y == "hello") { println!("Hello world!"); } + //~^^^^^ collapsible_if if x == "hello" && x == "world" && (y == "world" || y == "hello") { println!("Hello world!"); } + //~^^^^^ collapsible_if if (x == "hello" || x == "world") && y == "world" && y == "hello" { println!("Hello world!"); } + //~^^^^^ collapsible_if if x == "hello" && x == "world" && y == "world" && y == "hello" { println!("Hello world!"); } + //~^^^^^ collapsible_if if 42 == 1337 && 'a' != 'A' { println!("world!") } + //~^^^^^ collapsible_if // Works because any if with an else statement cannot be collapsed. if x == "hello" { @@ -89,6 +95,7 @@ fn main() { if x == "hello" && y == "world" { // Collapsible println!("Hello world!"); } + //~^^^^^ collapsible_if if x == "hello" { print!("Hello "); @@ -144,9 +151,11 @@ fn main() { // Fix #5962 if matches!(true, true) && matches!(true, true) {} + //~^^^ collapsible_if // Issue #9375 if matches!(true, true) && truth() && matches!(true, true) {} + //~^^^ collapsible_if if true { #[cfg(not(teehee))] diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs index 563a273dcddda..5cf591a658c7a 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_if.rs @@ -17,36 +17,42 @@ fn main() { println!("Hello world!"); } } + //~^^^^^ collapsible_if if x == "hello" || x == "world" { if y == "world" || y == "hello" { println!("Hello world!"); } } + //~^^^^^ collapsible_if if x == "hello" && x == "world" { if y == "world" || y == "hello" { println!("Hello world!"); } } + //~^^^^^ collapsible_if if x == "hello" || x == "world" { if y == "world" && y == "hello" { println!("Hello world!"); } } + //~^^^^^ collapsible_if if x == "hello" && x == "world" { if y == "world" && y == "hello" { println!("Hello world!"); } } + //~^^^^^ collapsible_if if 42 == 1337 { if 'a' != 'A' { println!("world!") } } + //~^^^^^ collapsible_if // Works because any if with an else statement cannot be collapsed. if x == "hello" { @@ -103,6 +109,7 @@ fn main() { println!("Hello world!"); } } + //~^^^^^ collapsible_if if x == "hello" { print!("Hello "); @@ -160,11 +167,13 @@ fn main() { if matches!(true, true) { if matches!(true, true) {} } + //~^^^ collapsible_if // Issue #9375 if matches!(true, true) && truth() { if matches!(true, true) {} } + //~^^^ collapsible_if if true { #[cfg(not(teehee))] diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr index 5bcbdf2fd08da..3cc3fe5534f25 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_if.stderr @@ -18,7 +18,7 @@ LL + } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:21:5 + --> tests/ui/collapsible_if.rs:22:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" || y == "hello" { @@ -35,7 +35,7 @@ LL + } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:27:5 + --> tests/ui/collapsible_if.rs:29:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" || y == "hello" { @@ -52,7 +52,7 @@ LL + } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:33:5 + --> tests/ui/collapsible_if.rs:36:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" && y == "hello" { @@ -69,7 +69,7 @@ LL + } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:39:5 + --> tests/ui/collapsible_if.rs:43:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" && y == "hello" { @@ -86,7 +86,7 @@ LL + } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:45:5 + --> tests/ui/collapsible_if.rs:50:5 | LL | / if 42 == 1337 { LL | | if 'a' != 'A' { @@ -103,7 +103,7 @@ LL + } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:101:5 + --> tests/ui/collapsible_if.rs:107:5 | LL | / if x == "hello" { LL | | if y == "world" { // Collapsible @@ -120,7 +120,7 @@ LL + } | error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:160:5 + --> tests/ui/collapsible_if.rs:167:5 | LL | / if matches!(true, true) { LL | | if matches!(true, true) {} @@ -128,7 +128,7 @@ LL | | } | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` error: this `if` statement can be collapsed - --> tests/ui/collapsible_if.rs:165:5 + --> tests/ui/collapsible_if.rs:173:5 | LL | / if matches!(true, true) && truth() { LL | | if matches!(true, true) {} diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs index 2264b560791aa..796cabd4b669a 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.rs +++ b/src/tools/clippy/tests/ui/collapsible_match.rs @@ -12,7 +12,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // match without block match res_opt { Ok(val) => match val { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match Some(n) => foo(n), _ => return, }, @@ -22,7 +22,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // match with block match res_opt { Ok(val) => match val { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match Some(n) => foo(n), _ => return, }, @@ -32,7 +32,8 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // if let, if let if let Ok(val) = res_opt { if let Some(n) = val { - //~^ ERROR: this `if let` can be collapsed into the outer `if let` + //~^ collapsible_match + take(n); } } @@ -40,7 +41,8 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // if let else, if let else if let Ok(val) = res_opt { if let Some(n) = val { - //~^ ERROR: this `if let` can be collapsed into the outer `if let` + //~^ collapsible_match + take(n); } else { return; @@ -52,7 +54,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // if let, match if let Ok(val) = res_opt { match val { - //~^ ERROR: this `match` can be collapsed into the outer `if let` + //~^ collapsible_match Some(n) => foo(n), _ => (), } @@ -62,7 +64,8 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> match res_opt { Ok(val) => { if let Some(n) = val { - //~^ ERROR: this `if let` can be collapsed into the outer `match` + //~^ collapsible_match + take(n); } }, @@ -72,7 +75,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // if let else, match if let Ok(val) = res_opt { match val { - //~^ ERROR: this `match` can be collapsed into the outer `if let` + //~^ collapsible_match Some(n) => foo(n), _ => return, } @@ -84,7 +87,8 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> match res_opt { Ok(val) => { if let Some(n) = val { - //~^ ERROR: this `if let` can be collapsed into the outer `match` + //~^ collapsible_match + take(n); } else { return; @@ -96,7 +100,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // None in inner match same as outer wild branch match res_opt { Ok(val) => match val { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match Some(n) => foo(n), None => return, }, @@ -106,7 +110,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // None in outer match same as inner wild branch match opt_opt { Some(val) => match val { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match Some(n) => foo(n), _ => return, }, @@ -250,6 +254,7 @@ fn negative_cases(res_opt: Result, String>, res_res: Result>>() { Some(val) => match val { + //~^ collapsible_match E::A(val) | E::B(val) => foo(val), _ => return, }, @@ -281,7 +286,8 @@ pub enum Issue9647 { pub fn test_1(x: Issue9647) { if let Issue9647::A { a, .. } = x { if let Some(u) = a { - //~^ ERROR: this `if let` can be collapsed into the outer `if let` + //~^ collapsible_match + println!("{u:?}") } } @@ -290,7 +296,8 @@ pub fn test_1(x: Issue9647) { pub fn test_2(x: Issue9647) { if let Issue9647::A { a: Some(a), .. } = x { if let Some(u) = a { - //~^ ERROR: this `if let` can be collapsed into the outer `if let` + //~^ collapsible_match + println!("{u}") } } diff --git a/src/tools/clippy/tests/ui/collapsible_match.stderr b/src/tools/clippy/tests/ui/collapsible_match.stderr index 1da78b56239c7..5294a9d6975db 100644 --- a/src/tools/clippy/tests/ui/collapsible_match.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match.stderr @@ -45,6 +45,7 @@ error: this `if let` can be collapsed into the outer `if let` | LL | / if let Some(n) = val { LL | | +LL | | LL | | take(n); LL | | } | |_________^ @@ -58,10 +59,11 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:42:9 + --> tests/ui/collapsible_match.rs:43:9 | LL | / if let Some(n) = val { LL | | +LL | | LL | | take(n); LL | | } else { LL | | return; @@ -69,7 +71,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:41:15 + --> tests/ui/collapsible_match.rs:42:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -77,7 +79,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:54:9 + --> tests/ui/collapsible_match.rs:56:9 | LL | / match val { LL | | @@ -87,7 +89,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:53:15 + --> tests/ui/collapsible_match.rs:55:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -96,16 +98,17 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:64:13 + --> tests/ui/collapsible_match.rs:66:13 | LL | / if let Some(n) = val { LL | | +LL | | LL | | take(n); LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:63:12 + --> tests/ui/collapsible_match.rs:65:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -113,7 +116,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:74:9 + --> tests/ui/collapsible_match.rs:77:9 | LL | / match val { LL | | @@ -123,7 +126,7 @@ LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:73:15 + --> tests/ui/collapsible_match.rs:76:15 | LL | if let Ok(val) = res_opt { | ^^^ replace this binding @@ -132,10 +135,11 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:86:13 + --> tests/ui/collapsible_match.rs:89:13 | LL | / if let Some(n) = val { LL | | +LL | | LL | | take(n); LL | | } else { LL | | return; @@ -143,7 +147,7 @@ LL | | } | |_____________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:85:12 + --> tests/ui/collapsible_match.rs:88:12 | LL | Ok(val) => { | ^^^ replace this binding @@ -151,7 +155,7 @@ LL | if let Some(n) = val { | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:98:20 + --> tests/ui/collapsible_match.rs:102:20 | LL | Ok(val) => match val { | ____________________^ @@ -162,7 +166,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:98:12 + --> tests/ui/collapsible_match.rs:102:12 | LL | Ok(val) => match val { | ^^^ replace this binding @@ -171,7 +175,7 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:108:22 + --> tests/ui/collapsible_match.rs:112:22 | LL | Some(val) => match val { | ______________________^ @@ -182,7 +186,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:108:14 + --> tests/ui/collapsible_match.rs:112:14 | LL | Some(val) => match val { | ^^^ replace this binding @@ -191,34 +195,37 @@ LL | Some(n) => foo(n), | ^^^^^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match.rs:252:22 + --> tests/ui/collapsible_match.rs:256:22 | LL | Some(val) => match val { | ______________________^ +LL | | LL | | E::A(val) | E::B(val) => foo(val), LL | | _ => return, LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:252:14 + --> tests/ui/collapsible_match.rs:256:14 | LL | Some(val) => match val { | ^^^ replace this binding +LL | LL | E::A(val) | E::B(val) => foo(val), | ^^^^^^^^^^^^^^^^^^^^^ with this pattern error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:283:9 + --> tests/ui/collapsible_match.rs:288:9 | LL | / if let Some(u) = a { LL | | +LL | | LL | | println!("{u:?}") LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:282:27 + --> tests/ui/collapsible_match.rs:287:27 | LL | if let Issue9647::A { a, .. } = x { | ^ replace this binding @@ -226,16 +233,17 @@ LL | if let Some(u) = a { | ^^^^^^^ with this pattern, prefixed by `a`: error: this `if let` can be collapsed into the outer `if let` - --> tests/ui/collapsible_match.rs:292:9 + --> tests/ui/collapsible_match.rs:298:9 | LL | / if let Some(u) = a { LL | | +LL | | LL | | println!("{u}") LL | | } | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match.rs:291:35 + --> tests/ui/collapsible_match.rs:297:35 | LL | if let Issue9647::A { a: Some(a), .. } = x { | ^ replace this binding diff --git a/src/tools/clippy/tests/ui/collapsible_match2.rs b/src/tools/clippy/tests/ui/collapsible_match2.rs index 56801f99e4545..ba7f2f2720dc5 100644 --- a/src/tools/clippy/tests/ui/collapsible_match2.rs +++ b/src/tools/clippy/tests/ui/collapsible_match2.rs @@ -11,7 +11,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> { match res_opt { Ok(val) if make() => match val { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match Some(n) => foo(n), _ => return, }, @@ -19,7 +19,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> } match res_opt { Ok(val) => match val { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match Some(n) => foo(n), _ => return, }, @@ -34,6 +34,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> ($outer:expr => $pat:pat, $e:expr => $inner_pat:pat, $then:expr) => { match $outer { $pat => match $e { + //~^ collapsible_match $inner_pat => $then, _ => return, }, @@ -51,7 +52,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // deref reference value match Some(&[1]) { Some(s) => match *s { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match [n] => foo(n), _ => (), }, @@ -61,7 +62,7 @@ fn lint_cases(opt_opt: Option>, res_opt: Result, String> // ref pattern and deref match Some(&[1]) { Some(ref s) => match s { - //~^ ERROR: this `match` can be collapsed into the outer `match` + //~^ collapsible_match [n] => foo(n), _ => (), }, diff --git a/src/tools/clippy/tests/ui/collapsible_match2.stderr b/src/tools/clippy/tests/ui/collapsible_match2.stderr index 13caa78fbeb54..7b27306375289 100644 --- a/src/tools/clippy/tests/ui/collapsible_match2.stderr +++ b/src/tools/clippy/tests/ui/collapsible_match2.stderr @@ -45,6 +45,7 @@ error: this `match` can be collapsed into the outer `match` | LL | $pat => match $e { | _____________________________^ +LL | | LL | | $inner_pat => $then, LL | | _ => return, LL | | }, @@ -54,7 +55,7 @@ LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); | ------------------------------------------------ in this macro invocation | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match2.rs:48:28 + --> tests/ui/collapsible_match2.rs:49:28 | LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); | ^^^ ^^^^^^^ with this pattern @@ -63,7 +64,7 @@ LL | mac!(res_opt => Ok(val), val => Some(n), foo(n)); = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match2.rs:53:20 + --> tests/ui/collapsible_match2.rs:54:20 | LL | Some(s) => match *s { | ____________________^ @@ -74,7 +75,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match2.rs:53:14 + --> tests/ui/collapsible_match2.rs:54:14 | LL | Some(s) => match *s { | ^ replace this binding @@ -83,7 +84,7 @@ LL | [n] => foo(n), | ^^^ with this pattern error: this `match` can be collapsed into the outer `match` - --> tests/ui/collapsible_match2.rs:63:24 + --> tests/ui/collapsible_match2.rs:64:24 | LL | Some(ref s) => match s { | ________________________^ @@ -94,7 +95,7 @@ LL | | }, | |_________^ | help: the outer pattern can be modified to include the inner pattern - --> tests/ui/collapsible_match2.rs:63:14 + --> tests/ui/collapsible_match2.rs:64:14 | LL | Some(ref s) => match s { | ^^^^^ replace this binding diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed index 03b393d5a6749..e9a7384b761b2 100644 --- a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed +++ b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed @@ -16,32 +16,44 @@ fn main() { // LINT CASES let _ = "hesuo worpd".replace(['s', 'u'], "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace(['s', 'u'], l); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace(['s', 'u', 'p'], "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd" .replace(['s', 'u', 'p', 'd'], "l"); let _ = "hesuo world".replace([s, 'u'], "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace([s, 'u', 'p'], "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace([s, u, 'p'], "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace([s, u, p], "l"); + //~^ collapsible_str_replace let _ = "hesuo worlp".replace(['s', 'u'], "l").replace('p', "d"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace('s', "x").replace(['u', 'p'], "l"); + //~^ collapsible_str_replace // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")` let _ = "hesudo worpd".replace("su", "l").replace(['d', 'p'], "l"); + //~^ collapsible_str_replace let _ = "hesudo worpd".replace([d, 'p'], "l").replace("su", "l"); + //~^ collapsible_str_replace let _ = "hesuo world".replace([get_filter(), 's'], "l"); + //~^ collapsible_str_replace // NO LINT CASES let _ = "hesuo world".replace('s', "l").replace('u', "p"); @@ -79,4 +91,5 @@ fn msrv_1_57() { #[clippy::msrv = "1.58"] fn msrv_1_58() { let _ = "".replace(['a', 'b'], "1.58"); + //~^ collapsible_str_replace } diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.rs b/src/tools/clippy/tests/ui/collapsible_str_replace.rs index 364e5493b872e..4dc12c1b1c6e6 100644 --- a/src/tools/clippy/tests/ui/collapsible_str_replace.rs +++ b/src/tools/clippy/tests/ui/collapsible_str_replace.rs @@ -16,35 +16,48 @@ fn main() { // LINT CASES let _ = "hesuo worpd".replace('s', "l").replace('u', "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace('s', l).replace('u', l); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd" .replace('s', "l") + //~^ collapsible_str_replace .replace('u', "l") .replace('p', "l") .replace('d', "l"); let _ = "hesuo world".replace(s, "l").replace('u', "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l"); + //~^ collapsible_str_replace let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d"); + //~^ collapsible_str_replace let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l"); + //~^ collapsible_str_replace // Note: Future iterations could lint `replace(|c| matches!(c, "su" | 'd' | 'p'), "l")` let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l"); + //~^ collapsible_str_replace let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l"); + //~^ collapsible_str_replace let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l"); + //~^ collapsible_str_replace // NO LINT CASES let _ = "hesuo world".replace('s', "l").replace('u', "p"); @@ -82,4 +95,5 @@ fn msrv_1_57() { #[clippy::msrv = "1.58"] fn msrv_1_58() { let _ = "".replace('a', "1.58").replace('b', "1.58"); + //~^ collapsible_str_replace } diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr index da681dffd8757..a634b857dd461 100644 --- a/src/tools/clippy/tests/ui/collapsible_str_replace.stderr +++ b/src/tools/clippy/tests/ui/collapsible_str_replace.stderr @@ -8,83 +8,84 @@ LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l"); = help: to override `-D warnings` add `#[allow(clippy::collapsible_str_replace)]` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:20:27 + --> tests/ui/collapsible_str_replace.rs:21:27 | LL | let _ = "hesuo worpd".replace('s', l).replace('u', l); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], l)` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:22:27 + --> tests/ui/collapsible_str_replace.rs:24:27 | LL | let _ = "hesuo worpd".replace('s', "l").replace('u', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u', 'p'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:25:10 + --> tests/ui/collapsible_str_replace.rs:28:10 | LL | .replace('s', "l") | __________^ +LL | | LL | | .replace('u', "l") LL | | .replace('p', "l") LL | | .replace('d', "l"); | |__________________________^ help: replace with: `replace(['s', 'u', 'p', 'd'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:30:27 + --> tests/ui/collapsible_str_replace.rs:34:27 | LL | let _ = "hesuo world".replace(s, "l").replace('u', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:32:27 + --> tests/ui/collapsible_str_replace.rs:37:27 | LL | let _ = "hesuo worpd".replace(s, "l").replace('u', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, 'u', 'p'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:34:27 + --> tests/ui/collapsible_str_replace.rs:40:27 | LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, 'p'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:36:27 + --> tests/ui/collapsible_str_replace.rs:43:27 | LL | let _ = "hesuo worpd".replace(s, "l").replace(u, "l").replace(p, "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([s, u, p], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:38:27 + --> tests/ui/collapsible_str_replace.rs:46:27 | LL | let _ = "hesuo worlp".replace('s', "l").replace('u', "l").replace('p', "d"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['s', 'u'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:40:45 + --> tests/ui/collapsible_str_replace.rs:49:45 | LL | let _ = "hesuo worpd".replace('s', "x").replace('u', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['u', 'p'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:43:47 + --> tests/ui/collapsible_str_replace.rs:53:47 | LL | let _ = "hesudo worpd".replace("su", "l").replace('d', "l").replace('p', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['d', 'p'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:45:28 + --> tests/ui/collapsible_str_replace.rs:56:28 | LL | let _ = "hesudo worpd".replace(d, "l").replace('p', "l").replace("su", "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([d, 'p'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:47:27 + --> tests/ui/collapsible_str_replace.rs:59:27 | LL | let _ = "hesuo world".replace(get_filter(), "l").replace('s', "l"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace([get_filter(), 's'], "l")` error: used consecutive `str::replace` call - --> tests/ui/collapsible_str_replace.rs:84:16 + --> tests/ui/collapsible_str_replace.rs:97:16 | LL | let _ = "".replace('a', "1.58").replace('b', "1.58"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `replace(['a', 'b'], "1.58")` diff --git a/src/tools/clippy/tests/ui/collection_is_never_read.rs b/src/tools/clippy/tests/ui/collection_is_never_read.rs index eeb10da3402a0..77cc84fef1777 100644 --- a/src/tools/clippy/tests/ui/collection_is_never_read.rs +++ b/src/tools/clippy/tests/ui/collection_is_never_read.rs @@ -19,8 +19,8 @@ fn no_access_at_all() { fn write_without_read() { // The main use case for `collection_is_never_read`. let mut x = HashMap::new(); - //~^ ERROR: collection is never read - //~| NOTE: `-D clippy::collection-is-never-read` implied by `-D warnings` + //~^ collection_is_never_read + x.insert(1, 2); } @@ -60,7 +60,8 @@ fn read_in_closure() { fn write_in_closure() { let mut x = vec![1, 2, 3]; - //~^ ERROR: collection is never read + //~^ collection_is_never_read + let _ = || { x.push(4); }; @@ -76,13 +77,15 @@ fn shadowing_1() { let x = HashMap::::new(); // Ok let _ = x.len(); let mut x = HashMap::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(1, 2); } fn shadowing_2() { let mut x = HashMap::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(1, 2); let x = HashMap::::new(); // Ok let _ = x.len(); @@ -91,21 +94,24 @@ fn shadowing_2() { #[allow(clippy::let_unit_value)] fn fake_read_1() { let mut x = vec![1, 2, 3]; - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.reverse(); let _: () = x.clear(); } fn fake_read_2() { let mut x = vec![1, 2, 3]; - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.reverse(); println!("{:?}", x.push(5)); } fn assignment() { let mut x = vec![1, 2, 3]; - //~^ ERROR: collection is never read + //~^ collection_is_never_read + let y = vec![4, 5, 6]; // Ok x = y; } @@ -113,7 +119,8 @@ fn assignment() { #[allow(clippy::self_assignment)] fn self_assignment() { let mut x = vec![1, 2, 3]; - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x = x; } @@ -131,7 +138,8 @@ fn method_argument_but_not_target() { fn insert_is_not_a_read() { let mut x = HashSet::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(5); } @@ -146,7 +154,8 @@ fn not_read_if_return_value_not_used() { // `is_empty` does not modify the set, so it's a query. But since the return value is not used, the // lint does not consider it a read here. let x = vec![1, 2, 3]; - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.is_empty(); } @@ -182,44 +191,54 @@ fn function_argument() { fn supported_types() { let mut x = std::collections::BTreeMap::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(true, 1); let mut x = std::collections::BTreeSet::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(1); let mut x = std::collections::BinaryHeap::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.push(1); let mut x = std::collections::HashMap::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(1, 2); let mut x = std::collections::HashSet::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(1); let mut x = std::collections::LinkedList::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.push_front(1); let mut x = Some(true); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.insert(false); let mut x = String::from("hello"); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.push('!'); let mut x = Vec::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.clear(); x.push(1); let mut x = std::collections::VecDeque::new(); - //~^ ERROR: collection is never read + //~^ collection_is_never_read + x.push_front(1); } diff --git a/src/tools/clippy/tests/ui/collection_is_never_read.stderr b/src/tools/clippy/tests/ui/collection_is_never_read.stderr index f91ce07483c33..d92b84c4a6528 100644 --- a/src/tools/clippy/tests/ui/collection_is_never_read.stderr +++ b/src/tools/clippy/tests/ui/collection_is_never_read.stderr @@ -14,109 +14,109 @@ LL | let mut x = vec![1, 2, 3]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:78:5 + --> tests/ui/collection_is_never_read.rs:79:5 | LL | let mut x = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:84:5 + --> tests/ui/collection_is_never_read.rs:86:5 | LL | let mut x = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:93:5 + --> tests/ui/collection_is_never_read.rs:96:5 | LL | let mut x = vec![1, 2, 3]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:100:5 + --> tests/ui/collection_is_never_read.rs:104:5 | LL | let mut x = vec![1, 2, 3]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:107:5 + --> tests/ui/collection_is_never_read.rs:112:5 | LL | let mut x = vec![1, 2, 3]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:115:5 + --> tests/ui/collection_is_never_read.rs:121:5 | LL | let mut x = vec![1, 2, 3]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:133:5 + --> tests/ui/collection_is_never_read.rs:140:5 | LL | let mut x = HashSet::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:148:5 + --> tests/ui/collection_is_never_read.rs:156:5 | LL | let x = vec![1, 2, 3]; | ^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:184:5 + --> tests/ui/collection_is_never_read.rs:193:5 | LL | let mut x = std::collections::BTreeMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:188:5 + --> tests/ui/collection_is_never_read.rs:198:5 | LL | let mut x = std::collections::BTreeSet::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:192:5 + --> tests/ui/collection_is_never_read.rs:203:5 | LL | let mut x = std::collections::BinaryHeap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:196:5 + --> tests/ui/collection_is_never_read.rs:208:5 | LL | let mut x = std::collections::HashMap::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:200:5 + --> tests/ui/collection_is_never_read.rs:213:5 | LL | let mut x = std::collections::HashSet::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:204:5 + --> tests/ui/collection_is_never_read.rs:218:5 | LL | let mut x = std::collections::LinkedList::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:208:5 + --> tests/ui/collection_is_never_read.rs:223:5 | LL | let mut x = Some(true); | ^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:212:5 + --> tests/ui/collection_is_never_read.rs:228:5 | LL | let mut x = String::from("hello"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:216:5 + --> tests/ui/collection_is_never_read.rs:233:5 | LL | let mut x = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> tests/ui/collection_is_never_read.rs:221:5 + --> tests/ui/collection_is_never_read.rs:239:5 | LL | let mut x = std::collections::VecDeque::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/comparison_chain.rs b/src/tools/clippy/tests/ui/comparison_chain.rs index cab460d100dda..669690a4d42ce 100644 --- a/src/tools/clippy/tests/ui/comparison_chain.rs +++ b/src/tools/clippy/tests/ui/comparison_chain.rs @@ -13,7 +13,8 @@ fn f(x: u8, y: u8, z: u8) { } if x > y { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + a() } else if x < y { b() @@ -27,7 +28,8 @@ fn f(x: u8, y: u8, z: u8) { } if x > y { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + a() } else if x < y { b() @@ -36,7 +38,8 @@ fn f(x: u8, y: u8, z: u8) { } if x > y { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + a() } else if y > x { b() @@ -45,7 +48,8 @@ fn f(x: u8, y: u8, z: u8) { } if x > 1 { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + a() } else if x < 1 { b() @@ -120,14 +124,16 @@ fn g(x: f64, y: f64, z: f64) { fn h(x: T, y: T, z: T) { if x > y { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + a() } else if x < y { b() } if x > y { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + a() } else if x < y { b() @@ -136,7 +142,8 @@ fn h(x: T, y: T, z: T) { } if x > y { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + a() } else if y > x { b() @@ -242,7 +249,8 @@ const fn sign_i8(n: i8) -> Sign { fn needs_parens() -> &'static str { let (x, y) = (1, 2); if x + 1 > y * 2 { - //~^ ERROR: `if` chain can be rewritten with `match` + //~^ comparison_chain + "aa" } else if x + 1 < y * 2 { "bb" diff --git a/src/tools/clippy/tests/ui/comparison_chain.stderr b/src/tools/clippy/tests/ui/comparison_chain.stderr index 814004e3d4b16..0256573d0d906 100644 --- a/src/tools/clippy/tests/ui/comparison_chain.stderr +++ b/src/tools/clippy/tests/ui/comparison_chain.stderr @@ -3,6 +3,7 @@ error: `if` chain can be rewritten with `match` | LL | / if x > y { LL | | +LL | | LL | | a() LL | | } else if x < y { LL | | b() @@ -13,46 +14,47 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::comparison_chain)]` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:29:5 + --> tests/ui/comparison_chain.rs:30:5 | LL | / if x > y { LL | | +LL | | LL | | a() -LL | | } else if x < y { ... | LL | | c() LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:38:5 + --> tests/ui/comparison_chain.rs:40:5 | LL | / if x > y { LL | | +LL | | LL | | a() -LL | | } else if y > x { ... | LL | | c() LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:47:5 + --> tests/ui/comparison_chain.rs:50:5 | LL | / if x > 1 { LL | | +LL | | LL | | a() -LL | | } else if x < 1 { ... | LL | | c() LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&1) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:122:5 + --> tests/ui/comparison_chain.rs:126:5 | LL | / if x > y { LL | | +LL | | LL | | a() LL | | } else if x < y { LL | | b() @@ -60,36 +62,36 @@ LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:129:5 + --> tests/ui/comparison_chain.rs:134:5 | LL | / if x > y { LL | | +LL | | LL | | a() -LL | | } else if x < y { ... | LL | | c() LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:138:5 + --> tests/ui/comparison_chain.rs:144:5 | LL | / if x > y { LL | | +LL | | LL | | a() -LL | | } else if y > x { ... | LL | | c() LL | | } | |_____^ help: consider rewriting the `if` chain with `match`: `match x.cmp(&y) {...}` error: `if` chain can be rewritten with `match` - --> tests/ui/comparison_chain.rs:244:5 + --> tests/ui/comparison_chain.rs:251:5 | LL | / if x + 1 > y * 2 { LL | | +LL | | LL | | "aa" -LL | | } else if x + 1 < y * 2 { ... | LL | | "cc" LL | | } diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed index a2a3dd9086d4c..dfbb616838402 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed +++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed @@ -6,17 +6,26 @@ fn main() { // Disallow comparisons to empty let s = String::new(); let _ = s.is_empty(); + //~^ comparison_to_empty let _ = !s.is_empty(); + //~^ comparison_to_empty let v = vec![0]; let _ = v.is_empty(); + //~^ comparison_to_empty let _ = !v.is_empty(); + //~^ comparison_to_empty if (*v).is_empty() {} + //~^ comparison_to_empty let s = [0].as_slice(); if s.is_empty() {} + //~^ comparison_to_empty if s.is_empty() {} + //~^ comparison_to_empty if s.is_empty() + //~^ comparison_to_empty && s.is_empty() + //~^ comparison_to_empty {} // Allow comparisons to non-empty @@ -37,8 +46,12 @@ fn main() { // Also lint the `PartialEq` methods let s = String::new(); let _ = s.is_empty(); + //~^ comparison_to_empty let _ = !s.is_empty(); + //~^ comparison_to_empty let v = vec![0]; let _ = v.is_empty(); + //~^ comparison_to_empty let _ = !v.is_empty(); + //~^ comparison_to_empty } diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs index 7c5689a4bbec9..61cdb2bbe9f81 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.rs +++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs @@ -6,17 +6,26 @@ fn main() { // Disallow comparisons to empty let s = String::new(); let _ = s == ""; + //~^ comparison_to_empty let _ = s != ""; + //~^ comparison_to_empty let v = vec![0]; let _ = v == []; + //~^ comparison_to_empty let _ = v != []; + //~^ comparison_to_empty if let [] = &*v {} + //~^ comparison_to_empty let s = [0].as_slice(); if let [] = s {} + //~^ comparison_to_empty if let [] = &*s {} + //~^ comparison_to_empty if let [] = &*s + //~^ comparison_to_empty && s == [] + //~^ comparison_to_empty {} // Allow comparisons to non-empty @@ -37,8 +46,12 @@ fn main() { // Also lint the `PartialEq` methods let s = String::new(); let _ = s.eq(""); + //~^ comparison_to_empty let _ = s.ne(""); + //~^ comparison_to_empty let v = vec![0]; let _ = v.eq(&[]); + //~^ comparison_to_empty let _ = v.ne(&[]); + //~^ comparison_to_empty } diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr index 2ee0efc7dbb19..00a50430a3eea 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr +++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr @@ -8,73 +8,73 @@ LL | let _ = s == ""; = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:9:13 + --> tests/ui/comparison_to_empty.rs:10:13 | LL | let _ = s != ""; | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:12:13 + --> tests/ui/comparison_to_empty.rs:14:13 | LL | let _ = v == []; | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:13:13 + --> tests/ui/comparison_to_empty.rs:16:13 | LL | let _ = v != []; | ^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:14:8 + --> tests/ui/comparison_to_empty.rs:18:8 | LL | if let [] = &*v {} | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(*v).is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:16:8 + --> tests/ui/comparison_to_empty.rs:21:8 | LL | if let [] = s {} | ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:17:8 + --> tests/ui/comparison_to_empty.rs:23:8 | LL | if let [] = &*s {} | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice using `if let` - --> tests/ui/comparison_to_empty.rs:18:8 + --> tests/ui/comparison_to_empty.rs:25:8 | LL | if let [] = &*s | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:19:12 + --> tests/ui/comparison_to_empty.rs:27:12 | LL | && s == [] | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:39:13 + --> tests/ui/comparison_to_empty.rs:48:13 | LL | let _ = s.eq(""); | ^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:40:13 + --> tests/ui/comparison_to_empty.rs:50:13 | LL | let _ = s.ne(""); | ^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!s.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:42:13 + --> tests/ui/comparison_to_empty.rs:53:13 | LL | let _ = v.eq(&[]); | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `v.is_empty()` error: comparison to empty slice - --> tests/ui/comparison_to_empty.rs:43:13 + --> tests/ui/comparison_to_empty.rs:55:13 | LL | let _ = v.ne(&[]); | ^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!v.is_empty()` diff --git a/src/tools/clippy/tests/ui/const_comparisons.rs b/src/tools/clippy/tests/ui/const_comparisons.rs index 0898b4ebd4657..b732d7d142fc5 100644 --- a/src/tools/clippy/tests/ui/const_comparisons.rs +++ b/src/tools/clippy/tests/ui/const_comparisons.rs @@ -43,42 +43,39 @@ fn main() { // Correct status_code >= 400 && status_code < 500; status_code <= 400 && status_code > 500; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `400` < `500`, the expression evaluates to false for any value of `st + //~^ impossible_comparisons + status_code > 500 && status_code < 400; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `500` > `400`, the expression evaluates to false for any value of `st + //~^ impossible_comparisons + status_code < 500 && status_code > 500; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: `status_code` cannot simultaneously be greater than and less than `500` + //~^ impossible_comparisons // More complex expressions status_code < { 400 } && status_code > { 500 }; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any valu + //~^ impossible_comparisons + status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluate + //~^ impossible_comparisons + status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to f + //~^ impossible_comparisons + status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: `status_code` cannot simultaneously be greater than and less than `STATUS_S + //~^ impossible_comparisons // Comparing two different types, via the `impl PartialOrd for Status` status < { 400 } && status > { 500 }; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any valu + //~^ impossible_comparisons + status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluate + //~^ impossible_comparisons + status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to f + //~^ impossible_comparisons + status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: `status` cannot simultaneously be greater than and less than `STATUS_SERVER + //~^ impossible_comparisons // Yoda conditions // Correct @@ -87,12 +84,11 @@ fn main() { 500 <= status_code && status_code <= 600; // Incorrect 500 >= status_code && 600 < status_code; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `500` < `600`, the expression evaluates to false for any value of `st + //~^ impossible_comparisons + // Incorrect 500 >= status_code && status_code > 600; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `500` < `600`, the expression evaluates to false for any value of `st + //~^ impossible_comparisons // Yoda conditions, comparing two different types // Correct @@ -101,50 +97,49 @@ fn main() { 500 <= status && status <= 600; // Incorrect 500 >= status && 600 < status; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `500` < `600`, the expression evaluates to false for any value of `st + //~^ impossible_comparisons + // Incorrect 500 >= status && status > 600; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `500` < `600`, the expression evaluates to false for any value of `st + //~^ impossible_comparisons // Expressions where one of the sides has no effect status_code < 200 && status_code <= 299; - //~^ ERROR: right-hand side of `&&` operator has no effect + //~^ redundant_comparisons + status_code > 200 && status_code >= 299; - //~^ ERROR: left-hand side of `&&` operator has no effect + //~^ redundant_comparisons // Useless left status_code >= 500 && status_code > 500; - //~^ ERROR: left-hand side of `&&` operator has no effect + //~^ redundant_comparisons + // Useless right status_code > 500 && status_code >= 500; - //~^ ERROR: right-hand side of `&&` operator has no effect + //~^ redundant_comparisons + // Useless left status_code <= 500 && status_code < 500; - //~^ ERROR: left-hand side of `&&` operator has no effect + //~^ redundant_comparisons + // Useless right status_code < 500 && status_code <= 500; - //~^ ERROR: right-hand side of `&&` operator has no effect + //~^ redundant_comparisons // Other types let name = "Steve"; name < "Jennifer" && name > "Shannon"; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `"Jennifer"` < `"Shannon"`, the expression evaluates to false for any + //~^ impossible_comparisons let numbers = [1, 2]; numbers < [3, 4] && numbers > [5, 6]; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `[3, 4]` < `[5, 6]`, the expression evaluates to false for any value + //~^ impossible_comparisons let letter = 'a'; letter < 'b' && letter > 'c'; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `'b'` < `'c'`, the expression evaluates to false for any value of `le + //~^ impossible_comparisons let area = 42.0; area < std::f32::consts::E && area > std::f32::consts::PI; - //~^ ERROR: boolean expression will never evaluate to 'true' - //~| NOTE: since `std::f32::consts::E` < `std::f32::consts::PI`, the expression evalua + //~^ impossible_comparisons } diff --git a/src/tools/clippy/tests/ui/const_comparisons.stderr b/src/tools/clippy/tests/ui/const_comparisons.stderr index 1b8fd9733fae7..48a2c6e8d4879 100644 --- a/src/tools/clippy/tests/ui/const_comparisons.stderr +++ b/src/tools/clippy/tests/ui/const_comparisons.stderr @@ -25,7 +25,7 @@ LL | status_code < 500 && status_code > 500; = note: `status_code` cannot simultaneously be greater than and less than `500` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:56:5 + --> tests/ui/const_comparisons.rs:55:5 | LL | status_code < { 400 } && status_code > { 500 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | status_code < { 400 } && status_code > { 500 }; = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status_code` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:59:5 + --> tests/ui/const_comparisons.rs:58:5 | LL | status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | status_code < STATUS_BAD_REQUEST && status_code > STATUS_SERVER_ERROR; = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:62:5 + --> tests/ui/const_comparisons.rs:61:5 | LL | status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | status_code <= u16::MIN + 1 && status_code > STATUS_SERVER_ERROR; = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status_code` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:65:5 + --> tests/ui/const_comparisons.rs:64:5 | LL | status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | status_code < STATUS_SERVER_ERROR && status_code > STATUS_SERVER_ERROR; = note: `status_code` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:70:5 + --> tests/ui/const_comparisons.rs:68:5 | LL | status < { 400 } && status > { 500 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | status < { 400 } && status > { 500 }; = note: since `{ 400 }` < `{ 500 }`, the expression evaluates to false for any value of `status` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:73:5 + --> tests/ui/const_comparisons.rs:71:5 | LL | status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | status < STATUS_BAD_REQUEST && status > STATUS_SERVER_ERROR; = note: since `STATUS_BAD_REQUEST` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:76:5 + --> tests/ui/const_comparisons.rs:74:5 | LL | status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | status <= u16::MIN + 1 && status > STATUS_SERVER_ERROR; = note: since `u16::MIN + 1` < `STATUS_SERVER_ERROR`, the expression evaluates to false for any value of `status` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:79:5 + --> tests/ui/const_comparisons.rs:77:5 | LL | status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | status < STATUS_SERVER_ERROR && status > STATUS_SERVER_ERROR; = note: `status` cannot simultaneously be greater than and less than `STATUS_SERVER_ERROR` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:89:5 + --> tests/ui/const_comparisons.rs:86:5 | LL | 500 >= status_code && 600 < status_code; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | 500 >= status_code && 600 < status_code; = note: since `500` < `600`, the expression evaluates to false for any value of `status_code` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:93:5 + --> tests/ui/const_comparisons.rs:90:5 | LL | 500 >= status_code && status_code > 600; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | 500 >= status_code && status_code > 600; = note: since `500` < `600`, the expression evaluates to false for any value of `status_code` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:103:5 + --> tests/ui/const_comparisons.rs:99:5 | LL | 500 >= status && 600 < status; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | 500 >= status && 600 < status; = note: since `500` < `600`, the expression evaluates to false for any value of `status` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:107:5 + --> tests/ui/const_comparisons.rs:103:5 | LL | 500 >= status && status > 600; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,13 +121,13 @@ LL | 500 >= status && status > 600; = note: since `500` < `600`, the expression evaluates to false for any value of `status` error: right-hand side of `&&` operator has no effect - --> tests/ui/const_comparisons.rs:112:5 + --> tests/ui/const_comparisons.rs:107:5 | LL | status_code < 200 && status_code <= 299; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `if `status_code < 200` evaluates to true, status_code <= 299` will always evaluate to true as well - --> tests/ui/const_comparisons.rs:112:23 + --> tests/ui/const_comparisons.rs:107:23 | LL | status_code < 200 && status_code <= 299; | ^^^^^^^^^^^^^^^^^^^^^ @@ -135,67 +135,67 @@ LL | status_code < 200 && status_code <= 299; = help: to override `-D warnings` add `#[allow(clippy::redundant_comparisons)]` error: left-hand side of `&&` operator has no effect - --> tests/ui/const_comparisons.rs:114:5 + --> tests/ui/const_comparisons.rs:110:5 | LL | status_code > 200 && status_code >= 299; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `if `status_code >= 299` evaluates to true, status_code > 200` will always evaluate to true as well - --> tests/ui/const_comparisons.rs:114:5 + --> tests/ui/const_comparisons.rs:110:5 | LL | status_code > 200 && status_code >= 299; | ^^^^^^^^^^^^^^^^^^^^^ error: left-hand side of `&&` operator has no effect - --> tests/ui/const_comparisons.rs:118:5 + --> tests/ui/const_comparisons.rs:114:5 | LL | status_code >= 500 && status_code > 500; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well - --> tests/ui/const_comparisons.rs:118:5 + --> tests/ui/const_comparisons.rs:114:5 | LL | status_code >= 500 && status_code > 500; | ^^^^^^^^^^^^^^^^^^^^^^ error: right-hand side of `&&` operator has no effect - --> tests/ui/const_comparisons.rs:121:5 + --> tests/ui/const_comparisons.rs:118:5 | LL | status_code > 500 && status_code >= 500; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `if `status_code > 500` evaluates to true, status_code >= 500` will always evaluate to true as well - --> tests/ui/const_comparisons.rs:121:23 + --> tests/ui/const_comparisons.rs:118:23 | LL | status_code > 500 && status_code >= 500; | ^^^^^^^^^^^^^^^^^^^^^ error: left-hand side of `&&` operator has no effect - --> tests/ui/const_comparisons.rs:124:5 + --> tests/ui/const_comparisons.rs:122:5 | LL | status_code <= 500 && status_code < 500; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well - --> tests/ui/const_comparisons.rs:124:5 + --> tests/ui/const_comparisons.rs:122:5 | LL | status_code <= 500 && status_code < 500; | ^^^^^^^^^^^^^^^^^^^^^^ error: right-hand side of `&&` operator has no effect - --> tests/ui/const_comparisons.rs:127:5 + --> tests/ui/const_comparisons.rs:126:5 | LL | status_code < 500 && status_code <= 500; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `if `status_code < 500` evaluates to true, status_code <= 500` will always evaluate to true as well - --> tests/ui/const_comparisons.rs:127:23 + --> tests/ui/const_comparisons.rs:126:23 | LL | status_code < 500 && status_code <= 500; | ^^^^^^^^^^^^^^^^^^^^^ error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:132:5 + --> tests/ui/const_comparisons.rs:131:5 | LL | name < "Jennifer" && name > "Shannon"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,7 +203,7 @@ LL | name < "Jennifer" && name > "Shannon"; = note: since `"Jennifer"` < `"Shannon"`, the expression evaluates to false for any value of `name` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:137:5 + --> tests/ui/const_comparisons.rs:135:5 | LL | numbers < [3, 4] && numbers > [5, 6]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -211,7 +211,7 @@ LL | numbers < [3, 4] && numbers > [5, 6]; = note: since `[3, 4]` < `[5, 6]`, the expression evaluates to false for any value of `numbers` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:142:5 + --> tests/ui/const_comparisons.rs:139:5 | LL | letter < 'b' && letter > 'c'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ LL | letter < 'b' && letter > 'c'; = note: since `'b'` < `'c'`, the expression evaluates to false for any value of `letter` error: boolean expression will never evaluate to 'true' - --> tests/ui/const_comparisons.rs:147:5 + --> tests/ui/const_comparisons.rs:143:5 | LL | area < std::f32::consts::E && area > std::f32::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/const_is_empty.rs b/src/tools/clippy/tests/ui/const_is_empty.rs index b5e27b61548a0..8bb4f0e5d9750 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.rs +++ b/src/tools/clippy/tests/ui/const_is_empty.rs @@ -3,19 +3,19 @@ fn test_literal() { if "".is_empty() { - //~^ERROR: this expression always evaluates to true + //~^ const_is_empty } if "foobar".is_empty() { - //~^ERROR: this expression always evaluates to false + //~^ const_is_empty } } fn test_byte_literal() { if b"".is_empty() { - //~^ERROR: this expression always evaluates to true + //~^ const_is_empty } if b"foobar".is_empty() { - //~^ERROR: this expression always evaluates to false + //~^ const_is_empty } } @@ -32,10 +32,10 @@ fn test_propagated() { let empty2 = empty; let non_empty2 = non_empty; if empty2.is_empty() { - //~^ERROR: this expression always evaluates to true + //~^ const_is_empty } if non_empty2.is_empty() { - //~^ERROR: this expression always evaluates to false + //~^ const_is_empty } } @@ -57,48 +57,65 @@ const NON_EMPTY_REF_ARRAY: &[u32; 3] = &[1, 2, 3]; fn test_from_const() { let _ = EMPTY_STR.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = NON_EMPTY_STR.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = EMPTY_BSTR.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = NON_EMPTY_BSTR.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = EMPTY_ARRAY.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = EMPTY_ARRAY_REPEAT.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = EMPTY_U8_SLICE.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = NON_EMPTY_U8_SLICE.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = NON_EMPTY_ARRAY.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = NON_EMPTY_ARRAY_REPEAT.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = EMPTY_REF_ARRAY.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = NON_EMPTY_REF_ARRAY.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = EMPTY_SLICE.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = NON_EMPTY_SLICE.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = NON_EMPTY_SLICE_REPEAT.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty } fn main() { let value = "foobar"; let _ = value.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let x = value; let _ = x.is_empty(); - //~^ ERROR: this expression always evaluates to false + //~^ const_is_empty + let _ = "".is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty + let _ = b"".is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty } fn str_from_arg(var: &str) { @@ -152,7 +169,7 @@ fn not_cfg_conditioned() { let val = ""; #[cfg(not(target_os = "inexistent"))] let _ = val.is_empty(); - //~^ ERROR: this expression always evaluates to true + //~^ const_is_empty } const fn const_rand() -> &'static str { @@ -183,5 +200,6 @@ fn issue_13106() { const { EMPTY_STR.is_empty(); + //~^ const_is_empty } } diff --git a/src/tools/clippy/tests/ui/const_is_empty.stderr b/src/tools/clippy/tests/ui/const_is_empty.stderr index 0afba940d8b4b..2ba189058e832 100644 --- a/src/tools/clippy/tests/ui/const_is_empty.stderr +++ b/src/tools/clippy/tests/ui/const_is_empty.stderr @@ -44,121 +44,121 @@ LL | let _ = EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:61:13 + --> tests/ui/const_is_empty.rs:62:13 | LL | let _ = NON_EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:63:13 + --> tests/ui/const_is_empty.rs:65:13 | LL | let _ = EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:65:13 + --> tests/ui/const_is_empty.rs:68:13 | LL | let _ = NON_EMPTY_BSTR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:67:13 + --> tests/ui/const_is_empty.rs:71:13 | LL | let _ = EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:69:13 + --> tests/ui/const_is_empty.rs:74:13 | LL | let _ = EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:71:13 + --> tests/ui/const_is_empty.rs:77:13 | LL | let _ = EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:73:13 + --> tests/ui/const_is_empty.rs:80:13 | LL | let _ = NON_EMPTY_U8_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:75:13 + --> tests/ui/const_is_empty.rs:83:13 | LL | let _ = NON_EMPTY_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:77:13 + --> tests/ui/const_is_empty.rs:86:13 | LL | let _ = NON_EMPTY_ARRAY_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:79:13 + --> tests/ui/const_is_empty.rs:89:13 | LL | let _ = EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:81:13 + --> tests/ui/const_is_empty.rs:92:13 | LL | let _ = NON_EMPTY_REF_ARRAY.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:83:13 + --> tests/ui/const_is_empty.rs:95:13 | LL | let _ = EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:85:13 + --> tests/ui/const_is_empty.rs:98:13 | LL | let _ = NON_EMPTY_SLICE.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:87:13 + --> tests/ui/const_is_empty.rs:101:13 | LL | let _ = NON_EMPTY_SLICE_REPEAT.is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:93:13 + --> tests/ui/const_is_empty.rs:107:13 | LL | let _ = value.is_empty(); | ^^^^^^^^^^^^^^^^ error: this expression always evaluates to false - --> tests/ui/const_is_empty.rs:96:13 + --> tests/ui/const_is_empty.rs:111:13 | LL | let _ = x.is_empty(); | ^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:98:13 + --> tests/ui/const_is_empty.rs:114:13 | LL | let _ = "".is_empty(); | ^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:100:13 + --> tests/ui/const_is_empty.rs:117:13 | LL | let _ = b"".is_empty(); | ^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:154:13 + --> tests/ui/const_is_empty.rs:171:13 | LL | let _ = val.is_empty(); | ^^^^^^^^^^^^^^ error: this expression always evaluates to true - --> tests/ui/const_is_empty.rs:185:9 + --> tests/ui/const_is_empty.rs:202:9 | LL | EMPTY_STR.is_empty(); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/copy_iterator.rs b/src/tools/clippy/tests/ui/copy_iterator.rs index ea3a4face93fe..5639583289d2d 100644 --- a/src/tools/clippy/tests/ui/copy_iterator.rs +++ b/src/tools/clippy/tests/ui/copy_iterator.rs @@ -5,8 +5,8 @@ struct Countdown(u8); impl Iterator for Countdown { - //~^ ERROR: you are implementing `Iterator` on a `Copy` type - //~| NOTE: consider implementing `IntoIterator` instead + //~^ copy_iterator + type Item = u8; fn next(&mut self) -> Option { diff --git a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs index fec16671eeb32..c5767cd656e97 100644 --- a/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs +++ b/src/tools/clippy/tests/ui/crashes/associated-constant-ice.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/1698 pub trait Trait { diff --git a/src/tools/clippy/tests/ui/crashes/cc_seme.rs b/src/tools/clippy/tests/ui/crashes/cc_seme.rs index 98897d6d7aaf9..1d8e635ffe442 100644 --- a/src/tools/clippy/tests/ui/crashes/cc_seme.rs +++ b/src/tools/clippy/tests/ui/crashes/cc_seme.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/478 enum Baz { diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed b/src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.fixed similarity index 65% rename from src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed rename to src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.fixed index 837069cae6d15..681887314ed51 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.fixed +++ b/src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.fixed @@ -1,4 +1,4 @@ -#![deny(clippy::needless_lifetimes)] +#![deny(clippy::elidable_lifetime_names)] #![allow(dead_code)] trait Foo {} @@ -10,10 +10,12 @@ struct Baz<'a> { } impl Foo for Baz<'_> {} +//~^ elidable_lifetime_names impl Bar { fn baz(&self) -> impl Foo + '_ { - //~^ ERROR: the following explicit lifetimes could be elided: 'a + //~^ elidable_lifetime_names + Baz { bar: self } } } diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs b/src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.rs similarity index 66% rename from src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs rename to src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.rs index 06947e3a3513d..ed5f95bdca824 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.rs +++ b/src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.rs @@ -1,4 +1,4 @@ -#![deny(clippy::needless_lifetimes)] +#![deny(clippy::elidable_lifetime_names)] #![allow(dead_code)] trait Foo {} @@ -10,10 +10,12 @@ struct Baz<'a> { } impl<'a> Foo for Baz<'a> {} +//~^ elidable_lifetime_names impl Bar { fn baz<'a>(&'a self) -> impl Foo + 'a { - //~^ ERROR: the following explicit lifetimes could be elided: 'a + //~^ elidable_lifetime_names + Baz { bar: self } } } diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.stderr similarity index 67% rename from src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr rename to src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.stderr index bed6aab25c4d2..ef4b7e0a476e5 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr +++ b/src/tools/clippy/tests/ui/crashes/elidable_lifetime_names_impl_trait.stderr @@ -1,14 +1,14 @@ error: the following explicit lifetimes could be elided: 'a - --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:12:6 + --> tests/ui/crashes/elidable_lifetime_names_impl_trait.rs:12:6 | LL | impl<'a> Foo for Baz<'a> {} | ^^ ^^ | note: the lint level is defined here - --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:1:9 + --> tests/ui/crashes/elidable_lifetime_names_impl_trait.rs:1:9 | -LL | #![deny(clippy::needless_lifetimes)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #![deny(clippy::elidable_lifetime_names)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: elide the lifetimes | LL - impl<'a> Foo for Baz<'a> {} @@ -16,7 +16,7 @@ LL + impl Foo for Baz<'_> {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/crashes/needless_lifetimes_impl_trait.rs:15:12 + --> tests/ui/crashes/elidable_lifetime_names_impl_trait.rs:16:12 | LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^ ^^ ^^ diff --git a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs index dca32aa3b5615..bbcd599f6d0b8 100644 --- a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs +++ b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(clippy::all)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-10148.rs b/src/tools/clippy/tests/ui/crashes/ice-10148.rs index d89d94edbcdb9..8baaccd811d7c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10148.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-10148.rs @@ -6,4 +6,5 @@ use proc_macros::with_span; fn main() { println!(with_span!(""something "")); + //~^ println_empty_string } diff --git a/src/tools/clippy/tests/ui/crashes/ice-10508a.rs b/src/tools/clippy/tests/ui/crashes/ice-10508a.rs new file mode 100644 index 0000000000000..43da013445556 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-10508a.rs @@ -0,0 +1,20 @@ +//@ check-pass +// Used to overflow in `is_normalizable` + +use std::marker::PhantomData; + +struct Node { + m: PhantomData<&'static T>, +} + +struct Digit { + elem: T, +} + +enum FingerTree { + Single(T), + + Deep(Digit, Box>>), +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-10508b.rs b/src/tools/clippy/tests/ui/crashes/ice-10508b.rs new file mode 100644 index 0000000000000..7588419381cfe --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-10508b.rs @@ -0,0 +1,26 @@ +//@ check-pass + +use std::marker::PhantomData; + +struct Digit { + elem: T, +} + +struct Node { + m: PhantomData<&'static T>, +} + +enum FingerTree { + Single(T), + + Deep(Digit, Node>>), +} + +enum Wrapper { + Simple, + Other(FingerTree), +} + +fn main() { + let w = Some(Wrapper::Simple::); +} diff --git a/src/tools/clippy/tests/ui/crashes/ice-10508c.rs b/src/tools/clippy/tests/ui/crashes/ice-10508c.rs new file mode 100644 index 0000000000000..d207fdb2c87ad --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-10508c.rs @@ -0,0 +1,9 @@ +//@ check-pass + +#[derive(Debug)] +struct S { + t: T, + s: Box>, +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs b/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs deleted file mode 100644 index f3ab9cebb7c26..0000000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-10972-tait.rs +++ /dev/null @@ -1,9 +0,0 @@ -// ICE: #10972 -// asked to assemble constituent types of unexpected type: Binder(Foo, []) -#![feature(type_alias_impl_trait)] - -use std::fmt::Debug; -type Foo = impl Debug; -const FOO2: Foo = 22_u32; - -pub fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-11065.rs b/src/tools/clippy/tests/ui/crashes/ice-11065.rs index a17d7e38e0c35..434f11a2c5774 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11065.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11065.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::useless_conversion)] use std::option::IntoIter as OptionIter; diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.fixed b/src/tools/clippy/tests/ui/crashes/ice-11230.fixed index 1d4c3dd9dcc47..181e1ebbe5a3a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11230.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-11230.fixed @@ -6,6 +6,7 @@ fn main() { const A: &[for<'a> fn(&'a ())] = &[]; for v in A {} + //~^ explicit_iter_loop } // needless_collect @@ -13,4 +14,5 @@ trait Helper<'a>: Iterator {} fn x(w: &mut dyn for<'a> Helper<'a>) { w.next().is_none(); + //~^ needless_collect } diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.rs b/src/tools/clippy/tests/ui/crashes/ice-11230.rs index a16fb271497cf..fb05dc781bc0d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11230.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11230.rs @@ -6,6 +6,7 @@ fn main() { const A: &[for<'a> fn(&'a ())] = &[]; for v in A.iter() {} + //~^ explicit_iter_loop } // needless_collect @@ -13,4 +14,5 @@ trait Helper<'a>: Iterator {} fn x(w: &mut dyn for<'a> Helper<'a>) { w.collect::>().is_empty(); + //~^ needless_collect } diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.stderr b/src/tools/clippy/tests/ui/crashes/ice-11230.stderr index 7167d90e456e9..b4a3f67081aec 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11230.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-11230.stderr @@ -8,7 +8,7 @@ LL | for v in A.iter() {} = help: to override `-D warnings` add `#[allow(clippy::explicit_iter_loop)]` error: avoid using `collect()` when not needed - --> tests/ui/crashes/ice-11230.rs:15:7 + --> tests/ui/crashes/ice-11230.rs:16:7 | LL | w.collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` diff --git a/src/tools/clippy/tests/ui/crashes/ice-11337.rs b/src/tools/clippy/tests/ui/crashes/ice-11337.rs index 0bed4035f6bf4..317b7a7083a60 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11337.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11337.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(trait_alias)] trait Confusing = Fn(i32) where F: Fn(u32); diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.fixed b/src/tools/clippy/tests/ui/crashes/ice-11422.fixed index d996b1db08a63..be07a9d8c1f98 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11422.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-11422.fixed @@ -4,6 +4,7 @@ use std::fmt::Debug; use std::ops::*; fn r#gen() -> impl PartialOrd + Debug {} +//~^ implied_bounds_in_impls struct Bar {} trait Foo {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-11422.rs b/src/tools/clippy/tests/ui/crashes/ice-11422.rs index eb89b7c38f43d..43de882caa11f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11422.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11422.rs @@ -4,6 +4,7 @@ use std::fmt::Debug; use std::ops::*; fn r#gen() -> impl PartialOrd + PartialEq + Debug {} +//~^ implied_bounds_in_impls struct Bar {} trait Foo {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-11755.rs b/src/tools/clippy/tests/ui/crashes/ice-11755.rs index 367cb69985786..d6aa1e5183d22 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11755.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11755.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::unused_enumerate_index)] fn main() { diff --git a/src/tools/clippy/tests/ui/crashes/ice-11803.rs b/src/tools/clippy/tests/ui/crashes/ice-11803.rs index 1bb8bf0c746b5..e85f319093880 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11803.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11803.rs @@ -3,6 +3,8 @@ #![warn(clippy::impl_trait_in_params)] pub fn g>>() { + //~^ impl_trait_in_params + //~| impl_trait_in_params extern "C" fn implementation_detail() {} } diff --git a/src/tools/clippy/tests/ui/crashes/ice-11939.rs b/src/tools/clippy/tests/ui/crashes/ice-11939.rs index 5e7193b682646..ce7a0de1ac3a8 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-11939.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-11939.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::unit_arg, clippy::no_effect)] const fn v(_: ()) {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-12253.rs b/src/tools/clippy/tests/ui/crashes/ice-12253.rs index 41f50035144a7..58ad7c3bfbf52 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-12253.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-12253.rs @@ -1,3 +1,5 @@ +//@ check-pass + #[allow(overflowing_literals, unconditional_panic, clippy::no_effect)] fn main() { let arr: [i32; 5] = [0; 5]; diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.fixed b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed index 4ea480b0663ca..ab9c61463e92d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-12491.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-12491.fixed @@ -3,5 +3,6 @@ fn main() { if (true) { // anything一些中文 + //~^^ needless_return } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-12491.rs b/src/tools/clippy/tests/ui/crashes/ice-12491.rs index 60add6afa2c4f..b774bd3788a77 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-12491.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-12491.rs @@ -4,5 +4,6 @@ fn main() { if (true) { // anything一些中文 return; + //~^^ needless_return } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-12585.rs b/src/tools/clippy/tests/ui/crashes/ice-12585.rs index 7928115c0a943..f35e95c6bc342 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-12585.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-12585.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::unit_arg)] struct One { diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.fixed b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed index a5a5b3d1e78ed..b7840cabc6b48 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-12616.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-12616.fixed @@ -4,4 +4,5 @@ fn main() { let s = std::ptr::null::<()>; s().cast::<()>(); + //~^ ptr_as_ptr } diff --git a/src/tools/clippy/tests/ui/crashes/ice-12616.rs b/src/tools/clippy/tests/ui/crashes/ice-12616.rs index 6ee9a5ec08fe9..bb37b2e6a6791 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-12616.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-12616.rs @@ -4,4 +4,5 @@ fn main() { let s = std::ptr::null::<()>; s() as *const (); + //~^ ptr_as_ptr } diff --git a/src/tools/clippy/tests/ui/crashes/ice-13862.rs b/src/tools/clippy/tests/ui/crashes/ice-13862.rs index a5f010054b2f9..774774e6245b4 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-13862.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-13862.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![crate_type = "lib"] #![no_std] diff --git a/src/tools/clippy/tests/ui/crashes/ice-14303.rs b/src/tools/clippy/tests/ui/crashes/ice-14303.rs new file mode 100644 index 0000000000000..e81f29cd7af9f --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-14303.rs @@ -0,0 +1,12 @@ +//@check-pass +#![warn(clippy::macro_use_imports)] + +#[repr(transparent)] +pub struct X(()); + +#[repr(u8)] +pub enum Action { + Off = 0, +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-14325.rs b/src/tools/clippy/tests/ui/crashes/ice-14325.rs new file mode 100644 index 0000000000000..d762bd6c9e00e --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-14325.rs @@ -0,0 +1,17 @@ +//@check-pass + +#![allow(clippy::redundant_pattern_matching)] + +struct S<'a> { + s: &'a str, +} + +fn foo() -> Option> { + if let Some(_) = Some(0) { + Some(S { s: "xyz" }) + } else { + None + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-1588.rs b/src/tools/clippy/tests/ui/crashes/ice-1588.rs index 9ec093721c17e..3ccd33052cd6c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1588.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1588.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::all)] // Test for https://github.com/rust-lang/rust-clippy/issues/1588 diff --git a/src/tools/clippy/tests/ui/crashes/ice-1782.rs b/src/tools/clippy/tests/ui/crashes/ice-1782.rs index 73de5721cbc1c..fefdc405cce2a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1782.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1782.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code, unused_variables)] #![allow(clippy::unnecessary_cast, clippy::missing_transmute_annotations)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-1969.rs b/src/tools/clippy/tests/ui/crashes/ice-1969.rs index eb901c7672948..34ff725d71176 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-1969.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-1969.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::all)] // Test for https://github.com/rust-lang/rust-clippy/issues/1969 diff --git a/src/tools/clippy/tests/ui/crashes/ice-2499.rs b/src/tools/clippy/tests/ui/crashes/ice-2499.rs index 732f331ad145e..685c28ff4d6a1 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2499.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2499.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code, clippy::char_lit_as_u8, clippy::needless_bool)] // Should not trigger an ICE in `SpanlessHash` / `consts::constant` diff --git a/src/tools/clippy/tests/ui/crashes/ice-2594.rs b/src/tools/clippy/tests/ui/crashes/ice-2594.rs index dddf860bd1785..d4d9e74cc1933 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2594.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2594.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code, unused_variables)] /// Should not trigger an ICE in `SpanlessHash` / `consts::constant` diff --git a/src/tools/clippy/tests/ui/crashes/ice-2727.rs b/src/tools/clippy/tests/ui/crashes/ice-2727.rs index 59fb9b04b86d0..92287459424fd 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2727.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2727.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/2727 pub fn f(new: fn()) { diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs index 5f7d91abf9959..188d90fcae22a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2760.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow( unused_variables, clippy::disallowed_names, diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.fixed b/src/tools/clippy/tests/ui/crashes/ice-2774.fixed index 96cf0d8540cd9..35d969441763c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2774.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-2774.fixed @@ -13,8 +13,8 @@ pub struct Foo; #[allow(clippy::implicit_hasher)] // This should not cause a "cannot relate bound region" ICE. pub fn add_barfoos_to_foos(bars: &HashSet<&Bar>) { - //~^ ERROR: the following explicit lifetimes could be elided: 'a - //~| NOTE: `-D clippy::needless-lifetimes` implied by `-D warnings` + //~^ needless_lifetimes + let mut foos = HashSet::new(); foos.extend(bars.iter().map(|b| &b.foo)); } diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.rs b/src/tools/clippy/tests/ui/crashes/ice-2774.rs index 464d7891c9f49..1eb6df0095edd 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2774.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2774.rs @@ -13,8 +13,8 @@ pub struct Foo; #[allow(clippy::implicit_hasher)] // This should not cause a "cannot relate bound region" ICE. pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) { - //~^ ERROR: the following explicit lifetimes could be elided: 'a - //~| NOTE: `-D clippy::needless-lifetimes` implied by `-D warnings` + //~^ needless_lifetimes + let mut foos = HashSet::new(); foos.extend(bars.iter().map(|b| &b.foo)); } diff --git a/src/tools/clippy/tests/ui/crashes/ice-2862.rs b/src/tools/clippy/tests/ui/crashes/ice-2862.rs index 2573b571f55cd..e27bdba04e809 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2862.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2862.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/2862 pub trait FooMap { diff --git a/src/tools/clippy/tests/ui/crashes/ice-2865.rs b/src/tools/clippy/tests/ui/crashes/ice-2865.rs index 28363707acca7..681d10a750144 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2865.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2865.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code, clippy::extra_unused_lifetimes)] // Test for https://github.com/rust-lang/rust-clippy/issues/2865 diff --git a/src/tools/clippy/tests/ui/crashes/ice-3151.rs b/src/tools/clippy/tests/ui/crashes/ice-3151.rs index f88a26cb48592..f0c57d2f19f46 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3151.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3151.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/3151 #[derive(Clone)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs index ccd617e305dae..4ce484917ae2f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::all)] #![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-360.rs b/src/tools/clippy/tests/ui/crashes/ice-360.rs index 0d10932b0987e..cb8176a2973fb 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-360.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-360.rs @@ -3,14 +3,14 @@ fn main() {} fn no_panic(slice: &[T]) { let mut iter = slice.iter(); loop { - //~^ ERROR: this loop never actually loops - //~| ERROR: this loop could be written as a `while let` loop - //~| NOTE: `-D clippy::while-let-loop` implied by `-D warnings` + //~^ never_loop + //~| while_let_loop + let _ = match iter.next() { Some(ele) => ele, None => break, }; loop {} - //~^ ERROR: empty `loop {}` wastes CPU cycles + //~^ empty_loop } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.fixed b/src/tools/clippy/tests/ui/crashes/ice-3717.fixed index 3f54b326979c9..5581b67fa5c44 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3717.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-3717.fixed @@ -5,7 +5,8 @@ use std::collections::HashSet; fn main() {} pub fn ice_3717(_: &HashSet) { - //~^ ERROR: parameter of type `HashSet` should be generalized over different hashers + //~^ implicit_hasher + let _ = [0u8; 0]; let _: HashSet = HashSet::default(); } diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.rs b/src/tools/clippy/tests/ui/crashes/ice-3717.rs index 2890a9277c719..c612270865c57 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3717.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3717.rs @@ -5,7 +5,8 @@ use std::collections::HashSet; fn main() {} pub fn ice_3717(_: &HashSet) { - //~^ ERROR: parameter of type `HashSet` should be generalized over different hashers + //~^ implicit_hasher + let _ = [0u8; 0]; let _: HashSet = HashSet::new(); } diff --git a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr index aac72c669654a..2e53b610922e6 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3717.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-3717.stderr @@ -13,6 +13,7 @@ help: add a type parameter for `BuildHasher` | LL ~ pub fn ice_3717(_: &HashSet) { LL | +LL | LL | let _ = [0u8; 0]; LL ~ let _: HashSet = HashSet::default(); | diff --git a/src/tools/clippy/tests/ui/crashes/ice-3741.rs b/src/tools/clippy/tests/ui/crashes/ice-3741.rs index 3106a2e721694..d8c02b1ba4528 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3741.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3741.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build:proc_macro_crash.rs #![warn(clippy::suspicious_else_formatting)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-3747.rs b/src/tools/clippy/tests/ui/crashes/ice-3747.rs index 44b1d7ed1b2e8..62c7835ac55c0 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3747.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3747.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/3747 macro_rules! a { diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.rs b/src/tools/clippy/tests/ui/crashes/ice-3969.rs index ac09ce08753af..fa3ca6f1d5387 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3969.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.rs @@ -18,13 +18,12 @@ struct Dst { struct TwoStrs(str, str) where str: Sized; -//~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetime -//~| NOTE: `-D trivial-bounds` implied by `-D warnings` +//~^ ERROR: trait bound fn unsized_local() where for<'a> Dst: Sized, - //~^ ERROR: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend + //~^ ERROR: trait bound { let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); } @@ -32,7 +31,7 @@ where fn return_str() -> str where str: Sized, - //~^ ERROR: trait bound str: std::marker::Sized does not depend on any type or lifetim + //~^ ERROR: trait bound { *"Sized".to_string().into_boxed_str() } @@ -40,7 +39,7 @@ where fn use_op(s: String) -> String where String: ::std::ops::Neg, - //~^ ERROR: trait bound std::string::String: std::ops::Neg does not depend on any type + //~^ ERROR: trait bound { -s } @@ -48,7 +47,7 @@ where fn use_for() where i32: Iterator, - //~^ ERROR: trait bound i32: std::iter::Iterator does not depend on any type or lifeti + //~^ ERROR: trait bound { for _ in 2i32 {} } diff --git a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr index 285efee36bd85..b820ecf7e3326 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3969.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-3969.stderr @@ -8,25 +8,25 @@ LL | str: Sized; = help: to override `-D warnings` add `#[allow(trivial_bounds)]` error: trait bound for<'a> Dst<(dyn A + 'a)>: std::marker::Sized does not depend on any type or lifetime parameters - --> tests/ui/crashes/ice-3969.rs:26:30 + --> tests/ui/crashes/ice-3969.rs:25:30 | LL | for<'a> Dst: Sized, | ^^^^^ error: trait bound str: std::marker::Sized does not depend on any type or lifetime parameters - --> tests/ui/crashes/ice-3969.rs:34:10 + --> tests/ui/crashes/ice-3969.rs:33:10 | LL | str: Sized, | ^^^^^ error: trait bound std::string::String: std::ops::Neg does not depend on any type or lifetime parameters - --> tests/ui/crashes/ice-3969.rs:42:13 + --> tests/ui/crashes/ice-3969.rs:41:13 | LL | String: ::std::ops::Neg, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: trait bound i32: std::iter::Iterator does not depend on any type or lifetime parameters - --> tests/ui/crashes/ice-3969.rs:50:10 + --> tests/ui/crashes/ice-3969.rs:49:10 | LL | i32: Iterator, | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/crashes/ice-4121.rs b/src/tools/clippy/tests/ui/crashes/ice-4121.rs index e1a142fdcb67f..a1192b229ecd0 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4121.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4121.rs @@ -1,3 +1,5 @@ +//@ check-pass + use std::mem; pub struct Foo(A, B); diff --git a/src/tools/clippy/tests/ui/crashes/ice-4545.rs b/src/tools/clippy/tests/ui/crashes/ice-4545.rs index d9c9c2096d97c..1d7cb53ee7be0 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4545.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4545.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn repro() { trait Foo { type Bar; diff --git a/src/tools/clippy/tests/ui/crashes/ice-4579.rs b/src/tools/clippy/tests/ui/crashes/ice-4579.rs index 2e7e279f847dd..14c8113e315b7 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4579.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4579.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::single_match)] use std::ptr; diff --git a/src/tools/clippy/tests/ui/crashes/ice-4671.rs b/src/tools/clippy/tests/ui/crashes/ice-4671.rs index 64e8e7769412d..3309d51302e2e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4671.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4671.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::use_self)] #[macro_use] diff --git a/src/tools/clippy/tests/ui/crashes/ice-4727.rs b/src/tools/clippy/tests/ui/crashes/ice-4727.rs index 2a4bc83f58a55..f90c6ca9a679b 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4727.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4727.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::use_self)] #[path = "auxiliary/ice-4727-aux.rs"] diff --git a/src/tools/clippy/tests/ui/crashes/ice-4760.rs b/src/tools/clippy/tests/ui/crashes/ice-4760.rs index e1265169762fc..07387db7b2940 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4760.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4760.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(non_local_definitions)] const COUNT: usize = 2; diff --git a/src/tools/clippy/tests/ui/crashes/ice-4775.rs b/src/tools/clippy/tests/ui/crashes/ice-4775.rs index f693aafd1cbb6..dd6c6b8de25af 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4775.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4775.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::uninlined_format_args)] pub struct ArrayWrapper([usize; N]); diff --git a/src/tools/clippy/tests/ui/crashes/ice-4968.rs b/src/tools/clippy/tests/ui/crashes/ice-4968.rs index 50473868005e0..542cb63516da4 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4968.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4968.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/4968 #![warn(clippy::unsound_collection_transmute)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.rs b/src/tools/clippy/tests/ui/crashes/ice-5207.rs index 0df8b88fea2f9..6e438bcc28430 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5207.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5207.rs @@ -1,3 +1,4 @@ +//@ check-pass // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 pub async fn bar<'a, T: 'a>(_: T) {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-5223.rs b/src/tools/clippy/tests/ui/crashes/ice-5223.rs index e3b3b27a6fc38..c055e551b2983 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5223.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5223.rs @@ -1,3 +1,4 @@ +//@ check-pass // Regression test for #5233 #![warn(clippy::indexing_slicing, clippy::iter_cloned_collect)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-5238.rs b/src/tools/clippy/tests/ui/crashes/ice-5238.rs index ee2ae4f1a042e..1d7dd8c765076 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5238.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5238.rs @@ -1,3 +1,4 @@ +//@ check-pass // Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562 #![feature(coroutines, coroutine_trait, stmt_expr_attributes)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-5389.rs b/src/tools/clippy/tests/ui/crashes/ice-5389.rs index de262199004b0..b54562095a21c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5389.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5389.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::explicit_counter_loop)] fn main() { diff --git a/src/tools/clippy/tests/ui/crashes/ice-5579.rs b/src/tools/clippy/tests/ui/crashes/ice-5579.rs index 8ab36bbf93cbf..e3e408a52539e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5579.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5579.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::unnecessary_literal_unwrap)] trait IsErr { diff --git a/src/tools/clippy/tests/ui/crashes/ice-5835.1.fixed b/src/tools/clippy/tests/ui/crashes/ice-5835.1.fixed new file mode 100644 index 0000000000000..acd61a9bd6c33 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-5835.1.fixed @@ -0,0 +1,11 @@ +#[rustfmt::skip] +pub struct Foo { + /// 位 + //~^ tabs_in_doc_comments + //~| empty_line_after_doc_comments + /// ^ Do not remove this tab character. + /// It was required to trigger the ICE. + pub bar: u8, +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-5835.2.fixed b/src/tools/clippy/tests/ui/crashes/ice-5835.2.fixed new file mode 100644 index 0000000000000..71d2ec0c00186 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-5835.2.fixed @@ -0,0 +1,13 @@ +#[rustfmt::skip] +pub struct Foo { + // /// 位 + //~^ tabs_in_doc_comments + //~| empty_line_after_doc_comments + + + /// ^ Do not remove this tab character. + /// It was required to trigger the ICE. + pub bar: u8, +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-5835.fixed b/src/tools/clippy/tests/ui/crashes/ice-5835.fixed index c0532d685786d..e9c24b8e9f091 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5835.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-5835.fixed @@ -1,8 +1,7 @@ #[rustfmt::skip] pub struct Foo { + //~v tabs_in_doc_comments /// 位 - //~^ ERROR: using tabs in doc comments is not recommended - //~| NOTE: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` /// ^ Do not remove this tab character. /// It was required to trigger the ICE. pub bar: u8, diff --git a/src/tools/clippy/tests/ui/crashes/ice-5835.rs b/src/tools/clippy/tests/ui/crashes/ice-5835.rs index 122bddd6ae679..99858f45933ee 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5835.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5835.rs @@ -1,8 +1,7 @@ #[rustfmt::skip] pub struct Foo { + //~v tabs_in_doc_comments /// 位 - //~^ ERROR: using tabs in doc comments is not recommended - //~| NOTE: `-D clippy::tabs-in-doc-comments` implied by `-D warnings` /// ^ Do not remove this tab character. /// It was required to trigger the ICE. pub bar: u8, diff --git a/src/tools/clippy/tests/ui/crashes/ice-5835.stderr b/src/tools/clippy/tests/ui/crashes/ice-5835.stderr index 45e5e9a4b83d5..4ef91e4116b22 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5835.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-5835.stderr @@ -1,5 +1,5 @@ error: using tabs in doc comments is not recommended - --> tests/ui/crashes/ice-5835.rs:3:10 + --> tests/ui/crashes/ice-5835.rs:4:10 | LL | /// 位 | ^^^^ help: consider using four spaces per tab diff --git a/src/tools/clippy/tests/ui/crashes/ice-5872.fixed b/src/tools/clippy/tests/ui/crashes/ice-5872.fixed index c8e870c62fbfb..521fa15e18460 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5872.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-5872.fixed @@ -2,6 +2,5 @@ fn main() { let _ = vec![1, 2, 3].into_iter().next().is_none(); - //~^ ERROR: avoid using `collect()` when not needed - //~| NOTE: `-D clippy::needless-collect` implied by `-D warnings` + //~^ needless_collect } diff --git a/src/tools/clippy/tests/ui/crashes/ice-5872.rs b/src/tools/clippy/tests/ui/crashes/ice-5872.rs index c6ed313658922..10235ea8ab7fc 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5872.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5872.rs @@ -2,6 +2,5 @@ fn main() { let _ = vec![1, 2, 3].into_iter().collect::>().is_empty(); - //~^ ERROR: avoid using `collect()` when not needed - //~| NOTE: `-D clippy::needless-collect` implied by `-D warnings` + //~^ needless_collect } diff --git a/src/tools/clippy/tests/ui/crashes/ice-5944.rs b/src/tools/clippy/tests/ui/crashes/ice-5944.rs index ce46bc1acc1b7..2a93c5436511c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5944.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5944.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::repeat_once)] #![allow(clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-6139.rs b/src/tools/clippy/tests/ui/crashes/ice-6139.rs index f3966e47f5e80..866e13a865926 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6139.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6139.rs @@ -1,3 +1,5 @@ +//@ check-pass + trait T<'a> {} fn foo(_: Vec>>) {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-6153.rs b/src/tools/clippy/tests/ui/crashes/ice-6153.rs index 9f73f39f10d79..84873c2ecf4ce 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6153.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6153.rs @@ -1,3 +1,5 @@ +//@ check-pass + pub struct S<'a, 'e>(&'a str, &'e str); pub type T<'a, 'e> = std::collections::HashMap, ()>; diff --git a/src/tools/clippy/tests/ui/crashes/ice-6179.rs b/src/tools/clippy/tests/ui/crashes/ice-6179.rs index 91160eef03df9..640b51517f74f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6179.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6179.rs @@ -1,3 +1,4 @@ +//@ check-pass //! This is a minimal reproducer for the ICE in https://github.com/rust-lang/rust-clippy/pull/6179. //! The ICE is mainly caused by using `lower_ty`. See the discussion in the PR for details. diff --git a/src/tools/clippy/tests/ui/crashes/ice-6250.rs b/src/tools/clippy/tests/ui/crashes/ice-6250.rs index 32849f2ca6f08..65cdce7931429 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6250.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6250.rs @@ -10,6 +10,8 @@ pub fn list_data(cache: &Cache, key: usize) { if /* let */ Some(reference) = cache.data.get(key) { + //~^ ERROR: mismatched types + //~| ERROR: mismatched types unimplemented!() } } diff --git a/src/tools/clippy/tests/ui/crashes/ice-6251.rs b/src/tools/clippy/tests/ui/crashes/ice-6251.rs index 73e919b6dd2eb..a58265752ec3c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6251.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6251.rs @@ -2,5 +2,8 @@ // assertion failed: `(left == right)` ; different DefIds //@no-rustfix fn bug() -> impl Iterator { + //~^ ERROR: the size for values + //~| ERROR: the size for values + //~| ERROR: mismatched types std::iter::empty() } diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.rs b/src/tools/clippy/tests/ui/crashes/ice-6252.rs index 67fbb0ff699c7..829cb447211c3 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.rs @@ -7,8 +7,11 @@ trait TypeVal { struct Five; struct Multiply { _n: PhantomData, + //~^ ERROR: cannot find type } impl TypeVal for Multiply where N: TypeVal {} +//~^ ERROR: cannot find type +//~| ERROR: not all trait items fn main() { [1; >::VAL]; diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr index cd2031af1c6da..201a897b23195 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr @@ -10,7 +10,7 @@ LL + use std::marker::PhantomData; | error[E0412]: cannot find type `VAL` in this scope - --> tests/ui/crashes/ice-6252.rs:11:63 + --> tests/ui/crashes/ice-6252.rs:12:63 | LL | impl TypeVal for Multiply where N: TypeVal {} | ^^^ not found in this scope @@ -21,7 +21,7 @@ LL | impl TypeVal for Multiply where N: TypeVal {} | +++++ error[E0046]: not all trait items implemented, missing: `VAL` - --> tests/ui/crashes/ice-6252.rs:11:1 + --> tests/ui/crashes/ice-6252.rs:12:1 | LL | const VAL: T; | ------------ `VAL` from trait diff --git a/src/tools/clippy/tests/ui/crashes/ice-6254.rs b/src/tools/clippy/tests/ui/crashes/ice-6254.rs index aaca32ab2d93e..45144fd9e5ecb 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6254.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6254.rs @@ -1,3 +1,4 @@ +//@ check-pass // originally from ./tests/ui/pattern/usefulness/consts-opaque.rs // panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', // compiler/rustc_mir_build/src/thir/pattern/_match.rs:2030:5 diff --git a/src/tools/clippy/tests/ui/crashes/ice-6332.rs b/src/tools/clippy/tests/ui/crashes/ice-6332.rs index 9dc92aa500b2f..25660a3ce8532 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6332.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6332.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn cmark_check() { let mut link_err = false; macro_rules! cmark_error { diff --git a/src/tools/clippy/tests/ui/crashes/ice-6539.rs b/src/tools/clippy/tests/ui/crashes/ice-6539.rs index ac6c3e4aba046..cff0882cbee39 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6539.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6539.rs @@ -1,3 +1,4 @@ +//@ check-pass // The test for the ICE 6539: https://github.com/rust-lang/rust-clippy/issues/6539. // The cause is that `zero_sized_map_values` used `layout_of` with types from type aliases, // which is essentially the same as the ICE 4968. diff --git a/src/tools/clippy/tests/ui/crashes/ice-6792.rs b/src/tools/clippy/tests/ui/crashes/ice-6792.rs index 9cbafc716b500..372ce5ac06f3e 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6792.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6792.rs @@ -1,3 +1,4 @@ +//@ check-pass //! This is a reproducer for the ICE 6792: https://github.com/rust-lang/rust-clippy/issues/6792. //! The ICE is caused by using `TyCtxt::type_of(assoc_type_id)`. diff --git a/src/tools/clippy/tests/ui/crashes/ice-6793.rs b/src/tools/clippy/tests/ui/crashes/ice-6793.rs index 12a4a0d25ef5d..d83a2ee251dbd 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6793.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6793.rs @@ -1,3 +1,4 @@ +//@ check-pass //! This is a reproducer for the ICE 6793: https://github.com/rust-lang/rust-clippy/issues/6793. //! The ICE is caused by using `TyCtxt::type_of(assoc_type_id)`, which is the same as the ICE 6792. diff --git a/src/tools/clippy/tests/ui/crashes/ice-6840.rs b/src/tools/clippy/tests/ui/crashes/ice-6840.rs index d789f60c5d5a0..94481f2489987 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-6840.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-6840.rs @@ -1,3 +1,4 @@ +//@ check-pass //! This is a reproducer for the ICE 6840: https://github.com/rust-lang/rust-clippy/issues/6840. //! The ICE is caused by `TyCtxt::layout_of` and `is_normalizable` not being strict enough #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-700.rs b/src/tools/clippy/tests/ui/crashes/ice-700.rs index 5e004b94330ea..aa3bf493c201c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-700.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-700.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(clippy::all)] // Test for https://github.com/rust-lang/rust-clippy/issues/700 diff --git a/src/tools/clippy/tests/ui/crashes/ice-7012.rs b/src/tools/clippy/tests/ui/crashes/ice-7012.rs index 60bdbc4f124e7..d76995adadf1a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7012.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7012.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::all)] enum _MyOption { diff --git a/src/tools/clippy/tests/ui/crashes/ice-7126.rs b/src/tools/clippy/tests/ui/crashes/ice-7126.rs index b2dc2248b5562..f0c23c7e852d3 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7126.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7126.rs @@ -1,3 +1,4 @@ +//@ check-pass // This test requires a feature gated const fn and will stop working in the future. #![feature(const_btree_len)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-7169.fixed b/src/tools/clippy/tests/ui/crashes/ice-7169.fixed index cf4077e4d8982..71a40ad7de71a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7169.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-7169.fixed @@ -8,6 +8,5 @@ struct A { fn main() { if Ok::<_, ()>(A::::default()).is_ok() {} - //~^ ERROR: redundant pattern matching, consider using `is_ok()` - //~| NOTE: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + //~^ redundant_pattern_matching } diff --git a/src/tools/clippy/tests/ui/crashes/ice-7169.rs b/src/tools/clippy/tests/ui/crashes/ice-7169.rs index b09e6f3846327..d43e2cc164d75 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7169.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7169.rs @@ -8,6 +8,5 @@ struct A { fn main() { if let Ok(_) = Ok::<_, ()>(A::::default()) {} - //~^ ERROR: redundant pattern matching, consider using `is_ok()` - //~| NOTE: `-D clippy::redundant-pattern-matching` implied by `-D warnings` + //~^ redundant_pattern_matching } diff --git a/src/tools/clippy/tests/ui/crashes/ice-7231.rs b/src/tools/clippy/tests/ui/crashes/ice-7231.rs index 4ad0d351372f7..873cdbb0516c5 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7231.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7231.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::never_loop)] async fn f() { diff --git a/src/tools/clippy/tests/ui/crashes/ice-7272.rs b/src/tools/clippy/tests/ui/crashes/ice-7272.rs index e949038c8d0b1..e1910096418b8 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7272.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7272.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build:ice-7272-aux.rs #![allow(clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-7340.rs b/src/tools/clippy/tests/ui/crashes/ice-7340.rs index 7d2351d606f13..6c71c232fddb4 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7340.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7340.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::no_effect)] fn main() { diff --git a/src/tools/clippy/tests/ui/crashes/ice-7410.rs b/src/tools/clippy/tests/ui/crashes/ice-7410.rs index addbca54e80aa..71f00fb9aedea 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7410.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7410.rs @@ -1,3 +1,4 @@ +//@ check-pass //@compile-flags: -Clink-arg=-nostartfiles //@ignore-target: apple windows diff --git a/src/tools/clippy/tests/ui/crashes/ice-7423.rs b/src/tools/clippy/tests/ui/crashes/ice-7423.rs index 31340b012dd0e..a03981842fcc4 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7423.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7423.rs @@ -1,3 +1,5 @@ +//@ check-pass + pub trait Trait { fn f(); } diff --git a/src/tools/clippy/tests/ui/crashes/ice-7868.rs b/src/tools/clippy/tests/ui/crashes/ice-7868.rs index c6932164e3bff..727dd41aa322d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7868.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7868.rs @@ -1,3 +1,4 @@ +//@error-in-other-file: #![warn(clippy::undocumented_unsafe_blocks)] #![allow(clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-7869.rs b/src/tools/clippy/tests/ui/crashes/ice-7869.rs index 774e22f6b4c59..a5b557849abaa 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7869.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7869.rs @@ -1,5 +1,5 @@ enum Tila { - //~^ ERROR: all variants have the same prefix: `Työ` + //~^ enum_variant_names TyöAlkoi, TyöKeskeytyi, TyöValmis, diff --git a/src/tools/clippy/tests/ui/crashes/ice-7934.rs b/src/tools/clippy/tests/ui/crashes/ice-7934.rs index a4691c4131b32..c7a8d68d63b62 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7934.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7934.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::undocumented_unsafe_blocks)] #![allow(clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-8250.fixed b/src/tools/clippy/tests/ui/crashes/ice-8250.fixed index 984b61258c781..b0c2ddb2450d0 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8250.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-8250.fixed @@ -1,7 +1,7 @@ fn _f(s: &str) -> Option<()> { let _ = s[1..].split('.').next()?; - //~^ ERROR: unnecessary use of `splitn` - //~| NOTE: `-D clippy::needless-splitn` implied by `-D warnings` + //~^ needless_splitn + Some(()) } diff --git a/src/tools/clippy/tests/ui/crashes/ice-8250.rs b/src/tools/clippy/tests/ui/crashes/ice-8250.rs index c1b2e48ba3c06..ee0eb8e1eb1a2 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8250.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-8250.rs @@ -1,7 +1,7 @@ fn _f(s: &str) -> Option<()> { let _ = s[1..].splitn(2, '.').next()?; - //~^ ERROR: unnecessary use of `splitn` - //~| NOTE: `-D clippy::needless-splitn` implied by `-D warnings` + //~^ needless_splitn + Some(()) } diff --git a/src/tools/clippy/tests/ui/crashes/ice-8386.rs b/src/tools/clippy/tests/ui/crashes/ice-8386.rs index 3e38b1408d8ca..1c7a809174b6f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8386.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-8386.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn f(x: u32, mut arg: &String) {} fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-8681.rs b/src/tools/clippy/tests/ui/crashes/ice-8681.rs index 607b9caa32491..b7d6c4556bbd3 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8681.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-8681.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build: ice-8681-aux.rs #![warn(clippy::undocumented_unsafe_blocks)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-8821.rs b/src/tools/clippy/tests/ui/crashes/ice-8821.rs index fb87b79aeed87..c9fea3d1ccb8f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8821.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-8821.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::let_unit_value)] fn f() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-8850.fixed b/src/tools/clippy/tests/ui/crashes/ice-8850.fixed index 4569b9e8793e2..0e1d8d5a2aae3 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8850.fixed +++ b/src/tools/clippy/tests/ui/crashes/ice-8850.fixed @@ -2,15 +2,14 @@ fn fn_pointer_static() -> usize { static FN: fn() -> usize = || 1; FN() + 1 - //~^ ERROR: returning the result of a `let` binding from a block - //~| NOTE: `-D clippy::let-and-return` implied by `-D warnings` + //~^ let_and_return } fn fn_pointer_const() -> usize { const FN: fn() -> usize = || 1; FN() + 1 - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } fn deref_to_dyn_fn() -> usize { @@ -25,7 +24,7 @@ fn deref_to_dyn_fn() -> usize { static FN: Derefs = Derefs; FN() + 1 - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-8850.rs b/src/tools/clippy/tests/ui/crashes/ice-8850.rs index 499756ecefe98..0109911bca689 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8850.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-8850.rs @@ -2,15 +2,14 @@ fn fn_pointer_static() -> usize { static FN: fn() -> usize = || 1; let res = FN() + 1; res - //~^ ERROR: returning the result of a `let` binding from a block - //~| NOTE: `-D clippy::let-and-return` implied by `-D warnings` + //~^ let_and_return } fn fn_pointer_const() -> usize { const FN: fn() -> usize = || 1; let res = FN() + 1; res - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } fn deref_to_dyn_fn() -> usize { @@ -25,7 +24,7 @@ fn deref_to_dyn_fn() -> usize { static FN: Derefs = Derefs; let res = FN() + 1; res - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-8850.stderr b/src/tools/clippy/tests/ui/crashes/ice-8850.stderr index 5a8f24ee8c0be..1a44f103beb39 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8850.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-8850.stderr @@ -15,7 +15,7 @@ LL ~ FN() + 1 | error: returning the result of a `let` binding from a block - --> tests/ui/crashes/ice-8850.rs:12:5 + --> tests/ui/crashes/ice-8850.rs:11:5 | LL | let res = FN() + 1; | ------------------- unnecessary `let` binding @@ -29,7 +29,7 @@ LL ~ FN() + 1 | error: returning the result of a `let` binding from a block - --> tests/ui/crashes/ice-8850.rs:27:5 + --> tests/ui/crashes/ice-8850.rs:26:5 | LL | let res = FN() + 1; | ------------------- unnecessary `let` binding diff --git a/src/tools/clippy/tests/ui/crashes/ice-9041.rs b/src/tools/clippy/tests/ui/crashes/ice-9041.rs index 727d88f7fbd26..4b2a0f9531148 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9041.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9041.rs @@ -3,8 +3,7 @@ pub struct Thing; pub fn has_thing(things: &[Thing]) -> bool { let is_thing_ready = |_peer: &Thing| -> bool { todo!() }; things.iter().find(|p| is_thing_ready(p)).is_some() - //~^ ERROR: called `is_some()` after searching an `Iterator` with `find` - //~| NOTE: `-D clippy::search-is-some` implied by `-D warnings` + //~^ search_is_some } fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9238.rs b/src/tools/clippy/tests/ui/crashes/ice-9238.rs index ee6abd519f16e..cbce84305ba81 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9238.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9238.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(incomplete_features)] #![feature(generic_const_exprs)] #![warn(clippy::branches_sharing_code)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-9242.rs b/src/tools/clippy/tests/ui/crashes/ice-9242.rs index 0099e6e2f34b8..ac5bbad98c147 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9242.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9242.rs @@ -1,3 +1,5 @@ +//@ check-pass + enum E { X(), Y, diff --git a/src/tools/clippy/tests/ui/crashes/ice-9405.rs b/src/tools/clippy/tests/ui/crashes/ice-9405.rs index e2d274aeb0442..74a56f4d2ef84 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9405.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9405.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::useless_format)] #![allow(clippy::print_literal)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-9405.stderr b/src/tools/clippy/tests/ui/crashes/ice-9405.stderr index e8a73b9e782ef..96e0f2ea736a6 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9405.stderr +++ b/src/tools/clippy/tests/ui/crashes/ice-9405.stderr @@ -1,5 +1,5 @@ warning: multiple lines skipped by escaped newline - --> tests/ui/crashes/ice-9405.rs:6:10 + --> tests/ui/crashes/ice-9405.rs:8:10 | LL | "\ | __________^ diff --git a/src/tools/clippy/tests/ui/crashes/ice-9414.rs b/src/tools/clippy/tests/ui/crashes/ice-9414.rs index 02cf5d5c240fa..2341c99b23903 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9414.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9414.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::result_large_err)] trait T {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9445.rs b/src/tools/clippy/tests/ui/crashes/ice-9445.rs index c67b22f6f8c47..232b8e4a7959d 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9445.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9445.rs @@ -1,3 +1,4 @@ const UNINIT: core::mem::MaybeUninit> = core::mem::MaybeUninit::uninit(); +//~^ declare_interior_mutable_const fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9459.rs b/src/tools/clippy/tests/ui/crashes/ice-9459.rs index 55615124fcf01..43d3264b264d0 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9459.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9459.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(unsized_fn_params)] pub fn f0(_f: dyn FnOnce()) {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.rs b/src/tools/clippy/tests/ui/crashes/ice-9463.rs index fa83d25b3942d..93808e0f8923b 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9463.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9463.rs @@ -4,6 +4,5 @@ fn main() { //~^ ERROR: this arithmetic operation will overflow let _y = 1u32 >> 10000000000000u32; //~^ ERROR: this arithmetic operation will overflow - //~| ERROR: literal out of range for `u32` - //~| NOTE: the literal `10000000000000u32` does not fit into the type `u32` whose rang + //~| ERROR: literal out of range } diff --git a/src/tools/clippy/tests/ui/crashes/ice-9625.rs b/src/tools/clippy/tests/ui/crashes/ice-9625.rs index a765882b5d818..52117883aa7d6 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9625.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9625.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn main() { let x = &1; let _ = &1 < x && x < &10; diff --git a/src/tools/clippy/tests/ui/crashes/ice-9746.rs b/src/tools/clippy/tests/ui/crashes/ice-9746.rs index fbd373c70bf28..39fa8ff7a9156 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9746.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9746.rs @@ -1,3 +1,4 @@ +//@ check-pass //! trait Trait {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs index 7f5bae60d55d9..55fe418bed123 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code)] struct Foo; diff --git a/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs index c0671eaff1450..cb4685e78e22f 100644 --- a/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs +++ b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(clippy::all)] // Test for https://github.com/rust-lang/rust-clippy/issues/1336 diff --git a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs index a900fe5e6bc66..58ee751948b52 100644 --- a/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/crashes/if_same_then_else.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::comparison_chain)] #![deny(clippy::if_same_then_else)] diff --git a/src/tools/clippy/tests/ui/crashes/implements-trait.rs b/src/tools/clippy/tests/ui/crashes/implements-trait.rs index 4502b0147a83e..0e68c40be9996 100644 --- a/src/tools/clippy/tests/ui/crashes/implements-trait.rs +++ b/src/tools/clippy/tests/ui/crashes/implements-trait.rs @@ -1,3 +1,5 @@ +//@ check-pass + #[allow(clippy::needless_borrowed_reference)] fn main() { let mut v = Vec::::new(); diff --git a/src/tools/clippy/tests/ui/crashes/inherent_impl.rs b/src/tools/clippy/tests/ui/crashes/inherent_impl.rs index 800a5a383f626..87f1347ecfca0 100644 --- a/src/tools/clippy/tests/ui/crashes/inherent_impl.rs +++ b/src/tools/clippy/tests/ui/crashes/inherent_impl.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(clippy::multiple_inherent_impl)] // Test for https://github.com/rust-lang/rust-clippy/issues/4578 diff --git a/src/tools/clippy/tests/ui/crashes/issue-825.rs b/src/tools/clippy/tests/ui/crashes/issue-825.rs index e8b455a0ec67b..9bbb86e4c65af 100644 --- a/src/tools/clippy/tests/ui/crashes/issue-825.rs +++ b/src/tools/clippy/tests/ui/crashes/issue-825.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(warnings)] // Test for https://github.com/rust-lang/rust-clippy/issues/825 diff --git a/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs index bb238c81ebc05..635580c6a6e71 100644 --- a/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs +++ b/src/tools/clippy/tests/ui/crashes/issues_loop_mut_cond.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code)] /// Issue: https://github.com/rust-lang/rust-clippy/issues/2596 diff --git a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs index 626179c001557..a70623f0c51fb 100644 --- a/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs +++ b/src/tools/clippy/tests/ui/crashes/match_same_arms_const.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(clippy::match_same_arms)] // Test for https://github.com/rust-lang/rust-clippy/issues/2427 diff --git a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs index 4f61c76828db8..68e39531682a0 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs +++ b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs @@ -1,3 +1,5 @@ +//@ check-pass + #[deny(clippy::all)] #[derive(Debug)] pub enum Error { diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.fixed b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.fixed index 774dea3919396..7d7286ceb99a8 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.fixed +++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.fixed @@ -5,6 +5,6 @@ struct Foo<'a>(&'a [(); 100]); fn test(x: &Foo<'_>) {} -//~^ ERROR: this argument is passed by value, but not consumed in the function body +//~^ needless_pass_by_value fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs index f3d8871929a22..949cd5de7fb84 100644 --- a/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs +++ b/src/tools/clippy/tests/ui/crashes/needless_pass_by_value-w-late-bound.rs @@ -5,6 +5,6 @@ struct Foo<'a>(&'a [(); 100]); fn test(x: Foo<'_>) {} -//~^ ERROR: this argument is passed by value, but not consumed in the function body +//~^ needless_pass_by_value fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs index b34997d4ee0ba..8fda12fab06a8 100644 --- a/src/tools/clippy/tests/ui/crashes/regressions.rs +++ b/src/tools/clippy/tests/ui/crashes/regressions.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(clippy::disallowed_names, clippy::uninlined_format_args)] pub fn foo(bar: *const u8) { diff --git a/src/tools/clippy/tests/ui/crashes/returns.rs b/src/tools/clippy/tests/ui/crashes/returns.rs index 91cdb5306c895..ccab9522753eb 100644 --- a/src/tools/clippy/tests/ui/crashes/returns.rs +++ b/src/tools/clippy/tests/ui/crashes/returns.rs @@ -1,3 +1,4 @@ +//@ check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/1346 #[deny(warnings)] diff --git a/src/tools/clippy/tests/ui/crashes/shadow.rs b/src/tools/clippy/tests/ui/crashes/shadow.rs index 843e8ef64dcd9..237988a01681c 100644 --- a/src/tools/clippy/tests/ui/crashes/shadow.rs +++ b/src/tools/clippy/tests/ui/crashes/shadow.rs @@ -1,3 +1,5 @@ +//@ check-pass + fn main() { let x: [i32; { let u = 2; diff --git a/src/tools/clippy/tests/ui/crashes/single-match-else.rs b/src/tools/clippy/tests/ui/crashes/single-match-else.rs index 1ba7ac082132f..2ef5dd891c565 100644 --- a/src/tools/clippy/tests/ui/crashes/single-match-else.rs +++ b/src/tools/clippy/tests/ui/crashes/single-match-else.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::single_match_else)] //! Test for https://github.com/rust-lang/rust-clippy/issues/1588 diff --git a/src/tools/clippy/tests/ui/crashes/third-party/conf_allowlisted.rs b/src/tools/clippy/tests/ui/crashes/third-party/conf_allowlisted.rs index f328e4d9d04c3..20c76a4d46d94 100644 --- a/src/tools/clippy/tests/ui/crashes/third-party/conf_allowlisted.rs +++ b/src/tools/clippy/tests/ui/crashes/third-party/conf_allowlisted.rs @@ -1 +1,3 @@ +//@ check-pass + fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs index 60105a8213feb..23982fca7e7c6 100644 --- a/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs +++ b/src/tools/clippy/tests/ui/crashes/trivial_bounds.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(trivial_bounds)] #![allow(unused, trivial_bounds)] diff --git a/src/tools/clippy/tests/ui/crashes/unreachable-array-or-slice.rs b/src/tools/clippy/tests/ui/crashes/unreachable-array-or-slice.rs index e920e58d6ec6d..bc2e9aa92ce1e 100644 --- a/src/tools/clippy/tests/ui/crashes/unreachable-array-or-slice.rs +++ b/src/tools/clippy/tests/ui/crashes/unreachable-array-or-slice.rs @@ -2,6 +2,7 @@ struct Foo(isize, isize, isize, isize); pub fn main() { let Self::anything_here_kills_it(a, b, ..) = Foo(5, 5, 5, 5); + //~^ ERROR: failed to resolve match [5, 5, 5, 5] { [..] => {}, } diff --git a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs index 901eb4e503988..0fff0afdf1fef 100644 --- a/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs +++ b/src/tools/clippy/tests/ui/crashes/used_underscore_binding_macro.rs @@ -1,3 +1,5 @@ +//@ check-pass + use serde::Deserialize; /// Tests that we do not lint for unused underscores in a `MacroAttribute` diff --git a/src/tools/clippy/tests/ui/crate_in_macro_def.fixed b/src/tools/clippy/tests/ui/crate_in_macro_def.fixed index bd91389c8219d..d7d8e2a644198 100644 --- a/src/tools/clippy/tests/ui/crate_in_macro_def.fixed +++ b/src/tools/clippy/tests/ui/crate_in_macro_def.fixed @@ -16,6 +16,7 @@ mod unhygienic { macro_rules! print_message_unhygienic { () => { println!("{}", $crate::unhygienic::MESSAGE); + //~^ crate_in_macro_def }; } diff --git a/src/tools/clippy/tests/ui/crate_in_macro_def.rs b/src/tools/clippy/tests/ui/crate_in_macro_def.rs index f6fa338eedbf3..9ed9dacee48be 100644 --- a/src/tools/clippy/tests/ui/crate_in_macro_def.rs +++ b/src/tools/clippy/tests/ui/crate_in_macro_def.rs @@ -16,6 +16,7 @@ mod unhygienic { macro_rules! print_message_unhygienic { () => { println!("{}", crate::unhygienic::MESSAGE); + //~^ crate_in_macro_def }; } diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs index 5d853d97bc35b..3ded902e36b16 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,3 +1,4 @@ +//@check-pass //@ignore-target: apple #![feature(rustc_attrs)] diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs index 536e71b4a25ac..66ca97690c175 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs @@ -9,7 +9,7 @@ pub fn main() { let mut b = 1337; a = b; - //~^ ERROR: this looks like you are trying to swap `a` and `b` - //~| NOTE: or maybe you should use `core::mem::replace`? + //~^ almost_swapped + b = a; } diff --git a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs index c2c3e0958ec78..50f82b59a96ee 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/std_main_recursion.rs @@ -3,5 +3,5 @@ fn main() { println!("Hello, World!"); main(); - //~^ ERROR: recursing into entrypoint `main` + //~^ main_recursion } diff --git a/src/tools/clippy/tests/ui/create_dir.fixed b/src/tools/clippy/tests/ui/create_dir.fixed index 8fbf7dd19b83b..4a5b1b77be6be 100644 --- a/src/tools/clippy/tests/ui/create_dir.fixed +++ b/src/tools/clippy/tests/ui/create_dir.fixed @@ -8,7 +8,9 @@ fn create_dir() {} fn main() { // Should be warned create_dir_all("foo"); + //~^ create_dir create_dir_all("bar").unwrap(); + //~^ create_dir // Shouldn't be warned create_dir(); diff --git a/src/tools/clippy/tests/ui/create_dir.rs b/src/tools/clippy/tests/ui/create_dir.rs index af2c326ec4363..bf185ba3a7c33 100644 --- a/src/tools/clippy/tests/ui/create_dir.rs +++ b/src/tools/clippy/tests/ui/create_dir.rs @@ -8,7 +8,9 @@ fn create_dir() {} fn main() { // Should be warned std::fs::create_dir("foo"); + //~^ create_dir std::fs::create_dir("bar").unwrap(); + //~^ create_dir // Shouldn't be warned create_dir(); diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr index 9bb98a2606dd7..51d6ac686e027 100644 --- a/src/tools/clippy/tests/ui/create_dir.stderr +++ b/src/tools/clippy/tests/ui/create_dir.stderr @@ -13,7 +13,7 @@ LL + create_dir_all("foo"); | error: calling `std::fs::create_dir` where there may be a better way - --> tests/ui/create_dir.rs:11:5 + --> tests/ui/create_dir.rs:12:5 | LL | std::fs::create_dir("bar").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed index bda9221a5e1e9..fd1a0d8934b3c 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed @@ -3,28 +3,31 @@ fn foo(n: u32) -> u32 { if let Some(n) = n.checked_sub(4) { n } else { n } - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } fn bar(_: ()) {} fn factorial(n: u32) -> u32 { if n <= 1 { - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + 1 - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } else { n * factorial(n - 1) - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } } fn main() { 42; - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + foo(3) + factorial(4); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + (1, 2, 3, 4, 5); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } fn issue9914() { @@ -41,21 +44,26 @@ fn issue9914() { macro_rules! expand_to_dbg { () => { - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro }; } - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + #[allow(clippy::let_unit_value)] let _ = (); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + bar(()); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + foo!(()); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + foo2!(foo!(())); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + expand_to_dbg!(); } @@ -77,35 +85,36 @@ mod issue7274 { struct MyThing; define_thing!(MyThing, { 2; - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro }); } #[test] pub fn issue8481() { 1; - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } #[cfg(test)] fn foo2() { 1; - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } #[cfg(test)] mod mod1 { fn func() { 1; - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } } mod issue12131 { fn dbg_in_print(s: &str) { println!("dbg: {:?}", s); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + print!("{}", s); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } } diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs index 8244254026be7..c96e2c7251c29 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs @@ -3,28 +3,31 @@ fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } fn bar(_: ()) {} fn factorial(n: u32) -> u32 { if dbg!(n <= 1) { - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + dbg!(1) - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } else { dbg!(n * factorial(n - 1)) - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } } fn main() { dbg!(42); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + foo(3) + dbg!(factorial(4)); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + dbg!(1, 2, 3, 4, 5); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } fn issue9914() { @@ -41,21 +44,26 @@ fn issue9914() { macro_rules! expand_to_dbg { () => { dbg!(); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro }; } dbg!(); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + #[allow(clippy::let_unit_value)] let _ = dbg!(); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + bar(dbg!()); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + foo!(dbg!()); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + foo2!(foo!(dbg!())); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + expand_to_dbg!(); } @@ -77,35 +85,36 @@ mod issue7274 { struct MyThing; define_thing!(MyThing, { dbg!(2); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro }); } #[test] pub fn issue8481() { dbg!(1); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } #[cfg(test)] fn foo2() { dbg!(1); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } #[cfg(test)] mod mod1 { fn func() { dbg!(1); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } } mod issue12131 { fn dbg_in_print(s: &str) { println!("dbg: {:?}", dbg!(s)); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + print!("{}", dbg!(s)); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro } } diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr index f218614fdd622..cd6dce584a2fa 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr @@ -25,7 +25,7 @@ LL + if n <= 1 { | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:13:9 + --> tests/ui/dbg_macro/dbg_macro.rs:14:9 | LL | dbg!(1) | ^^^^^^^ @@ -37,7 +37,7 @@ LL + 1 | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:16:9 + --> tests/ui/dbg_macro/dbg_macro.rs:17:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:22:5 + --> tests/ui/dbg_macro/dbg_macro.rs:23:5 | LL | dbg!(42); | ^^^^^^^^ @@ -61,7 +61,7 @@ LL + 42; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:24:14 + --> tests/ui/dbg_macro/dbg_macro.rs:26:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + foo(3) + factorial(4); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:26:5 + --> tests/ui/dbg_macro/dbg_macro.rs:29:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + (1, 2, 3, 4, 5); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:48:5 + --> tests/ui/dbg_macro/dbg_macro.rs:51:5 | LL | dbg!(); | ^^^^^^ @@ -96,7 +96,7 @@ LL - dbg!(); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:51:13 + --> tests/ui/dbg_macro/dbg_macro.rs:55:13 | LL | let _ = dbg!(); | ^^^^^^ @@ -108,7 +108,7 @@ LL + let _ = (); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:53:9 + --> tests/ui/dbg_macro/dbg_macro.rs:58:9 | LL | bar(dbg!()); | ^^^^^^ @@ -120,7 +120,7 @@ LL + bar(()); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:55:10 + --> tests/ui/dbg_macro/dbg_macro.rs:61:10 | LL | foo!(dbg!()); | ^^^^^^ @@ -132,7 +132,7 @@ LL + foo!(()); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:57:16 + --> tests/ui/dbg_macro/dbg_macro.rs:64:16 | LL | foo2!(foo!(dbg!())); | ^^^^^^ @@ -144,7 +144,7 @@ LL + foo2!(foo!(())); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:43:13 + --> tests/ui/dbg_macro/dbg_macro.rs:46:13 | LL | dbg!(); | ^^^^^^ @@ -159,7 +159,7 @@ LL - dbg!(); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:79:9 + --> tests/ui/dbg_macro/dbg_macro.rs:87:9 | LL | dbg!(2); | ^^^^^^^ @@ -171,7 +171,7 @@ LL + 2; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:86:5 + --> tests/ui/dbg_macro/dbg_macro.rs:94:5 | LL | dbg!(1); | ^^^^^^^ @@ -183,7 +183,7 @@ LL + 1; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:92:5 + --> tests/ui/dbg_macro/dbg_macro.rs:100:5 | LL | dbg!(1); | ^^^^^^^ @@ -195,7 +195,7 @@ LL + 1; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:99:9 + --> tests/ui/dbg_macro/dbg_macro.rs:107:9 | LL | dbg!(1); | ^^^^^^^ @@ -207,7 +207,7 @@ LL + 1; | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:106:31 + --> tests/ui/dbg_macro/dbg_macro.rs:114:31 | LL | println!("dbg: {:?}", dbg!(s)); | ^^^^^^^ @@ -219,7 +219,7 @@ LL + println!("dbg: {:?}", s); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro.rs:108:22 + --> tests/ui/dbg_macro/dbg_macro.rs:117:22 | LL | print!("{}", dbg!(s)); | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs index 0e83766ccaec7..1a5119651b539 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.rs @@ -1,4 +1,5 @@ //@no-rustfix +//@error-in-other-file: #![warn(clippy::dbg_macro)] #[path = "auxiliary/submodule.rs"] @@ -6,7 +7,11 @@ mod submodule; fn main() { dbg!(dbg!(dbg!(42))); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + //~| dbg_macro + //~| dbg_macro + dbg!(1, 2, dbg!(3, 4)); - //~^ ERROR: the `dbg!` macro is intended as a debugging tool + //~^ dbg_macro + //~| dbg_macro } diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr index e8d5f9f2f46f0..afade6f08b3c4 100644 --- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro_unfixable.stderr @@ -12,7 +12,7 @@ LL - dbg!(); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:5 + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:9:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL + dbg!(dbg!(42)); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:10 + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:9:10 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL + dbg!(dbg!(42)); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:8:15 + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:9:15 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^ @@ -48,7 +48,7 @@ LL + dbg!(dbg!(42)); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:10:5 + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:14:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + (1, 2, dbg!(3, 4)); | error: the `dbg!` macro is intended as a debugging tool - --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:10:16 + --> tests/ui/dbg_macro/dbg_macro_unfixable.rs:14:16 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs index 8d04be777c7b8..74d59b7593fa7 100644 --- a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs +++ b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.rs @@ -40,20 +40,26 @@ fn func_non_mutable() { fn func_mutable() { debug_assert!(bool_mut(&mut 3)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` - //~| NOTE: `-D clippy::debug-assert-with-mut-call` implied by `-D warnings` + //~^ debug_assert_with_mut_call + + debug_assert!(!bool_mut(&mut 3)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + debug_assert_eq!(0, u32_mut(&mut 3)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + debug_assert_eq!(u32_mut(&mut 3), 0); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + debug_assert_ne!(1, u32_mut(&mut 3)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_ne!` + //~^ debug_assert_with_mut_call + debug_assert_ne!(u32_mut(&mut 3), 1); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_ne!` + //~^ debug_assert_with_mut_call + } fn method_non_mutable() { @@ -69,33 +75,46 @@ fn method_non_mutable() { fn method_mutable() { debug_assert!(S.bool_self_mut()); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + debug_assert!(!S.bool_self_mut()); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + debug_assert!(S.bool_self_ref_arg_mut(&mut 3)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + debug_assert!(S.bool_self_mut_arg_ref(&3)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + debug_assert!(S.bool_self_mut_arg_mut(&mut 3)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + debug_assert_eq!(S.u32_self_mut(), 0); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + debug_assert_ne!(S.u32_self_mut(), 1); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_ne!` + //~^ debug_assert_with_mut_call + debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_ne!` + //~^ debug_assert_with_mut_call + debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_ne!` + //~^ debug_assert_with_mut_call + debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_ne!` + //~^ debug_assert_with_mut_call + } fn misc() { @@ -104,35 +123,43 @@ fn misc() { debug_assert_eq!(v.get(0), Some(&1)); debug_assert_ne!(v[0], 2); debug_assert_eq!(v.pop(), Some(1)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + debug_assert_ne!(Some(3), v.pop()); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_ne!` + //~^ debug_assert_with_mut_call + let a = &mut 3; debug_assert!(bool_mut(a)); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + // nested debug_assert!(!(bool_ref(&u32_mut(&mut 3)))); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + // chained debug_assert_eq!(v.pop().unwrap(), 3); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert_eq!` + //~^ debug_assert_with_mut_call + // format args debug_assert!(bool_ref(&3), "w/o format"); debug_assert!(bool_mut(&mut 3), "w/o format"); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + debug_assert!(bool_ref(&3), "{} format", "w/"); debug_assert!(bool_mut(&mut 3), "{} format", "w/"); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert!` + //~^ debug_assert_with_mut_call + // sub block let mut x = 42_u32; debug_assert!({ bool_mut(&mut x); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert! + //~^ debug_assert_with_mut_call + x > 10 }); @@ -140,7 +167,8 @@ fn misc() { debug_assert!((|| { let mut x = 42; bool_mut(&mut x); - //~^ ERROR: do not call a function with mutable arguments inside of `debug_assert! + //~^ debug_assert_with_mut_call + x > 10 })()); } diff --git a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr index 83e1105a07dff..216ab27264c15 100644 --- a/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr +++ b/src/tools/clippy/tests/ui/debug_assert_with_mut_call.stderr @@ -8,163 +8,163 @@ LL | debug_assert!(bool_mut(&mut 3)); = help: to override `-D warnings` add `#[allow(clippy::debug_assert_with_mut_call)]` error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:45:20 + --> tests/ui/debug_assert_with_mut_call.rs:46:20 | LL | debug_assert!(!bool_mut(&mut 3)); | ^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:48:25 + --> tests/ui/debug_assert_with_mut_call.rs:50:25 | LL | debug_assert_eq!(0, u32_mut(&mut 3)); | ^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:50:22 + --> tests/ui/debug_assert_with_mut_call.rs:53:22 | LL | debug_assert_eq!(u32_mut(&mut 3), 0); | ^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_ne!` - --> tests/ui/debug_assert_with_mut_call.rs:53:25 + --> tests/ui/debug_assert_with_mut_call.rs:57:25 | LL | debug_assert_ne!(1, u32_mut(&mut 3)); | ^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_ne!` - --> tests/ui/debug_assert_with_mut_call.rs:55:22 + --> tests/ui/debug_assert_with_mut_call.rs:60:22 | LL | debug_assert_ne!(u32_mut(&mut 3), 1); | ^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:71:19 + --> tests/ui/debug_assert_with_mut_call.rs:77:19 | LL | debug_assert!(S.bool_self_mut()); | ^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:73:20 + --> tests/ui/debug_assert_with_mut_call.rs:80:20 | LL | debug_assert!(!S.bool_self_mut()); | ^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:75:19 + --> tests/ui/debug_assert_with_mut_call.rs:83:19 | LL | debug_assert!(S.bool_self_ref_arg_mut(&mut 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:77:19 + --> tests/ui/debug_assert_with_mut_call.rs:86:19 | LL | debug_assert!(S.bool_self_mut_arg_ref(&3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:79:19 + --> tests/ui/debug_assert_with_mut_call.rs:89:19 | LL | debug_assert!(S.bool_self_mut_arg_mut(&mut 3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:82:22 + --> tests/ui/debug_assert_with_mut_call.rs:93:22 | LL | debug_assert_eq!(S.u32_self_mut(), 0); | ^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:84:22 + --> tests/ui/debug_assert_with_mut_call.rs:96:22 | LL | debug_assert_eq!(S.u32_self_mut_arg_ref(&3), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:86:22 + --> tests/ui/debug_assert_with_mut_call.rs:99:22 | LL | debug_assert_eq!(S.u32_self_ref_arg_mut(&mut 3), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:88:22 + --> tests/ui/debug_assert_with_mut_call.rs:102:22 | LL | debug_assert_eq!(S.u32_self_mut_arg_mut(&mut 3), 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_ne!` - --> tests/ui/debug_assert_with_mut_call.rs:91:22 + --> tests/ui/debug_assert_with_mut_call.rs:106:22 | LL | debug_assert_ne!(S.u32_self_mut(), 1); | ^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_ne!` - --> tests/ui/debug_assert_with_mut_call.rs:93:22 + --> tests/ui/debug_assert_with_mut_call.rs:109:22 | LL | debug_assert_ne!(S.u32_self_mut_arg_ref(&3), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_ne!` - --> tests/ui/debug_assert_with_mut_call.rs:95:22 + --> tests/ui/debug_assert_with_mut_call.rs:112:22 | LL | debug_assert_ne!(S.u32_self_ref_arg_mut(&mut 3), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_ne!` - --> tests/ui/debug_assert_with_mut_call.rs:97:22 + --> tests/ui/debug_assert_with_mut_call.rs:115:22 | LL | debug_assert_ne!(S.u32_self_mut_arg_mut(&mut 3), 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:106:22 + --> tests/ui/debug_assert_with_mut_call.rs:125:22 | LL | debug_assert_eq!(v.pop(), Some(1)); | ^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_ne!` - --> tests/ui/debug_assert_with_mut_call.rs:108:31 + --> tests/ui/debug_assert_with_mut_call.rs:128:31 | LL | debug_assert_ne!(Some(3), v.pop()); | ^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:112:19 + --> tests/ui/debug_assert_with_mut_call.rs:133:19 | LL | debug_assert!(bool_mut(a)); | ^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:116:31 + --> tests/ui/debug_assert_with_mut_call.rs:138:31 | LL | debug_assert!(!(bool_ref(&u32_mut(&mut 3)))); | ^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert_eq!` - --> tests/ui/debug_assert_with_mut_call.rs:120:22 + --> tests/ui/debug_assert_with_mut_call.rs:143:22 | LL | debug_assert_eq!(v.pop().unwrap(), 3); | ^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:125:19 + --> tests/ui/debug_assert_with_mut_call.rs:149:19 | LL | debug_assert!(bool_mut(&mut 3), "w/o format"); | ^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:128:19 + --> tests/ui/debug_assert_with_mut_call.rs:153:19 | LL | debug_assert!(bool_mut(&mut 3), "{} format", "w/"); | ^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:134:9 + --> tests/ui/debug_assert_with_mut_call.rs:160:9 | LL | bool_mut(&mut x); | ^^^^^^^^^^^^^^^^ error: do not call a function with mutable arguments inside of `debug_assert!` - --> tests/ui/debug_assert_with_mut_call.rs:142:9 + --> tests/ui/debug_assert_with_mut_call.rs:169:9 | LL | bool_mut(&mut x); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.fixed b/src/tools/clippy/tests/ui/decimal_literal_representation.fixed index e34f48b65dd1f..e0477578488c9 100644 --- a/src/tools/clippy/tests/ui/decimal_literal_representation.fixed +++ b/src/tools/clippy/tests/ui/decimal_literal_representation.fixed @@ -14,12 +14,19 @@ fn main() { ); let bad = ( // Hex: 0x8005, // 0x8005 + //~^ decimal_literal_representation 0xFF00, // 0xFF00 + //~^ decimal_literal_representation 0x7F0F_F00F, // 0x7F0F_F00F + //~^ decimal_literal_representation 0x7FFF_FFFF, // 0x7FFF_FFFF + //~^ decimal_literal_representation #[allow(overflowing_literals)] 0xF0F0_F0F0, // 0xF0F0_F0F0 + //~^ decimal_literal_representation 0x8005_usize, // 0x8005_usize + //~^ decimal_literal_representation 0x7F0F_F00F_isize, // 0x7F0F_F00F_isize + //~^ decimal_literal_representation ); } diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.rs b/src/tools/clippy/tests/ui/decimal_literal_representation.rs index bcc4d0df9c0e1..85dc4fac09289 100644 --- a/src/tools/clippy/tests/ui/decimal_literal_representation.rs +++ b/src/tools/clippy/tests/ui/decimal_literal_representation.rs @@ -14,12 +14,19 @@ fn main() { ); let bad = ( // Hex: 32_773, // 0x8005 + //~^ decimal_literal_representation 65_280, // 0xFF00 + //~^ decimal_literal_representation 2_131_750_927, // 0x7F0F_F00F + //~^ decimal_literal_representation 2_147_483_647, // 0x7FFF_FFFF + //~^ decimal_literal_representation #[allow(overflowing_literals)] 4_042_322_160, // 0xF0F0_F0F0 + //~^ decimal_literal_representation 32_773usize, // 0x8005_usize + //~^ decimal_literal_representation 2_131_750_927isize, // 0x7F0F_F00F_isize + //~^ decimal_literal_representation ); } diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.stderr b/src/tools/clippy/tests/ui/decimal_literal_representation.stderr index 824e7ec85ee00..0196350ce402b 100644 --- a/src/tools/clippy/tests/ui/decimal_literal_representation.stderr +++ b/src/tools/clippy/tests/ui/decimal_literal_representation.stderr @@ -8,37 +8,37 @@ LL | 32_773, // 0x8005 = help: to override `-D warnings` add `#[allow(clippy::decimal_literal_representation)]` error: integer literal has a better hexadecimal representation - --> tests/ui/decimal_literal_representation.rs:17:9 + --> tests/ui/decimal_literal_representation.rs:18:9 | LL | 65_280, // 0xFF00 | ^^^^^^ help: consider: `0xFF00` error: integer literal has a better hexadecimal representation - --> tests/ui/decimal_literal_representation.rs:18:9 + --> tests/ui/decimal_literal_representation.rs:20:9 | LL | 2_131_750_927, // 0x7F0F_F00F | ^^^^^^^^^^^^^ help: consider: `0x7F0F_F00F` error: integer literal has a better hexadecimal representation - --> tests/ui/decimal_literal_representation.rs:19:9 + --> tests/ui/decimal_literal_representation.rs:22:9 | LL | 2_147_483_647, // 0x7FFF_FFFF | ^^^^^^^^^^^^^ help: consider: `0x7FFF_FFFF` error: integer literal has a better hexadecimal representation - --> tests/ui/decimal_literal_representation.rs:21:9 + --> tests/ui/decimal_literal_representation.rs:25:9 | LL | 4_042_322_160, // 0xF0F0_F0F0 | ^^^^^^^^^^^^^ help: consider: `0xF0F0_F0F0` error: integer literal has a better hexadecimal representation - --> tests/ui/decimal_literal_representation.rs:22:9 + --> tests/ui/decimal_literal_representation.rs:27:9 | LL | 32_773usize, // 0x8005_usize | ^^^^^^^^^^^ help: consider: `0x8005_usize` error: integer literal has a better hexadecimal representation - --> tests/ui/decimal_literal_representation.rs:23:9 + --> tests/ui/decimal_literal_representation.rs:29:9 | LL | 2_131_750_927isize, // 0x7F0F_F00F_isize | ^^^^^^^^^^^^^^^^^^ help: consider: `0x7F0F_F00F_isize` diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs index a88bf7b21b8b7..c87468277fb31 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs @@ -9,7 +9,8 @@ enum OptionalCell { } // a constant with enums should be linted only when the used variant is unfrozen (#3962). -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR: interior mutable +const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); +//~^ declare_interior_mutable_const const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; const fn unfrozen_variant() -> OptionalCell { @@ -20,7 +21,8 @@ const fn frozen_variant() -> OptionalCell { OptionalCell::Frozen } -const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR: interior mutable +const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); +//~^ declare_interior_mutable_const const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); enum NestedInnermost { @@ -43,7 +45,7 @@ struct NestedOutermost { // a constant with enums should be linted according to its value, no matter how structs involve. const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - //~^ ERROR: interior mutable + //~^ declare_interior_mutable_const outer: NestedOuter::NestedInner(NestedInner { inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), }), @@ -57,11 +59,14 @@ const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { trait AssocConsts { // When there's no default value, lint it only according to its type. // Further details are on the corresponding code (`NonCopyConst::check_trait_item`). - const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR: interior mutable - const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR: interior mutable + const TO_BE_UNFROZEN_VARIANT: OptionalCell; + //~^ declare_interior_mutable_const + const TO_BE_FROZEN_VARIANT: OptionalCell; + //~^ declare_interior_mutable_const // Lint default values accordingly. - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR: interior mutable + const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); + //~^ declare_interior_mutable_const const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; } @@ -87,7 +92,8 @@ trait AssocTypes { impl AssocTypes for u64 { type ToBeUnfrozen = AtomicUsize; - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR: interior mutable + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); + //~^ declare_interior_mutable_const const TO_BE_FROZEN_VARIANT: Option = None; } @@ -99,25 +105,30 @@ enum BothOfCellAndGeneric { } impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR: interior mutable + const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); + //~^ declare_interior_mutable_const // This is a false positive. The argument about this is on `is_value_unfrozen_raw` - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR: interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); + //~^ declare_interior_mutable_const const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); // This is what is likely to be a false negative when one tries to fix // the `GENERIC_VARIANT` false positive. - const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR: interior mutable + const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); + //~^ declare_interior_mutable_const } // associated types here is basically the same as the one above. trait BothOfCellAndGenericWithAssocType { type AssocType; - const UNFROZEN_VARIANT: BothOfCellAndGeneric = //~ ERROR: interior mutable + const UNFROZEN_VARIANT: BothOfCellAndGeneric = + //~^ declare_interior_mutable_const BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR: interior mutable + const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); + //~^ declare_interior_mutable_const const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); } diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr index 22329172c3af0..32839d14f0ed3 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.stderr @@ -9,7 +9,7 @@ LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(tru = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:23:1 + --> tests/ui/declare_interior_mutable_const/enums.rs:24:1 | LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:45:1 + --> tests/ui/declare_interior_mutable_const/enums.rs:47:1 | LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { LL | | @@ -30,56 +30,57 @@ LL | | }; = help: consider making this a static item error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:60:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:62:5 | LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:61:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:64:5 | LL | const TO_BE_FROZEN_VARIANT: OptionalCell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:64:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:68:5 | LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:90:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:95:5 | LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:102:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:108:5 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:105:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:112:5 | LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:111:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:119:5 | LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:118:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:127:5 | LL | / const UNFROZEN_VARIANT: BothOfCellAndGeneric = +LL | | LL | | BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | |____________________________________________________________________^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/enums.rs:120:5 + --> tests/ui/declare_interior_mutable_const/enums.rs:130:5 | LL | const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs index 0dccf18c49303..7ce04a3f2c340 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.rs @@ -7,15 +7,17 @@ use std::ptr; use std::sync::Once; use std::sync::atomic::AtomicUsize; -const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ ERROR: interior mutable -const CELL: Cell = Cell::new(6); //~ ERROR: interior mutable +const ATOMIC: AtomicUsize = AtomicUsize::new(5); +//~^ declare_interior_mutable_const +const CELL: Cell = Cell::new(6); +//~^ declare_interior_mutable_const const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ ERROR: interior mutable +//~^ declare_interior_mutable_const macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; - //~^ ERROR: interior mutable + //~^ declare_interior_mutable_const }; } declare_const!(_ONCE: Once = Once::new()); @@ -43,6 +45,7 @@ mod issue_8493 { macro_rules! issue_8493 { () => { const _BAZ: Cell = Cell::new(0); + //~^ declare_interior_mutable_const static _FOOBAR: () = { thread_local! { static _VAR: Cell = const { Cell::new(0) }; diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr index 4a7251471424e..09299b290416d 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/others.stderr @@ -9,7 +9,7 @@ LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:11:1 + --> tests/ui/declare_interior_mutable_const/others.rs:12:1 | LL | const CELL: Cell = Cell::new(6); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | const CELL: Cell = Cell::new(6); = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:12:1 + --> tests/ui/declare_interior_mutable_const/others.rs:14:1 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], V = help: consider making this a static item error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:17:9 + --> tests/ui/declare_interior_mutable_const/others.rs:19:9 | LL | const $name: $ty = $e; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | declare_const!(_ONCE: Once = Once::new()); = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/others.rs:45:13 + --> tests/ui/declare_interior_mutable_const/others.rs:47:13 | LL | const _BAZ: Cell = Cell::new(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs index 490073f97fb12..d3139be6859f3 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.rs @@ -7,13 +7,14 @@ use std::sync::atomic::AtomicUsize; macro_rules! declare_const { ($name:ident: $ty:ty = $e:expr) => { const $name: $ty = $e; - //~^ ERROR: interior mutable + //~^ declare_interior_mutable_const }; } // a constant whose type is a concrete type should be linted at the definition site. trait ConcreteTypes { - const ATOMIC: AtomicUsize; //~ ERROR: interior mutable + const ATOMIC: AtomicUsize; + //~^ declare_interior_mutable_const const INTEGER: u64; const STRING: String; declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); @@ -41,7 +42,8 @@ trait GenericTypes { impl GenericTypes for u64 { const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); //~ ERROR: interior mutable + const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); + //~^ declare_interior_mutable_const } // a helper type used below @@ -66,8 +68,10 @@ impl AssocTypes for Vec { type ToBeGenericParam = T; const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ ERROR: interior mutable - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); //~ ERROR: interior mutable + const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); + //~^ declare_interior_mutable_const + const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); + //~^ declare_interior_mutable_const const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); } @@ -86,7 +90,8 @@ where T: AssocTypesHelper, { const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; //~ ERROR: interior mutable + const BOUNDED: T::ToBeBounded; + //~^ declare_interior_mutable_const } impl AssocTypesFromGenericParam for u64 @@ -114,19 +119,24 @@ impl SelfType for u64 { impl SelfType for AtomicUsize { // this (interior mutable `Self` const) exists in `parking_lot`. // `const_trait_impl` will replace it in the future, hopefully. - const SELF: Self = AtomicUsize::new(17); //~ ERROR: interior mutable - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); //~ ERROR: interior mutable + const SELF: Self = AtomicUsize::new(17); + //~^ declare_interior_mutable_const + const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); + //~^ declare_interior_mutable_const } // Even though a constant contains a generic type, if it also have an interior mutable type, // it should be linted at the definition site. trait BothOfCellAndGeneric { - const DIRECT: Cell; //~ ERROR: interior mutable - const INDIRECT: Cell<*const T>; //~ ERROR: interior mutable + const DIRECT: Cell; + //~^ declare_interior_mutable_const + const INDIRECT: Cell<*const T>; + //~^ declare_interior_mutable_const } impl BothOfCellAndGeneric for u64 { - const DIRECT: Cell = Cell::new(T::DEFAULT); //~ ERROR: interior mutable + const DIRECT: Cell = Cell::new(T::DEFAULT); + //~^ declare_interior_mutable_const const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); } @@ -138,13 +148,15 @@ impl Local where T: ConstDefault + AssocTypesHelper, { - const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ ERROR: interior mutable + const ATOMIC: AtomicUsize = AtomicUsize::new(18); + //~^ declare_interior_mutable_const const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy"); const GENERIC_TYPE: T = T::DEFAULT; const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ ERROR: interior mutable + const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); + //~^ declare_interior_mutable_const } fn main() {} diff --git a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr index 4a793d985e5ec..b03dd7a084033 100644 --- a/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/src/tools/clippy/tests/ui/declare_interior_mutable_const/traits.stderr @@ -19,67 +19,67 @@ LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info) error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:44:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:45:5 | LL | const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:69:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:71:5 | LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:70:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:73:5 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:89:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:93:5 | LL | const BOUNDED: T::ToBeBounded; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:117:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:122:5 | LL | const SELF: Self = AtomicUsize::new(17); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:118:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:124:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:131:5 | LL | const DIRECT: Cell; | ^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:125:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:133:5 | LL | const INDIRECT: Cell<*const T>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:129:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:138:5 | LL | const DIRECT: Cell = Cell::new(T::DEFAULT); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:141:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:151:5 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: a `const` item should not be interior mutable - --> tests/ui/declare_interior_mutable_const/traits.rs:147:5 + --> tests/ui/declare_interior_mutable_const/traits.rs:158:5 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed index 3047c221d4575..fa4d55177823e 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed @@ -9,6 +9,7 @@ impl UnitStruct { fn new() -> Self { //should lint Self + //~^ default_constructed_unit_structs } } @@ -51,6 +52,7 @@ impl NormalStruct { // should lint Self { inner: PhantomData, + //~^ default_constructed_unit_structs } } @@ -124,9 +126,13 @@ mod issue_10755 { fn main() { // should lint let _ = PhantomData::; + //~^ default_constructed_unit_structs let _: PhantomData = PhantomData; + //~^ default_constructed_unit_structs let _: PhantomData = std::marker::PhantomData; + //~^ default_constructed_unit_structs let _ = UnitStruct; + //~^ default_constructed_unit_structs // should not lint let _ = TupleStruct::default(); diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs index 66afedb238013..291cd89da0b79 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs @@ -9,6 +9,7 @@ impl UnitStruct { fn new() -> Self { //should lint Self::default() + //~^ default_constructed_unit_structs } } @@ -51,6 +52,7 @@ impl NormalStruct { // should lint Self { inner: PhantomData::default(), + //~^ default_constructed_unit_structs } } @@ -124,9 +126,13 @@ mod issue_10755 { fn main() { // should lint let _ = PhantomData::::default(); + //~^ default_constructed_unit_structs let _: PhantomData = PhantomData::default(); + //~^ default_constructed_unit_structs let _: PhantomData = std::marker::PhantomData::default(); + //~^ default_constructed_unit_structs let _ = UnitStruct::default(); + //~^ default_constructed_unit_structs // should not lint let _ = TupleStruct::default(); diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr index c0fa73515c034..6d4e1bdc2cc81 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr @@ -8,31 +8,31 @@ LL | Self::default() = help: to override `-D warnings` add `#[allow(clippy::default_constructed_unit_structs)]` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:53:31 + --> tests/ui/default_constructed_unit_structs.rs:54:31 | LL | inner: PhantomData::default(), | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:126:33 + --> tests/ui/default_constructed_unit_structs.rs:128:33 | LL | let _ = PhantomData::::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:127:42 + --> tests/ui/default_constructed_unit_structs.rs:130:42 | LL | let _: PhantomData = PhantomData::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:128:55 + --> tests/ui/default_constructed_unit_structs.rs:132:55 | LL | let _: PhantomData = std::marker::PhantomData::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> tests/ui/default_constructed_unit_structs.rs:129:23 + --> tests/ui/default_constructed_unit_structs.rs:134:23 | LL | let _ = UnitStruct::default(); | ^^^^^^^^^^^ help: remove this call to `default` diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed index 3298a222bda6a..548de93799271 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed @@ -10,8 +10,11 @@ struct Iter { fn main() { // Do lint. let _ = std::iter::empty::(); + //~^ default_instead_of_iter_empty let _ = std::iter::empty::>(); + //~^ default_instead_of_iter_empty let _foo: std::iter::Empty = std::iter::empty(); + //~^ default_instead_of_iter_empty // Do not lint. let _ = Vec::::default(); diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs index 75b088a99590a..824cc20566de8 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs @@ -10,8 +10,11 @@ struct Iter { fn main() { // Do lint. let _ = std::iter::Empty::::default(); + //~^ default_instead_of_iter_empty let _ = std::iter::Empty::>::default(); + //~^ default_instead_of_iter_empty let _foo: std::iter::Empty = std::iter::Empty::default(); + //~^ default_instead_of_iter_empty // Do not lint. let _ = Vec::::default(); diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr index 4bd4d060a3f75..dc0b757adc2e2 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.stderr @@ -8,13 +8,13 @@ LL | let _ = std::iter::Empty::::default(); = help: to override `-D warnings` add `#[allow(clippy::default_instead_of_iter_empty)]` error: `std::iter::empty()` is the more idiomatic way - --> tests/ui/default_instead_of_iter_empty.rs:13:13 + --> tests/ui/default_instead_of_iter_empty.rs:14:13 | LL | let _ = std::iter::Empty::>::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty::>()` error: `std::iter::empty()` is the more idiomatic way - --> tests/ui/default_instead_of_iter_empty.rs:14:41 + --> tests/ui/default_instead_of_iter_empty.rs:16:41 | LL | let _foo: std::iter::Empty = std::iter::Empty::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed index 7300bd9bd2abd..76d75ea7e5918 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.fixed @@ -21,7 +21,9 @@ struct Iter { fn main() { // Do lint. let _ = core::iter::empty::(); + //~^ default_instead_of_iter_empty let _foo: core::iter::Empty = core::iter::empty(); + //~^ default_instead_of_iter_empty // Do not lint. let _ = Iter::default(); diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs index 0bc5c7169d129..639b73ba38def 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.rs @@ -21,7 +21,9 @@ struct Iter { fn main() { // Do lint. let _ = core::iter::Empty::::default(); + //~^ default_instead_of_iter_empty let _foo: core::iter::Empty = core::iter::Empty::default(); + //~^ default_instead_of_iter_empty // Do not lint. let _ = Iter::default(); diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr index eb80da13e8506..69812eba5423a 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty_no_std.stderr @@ -8,7 +8,7 @@ LL | let _ = core::iter::Empty::::default(); = help: to override `-D warnings` add `#[allow(clippy::default_instead_of_iter_empty)]` error: `core::iter::empty()` is the more idiomatic way - --> tests/ui/default_instead_of_iter_empty_no_std.rs:24:42 + --> tests/ui/default_instead_of_iter_empty_no_std.rs:25:42 | LL | let _foo: core::iter::Empty = core::iter::Empty::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::iter::empty()` diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed index 00f0d76443401..cf1ccab688c5d 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed @@ -19,10 +19,20 @@ mod basic_expr { fn test() { // Should lint unsuffixed literals typed `f64`. let x = 0.12_f64; + //~^ default_numeric_fallback let x = [1.0_f64, 2.0_f64, 3.0_f64]; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = if true { (1.0_f64, 2.0_f64) } else { (3.0_f64, 4.0_f64) }; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = match 1.0_f64 { + //~^ default_numeric_fallback _ => 1.0_f64, + //~^ default_numeric_fallback }; // Should NOT lint suffixed literals. @@ -42,6 +52,7 @@ mod nested_local { let x: _ = { // Should lint this because this literal is not bound to any types. let y = 1.0_f64; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1. @@ -50,12 +61,14 @@ mod nested_local { let x: _ = if true { // Should lint this because this literal is not bound to any types. let y = 1.0_f64; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1. } else { // Should lint this because this literal is not bound to any types. let y = 1.0_f64; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2. @@ -64,6 +77,7 @@ mod nested_local { const X: f32 = { // Should lint this because this literal is not bound to any types. let y = 1.0_f64; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1. @@ -80,10 +94,12 @@ mod function_def { // Should lint this because return type is inferred to `f64` and NOT bound to a concrete // type. let f = || -> _ { 1.0_f64 }; + //~^ default_numeric_fallback // Even though the output type is specified, // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. let f = || -> f64 { 1.0_f64 }; + //~^ default_numeric_fallback } } @@ -98,9 +114,11 @@ mod function_calls { // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type. generic_arg(1.0_f64); + //~^ default_numeric_fallback // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type. let x: _ = generic_arg(1.0_f64); + //~^ default_numeric_fallback } } @@ -119,9 +137,11 @@ mod struct_ctor { // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type. GenericStruct { x: 1.0_f64 }; + //~^ default_numeric_fallback // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type. let _ = GenericStruct { x: 1.0_f64 }; + //~^ default_numeric_fallback } } @@ -140,6 +160,7 @@ mod enum_ctor { // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type. GenericEnum::X(1.0_f64); + //~^ default_numeric_fallback } } @@ -160,6 +181,7 @@ mod method_calls { // Should lint this because the argument type is bound to a concrete type. s.generic_arg(1.0_f64); + //~^ default_numeric_fallback } } @@ -170,6 +192,7 @@ mod in_macro { #[inline_macros] fn internal() { inline!(let x = 22.0_f64;); + //~^ default_numeric_fallback } // Should NOT lint in external macro. diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs index 942cedac27537..345e65e0b4f95 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs @@ -19,10 +19,20 @@ mod basic_expr { fn test() { // Should lint unsuffixed literals typed `f64`. let x = 0.12; + //~^ default_numeric_fallback let x = [1., 2., 3.]; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = if true { (1., 2.) } else { (3., 4.) }; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = match 1. { + //~^ default_numeric_fallback _ => 1., + //~^ default_numeric_fallback }; // Should NOT lint suffixed literals. @@ -42,6 +52,7 @@ mod nested_local { let x: _ = { // Should lint this because this literal is not bound to any types. let y = 1.; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1. @@ -50,12 +61,14 @@ mod nested_local { let x: _ = if true { // Should lint this because this literal is not bound to any types. let y = 1.; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1. } else { // Should lint this because this literal is not bound to any types. let y = 1.; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2. @@ -64,6 +77,7 @@ mod nested_local { const X: f32 = { // Should lint this because this literal is not bound to any types. let y = 1.; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1. @@ -80,10 +94,12 @@ mod function_def { // Should lint this because return type is inferred to `f64` and NOT bound to a concrete // type. let f = || -> _ { 1. }; + //~^ default_numeric_fallback // Even though the output type is specified, // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. let f = || -> f64 { 1. }; + //~^ default_numeric_fallback } } @@ -98,9 +114,11 @@ mod function_calls { // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type. generic_arg(1.); + //~^ default_numeric_fallback // Should lint this because the argument type is inferred to `f64` and NOT bound to a concrete type. let x: _ = generic_arg(1.); + //~^ default_numeric_fallback } } @@ -119,9 +137,11 @@ mod struct_ctor { // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type. GenericStruct { x: 1. }; + //~^ default_numeric_fallback // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type. let _ = GenericStruct { x: 1. }; + //~^ default_numeric_fallback } } @@ -140,6 +160,7 @@ mod enum_ctor { // Should lint this because the field type is inferred to `f64` and NOT bound to a concrete type. GenericEnum::X(1.); + //~^ default_numeric_fallback } } @@ -160,6 +181,7 @@ mod method_calls { // Should lint this because the argument type is bound to a concrete type. s.generic_arg(1.); + //~^ default_numeric_fallback } } @@ -170,6 +192,7 @@ mod in_macro { #[inline_macros] fn internal() { inline!(let x = 22.;); + //~^ default_numeric_fallback } // Should NOT lint in external macro. diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr index d7e4dbd637715..f9451211e1ac1 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.stderr @@ -8,133 +8,133 @@ LL | let x = 0.12; = help: to override `-D warnings` add `#[allow(clippy::default_numeric_fallback)]` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:22:18 + --> tests/ui/default_numeric_fallback_f64.rs:23:18 | LL | let x = [1., 2., 3.]; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:22:22 + --> tests/ui/default_numeric_fallback_f64.rs:23:22 | LL | let x = [1., 2., 3.]; | ^^ help: consider adding suffix: `2.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:22:26 + --> tests/ui/default_numeric_fallback_f64.rs:23:26 | LL | let x = [1., 2., 3.]; | ^^ help: consider adding suffix: `3.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:23:28 + --> tests/ui/default_numeric_fallback_f64.rs:27:28 | LL | let x = if true { (1., 2.) } else { (3., 4.) }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:23:32 + --> tests/ui/default_numeric_fallback_f64.rs:27:32 | LL | let x = if true { (1., 2.) } else { (3., 4.) }; | ^^ help: consider adding suffix: `2.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:23:46 + --> tests/ui/default_numeric_fallback_f64.rs:27:46 | LL | let x = if true { (1., 2.) } else { (3., 4.) }; | ^^ help: consider adding suffix: `3.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:23:50 + --> tests/ui/default_numeric_fallback_f64.rs:27:50 | LL | let x = if true { (1., 2.) } else { (3., 4.) }; | ^^ help: consider adding suffix: `4.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:24:23 + --> tests/ui/default_numeric_fallback_f64.rs:32:23 | LL | let x = match 1. { | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:25:18 + --> tests/ui/default_numeric_fallback_f64.rs:34:18 | LL | _ => 1., | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:44:21 + --> tests/ui/default_numeric_fallback_f64.rs:54:21 | LL | let y = 1.; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:52:21 + --> tests/ui/default_numeric_fallback_f64.rs:63:21 | LL | let y = 1.; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:58:21 + --> tests/ui/default_numeric_fallback_f64.rs:70:21 | LL | let y = 1.; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:66:21 + --> tests/ui/default_numeric_fallback_f64.rs:79:21 | LL | let y = 1.; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:82:27 + --> tests/ui/default_numeric_fallback_f64.rs:96:27 | LL | let f = || -> _ { 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:86:29 + --> tests/ui/default_numeric_fallback_f64.rs:101:29 | LL | let f = || -> f64 { 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:100:21 + --> tests/ui/default_numeric_fallback_f64.rs:116:21 | LL | generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:103:32 + --> tests/ui/default_numeric_fallback_f64.rs:120:32 | LL | let x: _ = generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:121:28 + --> tests/ui/default_numeric_fallback_f64.rs:139:28 | LL | GenericStruct { x: 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:124:36 + --> tests/ui/default_numeric_fallback_f64.rs:143:36 | LL | let _ = GenericStruct { x: 1. }; | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:142:24 + --> tests/ui/default_numeric_fallback_f64.rs:162:24 | LL | GenericEnum::X(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:162:23 + --> tests/ui/default_numeric_fallback_f64.rs:183:23 | LL | s.generic_arg(1.); | ^^ help: consider adding suffix: `1.0_f64` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_f64.rs:172:25 + --> tests/ui/default_numeric_fallback_f64.rs:194:25 | LL | inline!(let x = 22.;); | ^^^ help: consider adding suffix: `22.0_f64` diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed index f28ae04fd0a4b..496408aa9e87d 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed @@ -18,11 +18,23 @@ mod basic_expr { fn test() { // Should lint unsuffixed literals typed `i32`. let x = 22_i32; + //~^ default_numeric_fallback let x = [1_i32, 2_i32, 3_i32]; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = if true { (1_i32, 2_i32) } else { (3_i32, 4_i32) }; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = match 1_i32 { + //~^ default_numeric_fallback 1_i32 => 1_i32, + //~^ default_numeric_fallback + //~| default_numeric_fallback _ => 2_i32, + //~^ default_numeric_fallback }; // Should NOT lint suffixed literals. @@ -42,6 +54,7 @@ mod nested_local { let x: _ = { // Should lint this because this literal is not bound to any types. let y = 1_i32; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1 @@ -50,12 +63,14 @@ mod nested_local { let x: _ = if true { // Should lint this because this literal is not bound to any types. let y = 1_i32; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1 } else { // Should lint this because this literal is not bound to any types. let y = 1_i32; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2 @@ -64,6 +79,7 @@ mod nested_local { const CONST_X: i32 = { // Should lint this because this literal is not bound to any types. let y = 1_i32; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1 @@ -80,10 +96,12 @@ mod function_def { // Should lint this because return type is inferred to `i32` and NOT bound to a concrete // type. let f = || -> _ { 1_i32 }; + //~^ default_numeric_fallback // Even though the output type is specified, // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. let f = || -> i32 { 1_i32 }; + //~^ default_numeric_fallback } } @@ -98,9 +116,11 @@ mod function_calls { // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type. generic_arg(1_i32); + //~^ default_numeric_fallback // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type. let x: _ = generic_arg(1_i32); + //~^ default_numeric_fallback } } @@ -119,9 +139,11 @@ mod struct_ctor { // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. GenericStruct { x: 1_i32 }; + //~^ default_numeric_fallback // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. let _ = GenericStruct { x: 1_i32 }; + //~^ default_numeric_fallback } } @@ -140,6 +162,7 @@ mod enum_ctor { // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. GenericEnum::X(1_i32); + //~^ default_numeric_fallback } } @@ -160,6 +183,7 @@ mod method_calls { // Should lint this because the argument type is bound to a concrete type. s.generic_arg(1_i32); + //~^ default_numeric_fallback } } @@ -170,6 +194,7 @@ mod in_macro { #[inline_macros] fn internal() { inline!(let x = 22_i32;); + //~^ default_numeric_fallback } // Should NOT lint in external macro. @@ -212,6 +237,9 @@ mod type_already_inferred { // Should NOT lint in `vec!` call if the type was already stated let data_i32: Vec = vec![1, 2, 3]; let data_i32 = vec![1_i32, 2_i32, 3_i32]; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback } } diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs index 78a5006444eeb..90fcf4091ddcf 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs @@ -18,11 +18,23 @@ mod basic_expr { fn test() { // Should lint unsuffixed literals typed `i32`. let x = 22; + //~^ default_numeric_fallback let x = [1, 2, 3]; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = if true { (1, 2) } else { (3, 4) }; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback let x = match 1 { + //~^ default_numeric_fallback 1 => 1, + //~^ default_numeric_fallback + //~| default_numeric_fallback _ => 2, + //~^ default_numeric_fallback }; // Should NOT lint suffixed literals. @@ -42,6 +54,7 @@ mod nested_local { let x: _ = { // Should lint this because this literal is not bound to any types. let y = 1; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1 @@ -50,12 +63,14 @@ mod nested_local { let x: _ = if true { // Should lint this because this literal is not bound to any types. let y = 1; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1 } else { // Should lint this because this literal is not bound to any types. let y = 1; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 2 @@ -64,6 +79,7 @@ mod nested_local { const CONST_X: i32 = { // Should lint this because this literal is not bound to any types. let y = 1; + //~^ default_numeric_fallback // Should NOT lint this because this literal is bound to `_` of outer `Local`. 1 @@ -80,10 +96,12 @@ mod function_def { // Should lint this because return type is inferred to `i32` and NOT bound to a concrete // type. let f = || -> _ { 1 }; + //~^ default_numeric_fallback // Even though the output type is specified, // this unsuffixed literal is linted to reduce heuristics and keep codebase simple. let f = || -> i32 { 1 }; + //~^ default_numeric_fallback } } @@ -98,9 +116,11 @@ mod function_calls { // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type. generic_arg(1); + //~^ default_numeric_fallback // Should lint this because the argument type is inferred to `i32` and NOT bound to a concrete type. let x: _ = generic_arg(1); + //~^ default_numeric_fallback } } @@ -119,9 +139,11 @@ mod struct_ctor { // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. GenericStruct { x: 1 }; + //~^ default_numeric_fallback // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. let _ = GenericStruct { x: 1 }; + //~^ default_numeric_fallback } } @@ -140,6 +162,7 @@ mod enum_ctor { // Should lint this because the field type is inferred to `i32` and NOT bound to a concrete type. GenericEnum::X(1); + //~^ default_numeric_fallback } } @@ -160,6 +183,7 @@ mod method_calls { // Should lint this because the argument type is bound to a concrete type. s.generic_arg(1); + //~^ default_numeric_fallback } } @@ -170,6 +194,7 @@ mod in_macro { #[inline_macros] fn internal() { inline!(let x = 22;); + //~^ default_numeric_fallback } // Should NOT lint in external macro. @@ -212,6 +237,9 @@ mod type_already_inferred { // Should NOT lint in `vec!` call if the type was already stated let data_i32: Vec = vec![1, 2, 3]; let data_i32 = vec![1, 2, 3]; + //~^ default_numeric_fallback + //~| default_numeric_fallback + //~| default_numeric_fallback } } diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr index 67ab923ecf5fb..02afbddcb3be4 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.stderr @@ -8,145 +8,145 @@ LL | let x = 22; = help: to override `-D warnings` add `#[allow(clippy::default_numeric_fallback)]` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:21:18 + --> tests/ui/default_numeric_fallback_i32.rs:22:18 | LL | let x = [1, 2, 3]; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:21:21 + --> tests/ui/default_numeric_fallback_i32.rs:22:21 | LL | let x = [1, 2, 3]; | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:21:24 + --> tests/ui/default_numeric_fallback_i32.rs:22:24 | LL | let x = [1, 2, 3]; | ^ help: consider adding suffix: `3_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:22:28 + --> tests/ui/default_numeric_fallback_i32.rs:26:28 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:22:31 + --> tests/ui/default_numeric_fallback_i32.rs:26:31 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:22:44 + --> tests/ui/default_numeric_fallback_i32.rs:26:44 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `3_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:22:47 + --> tests/ui/default_numeric_fallback_i32.rs:26:47 | LL | let x = if true { (1, 2) } else { (3, 4) }; | ^ help: consider adding suffix: `4_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:23:23 + --> tests/ui/default_numeric_fallback_i32.rs:31:23 | LL | let x = match 1 { | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:24:13 + --> tests/ui/default_numeric_fallback_i32.rs:33:13 | LL | 1 => 1, | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:24:18 + --> tests/ui/default_numeric_fallback_i32.rs:33:18 | LL | 1 => 1, | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:25:18 + --> tests/ui/default_numeric_fallback_i32.rs:36:18 | LL | _ => 2, | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:44:21 + --> tests/ui/default_numeric_fallback_i32.rs:56:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:52:21 + --> tests/ui/default_numeric_fallback_i32.rs:65:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:58:21 + --> tests/ui/default_numeric_fallback_i32.rs:72:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:66:21 + --> tests/ui/default_numeric_fallback_i32.rs:81:21 | LL | let y = 1; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:82:27 + --> tests/ui/default_numeric_fallback_i32.rs:98:27 | LL | let f = || -> _ { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:86:29 + --> tests/ui/default_numeric_fallback_i32.rs:103:29 | LL | let f = || -> i32 { 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:100:21 + --> tests/ui/default_numeric_fallback_i32.rs:118:21 | LL | generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:103:32 + --> tests/ui/default_numeric_fallback_i32.rs:122:32 | LL | let x: _ = generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:121:28 + --> tests/ui/default_numeric_fallback_i32.rs:141:28 | LL | GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:124:36 + --> tests/ui/default_numeric_fallback_i32.rs:145:36 | LL | let _ = GenericStruct { x: 1 }; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:142:24 + --> tests/ui/default_numeric_fallback_i32.rs:164:24 | LL | GenericEnum::X(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:162:23 + --> tests/ui/default_numeric_fallback_i32.rs:185:23 | LL | s.generic_arg(1); | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:172:25 + --> tests/ui/default_numeric_fallback_i32.rs:196:25 | LL | inline!(let x = 22;); | ^^ help: consider adding suffix: `22_i32` @@ -154,19 +154,19 @@ LL | inline!(let x = 22;); = note: this error originates in the macro `__inline_mac_fn_internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:214:29 + --> tests/ui/default_numeric_fallback_i32.rs:239:29 | LL | let data_i32 = vec![1, 2, 3]; | ^ help: consider adding suffix: `1_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:214:32 + --> tests/ui/default_numeric_fallback_i32.rs:239:32 | LL | let data_i32 = vec![1, 2, 3]; | ^ help: consider adding suffix: `2_i32` error: default numeric fallback might occur - --> tests/ui/default_numeric_fallback_i32.rs:214:35 + --> tests/ui/default_numeric_fallback_i32.rs:239:35 | LL | let data_i32 = vec![1, 2, 3]; | ^ help: consider adding suffix: `3_i32` diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed index 6f1e72c5a6c0c..d3fe09a052ef3 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.fixed +++ b/src/tools/clippy/tests/ui/default_trait_access.fixed @@ -11,16 +11,20 @@ use std::{default, string}; fn main() { let s1: String = String::default(); + //~^ default_trait_access let s2 = String::default(); let s3: String = String::default(); + //~^ default_trait_access let s4: String = String::default(); + //~^ default_trait_access let s5 = string::String::default(); let s6: String = String::default(); + //~^ default_trait_access let s7 = std::string::String::default(); @@ -31,18 +35,22 @@ fn main() { let s10 = DerivedDefault::default(); let s11: GenericDerivedDefault = GenericDerivedDefault::default(); + //~^ default_trait_access let s12 = GenericDerivedDefault::::default(); let s13 = TupleDerivedDefault::default(); let s14: TupleDerivedDefault = TupleDerivedDefault::default(); + //~^ default_trait_access let s15: ArrayDerivedDefault = ArrayDerivedDefault::default(); + //~^ default_trait_access let s16 = ArrayDerivedDefault::default(); let s17: TupleStructDerivedDefault = TupleStructDerivedDefault::default(); + //~^ default_trait_access let s18 = TupleStructDerivedDefault::default(); diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs index 5528ca8b7936e..cdffb2a2ee8ca 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.rs +++ b/src/tools/clippy/tests/ui/default_trait_access.rs @@ -11,16 +11,20 @@ use std::{default, string}; fn main() { let s1: String = Default::default(); + //~^ default_trait_access let s2 = String::default(); let s3: String = D2::default(); + //~^ default_trait_access let s4: String = std::default::Default::default(); + //~^ default_trait_access let s5 = string::String::default(); let s6: String = default::Default::default(); + //~^ default_trait_access let s7 = std::string::String::default(); @@ -31,18 +35,22 @@ fn main() { let s10 = DerivedDefault::default(); let s11: GenericDerivedDefault = Default::default(); + //~^ default_trait_access let s12 = GenericDerivedDefault::::default(); let s13 = TupleDerivedDefault::default(); let s14: TupleDerivedDefault = Default::default(); + //~^ default_trait_access let s15: ArrayDerivedDefault = Default::default(); + //~^ default_trait_access let s16 = ArrayDerivedDefault::default(); let s17: TupleStructDerivedDefault = Default::default(); + //~^ default_trait_access let s18 = TupleStructDerivedDefault::default(); diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr index 276f03d79df1d..aa7eb4f89558c 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.stderr +++ b/src/tools/clippy/tests/ui/default_trait_access.stderr @@ -11,43 +11,43 @@ LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `String::default()` is more clear than this expression - --> tests/ui/default_trait_access.rs:17:22 + --> tests/ui/default_trait_access.rs:18:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `String::default()` error: calling `String::default()` is more clear than this expression - --> tests/ui/default_trait_access.rs:19:22 + --> tests/ui/default_trait_access.rs:21:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` error: calling `String::default()` is more clear than this expression - --> tests/ui/default_trait_access.rs:23:22 + --> tests/ui/default_trait_access.rs:26:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression - --> tests/ui/default_trait_access.rs:33:46 + --> tests/ui/default_trait_access.rs:37:46 | LL | let s11: GenericDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> tests/ui/default_trait_access.rs:39:36 + --> tests/ui/default_trait_access.rs:44:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> tests/ui/default_trait_access.rs:41:36 + --> tests/ui/default_trait_access.rs:47:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> tests/ui/default_trait_access.rs:45:42 + --> tests/ui/default_trait_access.rs:52:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` diff --git a/src/tools/clippy/tests/ui/default_union_representation.rs b/src/tools/clippy/tests/ui/default_union_representation.rs index ba63cde2fa9d4..92c429c79a078 100644 --- a/src/tools/clippy/tests/ui/default_union_representation.rs +++ b/src/tools/clippy/tests/ui/default_union_representation.rs @@ -3,7 +3,7 @@ #![allow(clippy::repr_packed_without_abi)] union NoAttribute { - //~^ ERROR: this union has the default representation + //~^ default_union_representation a: i32, b: u32, } @@ -16,7 +16,7 @@ union ReprC { #[repr(packed)] union ReprPacked { - //~^ ERROR: this union has the default representation + //~^ default_union_representation a: i32, b: u32, } @@ -35,7 +35,7 @@ union ReprCAlign { #[repr(align(32))] union ReprAlign { - //~^ ERROR: this union has the default representation + //~^ default_union_representation a: i32, b: u32, } @@ -56,7 +56,7 @@ union ZSTsAndField2 { f3: (), } union ZSTAndTwoFields { - //~^ ERROR: this union has the default representation + //~^ default_union_representation f0: u32, f1: u64, f2: (), diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs index 5617db90a470a..35646e1c23919 100644 --- a/src/tools/clippy/tests/ui/deprecated.rs +++ b/src/tools/clippy/tests/ui/deprecated.rs @@ -15,5 +15,6 @@ #![warn(clippy::regex_macro)] //~ ERROR: lint `clippy::regex_macro` #![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names` #![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention` +#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok` fn main() {} diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index b3e1646c8045b..d7be1e583b08b 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -79,5 +79,11 @@ error: lint `clippy::wrong_pub_self_convention` has been removed: `clippy::wrong LL | #![warn(clippy::wrong_pub_self_convention)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 13 previous errors +error: lint `clippy::option_map_or_err_ok` has been removed: `clippy::manual_ok_or` covers this case + --> tests/ui/deprecated.rs:18:9 + | +LL | #![warn(clippy::option_map_or_err_ok)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed index f412c57d65057..35dbd790e890c 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.fixed +++ b/src/tools/clippy/tests/ui/deref_addrof.fixed @@ -21,30 +21,39 @@ fn main() { let aref = &a; let b = a; + //~^ deref_addrof let b = get_number(); + //~^ deref_addrof let b = *get_reference(&a); let bytes: Vec = vec![1, 2, 3, 4]; let b = bytes[1..2][0]; + //~^ deref_addrof //This produces a suggestion of 'let b = (a);' which //will trigger the 'unused_parens' lint let b = (a); + //~^ deref_addrof let b = a; + //~^ deref_addrof #[rustfmt::skip] let b = a; + //~^ deref_addrof let b = &a; + //~^ deref_addrof let b = *aref; + //~^ deref_addrof let _ = unsafe { *core::ptr::addr_of!(a) }; let _repeat = [0; 64]; + //~^ deref_addrof // do NOT lint for array as semantic differences with/out `*&`. let _arr = *&[0, 1, 2, 3, 4]; } @@ -55,9 +64,11 @@ pub struct S; impl S { pub fn f(&self) -> &Self { inline!($(@expr self)) + //~^ deref_addrof } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { inline!($(@expr self)) + //~^ deref_addrof } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs index 67836b0de52dc..96d1b92ef7be9 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.rs +++ b/src/tools/clippy/tests/ui/deref_addrof.rs @@ -21,30 +21,39 @@ fn main() { let aref = &a; let b = *&a; + //~^ deref_addrof let b = *&get_number(); + //~^ deref_addrof let b = *get_reference(&a); let bytes: Vec = vec![1, 2, 3, 4]; let b = *&bytes[1..2][0]; + //~^ deref_addrof //This produces a suggestion of 'let b = (a);' which //will trigger the 'unused_parens' lint let b = *&(a); + //~^ deref_addrof let b = *(&a); + //~^ deref_addrof #[rustfmt::skip] let b = *((&a)); + //~^ deref_addrof let b = *&&a; + //~^ deref_addrof let b = **&aref; + //~^ deref_addrof let _ = unsafe { *core::ptr::addr_of!(a) }; let _repeat = *&[0; 64]; + //~^ deref_addrof // do NOT lint for array as semantic differences with/out `*&`. let _arr = *&[0, 1, 2, 3, 4]; } @@ -55,9 +64,11 @@ pub struct S; impl S { pub fn f(&self) -> &Self { inline!(*& $(@expr self)) + //~^ deref_addrof } #[allow(unused_mut)] // mut will be unused, once the macro is fixed pub fn f_mut(mut self) -> Self { inline!(*&mut $(@expr self)) + //~^ deref_addrof } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr index 20069f746c81c..81414b625b2fe 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof.stderr @@ -8,55 +8,55 @@ LL | let b = *&a; = help: to override `-D warnings` add `#[allow(clippy::deref_addrof)]` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:25:13 + --> tests/ui/deref_addrof.rs:26:13 | LL | let b = *&get_number(); | ^^^^^^^^^^^^^^ help: try: `get_number()` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:30:13 + --> tests/ui/deref_addrof.rs:32:13 | LL | let b = *&bytes[1..2][0]; | ^^^^^^^^^^^^^^^^ help: try: `bytes[1..2][0]` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:34:13 + --> tests/ui/deref_addrof.rs:37:13 | LL | let b = *&(a); | ^^^^^ help: try: `(a)` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:36:13 + --> tests/ui/deref_addrof.rs:40:13 | LL | let b = *(&a); | ^^^^^ help: try: `a` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:39:13 + --> tests/ui/deref_addrof.rs:44:13 | LL | let b = *((&a)); | ^^^^^^^ help: try: `a` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:41:13 + --> tests/ui/deref_addrof.rs:47:13 | LL | let b = *&&a; | ^^^^ help: try: `&a` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:43:14 + --> tests/ui/deref_addrof.rs:50:14 | LL | let b = **&aref; | ^^^^^^ help: try: `aref` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:47:19 + --> tests/ui/deref_addrof.rs:55:19 | LL | let _repeat = *&[0; 64]; | ^^^^^^^^^ help: try: `[0; 64]` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:57:17 + --> tests/ui/deref_addrof.rs:66:17 | LL | inline!(*& $(@expr self)) | ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` @@ -64,7 +64,7 @@ LL | inline!(*& $(@expr self)) = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:61:17 + --> tests/ui/deref_addrof.rs:71:17 | LL | inline!(*&mut $(@expr self)) | ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` diff --git a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs index 6f997875777e4..b08b2aba23196 100644 --- a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs +++ b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.rs @@ -8,13 +8,12 @@ fn main() { //This produces a suggestion of 'let b = *&a;' which //will trigger the 'clippy::deref_addrof' lint again let b = **&&a; - //~^ ERROR: immediately dereferencing a reference - //~| NOTE: `-D clippy::deref-addrof` implied by `-D warnings` + //~^ deref_addrof { let mut x = 10; let y = *&mut x; - //~^ ERROR: immediately dereferencing a reference + //~^ deref_addrof } { @@ -22,6 +21,6 @@ fn main() { //will trigger the 'clippy::deref_addrof' lint again let mut x = 10; let y = **&mut &mut x; - //~^ ERROR: immediately dereferencing a reference + //~^ deref_addrof } } diff --git a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr index 8905b14246740..9ac60dd6d544f 100644 --- a/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof_double_trigger.stderr @@ -8,13 +8,13 @@ LL | let b = **&&a; = help: to override `-D warnings` add `#[allow(clippy::deref_addrof)]` error: immediately dereferencing a reference - --> tests/ui/deref_addrof_double_trigger.rs:16:17 + --> tests/ui/deref_addrof_double_trigger.rs:15:17 | LL | let y = *&mut x; | ^^^^^^^ help: try: `x` error: immediately dereferencing a reference - --> tests/ui/deref_addrof_double_trigger.rs:24:18 + --> tests/ui/deref_addrof_double_trigger.rs:23:18 | LL | let y = **&mut &mut x; | ^^^^^^^^^^^^ help: try: `&mut x` diff --git a/src/tools/clippy/tests/ui/deref_addrof_macro.rs b/src/tools/clippy/tests/ui/deref_addrof_macro.rs index c7e60f3650603..452ccd173a16a 100644 --- a/src/tools/clippy/tests/ui/deref_addrof_macro.rs +++ b/src/tools/clippy/tests/ui/deref_addrof_macro.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build:proc_macros.rs #![warn(clippy::deref_addrof)] diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.fixed b/src/tools/clippy/tests/ui/deref_by_slicing.fixed index 87b33b1f881d8..ba03904040b41 100644 --- a/src/tools/clippy/tests/ui/deref_by_slicing.fixed +++ b/src/tools/clippy/tests/ui/deref_by_slicing.fixed @@ -6,27 +6,41 @@ use std::io::Read; fn main() { let mut vec = vec![0]; let _ = &*vec; + //~^ deref_by_slicing let _ = &mut *vec; + //~^ deref_by_slicing let ref_vec = &mut vec; let _ = &**ref_vec; + //~^ deref_by_slicing let mut_slice = &mut **ref_vec; + //~^ deref_by_slicing let _ = &mut *mut_slice; // Err, re-borrows slice + // + //~^^ deref_by_slicing let s = String::new(); let _ = &*s; + //~^ deref_by_slicing static S: &[u8] = &[0, 1, 2]; let _ = &mut &*S; // Err, re-borrows slice + // + //~^^ deref_by_slicing let slice: &[u32] = &[0u32, 1u32]; let slice_ref = &slice; let _ = *slice_ref; // Err, derefs slice + // + //~^^ deref_by_slicing let bytes: &[u8] = &[]; let _ = (&*bytes).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice + // + //~^^ deref_by_slicing // issue 12751 let a = &mut [1, 2, 3][..]; let _ = &*a; + //~^ deref_by_slicing } diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.rs b/src/tools/clippy/tests/ui/deref_by_slicing.rs index 8d8882a1781e8..fdaac9467f86f 100644 --- a/src/tools/clippy/tests/ui/deref_by_slicing.rs +++ b/src/tools/clippy/tests/ui/deref_by_slicing.rs @@ -6,27 +6,41 @@ use std::io::Read; fn main() { let mut vec = vec![0]; let _ = &vec[..]; + //~^ deref_by_slicing let _ = &mut vec[..]; + //~^ deref_by_slicing let ref_vec = &mut vec; let _ = &ref_vec[..]; + //~^ deref_by_slicing let mut_slice = &mut ref_vec[..]; + //~^ deref_by_slicing let _ = &mut mut_slice[..]; // Err, re-borrows slice + // + //~^^ deref_by_slicing let s = String::new(); let _ = &s[..]; + //~^ deref_by_slicing static S: &[u8] = &[0, 1, 2]; let _ = &mut &S[..]; // Err, re-borrows slice + // + //~^^ deref_by_slicing let slice: &[u32] = &[0u32, 1u32]; let slice_ref = &slice; let _ = &slice_ref[..]; // Err, derefs slice + // + //~^^ deref_by_slicing let bytes: &[u8] = &[]; let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice + // + //~^^ deref_by_slicing // issue 12751 let a = &mut [1, 2, 3][..]; let _ = &a[..]; + //~^ deref_by_slicing } diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.stderr b/src/tools/clippy/tests/ui/deref_by_slicing.stderr index ceb9ab6db73dc..4a379a83dfa7a 100644 --- a/src/tools/clippy/tests/ui/deref_by_slicing.stderr +++ b/src/tools/clippy/tests/ui/deref_by_slicing.stderr @@ -8,55 +8,55 @@ LL | let _ = &vec[..]; = help: to override `-D warnings` add `#[allow(clippy::deref_by_slicing)]` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:9:13 + --> tests/ui/deref_by_slicing.rs:10:13 | LL | let _ = &mut vec[..]; | ^^^^^^^^^^^^ help: dereference the original value instead: `&mut *vec` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:12:13 + --> tests/ui/deref_by_slicing.rs:14:13 | LL | let _ = &ref_vec[..]; | ^^^^^^^^^^^^ help: dereference the original value instead: `&**ref_vec` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:13:21 + --> tests/ui/deref_by_slicing.rs:16:21 | LL | let mut_slice = &mut ref_vec[..]; | ^^^^^^^^^^^^^^^^ help: dereference the original value instead: `&mut **ref_vec` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:14:13 + --> tests/ui/deref_by_slicing.rs:18:13 | LL | let _ = &mut mut_slice[..]; // Err, re-borrows slice | ^^^^^^^^^^^^^^^^^^ help: reborrow the original value instead: `&mut *mut_slice` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:17:13 + --> tests/ui/deref_by_slicing.rs:23:13 | LL | let _ = &s[..]; | ^^^^^^ help: dereference the original value instead: `&*s` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:20:18 + --> tests/ui/deref_by_slicing.rs:27:18 | LL | let _ = &mut &S[..]; // Err, re-borrows slice | ^^^^^^ help: reborrow the original value instead: `&*S` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:24:13 + --> tests/ui/deref_by_slicing.rs:33:13 | LL | let _ = &slice_ref[..]; // Err, derefs slice | ^^^^^^^^^^^^^^ help: dereference the original value instead: `*slice_ref` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:27:13 + --> tests/ui/deref_by_slicing.rs:38:13 | LL | let _ = (&bytes[..]).read_to_end(&mut vec![]).unwrap(); // Err, re-borrows slice | ^^^^^^^^^^^^ help: reborrow the original value instead: `(&*bytes)` error: slicing when dereferencing would work - --> tests/ui/deref_by_slicing.rs:31:13 + --> tests/ui/deref_by_slicing.rs:44:13 | LL | let _ = &a[..]; | ^^^^^^ help: reborrow the original value instead: `&*a` diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed index c85f384fd6eb9..65bfded38835e 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.fixed +++ b/src/tools/clippy/tests/ui/derivable_impls.fixed @@ -144,6 +144,40 @@ impl Default for SpecializedImpl2 { } } +#[derive(Default)] +pub struct DirectDefaultDefaultCall { + v: Vec, +} + + +#[derive(Default)] +pub struct EquivalentToDefaultDefaultCallVec { + v: Vec, +} + + +pub struct S { + x: i32, +} + +impl S { + fn new() -> S { + S { x: 42 } + } +} + +impl Default for S { + fn default() -> Self { + Self::new() + } +} + +#[derive(Default)] +pub struct EquivalentToDefaultDefaultCallLocal { + v: S, +} + + // https://github.com/rust-lang/rust-clippy/issues/7654 pub struct Color { diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs index 21d73ba8b7778..4826c5497b4a3 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.rs +++ b/src/tools/clippy/tests/ui/derivable_impls.rs @@ -18,6 +18,7 @@ struct FooDefault<'a> { } impl std::default::Default for FooDefault<'_> { + //~^ derivable_impls fn default() -> Self { Self { a: false, @@ -39,6 +40,7 @@ impl std::default::Default for FooDefault<'_> { struct TupleDefault(bool, i32, u64); impl std::default::Default for TupleDefault { + //~^ derivable_impls fn default() -> Self { Self(false, 0, 0u64) } @@ -91,6 +93,7 @@ impl Default for FooNDVec { struct StrDefault<'a>(&'a str); impl Default for StrDefault<'_> { + //~^ derivable_impls fn default() -> Self { Self("") } @@ -117,6 +120,7 @@ mac!(0); struct Y(u32); impl Default for Y { + //~^ derivable_impls fn default() -> Self { Self(mac!()) } @@ -156,6 +160,7 @@ struct WithoutSelfCurly { } impl Default for WithoutSelfCurly { + //~^ derivable_impls fn default() -> Self { WithoutSelfCurly { a: false } } @@ -164,6 +169,7 @@ impl Default for WithoutSelfCurly { struct WithoutSelfParan(bool); impl Default for WithoutSelfParan { + //~^ derivable_impls fn default() -> Self { WithoutSelfParan(false) } @@ -181,6 +187,58 @@ impl Default for SpecializedImpl2 { } } +pub struct DirectDefaultDefaultCall { + v: Vec, +} + +impl Default for DirectDefaultDefaultCall { + //~^ derivable_impls + fn default() -> Self { + // When calling `Default::default()` in all fields, we know it is the same as deriving. + Self { v: Default::default() } + } +} + +pub struct EquivalentToDefaultDefaultCallVec { + v: Vec, +} + +impl Default for EquivalentToDefaultDefaultCallVec { + //~^ derivable_impls + fn default() -> Self { + // The body of `::default()` is `Vec::new()`, so they are equivalent. + Self { v: Vec::new() } + } +} + +pub struct S { + x: i32, +} + +impl S { + fn new() -> S { + S { x: 42 } + } +} + +impl Default for S { + fn default() -> Self { + Self::new() + } +} + +pub struct EquivalentToDefaultDefaultCallLocal { + v: S, +} + +impl Default for EquivalentToDefaultDefaultCallLocal { + //~^ derivable_impls + fn default() -> Self { + // The body of `::default()` is `S::new()`, so they are equivalent. + Self { v: S::new() } + } +} + // https://github.com/rust-lang/rust-clippy/issues/7654 pub struct Color { @@ -214,6 +272,7 @@ pub struct RepeatDefault1 { } impl Default for RepeatDefault1 { + //~^ derivable_impls fn default() -> Self { RepeatDefault1 { a: [0; 32] } } @@ -248,6 +307,7 @@ pub enum SimpleEnum { } impl Default for SimpleEnum { + //~^ derivable_impls fn default() -> Self { SimpleEnum::Bar } diff --git a/src/tools/clippy/tests/ui/derivable_impls.stderr b/src/tools/clippy/tests/ui/derivable_impls.stderr index 0caea892358a0..0f73ad55a85eb 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.stderr +++ b/src/tools/clippy/tests/ui/derivable_impls.stderr @@ -2,9 +2,9 @@ error: this `impl` can be derived --> tests/ui/derivable_impls.rs:20:1 | LL | / impl std::default::Default for FooDefault<'_> { +LL | | LL | | fn default() -> Self { LL | | Self { -LL | | a: false, ... | LL | | } | |_^ @@ -18,9 +18,10 @@ LL ~ struct FooDefault<'a> { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:41:1 + --> tests/ui/derivable_impls.rs:42:1 | LL | / impl std::default::Default for TupleDefault { +LL | | LL | | fn default() -> Self { LL | | Self(false, 0, 0u64) LL | | } @@ -34,9 +35,10 @@ LL ~ struct TupleDefault(bool, i32, u64); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:93:1 + --> tests/ui/derivable_impls.rs:95:1 | LL | / impl Default for StrDefault<'_> { +LL | | LL | | fn default() -> Self { LL | | Self("") LL | | } @@ -50,9 +52,10 @@ LL ~ struct StrDefault<'a>(&'a str); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:119:1 + --> tests/ui/derivable_impls.rs:122:1 | LL | / impl Default for Y { +LL | | LL | | fn default() -> Self { LL | | Self(mac!()) LL | | } @@ -66,9 +69,10 @@ LL ~ struct Y(u32); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:158:1 + --> tests/ui/derivable_impls.rs:162:1 | LL | / impl Default for WithoutSelfCurly { +LL | | LL | | fn default() -> Self { LL | | WithoutSelfCurly { a: false } LL | | } @@ -82,9 +86,10 @@ LL ~ struct WithoutSelfCurly { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:166:1 + --> tests/ui/derivable_impls.rs:171:1 | LL | / impl Default for WithoutSelfParan { +LL | | LL | | fn default() -> Self { LL | | WithoutSelfParan(false) LL | | } @@ -98,9 +103,58 @@ LL ~ struct WithoutSelfParan(bool); | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:216:1 + --> tests/ui/derivable_impls.rs:194:1 + | +LL | / impl Default for DirectDefaultDefaultCall { +LL | | +LL | | fn default() -> Self { +... | +LL | | } + | |_^ + | +help: replace the manual implementation with a derive attribute + | +LL + #[derive(Default)] +LL ~ pub struct DirectDefaultDefaultCall { + | + +error: this `impl` can be derived + --> tests/ui/derivable_impls.rs:206:1 + | +LL | / impl Default for EquivalentToDefaultDefaultCallVec { +LL | | +LL | | fn default() -> Self { +... | +LL | | } + | |_^ + | +help: replace the manual implementation with a derive attribute + | +LL + #[derive(Default)] +LL ~ pub struct EquivalentToDefaultDefaultCallVec { + | + +error: this `impl` can be derived + --> tests/ui/derivable_impls.rs:234:1 + | +LL | / impl Default for EquivalentToDefaultDefaultCallLocal { +LL | | +LL | | fn default() -> Self { +... | +LL | | } + | |_^ + | +help: replace the manual implementation with a derive attribute + | +LL + #[derive(Default)] +LL ~ pub struct EquivalentToDefaultDefaultCallLocal { + | + +error: this `impl` can be derived + --> tests/ui/derivable_impls.rs:274:1 | LL | / impl Default for RepeatDefault1 { +LL | | LL | | fn default() -> Self { LL | | RepeatDefault1 { a: [0; 32] } LL | | } @@ -114,9 +168,10 @@ LL ~ pub struct RepeatDefault1 { | error: this `impl` can be derived - --> tests/ui/derivable_impls.rs:250:1 + --> tests/ui/derivable_impls.rs:309:1 | LL | / impl Default for SimpleEnum { +LL | | LL | | fn default() -> Self { LL | | SimpleEnum::Bar LL | | } @@ -132,5 +187,5 @@ LL ~ #[default] LL ~ Bar, | -error: aborting due to 8 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs index d03cc01a08b0b..707a9ff058576 100644 --- a/src/tools/clippy/tests/ui/derive.rs +++ b/src/tools/clippy/tests/ui/derive.rs @@ -12,7 +12,8 @@ struct Qux; impl Clone for Qux { - //~^ ERROR: you are implementing `Clone` explicitly on a `Copy` type + //~^ expl_impl_clone_on_copy + fn clone(&self) -> Self { Qux } @@ -37,7 +38,8 @@ struct Lt<'a> { } impl<'a> Clone for Lt<'a> { - //~^ ERROR: you are implementing `Clone` explicitly on a `Copy` type + //~^ expl_impl_clone_on_copy + fn clone(&self) -> Self { unimplemented!() } @@ -49,7 +51,8 @@ struct BigArray { } impl Clone for BigArray { - //~^ ERROR: you are implementing `Clone` explicitly on a `Copy` type + //~^ expl_impl_clone_on_copy + fn clone(&self) -> Self { unimplemented!() } @@ -61,7 +64,8 @@ struct FnPtr { } impl Clone for FnPtr { - //~^ ERROR: you are implementing `Clone` explicitly on a `Copy` type + //~^ expl_impl_clone_on_copy + fn clone(&self) -> Self { unimplemented!() } @@ -82,7 +86,8 @@ impl Clone for Generic { #[derive(Copy)] struct Generic2(T); impl Clone for Generic2 { - //~^ ERROR: you are implementing `Clone` explicitly on a `Copy` type + //~^ expl_impl_clone_on_copy + fn clone(&self) -> Self { Self(self.0.clone()) } diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr index d70a59855229d..20278d4f4e4a4 100644 --- a/src/tools/clippy/tests/ui/derive.stderr +++ b/src/tools/clippy/tests/ui/derive.stderr @@ -3,9 +3,9 @@ error: you are implementing `Clone` explicitly on a `Copy` type | LL | / impl Clone for Qux { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | Qux -LL | | } +... | LL | | } | |_^ | @@ -14,99 +14,99 @@ note: consider deriving `Clone` or removing `Copy` | LL | / impl Clone for Qux { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | Qux -LL | | } +... | LL | | } | |_^ = note: `-D clippy::expl-impl-clone-on-copy` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]` error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:39:1 + --> tests/ui/derive.rs:40:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | unimplemented!() -LL | | } +... | LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:39:1 + --> tests/ui/derive.rs:40:1 | LL | / impl<'a> Clone for Lt<'a> { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | unimplemented!() -LL | | } +... | LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:51:1 + --> tests/ui/derive.rs:53:1 | LL | / impl Clone for BigArray { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | unimplemented!() -LL | | } +... | LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:51:1 + --> tests/ui/derive.rs:53:1 | LL | / impl Clone for BigArray { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | unimplemented!() -LL | | } +... | LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:63:1 + --> tests/ui/derive.rs:66:1 | LL | / impl Clone for FnPtr { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | unimplemented!() -LL | | } +... | LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:63:1 + --> tests/ui/derive.rs:66:1 | LL | / impl Clone for FnPtr { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | unimplemented!() -LL | | } +... | LL | | } | |_^ error: you are implementing `Clone` explicitly on a `Copy` type - --> tests/ui/derive.rs:84:1 + --> tests/ui/derive.rs:88:1 | LL | / impl Clone for Generic2 { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | Self(self.0.clone()) -LL | | } +... | LL | | } | |_^ | note: consider deriving `Clone` or removing `Copy` - --> tests/ui/derive.rs:84:1 + --> tests/ui/derive.rs:88:1 | LL | / impl Clone for Generic2 { LL | | +LL | | LL | | fn clone(&self) -> Self { -LL | | Self(self.0.clone()) -LL | | } +... | LL | | } | |_^ diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs index 1c7e6d1c20230..3ef4ee9463dca 100644 --- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs +++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.rs @@ -20,7 +20,8 @@ impl PartialOrd for DeriveBoth { } #[derive(Ord, PartialEq, Eq)] -//~^ ERROR: you are deriving `Ord` but have implemented `PartialOrd` explicitly +//~^ derive_ord_xor_partial_ord + struct DeriveOrd; impl PartialOrd for DeriveOrd { @@ -30,7 +31,8 @@ impl PartialOrd for DeriveOrd { } #[derive(Ord, PartialEq, Eq)] -//~^ ERROR: you are deriving `Ord` but have implemented `PartialOrd` explicitly +//~^ derive_ord_xor_partial_ord + struct DeriveOrdWithExplicitTypeVariable; impl PartialOrd for DeriveOrdWithExplicitTypeVariable { @@ -43,7 +45,8 @@ impl PartialOrd for DeriveOrdWithExplicitType struct DerivePartialOrd; impl std::cmp::Ord for DerivePartialOrd { - //~^ ERROR: you are implementing `Ord` explicitly but have derived `PartialOrd` + //~^ derive_ord_xor_partial_ord + fn cmp(&self, other: &Self) -> Ordering { Ordering::Less } @@ -64,7 +67,8 @@ mod use_ord { struct DerivePartialOrdInUseOrd; impl Ord for DerivePartialOrdInUseOrd { - //~^ ERROR: you are implementing `Ord` explicitly but have derived `PartialOrd` + //~^ derive_ord_xor_partial_ord + fn cmp(&self, other: &Self) -> Ordering { Ordering::Less } diff --git a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr index dcf32419baa29..76dca3c79470a 100644 --- a/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr +++ b/src/tools/clippy/tests/ui/derive_ord_xor_partial_ord.stderr @@ -5,62 +5,58 @@ LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | note: `PartialOrd` implemented here - --> tests/ui/derive_ord_xor_partial_ord.rs:26:1 + --> tests/ui/derive_ord_xor_partial_ord.rs:27:1 | LL | impl PartialOrd for DeriveOrd { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::derive-ord-xor-partial-ord` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::derive_ord_xor_partial_ord)]` - = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Ord` but have implemented `PartialOrd` explicitly - --> tests/ui/derive_ord_xor_partial_ord.rs:32:10 + --> tests/ui/derive_ord_xor_partial_ord.rs:33:10 | LL | #[derive(Ord, PartialEq, Eq)] | ^^^ | note: `PartialOrd` implemented here - --> tests/ui/derive_ord_xor_partial_ord.rs:36:1 + --> tests/ui/derive_ord_xor_partial_ord.rs:38:1 | LL | impl PartialOrd for DeriveOrdWithExplicitTypeVariable { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Ord` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> tests/ui/derive_ord_xor_partial_ord.rs:45:1 + --> tests/ui/derive_ord_xor_partial_ord.rs:47:1 | LL | / impl std::cmp::Ord for DerivePartialOrd { LL | | +LL | | LL | | fn cmp(&self, other: &Self) -> Ordering { -LL | | Ordering::Less -LL | | } +... | LL | | } | |_^ | note: `PartialOrd` implemented here - --> tests/ui/derive_ord_xor_partial_ord.rs:42:10 + --> tests/ui/derive_ord_xor_partial_ord.rs:44:10 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ - = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are implementing `Ord` explicitly but have derived `PartialOrd` - --> tests/ui/derive_ord_xor_partial_ord.rs:66:5 + --> tests/ui/derive_ord_xor_partial_ord.rs:69:5 | LL | / impl Ord for DerivePartialOrdInUseOrd { LL | | +LL | | LL | | fn cmp(&self, other: &Self) -> Ordering { -LL | | Ordering::Less -LL | | } +... | LL | | } | |_____^ | note: `PartialOrd` implemented here - --> tests/ui/derive_ord_xor_partial_ord.rs:63:14 + --> tests/ui/derive_ord_xor_partial_ord.rs:66:14 | LL | #[derive(PartialOrd, PartialEq, Eq)] | ^^^^^^^^^^ - = note: this error originates in the derive macro `PartialOrd` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed index e4a33193a1ab4..00f51d6acb94f 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed @@ -9,6 +9,7 @@ pub struct NotPartialEq { // Eq can be derived but is missing #[derive(Debug, PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub struct MissingEq { foo: u32, bar: String, @@ -67,33 +68,39 @@ impl PartialEq for ManualPartialEqImpl { // Generic fields should be properly checked for Eq-ness #[derive(PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub struct GenericNotEq { foo: T, bar: U, } #[derive(PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub struct GenericEq { foo: T, bar: U, } #[derive(PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub struct TupleStruct(u32); #[derive(PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub struct GenericTupleStruct(T); #[derive(PartialEq)] pub struct TupleStructNotEq(f32); #[derive(PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub enum Enum { Foo(u32), Bar { a: String, b: () }, } #[derive(PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub enum GenericEnum { Foo(T), Bar { a: U, b: V }, @@ -107,9 +114,11 @@ pub enum EnumNotEq { // Ensure that rustfix works properly when `PartialEq` has other derives on either side #[derive(Debug, PartialEq, Eq, Clone)] +//~^ derive_partial_eq_without_eq pub struct RustFixWithOtherDerives; #[derive(PartialEq, Eq)] +//~^ derive_partial_eq_without_eq pub struct Generic(T); #[derive(PartialEq, Eq)] @@ -117,9 +126,11 @@ pub struct GenericPhantom(core::marker::PhantomData); mod _hidden { #[derive(PartialEq, Eq)] + //~^ derive_partial_eq_without_eq pub struct Reexported; #[derive(PartialEq, Eq)] + //~^ derive_partial_eq_without_eq pub struct InPubFn; #[derive(PartialEq)] @@ -180,7 +191,8 @@ mod struct_gen { } #[derive(PartialEq, Eq)] - //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + //~^ derive_partial_eq_without_eq + pub struct Foo(::Element); #[derive(PartialEq, Eq)] @@ -188,7 +200,8 @@ mod struct_gen { // issue 9319 #[derive(PartialEq, Eq)] - //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + //~^ derive_partial_eq_without_eq + pub struct Oof(T); #[derive(PartialEq, Eq)] diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs index a418b38e34999..073330468d318 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs @@ -9,6 +9,7 @@ pub struct NotPartialEq { // Eq can be derived but is missing #[derive(Debug, PartialEq)] +//~^ derive_partial_eq_without_eq pub struct MissingEq { foo: u32, bar: String, @@ -67,33 +68,39 @@ impl PartialEq for ManualPartialEqImpl { // Generic fields should be properly checked for Eq-ness #[derive(PartialEq)] +//~^ derive_partial_eq_without_eq pub struct GenericNotEq { foo: T, bar: U, } #[derive(PartialEq)] +//~^ derive_partial_eq_without_eq pub struct GenericEq { foo: T, bar: U, } #[derive(PartialEq)] +//~^ derive_partial_eq_without_eq pub struct TupleStruct(u32); #[derive(PartialEq)] +//~^ derive_partial_eq_without_eq pub struct GenericTupleStruct(T); #[derive(PartialEq)] pub struct TupleStructNotEq(f32); #[derive(PartialEq)] +//~^ derive_partial_eq_without_eq pub enum Enum { Foo(u32), Bar { a: String, b: () }, } #[derive(PartialEq)] +//~^ derive_partial_eq_without_eq pub enum GenericEnum { Foo(T), Bar { a: U, b: V }, @@ -107,9 +114,11 @@ pub enum EnumNotEq { // Ensure that rustfix works properly when `PartialEq` has other derives on either side #[derive(Debug, PartialEq, Clone)] +//~^ derive_partial_eq_without_eq pub struct RustFixWithOtherDerives; #[derive(PartialEq)] +//~^ derive_partial_eq_without_eq pub struct Generic(T); #[derive(PartialEq, Eq)] @@ -117,9 +126,11 @@ pub struct GenericPhantom(core::marker::PhantomData); mod _hidden { #[derive(PartialEq)] + //~^ derive_partial_eq_without_eq pub struct Reexported; #[derive(PartialEq)] + //~^ derive_partial_eq_without_eq pub struct InPubFn; #[derive(PartialEq)] @@ -180,7 +191,8 @@ mod struct_gen { } #[derive(PartialEq)] - //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + //~^ derive_partial_eq_without_eq + pub struct Foo(::Element); #[derive(PartialEq, Eq)] @@ -188,7 +200,8 @@ mod struct_gen { // issue 9319 #[derive(PartialEq)] - //~^ ERROR: you are deriving `PartialEq` and can implement `Eq` + //~^ derive_partial_eq_without_eq + pub struct Oof(T); #[derive(PartialEq, Eq)] diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr index 7436114fadb2e..fd9bac28a711c 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.stderr @@ -8,73 +8,73 @@ LL | #[derive(Debug, PartialEq)] = help: to override `-D warnings` add `#[allow(clippy::derive_partial_eq_without_eq)]` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:69:10 + --> tests/ui/derive_partial_eq_without_eq.rs:70:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:75:10 + --> tests/ui/derive_partial_eq_without_eq.rs:77:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:81:10 + --> tests/ui/derive_partial_eq_without_eq.rs:84:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:84:10 + --> tests/ui/derive_partial_eq_without_eq.rs:88:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:90:10 + --> tests/ui/derive_partial_eq_without_eq.rs:95:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:96:10 + --> tests/ui/derive_partial_eq_without_eq.rs:102:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:109:17 + --> tests/ui/derive_partial_eq_without_eq.rs:116:17 | LL | #[derive(Debug, PartialEq, Clone)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:112:10 + --> tests/ui/derive_partial_eq_without_eq.rs:120:10 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:119:14 + --> tests/ui/derive_partial_eq_without_eq.rs:128:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:122:14 + --> tests/ui/derive_partial_eq_without_eq.rs:132:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:182:14 + --> tests/ui/derive_partial_eq_without_eq.rs:193:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` error: you are deriving `PartialEq` and can implement `Eq` - --> tests/ui/derive_partial_eq_without_eq.rs:190:14 + --> tests/ui/derive_partial_eq_without_eq.rs:202:14 | LL | #[derive(PartialEq)] | ^^^^^^^^^ help: consider deriving `Eq` as well: `PartialEq, Eq` diff --git a/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs index 8423699d99ed8..88b574add3f27 100644 --- a/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs +++ b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.rs @@ -10,7 +10,8 @@ impl PartialEq for Foo { } #[derive(Hash)] -//~^ ERROR: you are deriving `Hash` but have implemented `PartialEq` explicitly +//~^ derived_hash_with_manual_eq + struct Bar; impl PartialEq for Bar { @@ -20,7 +21,8 @@ impl PartialEq for Bar { } #[derive(Hash)] -//~^ ERROR: you are deriving `Hash` but have implemented `PartialEq` explicitly +//~^ derived_hash_with_manual_eq + struct Baz; impl PartialEq for Baz { diff --git a/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr index af4d247f95ba9..55740780c8a50 100644 --- a/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr +++ b/src/tools/clippy/tests/ui/derived_hash_with_manual_eq.stderr @@ -5,25 +5,23 @@ LL | #[derive(Hash)] | ^^^^ | note: `PartialEq` implemented here - --> tests/ui/derived_hash_with_manual_eq.rs:16:1 + --> tests/ui/derived_hash_with_manual_eq.rs:17:1 | LL | impl PartialEq for Bar { | ^^^^^^^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::derived_hash_with_manual_eq)]` on by default - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: you are deriving `Hash` but have implemented `PartialEq` explicitly - --> tests/ui/derived_hash_with_manual_eq.rs:22:10 + --> tests/ui/derived_hash_with_manual_eq.rs:23:10 | LL | #[derive(Hash)] | ^^^^ | note: `PartialEq` implemented here - --> tests/ui/derived_hash_with_manual_eq.rs:26:1 + --> tests/ui/derived_hash_with_manual_eq.rs:28:1 | LL | impl PartialEq for Baz { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs index 96531bf8d88ca..30fbdbc1fdc82 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.rs +++ b/src/tools/clippy/tests/ui/disallowed_names.rs @@ -10,16 +10,18 @@ #![warn(clippy::disallowed_names)] fn test(foo: ()) {} -//~^ ERROR: use of a disallowed/placeholder name `foo` -//~| NOTE: `-D clippy::disallowed-names` implied by `-D warnings` +//~^ disallowed_names fn main() { let foo = 42; - //~^ ERROR: use of a disallowed/placeholder name `foo` + //~^ disallowed_names + let baz = 42; - //~^ ERROR: use of a disallowed/placeholder name `baz` + //~^ disallowed_names + let quux = 42; - //~^ ERROR: use of a disallowed/placeholder name `quux` + //~^ disallowed_names + // Unlike these others, `bar` is actually considered an acceptable name. // Among many other legitimate uses, bar commonly refers to a period of time in music. // See https://github.com/rust-lang/rust-clippy/issues/5225. @@ -31,33 +33,37 @@ fn main() { match (42, Some(1337), Some(0)) { (foo, Some(baz), quux @ Some(_)) => (), - //~^ ERROR: use of a disallowed/placeholder name `foo` - //~| ERROR: use of a disallowed/placeholder name `baz` - //~| ERROR: use of a disallowed/placeholder name `quux` + //~^ disallowed_names + //~| disallowed_names + //~| disallowed_names _ => (), } } fn issue_1647(mut foo: u8) { - //~^ ERROR: use of a disallowed/placeholder name `foo` + //~^ disallowed_names + let mut baz = 0; - //~^ ERROR: use of a disallowed/placeholder name `baz` + //~^ disallowed_names + if let Some(mut quux) = Some(42) {} - //~^ ERROR: use of a disallowed/placeholder name `quux` + //~^ disallowed_names } fn issue_1647_ref() { let ref baz = 0; - //~^ ERROR: use of a disallowed/placeholder name `baz` + //~^ disallowed_names + if let Some(ref quux) = Some(42) {} - //~^ ERROR: use of a disallowed/placeholder name `quux` + //~^ disallowed_names } fn issue_1647_ref_mut() { let ref mut baz = 0; - //~^ ERROR: use of a disallowed/placeholder name `baz` + //~^ disallowed_names + if let Some(ref mut quux) = Some(42) {} - //~^ ERROR: use of a disallowed/placeholder name `quux` + //~^ disallowed_names } #[cfg(test)] diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr index d131cad8e11e9..09398ebbab77f 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.stderr +++ b/src/tools/clippy/tests/ui/disallowed_names.stderr @@ -8,7 +8,7 @@ LL | fn test(foo: ()) {} = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:17:9 + --> tests/ui/disallowed_names.rs:16:9 | LL | let foo = 42; | ^^^ @@ -20,67 +20,67 @@ LL | let baz = 42; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:21:9 + --> tests/ui/disallowed_names.rs:22:9 | LL | let quux = 42; | ^^^^ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:33:10 + --> tests/ui/disallowed_names.rs:35:10 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:33:20 + --> tests/ui/disallowed_names.rs:35:20 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:33:26 + --> tests/ui/disallowed_names.rs:35:26 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^^ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:41:19 + --> tests/ui/disallowed_names.rs:43:19 | LL | fn issue_1647(mut foo: u8) { | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:43:13 + --> tests/ui/disallowed_names.rs:46:13 | LL | let mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:45:21 + --> tests/ui/disallowed_names.rs:49:21 | LL | if let Some(mut quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:50:13 + --> tests/ui/disallowed_names.rs:54:13 | LL | let ref baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:52:21 + --> tests/ui/disallowed_names.rs:57:21 | LL | if let Some(ref quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:57:17 + --> tests/ui/disallowed_names.rs:62:17 | LL | let ref mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:59:25 + --> tests/ui/disallowed_names.rs:65:25 | LL | if let Some(ref mut quux) = Some(42) {} | ^^^^ diff --git a/src/tools/clippy/tests/ui/disallowed_script_idents.rs b/src/tools/clippy/tests/ui/disallowed_script_idents.rs index 6b68fae318c03..08fd1d9669ee9 100644 --- a/src/tools/clippy/tests/ui/disallowed_script_idents.rs +++ b/src/tools/clippy/tests/ui/disallowed_script_idents.rs @@ -9,8 +9,9 @@ fn main() { // Cyrillic is not allowed by default. let счётчик = 10; - //~^ ERROR: identifier `счётчик` has a Unicode script that is not allowed by configura + //~^ disallowed_script_idents + // Same for japanese. let カウンタ = 10; - //~^ ERROR: identifier `カウンタ` has a Unicode script that is not allowed by configuratio + //~^ disallowed_script_idents } diff --git a/src/tools/clippy/tests/ui/disallowed_script_idents.stderr b/src/tools/clippy/tests/ui/disallowed_script_idents.stderr index c11655ab6021e..edbcea5e5dd6d 100644 --- a/src/tools/clippy/tests/ui/disallowed_script_idents.stderr +++ b/src/tools/clippy/tests/ui/disallowed_script_idents.stderr @@ -11,7 +11,7 @@ LL | #![deny(clippy::disallowed_script_idents)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: identifier `カウンタ` has a Unicode script that is not allowed by configuration: Katakana - --> tests/ui/disallowed_script_idents.rs:14:9 + --> tests/ui/disallowed_script_idents.rs:15:9 | LL | let カウンタ = 10; | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.rs b/src/tools/clippy/tests/ui/diverging_sub_expression.rs index 1abba60fd34a8..b226ba69799e7 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.rs +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.rs @@ -18,10 +18,10 @@ impl A { fn main() { let b = true; b || diverge(); - //~^ ERROR: sub-expression diverges - //~| NOTE: `-D clippy::diverging-sub-expression` implied by `-D warnings` + //~^ diverging_sub_expression + b || A.foo(); - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression } #[allow(dead_code, unused_variables)] @@ -32,28 +32,36 @@ fn foobar() { 4 => return, 5 => continue, 6 => true || return, - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + 7 => true || continue, - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + 8 => break, 9 => diverge(), 3 => true || diverge(), - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + 10 => match 42 { 99 => return, _ => true || panic!("boo"), - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + }, // lint blocks as well 15 => true || { return; }, - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + 16 => false || { return; }, - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + // ... and when it's a single expression 17 => true || { return }, - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + 18 => false || { return }, - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + // ... but not when there's both an expression and a statement 19 => true || { _ = 1; return }, 20 => false || { _ = 1; return }, @@ -63,7 +71,8 @@ fn foobar() { 23 => true || { return; true }, 24 => true || { return; true }, _ => true || break, - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression + }; } } diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr index f90c95696a9cc..ba08eb4e5f4b5 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr @@ -20,51 +20,49 @@ LL | 6 => true || return, | ^^^^^^ error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:36:26 + --> tests/ui/diverging_sub_expression.rs:37:26 | LL | 7 => true || continue, | ^^^^^^^^ error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:40:26 + --> tests/ui/diverging_sub_expression.rs:42:26 | LL | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:44:30 + --> tests/ui/diverging_sub_expression.rs:47:30 | LL | _ => true || panic!("boo"), | ^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:48:29 + --> tests/ui/diverging_sub_expression.rs:52:29 | LL | 15 => true || { return; }, | ^^^^^^ error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:50:30 + --> tests/ui/diverging_sub_expression.rs:55:30 | LL | 16 => false || { return; }, | ^^^^^^ error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:53:29 + --> tests/ui/diverging_sub_expression.rs:59:29 | LL | 17 => true || { return }, | ^^^^^^ error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:55:30 + --> tests/ui/diverging_sub_expression.rs:62:30 | LL | 18 => false || { return }, | ^^^^^^ error: sub-expression diverges - --> tests/ui/diverging_sub_expression.rs:65:26 + --> tests/ui/diverging_sub_expression.rs:73:26 | LL | _ => true || break, | ^^^^^ diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index 83574a5cd98d0..5f2b697f88b02 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -7,13 +7,22 @@ #![rustfmt::skip] /// The `foo_bar` function does _nothing_. See also `foo::bar`. (note the dot there) +//~^ doc_markdown +//~| doc_markdown /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not `Foo::some_fun` +//~^ doc_markdown /// which should be reported only once despite being __doubly bad__. /// Here be `::a::global:path`, and _`::another::global::path`_. :: is not a path though. +//~^ doc_markdown +//~| doc_markdown /// Import an item from `::awesome::global::blob::` (Intended postfix) +//~^ doc_markdown /// These are the options for `::Cat`: (Intended trailing single colon, shouldn't be linted) +//~^ doc_markdown /// That's not code ~`NotInCodeBlock`~. +//~^ doc_markdown /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn foo_bar() { } @@ -28,6 +37,7 @@ fn foo_bar() { /// _foo bar_ /// ~~~ /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn multiline_codeblock() { } @@ -35,6 +45,7 @@ fn multiline_codeblock() { /// multiline /// emphasis_. /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn test_emphasis() { } @@ -49,6 +60,7 @@ fn test_emphasis() { /// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb /// NaN /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn test_units() { } @@ -77,6 +89,7 @@ fn test_units() { /// MinGW /// CamelCase (see also #2395) /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn test_allowed() { } @@ -94,6 +107,7 @@ fn test_allowed() { /// expression of the type `_ m c` (where `` /// is one of {`&`, '|'} and `` is one of {`!=`, `>=`, `>` , /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn main() { foo_bar(); multiline_codeblock(); @@ -102,12 +116,16 @@ fn main() { } /// ## `CamelCaseThing` +//~^ doc_markdown /// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897. /// /// # `CamelCaseThing` +//~^ doc_markdown /// /// Not a title #897 `CamelCaseThing` +//~^ doc_markdown /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn issue897() { } @@ -115,6 +133,7 @@ fn issue897() { /// I am confused by brackets? (foo `x_y`) /// I am confused by brackets? (`x_y` foo) /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn issue900() { } @@ -128,6 +147,7 @@ fn issue900() { /// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html /// [helper_types]: ../helper_types/index.html /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn issue883() { } @@ -146,6 +166,9 @@ That's in a code block: `PackedNode` And `BarQuz` too. `be_sure_we_got_to_the_end_of_it` */ +//~^^^ doc_markdown +//~^^^ doc_markdown +//~^^^^^^^^^^ doc_markdown fn issue1073() { } @@ -157,6 +180,9 @@ That's in a code block: PackedNode And `BarQuz` too. `be_sure_we_got_to_the_end_of_it` */ +//~^^ doc_markdown +//~^^^^ doc_markdown +//~^^^^^^^^^^ doc_markdown fn issue1073_alt() { } @@ -167,6 +193,7 @@ fn issue1073_alt() { /// StillDont /// ```` /// `be_sure_we_got_to_the_end_of_it` +//~^ doc_markdown fn four_quotes() { } @@ -186,6 +213,7 @@ fn issue_1469() {} fn issue_1920() {} /// An iterator over `mycrate::Collection`'s values. +//~^ doc_markdown /// It should not lint a `'static` lifetime in ticks. fn issue_2210() {} @@ -210,6 +238,7 @@ fn intra_doc_link() {} fn issue_2581() {} /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` +//~^ doc_markdown fn lint_after_escaped_chars() {} // issue #7033 - generic_const_exprs ICE @@ -233,17 +262,22 @@ where [(); N.checked_next_power_of_two().unwrap()]: { fn issue_11568() {} /// There is no try (`do()` or `do_not()`). +//~^ doc_markdown +//~| doc_markdown fn parenthesized_word() {} /// `ABes` +//~^ doc_markdown /// OSes /// UXes fn plural_acronym_test() {} extern "C" { /// `foo()` + //~^ doc_markdown fn in_extern(); } /// +//~^ doc_markdown fn check_autofix_for_base_urls() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 20fe89cdc5369..ed3925694c67e 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -7,13 +7,22 @@ #![rustfmt::skip] /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there) +//~^ doc_markdown +//~| doc_markdown /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun +//~^ doc_markdown /// which should be reported only once despite being __doubly bad__. /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. +//~^ doc_markdown +//~| doc_markdown /// Import an item from ::awesome::global::blob:: (Intended postfix) +//~^ doc_markdown /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) +//~^ doc_markdown /// That's not code ~NotInCodeBlock~. +//~^ doc_markdown /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn foo_bar() { } @@ -28,6 +37,7 @@ fn foo_bar() { /// _foo bar_ /// ~~~ /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn multiline_codeblock() { } @@ -35,6 +45,7 @@ fn multiline_codeblock() { /// multiline /// emphasis_. /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn test_emphasis() { } @@ -49,6 +60,7 @@ fn test_emphasis() { /// 32kb 32Mb 32Gb 32Tb 32Pb 32Eb /// NaN /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn test_units() { } @@ -77,6 +89,7 @@ fn test_units() { /// MinGW /// CamelCase (see also #2395) /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn test_allowed() { } @@ -94,6 +107,7 @@ fn test_allowed() { /// expression of the type `_ m c` (where `` /// is one of {`&`, '|'} and `` is one of {`!=`, `>=`, `>` , /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn main() { foo_bar(); multiline_codeblock(); @@ -102,12 +116,16 @@ fn main() { } /// ## CamelCaseThing +//~^ doc_markdown /// Talks about `CamelCaseThing`. Titles should be ignored; see issue #897. /// /// # CamelCaseThing +//~^ doc_markdown /// /// Not a title #897 CamelCaseThing +//~^ doc_markdown /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn issue897() { } @@ -115,6 +133,7 @@ fn issue897() { /// I am confused by brackets? (foo `x_y`) /// I am confused by brackets? (`x_y` foo) /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn issue900() { } @@ -128,6 +147,7 @@ fn issue900() { /// [iterator]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html /// [helper_types]: ../helper_types/index.html /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn issue883() { } @@ -146,6 +166,9 @@ That's in a code block: `PackedNode` And BarQuz too. be_sure_we_got_to_the_end_of_it */ +//~^^^ doc_markdown +//~^^^ doc_markdown +//~^^^^^^^^^^ doc_markdown fn issue1073() { } @@ -157,6 +180,9 @@ That's in a code block: PackedNode And BarQuz too. be_sure_we_got_to_the_end_of_it */ +//~^^ doc_markdown +//~^^^^ doc_markdown +//~^^^^^^^^^^ doc_markdown fn issue1073_alt() { } @@ -167,6 +193,7 @@ fn issue1073_alt() { /// StillDont /// ```` /// be_sure_we_got_to_the_end_of_it +//~^ doc_markdown fn four_quotes() { } @@ -186,6 +213,7 @@ fn issue_1469() {} fn issue_1920() {} /// An iterator over mycrate::Collection's values. +//~^ doc_markdown /// It should not lint a `'static` lifetime in ticks. fn issue_2210() {} @@ -210,6 +238,7 @@ fn intra_doc_link() {} fn issue_2581() {} /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint +//~^ doc_markdown fn lint_after_escaped_chars() {} // issue #7033 - generic_const_exprs ICE @@ -233,17 +262,22 @@ where [(); N.checked_next_power_of_two().unwrap()]: { fn issue_11568() {} /// There is no try (do() or do_not()). +//~^ doc_markdown +//~| doc_markdown fn parenthesized_word() {} /// ABes +//~^ doc_markdown /// OSes /// UXes fn plural_acronym_test() {} extern "C" { /// foo() + //~^ doc_markdown fn in_extern(); } /// https://github.com/rust-lang/rust-clippy/pull/12836 +//~^ doc_markdown fn check_autofix_for_base_urls() {} diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr index 54d7358148555..d67da75a230ca 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr @@ -25,7 +25,7 @@ LL + /// The foo_bar function does _nothing_. See also `foo::bar`. (note the dot | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:10:83 + --> tests/ui/doc/doc-fixable.rs:12:83 | LL | /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun | ^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. B | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:12:13 + --> tests/ui/doc/doc-fixable.rs:15:13 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + /// Here be `::a::global:path`, and _::another::global::path_. :: is not a | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:12:36 + --> tests/ui/doc/doc-fixable.rs:15:36 | LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though. | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + /// Here be ::a::global:path, and _`::another::global::path`_. :: is not a | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:13:25 + --> tests/ui/doc/doc-fixable.rs:18:25 | LL | /// Import an item from ::awesome::global::blob:: (Intended postfix) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + /// Import an item from `::awesome::global::blob::` (Intended postfix) | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:14:31 + --> tests/ui/doc/doc-fixable.rs:20:31 | LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted) | ^^^^^ @@ -85,7 +85,7 @@ LL + /// These are the options for `::Cat`: (Intended trailing single colon, sho | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:15:22 + --> tests/ui/doc/doc-fixable.rs:22:22 | LL | /// That's not code ~NotInCodeBlock~. | ^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + /// That's not code ~`NotInCodeBlock`~. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:16:5 + --> tests/ui/doc/doc-fixable.rs:24:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:30:5 + --> tests/ui/doc/doc-fixable.rs:39:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:37:5 + --> tests/ui/doc/doc-fixable.rs:47:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:51:5 + --> tests/ui/doc/doc-fixable.rs:62:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:79:5 + --> tests/ui/doc/doc-fixable.rs:91:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:96:5 + --> tests/ui/doc/doc-fixable.rs:109:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:104:8 + --> tests/ui/doc/doc-fixable.rs:118:8 | LL | /// ## CamelCaseThing | ^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + /// ## `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:107:7 + --> tests/ui/doc/doc-fixable.rs:122:7 | LL | /// # CamelCaseThing | ^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + /// # `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:109:22 + --> tests/ui/doc/doc-fixable.rs:125:22 | LL | /// Not a title #897 CamelCaseThing | ^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + /// Not a title #897 `CamelCaseThing` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:110:5 + --> tests/ui/doc/doc-fixable.rs:127:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:117:5 + --> tests/ui/doc/doc-fixable.rs:135:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:130:5 + --> tests/ui/doc/doc-fixable.rs:149:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:141:43 + --> tests/ui/doc/doc-fixable.rs:161:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -253,7 +253,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:146:5 + --> tests/ui/doc/doc-fixable.rs:166:5 | LL | And BarQuz too. | ^^^^^^ @@ -265,7 +265,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:147:1 + --> tests/ui/doc/doc-fixable.rs:167:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:152:43 + --> tests/ui/doc/doc-fixable.rs:175:43 | LL | /** E.g., serialization of an empty list: FooBar | ^^^^^^ @@ -289,7 +289,7 @@ LL + /** E.g., serialization of an empty list: `FooBar` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:157:5 + --> tests/ui/doc/doc-fixable.rs:180:5 | LL | And BarQuz too. | ^^^^^^ @@ -301,7 +301,7 @@ LL + And `BarQuz` too. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:158:1 + --> tests/ui/doc/doc-fixable.rs:181:1 | LL | be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:169:5 + --> tests/ui/doc/doc-fixable.rs:195:5 | LL | /// be_sure_we_got_to_the_end_of_it | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + /// `be_sure_we_got_to_the_end_of_it` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:188:22 + --> tests/ui/doc/doc-fixable.rs:215:22 | LL | /// An iterator over mycrate::Collection's values. | ^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + /// An iterator over `mycrate::Collection`'s values. | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:212:34 + --> tests/ui/doc/doc-fixable.rs:240:34 | LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint | ^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + /// Foo \[bar\] \[baz\] \[qux\]. `DocMarkdownLint` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:235:22 + --> tests/ui/doc/doc-fixable.rs:264:22 | LL | /// There is no try (do() or do_not()). | ^^^^ @@ -361,7 +361,7 @@ LL + /// There is no try (`do()` or do_not()). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:235:30 + --> tests/ui/doc/doc-fixable.rs:264:30 | LL | /// There is no try (do() or do_not()). | ^^^^^^^^ @@ -373,7 +373,7 @@ LL + /// There is no try (do() or `do_not()`). | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:238:5 + --> tests/ui/doc/doc-fixable.rs:269:5 | LL | /// ABes | ^^^^ @@ -385,7 +385,7 @@ LL + /// `ABes` | error: item in documentation is missing backticks - --> tests/ui/doc/doc-fixable.rs:244:9 + --> tests/ui/doc/doc-fixable.rs:276:9 | LL | /// foo() | ^^^^^ @@ -397,7 +397,7 @@ LL + /// `foo()` | error: you should put bare URLs between `<`/`>` or make a proper Markdown link - --> tests/ui/doc/doc-fixable.rs:248:5 + --> tests/ui/doc/doc-fixable.rs:281:5 | LL | /// https://github.com/rust-lang/rust-clippy/pull/12836 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `` diff --git a/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.fixed b/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.fixed index d4ae810d73855..a05954adf5a53 100644 --- a/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.fixed +++ b/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.fixed @@ -1,7 +1,8 @@ #![warn(clippy::doc_include_without_cfg)] // Should not lint. #![doc(html_playground_url = "https://playground.example.com/")] -#![cfg_attr(doc, doc = include_str!("../approx_const.rs"))] //~ doc_include_without_cfg +#![cfg_attr(doc, doc = include_str!("../approx_const.rs"))] +//~^ doc_include_without_cfg // Should not lint. #![cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] #![cfg_attr(doc, doc = include_str!("../approx_const.rs"))] @@ -28,7 +29,8 @@ tst! { /// This is a test with no included file } -#[cfg_attr(doc, doc = include_str!("../approx_const.rs"))] //~ doc_include_without_cfg +#[cfg_attr(doc, doc = include_str!("../approx_const.rs"))] +//~^ doc_include_without_cfg // Should not lint. #[doc = man_link!("bla", "blob")] #[cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] diff --git a/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.rs b/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.rs index c82f6bf20356a..26aa7a3a706a0 100644 --- a/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.rs +++ b/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.rs @@ -1,7 +1,8 @@ #![warn(clippy::doc_include_without_cfg)] // Should not lint. #![doc(html_playground_url = "https://playground.example.com/")] -#![doc = include_str!("../approx_const.rs")] //~ doc_include_without_cfg +#![doc = include_str!("../approx_const.rs")] +//~^ doc_include_without_cfg // Should not lint. #![cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] #![cfg_attr(doc, doc = include_str!("../approx_const.rs"))] @@ -28,7 +29,8 @@ tst! { /// This is a test with no included file } -#[doc = include_str!("../approx_const.rs")] //~ doc_include_without_cfg +#[doc = include_str!("../approx_const.rs")] +//~^ doc_include_without_cfg // Should not lint. #[doc = man_link!("bla", "blob")] #[cfg_attr(feature = "whatever", doc = include_str!("../approx_const.rs"))] diff --git a/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.stderr b/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.stderr index 17ea53c7c318a..24991df581e81 100644 --- a/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.stderr +++ b/src/tools/clippy/tests/ui/doc/doc_include_without_cfg.stderr @@ -8,7 +8,7 @@ LL | #![doc = include_str!("../approx_const.rs")] = help: to override `-D warnings` add `#[allow(clippy::doc_include_without_cfg)]` error: included a file in documentation unconditionally - --> tests/ui/doc/doc_include_without_cfg.rs:31:1 + --> tests/ui/doc/doc_include_without_cfg.rs:32:1 | LL | #[doc = include_str!("../approx_const.rs")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `cfg_attr(doc, doc = "...")`: `#[cfg_attr(doc, doc = include_str!("../approx_const.rs"))]` diff --git a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed index fcfcfcc40736a..065f4486e390a 100644 --- a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed +++ b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.fixed @@ -69,3 +69,11 @@ pub struct NotEmpty; /// - [link]\: notdef /// inner text pub struct NotEmptyTight; + +/// ## Heading +/// +/// - [x][] - Done +//~^ ERROR: link reference defined in list item +/// - [ ][] - Not Done +//~^ ERROR: link reference defined in list item +pub struct GithubCheckboxes; diff --git a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs index 53368de4616d8..c7eab50c8b386 100644 --- a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs +++ b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.rs @@ -69,3 +69,11 @@ pub struct NotEmpty; /// - [link]\: notdef /// inner text pub struct NotEmptyTight; + +/// ## Heading +/// +/// - [x] - Done +//~^ ERROR: link reference defined in list item +/// - [ ] - Not Done +//~^ ERROR: link reference defined in list item +pub struct GithubCheckboxes; diff --git a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr index 27314c7e968dd..5a815dabf4d8f 100644 --- a/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr +++ b/src/tools/clippy/tests/ui/doc/doc_nested_refdef_list_item.stderr @@ -144,5 +144,29 @@ help: for an intra-doc link, add `[]` between the label and the colon LL | /// - [link][]: def "title" | ++ -error: aborting due to 12 previous errors +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:75:7 + | +LL | /// - [x] - Done + | ^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [x][] - Done + | ++ + +error: link reference defined in list item + --> tests/ui/doc/doc_nested_refdef_list_item.rs:77:7 + | +LL | /// - [ ] - Not Done + | ^^^ + | + = help: link definitions are not shown in rendered documentation +help: for an intra-doc link, add `[]` between the label and the colon + | +LL | /// - [ ][] - Not Done + | ++ + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs b/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs index a18b4c3ac539b..dbb01bd5155be 100644 --- a/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs +++ b/src/tools/clippy/tests/ui/doc/footnote_issue_13183.rs @@ -1,3 +1,4 @@ +//@ check-pass // This is a regression test for . // It should not warn on missing backticks on footnote references. diff --git a/src/tools/clippy/tests/ui/doc/issue_12795.fixed b/src/tools/clippy/tests/ui/doc/issue_12795.fixed index ade23bf975c2e..4172438a82a6e 100644 --- a/src/tools/clippy/tests/ui/doc/issue_12795.fixed +++ b/src/tools/clippy/tests/ui/doc/issue_12795.fixed @@ -1,9 +1,9 @@ #![warn(clippy::doc_markdown)] //! A comment with `a_b(x)` and `a_c` in it and (`a_b((c))` ) too and (maybe `a_b((c))`) -//~^ ERROR: item in documentation is missing backticks -//~| ERROR: item in documentation is missing backticks -//~| ERROR: item in documentation is missing backticks -//~| ERROR: item in documentation is missing backticks +//~^ doc_markdown +//~| doc_markdown +//~| doc_markdown +//~| doc_markdown pub fn main() {} diff --git a/src/tools/clippy/tests/ui/doc/issue_12795.rs b/src/tools/clippy/tests/ui/doc/issue_12795.rs index 6d94a07e30367..dbc03cc708656 100644 --- a/src/tools/clippy/tests/ui/doc/issue_12795.rs +++ b/src/tools/clippy/tests/ui/doc/issue_12795.rs @@ -1,9 +1,9 @@ #![warn(clippy::doc_markdown)] //! A comment with a_b(x) and a_c in it and (a_b((c)) ) too and (maybe a_b((c))) -//~^ ERROR: item in documentation is missing backticks -//~| ERROR: item in documentation is missing backticks -//~| ERROR: item in documentation is missing backticks -//~| ERROR: item in documentation is missing backticks +//~^ doc_markdown +//~| doc_markdown +//~| doc_markdown +//~| doc_markdown pub fn main() {} diff --git a/src/tools/clippy/tests/ui/doc/issue_1832.rs b/src/tools/clippy/tests/ui/doc/issue_1832.rs index 10586f16d466a..9678badd11c82 100644 --- a/src/tools/clippy/tests/ui/doc/issue_1832.rs +++ b/src/tools/clippy/tests/ui/doc/issue_1832.rs @@ -1,3 +1,4 @@ +//@ check-pass /// Ok: /// /// Not ok: http://www.unicode.org diff --git a/src/tools/clippy/tests/ui/doc/issue_902.rs b/src/tools/clippy/tests/ui/doc/issue_902.rs index 4b0c835dd3f07..1be6db01dcb2a 100644 --- a/src/tools/clippy/tests/ui/doc/issue_902.rs +++ b/src/tools/clippy/tests/ui/doc/issue_902.rs @@ -1,3 +1,4 @@ +//@ check-pass /// See [NIST SP 800-56A, revision 2]. /// /// [NIST SP 800-56A, revision 2]: diff --git a/src/tools/clippy/tests/ui/doc/issue_9473.fixed b/src/tools/clippy/tests/ui/doc/issue_9473.fixed index 276ce7620ca76..2d910c43b2632 100644 --- a/src/tools/clippy/tests/ui/doc/issue_9473.fixed +++ b/src/tools/clippy/tests/ui/doc/issue_9473.fixed @@ -6,4 +6,5 @@ pub struct Foo(u32); // Should warn. /// Blah blah blah [FooBar]<[FooBar]>[`FooBar`]. +//~^ doc_markdown pub struct FooBar(u32); diff --git a/src/tools/clippy/tests/ui/doc/issue_9473.rs b/src/tools/clippy/tests/ui/doc/issue_9473.rs index 52527f7106d16..e5798685382ac 100644 --- a/src/tools/clippy/tests/ui/doc/issue_9473.rs +++ b/src/tools/clippy/tests/ui/doc/issue_9473.rs @@ -6,4 +6,5 @@ pub struct Foo(u32); // Should warn. /// Blah blah blah [FooBar]<[FooBar]>[FooBar]. +//~^ doc_markdown pub struct FooBar(u32); diff --git a/src/tools/clippy/tests/ui/doc/link_adjacent.fixed b/src/tools/clippy/tests/ui/doc/link_adjacent.fixed new file mode 100644 index 0000000000000..0ac297a6b1973 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/link_adjacent.fixed @@ -0,0 +1,52 @@ +#![warn(clippy::doc_link_code)] + +//! Test case for code links that are adjacent to code text. +//! +//! This is not an example: `first``second` +//! +//! Neither is this: [`first`](x) +//! +//! Neither is this: [`first`](x) `second` +//! +//! Neither is this: [first](x)`second` +//! +//! This is: [first](x)second +//~^ ERROR: adjacent +//! +//! So is this first[second](x) +//~^ ERROR: adjacent +//! +//! So is this [first](x)[second](x) +//~^ ERROR: adjacent +//! +//! So is this [first](x)[second](x)[third](x) +//~^ ERROR: adjacent +//! +//! So is this [first](x)second[third](x) +//~^ ERROR: adjacent + +/// Test case for code links that are adjacent to code text. +/// +/// This is not an example: `first``second` arst +/// +/// Neither is this: [`first`](x) arst +/// +/// Neither is this: [`first`](x) `second` arst +/// +/// Neither is this: [first](x)`second` arst +/// +/// This is: [first](x)second arst +//~^ ERROR: adjacent +/// +/// So is this first[second](x) arst +//~^ ERROR: adjacent +/// +/// So is this [first](x)[second](x) arst +//~^ ERROR: adjacent +/// +/// So is this [first](x)[second](x)[third](x) arst +//~^ ERROR: adjacent +/// +/// So is this [first](x)second[third](x) arst +//~^ ERROR: adjacent +pub struct WithTrailing; diff --git a/src/tools/clippy/tests/ui/doc/link_adjacent.rs b/src/tools/clippy/tests/ui/doc/link_adjacent.rs new file mode 100644 index 0000000000000..af6755eeff611 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/link_adjacent.rs @@ -0,0 +1,52 @@ +#![warn(clippy::doc_link_code)] + +//! Test case for code links that are adjacent to code text. +//! +//! This is not an example: `first``second` +//! +//! Neither is this: [`first`](x) +//! +//! Neither is this: [`first`](x) `second` +//! +//! Neither is this: [first](x)`second` +//! +//! This is: [`first`](x)`second` +//~^ ERROR: adjacent +//! +//! So is this `first`[`second`](x) +//~^ ERROR: adjacent +//! +//! So is this [`first`](x)[`second`](x) +//~^ ERROR: adjacent +//! +//! So is this [`first`](x)[`second`](x)[`third`](x) +//~^ ERROR: adjacent +//! +//! So is this [`first`](x)`second`[`third`](x) +//~^ ERROR: adjacent + +/// Test case for code links that are adjacent to code text. +/// +/// This is not an example: `first``second` arst +/// +/// Neither is this: [`first`](x) arst +/// +/// Neither is this: [`first`](x) `second` arst +/// +/// Neither is this: [first](x)`second` arst +/// +/// This is: [`first`](x)`second` arst +//~^ ERROR: adjacent +/// +/// So is this `first`[`second`](x) arst +//~^ ERROR: adjacent +/// +/// So is this [`first`](x)[`second`](x) arst +//~^ ERROR: adjacent +/// +/// So is this [`first`](x)[`second`](x)[`third`](x) arst +//~^ ERROR: adjacent +/// +/// So is this [`first`](x)`second`[`third`](x) arst +//~^ ERROR: adjacent +pub struct WithTrailing; diff --git a/src/tools/clippy/tests/ui/doc/link_adjacent.stderr b/src/tools/clippy/tests/ui/doc/link_adjacent.stderr new file mode 100644 index 0000000000000..27e8a73c70833 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc/link_adjacent.stderr @@ -0,0 +1,134 @@ +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:13:14 + | +LL | //! This is: [`first`](x)`second` + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap + = note: `-D clippy::doc-link-code` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_link_code)]` +help: wrap the entire group in `` tags + | +LL - //! This is: [`first`](x)`second` +LL + //! This is: [first](x)second + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:16:16 + | +LL | //! So is this `first`[`second`](x) + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - //! So is this `first`[`second`](x) +LL + //! So is this first[second](x) + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:19:16 + | +LL | //! So is this [`first`](x)[`second`](x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - //! So is this [`first`](x)[`second`](x) +LL + //! So is this [first](x)[second](x) + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:22:16 + | +LL | //! So is this [`first`](x)[`second`](x)[`third`](x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - //! So is this [`first`](x)[`second`](x)[`third`](x) +LL + //! So is this [first](x)[second](x)[third](x) + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:25:16 + | +LL | //! So is this [`first`](x)`second`[`third`](x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - //! So is this [`first`](x)`second`[`third`](x) +LL + //! So is this [first](x)second[third](x) + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:38:14 + | +LL | /// This is: [`first`](x)`second` arst + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - /// This is: [`first`](x)`second` arst +LL + /// This is: [first](x)second arst + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:41:16 + | +LL | /// So is this `first`[`second`](x) arst + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - /// So is this `first`[`second`](x) arst +LL + /// So is this first[second](x) arst + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:44:16 + | +LL | /// So is this [`first`](x)[`second`](x) arst + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - /// So is this [`first`](x)[`second`](x) arst +LL + /// So is this [first](x)[second](x) arst + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:47:16 + | +LL | /// So is this [`first`](x)[`second`](x)[`third`](x) arst + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - /// So is this [`first`](x)[`second`](x)[`third`](x) arst +LL + /// So is this [first](x)[second](x)[third](x) arst + | + +error: code link adjacent to code text + --> tests/ui/doc/link_adjacent.rs:50:16 + | +LL | /// So is this [`first`](x)`second`[`third`](x) arst + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: separate code snippets will be shown with a gap +help: wrap the entire group in `` tags + | +LL - /// So is this [`first`](x)`second`[`third`](x) arst +LL + /// So is this [first](x)second[third](x) arst + | + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs b/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs index f1a2c0575ee5e..633a435ca5ed7 100644 --- a/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs +++ b/src/tools/clippy/tests/ui/doc/needless_doctest_main.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::needless_doctest_main)] //! issue 10491: //! ```rust,no_test diff --git a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs index a065654e319d0..76befb15db80a 100644 --- a/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs +++ b/src/tools/clippy/tests/ui/doc/unbalanced_ticks.rs @@ -5,20 +5,20 @@ #![warn(clippy::doc_markdown)] /// This is a doc comment with `unbalanced_tick marks and several words that -//~^ ERROR: backticks are unbalanced +//~^ doc_markdown /// should be `encompassed_by` tick marks because they `contain_underscores`. /// Because of the initial `unbalanced_tick` pair, the error message is /// very `confusing_and_misleading`. fn main() {} /// This paragraph has `unbalanced_tick marks and should stop_linting. -//~^ ERROR: backticks are unbalanced +//~^ doc_markdown /// /// This paragraph is fine and should_be linted normally. -//~^ ERROR: item in documentation is missing backticks +//~^ doc_markdown /// /// Double unbalanced backtick from ``here to here` should lint. -//~^ ERROR: backticks are unbalanced +//~^ doc_markdown /// /// Double balanced back ticks ``start end`` is fine. fn multiple_paragraphs() {} @@ -32,15 +32,15 @@ fn in_code_block() {} /// # `Fine` /// /// ## not_fine -//~^ ERROR: item in documentation is missing backticks +//~^ doc_markdown /// /// ### `unbalanced -//~^ ERROR: backticks are unbalanced +//~^ doc_markdown /// /// - This `item has unbalanced tick marks -//~^ ERROR: backticks are unbalanced +//~^ doc_markdown /// - This item needs backticks_here -//~^ ERROR: item in documentation is missing backticks +//~^ doc_markdown fn other_markdown() {} #[rustfmt::skip] @@ -51,7 +51,7 @@ fn other_markdown() {} fn issue_7421() {} /// ` -//~^ ERROR: backticks are unbalanced +//~^ doc_markdown fn escape_0() {} /// Escaped \` backticks don't count. @@ -61,7 +61,7 @@ fn escape_1() {} fn escape_2() {} /// Escaped \` ` backticks don't count, but unescaped backticks do. -//~^ ERROR: backticks are unbalanced +//~^ doc_markdown fn escape_3() {} /// Backslashes ` \` within code blocks don't count. @@ -80,5 +80,6 @@ impl Foo for Bar { /// ---------------------------| -------------------- | --------------------- | ... | ----- /// ``: | Some(Month::January) | Some(Month::February) | ... | /// Some(Month::December) + //~^^^^ doc_markdown fn bar() {} } diff --git a/src/tools/clippy/tests/ui/doc_errors.rs b/src/tools/clippy/tests/ui/doc_errors.rs index 9b3783aaf09de..f67e3216c01e8 100644 --- a/src/tools/clippy/tests/ui/doc_errors.rs +++ b/src/tools/clippy/tests/ui/doc_errors.rs @@ -5,25 +5,28 @@ use std::io; pub fn pub_fn_missing_errors_header() -> Result<(), ()> { - //~^ ERROR: docs for function returning `Result` missing `# Errors` section - //~| NOTE: `-D clippy::missing-errors-doc` implied by `-D warnings` + //~^ missing_errors_doc + unimplemented!(); } pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { - //~^ ERROR: docs for function returning `Result` missing `# Errors` section + //~^ missing_errors_doc + unimplemented!(); } /// This is not sufficiently documented. pub fn pub_fn_returning_io_result() -> io::Result<()> { - //~^ ERROR: docs for function returning `Result` missing `# Errors` section + //~^ missing_errors_doc + unimplemented!(); } /// This is not sufficiently documented. pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { - //~^ ERROR: docs for function returning `Result` missing `# Errors` section + //~^ missing_errors_doc + unimplemented!(); } @@ -54,13 +57,15 @@ pub struct Struct1; impl Struct1 { /// This is not sufficiently documented. pub fn pub_method_missing_errors_header() -> Result<(), ()> { - //~^ ERROR: docs for function returning `Result` missing `# Errors` section + //~^ missing_errors_doc + unimplemented!(); } /// This is not sufficiently documented. pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { - //~^ ERROR: docs for function returning `Result` missing `# Errors` section + //~^ missing_errors_doc + unimplemented!(); } @@ -111,7 +116,7 @@ impl Struct1 { pub trait Trait1 { /// This is not sufficiently documented. fn trait_method_missing_errors_header() -> Result<(), ()>; - //~^ ERROR: docs for function returning `Result` missing `# Errors` section + //~^ missing_errors_doc /// # Errors /// A description of the errors goes here. diff --git a/src/tools/clippy/tests/ui/doc_errors.stderr b/src/tools/clippy/tests/ui/doc_errors.stderr index c5b9479adace4..aeb2516e51231 100644 --- a/src/tools/clippy/tests/ui/doc_errors.stderr +++ b/src/tools/clippy/tests/ui/doc_errors.stderr @@ -14,31 +14,31 @@ LL | pub async fn async_pub_fn_missing_errors_header() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function returning `Result` missing `# Errors` section - --> tests/ui/doc_errors.rs:19:1 + --> tests/ui/doc_errors.rs:20:1 | LL | pub fn pub_fn_returning_io_result() -> io::Result<()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function returning `Result` missing `# Errors` section - --> tests/ui/doc_errors.rs:25:1 + --> tests/ui/doc_errors.rs:27:1 | LL | pub async fn async_pub_fn_returning_io_result() -> io::Result<()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function returning `Result` missing `# Errors` section - --> tests/ui/doc_errors.rs:56:5 + --> tests/ui/doc_errors.rs:59:5 | LL | pub fn pub_method_missing_errors_header() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function returning `Result` missing `# Errors` section - --> tests/ui/doc_errors.rs:62:5 + --> tests/ui/doc_errors.rs:66:5 | LL | pub async fn async_pub_method_missing_errors_header() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function returning `Result` missing `# Errors` section - --> tests/ui/doc_errors.rs:113:5 + --> tests/ui/doc_errors.rs:118:5 | LL | fn trait_method_missing_errors_header() -> Result<(), ()>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs index 48e1b1819c6ff..0c0e273da6db4 100644 --- a/src/tools/clippy/tests/ui/doc_link_with_quotes.rs +++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.rs @@ -5,14 +5,13 @@ fn main() { } /// Calls ['bar'] uselessly -//~^ ERROR: possible intra-doc link using quotes instead of backticks -//~| NOTE: `-D clippy::doc-link-with-quotes` implied by `-D warnings` +//~^ doc_link_with_quotes pub fn foo() { bar() } /// Calls ["bar"] uselessly -//~^ ERROR: possible intra-doc link using quotes instead of backticks +//~^ doc_link_with_quotes pub fn foo2() { bar() } diff --git a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr index e4be59c65719c..47c60390310c1 100644 --- a/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr +++ b/src/tools/clippy/tests/ui/doc_link_with_quotes.stderr @@ -8,7 +8,7 @@ LL | /// Calls ['bar'] uselessly = help: to override `-D warnings` add `#[allow(clippy::doc_link_with_quotes)]` error: possible intra-doc link using quotes instead of backticks - --> tests/ui/doc_link_with_quotes.rs:14:12 + --> tests/ui/doc_link_with_quotes.rs:13:12 | LL | /// Calls ["bar"] uselessly | ^^^^^ diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs index f7f41c915e3f0..1bdf01e4e22e9 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.rs +++ b/src/tools/clippy/tests/ui/doc_unsafe.rs @@ -7,6 +7,7 @@ use proc_macros::external; /// This is not sufficiently documented pub unsafe fn destroy_the_planet() { + //~^ missing_safety_doc unimplemented!(); } @@ -30,6 +31,7 @@ mod private_mod { } pub unsafe fn republished() { + //~^ missing_safety_doc unimplemented!(); } } @@ -38,12 +40,14 @@ pub use private_mod::republished; pub trait SafeTraitUnsafeMethods { unsafe fn woefully_underdocumented(self); + //~^ missing_safety_doc /// # Safety unsafe fn at_least_somewhat_documented(self); } pub unsafe trait UnsafeTrait { + //~^ missing_safety_doc fn method(); } @@ -74,6 +78,7 @@ unsafe impl DocumentedUnsafeTrait for Struct { impl Struct { pub unsafe fn more_undocumented_unsafe() -> Self { + //~^ missing_safety_doc unimplemented!(); } @@ -90,6 +95,7 @@ impl Struct { macro_rules! very_unsafe { () => { pub unsafe fn whee() { + //~^ missing_safety_doc unimplemented!() } diff --git a/src/tools/clippy/tests/ui/doc_unsafe.stderr b/src/tools/clippy/tests/ui/doc_unsafe.stderr index 929afbceb879d..6e128133d498e 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.stderr +++ b/src/tools/clippy/tests/ui/doc_unsafe.stderr @@ -8,31 +8,31 @@ LL | pub unsafe fn destroy_the_planet() { = help: to override `-D warnings` add `#[allow(clippy::missing_safety_doc)]` error: unsafe function's docs are missing a `# Safety` section - --> tests/ui/doc_unsafe.rs:32:5 + --> tests/ui/doc_unsafe.rs:33:5 | LL | pub unsafe fn republished() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe function's docs are missing a `# Safety` section - --> tests/ui/doc_unsafe.rs:40:5 + --> tests/ui/doc_unsafe.rs:42:5 | LL | unsafe fn woefully_underdocumented(self); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for unsafe trait missing `# Safety` section - --> tests/ui/doc_unsafe.rs:46:1 + --> tests/ui/doc_unsafe.rs:49:1 | LL | pub unsafe trait UnsafeTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe function's docs are missing a `# Safety` section - --> tests/ui/doc_unsafe.rs:76:5 + --> tests/ui/doc_unsafe.rs:80:5 | LL | pub unsafe fn more_undocumented_unsafe() -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: unsafe function's docs are missing a `# Safety` section - --> tests/ui/doc_unsafe.rs:92:9 + --> tests/ui/doc_unsafe.rs:97:9 | LL | pub unsafe fn whee() { | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/double_comparison.fixed b/src/tools/clippy/tests/ui/double_comparison.fixed index 788f3224b4186..685e3319bf9af 100644 --- a/src/tools/clippy/tests/ui/double_comparison.fixed +++ b/src/tools/clippy/tests/ui/double_comparison.fixed @@ -4,27 +4,35 @@ fn main() { let x = 1; let y = 2; if x <= y { + //~^ double_comparisons // do something } if x <= y { + //~^ double_comparisons // do something } if x >= y { + //~^ double_comparisons // do something } if x >= y { + //~^ double_comparisons // do something } if x != y { + //~^ double_comparisons // do something } if x != y { + //~^ double_comparisons // do something } if x == y { + //~^ double_comparisons // do something } if x == y { + //~^ double_comparisons // do something } } diff --git a/src/tools/clippy/tests/ui/double_comparison.rs b/src/tools/clippy/tests/ui/double_comparison.rs index 245a83d5709d4..3670a050e88d1 100644 --- a/src/tools/clippy/tests/ui/double_comparison.rs +++ b/src/tools/clippy/tests/ui/double_comparison.rs @@ -4,27 +4,35 @@ fn main() { let x = 1; let y = 2; if x == y || x < y { + //~^ double_comparisons // do something } if x < y || x == y { + //~^ double_comparisons // do something } if x == y || x > y { + //~^ double_comparisons // do something } if x > y || x == y { + //~^ double_comparisons // do something } if x < y || x > y { + //~^ double_comparisons // do something } if x > y || x < y { + //~^ double_comparisons // do something } if x <= y && x >= y { + //~^ double_comparisons // do something } if x >= y && x <= y { + //~^ double_comparisons // do something } } diff --git a/src/tools/clippy/tests/ui/double_comparison.stderr b/src/tools/clippy/tests/ui/double_comparison.stderr index 01ba7a8ee1083..984614c203eb6 100644 --- a/src/tools/clippy/tests/ui/double_comparison.stderr +++ b/src/tools/clippy/tests/ui/double_comparison.stderr @@ -8,43 +8,43 @@ LL | if x == y || x < y { = help: to override `-D warnings` add `#[allow(clippy::double_comparisons)]` error: this binary expression can be simplified - --> tests/ui/double_comparison.rs:9:8 + --> tests/ui/double_comparison.rs:10:8 | LL | if x < y || x == y { | ^^^^^^^^^^^^^^^ help: try: `x <= y` error: this binary expression can be simplified - --> tests/ui/double_comparison.rs:12:8 + --> tests/ui/double_comparison.rs:14:8 | LL | if x == y || x > y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: this binary expression can be simplified - --> tests/ui/double_comparison.rs:15:8 + --> tests/ui/double_comparison.rs:18:8 | LL | if x > y || x == y { | ^^^^^^^^^^^^^^^ help: try: `x >= y` error: this binary expression can be simplified - --> tests/ui/double_comparison.rs:18:8 + --> tests/ui/double_comparison.rs:22:8 | LL | if x < y || x > y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: this binary expression can be simplified - --> tests/ui/double_comparison.rs:21:8 + --> tests/ui/double_comparison.rs:26:8 | LL | if x > y || x < y { | ^^^^^^^^^^^^^^ help: try: `x != y` error: this binary expression can be simplified - --> tests/ui/double_comparison.rs:24:8 + --> tests/ui/double_comparison.rs:30:8 | LL | if x <= y && x >= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` error: this binary expression can be simplified - --> tests/ui/double_comparison.rs:27:8 + --> tests/ui/double_comparison.rs:34:8 | LL | if x >= y && x <= y { | ^^^^^^^^^^^^^^^^ help: try: `x == y` diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed index 06c48e337537c..17d0d71a88545 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed @@ -2,7 +2,7 @@ // Typical case pub fn last_arg(s: &str) -> Option<&str> { - s.split(' ').next_back() + s.split(' ').next_back() //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` } fn main() { @@ -19,7 +19,7 @@ fn main() { Some(()) } } - let _ = DeIterator.next_back(); + let _ = DeIterator.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` // Should not apply to other methods of Iterator let _ = DeIterator.count(); @@ -51,3 +51,42 @@ fn main() { } let _ = CustomLast.last(); } + +fn issue_14139() { + let mut index = [true, true, false, false, false, true].iter(); + let mut subindex = index.by_ref().take(3); + let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let mut subindex = index.by_ref().take(3); + let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let mut subindex = index.by_ref().take(3); + let subindex = &mut subindex; + let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let mut subindex = index.by_ref().take(3); + let subindex = &mut subindex; + let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let (mut subindex, _) = (index.by_ref().take(3), 42); + let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` +} + +fn drop_order() { + struct S(&'static str); + impl std::ops::Drop for S { + fn drop(&mut self) { + println!("Dropping {}", self.0); + } + } + + let v = vec![S("one"), S("two"), S("three")]; + let mut v = v.into_iter(); + println!("Last element is {}", v.next_back().unwrap().0); + //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + println!("Done"); +} diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs index 9c13b496d117e..41bc669b1719f 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs @@ -2,7 +2,7 @@ // Typical case pub fn last_arg(s: &str) -> Option<&str> { - s.split(' ').last() + s.split(' ').last() //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` } fn main() { @@ -19,7 +19,7 @@ fn main() { Some(()) } } - let _ = DeIterator.last(); + let _ = DeIterator.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` // Should not apply to other methods of Iterator let _ = DeIterator.count(); @@ -51,3 +51,42 @@ fn main() { } let _ = CustomLast.last(); } + +fn issue_14139() { + let mut index = [true, true, false, false, false, true].iter(); + let subindex = index.by_ref().take(3); + let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let mut subindex = index.by_ref().take(3); + let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let mut subindex = index.by_ref().take(3); + let subindex = &mut subindex; + let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let mut subindex = index.by_ref().take(3); + let subindex = &mut subindex; + let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let mut index = [true, true, false, false, false, true].iter(); + let (subindex, _) = (index.by_ref().take(3), 42); + let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` +} + +fn drop_order() { + struct S(&'static str); + impl std::ops::Drop for S { + fn drop(&mut self) { + println!("Dropping {}", self.0); + } + } + + let v = vec![S("one"), S("two"), S("three")]; + let v = v.into_iter(); + println!("Last element is {}", v.last().unwrap().0); + //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + println!("Done"); +} diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr index b795c18a736ea..1702a24d7a055 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr @@ -1,17 +1,82 @@ error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:5:18 + --> tests/ui/double_ended_iterator_last.rs:5:5 | LL | s.split(' ').last() - | ^^^^^^ help: try: `next_back()` + | ^^^^^^^^^^^^^------ + | | + | help: try: `next_back()` | = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]` error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:22:24 + --> tests/ui/double_ended_iterator_last.rs:22:13 | LL | let _ = DeIterator.last(); - | ^^^^^^ help: try: `next_back()` + | ^^^^^^^^^^^------ + | | + | help: try: `next_back()` -error: aborting due to 2 previous errors +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:58:13 + | +LL | let _ = subindex.last(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ let mut subindex = index.by_ref().take(3); +LL ~ let _ = subindex.next_back(); + | + +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:62:13 + | +LL | let _ = subindex.last(); + | ^^^^^^^^^------ + | | + | help: try: `next_back()` + +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:67:13 + | +LL | let _ = subindex.last(); + | ^^^^^^^^^------ + | | + | help: try: `next_back()` + +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:72:13 + | +LL | let _ = subindex.last(); + | ^^^^^^^^^------ + | | + | help: try: `next_back()` + +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:76:13 + | +LL | let _ = subindex.last(); + | ^^^^^^^^^^^^^^^ + | +help: try + | +LL ~ let (mut subindex, _) = (index.by_ref().take(3), 42); +LL ~ let _ = subindex.next_back(); + | + +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:89:36 + | +LL | println!("Last element is {}", v.last().unwrap().0); + | ^^^^^^^^ + | + = note: this change will alter drop order which may be undesirable +help: try + | +LL ~ let mut v = v.into_iter(); +LL ~ println!("Last element is {}", v.next_back().unwrap().0); + | + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs new file mode 100644 index 0000000000000..3f125c7f20c1e --- /dev/null +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs @@ -0,0 +1,23 @@ +//@no-rustfix +#![warn(clippy::double_ended_iterator_last)] + +fn main() { + let mut index = [true, true, false, false, false, true].iter(); + let subindex = (index.by_ref().take(3), 42); + let _ = subindex.0.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator` +} + +fn drop_order() { + struct S(&'static str); + impl std::ops::Drop for S { + fn drop(&mut self) { + println!("Dropping {}", self.0); + } + } + + let v = vec![S("one"), S("two"), S("three")]; + let v = (v.into_iter(), 42); + println!("Last element is {}", v.0.last().unwrap().0); + //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + println!("Done"); +} diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr new file mode 100644 index 0000000000000..f4be757d00d29 --- /dev/null +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr @@ -0,0 +1,33 @@ +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last_unfixable.rs:7:13 + | +LL | let _ = subindex.0.last(); + | ^^^^^^^^^^^------ + | | + | help: try: `next_back()` + | +note: this must be made mutable to use `.next_back()` + --> tests/ui/double_ended_iterator_last_unfixable.rs:7:13 + | +LL | let _ = subindex.0.last(); + | ^^^^^^^^^^ + = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]` + +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last_unfixable.rs:20:36 + | +LL | println!("Last element is {}", v.0.last().unwrap().0); + | ^^^^------ + | | + | help: try: `next_back()` + | + = note: this change will alter drop order which may be undesirable +note: this must be made mutable to use `.next_back()` + --> tests/ui/double_ended_iterator_last_unfixable.rs:20:36 + | +LL | println!("Last element is {}", v.0.last().unwrap().0); + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/double_must_use.rs b/src/tools/clippy/tests/ui/double_must_use.rs index 4460aeb075bf6..3d4aaa9baa49c 100644 --- a/src/tools/clippy/tests/ui/double_must_use.rs +++ b/src/tools/clippy/tests/ui/double_must_use.rs @@ -3,19 +3,22 @@ #[must_use] pub fn must_use_result() -> Result<(), ()> { - //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already + //~^ double_must_use + unimplemented!(); } #[must_use] pub fn must_use_tuple() -> (Result<(), ()>, u8) { - //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already + //~^ double_must_use + unimplemented!(); } #[must_use] pub fn must_use_array() -> [Result<(), ()>; 1] { - //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already + //~^ double_must_use + unimplemented!(); } @@ -32,7 +35,8 @@ async fn async_must_use() -> usize { #[must_use] async fn async_must_use_result() -> Result<(), ()> { - //~^ ERROR: this function has a `#[must_use]` attribute with no message, but returns a type already + //~^ double_must_use + Ok(()) } diff --git a/src/tools/clippy/tests/ui/double_must_use.stderr b/src/tools/clippy/tests/ui/double_must_use.stderr index b26d1e48a8b86..555dd8902cac4 100644 --- a/src/tools/clippy/tests/ui/double_must_use.stderr +++ b/src/tools/clippy/tests/ui/double_must_use.stderr @@ -9,7 +9,7 @@ LL | pub fn must_use_result() -> Result<(), ()> { = help: to override `-D warnings` add `#[allow(clippy::double_must_use)]` error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` - --> tests/ui/double_must_use.rs:11:1 + --> tests/ui/double_must_use.rs:12:1 | LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pub fn must_use_tuple() -> (Result<(), ()>, u8) { = help: either add some descriptive message or remove the attribute error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` - --> tests/ui/double_must_use.rs:17:1 + --> tests/ui/double_must_use.rs:19:1 | LL | pub fn must_use_array() -> [Result<(), ()>; 1] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | pub fn must_use_array() -> [Result<(), ()>; 1] { = help: either add some descriptive message or remove the attribute error: this function has a `#[must_use]` attribute with no message, but returns a type already marked as `#[must_use]` - --> tests/ui/double_must_use.rs:34:1 + --> tests/ui/double_must_use.rs:37:1 | LL | async fn async_must_use_result() -> Result<(), ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/double_parens.rs b/src/tools/clippy/tests/ui/double_parens.rs index ab1459eed48bc..7c976015b4e79 100644 --- a/src/tools/clippy/tests/ui/double_parens.rs +++ b/src/tools/clippy/tests/ui/double_parens.rs @@ -13,28 +13,33 @@ impl DummyStruct { fn simple_double_parens() -> i32 { ((0)) - //~^ ERROR: consider removing unnecessary double parentheses - //~| NOTE: `-D clippy::double-parens` implied by `-D warnings` + //~^ double_parens + + } fn fn_double_parens() { dummy_fn((0)); - //~^ ERROR: consider removing unnecessary double parentheses + //~^ double_parens + } fn method_double_parens(x: DummyStruct) { x.dummy_method((0)); - //~^ ERROR: consider removing unnecessary double parentheses + //~^ double_parens + } fn tuple_double_parens() -> (i32, i32) { ((1, 2)) - //~^ ERROR: consider removing unnecessary double parentheses + //~^ double_parens + } fn unit_double_parens() { (()) - //~^ ERROR: consider removing unnecessary double parentheses + //~^ double_parens + } fn fn_tuple_ok() { @@ -57,7 +62,8 @@ fn method_unit_ok(x: DummyStruct) { fn inside_macro() { assert_eq!((1, 2), (1, 2), "Error"); assert_eq!(((1, 2)), (1, 2), "Error"); - //~^ ERROR: consider removing unnecessary double parentheses + //~^ double_parens + } fn main() {} diff --git a/src/tools/clippy/tests/ui/double_parens.stderr b/src/tools/clippy/tests/ui/double_parens.stderr index aba301e9f072f..e119f54949b1f 100644 --- a/src/tools/clippy/tests/ui/double_parens.stderr +++ b/src/tools/clippy/tests/ui/double_parens.stderr @@ -8,31 +8,31 @@ LL | ((0)) = help: to override `-D warnings` add `#[allow(clippy::double_parens)]` error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:21:14 + --> tests/ui/double_parens.rs:22:14 | LL | dummy_fn((0)); | ^^^ error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:26:20 + --> tests/ui/double_parens.rs:28:20 | LL | x.dummy_method((0)); | ^^^ error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:31:5 + --> tests/ui/double_parens.rs:34:5 | LL | ((1, 2)) | ^^^^^^^^ error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:36:5 + --> tests/ui/double_parens.rs:40:5 | LL | (()) | ^^^^ error: consider removing unnecessary double parentheses - --> tests/ui/double_parens.rs:59:16 + --> tests/ui/double_parens.rs:64:16 | LL | assert_eq!(((1, 2)), (1, 2), "Error"); | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/drain_collect.fixed b/src/tools/clippy/tests/ui/drain_collect.fixed index 6f597243fe6fc..7ae971d975b1a 100644 --- a/src/tools/clippy/tests/ui/drain_collect.fixed +++ b/src/tools/clippy/tests/ui/drain_collect.fixed @@ -5,6 +5,7 @@ use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; fn binaryheap(b: &mut BinaryHeap) -> BinaryHeap { std::mem::take(b) + //~^ drain_collect } fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { @@ -13,6 +14,7 @@ fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { fn hashmap(b: &mut HashMap) -> HashMap { std::mem::take(b) + //~^ drain_collect } fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { @@ -21,6 +23,7 @@ fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { fn hashset(b: &mut HashSet) -> HashSet { std::mem::take(b) + //~^ drain_collect } fn hashset_dont_lint(b: &mut HashSet) -> Vec { @@ -29,6 +32,7 @@ fn hashset_dont_lint(b: &mut HashSet) -> Vec { fn vecdeque(b: &mut VecDeque) -> VecDeque { std::mem::take(b) + //~^ drain_collect } fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { @@ -37,23 +41,28 @@ fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { fn vec(b: &mut Vec) -> Vec { std::mem::take(b) + //~^ drain_collect } fn vec2(b: &mut Vec) -> Vec { std::mem::take(b) + //~^ drain_collect } fn vec3(b: &mut Vec) -> Vec { std::mem::take(b) + //~^ drain_collect } fn vec4(b: &mut Vec) -> Vec { std::mem::take(b) + //~^ drain_collect } fn vec_no_reborrow() -> Vec { let mut b = vec![1, 2, 3]; std::mem::take(&mut b) + //~^ drain_collect } fn vec_dont_lint(b: &mut Vec) -> HashSet { @@ -62,6 +71,7 @@ fn vec_dont_lint(b: &mut Vec) -> HashSet { fn string(b: &mut String) -> String { std::mem::take(b) + //~^ drain_collect } fn string_dont_lint(b: &mut String) -> HashSet { diff --git a/src/tools/clippy/tests/ui/drain_collect.rs b/src/tools/clippy/tests/ui/drain_collect.rs index 353aac4da9a4f..e99d84fa8b66e 100644 --- a/src/tools/clippy/tests/ui/drain_collect.rs +++ b/src/tools/clippy/tests/ui/drain_collect.rs @@ -5,6 +5,7 @@ use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; fn binaryheap(b: &mut BinaryHeap) -> BinaryHeap { b.drain().collect() + //~^ drain_collect } fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { @@ -13,6 +14,7 @@ fn binaryheap_dont_lint(b: &mut BinaryHeap) -> HashSet { fn hashmap(b: &mut HashMap) -> HashMap { b.drain().collect() + //~^ drain_collect } fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { @@ -21,6 +23,7 @@ fn hashmap_dont_lint(b: &mut HashMap) -> Vec<(i32, i32)> { fn hashset(b: &mut HashSet) -> HashSet { b.drain().collect() + //~^ drain_collect } fn hashset_dont_lint(b: &mut HashSet) -> Vec { @@ -29,6 +32,7 @@ fn hashset_dont_lint(b: &mut HashSet) -> Vec { fn vecdeque(b: &mut VecDeque) -> VecDeque { b.drain(..).collect() + //~^ drain_collect } fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { @@ -37,23 +41,28 @@ fn vecdeque_dont_lint(b: &mut VecDeque) -> HashSet { fn vec(b: &mut Vec) -> Vec { b.drain(..).collect() + //~^ drain_collect } fn vec2(b: &mut Vec) -> Vec { b.drain(0..).collect() + //~^ drain_collect } fn vec3(b: &mut Vec) -> Vec { b.drain(..b.len()).collect() + //~^ drain_collect } fn vec4(b: &mut Vec) -> Vec { b.drain(0..b.len()).collect() + //~^ drain_collect } fn vec_no_reborrow() -> Vec { let mut b = vec![1, 2, 3]; b.drain(..).collect() + //~^ drain_collect } fn vec_dont_lint(b: &mut Vec) -> HashSet { @@ -62,6 +71,7 @@ fn vec_dont_lint(b: &mut Vec) -> HashSet { fn string(b: &mut String) -> String { b.drain(..).collect() + //~^ drain_collect } fn string_dont_lint(b: &mut String) -> HashSet { diff --git a/src/tools/clippy/tests/ui/drain_collect.stderr b/src/tools/clippy/tests/ui/drain_collect.stderr index 1dfd0f1e3463e..cfb1e01b65cf6 100644 --- a/src/tools/clippy/tests/ui/drain_collect.stderr +++ b/src/tools/clippy/tests/ui/drain_collect.stderr @@ -11,55 +11,55 @@ LL | #![deny(clippy::drain_collect)] | ^^^^^^^^^^^^^^^^^^^^^ error: you seem to be trying to move all elements into a new `HashMap` - --> tests/ui/drain_collect.rs:15:5 + --> tests/ui/drain_collect.rs:16:5 | LL | b.drain().collect() | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `HashSet` - --> tests/ui/drain_collect.rs:23:5 + --> tests/ui/drain_collect.rs:25:5 | LL | b.drain().collect() | ^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> tests/ui/drain_collect.rs:31:5 + --> tests/ui/drain_collect.rs:34:5 | LL | b.drain(..).collect() | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> tests/ui/drain_collect.rs:39:5 + --> tests/ui/drain_collect.rs:43:5 | LL | b.drain(..).collect() | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> tests/ui/drain_collect.rs:43:5 + --> tests/ui/drain_collect.rs:48:5 | LL | b.drain(0..).collect() | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> tests/ui/drain_collect.rs:47:5 + --> tests/ui/drain_collect.rs:53:5 | LL | b.drain(..b.len()).collect() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> tests/ui/drain_collect.rs:51:5 + --> tests/ui/drain_collect.rs:58:5 | LL | b.drain(0..b.len()).collect() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` error: you seem to be trying to move all elements into a new `Vec` - --> tests/ui/drain_collect.rs:56:5 + --> tests/ui/drain_collect.rs:64:5 | LL | b.drain(..).collect() | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(&mut b)` error: you seem to be trying to move all elements into a new `String` - --> tests/ui/drain_collect.rs:64:5 + --> tests/ui/drain_collect.rs:73:5 | LL | b.drain(..).collect() | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `mem::take`: `std::mem::take(b)` diff --git a/src/tools/clippy/tests/ui/drain_collect_nostd.fixed b/src/tools/clippy/tests/ui/drain_collect_nostd.fixed index a4ab2956f2a62..4741922d1dc40 100644 --- a/src/tools/clippy/tests/ui/drain_collect_nostd.fixed +++ b/src/tools/clippy/tests/ui/drain_collect_nostd.fixed @@ -5,4 +5,5 @@ use alloc::vec::Vec; fn remove_all(v: &mut Vec) -> Vec { core::mem::take(v) + //~^ drain_collect } diff --git a/src/tools/clippy/tests/ui/drain_collect_nostd.rs b/src/tools/clippy/tests/ui/drain_collect_nostd.rs index a8be1ce6bbd3b..69dcb1c416586 100644 --- a/src/tools/clippy/tests/ui/drain_collect_nostd.rs +++ b/src/tools/clippy/tests/ui/drain_collect_nostd.rs @@ -5,4 +5,5 @@ use alloc::vec::Vec; fn remove_all(v: &mut Vec) -> Vec { v.drain(..).collect() + //~^ drain_collect } diff --git a/src/tools/clippy/tests/ui/drop_non_drop.rs b/src/tools/clippy/tests/ui/drop_non_drop.rs index 6dbcb7777d49e..0345e8670ab83 100644 --- a/src/tools/clippy/tests/ui/drop_non_drop.rs +++ b/src/tools/clippy/tests/ui/drop_non_drop.rs @@ -20,7 +20,8 @@ fn main() { struct Foo; // Lint drop(Foo); - //~^ ERROR: call to `std::mem::drop` with a value that does not implement `Drop`. Drop + //~^ drop_non_drop + // Don't lint drop(make_result(Foo)); // Don't lint @@ -36,7 +37,8 @@ fn main() { struct Baz(T); // Lint drop(Baz(Foo)); - //~^ ERROR: call to `std::mem::drop` with a value that does not implement `Drop`. Drop + //~^ drop_non_drop + // Don't lint drop(Baz(Bar)); } diff --git a/src/tools/clippy/tests/ui/drop_non_drop.stderr b/src/tools/clippy/tests/ui/drop_non_drop.stderr index fac89bf1f26a7..b431c62c92c57 100644 --- a/src/tools/clippy/tests/ui/drop_non_drop.stderr +++ b/src/tools/clippy/tests/ui/drop_non_drop.stderr @@ -13,13 +13,13 @@ LL | drop(Foo); = help: to override `-D warnings` add `#[allow(clippy::drop_non_drop)]` error: call to `std::mem::drop` with a value that does not implement `Drop`. Dropping such a type only extends its contained lifetimes - --> tests/ui/drop_non_drop.rs:38:5 + --> tests/ui/drop_non_drop.rs:39:5 | LL | drop(Baz(Foo)); | ^^^^^^^^^^^^^^ | note: argument has type `main::Baz` - --> tests/ui/drop_non_drop.rs:38:10 + --> tests/ui/drop_non_drop.rs:39:10 | LL | drop(Baz(Foo)); | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs index a725538436cb1..b71f5a20a8439 100644 --- a/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs +++ b/src/tools/clippy/tests/ui/duplicate_underscore_argument.rs @@ -1,8 +1,8 @@ #![warn(clippy::duplicate_underscore_argument)] fn join_the_dark_side(darth: i32, _darth: i32) {} -//~^ ERROR: `darth` already exists, having another argument having almost the same name ma -//~| NOTE: `-D clippy::duplicate-underscore-argument` implied by `-D warnings` +//~^ duplicate_underscore_argument + fn join_the_light_side(knight: i32, _master: i32) {} // the Force is strong with this one fn main() { diff --git a/src/tools/clippy/tests/ui/duration_subsec.fixed b/src/tools/clippy/tests/ui/duration_subsec.fixed index 114c516ed1a19..a8c2f78ca383a 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.fixed +++ b/src/tools/clippy/tests/ui/duration_subsec.fixed @@ -7,21 +7,26 @@ fn main() { let dur = Duration::new(5, 0); let bad_millis_1 = dur.subsec_millis(); + //~^ duration_subsec let bad_millis_2 = dur.subsec_millis(); + //~^ duration_subsec let good_millis = dur.subsec_millis(); assert_eq!(bad_millis_1, good_millis); assert_eq!(bad_millis_2, good_millis); let bad_micros = dur.subsec_micros(); + //~^ duration_subsec let good_micros = dur.subsec_micros(); assert_eq!(bad_micros, good_micros); // Handle refs let _ = (&dur).subsec_micros(); + //~^ duration_subsec // Handle constants const NANOS_IN_MICRO: u32 = 1_000; let _ = dur.subsec_micros(); + //~^ duration_subsec // Other literals aren't linted let _ = dur.subsec_nanos() / 699; diff --git a/src/tools/clippy/tests/ui/duration_subsec.rs b/src/tools/clippy/tests/ui/duration_subsec.rs index 8469fe086b10c..582f4717de27f 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.rs +++ b/src/tools/clippy/tests/ui/duration_subsec.rs @@ -7,21 +7,26 @@ fn main() { let dur = Duration::new(5, 0); let bad_millis_1 = dur.subsec_micros() / 1_000; + //~^ duration_subsec let bad_millis_2 = dur.subsec_nanos() / 1_000_000; + //~^ duration_subsec let good_millis = dur.subsec_millis(); assert_eq!(bad_millis_1, good_millis); assert_eq!(bad_millis_2, good_millis); let bad_micros = dur.subsec_nanos() / 1_000; + //~^ duration_subsec let good_micros = dur.subsec_micros(); assert_eq!(bad_micros, good_micros); // Handle refs let _ = (&dur).subsec_nanos() / 1_000; + //~^ duration_subsec // Handle constants const NANOS_IN_MICRO: u32 = 1_000; let _ = dur.subsec_nanos() / NANOS_IN_MICRO; + //~^ duration_subsec // Other literals aren't linted let _ = dur.subsec_nanos() / 699; diff --git a/src/tools/clippy/tests/ui/duration_subsec.stderr b/src/tools/clippy/tests/ui/duration_subsec.stderr index 55e44f149cf1e..1a41742e1fa6d 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.stderr +++ b/src/tools/clippy/tests/ui/duration_subsec.stderr @@ -8,25 +8,25 @@ LL | let bad_millis_1 = dur.subsec_micros() / 1_000; = help: to override `-D warnings` add `#[allow(clippy::duration_subsec)]` error: calling `subsec_millis()` is more concise than this calculation - --> tests/ui/duration_subsec.rs:10:24 + --> tests/ui/duration_subsec.rs:11:24 | LL | let bad_millis_2 = dur.subsec_nanos() / 1_000_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_millis()` error: calling `subsec_micros()` is more concise than this calculation - --> tests/ui/duration_subsec.rs:15:22 + --> tests/ui/duration_subsec.rs:17:22 | LL | let bad_micros = dur.subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()` error: calling `subsec_micros()` is more concise than this calculation - --> tests/ui/duration_subsec.rs:20:13 + --> tests/ui/duration_subsec.rs:23:13 | LL | let _ = (&dur).subsec_nanos() / 1_000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&dur).subsec_micros()` error: calling `subsec_micros()` is more concise than this calculation - --> tests/ui/duration_subsec.rs:24:13 + --> tests/ui/duration_subsec.rs:28:13 | LL | let _ = dur.subsec_nanos() / NANOS_IN_MICRO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `dur.subsec_micros()` diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed index ba4342462dca0..14cbb6113e62f 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.fixed +++ b/src/tools/clippy/tests/ui/eager_transmute.fixed @@ -19,20 +19,27 @@ struct Data { fn int_to_opcode(op: u8) -> Option { (op < 4).then(|| unsafe { std::mem::transmute(op) }) + //~^ eager_transmute } fn f(op: u8, op2: Data, unrelated: u8) { true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); (unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) }); + //~^ eager_transmute (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) }); + //~^ eager_transmute (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) }); + //~^ eager_transmute let _: Option = (op > 0 && op < 10).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (op > 0 && op < 10 && unrelated == 0).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute // lint even when the transmutable goes through field/array accesses let _: Option = (op2.foo[0] > 0 && op2.foo[0] < 10).then(|| unsafe { std::mem::transmute(op2.foo[0]) }); + //~^ eager_transmute // don't lint: wrong index used in the transmute let _: Option = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[1]) }); @@ -45,11 +52,17 @@ fn f(op: u8, op2: Data, unrelated: u8) { // range contains checks let _: Option = (1..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = ((1..=3).contains(&op) || op == 4).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (1..3).contains(&op).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (1..).contains(&op).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (..3).contains(&op).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (..=3).contains(&op).then(|| unsafe { std::mem::transmute(op) }); + //~^ eager_transmute // unrelated binding in contains let _: Option = (1..=3) @@ -59,6 +72,7 @@ fn f(op: u8, op2: Data, unrelated: u8) { unsafe fn f2(op: u8) { (op < 4).then(|| std::mem::transmute::<_, Opcode>(op)); + //~^ eager_transmute } #[rustc_layout_scalar_valid_range_end(254)] @@ -88,18 +102,21 @@ impls!(NonMaxU8, NonZeroNonMaxU8); fn niche_tests(v1: u8, v2: NonZero, v3: NonZeroNonMaxU8) { // u8 -> NonZero, do lint let _: Option> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) }); + //~^ eager_transmute // NonZero -> u8, don't lint, target type has no niche and therefore a higher validity range let _: Option = (v2 > NonZero::new(1u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); // NonZero -> NonMaxU8, do lint, different niche let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); + //~^ eager_transmute // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity let _: Option = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) }); // NonZero -> NonZeroNonMaxU8, do lint, target type has less validity let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) }); + //~^ eager_transmute } fn main() {} diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs index 9750e87ce5741..48d7d50cdaef8 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.rs +++ b/src/tools/clippy/tests/ui/eager_transmute.rs @@ -19,20 +19,27 @@ struct Data { fn int_to_opcode(op: u8) -> Option { (op < 4).then_some(unsafe { std::mem::transmute(op) }) + //~^ eager_transmute } fn f(op: u8, op2: Data, unrelated: u8) { true.then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); (unrelated < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); + //~^ eager_transmute (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); + //~^ eager_transmute (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); + //~^ eager_transmute let _: Option = (op > 0 && op < 10).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (op > 0 && op < 10 && unrelated == 0).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute // lint even when the transmutable goes through field/array accesses let _: Option = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[0]) }); + //~^ eager_transmute // don't lint: wrong index used in the transmute let _: Option = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[1]) }); @@ -45,11 +52,17 @@ fn f(op: u8, op2: Data, unrelated: u8) { // range contains checks let _: Option = (1..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = ((1..=3).contains(&op) || op == 4).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (1..3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (1..).contains(&op).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (..3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute let _: Option = (..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); + //~^ eager_transmute // unrelated binding in contains let _: Option = (1..=3) @@ -59,6 +72,7 @@ fn f(op: u8, op2: Data, unrelated: u8) { unsafe fn f2(op: u8) { (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); + //~^ eager_transmute } #[rustc_layout_scalar_valid_range_end(254)] @@ -88,18 +102,21 @@ impls!(NonMaxU8, NonZeroNonMaxU8); fn niche_tests(v1: u8, v2: NonZero, v3: NonZeroNonMaxU8) { // u8 -> NonZero, do lint let _: Option> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) }); + //~^ eager_transmute // NonZero -> u8, don't lint, target type has no niche and therefore a higher validity range let _: Option = (v2 > NonZero::new(1u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); // NonZero -> NonMaxU8, do lint, different niche let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); + //~^ eager_transmute // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity let _: Option = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) }); // NonZero -> NonZeroNonMaxU8, do lint, target type has less validity let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); + //~^ eager_transmute } fn main() {} diff --git a/src/tools/clippy/tests/ui/eager_transmute.stderr b/src/tools/clippy/tests/ui/eager_transmute.stderr index 68690c3730d89..54850d110eb26 100644 --- a/src/tools/clippy/tests/ui/eager_transmute.stderr +++ b/src/tools/clippy/tests/ui/eager_transmute.stderr @@ -13,7 +13,7 @@ LL + (op < 4).then(|| unsafe { std::mem::transmute(op) }) | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:27:33 + --> tests/ui/eager_transmute.rs:28:33 | LL | (op < 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + (op < 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) }); | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:28:33 + --> tests/ui/eager_transmute.rs:30:33 | LL | (op > 4).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + (op > 4).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) }); | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:29:34 + --> tests/ui/eager_transmute.rs:32:34 | LL | (op == 0).then_some(unsafe { std::mem::transmute::<_, Opcode>(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + (op == 0).then(|| unsafe { std::mem::transmute::<_, Opcode>(op) }); | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:31:68 + --> tests/ui/eager_transmute.rs:35:68 | LL | let _: Option = (op > 0 && op < 10).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let _: Option = (op > 0 && op < 10).then(|| unsafe { std::mem:: | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:32:86 + --> tests/ui/eager_transmute.rs:37:86 | LL | let _: Option = (op > 0 && op < 10 && unrelated == 0).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + let _: Option = (op > 0 && op < 10 && unrelated == 0).then(|| u | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:35:84 + --> tests/ui/eager_transmute.rs:41:84 | LL | let _: Option = (op2.foo[0] > 0 && op2.foo[0] < 10).then_some(unsafe { std::mem::transmute(op2.foo[0]) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + let _: Option = (op2.foo[0] > 0 && op2.foo[0] < 10).then(|| uns | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:47:70 + --> tests/ui/eager_transmute.rs:54:70 | LL | let _: Option = (1..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + let _: Option = (1..=3).contains(&op).then(|| unsafe { std::mem | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:48:83 + --> tests/ui/eager_transmute.rs:56:83 | LL | let _: Option = ((1..=3).contains(&op) || op == 4).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + let _: Option = ((1..=3).contains(&op) || op == 4).then(|| unsa | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:49:69 + --> tests/ui/eager_transmute.rs:58:69 | LL | let _: Option = (1..3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + let _: Option = (1..3).contains(&op).then(|| unsafe { std::mem: | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:50:68 + --> tests/ui/eager_transmute.rs:60:68 | LL | let _: Option = (1..).contains(&op).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + let _: Option = (1..).contains(&op).then(|| unsafe { std::mem:: | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:51:68 + --> tests/ui/eager_transmute.rs:62:68 | LL | let _: Option = (..3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + let _: Option = (..3).contains(&op).then(|| unsafe { std::mem:: | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:52:69 + --> tests/ui/eager_transmute.rs:64:69 | LL | let _: Option = (..=3).contains(&op).then_some(unsafe { std::mem::transmute(op) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + let _: Option = (..=3).contains(&op).then(|| unsafe { std::mem: | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:61:24 + --> tests/ui/eager_transmute.rs:74:24 | LL | (op < 4).then_some(std::mem::transmute::<_, Opcode>(op)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + (op < 4).then(|| std::mem::transmute::<_, Opcode>(op)); | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:90:62 + --> tests/ui/eager_transmute.rs:104:62 | LL | let _: Option> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let _: Option> = (v1 > 0).then(|| unsafe { std::mem::transm | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:96:86 + --> tests/ui/eager_transmute.rs:111:86 | LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + let _: Option = (v2 < NonZero::new(255u8).unwrap()).then(|| u | error: this transmute is always evaluated eagerly, even if the condition is false - --> tests/ui/eager_transmute.rs:102:93 + --> tests/ui/eager_transmute.rs:118:93 | LL | let _: Option = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) }); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed b/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed new file mode 100644 index 0000000000000..abeee5c4cef34 --- /dev/null +++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.fixed @@ -0,0 +1,194 @@ +#![warn(clippy::needless_lifetimes, clippy::elidable_lifetime_names)] + +type Ref<'r> = &'r u8; + +// No error; same lifetime on two params. +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} + +//~v ERROR: could be elided: 'a, 'b +fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} + +// No error; bounded lifetime. +fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} + +// No error; bounded lifetime. +fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) +where + 'b: 'a, +{ +} + +struct Lt<'a, I: 'static> { + x: &'a I, +} + +// No error; fn bound references `'a`. +fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> +where + F: Fn(Lt<'a, I>) -> Lt<'a, I>, +{ + unreachable!() +} + +//~v ERROR: could be elided: 'a +fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> +where + for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>, +{ + unreachable!() +} + +struct Foo<'a>(&'a u8); + +//~v ERROR: could be elided: 'a +fn struct_with_lt(_foo: Foo<'_>) -> &str { + unimplemented!() +} + +// No warning; two input lifetimes (named on the reference, anonymous on `Foo`). +fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (anonymous on the reference, named on `Foo`). +fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str { + unimplemented!() +} + +//~v ERROR: could be elided: 'b +fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { + unimplemented!() +} + +type FooAlias<'a> = Foo<'a>; + +//~v ERROR: could be elided: 'a +fn alias_with_lt(_foo: FooAlias<'_>) -> &str { + unimplemented!() +} + +// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`). +fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`). +fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str { + unimplemented!() +} + +//~v ERROR: could be elided: 'b +fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { + unimplemented!() +} + +// Issue #3284: give hint regarding lifetime in return type. +struct Cow<'a> { + x: &'a str, +} + +//~v ERROR: could be elided: 'a +fn out_return_type_lts(e: &str) -> Cow<'_> { + unimplemented!() +} + +mod issue2944 { + trait Foo {} + struct Bar; + struct Baz<'a> { + bar: &'a Bar, + } + + //~v ERROR: could be elided: 'a + impl Foo for Baz<'_> {} + impl Bar { + //~v ERROR: could be elided: 'a + fn baz(&self) -> impl Foo + '_ { + Baz { bar: self } + } + } +} + +mod issue13923 { + struct Py<'py> { + data: &'py str, + } + + enum Content<'t, 'py> { + Py(Py<'py>), + T1(&'t str), + T2(&'t str), + } + + enum ContentString<'t> { + T1(&'t str), + T2(&'t str), + } + + impl<'t, 'py> ContentString<'t> { + // `'py` cannot be elided + fn map_content1(self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + //~v ERROR: could be elided: 'py + impl<'t> ContentString<'t> { + // `'py` can be elided because of `&self` + fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + //~v ERROR: could be elided: 'py + impl<'t> ContentString<'t> { + // `'py` can be elided because of `&'_ self` + fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t, 'py> ContentString<'t> { + // `'py` should not be elided as the default lifetime, even if working, could be named as `'t` + fn map_content4(self, f: impl FnOnce(&'t str) -> &'t str, o: &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + //~v ERROR: could be elided: 'py + impl<'t> ContentString<'t> { + // `'py` can be elided because of `&Self` + fn map_content5( + self: std::pin::Pin<&Self>, + f: impl FnOnce(&'t str) -> &'t str, + o: &'t str, + ) -> Content<'t, '_> { + match *self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + struct Cx<'a, 'b> { + a: &'a u32, + b: &'b u32, + } + + // `'c` cannot be elided because we have several input lifetimes + fn one_explicit<'b>(x: Cx<'_, 'b>) -> &'b u32 { + x.b + } +} diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.rs b/src/tools/clippy/tests/ui/elidable_lifetime_names.rs new file mode 100644 index 0000000000000..fae3577a8e960 --- /dev/null +++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.rs @@ -0,0 +1,194 @@ +#![warn(clippy::needless_lifetimes, clippy::elidable_lifetime_names)] + +type Ref<'r> = &'r u8; + +// No error; same lifetime on two params. +fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} + +//~v ERROR: could be elided: 'a, 'b +fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} + +// No error; bounded lifetime. +fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} + +// No error; bounded lifetime. +fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) +where + 'b: 'a, +{ +} + +struct Lt<'a, I: 'static> { + x: &'a I, +} + +// No error; fn bound references `'a`. +fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> +where + F: Fn(Lt<'a, I>) -> Lt<'a, I>, +{ + unreachable!() +} + +//~v ERROR: could be elided: 'a +fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> +where + for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>, +{ + unreachable!() +} + +struct Foo<'a>(&'a u8); + +//~v ERROR: could be elided: 'a +fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (named on the reference, anonymous on `Foo`). +fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (anonymous on the reference, named on `Foo`). +fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str { + unimplemented!() +} + +//~v ERROR: could be elided: 'b +fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { + unimplemented!() +} + +type FooAlias<'a> = Foo<'a>; + +//~v ERROR: could be elided: 'a +fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`). +fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { + unimplemented!() +} + +// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`). +fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str { + unimplemented!() +} + +//~v ERROR: could be elided: 'b +fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { + unimplemented!() +} + +// Issue #3284: give hint regarding lifetime in return type. +struct Cow<'a> { + x: &'a str, +} + +//~v ERROR: could be elided: 'a +fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { + unimplemented!() +} + +mod issue2944 { + trait Foo {} + struct Bar; + struct Baz<'a> { + bar: &'a Bar, + } + + //~v ERROR: could be elided: 'a + impl<'a> Foo for Baz<'a> {} + impl Bar { + //~v ERROR: could be elided: 'a + fn baz<'a>(&'a self) -> impl Foo + 'a { + Baz { bar: self } + } + } +} + +mod issue13923 { + struct Py<'py> { + data: &'py str, + } + + enum Content<'t, 'py> { + Py(Py<'py>), + T1(&'t str), + T2(&'t str), + } + + enum ContentString<'t> { + T1(&'t str), + T2(&'t str), + } + + impl<'t, 'py> ContentString<'t> { + // `'py` cannot be elided + fn map_content1(self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + //~v ERROR: could be elided: 'py + impl<'t, 'py> ContentString<'t> { + // `'py` can be elided because of `&self` + fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + //~v ERROR: could be elided: 'py + impl<'t, 'py> ContentString<'t> { + // `'py` can be elided because of `&'_ self` + fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(content) => Content::T2(f(content)), + } + } + } + + impl<'t, 'py> ContentString<'t> { + // `'py` should not be elided as the default lifetime, even if working, could be named as `'t` + fn map_content4(self, f: impl FnOnce(&'t str) -> &'t str, o: &'t str) -> Content<'t, 'py> { + match self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + //~v ERROR: could be elided: 'py + impl<'t, 'py> ContentString<'t> { + // `'py` can be elided because of `&Self` + fn map_content5( + self: std::pin::Pin<&Self>, + f: impl FnOnce(&'t str) -> &'t str, + o: &'t str, + ) -> Content<'t, 'py> { + match *self { + Self::T1(content) => Content::T1(f(content)), + Self::T2(_) => Content::T2(o), + } + } + } + + struct Cx<'a, 'b> { + a: &'a u32, + b: &'b u32, + } + + // `'c` cannot be elided because we have several input lifetimes + fn one_explicit<'b>(x: Cx<'_, 'b>) -> &'b u32 { + x.b + } +} diff --git a/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr b/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr new file mode 100644 index 0000000000000..a60dfc697564e --- /dev/null +++ b/src/tools/clippy/tests/ui/elidable_lifetime_names.stderr @@ -0,0 +1,162 @@ +error: the following explicit lifetimes could be elided: 'a, 'b + --> tests/ui/elidable_lifetime_names.rs:9:21 + | +LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} + | ^^ ^^ ^^ ^^ + | + = note: `-D clippy::elidable-lifetime-names` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::elidable_lifetime_names)]` +help: elide the lifetimes + | +LL - fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} +LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/elidable_lifetime_names.rs:34:15 + | +LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> +LL + fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/elidable_lifetime_names.rs:44:19 + | +LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { +LL + fn struct_with_lt(_foo: Foo<'_>) -> &str { + | + +error: the following explicit lifetimes could be elided: 'b + --> tests/ui/elidable_lifetime_names.rs:59:25 + | +LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { + | ^^ ^^ + | +help: elide the lifetimes + | +LL - fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { +LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/elidable_lifetime_names.rs:66:18 + | +LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { +LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str { + | + +error: the following explicit lifetimes could be elided: 'b + --> tests/ui/elidable_lifetime_names.rs:81:24 + | +LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { + | ^^ ^^ + | +help: elide the lifetimes + | +LL - fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { +LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/elidable_lifetime_names.rs:91:24 + | +LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { +LL + fn out_return_type_lts(e: &str) -> Cow<'_> { + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/elidable_lifetime_names.rs:103:10 + | +LL | impl<'a> Foo for Baz<'a> {} + | ^^ ^^ + | +help: elide the lifetimes + | +LL - impl<'a> Foo for Baz<'a> {} +LL + impl Foo for Baz<'_> {} + | + +error: the following explicit lifetimes could be elided: 'a + --> tests/ui/elidable_lifetime_names.rs:106:16 + | +LL | fn baz<'a>(&'a self) -> impl Foo + 'a { + | ^^ ^^ ^^ + | +help: elide the lifetimes + | +LL - fn baz<'a>(&'a self) -> impl Foo + 'a { +LL + fn baz(&self) -> impl Foo + '_ { + | + +error: the following explicit lifetimes could be elided: 'py + --> tests/ui/elidable_lifetime_names.rs:139:14 + | +LL | impl<'t, 'py> ContentString<'t> { + | ^^^ +LL | // `'py` can be elided because of `&self` +LL | fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + | ^^^ + | +help: elide the lifetimes + | +LL ~ impl<'t> ContentString<'t> { +LL | // `'py` can be elided because of `&self` +LL ~ fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + | + +error: the following explicit lifetimes could be elided: 'py + --> tests/ui/elidable_lifetime_names.rs:150:14 + | +LL | impl<'t, 'py> ContentString<'t> { + | ^^^ +LL | // `'py` can be elided because of `&'_ self` +LL | fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { + | ^^^ + | +help: elide the lifetimes + | +LL ~ impl<'t> ContentString<'t> { +LL | // `'py` can be elided because of `&'_ self` +LL ~ fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { + | + +error: the following explicit lifetimes could be elided: 'py + --> tests/ui/elidable_lifetime_names.rs:171:14 + | +LL | impl<'t, 'py> ContentString<'t> { + | ^^^ +... +LL | ) -> Content<'t, 'py> { + | ^^^ + | +help: elide the lifetimes + | +LL ~ impl<'t> ContentString<'t> { +LL | // `'py` can be elided because of `&Self` +... +LL | o: &'t str, +LL ~ ) -> Content<'t, '_> { + | + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/else_if_without_else.rs b/src/tools/clippy/tests/ui/else_if_without_else.rs index b04c22fa2aed6..05d56600e1006 100644 --- a/src/tools/clippy/tests/ui/else_if_without_else.rs +++ b/src/tools/clippy/tests/ui/else_if_without_else.rs @@ -49,7 +49,8 @@ fn main() { if bla1() { println!("if"); } else if bla2() { - //~^ ERROR: `if` expression with an `else if`, but without a final `else` + //~^ else_if_without_else + println!("else if"); } @@ -58,7 +59,8 @@ fn main() { } else if bla2() { println!("else if 1"); } else if bla3() { - //~^ ERROR: `if` expression with an `else if`, but without a final `else` + //~^ else_if_without_else + println!("else if 2"); } @@ -85,7 +87,8 @@ fn main() { } else if bla4() { println!("else if 3"); } else if bla5() { - //~^ ERROR: `if` expression with an `else if`, but without a final `else` + //~^ else_if_without_else + println!("else if 4"); } @@ -115,7 +118,8 @@ fn main() { } else if bla4() { println!("else if 3"); } else if bla5() { - //~^ ERROR: `if` expression with an `else if`, but without a final `else` + //~^ else_if_without_else + println!("else if 4"); } } diff --git a/src/tools/clippy/tests/ui/else_if_without_else.stderr b/src/tools/clippy/tests/ui/else_if_without_else.stderr index bc7174852293a..ac7802345b97f 100644 --- a/src/tools/clippy/tests/ui/else_if_without_else.stderr +++ b/src/tools/clippy/tests/ui/else_if_without_else.stderr @@ -4,6 +4,7 @@ error: `if` expression with an `else if`, but without a final `else` LL | } else if bla2() { | ____________^ LL | | +LL | | LL | | println!("else if"); LL | | } | |_____^ @@ -13,11 +14,12 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::else_if_without_else)]` error: `if` expression with an `else if`, but without a final `else` - --> tests/ui/else_if_without_else.rs:60:12 + --> tests/ui/else_if_without_else.rs:61:12 | LL | } else if bla3() { | ____________^ LL | | +LL | | LL | | println!("else if 2"); LL | | } | |_____^ @@ -25,11 +27,12 @@ LL | | } = help: add an `else` block here error: `if` expression with an `else if`, but without a final `else` - --> tests/ui/else_if_without_else.rs:87:12 + --> tests/ui/else_if_without_else.rs:89:12 | LL | } else if bla5() { | ____________^ LL | | +LL | | LL | | println!("else if 4"); LL | | } | |_____^ @@ -37,11 +40,12 @@ LL | | } = help: add an `else` block here error: `if` expression with an `else if`, but without a final `else` - --> tests/ui/else_if_without_else.rs:117:16 + --> tests/ui/else_if_without_else.rs:120:16 | LL | } else if bla5() { | ________________^ LL | | +LL | | LL | | println!("else if 4"); LL | | } | |_________^ diff --git a/src/tools/clippy/tests/ui/empty_docs.rs b/src/tools/clippy/tests/ui/empty_docs.rs index 00e64eebc5fba..d7768e07901ae 100644 --- a/src/tools/clippy/tests/ui/empty_docs.rs +++ b/src/tools/clippy/tests/ui/empty_docs.rs @@ -7,6 +7,7 @@ mod outer { //! + //~^ empty_docs /// this is a struct struct Bananas { @@ -15,8 +16,10 @@ mod outer { } /// + //~^ empty_docs enum Warn { /// + //~^ empty_docs A, B, } @@ -28,16 +31,19 @@ mod outer { } #[doc = ""] + //~^ empty_docs fn warn_about_this() {} #[doc = ""] #[doc = ""] + //~^^ empty_docs fn this_doesn_warn() {} #[doc = "a fine function"] fn this_is_fine() {} /// + //~^ empty_docs mod inner { /// fn dont_warn_inner_outer() { @@ -51,6 +57,7 @@ mod outer { fn warn() { /*! */ + //~^ empty_docs } fn dont_warn() { @@ -59,6 +66,7 @@ mod outer { trait NoDoc { /// + //~^ empty_docs fn some() {} } } @@ -67,6 +75,7 @@ mod outer { /// lint y x: i32, /// + //~^ empty_docs y: i32, } } diff --git a/src/tools/clippy/tests/ui/empty_docs.stderr b/src/tools/clippy/tests/ui/empty_docs.stderr index 5fd7272d7c168..2eba6806852b2 100644 --- a/src/tools/clippy/tests/ui/empty_docs.stderr +++ b/src/tools/clippy/tests/ui/empty_docs.stderr @@ -9,7 +9,7 @@ LL | //! = help: to override `-D warnings` add `#[allow(clippy::empty_docs)]` error: empty doc comment - --> tests/ui/empty_docs.rs:17:5 + --> tests/ui/empty_docs.rs:18:5 | LL | /// | ^^^ @@ -17,7 +17,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:19:9 + --> tests/ui/empty_docs.rs:21:9 | LL | /// | ^^^ @@ -25,7 +25,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:30:13 + --> tests/ui/empty_docs.rs:33:13 | LL | #[doc = ""] | ^^ @@ -33,7 +33,7 @@ LL | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:33:13 + --> tests/ui/empty_docs.rs:37:13 | LL | #[doc = ""] | _____________^ @@ -43,7 +43,7 @@ LL | | #[doc = ""] = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:40:5 + --> tests/ui/empty_docs.rs:45:5 | LL | /// | ^^^ @@ -51,7 +51,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:53:13 + --> tests/ui/empty_docs.rs:59:13 | LL | /*! */ | ^^^^^^ @@ -59,7 +59,7 @@ LL | /*! */ = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:61:13 + --> tests/ui/empty_docs.rs:68:13 | LL | /// | ^^^ @@ -67,7 +67,7 @@ LL | /// = help: consider removing or filling it error: empty doc comment - --> tests/ui/empty_docs.rs:69:9 + --> tests/ui/empty_docs.rs:77:9 | LL | /// | ^^^ diff --git a/src/tools/clippy/tests/ui/empty_drop.rs b/src/tools/clippy/tests/ui/empty_drop.rs index 74822ea50ec71..5793f783a7242 100644 --- a/src/tools/clippy/tests/ui/empty_drop.rs +++ b/src/tools/clippy/tests/ui/empty_drop.rs @@ -5,6 +5,7 @@ struct Foo; impl Drop for Foo { + //~^ empty_drop fn drop(&mut self) {} } @@ -21,6 +22,7 @@ impl Drop for Bar { struct Baz; impl Drop for Baz { + //~^ empty_drop fn drop(&mut self) { {} } diff --git a/src/tools/clippy/tests/ui/empty_drop.stderr b/src/tools/clippy/tests/ui/empty_drop.stderr index d4d020fec30cf..3073bf553969b 100644 --- a/src/tools/clippy/tests/ui/empty_drop.stderr +++ b/src/tools/clippy/tests/ui/empty_drop.stderr @@ -2,6 +2,7 @@ error: empty drop implementation --> tests/ui/empty_drop.rs:7:1 | LL | / impl Drop for Foo { +LL | | LL | | fn drop(&mut self) {} LL | | } | |_^ @@ -11,9 +12,10 @@ LL | | } = help: try removing this impl error: empty drop implementation - --> tests/ui/empty_drop.rs:23:1 + --> tests/ui/empty_drop.rs:24:1 | LL | / impl Drop for Baz { +LL | | LL | | fn drop(&mut self) { LL | | {} LL | | } diff --git a/src/tools/clippy/tests/ui/empty_enum.rs b/src/tools/clippy/tests/ui/empty_enum.rs index 77357c15d957f..439fd0974f5f8 100644 --- a/src/tools/clippy/tests/ui/empty_enum.rs +++ b/src/tools/clippy/tests/ui/empty_enum.rs @@ -3,6 +3,6 @@ // Enable never type to test empty enum lint #![feature(never_type)] enum Empty {} -//~^ ERROR: enum with no variants +//~^ empty_enum fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed index 1a5e78dd47fef..885f6a50025e9 100644 --- a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed +++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed @@ -4,16 +4,20 @@ pub enum PublicTestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error NonEmptyParentheses(i32, i32), // No error - EmptyBraces, //~ ERROR: enum variant has empty brackets - EmptyParentheses, //~ ERROR: enum variant has empty brackets + EmptyBraces, + //~^ empty_enum_variants_with_brackets + EmptyParentheses, + //~^ empty_enum_variants_with_brackets } enum TestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error NonEmptyParentheses(i32, i32), // No error - EmptyBraces, //~ ERROR: enum variant has empty brackets - EmptyParentheses, //~ ERROR: enum variant has empty brackets - AnotherEnum, // No error + EmptyBraces, + //~^ empty_enum_variants_with_brackets + EmptyParentheses, + //~^ empty_enum_variants_with_brackets + AnotherEnum, // No error } enum TestEnumWithFeatures { diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs index ca20b969a240a..092712ee2ead4 100644 --- a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs +++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs @@ -4,16 +4,20 @@ pub enum PublicTestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error NonEmptyParentheses(i32, i32), // No error - EmptyBraces {}, //~ ERROR: enum variant has empty brackets - EmptyParentheses(), //~ ERROR: enum variant has empty brackets + EmptyBraces {}, + //~^ empty_enum_variants_with_brackets + EmptyParentheses(), + //~^ empty_enum_variants_with_brackets } enum TestEnum { NonEmptyBraces { x: i32, y: i32 }, // No error NonEmptyParentheses(i32, i32), // No error - EmptyBraces {}, //~ ERROR: enum variant has empty brackets - EmptyParentheses(), //~ ERROR: enum variant has empty brackets - AnotherEnum, // No error + EmptyBraces {}, + //~^ empty_enum_variants_with_brackets + EmptyParentheses(), + //~^ empty_enum_variants_with_brackets + AnotherEnum, // No error } enum TestEnumWithFeatures { diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr index 2b187b8f755b4..a9ae3b476dd68 100644 --- a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr +++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr @@ -9,7 +9,7 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:8:21 + --> tests/ui/empty_enum_variants_with_brackets.rs:9:21 | LL | EmptyParentheses(), | ^^ @@ -17,7 +17,7 @@ LL | EmptyParentheses(), = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:14:16 + --> tests/ui/empty_enum_variants_with_brackets.rs:16:16 | LL | EmptyBraces {}, | ^^^ @@ -25,7 +25,7 @@ LL | EmptyBraces {}, = help: remove the brackets error: enum variant has empty brackets - --> tests/ui/empty_enum_variants_with_brackets.rs:15:21 + --> tests/ui/empty_enum_variants_with_brackets.rs:18:21 | LL | EmptyParentheses(), | ^^ diff --git a/src/tools/clippy/tests/ui/empty_enum_without_never_type.rs b/src/tools/clippy/tests/ui/empty_enum_without_never_type.rs index 386677352e29b..3661a15372086 100644 --- a/src/tools/clippy/tests/ui/empty_enum_without_never_type.rs +++ b/src/tools/clippy/tests/ui/empty_enum_without_never_type.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(dead_code)] #![warn(clippy::empty_enum)] diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed index 3772b465fdb2a..e4ba09ea1d478 100644 --- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed @@ -138,6 +138,7 @@ trait Foo { impl Foo for LineComment { /// comment on assoc item + //~^ empty_line_after_doc_comments fn bar() {} } diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed index 3028d03b66994..a20f9bc20eb56 100644 --- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed @@ -146,7 +146,9 @@ trait Foo { } impl Foo for LineComment { - /// comment on assoc item + // /// comment on assoc item + //~^ empty_line_after_doc_comments + fn bar() {} } diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs index ae4ebc271fa1c..9e3ddfd5abe11 100644 --- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs @@ -150,6 +150,7 @@ trait Foo { impl Foo for LineComment { /// comment on assoc item + //~^ empty_line_after_doc_comments fn bar() {} } diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr index ca05a1b03eb1c..fe25ba9afcb90 100644 --- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr +++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr @@ -176,12 +176,17 @@ error: empty line after doc comment --> tests/ui/empty_line_after/doc_comments.rs:152:5 | LL | / /// comment on assoc item +LL | | LL | | | |_^ LL | fn bar() {} | ------ the comment documents this function | = help: if the empty line is unintentional, remove it +help: if the doc comment should not document `bar` comment it out + | +LL | // /// comment on assoc item + | ++ error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/empty_loop.rs b/src/tools/clippy/tests/ui/empty_loop.rs index be347563135c3..e2d4ff84b56a9 100644 --- a/src/tools/clippy/tests/ui/empty_loop.rs +++ b/src/tools/clippy/tests/ui/empty_loop.rs @@ -7,14 +7,17 @@ use proc_macros::{external, inline_macros}; fn should_trigger() { loop {} + //~^ empty_loop #[allow(clippy::never_loop)] loop { loop {} + //~^ empty_loop } #[allow(clippy::never_loop)] 'outer: loop { 'inner: loop {} + //~^ empty_loop } } diff --git a/src/tools/clippy/tests/ui/empty_loop.stderr b/src/tools/clippy/tests/ui/empty_loop.stderr index 3ac93f4ece0cc..bc723ceefbb37 100644 --- a/src/tools/clippy/tests/ui/empty_loop.stderr +++ b/src/tools/clippy/tests/ui/empty_loop.stderr @@ -9,7 +9,7 @@ LL | loop {} = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]` error: empty `loop {}` wastes CPU cycles - --> tests/ui/empty_loop.rs:12:9 + --> tests/ui/empty_loop.rs:13:9 | LL | loop {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | loop {} = help: you should either use `panic!()` or add `std::thread::sleep(..);` to the loop body error: empty `loop {}` wastes CPU cycles - --> tests/ui/empty_loop.rs:17:9 + --> tests/ui/empty_loop.rs:19:9 | LL | 'inner: loop {} | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs index 9bfcbfba9697f..6407bd678f9ca 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs @@ -8,5 +8,5 @@ pub fn main(argc: isize, argv: *const *const u8) -> isize { // This should trigger the lint loop {} - //~^ ERROR: empty `loop {}` wastes CPU cycles + //~^ empty_loop } diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed index 80572645f5d1c..b1600862a8f60 100644 --- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed +++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed @@ -2,7 +2,9 @@ #![allow(dead_code)] pub struct MyEmptyStruct; // should trigger lint +//~^ empty_structs_with_brackets struct MyEmptyTupleStruct; // should trigger lint +//~^ empty_structs_with_brackets // should not trigger lint struct MyCfgStruct { diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs index 8fb3e247a4198..1f69c4be9ec77 100644 --- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs +++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs @@ -2,7 +2,9 @@ #![allow(dead_code)] pub struct MyEmptyStruct {} // should trigger lint +//~^ empty_structs_with_brackets struct MyEmptyTupleStruct(); // should trigger lint +//~^ empty_structs_with_brackets // should not trigger lint struct MyCfgStruct { diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr b/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr index e57249aec0238..86ef43aa9600b 100644 --- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr +++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.stderr @@ -9,7 +9,7 @@ LL | pub struct MyEmptyStruct {} // should trigger lint = help: remove the brackets error: found empty brackets on struct declaration - --> tests/ui/empty_structs_with_brackets.rs:5:26 + --> tests/ui/empty_structs_with_brackets.rs:6:26 | LL | struct MyEmptyTupleStruct(); // should trigger lint | ^^^ diff --git a/src/tools/clippy/tests/ui/endian_bytes.rs b/src/tools/clippy/tests/ui/endian_bytes.rs index 580fc2fc24d76..879467c7f6e23 100644 --- a/src/tools/clippy/tests/ui/endian_bytes.rs +++ b/src/tools/clippy/tests/ui/endian_bytes.rs @@ -7,62 +7,118 @@ macro_rules! fn_body { () => { 2u8.to_ne_bytes(); + //~^ host_endian_bytes 2i8.to_ne_bytes(); + //~^ host_endian_bytes 2u16.to_ne_bytes(); + //~^ host_endian_bytes 2i16.to_ne_bytes(); + //~^ host_endian_bytes 2u32.to_ne_bytes(); + //~^ host_endian_bytes 2i32.to_ne_bytes(); + //~^ host_endian_bytes 2u64.to_ne_bytes(); + //~^ host_endian_bytes 2i64.to_ne_bytes(); + //~^ host_endian_bytes 2u128.to_ne_bytes(); + //~^ host_endian_bytes 2i128.to_ne_bytes(); + //~^ host_endian_bytes 2.0f32.to_ne_bytes(); + //~^ host_endian_bytes 2.0f64.to_ne_bytes(); + //~^ host_endian_bytes 2usize.to_ne_bytes(); + //~^ host_endian_bytes 2isize.to_ne_bytes(); + //~^ host_endian_bytes u8::from_ne_bytes(todo!()); + //~^ host_endian_bytes i8::from_ne_bytes(todo!()); + //~^ host_endian_bytes u16::from_ne_bytes(todo!()); + //~^ host_endian_bytes i16::from_ne_bytes(todo!()); + //~^ host_endian_bytes u32::from_ne_bytes(todo!()); + //~^ host_endian_bytes i32::from_ne_bytes(todo!()); + //~^ host_endian_bytes u64::from_ne_bytes(todo!()); + //~^ host_endian_bytes i64::from_ne_bytes(todo!()); + //~^ host_endian_bytes u128::from_ne_bytes(todo!()); + //~^ host_endian_bytes i128::from_ne_bytes(todo!()); + //~^ host_endian_bytes usize::from_ne_bytes(todo!()); + //~^ host_endian_bytes isize::from_ne_bytes(todo!()); + //~^ host_endian_bytes f32::from_ne_bytes(todo!()); + //~^ host_endian_bytes f64::from_ne_bytes(todo!()); + //~^ host_endian_bytes 2u8.to_le_bytes(); + //~^ little_endian_bytes 2i8.to_le_bytes(); + //~^ little_endian_bytes 2u16.to_le_bytes(); + //~^ little_endian_bytes 2i16.to_le_bytes(); + //~^ little_endian_bytes 2u32.to_le_bytes(); + //~^ little_endian_bytes 2i32.to_le_bytes(); + //~^ little_endian_bytes 2u64.to_le_bytes(); + //~^ little_endian_bytes 2i64.to_le_bytes(); + //~^ little_endian_bytes 2u128.to_le_bytes(); + //~^ little_endian_bytes 2i128.to_le_bytes(); + //~^ little_endian_bytes 2.0f32.to_le_bytes(); + //~^ little_endian_bytes 2.0f64.to_le_bytes(); + //~^ little_endian_bytes 2usize.to_le_bytes(); + //~^ little_endian_bytes 2isize.to_le_bytes(); + //~^ little_endian_bytes u8::from_le_bytes(todo!()); + //~^ little_endian_bytes i8::from_le_bytes(todo!()); + //~^ little_endian_bytes u16::from_le_bytes(todo!()); + //~^ little_endian_bytes i16::from_le_bytes(todo!()); + //~^ little_endian_bytes u32::from_le_bytes(todo!()); + //~^ little_endian_bytes i32::from_le_bytes(todo!()); + //~^ little_endian_bytes u64::from_le_bytes(todo!()); + //~^ little_endian_bytes i64::from_le_bytes(todo!()); + //~^ little_endian_bytes u128::from_le_bytes(todo!()); + //~^ little_endian_bytes i128::from_le_bytes(todo!()); + //~^ little_endian_bytes usize::from_le_bytes(todo!()); + //~^ little_endian_bytes isize::from_le_bytes(todo!()); + //~^ little_endian_bytes f32::from_le_bytes(todo!()); + //~^ little_endian_bytes f64::from_le_bytes(todo!()); + //~^ little_endian_bytes }; } @@ -70,13 +126,43 @@ macro_rules! fn_body { macro_rules! fn_body_smol { () => { 2u8.to_ne_bytes(); + //~^ host_endian_bytes + //~| host_endian_bytes + //~| host_endian_bytes + //~| host_endian_bytes + //~| host_endian_bytes u8::from_ne_bytes(todo!()); + //~^ host_endian_bytes + //~| host_endian_bytes + //~| host_endian_bytes + //~| host_endian_bytes + //~| host_endian_bytes 2u8.to_le_bytes(); + //~^ little_endian_bytes + //~| little_endian_bytes + //~| little_endian_bytes + //~| little_endian_bytes + //~| little_endian_bytes u8::from_le_bytes(todo!()); + //~^ little_endian_bytes + //~| little_endian_bytes + //~| little_endian_bytes + //~| little_endian_bytes + //~| little_endian_bytes 2u8.to_be_bytes(); + //~^ big_endian_bytes + //~| big_endian_bytes + //~| big_endian_bytes + //~| big_endian_bytes + //~| big_endian_bytes u8::from_be_bytes(todo!()); + //~^ big_endian_bytes + //~| big_endian_bytes + //~| big_endian_bytes + //~| big_endian_bytes + //~| big_endian_bytes }; } diff --git a/src/tools/clippy/tests/ui/endian_bytes.stderr b/src/tools/clippy/tests/ui/endian_bytes.stderr index fd19ec45872b4..edc2a3309f24f 100644 --- a/src/tools/clippy/tests/ui/endian_bytes.stderr +++ b/src/tools/clippy/tests/ui/endian_bytes.stderr @@ -13,7 +13,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:10:9 + --> tests/ui/endian_bytes.rs:11:9 | LL | 2i8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u16::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:11:9 + --> tests/ui/endian_bytes.rs:13:9 | LL | 2u16.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i16::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:12:9 + --> tests/ui/endian_bytes.rs:15:9 | LL | 2i16.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u32::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:13:9 + --> tests/ui/endian_bytes.rs:17:9 | LL | 2u32.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i32::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:14:9 + --> tests/ui/endian_bytes.rs:19:9 | LL | 2i32.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u64::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:15:9 + --> tests/ui/endian_bytes.rs:21:9 | LL | 2u64.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i64::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:16:9 + --> tests/ui/endian_bytes.rs:23:9 | LL | 2i64.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u128::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:17:9 + --> tests/ui/endian_bytes.rs:25:9 | LL | 2u128.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i128::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:18:9 + --> tests/ui/endian_bytes.rs:27:9 | LL | 2i128.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f32::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:19:9 + --> tests/ui/endian_bytes.rs:29:9 | LL | 2.0f32.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f64::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:20:9 + --> tests/ui/endian_bytes.rs:31:9 | LL | 2.0f64.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `usize::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:21:9 + --> tests/ui/endian_bytes.rs:33:9 | LL | 2usize.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `isize::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:22:9 + --> tests/ui/endian_bytes.rs:35:9 | LL | 2isize.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:23:9 + --> tests/ui/endian_bytes.rs:37:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:24:9 + --> tests/ui/endian_bytes.rs:39:9 | LL | i8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u16::from_ne_bytes` - --> tests/ui/endian_bytes.rs:25:9 + --> tests/ui/endian_bytes.rs:41:9 | LL | u16::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i16::from_ne_bytes` - --> tests/ui/endian_bytes.rs:26:9 + --> tests/ui/endian_bytes.rs:43:9 | LL | i16::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u32::from_ne_bytes` - --> tests/ui/endian_bytes.rs:27:9 + --> tests/ui/endian_bytes.rs:45:9 | LL | u32::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i32::from_ne_bytes` - --> tests/ui/endian_bytes.rs:28:9 + --> tests/ui/endian_bytes.rs:47:9 | LL | i32::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u64::from_ne_bytes` - --> tests/ui/endian_bytes.rs:29:9 + --> tests/ui/endian_bytes.rs:49:9 | LL | u64::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i64::from_ne_bytes` - --> tests/ui/endian_bytes.rs:30:9 + --> tests/ui/endian_bytes.rs:51:9 | LL | i64::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u128::from_ne_bytes` - --> tests/ui/endian_bytes.rs:31:9 + --> tests/ui/endian_bytes.rs:53:9 | LL | u128::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i128::from_ne_bytes` - --> tests/ui/endian_bytes.rs:32:9 + --> tests/ui/endian_bytes.rs:55:9 | LL | i128::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -289,7 +289,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `usize::from_ne_bytes` - --> tests/ui/endian_bytes.rs:33:9 + --> tests/ui/endian_bytes.rs:57:9 | LL | usize::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `isize::from_ne_bytes` - --> tests/ui/endian_bytes.rs:34:9 + --> tests/ui/endian_bytes.rs:59:9 | LL | isize::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f32::from_ne_bytes` - --> tests/ui/endian_bytes.rs:35:9 + --> tests/ui/endian_bytes.rs:61:9 | LL | f32::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f64::from_ne_bytes` - --> tests/ui/endian_bytes.rs:36:9 + --> tests/ui/endian_bytes.rs:63:9 | LL | f64::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL | fn host() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:38:9 + --> tests/ui/endian_bytes.rs:66:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -351,7 +351,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:39:9 + --> tests/ui/endian_bytes.rs:68:9 | LL | 2i8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -363,7 +363,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u16::to_le_bytes` method - --> tests/ui/endian_bytes.rs:40:9 + --> tests/ui/endian_bytes.rs:70:9 | LL | 2u16.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -375,7 +375,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i16::to_le_bytes` method - --> tests/ui/endian_bytes.rs:41:9 + --> tests/ui/endian_bytes.rs:72:9 | LL | 2i16.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -387,7 +387,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u32::to_le_bytes` method - --> tests/ui/endian_bytes.rs:42:9 + --> tests/ui/endian_bytes.rs:74:9 | LL | 2u32.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -399,7 +399,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i32::to_le_bytes` method - --> tests/ui/endian_bytes.rs:43:9 + --> tests/ui/endian_bytes.rs:76:9 | LL | 2i32.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -411,7 +411,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u64::to_le_bytes` method - --> tests/ui/endian_bytes.rs:44:9 + --> tests/ui/endian_bytes.rs:78:9 | LL | 2u64.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -423,7 +423,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i64::to_le_bytes` method - --> tests/ui/endian_bytes.rs:45:9 + --> tests/ui/endian_bytes.rs:80:9 | LL | 2i64.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^ @@ -435,7 +435,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u128::to_le_bytes` method - --> tests/ui/endian_bytes.rs:46:9 + --> tests/ui/endian_bytes.rs:82:9 | LL | 2u128.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -447,7 +447,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `i128::to_le_bytes` method - --> tests/ui/endian_bytes.rs:47:9 + --> tests/ui/endian_bytes.rs:84:9 | LL | 2i128.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^ @@ -459,7 +459,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f32::to_le_bytes` method - --> tests/ui/endian_bytes.rs:48:9 + --> tests/ui/endian_bytes.rs:86:9 | LL | 2.0f32.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -471,7 +471,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `f64::to_le_bytes` method - --> tests/ui/endian_bytes.rs:49:9 + --> tests/ui/endian_bytes.rs:88:9 | LL | 2.0f64.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -483,7 +483,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `usize::to_le_bytes` method - --> tests/ui/endian_bytes.rs:50:9 + --> tests/ui/endian_bytes.rs:90:9 | LL | 2usize.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -495,7 +495,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `isize::to_le_bytes` method - --> tests/ui/endian_bytes.rs:51:9 + --> tests/ui/endian_bytes.rs:92:9 | LL | 2isize.to_le_bytes(); | ^^^^^^^^^^^^^^^^^^^^ @@ -507,7 +507,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:52:9 + --> tests/ui/endian_bytes.rs:94:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -519,7 +519,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i8::from_le_bytes` - --> tests/ui/endian_bytes.rs:53:9 + --> tests/ui/endian_bytes.rs:96:9 | LL | i8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -531,7 +531,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u16::from_le_bytes` - --> tests/ui/endian_bytes.rs:54:9 + --> tests/ui/endian_bytes.rs:98:9 | LL | u16::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -543,7 +543,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i16::from_le_bytes` - --> tests/ui/endian_bytes.rs:55:9 + --> tests/ui/endian_bytes.rs:100:9 | LL | i16::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -555,7 +555,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u32::from_le_bytes` - --> tests/ui/endian_bytes.rs:56:9 + --> tests/ui/endian_bytes.rs:102:9 | LL | u32::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -567,7 +567,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i32::from_le_bytes` - --> tests/ui/endian_bytes.rs:57:9 + --> tests/ui/endian_bytes.rs:104:9 | LL | i32::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -579,7 +579,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u64::from_le_bytes` - --> tests/ui/endian_bytes.rs:58:9 + --> tests/ui/endian_bytes.rs:106:9 | LL | u64::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -591,7 +591,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i64::from_le_bytes` - --> tests/ui/endian_bytes.rs:59:9 + --> tests/ui/endian_bytes.rs:108:9 | LL | i64::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -603,7 +603,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u128::from_le_bytes` - --> tests/ui/endian_bytes.rs:60:9 + --> tests/ui/endian_bytes.rs:110:9 | LL | u128::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -615,7 +615,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `i128::from_le_bytes` - --> tests/ui/endian_bytes.rs:61:9 + --> tests/ui/endian_bytes.rs:112:9 | LL | i128::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -627,7 +627,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `usize::from_le_bytes` - --> tests/ui/endian_bytes.rs:62:9 + --> tests/ui/endian_bytes.rs:114:9 | LL | usize::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -639,7 +639,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `isize::from_le_bytes` - --> tests/ui/endian_bytes.rs:63:9 + --> tests/ui/endian_bytes.rs:116:9 | LL | isize::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -651,7 +651,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f32::from_le_bytes` - --> tests/ui/endian_bytes.rs:64:9 + --> tests/ui/endian_bytes.rs:118:9 | LL | f32::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -663,7 +663,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `f64::from_le_bytes` - --> tests/ui/endian_bytes.rs:65:9 + --> tests/ui/endian_bytes.rs:120:9 | LL | f64::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -675,7 +675,7 @@ LL | fn little() { fn_body!(); } = note: this error originates in the macro `fn_body` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:72:9 + --> tests/ui/endian_bytes.rs:128:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -687,7 +687,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:134:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -699,7 +699,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:78:9 + --> tests/ui/endian_bytes.rs:154:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -713,7 +713,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:79:9 + --> tests/ui/endian_bytes.rs:160:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -725,7 +725,7 @@ LL | fn host_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:72:9 + --> tests/ui/endian_bytes.rs:128:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -737,7 +737,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:134:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -749,7 +749,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:75:9 + --> tests/ui/endian_bytes.rs:141:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -761,7 +761,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:147:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -773,7 +773,7 @@ LL | fn host_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:72:9 + --> tests/ui/endian_bytes.rs:128:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -784,7 +784,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:134:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -795,7 +795,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:75:9 + --> tests/ui/endian_bytes.rs:141:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -806,7 +806,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:147:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -817,7 +817,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:78:9 + --> tests/ui/endian_bytes.rs:154:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -828,7 +828,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:79:9 + --> tests/ui/endian_bytes.rs:160:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -839,7 +839,7 @@ LL | fn no_help() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:75:9 + --> tests/ui/endian_bytes.rs:141:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -851,7 +851,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:147:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -863,7 +863,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:78:9 + --> tests/ui/endian_bytes.rs:154:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -875,7 +875,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:79:9 + --> tests/ui/endian_bytes.rs:160:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -887,7 +887,7 @@ LL | fn little_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:72:9 + --> tests/ui/endian_bytes.rs:128:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -899,7 +899,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:134:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -911,7 +911,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:75:9 + --> tests/ui/endian_bytes.rs:141:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -923,7 +923,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:147:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -935,7 +935,7 @@ LL | fn little_encourage_big() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_le_bytes` method - --> tests/ui/endian_bytes.rs:75:9 + --> tests/ui/endian_bytes.rs:141:9 | LL | 2u8.to_le_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -947,7 +947,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_le_bytes` - --> tests/ui/endian_bytes.rs:76:9 + --> tests/ui/endian_bytes.rs:147:9 | LL | u8::from_le_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -959,7 +959,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:78:9 + --> tests/ui/endian_bytes.rs:154:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -971,7 +971,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:79:9 + --> tests/ui/endian_bytes.rs:160:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -983,7 +983,7 @@ LL | fn big_encourage_host() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_ne_bytes` method - --> tests/ui/endian_bytes.rs:72:9 + --> tests/ui/endian_bytes.rs:128:9 | LL | 2u8.to_ne_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -995,7 +995,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_ne_bytes` - --> tests/ui/endian_bytes.rs:73:9 + --> tests/ui/endian_bytes.rs:134:9 | LL | u8::from_ne_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -1007,7 +1007,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the `u8::to_be_bytes` method - --> tests/ui/endian_bytes.rs:78:9 + --> tests/ui/endian_bytes.rs:154:9 | LL | 2u8.to_be_bytes(); | ^^^^^^^^^^^^^^^^^ @@ -1019,7 +1019,7 @@ LL | fn big_encourage_little() { fn_body_smol!(); } = note: this error originates in the macro `fn_body_smol` (in Nightly builds, run with -Z macro-backtrace for more info) error: usage of the function `u8::from_be_bytes` - --> tests/ui/endian_bytes.rs:79:9 + --> tests/ui/endian_bytes.rs:160:9 | LL | u8::from_be_bytes(todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed index abdfae2a3e133..69452a8d9a671 100644 --- a/src/tools/clippy/tests/ui/entry.fixed +++ b/src/tools/clippy/tests/ui/entry.fixed @@ -25,6 +25,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // semicolon on insert, use or_insert_with(..) m.entry(k).or_insert_with(|| { + //~^ map_entry if true { v } else { @@ -34,6 +35,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // semicolon on if, use or_insert_with(..) m.entry(k).or_insert_with(|| { + //~^ map_entry if true { v } else { @@ -43,6 +45,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // early return, use if let if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { + //~^ map_entry if true { e.insert(v); } else { @@ -53,12 +56,14 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // use or_insert_with(..) m.entry(k).or_insert_with(|| { + //~^ map_entry foo(); v }); // semicolon on insert and match, use or_insert_with(..) m.entry(k).or_insert_with(|| { + //~^ map_entry match 0 { 1 if true => { v @@ -71,6 +76,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // one branch doesn't insert, use if let if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { + //~^ map_entry match 0 { 0 => foo(), _ => { @@ -81,6 +87,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // use or_insert_with m.entry(k).or_insert_with(|| { + //~^ map_entry foo(); match 0 { 0 if false => { @@ -145,6 +152,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // or_insert_with. Partial move of a local declared in the closure is ok. m.entry(k).or_insert_with(|| { + //~^ map_entry let x = (String::new(), String::new()); let _ = x.0; v @@ -178,6 +186,7 @@ pub fn issue_11935() { fn issue12489(map: &mut HashMap) -> Option<()> { if let std::collections::hash_map::Entry::Vacant(e) = map.entry(1) { + //~^ map_entry let Some(1) = Some(2) else { return None; }; @@ -186,4 +195,35 @@ fn issue12489(map: &mut HashMap) -> Option<()> { Some(()) } +mod issue13934 { + use std::collections::HashMap; + + struct Member {} + + pub struct Foo { + members: HashMap, + } + + impl Foo { + pub fn should_also_not_cause_lint(&mut self, input: u8) { + if self.members.contains_key(&input) { + todo!(); + } else { + self.other(); + self.members.insert(input, Member {}); + } + } + + fn other(&self) {} + } +} + +fn issue11976() { + let mut hashmap = std::collections::HashMap::new(); + if !hashmap.contains_key(&0) { + let _ = || hashmap.get(&0); + hashmap.insert(0, 0); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs index 7774f99a2a226..3578324f01c58 100644 --- a/src/tools/clippy/tests/ui/entry.rs +++ b/src/tools/clippy/tests/ui/entry.rs @@ -22,11 +22,13 @@ fn foo() {} fn hash_map(m: &mut HashMap, m2: &mut HashMap, k: K, k2: K, v: V, v2: V) { // or_insert(v) if !m.contains_key(&k) { + //~^ map_entry m.insert(k, v); } // semicolon on insert, use or_insert_with(..) if !m.contains_key(&k) { + //~^ map_entry if true { m.insert(k, v); } else { @@ -36,6 +38,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // semicolon on if, use or_insert_with(..) if !m.contains_key(&k) { + //~^ map_entry if true { m.insert(k, v) } else { @@ -45,6 +48,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // early return, use if let if !m.contains_key(&k) { + //~^ map_entry if true { m.insert(k, v); } else { @@ -55,12 +59,14 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // use or_insert_with(..) if !m.contains_key(&k) { + //~^ map_entry foo(); m.insert(k, v); } // semicolon on insert and match, use or_insert_with(..) if !m.contains_key(&k) { + //~^ map_entry match 0 { 1 if true => { m.insert(k, v); @@ -73,6 +79,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // one branch doesn't insert, use if let if !m.contains_key(&k) { + //~^ map_entry match 0 { 0 => foo(), _ => { @@ -83,6 +90,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // use or_insert_with if !m.contains_key(&k) { + //~^ map_entry foo(); match 0 { 0 if false => { @@ -117,6 +125,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // macro_expansion test, use or_insert(..) if !m.contains_key(&m!(k)) { + //~^ map_entry m.insert(m!(k), m!(v)); } @@ -149,6 +158,7 @@ fn hash_map(m: &mut HashMap, m2: &mut HashMa // or_insert_with. Partial move of a local declared in the closure is ok. if !m.contains_key(&k) { + //~^ map_entry let x = (String::new(), String::new()); let _ = x.0; m.insert(k, v); @@ -182,6 +192,7 @@ pub fn issue_11935() { fn issue12489(map: &mut HashMap) -> Option<()> { if !map.contains_key(&1) { + //~^ map_entry let Some(1) = Some(2) else { return None; }; @@ -190,4 +201,35 @@ fn issue12489(map: &mut HashMap) -> Option<()> { Some(()) } +mod issue13934 { + use std::collections::HashMap; + + struct Member {} + + pub struct Foo { + members: HashMap, + } + + impl Foo { + pub fn should_also_not_cause_lint(&mut self, input: u8) { + if self.members.contains_key(&input) { + todo!(); + } else { + self.other(); + self.members.insert(input, Member {}); + } + } + + fn other(&self) {} + } +} + +fn issue11976() { + let mut hashmap = std::collections::HashMap::new(); + if !hashmap.contains_key(&0) { + let _ = || hashmap.get(&0); + hashmap.insert(0, 0); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/entry.stderr b/src/tools/clippy/tests/ui/entry.stderr index 4b6bd3b4a2587..009b78d290730 100644 --- a/src/tools/clippy/tests/ui/entry.stderr +++ b/src/tools/clippy/tests/ui/entry.stderr @@ -2,6 +2,7 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` --> tests/ui/entry.rs:24:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | m.insert(k, v); LL | | } | |_____^ help: try: `m.entry(k).or_insert(v);` @@ -10,12 +11,12 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::map_entry)]` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:29:5 + --> tests/ui/entry.rs:30:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | if true { LL | | m.insert(k, v); -LL | | } else { ... | LL | | } | |_____^ @@ -23,6 +24,7 @@ LL | | } help: try | LL ~ m.entry(k).or_insert_with(|| { +LL + LL + if true { LL + v LL + } else { @@ -32,13 +34,13 @@ LL + }); | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:38:5 + --> tests/ui/entry.rs:40:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | if true { LL | | m.insert(k, v) -LL | | } else { -LL | | m.insert(k, v2) +... | LL | | }; LL | | } | |_____^ @@ -46,6 +48,7 @@ LL | | } help: try | LL ~ m.entry(k).or_insert_with(|| { +LL + LL + if true { LL + v LL + } else { @@ -55,12 +58,12 @@ LL + }); | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:47:5 + --> tests/ui/entry.rs:50:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | if true { LL | | m.insert(k, v); -LL | | } else { ... | LL | | } | |_____^ @@ -68,6 +71,7 @@ LL | | } help: try | LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { +LL + LL + if true { LL + e.insert(v); LL + } else { @@ -78,9 +82,10 @@ LL + } | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:57:5 + --> tests/ui/entry.rs:61:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | foo(); LL | | m.insert(k, v); LL | | } @@ -89,18 +94,19 @@ LL | | } help: try | LL ~ m.entry(k).or_insert_with(|| { +LL + LL + foo(); LL + v LL + }); | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:63:5 + --> tests/ui/entry.rs:68:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | match 0 { LL | | 1 if true => { -LL | | m.insert(k, v); ... | LL | | }; LL | | } @@ -109,6 +115,7 @@ LL | | } help: try | LL ~ m.entry(k).or_insert_with(|| { +LL + LL + match 0 { LL + 1 if true => { LL + v @@ -121,12 +128,12 @@ LL + }); | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:75:5 + --> tests/ui/entry.rs:81:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | match 0 { LL | | 0 => foo(), -LL | | _ => { ... | LL | | }; LL | | } @@ -135,6 +142,7 @@ LL | | } help: try | LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { +LL + LL + match 0 { LL + 0 => foo(), LL + _ => { @@ -145,12 +153,12 @@ LL + } | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:85:5 + --> tests/ui/entry.rs:92:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | foo(); LL | | match 0 { -LL | | 0 if false => { ... | LL | | } | |_____^ @@ -158,6 +166,7 @@ LL | | } help: try | LL ~ m.entry(k).or_insert_with(|| { +LL + LL + foo(); LL + match 0 { LL + 0 if false => { @@ -185,17 +194,19 @@ LL + }); | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:119:5 + --> tests/ui/entry.rs:127:5 | LL | / if !m.contains_key(&m!(k)) { +LL | | LL | | m.insert(m!(k), m!(v)); LL | | } | |_____^ help: try: `m.entry(m!(k)).or_insert_with(|| m!(v));` error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:151:5 + --> tests/ui/entry.rs:160:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | let x = (String::new(), String::new()); LL | | let _ = x.0; LL | | m.insert(k, v); @@ -205,6 +216,7 @@ LL | | } help: try | LL ~ m.entry(k).or_insert_with(|| { +LL + LL + let x = (String::new(), String::new()); LL + let _ = x.0; LL + v @@ -212,9 +224,10 @@ LL + }); | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry.rs:184:5 + --> tests/ui/entry.rs:194:5 | LL | / if !map.contains_key(&1) { +LL | | LL | | let Some(1) = Some(2) else { LL | | return None; LL | | }; @@ -225,6 +238,7 @@ LL | | } help: try | LL ~ if let std::collections::hash_map::Entry::Vacant(e) = map.entry(1) { +LL + LL + let Some(1) = Some(2) else { LL + return None; LL + }; diff --git a/src/tools/clippy/tests/ui/entry_btree.fixed b/src/tools/clippy/tests/ui/entry_btree.fixed index 228212c79eaf8..1218202f02b95 100644 --- a/src/tools/clippy/tests/ui/entry_btree.fixed +++ b/src/tools/clippy/tests/ui/entry_btree.fixed @@ -8,6 +8,7 @@ fn foo() {} fn btree_map(m: &mut BTreeMap, k: K, v: V) { // insert then do something, use if let if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { + //~^ map_entry e.insert(v); foo(); } diff --git a/src/tools/clippy/tests/ui/entry_btree.rs b/src/tools/clippy/tests/ui/entry_btree.rs index 44703c5671135..b795e32158ad6 100644 --- a/src/tools/clippy/tests/ui/entry_btree.rs +++ b/src/tools/clippy/tests/ui/entry_btree.rs @@ -8,6 +8,7 @@ fn foo() {} fn btree_map(m: &mut BTreeMap, k: K, v: V) { // insert then do something, use if let if !m.contains_key(&k) { + //~^ map_entry m.insert(k, v); foo(); } diff --git a/src/tools/clippy/tests/ui/entry_btree.stderr b/src/tools/clippy/tests/ui/entry_btree.stderr index 290e6b7880541..671340b895323 100644 --- a/src/tools/clippy/tests/ui/entry_btree.stderr +++ b/src/tools/clippy/tests/ui/entry_btree.stderr @@ -2,6 +2,7 @@ error: usage of `contains_key` followed by `insert` on a `BTreeMap` --> tests/ui/entry_btree.rs:10:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | m.insert(k, v); LL | | foo(); LL | | } @@ -12,6 +13,7 @@ LL | | } help: try | LL ~ if let std::collections::btree_map::Entry::Vacant(e) = m.entry(k) { +LL + LL + e.insert(v); LL + foo(); LL + } diff --git a/src/tools/clippy/tests/ui/entry_with_else.fixed b/src/tools/clippy/tests/ui/entry_with_else.fixed index 34804b9ee5d77..76e6998235c24 100644 --- a/src/tools/clippy/tests/ui/entry_with_else.fixed +++ b/src/tools/clippy/tests/ui/entry_with_else.fixed @@ -13,6 +13,7 @@ fn foo() {} fn insert_if_absent0(m: &mut HashMap, k: K, v: V, v2: V) { match m.entry(k) { std::collections::hash_map::Entry::Vacant(e) => { + //~^ map_entry e.insert(v); } std::collections::hash_map::Entry::Occupied(mut e) => { @@ -22,6 +23,7 @@ fn insert_if_absent0(m: &mut HashMap, k: K, match m.entry(k) { std::collections::hash_map::Entry::Occupied(mut e) => { + //~^ map_entry e.insert(v); } std::collections::hash_map::Entry::Vacant(e) => { @@ -30,6 +32,7 @@ fn insert_if_absent0(m: &mut HashMap, k: K, } if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { + //~^ map_entry e.insert(v); } else { foo(); @@ -38,11 +41,13 @@ fn insert_if_absent0(m: &mut HashMap, k: K, if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) { e.insert(v); } else { + //~^ map_entry foo(); } match m.entry(k) { std::collections::hash_map::Entry::Vacant(e) => { + //~^ map_entry e.insert(v); } std::collections::hash_map::Entry::Occupied(mut e) => { @@ -52,6 +57,7 @@ fn insert_if_absent0(m: &mut HashMap, k: K, match m.entry(k) { std::collections::hash_map::Entry::Occupied(mut e) => { + //~^ map_entry if true { Some(e.insert(v)) } else { Some(e.insert(v2)) } } std::collections::hash_map::Entry::Vacant(e) => { @@ -61,6 +67,7 @@ fn insert_if_absent0(m: &mut HashMap, k: K, }; if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) { + //~^ map_entry foo(); Some(e.insert(v)) } else { diff --git a/src/tools/clippy/tests/ui/entry_with_else.rs b/src/tools/clippy/tests/ui/entry_with_else.rs index 0515748fd7336..1669cdc0c7cf7 100644 --- a/src/tools/clippy/tests/ui/entry_with_else.rs +++ b/src/tools/clippy/tests/ui/entry_with_else.rs @@ -12,42 +12,49 @@ fn foo() {} fn insert_if_absent0(m: &mut HashMap, k: K, v: V, v2: V) { if !m.contains_key(&k) { + //~^ map_entry m.insert(k, v); } else { m.insert(k, v2); } if m.contains_key(&k) { + //~^ map_entry m.insert(k, v); } else { m.insert(k, v2); } if !m.contains_key(&k) { + //~^ map_entry m.insert(k, v); } else { foo(); } if !m.contains_key(&k) { + //~^ map_entry foo(); } else { m.insert(k, v); } if !m.contains_key(&k) { + //~^ map_entry m.insert(k, v); } else { m.insert(k, v2); } if m.contains_key(&k) { + //~^ map_entry if true { m.insert(k, v) } else { m.insert(k, v2) } } else { m.insert(k, v) }; if m.contains_key(&k) { + //~^ map_entry foo(); m.insert(k, v) } else { diff --git a/src/tools/clippy/tests/ui/entry_with_else.stderr b/src/tools/clippy/tests/ui/entry_with_else.stderr index 26b21b076b6c0..d483ac95ad5b6 100644 --- a/src/tools/clippy/tests/ui/entry_with_else.stderr +++ b/src/tools/clippy/tests/ui/entry_with_else.stderr @@ -2,6 +2,7 @@ error: usage of `contains_key` followed by `insert` on a `HashMap` --> tests/ui/entry_with_else.rs:14:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | m.insert(k, v); LL | | } else { LL | | m.insert(k, v2); @@ -14,6 +15,7 @@ help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Vacant(e) => { +LL + LL + e.insert(v); LL + } LL + std::collections::hash_map::Entry::Occupied(mut e) => { @@ -23,9 +25,10 @@ LL + } | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_with_else.rs:20:5 + --> tests/ui/entry_with_else.rs:21:5 | LL | / if m.contains_key(&k) { +LL | | LL | | m.insert(k, v); LL | | } else { LL | | m.insert(k, v2); @@ -36,6 +39,7 @@ help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Occupied(mut e) => { +LL + LL + e.insert(v); LL + } LL + std::collections::hash_map::Entry::Vacant(e) => { @@ -45,9 +49,10 @@ LL + } | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_with_else.rs:26:5 + --> tests/ui/entry_with_else.rs:28:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | m.insert(k, v); LL | | } else { LL | | foo(); @@ -57,6 +62,7 @@ LL | | } help: try | LL ~ if let std::collections::hash_map::Entry::Vacant(e) = m.entry(k) { +LL + LL + e.insert(v); LL + } else { LL + foo(); @@ -64,9 +70,10 @@ LL + } | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_with_else.rs:32:5 + --> tests/ui/entry_with_else.rs:35:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | foo(); LL | | } else { LL | | m.insert(k, v); @@ -78,14 +85,16 @@ help: try LL ~ if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) { LL + e.insert(v); LL + } else { +LL + LL + foo(); LL + } | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_with_else.rs:38:5 + --> tests/ui/entry_with_else.rs:42:5 | LL | / if !m.contains_key(&k) { +LL | | LL | | m.insert(k, v); LL | | } else { LL | | m.insert(k, v2); @@ -96,6 +105,7 @@ help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Vacant(e) => { +LL + LL + e.insert(v); LL + } LL + std::collections::hash_map::Entry::Occupied(mut e) => { @@ -105,9 +115,10 @@ LL + } | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_with_else.rs:44:5 + --> tests/ui/entry_with_else.rs:49:5 | LL | / if m.contains_key(&k) { +LL | | LL | | if true { m.insert(k, v) } else { m.insert(k, v2) } LL | | } else { LL | | m.insert(k, v) @@ -118,6 +129,7 @@ help: try | LL ~ match m.entry(k) { LL + std::collections::hash_map::Entry::Occupied(mut e) => { +LL + LL + if true { Some(e.insert(v)) } else { Some(e.insert(v2)) } LL + } LL + std::collections::hash_map::Entry::Vacant(e) => { @@ -128,9 +140,10 @@ LL ~ }; | error: usage of `contains_key` followed by `insert` on a `HashMap` - --> tests/ui/entry_with_else.rs:50:5 + --> tests/ui/entry_with_else.rs:56:5 | LL | / if m.contains_key(&k) { +LL | | LL | | foo(); LL | | m.insert(k, v) LL | | } else { @@ -141,6 +154,7 @@ LL | | }; help: try | LL ~ if let std::collections::hash_map::Entry::Occupied(mut e) = m.entry(k) { +LL + LL + foo(); LL + Some(e.insert(v)) LL + } else { diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs index 37849179d6a0b..4ff2024b25e95 100644 --- a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs +++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs @@ -6,8 +6,7 @@ #[repr(usize)] enum NonPortable { X = 0x1_0000_0000, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets - //~| NOTE: `-D clippy::enum-clike-unportable-variant` implied by `-D warnings` + //~^ enum_clike_unportable_variant Y = 0, Z = 0x7FFF_FFFF, A = 0xFFFF_FFFF, @@ -15,11 +14,11 @@ enum NonPortable { enum NonPortableNoHint { X = 0x1_0000_0000, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant Y = 0, Z = 0x7FFF_FFFF, A = 0xFFFF_FFFF, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant } #[repr(isize)] @@ -27,27 +26,27 @@ enum NonPortableSigned { X = -1, Y = 0x7FFF_FFFF, Z = 0xFFFF_FFFF, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant A = 0x1_0000_0000, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant B = i32::MIN as isize, C = (i32::MIN as isize) - 1, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant } enum NonPortableSignedNoHint { X = -1, Y = 0x7FFF_FFFF, Z = 0xFFFF_FFFF, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant A = 0x1_0000_0000, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant } #[repr(usize)] enum NonPortable2 { X = ::Number, - //~^ ERROR: C-like enum variant discriminant is not portable to 32-bit targets + //~^ enum_clike_unportable_variant Y = 0, } diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr index 741de179a497a..5a022a6fe8a61 100644 --- a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr +++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.stderr @@ -8,49 +8,49 @@ LL | X = 0x1_0000_0000, = help: to override `-D warnings` add `#[allow(clippy::enum_clike_unportable_variant)]` error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:17:5 + --> tests/ui/enum_clike_unportable_variant.rs:16:5 | LL | X = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:21:5 + --> tests/ui/enum_clike_unportable_variant.rs:20:5 | LL | A = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:29:5 + --> tests/ui/enum_clike_unportable_variant.rs:28:5 | LL | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:31:5 + --> tests/ui/enum_clike_unportable_variant.rs:30:5 | LL | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:34:5 + --> tests/ui/enum_clike_unportable_variant.rs:33:5 | LL | C = (i32::MIN as isize) - 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:41:5 + --> tests/ui/enum_clike_unportable_variant.rs:40:5 | LL | Z = 0xFFFF_FFFF, | ^^^^^^^^^^^^^^^ error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:43:5 + --> tests/ui/enum_clike_unportable_variant.rs:42:5 | LL | A = 0x1_0000_0000, | ^^^^^^^^^^^^^^^^^ error: C-like enum variant discriminant is not portable to 32-bit targets - --> tests/ui/enum_clike_unportable_variant.rs:49:5 + --> tests/ui/enum_clike_unportable_variant.rs:48:5 | LL | X = ::Number, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/enum_glob_use.fixed b/src/tools/clippy/tests/ui/enum_glob_use.fixed index 3c0db9beb1a6e..881493f3d5ff0 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.fixed +++ b/src/tools/clippy/tests/ui/enum_glob_use.fixed @@ -3,16 +3,19 @@ #![warn(unused_imports)] use std::cmp::Ordering::Less; +//~^ enum_glob_use enum Enum { Foo, } use self::Enum::Foo; +//~^ enum_glob_use mod in_fn_test { fn blarg() { use crate::Enum::Foo; + //~^ enum_glob_use let _ = Foo; } diff --git a/src/tools/clippy/tests/ui/enum_glob_use.rs b/src/tools/clippy/tests/ui/enum_glob_use.rs index 2538477f79789..a510462ecb2f5 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.rs +++ b/src/tools/clippy/tests/ui/enum_glob_use.rs @@ -3,16 +3,19 @@ #![warn(unused_imports)] use std::cmp::Ordering::*; +//~^ enum_glob_use enum Enum { Foo, } use self::Enum::*; +//~^ enum_glob_use mod in_fn_test { fn blarg() { use crate::Enum::*; + //~^ enum_glob_use let _ = Foo; } diff --git a/src/tools/clippy/tests/ui/enum_glob_use.stderr b/src/tools/clippy/tests/ui/enum_glob_use.stderr index 6825383b769d7..a2cef8008e210 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.stderr +++ b/src/tools/clippy/tests/ui/enum_glob_use.stderr @@ -8,13 +8,13 @@ LL | use std::cmp::Ordering::*; = help: to override `-D warnings` add `#[allow(clippy::enum_glob_use)]` error: usage of wildcard import for enum variants - --> tests/ui/enum_glob_use.rs:11:5 + --> tests/ui/enum_glob_use.rs:12:5 | LL | use self::Enum::*; | ^^^^^^^^^^^^^ help: try: `self::Enum::Foo` error: usage of wildcard import for enum variants - --> tests/ui/enum_glob_use.rs:15:13 + --> tests/ui/enum_glob_use.rs:17:13 | LL | use crate::Enum::*; | ^^^^^^^^^^^^^^ help: try: `crate::Enum::Foo` diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index ddf2dfdaea9b4..f7bbf83654f11 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -12,10 +12,9 @@ enum FakeCallType2 { } enum Foo { - //~^ ERROR: all variants have the same prefix: `c` + //~^ enum_variant_names cFoo, - //~^ ERROR: variant name ends with the enum's name - //~| NOTE: `-D clippy::enum-variant-names` implied by `-D warnings` + //~^ enum_variant_names cBar, cBaz, } @@ -26,13 +25,13 @@ enum Fooo { } enum Food { - //~^ ERROR: all variants have the same prefix: `Food` + //~^ enum_variant_names FoodGood, - //~^ ERROR: variant name starts with the enum's name + //~^ enum_variant_names FoodMiddle, - //~^ ERROR: variant name starts with the enum's name + //~^ enum_variant_names FoodBad, - //~^ ERROR: variant name starts with the enum's name + //~^ enum_variant_names } enum Stuff { @@ -40,7 +39,7 @@ enum Stuff { } enum BadCallType { - //~^ ERROR: all variants have the same prefix: `CallType` + //~^ enum_variant_names CallTypeCall, CallTypeCreate, CallTypeDestroy, @@ -53,7 +52,7 @@ enum TwoCallType { } enum Consts { - //~^ ERROR: all variants have the same prefix: `Constant` + //~^ enum_variant_names ConstantInt, ConstantCake, ConstantLie, @@ -66,7 +65,7 @@ enum Two { } enum Something { - //~^ ERROR: all variants have the same prefix: `C` + //~^ enum_variant_names CCall, CCreate, CCryogenize, @@ -89,7 +88,7 @@ enum Sealll { } enum Seallll { - //~^ ERROR: all variants have the same prefix: `WithOut` + //~^ enum_variant_names WithOutCake, WithOutTea, WithOut, @@ -145,14 +144,14 @@ pub enum NetworkLayer { // should lint suggesting `IData`, not only `Data` (see #4639) enum IDataRequest { - //~^ ERROR: all variants have the same postfix: `IData` + //~^ enum_variant_names PutIData(String), GetIData(String), DeleteUnpubIData(String), } enum HIDataRequest { - //~^ ERROR: all variants have the same postfix: `HIData` + //~^ enum_variant_names PutHIData(String), GetHIData(String), DeleteUnpubHIData(String), @@ -173,7 +172,7 @@ enum Phase { mod issue9018 { enum DoLint { - //~^ ERROR: all variants have the same prefix: `_Type` + //~^ enum_variant_names _TypeCreate, _TypeRead, _TypeUpdate, @@ -181,7 +180,7 @@ mod issue9018 { } enum DoLintToo { - //~^ ERROR: all variants have the same postfix: `Type` + //~^ enum_variant_names _CreateType, _UpdateType, _DeleteType, @@ -210,12 +209,12 @@ mod issue11494 { Valid, Invalid, DataDependent, - //~^ ERROR: variant name starts with the enum's name + //~^ enum_variant_names } enum Datas { DatasDependent, - //~^ ERROR: variant name starts with the enum's name + //~^ enum_variant_names Valid, Invalid, } diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index ecca6c833ac55..cca9d50033cfe 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -21,25 +21,25 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: variant name starts with the enum's name - --> tests/ui/enum_variants.rs:30:5 + --> tests/ui/enum_variants.rs:29:5 | LL | FoodGood, | ^^^^^^^^ error: variant name starts with the enum's name - --> tests/ui/enum_variants.rs:32:5 + --> tests/ui/enum_variants.rs:31:5 | LL | FoodMiddle, | ^^^^^^^^^^ error: variant name starts with the enum's name - --> tests/ui/enum_variants.rs:34:5 + --> tests/ui/enum_variants.rs:33:5 | LL | FoodBad, | ^^^^^^^ error: all variants have the same prefix: `Food` - --> tests/ui/enum_variants.rs:28:1 + --> tests/ui/enum_variants.rs:27:1 | LL | / enum Food { LL | | @@ -51,7 +51,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `CallType` - --> tests/ui/enum_variants.rs:42:1 + --> tests/ui/enum_variants.rs:41:1 | LL | / enum BadCallType { LL | | @@ -64,7 +64,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `Constant` - --> tests/ui/enum_variants.rs:55:1 + --> tests/ui/enum_variants.rs:54:1 | LL | / enum Consts { LL | | @@ -77,7 +77,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `C` - --> tests/ui/enum_variants.rs:68:1 + --> tests/ui/enum_variants.rs:67:1 | LL | / enum Something { LL | | @@ -90,7 +90,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `WithOut` - --> tests/ui/enum_variants.rs:91:1 + --> tests/ui/enum_variants.rs:90:1 | LL | / enum Seallll { LL | | @@ -103,7 +103,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same postfix: `IData` - --> tests/ui/enum_variants.rs:147:1 + --> tests/ui/enum_variants.rs:146:1 | LL | / enum IDataRequest { LL | | @@ -116,7 +116,7 @@ LL | | } = help: remove the postfixes and use full paths to the variants instead of glob imports error: all variants have the same postfix: `HIData` - --> tests/ui/enum_variants.rs:154:1 + --> tests/ui/enum_variants.rs:153:1 | LL | / enum HIDataRequest { LL | | @@ -129,7 +129,7 @@ LL | | } = help: remove the postfixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `_Type` - --> tests/ui/enum_variants.rs:175:5 + --> tests/ui/enum_variants.rs:174:5 | LL | / enum DoLint { LL | | @@ -143,7 +143,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same postfix: `Type` - --> tests/ui/enum_variants.rs:183:5 + --> tests/ui/enum_variants.rs:182:5 | LL | / enum DoLintToo { LL | | @@ -156,13 +156,13 @@ LL | | } = help: remove the postfixes and use full paths to the variants instead of glob imports error: variant name starts with the enum's name - --> tests/ui/enum_variants.rs:212:9 + --> tests/ui/enum_variants.rs:211:9 | LL | DataDependent, | ^^^^^^^^^^^^^ error: variant name starts with the enum's name - --> tests/ui/enum_variants.rs:217:9 + --> tests/ui/enum_variants.rs:216:9 | LL | DatasDependent, | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/eprint_with_newline.fixed b/src/tools/clippy/tests/ui/eprint_with_newline.fixed index 7383d784c8410..c50a707ace92e 100644 --- a/src/tools/clippy/tests/ui/eprint_with_newline.fixed +++ b/src/tools/clippy/tests/ui/eprint_with_newline.fixed @@ -3,16 +3,19 @@ fn main() { eprintln!("Hello"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline - //~| NOTE: `-D clippy::print-with-newline` implied by `-D warnings` + //~^ print_with_newline + eprintln!("Hello {}", "world"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprintln!("Hello {} {}", "world", "#2"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprintln!("{}", 1265); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprintln!(); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline // these are all fine eprint!(""); @@ -35,7 +38,8 @@ fn main() { // #3514 eprint!("\\n"); eprintln!("\\"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprint!("\\\\n"); // Raw strings @@ -44,11 +48,11 @@ fn main() { // Literal newlines should also fail eprintln!( - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline ); eprintln!( - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline ); @@ -56,7 +60,8 @@ fn main() { eprint!("\r\n"); eprint!("foo\r\n"); eprintln!("\\r"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprint!("foo\rbar\n"); // Ignore expanded format strings diff --git a/src/tools/clippy/tests/ui/eprint_with_newline.rs b/src/tools/clippy/tests/ui/eprint_with_newline.rs index 5b114056411d9..2c90480bdc781 100644 --- a/src/tools/clippy/tests/ui/eprint_with_newline.rs +++ b/src/tools/clippy/tests/ui/eprint_with_newline.rs @@ -3,16 +3,19 @@ fn main() { eprint!("Hello\n"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline - //~| NOTE: `-D clippy::print-with-newline` implied by `-D warnings` + //~^ print_with_newline + eprint!("Hello {}\n", "world"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprint!("Hello {} {}\n", "world", "#2"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprint!("{}\n", 1265); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprint!("\n"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline // these are all fine eprint!(""); @@ -35,7 +38,8 @@ fn main() { // #3514 eprint!("\\n"); eprint!("\\\n"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprint!("\\\\n"); // Raw strings @@ -44,12 +48,12 @@ fn main() { // Literal newlines should also fail eprint!( - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline " " ); eprint!( - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline r" " ); @@ -58,7 +62,8 @@ fn main() { eprint!("\r\n"); eprint!("foo\r\n"); eprint!("\\r\n"); - //~^ ERROR: using `eprint!()` with a format string that ends in a single newline + //~^ print_with_newline + eprint!("foo\rbar\n"); // Ignore expanded format strings diff --git a/src/tools/clippy/tests/ui/eprint_with_newline.stderr b/src/tools/clippy/tests/ui/eprint_with_newline.stderr index de450090a66e5..c78cffd40c99e 100644 --- a/src/tools/clippy/tests/ui/eprint_with_newline.stderr +++ b/src/tools/clippy/tests/ui/eprint_with_newline.stderr @@ -25,7 +25,7 @@ LL + eprintln!("Hello {}", "world"); | error: using `eprint!()` with a format string that ends in a single newline - --> tests/ui/eprint_with_newline.rs:10:5 + --> tests/ui/eprint_with_newline.rs:11:5 | LL | eprint!("Hello {} {}\n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + eprintln!("Hello {} {}", "world", "#2"); | error: using `eprint!()` with a format string that ends in a single newline - --> tests/ui/eprint_with_newline.rs:12:5 + --> tests/ui/eprint_with_newline.rs:14:5 | LL | eprint!("{}\n", 1265); | ^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + eprintln!("{}", 1265); | error: using `eprint!()` with a format string that ends in a single newline - --> tests/ui/eprint_with_newline.rs:14:5 + --> tests/ui/eprint_with_newline.rs:17:5 | LL | eprint!("\n"); | ^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + eprintln!(); | error: using `eprint!()` with a format string that ends in a single newline - --> tests/ui/eprint_with_newline.rs:37:5 + --> tests/ui/eprint_with_newline.rs:40:5 | LL | eprint!("\\\n"); | ^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + eprintln!("\\"); | error: using `eprint!()` with a format string that ends in a single newline - --> tests/ui/eprint_with_newline.rs:46:5 + --> tests/ui/eprint_with_newline.rs:50:5 | LL | / eprint!( LL | | @@ -90,7 +90,7 @@ LL ~ | error: using `eprint!()` with a format string that ends in a single newline - --> tests/ui/eprint_with_newline.rs:51:5 + --> tests/ui/eprint_with_newline.rs:55:5 | LL | / eprint!( LL | | @@ -107,7 +107,7 @@ LL ~ | error: using `eprint!()` with a format string that ends in a single newline - --> tests/ui/eprint_with_newline.rs:60:5 + --> tests/ui/eprint_with_newline.rs:64:5 | LL | eprint!("\\r\n"); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/eq_op.rs b/src/tools/clippy/tests/ui/eq_op.rs index 7c2c131875182..ced0452ee9a80 100644 --- a/src/tools/clippy/tests/ui/eq_op.rs +++ b/src/tools/clippy/tests/ui/eq_op.rs @@ -5,80 +5,96 @@ fn main() { // simple values and comparisons let _ = 1 == 1; - //~^ ERROR: equal expressions as operands to `==` - //~| NOTE: `-D clippy::eq-op` implied by `-D warnings` + //~^ eq_op + let _ = "no" == "no"; - //~^ ERROR: equal expressions as operands to `==` + //~^ eq_op + // even though I agree that no means no ;-) let _ = false != false; - //~^ ERROR: equal expressions as operands to `!=` + //~^ eq_op + let _ = 1.5 < 1.5; - //~^ ERROR: equal expressions as operands to `<` + //~^ eq_op + let _ = 1u64 >= 1u64; - //~^ ERROR: equal expressions as operands to `>=` + //~^ eq_op + let x = f32::NAN; let _ = x != x; - //~^ ERROR: equal expressions as operands to `!=` - //~| NOTE: if you intended to check if the operand is NaN, use `.is_nan()` instead + //~^ eq_op // casts, methods, parentheses let _ = (1u32 as u64) & (1u32 as u64); - //~^ ERROR: equal expressions as operands to `&` + //~^ eq_op + #[rustfmt::skip] { let _ = 1 ^ ((((((1)))))); - //~^ ERROR: equal expressions as operands to `^` + //~^ eq_op + }; // unary and binary operators let _ = (-(2) < -(2)); - //~^ ERROR: equal expressions as operands to `<` + //~^ eq_op + let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); - //~^ ERROR: equal expressions as operands to `==` - //~| ERROR: equal expressions as operands to `&` - //~| ERROR: equal expressions as operands to `&` + //~^ eq_op + //~| eq_op + //~| eq_op + let _ = (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; - //~^ ERROR: equal expressions as operands to `==` + //~^ eq_op // various other things let _ = ([1] != [1]); - //~^ ERROR: equal expressions as operands to `!=` + //~^ eq_op + let _ = ((1, 2) != (1, 2)); - //~^ ERROR: equal expressions as operands to `!=` + //~^ eq_op + let _ = vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros // const folding let _ = 1 + 1 == 2; - //~^ ERROR: equal expressions as operands to `==` + //~^ eq_op + let _ = 1 - 1 == 0; - //~^ ERROR: equal expressions as operands to `==` - //~| ERROR: equal expressions as operands to `-` + //~^ eq_op + //~| eq_op let _ = 1 - 1; - //~^ ERROR: equal expressions as operands to `-` + //~^ eq_op + let _ = 1 / 1; - //~^ ERROR: equal expressions as operands to `/` + //~^ eq_op + let _ = true && true; - //~^ ERROR: equal expressions as operands to `&&` + //~^ eq_op let _ = true || true; - //~^ ERROR: equal expressions as operands to `||` + //~^ eq_op let a: u32 = 0; let b: u32 = 0; let _ = a == b && b == a; - //~^ ERROR: equal expressions as operands to `&&` + //~^ eq_op + let _ = a != b && b != a; - //~^ ERROR: equal expressions as operands to `&&` + //~^ eq_op + let _ = a < b && b > a; - //~^ ERROR: equal expressions as operands to `&&` + //~^ eq_op + let _ = a <= b && b >= a; - //~^ ERROR: equal expressions as operands to `&&` + //~^ eq_op let mut a = vec![1]; let _ = a == a; - //~^ ERROR: equal expressions as operands to `==` + //~^ eq_op + let _ = 2 * a.len() == 2 * a.len(); // ok, functions let _ = a.pop() == a.pop(); // ok, functions @@ -89,7 +105,7 @@ fn main() { const B: u32 = 10; const C: u32 = A / B; // ok, different named constants const D: u32 = A / A; - //~^ ERROR: equal expressions as operands to `/` + //~^ eq_op } macro_rules! check_if_named_foo { @@ -121,7 +137,7 @@ struct Nested { fn check_nested(n1: &Nested, n2: &Nested) -> bool { // `n2.inner.0.0` mistyped as `n1.inner.0.0` (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 - //~^ ERROR: equal expressions as operands to `==` + //~^ eq_op } #[test] diff --git a/src/tools/clippy/tests/ui/eq_op.stderr b/src/tools/clippy/tests/ui/eq_op.stderr index bd3c115d8b8bc..1696f09d6d178 100644 --- a/src/tools/clippy/tests/ui/eq_op.stderr +++ b/src/tools/clippy/tests/ui/eq_op.stderr @@ -14,25 +14,25 @@ LL | let _ = "no" == "no"; | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/eq_op.rs:13:13 + --> tests/ui/eq_op.rs:14:13 | LL | let _ = false != false; | ^^^^^^^^^^^^^^ error: equal expressions as operands to `<` - --> tests/ui/eq_op.rs:15:13 + --> tests/ui/eq_op.rs:17:13 | LL | let _ = 1.5 < 1.5; | ^^^^^^^^^ error: equal expressions as operands to `>=` - --> tests/ui/eq_op.rs:17:13 + --> tests/ui/eq_op.rs:20:13 | LL | let _ = 1u64 >= 1u64; | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/eq_op.rs:20:13 + --> tests/ui/eq_op.rs:24:13 | LL | let _ = x != x; | ^^^^^^ @@ -40,139 +40,139 @@ LL | let _ = x != x; = note: if you intended to check if the operand is NaN, use `.is_nan()` instead error: equal expressions as operands to `&` - --> tests/ui/eq_op.rs:25:13 + --> tests/ui/eq_op.rs:28:13 | LL | let _ = (1u32 as u64) & (1u32 as u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `^` - --> tests/ui/eq_op.rs:29:17 + --> tests/ui/eq_op.rs:33:17 | LL | let _ = 1 ^ ((((((1)))))); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `<` - --> tests/ui/eq_op.rs:34:13 + --> tests/ui/eq_op.rs:39:13 | LL | let _ = (-(2) < -(2)); | ^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/eq_op.rs:36:13 + --> tests/ui/eq_op.rs:42:13 | LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> tests/ui/eq_op.rs:36:14 + --> tests/ui/eq_op.rs:42:14 | LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&` - --> tests/ui/eq_op.rs:36:35 + --> tests/ui/eq_op.rs:42:35 | LL | let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1)); | ^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/eq_op.rs:40:13 + --> tests/ui/eq_op.rs:47:13 | LL | let _ = (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/eq_op.rs:44:13 + --> tests/ui/eq_op.rs:51:13 | LL | let _ = ([1] != [1]); | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/eq_op.rs:46:13 + --> tests/ui/eq_op.rs:54:13 | LL | let _ = ((1, 2) != (1, 2)); | ^^^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/eq_op.rs:51:13 + --> tests/ui/eq_op.rs:60:13 | LL | let _ = 1 + 1 == 2; | ^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/eq_op.rs:53:13 + --> tests/ui/eq_op.rs:63:13 | LL | let _ = 1 - 1 == 0; | ^^^^^^^^^^ error: equal expressions as operands to `-` - --> tests/ui/eq_op.rs:53:13 + --> tests/ui/eq_op.rs:63:13 | LL | let _ = 1 - 1 == 0; | ^^^^^ error: equal expressions as operands to `-` - --> tests/ui/eq_op.rs:57:13 + --> tests/ui/eq_op.rs:67:13 | LL | let _ = 1 - 1; | ^^^^^ error: equal expressions as operands to `/` - --> tests/ui/eq_op.rs:59:13 + --> tests/ui/eq_op.rs:70:13 | LL | let _ = 1 / 1; | ^^^^^ error: equal expressions as operands to `&&` - --> tests/ui/eq_op.rs:61:13 + --> tests/ui/eq_op.rs:73:13 | LL | let _ = true && true; | ^^^^^^^^^^^^ error: equal expressions as operands to `||` - --> tests/ui/eq_op.rs:64:13 + --> tests/ui/eq_op.rs:76:13 | LL | let _ = true || true; | ^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> tests/ui/eq_op.rs:70:13 + --> tests/ui/eq_op.rs:82:13 | LL | let _ = a == b && b == a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> tests/ui/eq_op.rs:72:13 + --> tests/ui/eq_op.rs:85:13 | LL | let _ = a != b && b != a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> tests/ui/eq_op.rs:74:13 + --> tests/ui/eq_op.rs:88:13 | LL | let _ = a < b && b > a; | ^^^^^^^^^^^^^^ error: equal expressions as operands to `&&` - --> tests/ui/eq_op.rs:76:13 + --> tests/ui/eq_op.rs:91:13 | LL | let _ = a <= b && b >= a; | ^^^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/eq_op.rs:80:13 + --> tests/ui/eq_op.rs:95:13 | LL | let _ = a == a; | ^^^^^^ error: equal expressions as operands to `/` - --> tests/ui/eq_op.rs:91:20 + --> tests/ui/eq_op.rs:107:20 | LL | const D: u32 = A / A; | ^^^^^ error: equal expressions as operands to `==` - --> tests/ui/eq_op.rs:123:5 + --> tests/ui/eq_op.rs:139:5 | LL | (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/eq_op_macros.rs b/src/tools/clippy/tests/ui/eq_op_macros.rs index a511af4a31c8c..82242d0eb1967 100644 --- a/src/tools/clippy/tests/ui/eq_op_macros.rs +++ b/src/tools/clippy/tests/ui/eq_op_macros.rs @@ -6,9 +6,13 @@ macro_rules! assert_in_macro_def { () => { let a = 42; assert_eq!(a, a); + //~^ eq_op assert_ne!(a, a); + //~^ eq_op debug_assert_eq!(a, a); + //~^ eq_op debug_assert_ne!(a, a); + //~^ eq_op }; } @@ -21,9 +25,11 @@ fn main() { // lint identical args in `assert_eq!` assert_eq!(a, a); - //~^ ERROR: identical args used in this `assert_eq!` macro call + //~^ eq_op + assert_eq!(a + 1, a + 1); - //~^ ERROR: identical args used in this `assert_eq!` macro call + //~^ eq_op + // ok assert_eq!(a, b); assert_eq!(a, a + 1); @@ -31,9 +37,11 @@ fn main() { // lint identical args in `assert_ne!` assert_ne!(a, a); - //~^ ERROR: identical args used in this `assert_ne!` macro call + //~^ eq_op + assert_ne!(a + 1, a + 1); - //~^ ERROR: identical args used in this `assert_ne!` macro call + //~^ eq_op + // ok assert_ne!(a, b); assert_ne!(a, a + 1); @@ -41,9 +49,11 @@ fn main() { // lint identical args in `debug_assert_eq!` debug_assert_eq!(a, a); - //~^ ERROR: identical args used in this `debug_assert_eq!` macro call + //~^ eq_op + debug_assert_eq!(a + 1, a + 1); - //~^ ERROR: identical args used in this `debug_assert_eq!` macro call + //~^ eq_op + // ok debug_assert_eq!(a, b); debug_assert_eq!(a, a + 1); @@ -51,9 +61,11 @@ fn main() { // lint identical args in `debug_assert_ne!` debug_assert_ne!(a, a); - //~^ ERROR: identical args used in this `debug_assert_ne!` macro call + //~^ eq_op + debug_assert_ne!(a + 1, a + 1); - //~^ ERROR: identical args used in this `debug_assert_ne!` macro call + //~^ eq_op + // ok debug_assert_ne!(a, b); debug_assert_ne!(a, a + 1); diff --git a/src/tools/clippy/tests/ui/eq_op_macros.stderr b/src/tools/clippy/tests/ui/eq_op_macros.stderr index b114db0ca98e1..72315e87bfeff 100644 --- a/src/tools/clippy/tests/ui/eq_op_macros.stderr +++ b/src/tools/clippy/tests/ui/eq_op_macros.stderr @@ -12,7 +12,7 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `assert_ne!` macro call - --> tests/ui/eq_op_macros.rs:9:20 + --> tests/ui/eq_op_macros.rs:10:20 | LL | assert_ne!(a, a); | ^^^^ @@ -23,7 +23,7 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `debug_assert_eq!` macro call - --> tests/ui/eq_op_macros.rs:10:26 + --> tests/ui/eq_op_macros.rs:12:26 | LL | debug_assert_eq!(a, a); | ^^^^ @@ -34,7 +34,7 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `debug_assert_ne!` macro call - --> tests/ui/eq_op_macros.rs:11:26 + --> tests/ui/eq_op_macros.rs:14:26 | LL | debug_assert_ne!(a, a); | ^^^^ @@ -45,49 +45,49 @@ LL | assert_in_macro_def!(); = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info) error: identical args used in this `assert_eq!` macro call - --> tests/ui/eq_op_macros.rs:23:16 + --> tests/ui/eq_op_macros.rs:27:16 | LL | assert_eq!(a, a); | ^^^^ error: identical args used in this `assert_eq!` macro call - --> tests/ui/eq_op_macros.rs:25:16 + --> tests/ui/eq_op_macros.rs:30:16 | LL | assert_eq!(a + 1, a + 1); | ^^^^^^^^^^^^ error: identical args used in this `assert_ne!` macro call - --> tests/ui/eq_op_macros.rs:33:16 + --> tests/ui/eq_op_macros.rs:39:16 | LL | assert_ne!(a, a); | ^^^^ error: identical args used in this `assert_ne!` macro call - --> tests/ui/eq_op_macros.rs:35:16 + --> tests/ui/eq_op_macros.rs:42:16 | LL | assert_ne!(a + 1, a + 1); | ^^^^^^^^^^^^ error: identical args used in this `debug_assert_eq!` macro call - --> tests/ui/eq_op_macros.rs:43:22 + --> tests/ui/eq_op_macros.rs:51:22 | LL | debug_assert_eq!(a, a); | ^^^^ error: identical args used in this `debug_assert_eq!` macro call - --> tests/ui/eq_op_macros.rs:45:22 + --> tests/ui/eq_op_macros.rs:54:22 | LL | debug_assert_eq!(a + 1, a + 1); | ^^^^^^^^^^^^ error: identical args used in this `debug_assert_ne!` macro call - --> tests/ui/eq_op_macros.rs:53:22 + --> tests/ui/eq_op_macros.rs:63:22 | LL | debug_assert_ne!(a, a); | ^^^^ error: identical args used in this `debug_assert_ne!` macro call - --> tests/ui/eq_op_macros.rs:55:22 + --> tests/ui/eq_op_macros.rs:66:22 | LL | debug_assert_ne!(a + 1, a + 1); | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed index 2b523e1e185c6..166b1387ba265 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.fixed +++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed @@ -62,13 +62,21 @@ fn main() { // true if a == 2 {} + //~^ equatable_if_let if a.cmp(&b) == Ordering::Greater {} + //~^ equatable_if_let if c == Some(2) {} + //~^ equatable_if_let if d == (Struct { a: 2, b: false }) {} + //~^ equatable_if_let if e == Enum::TupleVariant(32, 64) {} + //~^ equatable_if_let if e == (Enum::RecordVariant { a: 64, b: 32 }) {} + //~^ equatable_if_let if e == Enum::UnitVariant {} + //~^ equatable_if_let if (e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false }) {} + //~^ equatable_if_let // false @@ -78,12 +86,18 @@ fn main() { if let Struct { a, b: false } = d {} if let Struct { a: 2, b: x } = d {} if matches!(f, NotPartialEq::A) {} + //~^ equatable_if_let if g == NotStructuralEq::A {} + //~^ equatable_if_let if matches!(Some(f), Some(NotPartialEq::A)) {} + //~^ equatable_if_let if Some(g) == Some(NotStructuralEq::A) {} + //~^ equatable_if_let if matches!(h, NoPartialEqStruct { a: 2, b: false }) {} + //~^ equatable_if_let if "abc" == inline!("abc") { + //~^ equatable_if_let println!("OK"); } diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs index f7e3bb2964da3..09c2483ae6d43 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.rs +++ b/src/tools/clippy/tests/ui/equatable_if_let.rs @@ -62,13 +62,21 @@ fn main() { // true if let 2 = a {} + //~^ equatable_if_let if let Ordering::Greater = a.cmp(&b) {} + //~^ equatable_if_let if let Some(2) = c {} + //~^ equatable_if_let if let Struct { a: 2, b: false } = d {} + //~^ equatable_if_let if let Enum::TupleVariant(32, 64) = e {} + //~^ equatable_if_let if let Enum::RecordVariant { a: 64, b: 32 } = e {} + //~^ equatable_if_let if let Enum::UnitVariant = e {} + //~^ equatable_if_let if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} + //~^ equatable_if_let // false @@ -78,12 +86,18 @@ fn main() { if let Struct { a, b: false } = d {} if let Struct { a: 2, b: x } = d {} if let NotPartialEq::A = f {} + //~^ equatable_if_let if let NotStructuralEq::A = g {} + //~^ equatable_if_let if let Some(NotPartialEq::A) = Some(f) {} + //~^ equatable_if_let if let Some(NotStructuralEq::A) = Some(g) {} + //~^ equatable_if_let if let NoPartialEqStruct { a: 2, b: false } = h {} + //~^ equatable_if_let if let inline!("abc") = "abc" { + //~^ equatable_if_let println!("OK"); } diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr index 9e93a33cd7e21..81e0e15a5c747 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.stderr +++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr @@ -8,79 +8,79 @@ LL | if let 2 = a {} = help: to override `-D warnings` add `#[allow(clippy::equatable_if_let)]` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:65:8 + --> tests/ui/equatable_if_let.rs:66:8 | LL | if let Ordering::Greater = a.cmp(&b) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.cmp(&b) == Ordering::Greater` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:66:8 + --> tests/ui/equatable_if_let.rs:68:8 | LL | if let Some(2) = c {} | ^^^^^^^^^^^^^^^ help: try: `c == Some(2)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:67:8 + --> tests/ui/equatable_if_let.rs:70:8 | LL | if let Struct { a: 2, b: false } = d {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `d == (Struct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:68:8 + --> tests/ui/equatable_if_let.rs:72:8 | LL | if let Enum::TupleVariant(32, 64) = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::TupleVariant(32, 64)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:69:8 + --> tests/ui/equatable_if_let.rs:74:8 | LL | if let Enum::RecordVariant { a: 64, b: 32 } = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == (Enum::RecordVariant { a: 64, b: 32 })` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:70:8 + --> tests/ui/equatable_if_let.rs:76:8 | LL | if let Enum::UnitVariant = e {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `e == Enum::UnitVariant` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:71:8 + --> tests/ui/equatable_if_let.rs:78:8 | LL | if let (Enum::UnitVariant, &Struct { a: 2, b: false }) = (e, &d) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(e, &d) == (Enum::UnitVariant, &Struct { a: 2, b: false })` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:80:8 + --> tests/ui/equatable_if_let.rs:88:8 | LL | if let NotPartialEq::A = f {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(f, NotPartialEq::A)` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:81:8 + --> tests/ui/equatable_if_let.rs:90:8 | LL | if let NotStructuralEq::A = g {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `g == NotStructuralEq::A` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:82:8 + --> tests/ui/equatable_if_let.rs:92:8 | LL | if let Some(NotPartialEq::A) = Some(f) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(Some(f), Some(NotPartialEq::A))` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:83:8 + --> tests/ui/equatable_if_let.rs:94:8 | LL | if let Some(NotStructuralEq::A) = Some(g) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(g) == Some(NotStructuralEq::A)` error: this pattern matching can be expressed using `matches!` - --> tests/ui/equatable_if_let.rs:84:8 + --> tests/ui/equatable_if_let.rs:96:8 | LL | if let NoPartialEqStruct { a: 2, b: false } = h {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(h, NoPartialEqStruct { a: 2, b: false })` error: this pattern matching can be expressed using equality - --> tests/ui/equatable_if_let.rs:86:8 + --> tests/ui/equatable_if_let.rs:99:8 | LL | if let inline!("abc") = "abc" { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` diff --git a/src/tools/clippy/tests/ui/erasing_op.rs b/src/tools/clippy/tests/ui/erasing_op.rs index 00c74f23fed04..9237b9eb11f05 100644 --- a/src/tools/clippy/tests/ui/erasing_op.rs +++ b/src/tools/clippy/tests/ui/erasing_op.rs @@ -33,17 +33,20 @@ impl core::ops::Mul for Vec1 { #[warn(clippy::erasing_op)] fn test(x: u8) { x * 0; - //~^ ERROR: this operation will always return zero. This is likely not the intended ou - //~| NOTE: `-D clippy::erasing-op` implied by `-D warnings` + //~^ erasing_op + 0 & x; - //~^ ERROR: this operation will always return zero. This is likely not the intended ou + //~^ erasing_op + 0 / x; - //~^ ERROR: this operation will always return zero. This is likely not the intended ou + //~^ erasing_op + 0 * Meter; // no error: Output type is different from the non-zero argument 0 * Vec1 { x: 5 }; - //~^ ERROR: this operation will always return zero. This is likely not the intended ou + //~^ erasing_op + Vec1 { x: 5 } * 0; - //~^ ERROR: this operation will always return zero. This is likely not the intended ou + //~^ erasing_op } fn main() { diff --git a/src/tools/clippy/tests/ui/erasing_op.stderr b/src/tools/clippy/tests/ui/erasing_op.stderr index 6ed8bffeb24d5..94730b0668011 100644 --- a/src/tools/clippy/tests/ui/erasing_op.stderr +++ b/src/tools/clippy/tests/ui/erasing_op.stderr @@ -14,19 +14,19 @@ LL | 0 & x; | ^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> tests/ui/erasing_op.rs:40:5 + --> tests/ui/erasing_op.rs:41:5 | LL | 0 / x; | ^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> tests/ui/erasing_op.rs:43:5 + --> tests/ui/erasing_op.rs:45:5 | LL | 0 * Vec1 { x: 5 }; | ^^^^^^^^^^^^^^^^^ error: this operation will always return zero. This is likely not the intended outcome - --> tests/ui/erasing_op.rs:45:5 + --> tests/ui/erasing_op.rs:48:5 | LL | Vec1 { x: 5 } * 0; | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/err_expect.fixed b/src/tools/clippy/tests/ui/err_expect.fixed index abbc6dbebedb5..9e1a3a0c739cb 100644 --- a/src/tools/clippy/tests/ui/err_expect.fixed +++ b/src/tools/clippy/tests/ui/err_expect.fixed @@ -8,6 +8,7 @@ struct MyTypeDebug; fn main() { let test_debug: Result = Ok(MyTypeDebug); test_debug.expect_err("Testing debug type"); + //~^ err_expect let test_non_debug: Result = Ok(MyTypeNonDebug); test_non_debug.err().expect("Testing non debug type"); @@ -23,4 +24,5 @@ fn msrv_1_16() { fn msrv_1_17() { let x: Result = Ok(17); x.expect_err("17"); + //~^ err_expect } diff --git a/src/tools/clippy/tests/ui/err_expect.rs b/src/tools/clippy/tests/ui/err_expect.rs index 0c7ad185dfbe8..8e9063a2e1d4c 100644 --- a/src/tools/clippy/tests/ui/err_expect.rs +++ b/src/tools/clippy/tests/ui/err_expect.rs @@ -8,6 +8,7 @@ struct MyTypeDebug; fn main() { let test_debug: Result = Ok(MyTypeDebug); test_debug.err().expect("Testing debug type"); + //~^ err_expect let test_non_debug: Result = Ok(MyTypeNonDebug); test_non_debug.err().expect("Testing non debug type"); @@ -23,4 +24,5 @@ fn msrv_1_16() { fn msrv_1_17() { let x: Result = Ok(17); x.err().expect("17"); + //~^ err_expect } diff --git a/src/tools/clippy/tests/ui/err_expect.stderr b/src/tools/clippy/tests/ui/err_expect.stderr index 68f39cc45c5b1..5b591e1604db6 100644 --- a/src/tools/clippy/tests/ui/err_expect.stderr +++ b/src/tools/clippy/tests/ui/err_expect.stderr @@ -8,7 +8,7 @@ LL | test_debug.err().expect("Testing debug type"); = help: to override `-D warnings` add `#[allow(clippy::err_expect)]` error: called `.err().expect()` on a `Result` value - --> tests/ui/err_expect.rs:25:7 + --> tests/ui/err_expect.rs:26:7 | LL | x.err().expect("17"); | ^^^^^^^^^^^^ help: try: `expect_err` diff --git a/src/tools/clippy/tests/ui/error_impl_error.rs b/src/tools/clippy/tests/ui/error_impl_error.rs index 05003f7d047ca..5c88888f38eac 100644 --- a/src/tools/clippy/tests/ui/error_impl_error.rs +++ b/src/tools/clippy/tests/ui/error_impl_error.rs @@ -5,7 +5,7 @@ pub mod a { #[derive(Debug)] pub struct Error; - //~^ ERROR: exported type named `Error` that implements `Error` + //~^ error_impl_error impl std::fmt::Display for Error { fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -19,7 +19,7 @@ pub mod a { mod b { #[derive(Debug)] pub(super) enum Error {} - //~^ ERROR: exported type named `Error` that implements `Error` + //~^ error_impl_error impl std::fmt::Display for Error { fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -32,7 +32,7 @@ mod b { pub mod c { pub union Error { - //~^ ERROR: exported type named `Error` that implements `Error` + //~^ error_impl_error a: u32, b: u32, } @@ -54,7 +54,7 @@ pub mod c { pub mod d { pub type Error = std::fmt::Error; - //~^ ERROR: exported type alias named `Error` that implements `Error` + //~^ error_impl_error } mod e { diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index abccc30ef87dd..0ba631fda051b 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -29,12 +29,19 @@ macro_rules! closure_mac { fn main() { let a = Some(1u8).map(foo); + //~^ redundant_closure let c = Some(1u8).map(|a| {1+2; foo}(a)); true.then(|| mac!()); // don't lint function in macro expansion Some(1).map(closure_mac!()); // don't lint closure in macro expansion let _: Option> = true.then(std::vec::Vec::new); // special case vec! + // + //~^^ redundant_closure let d = Some(1u8).map(|a| foo(foo2(a))); //is adjusted? + // + //~^^ redundant_closure all(&[1, 2, 3], &&2, below); //is adjusted + // + //~^^ redundant_closure unsafe { Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn } @@ -42,6 +49,7 @@ fn main() { // See #815 let e = Some(1u8).map(|a| divergent(a)); let e = Some(1u8).map(generic); + //~^ redundant_closure let e = Some(1u8).map(generic); // See #515 let a: Option)>> = @@ -94,16 +102,22 @@ impl<'a> std::ops::Deref for TestStruct<'a> { fn test_redundant_closures_containing_method_calls() { let i = 10; let e = Some(TestStruct { some_ref: &i }).map(TestStruct::foo); + //~^ redundant_closure_for_method_calls let e = Some(TestStruct { some_ref: &i }).map(TestTrait::trait_foo); + //~^ redundant_closure_for_method_calls let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref()); let e = Some(&mut vec![1, 2, 3]).map(std::vec::Vec::clear); + //~^ redundant_closure_for_method_calls unsafe { let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe()); } let e = Some("str").map(std::string::ToString::to_string); + //~^ redundant_closure_for_method_calls let e = Some('a').map(char::to_uppercase); + //~^ redundant_closure_for_method_calls let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect(); let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(char::to_ascii_uppercase).collect(); + //~^ redundant_closure_for_method_calls let e = Some(PathBuf::new()).as_ref().and_then(|s| s.to_str()); let c = Some(TestStruct { some_ref: &i }) .as_ref() @@ -120,6 +134,7 @@ fn test_redundant_closures_containing_method_calls() { fn issue14096() { let x = Some("42"); let _ = x.map(str::parse::); + //~^ redundant_closure_for_method_calls } } @@ -172,6 +187,7 @@ fn generic(_: T) -> u8 { fn passes_fn_mut(mut x: Box) { requires_fn_once(x); + //~^ redundant_closure } fn requires_fn_once(_: T) {} @@ -179,11 +195,13 @@ fn test_redundant_closure_with_function_pointer() { type FnPtrType = fn(u8); let foo_ptr: FnPtrType = foo; let a = Some(1u8).map(foo_ptr); + //~^ redundant_closure } fn test_redundant_closure_with_another_closure() { let closure = |a| println!("{}", a); let a = Some(1u8).map(closure); + //~^ redundant_closure } fn make_lazy(f: impl Fn() -> fn(u8) -> u8) -> impl Fn(u8) -> u8 { @@ -216,8 +234,11 @@ fn mutable_closure_used_again(x: Vec, y: Vec, z: Vec) { let mut res = Vec::new(); let mut add_to_res = |n| res.push(n); x.into_iter().for_each(&mut add_to_res); + //~^ redundant_closure y.into_iter().for_each(&mut add_to_res); + //~^ redundant_closure z.into_iter().for_each(add_to_res); + //~^ redundant_closure } fn mutable_closure_in_loop() { @@ -225,10 +246,12 @@ fn mutable_closure_in_loop() { let mut closure = |n| value += n; for _ in 0..5 { Some(1).map(&mut closure); + //~^ redundant_closure let mut value = 0; let mut in_loop = |n| value += n; Some(1).map(in_loop); + //~^ redundant_closure } } @@ -322,13 +345,16 @@ fn not_general_enough() { pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() { fn takes_fn_mut(_: impl FnMut()) {} takes_fn_mut(&mut f); + //~^ redundant_closure fn takes_fn_once(_: impl FnOnce()) {} takes_fn_once(&mut f); + //~^ redundant_closure f(); move || takes_fn_mut(&mut f_used_once) + //~^ redundant_closure } impl dyn TestTrait + '_ { @@ -341,16 +367,20 @@ impl dyn TestTrait + '_ { fn angle_brackets_and_args() { let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]); array_opt.map(<[u8; 3]>::as_slice); + //~^ redundant_closure_for_method_calls let slice_opt: Option<&[u8]> = Some(b"slice"); slice_opt.map(<[u8]>::len); + //~^ redundant_closure_for_method_calls let ptr_opt: Option<*const usize> = Some(&487); ptr_opt.map(<*const usize>::is_null); + //~^ redundant_closure_for_method_calls let test_struct = TestStruct { some_ref: &487 }; let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct); dyn_opt.map(::method_on_dyn); + //~^ redundant_closure_for_method_calls } // https://github.com/rust-lang/rust-clippy/issues/12199 @@ -411,6 +441,7 @@ fn _mixed_late_bound_and_early_bound_regions() { *y } let _ = f(&0, f2); + //~^ redundant_closure } fn _closure_with_types() { @@ -439,10 +470,12 @@ mod issue_10854 { pub fn calls_test(test: Option) -> Option { test.map(Test::method) + //~^ redundant_closure_for_method_calls } pub fn calls_outer(test: Option) -> Option { test.map(super::Outer::method) + //~^ redundant_closure_for_method_calls } } @@ -456,6 +489,7 @@ mod issue_10854 { pub fn calls_into_mod(test: Option) -> Option { test.map(test_mod::Test::method) + //~^ redundant_closure_for_method_calls } mod a { @@ -463,6 +497,7 @@ mod issue_10854 { pub mod c { pub fn extreme_nesting(test: Option) -> Option { test.map(crate::issue_10854::d::Test::method) + //~^ redundant_closure_for_method_calls } } } @@ -482,10 +517,12 @@ mod issue_10854 { mod issue_12853 { fn f_by_value(f: F) { let x = Box::new(|| None.map(&f)); + //~^ redundant_closure x(); } fn f_by_ref(f: &F) { let x = Box::new(|| None.map(f)); + //~^ redundant_closure x(); } } @@ -503,5 +540,6 @@ mod issue_13073 { let _field = bind.as_deref().or_else(|| get_default()).unwrap(); // should lint let _field = bind.or_else(get_default).unwrap(); + //~^ redundant_closure } } diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index 9bcee4eba3409..4d8b29d450c54 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -29,12 +29,19 @@ macro_rules! closure_mac { fn main() { let a = Some(1u8).map(|a| foo(a)); + //~^ redundant_closure let c = Some(1u8).map(|a| {1+2; foo}(a)); true.then(|| mac!()); // don't lint function in macro expansion Some(1).map(closure_mac!()); // don't lint closure in macro expansion let _: Option> = true.then(|| vec![]); // special case vec! + // + //~^^ redundant_closure let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? + // + //~^^ redundant_closure all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted + // + //~^^ redundant_closure unsafe { Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn } @@ -42,6 +49,7 @@ fn main() { // See #815 let e = Some(1u8).map(|a| divergent(a)); let e = Some(1u8).map(|a| generic(a)); + //~^ redundant_closure let e = Some(1u8).map(generic); // See #515 let a: Option)>> = @@ -94,16 +102,22 @@ impl<'a> std::ops::Deref for TestStruct<'a> { fn test_redundant_closures_containing_method_calls() { let i = 10; let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); + //~^ redundant_closure_for_method_calls let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); + //~^ redundant_closure_for_method_calls let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo_ref()); let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); + //~^ redundant_closure_for_method_calls unsafe { let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo_unsafe()); } let e = Some("str").map(|s| s.to_string()); + //~^ redundant_closure_for_method_calls let e = Some('a').map(|s| s.to_uppercase()); + //~^ redundant_closure_for_method_calls let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.len_utf8()).collect(); let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); + //~^ redundant_closure_for_method_calls let e = Some(PathBuf::new()).as_ref().and_then(|s| s.to_str()); let c = Some(TestStruct { some_ref: &i }) .as_ref() @@ -120,6 +134,7 @@ fn test_redundant_closures_containing_method_calls() { fn issue14096() { let x = Some("42"); let _ = x.map(|x| x.parse::()); + //~^ redundant_closure_for_method_calls } } @@ -172,6 +187,7 @@ fn generic(_: T) -> u8 { fn passes_fn_mut(mut x: Box) { requires_fn_once(|| x()); + //~^ redundant_closure } fn requires_fn_once(_: T) {} @@ -179,11 +195,13 @@ fn test_redundant_closure_with_function_pointer() { type FnPtrType = fn(u8); let foo_ptr: FnPtrType = foo; let a = Some(1u8).map(|a| foo_ptr(a)); + //~^ redundant_closure } fn test_redundant_closure_with_another_closure() { let closure = |a| println!("{}", a); let a = Some(1u8).map(|a| closure(a)); + //~^ redundant_closure } fn make_lazy(f: impl Fn() -> fn(u8) -> u8) -> impl Fn(u8) -> u8 { @@ -216,8 +234,11 @@ fn mutable_closure_used_again(x: Vec, y: Vec, z: Vec) { let mut res = Vec::new(); let mut add_to_res = |n| res.push(n); x.into_iter().for_each(|x| add_to_res(x)); + //~^ redundant_closure y.into_iter().for_each(|x| add_to_res(x)); + //~^ redundant_closure z.into_iter().for_each(|x| add_to_res(x)); + //~^ redundant_closure } fn mutable_closure_in_loop() { @@ -225,10 +246,12 @@ fn mutable_closure_in_loop() { let mut closure = |n| value += n; for _ in 0..5 { Some(1).map(|n| closure(n)); + //~^ redundant_closure let mut value = 0; let mut in_loop = |n| value += n; Some(1).map(|n| in_loop(n)); + //~^ redundant_closure } } @@ -322,13 +345,16 @@ fn not_general_enough() { pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() { fn takes_fn_mut(_: impl FnMut()) {} takes_fn_mut(|| f()); + //~^ redundant_closure fn takes_fn_once(_: impl FnOnce()) {} takes_fn_once(|| f()); + //~^ redundant_closure f(); move || takes_fn_mut(|| f_used_once()) + //~^ redundant_closure } impl dyn TestTrait + '_ { @@ -341,16 +367,20 @@ impl dyn TestTrait + '_ { fn angle_brackets_and_args() { let array_opt: Option<&[u8; 3]> = Some(&[4, 8, 7]); array_opt.map(|a| a.as_slice()); + //~^ redundant_closure_for_method_calls let slice_opt: Option<&[u8]> = Some(b"slice"); slice_opt.map(|s| s.len()); + //~^ redundant_closure_for_method_calls let ptr_opt: Option<*const usize> = Some(&487); ptr_opt.map(|p| p.is_null()); + //~^ redundant_closure_for_method_calls let test_struct = TestStruct { some_ref: &487 }; let dyn_opt: Option<&dyn TestTrait> = Some(&test_struct); dyn_opt.map(|d| d.method_on_dyn()); + //~^ redundant_closure_for_method_calls } // https://github.com/rust-lang/rust-clippy/issues/12199 @@ -411,6 +441,7 @@ fn _mixed_late_bound_and_early_bound_regions() { *y } let _ = f(&0, |x, y| f2(x, y)); + //~^ redundant_closure } fn _closure_with_types() { @@ -439,10 +470,12 @@ mod issue_10854 { pub fn calls_test(test: Option) -> Option { test.map(|t| t.method()) + //~^ redundant_closure_for_method_calls } pub fn calls_outer(test: Option) -> Option { test.map(|t| t.method()) + //~^ redundant_closure_for_method_calls } } @@ -456,6 +489,7 @@ mod issue_10854 { pub fn calls_into_mod(test: Option) -> Option { test.map(|t| t.method()) + //~^ redundant_closure_for_method_calls } mod a { @@ -463,6 +497,7 @@ mod issue_10854 { pub mod c { pub fn extreme_nesting(test: Option) -> Option { test.map(|t| t.method()) + //~^ redundant_closure_for_method_calls } } } @@ -482,10 +517,12 @@ mod issue_10854 { mod issue_12853 { fn f_by_value(f: F) { let x = Box::new(|| None.map(|x| f(x))); + //~^ redundant_closure x(); } fn f_by_ref(f: &F) { let x = Box::new(|| None.map(|x| f(x))); + //~^ redundant_closure x(); } } @@ -503,5 +540,6 @@ mod issue_13073 { let _field = bind.as_deref().or_else(|| get_default()).unwrap(); // should lint let _field = bind.or_else(|| get_default()).unwrap(); + //~^ redundant_closure } } diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index ac58e87bc5ecd..8bc08add2fab3 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -8,31 +8,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: redundant closure - --> tests/ui/eta.rs:35:40 + --> tests/ui/eta.rs:36:40 | LL | let _: Option> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> tests/ui/eta.rs:36:35 + --> tests/ui/eta.rs:39:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> tests/ui/eta.rs:37:26 + --> tests/ui/eta.rs:42:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> tests/ui/eta.rs:44:27 + --> tests/ui/eta.rs:51:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> tests/ui/eta.rs:96:51 + --> tests/ui/eta.rs:104:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -41,175 +41,175 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]` error: redundant closure - --> tests/ui/eta.rs:97:51 + --> tests/ui/eta.rs:106:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> tests/ui/eta.rs:99:42 + --> tests/ui/eta.rs:109:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> tests/ui/eta.rs:103:29 + --> tests/ui/eta.rs:114:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> tests/ui/eta.rs:104:27 + --> tests/ui/eta.rs:116:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> tests/ui/eta.rs:106:65 + --> tests/ui/eta.rs:119:65 | LL | let e: std::vec::Vec = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> tests/ui/eta.rs:122:23 + --> tests/ui/eta.rs:136:23 | LL | let _ = x.map(|x| x.parse::()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::` error: redundant closure - --> tests/ui/eta.rs:174:22 + --> tests/ui/eta.rs:189:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> tests/ui/eta.rs:181:27 + --> tests/ui/eta.rs:197:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> tests/ui/eta.rs:186:27 + --> tests/ui/eta.rs:203:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> tests/ui/eta.rs:218:28 + --> tests/ui/eta.rs:236:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:219:28 + --> tests/ui/eta.rs:238:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:220:28 + --> tests/ui/eta.rs:240:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> tests/ui/eta.rs:227:21 + --> tests/ui/eta.rs:248:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> tests/ui/eta.rs:231:21 + --> tests/ui/eta.rs:253:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> tests/ui/eta.rs:324:18 + --> tests/ui/eta.rs:347:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:327:19 + --> tests/ui/eta.rs:351:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:331:26 + --> tests/ui/eta.rs:356:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> tests/ui/eta.rs:343:19 + --> tests/ui/eta.rs:369:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> tests/ui/eta.rs:346:19 + --> tests/ui/eta.rs:373:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> tests/ui/eta.rs:349:17 + --> tests/ui/eta.rs:377:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> tests/ui/eta.rs:353:17 + --> tests/ui/eta.rs:382:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `::method_on_dyn` error: redundant closure - --> tests/ui/eta.rs:413:19 + --> tests/ui/eta.rs:443:19 | LL | let _ = f(&0, |x, y| f2(x, y)); | ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2` error: redundant closure - --> tests/ui/eta.rs:441:22 + --> tests/ui/eta.rs:472:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method` error: redundant closure - --> tests/ui/eta.rs:445:22 + --> tests/ui/eta.rs:477:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method` error: redundant closure - --> tests/ui/eta.rs:458:18 + --> tests/ui/eta.rs:491:18 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method` error: redundant closure - --> tests/ui/eta.rs:465:30 + --> tests/ui/eta.rs:499:30 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method` error: redundant closure - --> tests/ui/eta.rs:484:38 + --> tests/ui/eta.rs:519:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `&f` error: redundant closure - --> tests/ui/eta.rs:488:38 + --> tests/ui/eta.rs:524:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `f` error: redundant closure - --> tests/ui/eta.rs:505:35 + --> tests/ui/eta.rs:542:35 | LL | let _field = bind.or_else(|| get_default()).unwrap(); | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default` diff --git a/src/tools/clippy/tests/ui/eta_nostd.fixed b/src/tools/clippy/tests/ui/eta_nostd.fixed index 23059c52b67f7..134af34a826a4 100644 --- a/src/tools/clippy/tests/ui/eta_nostd.fixed +++ b/src/tools/clippy/tests/ui/eta_nostd.fixed @@ -7,4 +7,5 @@ use alloc::vec::Vec; fn issue_13895() { let _: Option> = true.then(alloc::vec::Vec::new); + //~^ redundant_closure } diff --git a/src/tools/clippy/tests/ui/eta_nostd.rs b/src/tools/clippy/tests/ui/eta_nostd.rs index ae44ac348c64f..8d0541bedb2e1 100644 --- a/src/tools/clippy/tests/ui/eta_nostd.rs +++ b/src/tools/clippy/tests/ui/eta_nostd.rs @@ -7,4 +7,5 @@ use alloc::vec::Vec; fn issue_13895() { let _: Option> = true.then(|| vec![]); + //~^ redundant_closure } diff --git a/src/tools/clippy/tests/ui/excessive_precision.fixed b/src/tools/clippy/tests/ui/excessive_precision.fixed index 372f64f7d99e2..99d09774d16d3 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.fixed +++ b/src/tools/clippy/tests/ui/excessive_precision.fixed @@ -18,16 +18,22 @@ fn main() { const GOOD64_DOT: f32 = 10_000_000_000_000_000.0; const BAD32_1: f32 = 0.123_456_79_f32; + //~^ excessive_precision const BAD32_2: f32 = 0.123_456_79; + //~^ excessive_precision const BAD32_3: f32 = 0.1; + //~^ excessive_precision const BAD32_EDGE: f32 = 1.000_001; + //~^ excessive_precision const BAD64_1: f64 = 0.123_456_789_012_345_67f64; const BAD64_2: f64 = 0.123_456_789_012_345_67; const BAD64_3: f64 = 0.1; + //~^ excessive_precision // Literal as param println!("{:?}", 8.888_888_888_888_89); + //~^ excessive_precision // // TODO add inferred type tests for f32 // Locals @@ -39,8 +45,11 @@ fn main() { let good64_inf = 0.123_456_789_012; let bad32: f32 = 1.123_456_8; + //~^ excessive_precision let bad32_suf: f32 = 1.123_456_8_f32; + //~^ excessive_precision let bad32_inf = 1.123_456_8_f32; + //~^ excessive_precision let bad64: f64 = 0.123_456_789_012_345_67; let bad64_suf: f64 = 0.123_456_789_012_345_67f64; @@ -51,14 +60,18 @@ fn main() { let good_vec64: Vec = vec![0.123_456_789]; let bad_vec32: Vec = vec![0.123_456_79]; + //~^ excessive_precision let bad_vec64: Vec = vec![0.123_456_789_123_456_78]; + //~^ excessive_precision // Exponential float notation let good_e32: f32 = 1e-10; let bad_e32: f32 = 1.123_456_8e-10; + //~^ excessive_precision let good_bige32: f32 = 1E-10; let bad_bige32: f32 = 1.123_456_8E-10; + //~^ excessive_precision // Inferred type let good_inferred: f32 = 1f32 * 1_000_000_000.; @@ -68,9 +81,11 @@ fn main() { // issue #7744 let _ = 2.225_073_858_507_201e-308_f64; + //~^ excessive_precision // issue #7745 let _ = 0_f64; + //~^ excessive_precision // issue #9910 const INF1: f32 = 1.0e+33f32; @@ -81,5 +96,6 @@ fn main() { // issue #12954 const _: f64 = 3.0; + //~^ excessive_precision const _: f64 = 3.0000000000000000; } diff --git a/src/tools/clippy/tests/ui/excessive_precision.rs b/src/tools/clippy/tests/ui/excessive_precision.rs index 1e40efbf2452c..a542fb2e7e3cd 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.rs +++ b/src/tools/clippy/tests/ui/excessive_precision.rs @@ -18,16 +18,22 @@ fn main() { const GOOD64_DOT: f32 = 10_000_000_000_000_000.0; const BAD32_1: f32 = 0.123_456_789_f32; + //~^ excessive_precision const BAD32_2: f32 = 0.123_456_789; + //~^ excessive_precision const BAD32_3: f32 = 0.100_000_000_000_1; + //~^ excessive_precision const BAD32_EDGE: f32 = 1.000_000_9; + //~^ excessive_precision const BAD64_1: f64 = 0.123_456_789_012_345_67f64; const BAD64_2: f64 = 0.123_456_789_012_345_67; const BAD64_3: f64 = 0.100_000_000_000_000_000_1; + //~^ excessive_precision // Literal as param println!("{:?}", 8.888_888_888_888_888_888_888); + //~^ excessive_precision // // TODO add inferred type tests for f32 // Locals @@ -39,8 +45,11 @@ fn main() { let good64_inf = 0.123_456_789_012; let bad32: f32 = 1.123_456_789; + //~^ excessive_precision let bad32_suf: f32 = 1.123_456_789_f32; + //~^ excessive_precision let bad32_inf = 1.123_456_789_f32; + //~^ excessive_precision let bad64: f64 = 0.123_456_789_012_345_67; let bad64_suf: f64 = 0.123_456_789_012_345_67f64; @@ -51,14 +60,18 @@ fn main() { let good_vec64: Vec = vec![0.123_456_789]; let bad_vec32: Vec = vec![0.123_456_789]; + //~^ excessive_precision let bad_vec64: Vec = vec![0.123_456_789_123_456_789]; + //~^ excessive_precision // Exponential float notation let good_e32: f32 = 1e-10; let bad_e32: f32 = 1.123_456_788_888e-10; + //~^ excessive_precision let good_bige32: f32 = 1E-10; let bad_bige32: f32 = 1.123_456_788_888E-10; + //~^ excessive_precision // Inferred type let good_inferred: f32 = 1f32 * 1_000_000_000.; @@ -68,9 +81,11 @@ fn main() { // issue #7744 let _ = 2.225_073_858_507_201_1e-308_f64; + //~^ excessive_precision // issue #7745 let _ = 1.000_000_000_000_001e-324_f64; + //~^ excessive_precision // issue #9910 const INF1: f32 = 1.0e+33f32; @@ -81,5 +96,6 @@ fn main() { // issue #12954 const _: f64 = 3.0000000000000000e+00; + //~^ excessive_precision const _: f64 = 3.0000000000000000; } diff --git a/src/tools/clippy/tests/ui/excessive_precision.stderr b/src/tools/clippy/tests/ui/excessive_precision.stderr index b1f12eed42007..934a367e10659 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.stderr +++ b/src/tools/clippy/tests/ui/excessive_precision.stderr @@ -13,7 +13,7 @@ LL + const BAD32_1: f32 = 0.123_456_79_f32; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:21:26 + --> tests/ui/excessive_precision.rs:22:26 | LL | const BAD32_2: f32 = 0.123_456_789; | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + const BAD32_2: f32 = 0.123_456_79; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:22:26 + --> tests/ui/excessive_precision.rs:24:26 | LL | const BAD32_3: f32 = 0.100_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + const BAD32_3: f32 = 0.1; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:23:29 + --> tests/ui/excessive_precision.rs:26:29 | LL | const BAD32_EDGE: f32 = 1.000_000_9; | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + const BAD32_EDGE: f32 = 1.000_001; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:27:26 + --> tests/ui/excessive_precision.rs:31:26 | LL | const BAD64_3: f64 = 0.100_000_000_000_000_000_1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + const BAD64_3: f64 = 0.1; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:30:22 + --> tests/ui/excessive_precision.rs:35:22 | LL | println!("{:?}", 8.888_888_888_888_888_888_888); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + println!("{:?}", 8.888_888_888_888_89); | error: float has excessive precision - --> tests/ui/excessive_precision.rs:41:22 + --> tests/ui/excessive_precision.rs:47:22 | LL | let bad32: f32 = 1.123_456_789; | ^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + let bad32: f32 = 1.123_456_8; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:42:26 + --> tests/ui/excessive_precision.rs:49:26 | LL | let bad32_suf: f32 = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + let bad32_suf: f32 = 1.123_456_8_f32; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:43:21 + --> tests/ui/excessive_precision.rs:51:21 | LL | let bad32_inf = 1.123_456_789_f32; | ^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + let bad32_inf = 1.123_456_8_f32; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:53:36 + --> tests/ui/excessive_precision.rs:62:36 | LL | let bad_vec32: Vec = vec![0.123_456_789]; | ^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + let bad_vec32: Vec = vec![0.123_456_79]; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:54:36 + --> tests/ui/excessive_precision.rs:64:36 | LL | let bad_vec64: Vec = vec![0.123_456_789_123_456_789]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + let bad_vec64: Vec = vec![0.123_456_789_123_456_78]; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:58:24 + --> tests/ui/excessive_precision.rs:69:24 | LL | let bad_e32: f32 = 1.123_456_788_888e-10; | ^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + let bad_e32: f32 = 1.123_456_8e-10; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:61:27 + --> tests/ui/excessive_precision.rs:73:27 | LL | let bad_bige32: f32 = 1.123_456_788_888E-10; | ^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + let bad_bige32: f32 = 1.123_456_8E-10; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:70:13 + --> tests/ui/excessive_precision.rs:83:13 | LL | let _ = 2.225_073_858_507_201_1e-308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + let _ = 2.225_073_858_507_201e-308_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:73:13 + --> tests/ui/excessive_precision.rs:87:13 | LL | let _ = 1.000_000_000_000_001e-324_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let _ = 0_f64; | error: float has excessive precision - --> tests/ui/excessive_precision.rs:83:20 + --> tests/ui/excessive_precision.rs:98:20 | LL | const _: f64 = 3.0000000000000000e+00; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/exhaustive_items.fixed b/src/tools/clippy/tests/ui/exhaustive_items.fixed index 1bf33a5f2f13c..79c74aeefbd83 100644 --- a/src/tools/clippy/tests/ui/exhaustive_items.fixed +++ b/src/tools/clippy/tests/ui/exhaustive_items.fixed @@ -8,6 +8,7 @@ fn main() { pub mod enums { #[non_exhaustive] pub enum Exhaustive { + //~^ exhaustive_enums Foo, Bar, Baz, @@ -18,6 +19,7 @@ pub mod enums { #[repr(C)] #[non_exhaustive] pub enum ExhaustiveWithAttrs { + //~^ exhaustive_enums Foo, Bar, Baz, @@ -54,6 +56,7 @@ pub mod enums { pub mod structs { #[non_exhaustive] pub struct Exhaustive { + //~^ exhaustive_structs pub foo: u8, pub bar: String, } diff --git a/src/tools/clippy/tests/ui/exhaustive_items.rs b/src/tools/clippy/tests/ui/exhaustive_items.rs index 1328791e186d9..4e851f4c492e8 100644 --- a/src/tools/clippy/tests/ui/exhaustive_items.rs +++ b/src/tools/clippy/tests/ui/exhaustive_items.rs @@ -7,6 +7,7 @@ fn main() { pub mod enums { pub enum Exhaustive { + //~^ exhaustive_enums Foo, Bar, Baz, @@ -16,6 +17,7 @@ pub mod enums { /// Some docs #[repr(C)] pub enum ExhaustiveWithAttrs { + //~^ exhaustive_enums Foo, Bar, Baz, @@ -51,6 +53,7 @@ pub mod enums { pub mod structs { pub struct Exhaustive { + //~^ exhaustive_structs pub foo: u8, pub bar: String, } diff --git a/src/tools/clippy/tests/ui/exhaustive_items.stderr b/src/tools/clippy/tests/ui/exhaustive_items.stderr index 536fbe8d790f6..c92c8a9efaaea 100644 --- a/src/tools/clippy/tests/ui/exhaustive_items.stderr +++ b/src/tools/clippy/tests/ui/exhaustive_items.stderr @@ -2,6 +2,7 @@ error: exported enums should not be exhaustive --> tests/ui/exhaustive_items.rs:9:5 | LL | / pub enum Exhaustive { +LL | | LL | | Foo, LL | | Bar, LL | | Baz, @@ -21,9 +22,10 @@ LL ~ pub enum Exhaustive { | error: exported enums should not be exhaustive - --> tests/ui/exhaustive_items.rs:18:5 + --> tests/ui/exhaustive_items.rs:19:5 | LL | / pub enum ExhaustiveWithAttrs { +LL | | LL | | Foo, LL | | Bar, LL | | Baz, @@ -38,9 +40,10 @@ LL ~ pub enum ExhaustiveWithAttrs { | error: exported structs should not be exhaustive - --> tests/ui/exhaustive_items.rs:53:5 + --> tests/ui/exhaustive_items.rs:55:5 | LL | / pub struct Exhaustive { +LL | | LL | | pub foo: u8, LL | | pub bar: String, LL | | } diff --git a/src/tools/clippy/tests/ui/exit1.rs b/src/tools/clippy/tests/ui/exit1.rs index 36b3c42fd9958..be8752cc7d8e2 100644 --- a/src/tools/clippy/tests/ui/exit1.rs +++ b/src/tools/clippy/tests/ui/exit1.rs @@ -3,8 +3,7 @@ fn not_main() { if true { std::process::exit(4); - //~^ ERROR: usage of `process::exit` - //~| NOTE: `-D clippy::exit` implied by `-D warnings` + //~^ exit } } diff --git a/src/tools/clippy/tests/ui/exit2.rs b/src/tools/clippy/tests/ui/exit2.rs index 9bbb7b073a4b0..2be8a84b6d4bb 100644 --- a/src/tools/clippy/tests/ui/exit2.rs +++ b/src/tools/clippy/tests/ui/exit2.rs @@ -2,8 +2,7 @@ fn also_not_main() { std::process::exit(3); - //~^ ERROR: usage of `process::exit` - //~| NOTE: `-D clippy::exit` implied by `-D warnings` + //~^ exit } fn main() { diff --git a/src/tools/clippy/tests/ui/exit3.rs b/src/tools/clippy/tests/ui/exit3.rs index cab908aafd33d..a8af1b225788c 100644 --- a/src/tools/clippy/tests/ui/exit3.rs +++ b/src/tools/clippy/tests/ui/exit3.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::exit)] fn main() { diff --git a/src/tools/clippy/tests/ui/expect.rs b/src/tools/clippy/tests/ui/expect.rs index f15b3d37e154b..8f7379f002143 100644 --- a/src/tools/clippy/tests/ui/expect.rs +++ b/src/tools/clippy/tests/ui/expect.rs @@ -4,15 +4,16 @@ fn expect_option() { let opt = Some(0); let _ = opt.expect(""); - //~^ ERROR: used `expect()` on an `Option` value + //~^ expect_used } fn expect_result() { let res: Result = Ok(0); let _ = res.expect(""); - //~^ ERROR: used `expect()` on a `Result` value + //~^ expect_used + let _ = res.expect_err(""); - //~^ ERROR: used `expect_err()` on a `Result` value + //~^ expect_used } fn main() { diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr index c0ba3390aac59..70cf3072003e6 100644 --- a/src/tools/clippy/tests/ui/expect.stderr +++ b/src/tools/clippy/tests/ui/expect.stderr @@ -17,7 +17,7 @@ LL | let _ = res.expect(""); = note: if this value is an `Err`, it will panic error: used `expect_err()` on a `Result` value - --> tests/ui/expect.rs:14:13 + --> tests/ui/expect.rs:15:13 | LL | let _ = res.expect_err(""); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed index 8f800c71941a1..73eaebf773c83 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.fixed +++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed @@ -33,12 +33,15 @@ fn main() { let error_code = 123_i32; let with_none_and_format: Option = None; with_none_and_format.unwrap_or_else(|| panic!("Error {}: fake error", error_code)); + //~^ expect_fun_call let with_none_and_as_str: Option = None; with_none_and_as_str.unwrap_or_else(|| panic!("Error {}: fake error", error_code)); + //~^ expect_fun_call let with_none_and_format_with_macro: Option = None; with_none_and_format_with_macro.unwrap_or_else(|| panic!("Error {}: fake error", one!())); + //~^ expect_fun_call let with_ok: Result<(), ()> = Ok(()); with_ok.expect("error"); @@ -49,9 +52,11 @@ fn main() { let error_code = 123_i32; let with_err_and_format: Result<(), ()> = Err(()); with_err_and_format.unwrap_or_else(|_| panic!("Error {}: fake error", error_code)); + //~^ expect_fun_call let with_err_and_as_str: Result<(), ()> = Err(()); with_err_and_as_str.unwrap_or_else(|_| panic!("Error {}: fake error", error_code)); + //~^ expect_fun_call let with_dummy_type = Foo::new(); with_dummy_type.expect("another test string"); @@ -64,6 +69,7 @@ fn main() { //Issue #2937 Some("foo").unwrap_or_else(|| panic!("{} {}", 1, 2)); + //~^ expect_fun_call //Issue #2979 - this should not lint { @@ -85,26 +91,35 @@ fn main() { } Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + //~^ expect_fun_call Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + //~^ expect_fun_call Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + //~^ expect_fun_call Some("foo").unwrap_or_else(|| { panic!("{}", get_static_str()) }); + //~^ expect_fun_call Some("foo").unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) }); + //~^ expect_fun_call } //Issue #3839 Some(true).unwrap_or_else(|| panic!("key {}, {}", 1, 2)); + //~^ expect_fun_call //Issue #4912 - the receiver is a &Option { let opt = Some(1); let opt_ref = &opt; opt_ref.unwrap_or_else(|| panic!("{:?}", opt_ref)); + //~^ expect_fun_call } let format_capture: Option = None; format_capture.unwrap_or_else(|| panic!("{error_code}")); + //~^ expect_fun_call let format_capture_and_value: Option = None; format_capture_and_value.unwrap_or_else(|| panic!("{error_code}, {}", 1)); + //~^ expect_fun_call } diff --git a/src/tools/clippy/tests/ui/expect_fun_call.rs b/src/tools/clippy/tests/ui/expect_fun_call.rs index b5cfafb2993e5..ecebc9ebfb6f0 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.rs +++ b/src/tools/clippy/tests/ui/expect_fun_call.rs @@ -33,12 +33,15 @@ fn main() { let error_code = 123_i32; let with_none_and_format: Option = None; with_none_and_format.expect(&format!("Error {}: fake error", error_code)); + //~^ expect_fun_call let with_none_and_as_str: Option = None; with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); + //~^ expect_fun_call let with_none_and_format_with_macro: Option = None; with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); + //~^ expect_fun_call let with_ok: Result<(), ()> = Ok(()); with_ok.expect("error"); @@ -49,9 +52,11 @@ fn main() { let error_code = 123_i32; let with_err_and_format: Result<(), ()> = Err(()); with_err_and_format.expect(&format!("Error {}: fake error", error_code)); + //~^ expect_fun_call let with_err_and_as_str: Result<(), ()> = Err(()); with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); + //~^ expect_fun_call let with_dummy_type = Foo::new(); with_dummy_type.expect("another test string"); @@ -64,6 +69,7 @@ fn main() { //Issue #2937 Some("foo").expect(format!("{} {}", 1, 2).as_ref()); + //~^ expect_fun_call //Issue #2979 - this should not lint { @@ -85,26 +91,35 @@ fn main() { } Some("foo").expect(&get_string()); + //~^ expect_fun_call Some("foo").expect(get_string().as_ref()); + //~^ expect_fun_call Some("foo").expect(get_string().as_str()); + //~^ expect_fun_call Some("foo").expect(get_static_str()); + //~^ expect_fun_call Some("foo").expect(get_non_static_str(&0)); + //~^ expect_fun_call } //Issue #3839 Some(true).expect(&format!("key {}, {}", 1, 2)); + //~^ expect_fun_call //Issue #4912 - the receiver is a &Option { let opt = Some(1); let opt_ref = &opt; opt_ref.expect(&format!("{:?}", opt_ref)); + //~^ expect_fun_call } let format_capture: Option = None; format_capture.expect(&format!("{error_code}")); + //~^ expect_fun_call let format_capture_and_value: Option = None; format_capture_and_value.expect(&format!("{error_code}, {}", 1)); + //~^ expect_fun_call } diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr index 050c039f834dc..36713196cb920 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.stderr +++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr @@ -8,85 +8,85 @@ LL | with_none_and_format.expect(&format!("Error {}: fake error", error_code = help: to override `-D warnings` add `#[allow(clippy::expect_fun_call)]` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:38:26 + --> tests/ui/expect_fun_call.rs:39:26 | LL | with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:41:37 + --> tests/ui/expect_fun_call.rs:43:37 | LL | with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:51:25 + --> tests/ui/expect_fun_call.rs:54:25 | LL | with_err_and_format.expect(&format!("Error {}: fake error", error_code)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:54:25 + --> tests/ui/expect_fun_call.rs:58:25 | LL | with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:66:17 + --> tests/ui/expect_fun_call.rs:71:17 | LL | Some("foo").expect(format!("{} {}", 1, 2).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{} {}", 1, 2))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:87:21 + --> tests/ui/expect_fun_call.rs:93:21 | LL | Some("foo").expect(&get_string()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:88:21 + --> tests/ui/expect_fun_call.rs:95:21 | LL | Some("foo").expect(get_string().as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:89:21 + --> tests/ui/expect_fun_call.rs:97:21 | LL | Some("foo").expect(get_string().as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:91:21 + --> tests/ui/expect_fun_call.rs:100:21 | LL | Some("foo").expect(get_static_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:92:21 + --> tests/ui/expect_fun_call.rs:102:21 | LL | Some("foo").expect(get_non_static_str(&0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:96:16 + --> tests/ui/expect_fun_call.rs:107:16 | LL | Some(true).expect(&format!("key {}, {}", 1, 2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:102:17 + --> tests/ui/expect_fun_call.rs:114:17 | LL | opt_ref.expect(&format!("{:?}", opt_ref)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{:?}", opt_ref))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:106:20 + --> tests/ui/expect_fun_call.rs:119:20 | LL | format_capture.expect(&format!("{error_code}")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}"))` error: function call inside of `expect` - --> tests/ui/expect_fun_call.rs:109:30 + --> tests/ui/expect_fun_call.rs:123:30 | LL | format_capture_and_value.expect(&format!("{error_code}, {}", 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| panic!("{error_code}, {}", 1))` diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs index 2634c56794e70..2295691c81272 100644 --- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs +++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs @@ -30,11 +30,14 @@ mod rustc_warn { #[expect(dead_code)] //~^ ERROR: this lint expectation is unfulfilled //~| NOTE: `-D unfulfilled-lint-expectations` implied by `-D warnings` + //~| HELP: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]` pub fn rustc_lints() { let x = 42; #[expect(invalid_nan_comparisons)] //~^ ERROR: this lint expectation is unfulfilled + //~| NOTE: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + //~| ERROR: this lint expectation is unfulfilled let _b = x == 5; } } diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr index 028e22ca724e4..b274d5c236933 100644 --- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr +++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr @@ -8,13 +8,13 @@ LL | #[expect(dead_code)] = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]` error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:36:18 + --> tests/ui/expect_tool_lint_rfc_2383.rs:37:18 | LL | #[expect(invalid_nan_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:36:18 + --> tests/ui/expect_tool_lint_rfc_2383.rs:37:18 | LL | #[expect(invalid_nan_comparisons)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,25 +22,25 @@ LL | #[expect(invalid_nan_comparisons)] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:107:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:110:14 | LL | #[expect(clippy::almost_swapped)] | ^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:115:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:118:14 | LL | #[expect(clippy::bytes_nth)] | ^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:121:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:124:14 | LL | #[expect(clippy::if_same_then_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this lint expectation is unfulfilled - --> tests/ui/expect_tool_lint_rfc_2383.rs:127:14 + --> tests/ui/expect_tool_lint_rfc_2383.rs:130:14 | LL | #[expect(clippy::overly_complex_bool_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed index 9d476259b87e0..7235f7d5b82af 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed @@ -67,43 +67,55 @@ fn main() { let s = String::new(); let _: &str = &s; + //~^ explicit_auto_deref let _: &str = &{ String::new() }; + //~^ explicit_auto_deref let _: &str = &mut { String::new() }; + //~^ explicit_auto_deref let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. f_str(&s); + //~^ explicit_auto_deref f_t(&*s); // Don't lint. Inferred type would change. f_ref_t(&*s); // Don't lint. Inferred type would change. f_str_t(&s, &*s); // Don't lint second param. + // + //~^^ explicit_auto_deref let b = Box::new(Box::new(Box::new(5))); let _: &Box = &b; + //~^ explicit_auto_deref let _: &Box<_> = &**b; // Don't lint. Inferred type would change. f_box_t(&**b); // Don't lint. Inferred type would change. let c = |_x: &str| (); c(&s); + //~^ explicit_auto_deref let c = |_x| (); c(&*s); // Don't lint. Inferred type would change. fn _f(x: &String) -> &str { x + //~^ explicit_auto_deref } fn _f1(x: &String) -> &str { { x } + //~^ explicit_auto_deref } fn _f2(x: &String) -> &str { { x } + //~^ explicit_auto_deref } fn _f3(x: &Box>>) -> &Box { x + //~^ explicit_auto_deref } fn _f4( @@ -121,25 +133,38 @@ fn main() { f11: &dyn CallableT, ) { f1(&x); + //~^ explicit_auto_deref f2(&x); + //~^ explicit_auto_deref f3(&x); + //~^ explicit_auto_deref f4.callable_str()(&x); + //~^ explicit_auto_deref f5(&x); + //~^ explicit_auto_deref f6(&x); + //~^ explicit_auto_deref f7.callable_str()(&x); + //~^ explicit_auto_deref f8.callable_t()(&x); + //~^ explicit_auto_deref f9(&x); + //~^ explicit_auto_deref f10(&x); + //~^ explicit_auto_deref f11.callable_t()(&x); + //~^ explicit_auto_deref } struct S1<'a>(&'a str); let _ = S1(&s); + //~^ explicit_auto_deref struct S2<'a> { s: &'a str, } let _ = S2 { s: &s }; + //~^ explicit_auto_deref struct S3<'a, T: ?Sized>(&'a T); let _ = S3(&*s); // Don't lint. Inferred type would change. @@ -156,11 +181,15 @@ fn main() { impl<'a> E1<'a> { fn m1(s: &'a String) { let _ = Self::S1(s); + //~^ explicit_auto_deref let _ = Self::S2 { s: s }; + //~^ explicit_auto_deref } } let _ = E1::S1(&s); + //~^ explicit_auto_deref let _ = E1::S2 { s: &s }; + //~^ explicit_auto_deref enum E2<'a, T: ?Sized> { S1(&'a T), @@ -179,7 +208,9 @@ fn main() { let b = Box::new(Box::new(S5 { foo: 5 })); let _ = b.foo; let _ = b.foo; + //~^ explicit_auto_deref let _ = b.foo; + //~^ explicit_auto_deref struct S6 { foo: S5, @@ -195,8 +226,10 @@ fn main() { let ref_str = &"foo"; let _ = f_str(ref_str); + //~^ explicit_auto_deref let ref_ref_str = &ref_str; let _ = f_str(ref_ref_str); + //~^ explicit_auto_deref fn _f5(x: &u32) -> u32 { if true { @@ -207,7 +240,11 @@ fn main() { } f_str(&ref_str); // `needless_borrow` will suggest removing both references + // + //~^^ explicit_auto_deref f_str(&ref_str); // `needless_borrow` will suggest removing only one reference + // + //~^^ explicit_auto_deref let x = &&40; unsafe { @@ -217,6 +254,7 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return s }; + //~^ explicit_auto_deref struct X; struct Y(X); @@ -236,6 +274,7 @@ fn main() { fn deref_to_u>(x: &T) -> &U { x + //~^ explicit_auto_deref } let _ = |x: &'static Box>| -> &'static dyn Iterator { &**x }; @@ -259,11 +298,14 @@ fn main() { let c1 = |_: &Vec<&u32>| {}; let x = &&vec![&1u32]; c1(x); + //~^ explicit_auto_deref let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { if b { return x; + //~^ explicit_auto_deref } x + //~^ explicit_auto_deref }; trait WithAssoc { @@ -298,6 +340,7 @@ fn main() { // Issue #11366 let _: &mut u32 = match &mut Some(&mut 0u32) { Some(x) => x, + //~^ explicit_auto_deref None => panic!(), }; @@ -331,18 +374,23 @@ fn main() { }; let _ = &mut (*x.u).x; let _ = &mut { x.u }.x; + //~^ explicit_auto_deref let _ = &mut ({ *x.u }).x; let mut x = U { u: Wrap(core::mem::ManuallyDrop::new(S8 { x: "" })), }; let _ = &mut (*x.u).x; + //~^ explicit_auto_deref let _ = &mut { x.u }.x; + //~^ explicit_auto_deref let _ = &mut ({ **x.u }).x; let mut x = U { u: Wrap(S8 { x: "" }) }; let _ = &mut x.u.x; + //~^ explicit_auto_deref let _ = &mut { x.u }.x; + //~^ explicit_auto_deref let _ = &mut ({ *x.u }).x; } } @@ -366,6 +414,7 @@ mod issue_12969 { let wrapped_bar = Wrapper(""); foo(&wrapped_bar); + //~^ explicit_auto_deref } } diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs index 23307c837f0e8..c4d2b28ff4b5f 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs @@ -67,43 +67,55 @@ fn main() { let s = String::new(); let _: &str = &*s; + //~^ explicit_auto_deref let _: &str = &*{ String::new() }; + //~^ explicit_auto_deref let _: &str = &mut *{ String::new() }; + //~^ explicit_auto_deref let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. f_str(&*s); + //~^ explicit_auto_deref f_t(&*s); // Don't lint. Inferred type would change. f_ref_t(&*s); // Don't lint. Inferred type would change. f_str_t(&*s, &*s); // Don't lint second param. + // + //~^^ explicit_auto_deref let b = Box::new(Box::new(Box::new(5))); let _: &Box = &**b; + //~^ explicit_auto_deref let _: &Box<_> = &**b; // Don't lint. Inferred type would change. f_box_t(&**b); // Don't lint. Inferred type would change. let c = |_x: &str| (); c(&*s); + //~^ explicit_auto_deref let c = |_x| (); c(&*s); // Don't lint. Inferred type would change. fn _f(x: &String) -> &str { &**x + //~^ explicit_auto_deref } fn _f1(x: &String) -> &str { { &**x } + //~^ explicit_auto_deref } fn _f2(x: &String) -> &str { &**{ x } + //~^ explicit_auto_deref } fn _f3(x: &Box>>) -> &Box { &***x + //~^ explicit_auto_deref } fn _f4( @@ -121,25 +133,38 @@ fn main() { f11: &dyn CallableT, ) { f1(&*x); + //~^ explicit_auto_deref f2(&*x); + //~^ explicit_auto_deref f3(&*x); + //~^ explicit_auto_deref f4.callable_str()(&*x); + //~^ explicit_auto_deref f5(&*x); + //~^ explicit_auto_deref f6(&*x); + //~^ explicit_auto_deref f7.callable_str()(&*x); + //~^ explicit_auto_deref f8.callable_t()(&*x); + //~^ explicit_auto_deref f9(&*x); + //~^ explicit_auto_deref f10(&*x); + //~^ explicit_auto_deref f11.callable_t()(&*x); + //~^ explicit_auto_deref } struct S1<'a>(&'a str); let _ = S1(&*s); + //~^ explicit_auto_deref struct S2<'a> { s: &'a str, } let _ = S2 { s: &*s }; + //~^ explicit_auto_deref struct S3<'a, T: ?Sized>(&'a T); let _ = S3(&*s); // Don't lint. Inferred type would change. @@ -156,11 +181,15 @@ fn main() { impl<'a> E1<'a> { fn m1(s: &'a String) { let _ = Self::S1(&**s); + //~^ explicit_auto_deref let _ = Self::S2 { s: &**s }; + //~^ explicit_auto_deref } } let _ = E1::S1(&*s); + //~^ explicit_auto_deref let _ = E1::S2 { s: &*s }; + //~^ explicit_auto_deref enum E2<'a, T: ?Sized> { S1(&'a T), @@ -179,7 +208,9 @@ fn main() { let b = Box::new(Box::new(S5 { foo: 5 })); let _ = b.foo; let _ = (*b).foo; + //~^ explicit_auto_deref let _ = (**b).foo; + //~^ explicit_auto_deref struct S6 { foo: S5, @@ -195,8 +226,10 @@ fn main() { let ref_str = &"foo"; let _ = f_str(*ref_str); + //~^ explicit_auto_deref let ref_ref_str = &ref_str; let _ = f_str(**ref_ref_str); + //~^ explicit_auto_deref fn _f5(x: &u32) -> u32 { if true { @@ -207,7 +240,11 @@ fn main() { } f_str(&&*ref_str); // `needless_borrow` will suggest removing both references + // + //~^^ explicit_auto_deref f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference + // + //~^^ explicit_auto_deref let x = &&40; unsafe { @@ -217,6 +254,7 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return *s }; + //~^ explicit_auto_deref struct X; struct Y(X); @@ -236,6 +274,7 @@ fn main() { fn deref_to_u>(x: &T) -> &U { &**x + //~^ explicit_auto_deref } let _ = |x: &'static Box>| -> &'static dyn Iterator { &**x }; @@ -259,11 +298,14 @@ fn main() { let c1 = |_: &Vec<&u32>| {}; let x = &&vec![&1u32]; c1(*x); + //~^ explicit_auto_deref let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { if b { return *x; + //~^ explicit_auto_deref } *x + //~^ explicit_auto_deref }; trait WithAssoc { @@ -298,6 +340,7 @@ fn main() { // Issue #11366 let _: &mut u32 = match &mut Some(&mut 0u32) { Some(x) => &mut *x, + //~^ explicit_auto_deref None => panic!(), }; @@ -331,18 +374,23 @@ fn main() { }; let _ = &mut (*x.u).x; let _ = &mut (*{ x.u }).x; + //~^ explicit_auto_deref let _ = &mut ({ *x.u }).x; let mut x = U { u: Wrap(core::mem::ManuallyDrop::new(S8 { x: "" })), }; let _ = &mut (**x.u).x; + //~^ explicit_auto_deref let _ = &mut (**{ x.u }).x; + //~^ explicit_auto_deref let _ = &mut ({ **x.u }).x; let mut x = U { u: Wrap(S8 { x: "" }) }; let _ = &mut (*x.u).x; + //~^ explicit_auto_deref let _ = &mut (*{ x.u }).x; + //~^ explicit_auto_deref let _ = &mut ({ *x.u }).x; } } @@ -366,6 +414,7 @@ mod issue_12969 { let wrapped_bar = Wrapper(""); foo(&*wrapped_bar); + //~^ explicit_auto_deref } } diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr index 0b05a554eb11f..ba4cd86e0b5af 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr @@ -8,271 +8,271 @@ LL | let _: &str = &*s; = help: to override `-D warnings` add `#[allow(clippy::explicit_auto_deref)]` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:70:19 + --> tests/ui/explicit_auto_deref.rs:71:19 | LL | let _: &str = &*{ String::new() }; | ^^^^^^^^^^^^^^^^^^^ help: try: `&{ String::new() }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:71:19 + --> tests/ui/explicit_auto_deref.rs:73:19 | LL | let _: &str = &mut *{ String::new() }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut { String::new() }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:75:11 + --> tests/ui/explicit_auto_deref.rs:78:11 | LL | f_str(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:79:13 + --> tests/ui/explicit_auto_deref.rs:83:13 | LL | f_str_t(&*s, &*s); // Don't lint second param. | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:82:24 + --> tests/ui/explicit_auto_deref.rs:88:24 | LL | let _: &Box = &**b; | ^^^^ help: try: `&b` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:88:7 + --> tests/ui/explicit_auto_deref.rs:95:7 | LL | c(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:94:9 + --> tests/ui/explicit_auto_deref.rs:102:9 | LL | &**x | ^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:98:11 + --> tests/ui/explicit_auto_deref.rs:107:11 | LL | { &**x } | ^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:102:9 + --> tests/ui/explicit_auto_deref.rs:112:9 | LL | &**{ x } | ^^^^^^^^ help: try: `{ x }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:106:9 + --> tests/ui/explicit_auto_deref.rs:117:9 | LL | &***x | ^^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:123:12 + --> tests/ui/explicit_auto_deref.rs:135:12 | LL | f1(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:124:12 + --> tests/ui/explicit_auto_deref.rs:137:12 | LL | f2(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:125:12 + --> tests/ui/explicit_auto_deref.rs:139:12 | LL | f3(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:126:27 + --> tests/ui/explicit_auto_deref.rs:141:27 | LL | f4.callable_str()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:127:12 + --> tests/ui/explicit_auto_deref.rs:143:12 | LL | f5(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:128:12 + --> tests/ui/explicit_auto_deref.rs:145:12 | LL | f6(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:129:27 + --> tests/ui/explicit_auto_deref.rs:147:27 | LL | f7.callable_str()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:130:25 + --> tests/ui/explicit_auto_deref.rs:149:25 | LL | f8.callable_t()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:131:12 + --> tests/ui/explicit_auto_deref.rs:151:12 | LL | f9(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:132:13 + --> tests/ui/explicit_auto_deref.rs:153:13 | LL | f10(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:133:26 + --> tests/ui/explicit_auto_deref.rs:155:26 | LL | f11.callable_t()(&*x); | ^^^ help: try: `&x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:137:16 + --> tests/ui/explicit_auto_deref.rs:160:16 | LL | let _ = S1(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:142:21 + --> tests/ui/explicit_auto_deref.rs:166:21 | LL | let _ = S2 { s: &*s }; | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:158:30 + --> tests/ui/explicit_auto_deref.rs:183:30 | LL | let _ = Self::S1(&**s); | ^^^^ help: try: `s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:159:35 + --> tests/ui/explicit_auto_deref.rs:185:35 | LL | let _ = Self::S2 { s: &**s }; | ^^^^ help: try: `s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:162:20 + --> tests/ui/explicit_auto_deref.rs:189:20 | LL | let _ = E1::S1(&*s); | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:163:25 + --> tests/ui/explicit_auto_deref.rs:191:25 | LL | let _ = E1::S2 { s: &*s }; | ^^^ help: try: `&s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:181:13 + --> tests/ui/explicit_auto_deref.rs:210:13 | LL | let _ = (*b).foo; | ^^^^ help: try: `b` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:182:13 + --> tests/ui/explicit_auto_deref.rs:212:13 | LL | let _ = (**b).foo; | ^^^^^ help: try: `b` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:197:19 + --> tests/ui/explicit_auto_deref.rs:228:19 | LL | let _ = f_str(*ref_str); | ^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:199:19 + --> tests/ui/explicit_auto_deref.rs:231:19 | LL | let _ = f_str(**ref_ref_str); | ^^^^^^^^^^^^^ help: try: `ref_ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:209:12 + --> tests/ui/explicit_auto_deref.rs:242:12 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references | ^^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:210:12 + --> tests/ui/explicit_auto_deref.rs:245:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference | ^^^^^^^^^^ help: try: `ref_str` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:219:41 + --> tests/ui/explicit_auto_deref.rs:256:41 | LL | let _ = || -> &'static str { return *s }; | ^^ help: try: `s` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:238:9 + --> tests/ui/explicit_auto_deref.rs:276:9 | LL | &**x | ^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:261:8 + --> tests/ui/explicit_auto_deref.rs:300:8 | LL | c1(*x); | ^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:264:20 + --> tests/ui/explicit_auto_deref.rs:304:20 | LL | return *x; | ^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:266:9 + --> tests/ui/explicit_auto_deref.rs:307:9 | LL | *x | ^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:300:20 + --> tests/ui/explicit_auto_deref.rs:342:20 | LL | Some(x) => &mut *x, | ^^^^^^^ help: try: `x` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:333:22 + --> tests/ui/explicit_auto_deref.rs:376:22 | LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:339:22 + --> tests/ui/explicit_auto_deref.rs:383:22 | LL | let _ = &mut (**x.u).x; | ^^^^^^^ help: try: `(*x.u)` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:340:22 + --> tests/ui/explicit_auto_deref.rs:385:22 | LL | let _ = &mut (**{ x.u }).x; | ^^^^^^^^^^^ help: try: `{ x.u }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:344:22 + --> tests/ui/explicit_auto_deref.rs:390:22 | LL | let _ = &mut (*x.u).x; | ^^^^^^ help: try: `x.u` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:345:22 + --> tests/ui/explicit_auto_deref.rs:392:22 | LL | let _ = &mut (*{ x.u }).x; | ^^^^^^^^^^ help: try: `{ x.u }` error: deref which would be done by auto-deref - --> tests/ui/explicit_auto_deref.rs:368:13 + --> tests/ui/explicit_auto_deref.rs:416:13 | LL | foo(&*wrapped_bar); | ^^^^^^^^^^^^^ help: try: `&wrapped_bar` diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.rs b/src/tools/clippy/tests/ui/explicit_counter_loop.rs index 28b477b69215b..8340d99ace226 100644 --- a/src/tools/clippy/tests/ui/explicit_counter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_counter_loop.rs @@ -5,27 +5,30 @@ fn main() { let mut vec = vec![1, 2, 3, 4]; let mut _index = 0; for _v in &vec { - //~^ ERROR: the variable `_index` is used as a loop counter - //~| NOTE: `-D clippy::explicit-counter-loop` implied by `-D warnings` + //~^ explicit_counter_loop + _index += 1 } let mut _index = 1; _index = 0; for _v in &vec { - //~^ ERROR: the variable `_index` is used as a loop counter + //~^ explicit_counter_loop + _index += 1 } let mut _index = 0; for _v in &mut vec { - //~^ ERROR: the variable `_index` is used as a loop counter + //~^ explicit_counter_loop + _index += 1; } let mut _index = 0; for _v in vec { - //~^ ERROR: the variable `_index` is used as a loop counter + //~^ explicit_counter_loop + _index += 1; } @@ -113,7 +116,8 @@ mod issue_1219 { let text = "banana"; let mut count = 0; for ch in text.chars() { - //~^ ERROR: the variable `count` is used as a loop counter + //~^ explicit_counter_loop + println!("{}", count); count += 1; if ch == 'a' { @@ -125,7 +129,8 @@ mod issue_1219 { let text = "banana"; let mut count = 0; for ch in text.chars() { - //~^ ERROR: the variable `count` is used as a loop counter + //~^ explicit_counter_loop + println!("{}", count); count += 1; for i in 0..2 { @@ -184,7 +189,8 @@ mod issue_1670 { pub fn test() { let mut count = 0; for _i in 3..10 { - //~^ ERROR: the variable `count` is used as a loop counter + //~^ explicit_counter_loop + count += 1; } } @@ -225,7 +231,8 @@ mod issue_7920 { // should suggest `enumerate` for _item in slice { - //~^ ERROR: the variable `idx_usize` is used as a loop counter + //~^ explicit_counter_loop + if idx_usize == index_usize { break; } @@ -238,8 +245,8 @@ mod issue_7920 { // should suggest `zip` for _item in slice { - //~^ ERROR: the variable `idx_u32` is used as a loop counter - //~| NOTE: `idx_u32` is of type `u32`, making it ineligible for `Iterator::enumera + //~^ explicit_counter_loop + if idx_u32 == index_u32 { break; } @@ -284,6 +291,7 @@ mod issue_13123 { let mut vec = vec![1, 2, 3, 4]; let mut _index = 0; 'label: for v in vec { + //~^ explicit_counter_loop _index += 1; if v == 1 { break 'label; diff --git a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr index 1b2d1f8570a3e..a73516558c20c 100644 --- a/src/tools/clippy/tests/ui/explicit_counter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_counter_loop.stderr @@ -14,43 +14,43 @@ LL | for _v in &vec { | ^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter().enumerate()` error: the variable `_index` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:21:5 + --> tests/ui/explicit_counter_loop.rs:22:5 | LL | for _v in &mut vec { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.iter_mut().enumerate()` error: the variable `_index` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:27:5 + --> tests/ui/explicit_counter_loop.rs:29:5 | LL | for _v in vec { | ^^^^^^^^^^^^^ help: consider using: `for (_index, _v) in vec.into_iter().enumerate()` error: the variable `count` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:115:9 + --> tests/ui/explicit_counter_loop.rs:118:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` error: the variable `count` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:127:9 + --> tests/ui/explicit_counter_loop.rs:131:9 | LL | for ch in text.chars() { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `for (count, ch) in text.chars().enumerate()` error: the variable `count` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:186:9 + --> tests/ui/explicit_counter_loop.rs:191:9 | LL | for _i in 3..10 { | ^^^^^^^^^^^^^^^ help: consider using: `for (count, _i) in (3..10).enumerate()` error: the variable `idx_usize` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:227:9 + --> tests/ui/explicit_counter_loop.rs:233:9 | LL | for _item in slice { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_usize, _item) in slice.iter().enumerate()` error: the variable `idx_u32` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:240:9 + --> tests/ui/explicit_counter_loop.rs:247:9 | LL | for _item in slice { | ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_u32, _item) in (0_u32..).zip(slice.iter())` @@ -58,7 +58,7 @@ LL | for _item in slice { = note: `idx_u32` is of type `u32`, making it ineligible for `Iterator::enumerate` error: the variable `_index` is used as a loop counter - --> tests/ui/explicit_counter_loop.rs:286:9 + --> tests/ui/explicit_counter_loop.rs:293:9 | LL | 'label: for v in vec { | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `'label: for (_index, v) in vec.into_iter().enumerate()` diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed index 7b2dd2fe6eb82..0d1a5f80f3d5a 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed @@ -52,29 +52,40 @@ fn main() { // these should require linting let b: &str = &*a; + //~^ explicit_deref_methods let b: &mut str = &mut **a; + //~^ explicit_deref_methods // both derefs should get linted here let b: String = format!("{}, {}", &*a, &*a); + //~^ explicit_deref_methods + //~| explicit_deref_methods println!("{}", &*a); + //~^ explicit_deref_methods #[allow(clippy::match_single_binding)] match &*a { + //~^ explicit_deref_methods _ => (), } let b: String = concat(&*a); + //~^ explicit_deref_methods let b = just_return(a); + //~^ explicit_deref_methods let b: String = concat(just_return(a)); + //~^ explicit_deref_methods let b: &str = &**a; + //~^ explicit_deref_methods let opt_a = Some(a.clone()); let b = &*opt_a.unwrap(); + //~^ explicit_deref_methods // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified // syntax @@ -112,6 +123,7 @@ fn main() { let b: &str = expr_deref!(a); let b: &str = expr_deref!(&*a); + //~^ explicit_deref_methods // The struct does not implement Deref trait #[derive(Copy, Clone)] diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs index eb52cfb0d8577..8d4a899cd2607 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs @@ -52,29 +52,40 @@ fn main() { // these should require linting let b: &str = a.deref(); + //~^ explicit_deref_methods let b: &mut str = a.deref_mut(); + //~^ explicit_deref_methods // both derefs should get linted here let b: String = format!("{}, {}", a.deref(), a.deref()); + //~^ explicit_deref_methods + //~| explicit_deref_methods println!("{}", a.deref()); + //~^ explicit_deref_methods #[allow(clippy::match_single_binding)] match a.deref() { + //~^ explicit_deref_methods _ => (), } let b: String = concat(a.deref()); + //~^ explicit_deref_methods let b = just_return(a).deref(); + //~^ explicit_deref_methods let b: String = concat(just_return(a).deref()); + //~^ explicit_deref_methods let b: &str = a.deref().deref(); + //~^ explicit_deref_methods let opt_a = Some(a.clone()); let b = opt_a.unwrap().deref(); + //~^ explicit_deref_methods // make sure `Aaa::deref` instead of `aaa.deref()` is not linted, as well as fully qualified // syntax @@ -112,6 +123,7 @@ fn main() { let b: &str = expr_deref!(a); let b: &str = expr_deref!(a.deref()); + //~^ explicit_deref_methods // The struct does not implement Deref trait #[derive(Copy, Clone)] diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr index aab862baf5991..2ca376cba00bd 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.stderr +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.stderr @@ -8,67 +8,67 @@ LL | let b: &str = a.deref(); = help: to override `-D warnings` add `#[allow(clippy::explicit_deref_methods)]` error: explicit `deref_mut` method call - --> tests/ui/explicit_deref_methods.rs:56:23 + --> tests/ui/explicit_deref_methods.rs:57:23 | LL | let b: &mut str = a.deref_mut(); | ^^^^^^^^^^^^^ help: try: `&mut **a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:59:39 + --> tests/ui/explicit_deref_methods.rs:61:39 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:59:50 + --> tests/ui/explicit_deref_methods.rs:61:50 | LL | let b: String = format!("{}, {}", a.deref(), a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:61:20 + --> tests/ui/explicit_deref_methods.rs:65:20 | LL | println!("{}", a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:64:11 + --> tests/ui/explicit_deref_methods.rs:69:11 | LL | match a.deref() { | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:68:28 + --> tests/ui/explicit_deref_methods.rs:74:28 | LL | let b: String = concat(a.deref()); | ^^^^^^^^^ help: try: `&*a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:70:13 + --> tests/ui/explicit_deref_methods.rs:77:13 | LL | let b = just_return(a).deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:72:28 + --> tests/ui/explicit_deref_methods.rs:80:28 | LL | let b: String = concat(just_return(a).deref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `just_return(a)` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:74:19 + --> tests/ui/explicit_deref_methods.rs:83:19 | LL | let b: &str = a.deref().deref(); | ^^^^^^^^^^^^^^^^^ help: try: `&**a` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:77:13 + --> tests/ui/explicit_deref_methods.rs:87:13 | LL | let b = opt_a.unwrap().deref(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*opt_a.unwrap()` error: explicit `deref` method call - --> tests/ui/explicit_deref_methods.rs:114:31 + --> tests/ui/explicit_deref_methods.rs:125:31 | LL | let b: &str = expr_deref!(a.deref()); | ^^^^^^^^^ help: try: `&*a` diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed index 6d67488a71309..2b68906ae39fa 100644 --- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed +++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.fixed @@ -8,6 +8,7 @@ fn main() { for<'a> &'a T: IntoIterator, { for _ in iterator {} + //~^ explicit_into_iter_loop } struct T; @@ -21,9 +22,11 @@ fn main() { let mut t = T; for _ in &t {} + //~^ explicit_into_iter_loop let r = &t; for _ in r {} + //~^ explicit_into_iter_loop // No suggestion for this. // We'd have to suggest `for _ in *rr {}` which is less clear. @@ -32,6 +35,7 @@ fn main() { let mr = &mut t; for _ in &*mr {} + //~^ explicit_into_iter_loop struct U; impl IntoIterator for &mut U { @@ -44,9 +48,11 @@ fn main() { let mut u = U; for _ in &mut u {} + //~^ explicit_into_iter_loop let mr = &mut u; for _ in &mut *mr {} + //~^ explicit_into_iter_loop // Issue #6900 struct S; diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs index 14630c07c5cc4..ca335b62d9068 100644 --- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.rs @@ -8,6 +8,7 @@ fn main() { for<'a> &'a T: IntoIterator, { for _ in iterator.into_iter() {} + //~^ explicit_into_iter_loop } struct T; @@ -21,9 +22,11 @@ fn main() { let mut t = T; for _ in t.into_iter() {} + //~^ explicit_into_iter_loop let r = &t; for _ in r.into_iter() {} + //~^ explicit_into_iter_loop // No suggestion for this. // We'd have to suggest `for _ in *rr {}` which is less clear. @@ -32,6 +35,7 @@ fn main() { let mr = &mut t; for _ in mr.into_iter() {} + //~^ explicit_into_iter_loop struct U; impl IntoIterator for &mut U { @@ -44,9 +48,11 @@ fn main() { let mut u = U; for _ in u.into_iter() {} + //~^ explicit_into_iter_loop let mr = &mut u; for _ in mr.into_iter() {} + //~^ explicit_into_iter_loop // Issue #6900 struct S; diff --git a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr index f0e2048e036f5..1c3156755d4ee 100644 --- a/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_into_iter_loop.stderr @@ -8,31 +8,31 @@ LL | for _ in iterator.into_iter() {} = help: to override `-D warnings` add `#[allow(clippy::explicit_into_iter_loop)]` error: it is more concise to loop over containers instead of using explicit iteration methods - --> tests/ui/explicit_into_iter_loop.rs:23:14 + --> tests/ui/explicit_into_iter_loop.rs:24:14 | LL | for _ in t.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t` error: it is more concise to loop over containers instead of using explicit iteration methods - --> tests/ui/explicit_into_iter_loop.rs:26:14 + --> tests/ui/explicit_into_iter_loop.rs:28:14 | LL | for _ in r.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `r` error: it is more concise to loop over containers instead of using explicit iteration methods - --> tests/ui/explicit_into_iter_loop.rs:34:14 + --> tests/ui/explicit_into_iter_loop.rs:37:14 | LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&*mr` error: it is more concise to loop over containers instead of using explicit iteration methods - --> tests/ui/explicit_into_iter_loop.rs:46:14 + --> tests/ui/explicit_into_iter_loop.rs:50:14 | LL | for _ in u.into_iter() {} | ^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut u` error: it is more concise to loop over containers instead of using explicit iteration methods - --> tests/ui/explicit_into_iter_loop.rs:49:14 + --> tests/ui/explicit_into_iter_loop.rs:54:14 | LL | for _ in mr.into_iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut *mr` diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed index 1148f0f6c6a63..cd0898dfc3672 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.fixed +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.fixed @@ -16,10 +16,13 @@ fn main() { let mut vec = vec![1, 2, 3, 4]; for _ in &vec {} + //~^ explicit_iter_loop for _ in &mut vec {} + //~^ explicit_iter_loop let rvec = &vec; for _ in rvec {} + //~^ explicit_iter_loop let rmvec = &mut vec; for _ in rmvec.iter() {} @@ -29,36 +32,48 @@ fn main() { for _ in &mut vec {} // these are fine for _ in &[1, 2, 3] {} + //~^ explicit_iter_loop for _ in (&mut [1, 2, 3]).iter() {} for _ in &[0; 32] {} + //~^ explicit_iter_loop for _ in &[0; 33] {} + //~^ explicit_iter_loop let ll: LinkedList<()> = LinkedList::new(); for _ in &ll {} + //~^ explicit_iter_loop let rll = ≪ for _ in rll {} + //~^ explicit_iter_loop let vd: VecDeque<()> = VecDeque::new(); for _ in &vd {} + //~^ explicit_iter_loop let rvd = &vd; for _ in rvd {} + //~^ explicit_iter_loop let bh: BinaryHeap<()> = BinaryHeap::new(); for _ in &bh {} + //~^ explicit_iter_loop let hm: HashMap<(), ()> = HashMap::new(); for _ in &hm {} + //~^ explicit_iter_loop let bt: BTreeMap<(), ()> = BTreeMap::new(); for _ in &bt {} + //~^ explicit_iter_loop let hs: HashSet<()> = HashSet::new(); for _ in &hs {} + //~^ explicit_iter_loop let bs: BTreeSet<()> = BTreeSet::new(); for _ in &bs {} + //~^ explicit_iter_loop struct NoIntoIter(); impl NoIntoIter { @@ -148,10 +163,13 @@ fn main() { } let mut x = CustomType; for _ in &x {} + //~^ explicit_iter_loop for _ in &mut x {} + //~^ explicit_iter_loop let r = &x; for _ in r {} + //~^ explicit_iter_loop } #[clippy::msrv = "1.79"] diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.rs b/src/tools/clippy/tests/ui/explicit_iter_loop.rs index 4dda2f13e5b83..02405280ce423 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.rs +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.rs @@ -16,10 +16,13 @@ fn main() { let mut vec = vec![1, 2, 3, 4]; for _ in vec.iter() {} + //~^ explicit_iter_loop for _ in vec.iter_mut() {} + //~^ explicit_iter_loop let rvec = &vec; for _ in rvec.iter() {} + //~^ explicit_iter_loop let rmvec = &mut vec; for _ in rmvec.iter() {} @@ -29,36 +32,48 @@ fn main() { for _ in &mut vec {} // these are fine for _ in [1, 2, 3].iter() {} + //~^ explicit_iter_loop for _ in (&mut [1, 2, 3]).iter() {} for _ in [0; 32].iter() {} + //~^ explicit_iter_loop for _ in [0; 33].iter() {} + //~^ explicit_iter_loop let ll: LinkedList<()> = LinkedList::new(); for _ in ll.iter() {} + //~^ explicit_iter_loop let rll = ≪ for _ in rll.iter() {} + //~^ explicit_iter_loop let vd: VecDeque<()> = VecDeque::new(); for _ in vd.iter() {} + //~^ explicit_iter_loop let rvd = &vd; for _ in rvd.iter() {} + //~^ explicit_iter_loop let bh: BinaryHeap<()> = BinaryHeap::new(); for _ in bh.iter() {} + //~^ explicit_iter_loop let hm: HashMap<(), ()> = HashMap::new(); for _ in hm.iter() {} + //~^ explicit_iter_loop let bt: BTreeMap<(), ()> = BTreeMap::new(); for _ in bt.iter() {} + //~^ explicit_iter_loop let hs: HashSet<()> = HashSet::new(); for _ in hs.iter() {} + //~^ explicit_iter_loop let bs: BTreeSet<()> = BTreeSet::new(); for _ in bs.iter() {} + //~^ explicit_iter_loop struct NoIntoIter(); impl NoIntoIter { @@ -148,10 +163,13 @@ fn main() { } let mut x = CustomType; for _ in x.iter() {} + //~^ explicit_iter_loop for _ in x.iter_mut() {} + //~^ explicit_iter_loop let r = &x; for _ in r.iter() {} + //~^ explicit_iter_loop } #[clippy::msrv = "1.79"] diff --git a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr index c646e61aa0456..3816bb4db98b3 100644 --- a/src/tools/clippy/tests/ui/explicit_iter_loop.stderr +++ b/src/tools/clippy/tests/ui/explicit_iter_loop.stderr @@ -11,103 +11,103 @@ LL | #![deny(clippy::explicit_iter_loop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:19:14 + --> tests/ui/explicit_iter_loop.rs:20:14 | LL | for _ in vec.iter_mut() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:22:14 + --> tests/ui/explicit_iter_loop.rs:24:14 | LL | for _ in rvec.iter() {} | ^^^^^^^^^^^ help: to write this more concisely, try: `rvec` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:31:14 + --> tests/ui/explicit_iter_loop.rs:34:14 | LL | for _ in [1, 2, 3].iter() {} | ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:35:14 + --> tests/ui/explicit_iter_loop.rs:39:14 | LL | for _ in [0; 32].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:36:14 + --> tests/ui/explicit_iter_loop.rs:41:14 | LL | for _ in [0; 33].iter() {} | ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 33]` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:39:14 + --> tests/ui/explicit_iter_loop.rs:45:14 | LL | for _ in ll.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&ll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:41:14 + --> tests/ui/explicit_iter_loop.rs:48:14 | LL | for _ in rll.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `rll` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:44:14 + --> tests/ui/explicit_iter_loop.rs:52:14 | LL | for _ in vd.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&vd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:46:14 + --> tests/ui/explicit_iter_loop.rs:55:14 | LL | for _ in rvd.iter() {} | ^^^^^^^^^^ help: to write this more concisely, try: `rvd` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:49:14 + --> tests/ui/explicit_iter_loop.rs:59:14 | LL | for _ in bh.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bh` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:52:14 + --> tests/ui/explicit_iter_loop.rs:63:14 | LL | for _ in hm.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hm` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:55:14 + --> tests/ui/explicit_iter_loop.rs:67:14 | LL | for _ in bt.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bt` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:58:14 + --> tests/ui/explicit_iter_loop.rs:71:14 | LL | for _ in hs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&hs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:61:14 + --> tests/ui/explicit_iter_loop.rs:75:14 | LL | for _ in bs.iter() {} | ^^^^^^^^^ help: to write this more concisely, try: `&bs` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:150:14 + --> tests/ui/explicit_iter_loop.rs:165:14 | LL | for _ in x.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `&x` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:151:14 + --> tests/ui/explicit_iter_loop.rs:167:14 | LL | for _ in x.iter_mut() {} | ^^^^^^^^^^^^ help: to write this more concisely, try: `&mut x` error: it is more concise to loop over references to containers instead of using explicit iteration methods - --> tests/ui/explicit_iter_loop.rs:154:14 + --> tests/ui/explicit_iter_loop.rs:171:14 | LL | for _ in r.iter() {} | ^^^^^^^^ help: to write this more concisely, try: `r` diff --git a/src/tools/clippy/tests/ui/explicit_write.fixed b/src/tools/clippy/tests/ui/explicit_write.fixed index 77a910dc1963a..024999fc609ee 100644 --- a/src/tools/clippy/tests/ui/explicit_write.fixed +++ b/src/tools/clippy/tests/ui/explicit_write.fixed @@ -21,23 +21,36 @@ fn main() { { use std::io::Write; print!("test"); + //~^ explicit_write eprint!("test"); + //~^ explicit_write println!("test"); + //~^ explicit_write eprintln!("test"); + //~^ explicit_write print!("test"); + //~^ explicit_write eprint!("test"); + //~^ explicit_write // including newlines println!("test\ntest"); + //~^ explicit_write eprintln!("test\ntest"); + //~^ explicit_write let value = 1; eprintln!("with {}", value); + //~^ explicit_write eprintln!("with {} {}", 2, value); + //~^ explicit_write eprintln!("with {value}"); + //~^ explicit_write eprintln!("macro arg {}", one!()); + //~^ explicit_write let width = 2; eprintln!("{:w$}", value, w = width); + //~^ explicit_write } // these should not warn, different destination { diff --git a/src/tools/clippy/tests/ui/explicit_write.rs b/src/tools/clippy/tests/ui/explicit_write.rs index c77956264f6db..c83c760d48c8b 100644 --- a/src/tools/clippy/tests/ui/explicit_write.rs +++ b/src/tools/clippy/tests/ui/explicit_write.rs @@ -21,23 +21,36 @@ fn main() { { use std::io::Write; write!(std::io::stdout(), "test").unwrap(); + //~^ explicit_write write!(std::io::stderr(), "test").unwrap(); + //~^ explicit_write writeln!(std::io::stdout(), "test").unwrap(); + //~^ explicit_write writeln!(std::io::stderr(), "test").unwrap(); + //~^ explicit_write std::io::stdout().write_fmt(format_args!("test")).unwrap(); + //~^ explicit_write std::io::stderr().write_fmt(format_args!("test")).unwrap(); + //~^ explicit_write // including newlines writeln!(std::io::stdout(), "test\ntest").unwrap(); + //~^ explicit_write writeln!(std::io::stderr(), "test\ntest").unwrap(); + //~^ explicit_write let value = 1; writeln!(std::io::stderr(), "with {}", value).unwrap(); + //~^ explicit_write writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap(); + //~^ explicit_write writeln!(std::io::stderr(), "with {value}").unwrap(); + //~^ explicit_write writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap(); + //~^ explicit_write let width = 2; writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap(); + //~^ explicit_write } // these should not warn, different destination { diff --git a/src/tools/clippy/tests/ui/explicit_write.stderr b/src/tools/clippy/tests/ui/explicit_write.stderr index 0d22f02c36f2e..670a0411b3107 100644 --- a/src/tools/clippy/tests/ui/explicit_write.stderr +++ b/src/tools/clippy/tests/ui/explicit_write.stderr @@ -8,73 +8,73 @@ LL | write!(std::io::stdout(), "test").unwrap(); = help: to override `-D warnings` add `#[allow(clippy::explicit_write)]` error: use of `write!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:24:9 + --> tests/ui/explicit_write.rs:25:9 | LL | write!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` - --> tests/ui/explicit_write.rs:25:9 + --> tests/ui/explicit_write.rs:27:9 | LL | writeln!(std::io::stdout(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test")` error: use of `writeln!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:26:9 + --> tests/ui/explicit_write.rs:29:9 | LL | writeln!(std::io::stderr(), "test").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test")` error: use of `stdout().write_fmt(...).unwrap()` - --> tests/ui/explicit_write.rs:27:9 + --> tests/ui/explicit_write.rs:31:9 | LL | std::io::stdout().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `print!("test")` error: use of `stderr().write_fmt(...).unwrap()` - --> tests/ui/explicit_write.rs:28:9 + --> tests/ui/explicit_write.rs:33:9 | LL | std::io::stderr().write_fmt(format_args!("test")).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprint!("test")` error: use of `writeln!(stdout(), ...).unwrap()` - --> tests/ui/explicit_write.rs:31:9 + --> tests/ui/explicit_write.rs:37:9 | LL | writeln!(std::io::stdout(), "test\ntest").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `println!("test\ntest")` error: use of `writeln!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:32:9 + --> tests/ui/explicit_write.rs:39:9 | LL | writeln!(std::io::stderr(), "test\ntest").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("test\ntest")` error: use of `writeln!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:35:9 + --> tests/ui/explicit_write.rs:43:9 | LL | writeln!(std::io::stderr(), "with {}", value).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {}", value)` error: use of `writeln!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:36:9 + --> tests/ui/explicit_write.rs:45:9 | LL | writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {} {}", 2, value)` error: use of `writeln!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:37:9 + --> tests/ui/explicit_write.rs:47:9 | LL | writeln!(std::io::stderr(), "with {value}").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("with {value}")` error: use of `writeln!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:38:9 + --> tests/ui/explicit_write.rs:49:9 | LL | writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("macro arg {}", one!())` error: use of `writeln!(stderr(), ...).unwrap()` - --> tests/ui/explicit_write.rs:40:9 + --> tests/ui/explicit_write.rs:52:9 | LL | writeln!(std::io::stderr(), "{:w$}", value, w = width).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `eprintln!("{:w$}", value, w = width)` diff --git a/src/tools/clippy/tests/ui/extend_with_drain.fixed b/src/tools/clippy/tests/ui/extend_with_drain.fixed index 856c1a42dafcd..7b314381e9a36 100644 --- a/src/tools/clippy/tests/ui/extend_with_drain.fixed +++ b/src/tools/clippy/tests/ui/extend_with_drain.fixed @@ -6,15 +6,18 @@ fn main() { let mut vec1 = vec![0u8; 1024]; let mut vec2: std::vec::Vec = Vec::new(); vec2.append(&mut vec1); + //~^ extend_with_drain let mut vec3 = vec![0u8; 1024]; let mut vec4: std::vec::Vec = Vec::new(); vec4.append(&mut vec3); + //~^ extend_with_drain let mut vec11: std::vec::Vec = Vec::new(); vec11.append(&mut return_vector()); + //~^ extend_with_drain //won't get linted it doesn't move the entire content of a vec into another let mut test1 = vec![0u8, 10]; @@ -46,6 +49,7 @@ fn main() { let ref_x = &mut x; let mut y = Vec::new(); y.append(ref_x); + //~^ extend_with_drain } fn return_vector() -> Vec { diff --git a/src/tools/clippy/tests/ui/extend_with_drain.rs b/src/tools/clippy/tests/ui/extend_with_drain.rs index 7d538097639f5..77214c053979d 100644 --- a/src/tools/clippy/tests/ui/extend_with_drain.rs +++ b/src/tools/clippy/tests/ui/extend_with_drain.rs @@ -6,15 +6,18 @@ fn main() { let mut vec1 = vec![0u8; 1024]; let mut vec2: std::vec::Vec = Vec::new(); vec2.extend(vec1.drain(..)); + //~^ extend_with_drain let mut vec3 = vec![0u8; 1024]; let mut vec4: std::vec::Vec = Vec::new(); vec4.extend(vec3.drain(..)); + //~^ extend_with_drain let mut vec11: std::vec::Vec = Vec::new(); vec11.extend(return_vector().drain(..)); + //~^ extend_with_drain //won't get linted it doesn't move the entire content of a vec into another let mut test1 = vec![0u8, 10]; @@ -46,6 +49,7 @@ fn main() { let ref_x = &mut x; let mut y = Vec::new(); y.extend(ref_x.drain(..)); + //~^ extend_with_drain } fn return_vector() -> Vec { diff --git a/src/tools/clippy/tests/ui/extend_with_drain.stderr b/src/tools/clippy/tests/ui/extend_with_drain.stderr index 444cc82bbae7c..2ee7aa7294e0e 100644 --- a/src/tools/clippy/tests/ui/extend_with_drain.stderr +++ b/src/tools/clippy/tests/ui/extend_with_drain.stderr @@ -8,19 +8,19 @@ LL | vec2.extend(vec1.drain(..)); = help: to override `-D warnings` add `#[allow(clippy::extend_with_drain)]` error: use of `extend` instead of `append` for adding the full range of a second vector - --> tests/ui/extend_with_drain.rs:13:5 + --> tests/ui/extend_with_drain.rs:14:5 | LL | vec4.extend(vec3.drain(..)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec4.append(&mut vec3)` error: use of `extend` instead of `append` for adding the full range of a second vector - --> tests/ui/extend_with_drain.rs:17:5 + --> tests/ui/extend_with_drain.rs:19:5 | LL | vec11.extend(return_vector().drain(..)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec11.append(&mut return_vector())` error: use of `extend` instead of `append` for adding the full range of a second vector - --> tests/ui/extend_with_drain.rs:48:5 + --> tests/ui/extend_with_drain.rs:51:5 | LL | y.extend(ref_x.drain(..)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `y.append(ref_x)` diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs index aa964af3fc2db..5fdcd5a7e0786 100644 --- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs +++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs @@ -17,6 +17,7 @@ fn empty() {} fn used_lt<'a>(x: &'a u8) {} fn unused_lt<'a>(x: u8) {} +//~^ extra_unused_lifetimes fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { // 'a is useless here since it's not directly bound @@ -44,6 +45,7 @@ struct Bar; impl Bar { fn x<'a>(&self) {} + //~^ extra_unused_lifetimes } // test for #489 (used lifetimes in bounds) @@ -70,6 +72,7 @@ impl X { mod issue4291 { trait BadTrait { fn unused_lt<'a>(x: u8) {} + //~^ extra_unused_lifetimes } impl BadTrait for () { @@ -81,13 +84,16 @@ mod issue6437 { pub struct Scalar; impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar { + //~^ extra_unused_lifetimes fn add_assign(&mut self, _rhs: &Scalar) { unimplemented!(); } } impl<'b> Scalar { + //~^ extra_unused_lifetimes pub fn something<'c>() -> Self { + //~^ extra_unused_lifetimes Self } } @@ -117,6 +123,7 @@ mod second_case { // Should lint. The response to the above comment incorrectly called this a false positive. The // lifetime `'a` can be removed, as demonstrated below. impl<'a, T: Source + ?Sized + 'a> Source for Box { + //~^ extra_unused_lifetimes fn hey() {} } diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr index 85fbb7568ff4c..0cecbbe80f763 100644 --- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr @@ -8,37 +8,37 @@ LL | fn unused_lt<'a>(x: u8) {} = help: to override `-D warnings` add `#[allow(clippy::extra_unused_lifetimes)]` error: this lifetime isn't used in the function definition - --> tests/ui/extra_unused_lifetimes.rs:46:10 + --> tests/ui/extra_unused_lifetimes.rs:47:10 | LL | fn x<'a>(&self) {} | ^^ error: this lifetime isn't used in the function definition - --> tests/ui/extra_unused_lifetimes.rs:72:22 + --> tests/ui/extra_unused_lifetimes.rs:74:22 | LL | fn unused_lt<'a>(x: u8) {} | ^^ error: this lifetime isn't used in the impl - --> tests/ui/extra_unused_lifetimes.rs:83:10 + --> tests/ui/extra_unused_lifetimes.rs:86:10 | LL | impl<'a> std::ops::AddAssign<&Scalar> for &mut Scalar { | ^^ error: this lifetime isn't used in the impl - --> tests/ui/extra_unused_lifetimes.rs:89:10 + --> tests/ui/extra_unused_lifetimes.rs:93:10 | LL | impl<'b> Scalar { | ^^ error: this lifetime isn't used in the function definition - --> tests/ui/extra_unused_lifetimes.rs:90:26 + --> tests/ui/extra_unused_lifetimes.rs:95:26 | LL | pub fn something<'c>() -> Self { | ^^ error: this lifetime isn't used in the impl - --> tests/ui/extra_unused_lifetimes.rs:119:10 + --> tests/ui/extra_unused_lifetimes.rs:125:10 | LL | impl<'a, T: Source + ?Sized + 'a> Source for Box { | ^^ diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed b/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed index c9bebabdf17ae..32d4f6c693909 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed @@ -7,14 +7,17 @@ extern crate proc_macros; use proc_macros::with_span; fn unused_ty(x: u8) { + //~^ extra_unused_type_parameters unimplemented!() } fn unused_multi(x: u8) { + //~^ extra_unused_type_parameters unimplemented!() } fn unused_with_lt<'a>(x: &'a u8) { + //~^ extra_unused_type_parameters unimplemented!() } @@ -27,10 +30,12 @@ fn used_ret(x: u8) -> T { } fn unused_bounded(x: U) { + //~^ extra_unused_type_parameters unimplemented!(); } fn some_unused(b: B, c: C) { + //~^ extra_unused_type_parameters unimplemented!(); } @@ -56,6 +61,7 @@ struct S; impl S { fn unused_ty_impl(&self) { + //~^ extra_unused_type_parameters unimplemented!() } } @@ -78,6 +84,7 @@ where } fn unused_opaque(dummy: impl Default) { + //~^ extra_unused_type_parameters unimplemented!() } @@ -91,6 +98,7 @@ mod unexported_trait_bounds { } fn unused_with_priv_trait_bound() { + //~^ extra_unused_type_parameters unimplemented!(); } } diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs index 1bc0047adf01f..c1e6f32ca12f1 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs @@ -7,14 +7,17 @@ extern crate proc_macros; use proc_macros::with_span; fn unused_ty(x: u8) { + //~^ extra_unused_type_parameters unimplemented!() } fn unused_multi(x: u8) { + //~^ extra_unused_type_parameters unimplemented!() } fn unused_with_lt<'a, T>(x: &'a u8) { + //~^ extra_unused_type_parameters unimplemented!() } @@ -27,10 +30,12 @@ fn used_ret(x: u8) -> T { } fn unused_bounded(x: U) { + //~^ extra_unused_type_parameters unimplemented!(); } fn some_unused, E>(b: B, c: C) { + //~^ extra_unused_type_parameters unimplemented!(); } @@ -56,6 +61,7 @@ struct S; impl S { fn unused_ty_impl(&self) { + //~^ extra_unused_type_parameters unimplemented!() } } @@ -78,6 +84,7 @@ where } fn unused_opaque(dummy: impl Default) { + //~^ extra_unused_type_parameters unimplemented!() } @@ -91,6 +98,7 @@ mod unexported_trait_bounds { } fn unused_with_priv_trait_bound() { + //~^ extra_unused_type_parameters unimplemented!(); } } diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr index 928c0038c2c3d..5086826ae5c06 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr @@ -8,19 +8,19 @@ LL | fn unused_ty(x: u8) { = help: to override `-D warnings` add `#[allow(clippy::extra_unused_type_parameters)]` error: type parameters go unused in function definition: T, U - --> tests/ui/extra_unused_type_parameters.rs:13:16 + --> tests/ui/extra_unused_type_parameters.rs:14:16 | LL | fn unused_multi(x: u8) { | ^^^^^^ help: consider removing the parameters error: type parameter `T` goes unused in function definition - --> tests/ui/extra_unused_type_parameters.rs:17:21 + --> tests/ui/extra_unused_type_parameters.rs:19:21 | LL | fn unused_with_lt<'a, T>(x: &'a u8) { | ^^^ help: consider removing the parameter error: type parameters go unused in function definition: T, V - --> tests/ui/extra_unused_type_parameters.rs:29:19 + --> tests/ui/extra_unused_type_parameters.rs:32:19 | LL | fn unused_bounded(x: U) { | ^^^^^^^^^^^^ ^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL + fn unused_bounded(x: U) { | error: type parameters go unused in function definition: A, D, E - --> tests/ui/extra_unused_type_parameters.rs:33:16 + --> tests/ui/extra_unused_type_parameters.rs:37:16 | LL | fn some_unused, E>(b: B, c: C) { | ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,19 +44,19 @@ LL + fn some_unused(b: B, c: C) { | error: type parameter `T` goes unused in function definition - --> tests/ui/extra_unused_type_parameters.rs:58:22 + --> tests/ui/extra_unused_type_parameters.rs:63:22 | LL | fn unused_ty_impl(&self) { | ^^^ help: consider removing the parameter error: type parameters go unused in function definition: A, B - --> tests/ui/extra_unused_type_parameters.rs:80:17 + --> tests/ui/extra_unused_type_parameters.rs:86:17 | LL | fn unused_opaque(dummy: impl Default) { | ^^^^^^ help: consider removing the parameters error: type parameter `U` goes unused in function definition - --> tests/ui/extra_unused_type_parameters.rs:93:56 + --> tests/ui/extra_unused_type_parameters.rs:100:56 | LL | fn unused_with_priv_trait_bound() { | ^^^ help: consider removing the parameter diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.rs b/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.rs index 65b53eb2e4b3a..87ce517a0a451 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.rs +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters_unfixable.rs @@ -1,7 +1,7 @@ #![warn(clippy::extra_unused_type_parameters)] fn unused_where_clause(x: U) -//~^ ERROR: type parameter `T` goes unused in function definition +//~^ extra_unused_type_parameters where T: Default, { @@ -9,7 +9,7 @@ where } fn unused_multi_where_clause(x: U) -//~^ ERROR: type parameters go unused in function definition: T, V +//~^ extra_unused_type_parameters where T: Default, { @@ -17,7 +17,7 @@ where } fn unused_all_where_clause() -//~^ ERROR: type parameters go unused in function definition: T, U, V +//~^ extra_unused_type_parameters where T: Default, { diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.rs b/src/tools/clippy/tests/ui/fallible_impl_from.rs index a81e51fcac75a..1c62c1e937b63 100644 --- a/src/tools/clippy/tests/ui/fallible_impl_from.rs +++ b/src/tools/clippy/tests/ui/fallible_impl_from.rs @@ -4,7 +4,8 @@ // docs example struct Foo(i32); impl From for Foo { - //~^ ERROR: consider implementing `TryFrom` instead + //~^ fallible_impl_from + fn from(s: String) -> Self { Foo(s.parse().unwrap()) } @@ -26,7 +27,8 @@ impl From for Valid { struct Invalid; impl From for Invalid { - //~^ ERROR: consider implementing `TryFrom` instead + //~^ fallible_impl_from + fn from(i: usize) -> Invalid { if i != 42 { panic!(); @@ -36,7 +38,8 @@ impl From for Invalid { } impl From> for Invalid { - //~^ ERROR: consider implementing `TryFrom` instead + //~^ fallible_impl_from + fn from(s: Option) -> Invalid { let s = s.unwrap(); if !s.is_empty() { @@ -55,7 +58,8 @@ impl ProjStrTrait for Box { type ProjString = String; } impl<'a> From<&'a mut as ProjStrTrait>::ProjString> for Invalid { - //~^ ERROR: consider implementing `TryFrom` instead + //~^ fallible_impl_from + fn from(s: &'a mut as ProjStrTrait>::ProjString) -> Invalid { if s.parse::().ok().unwrap() != 42 { panic!("{:?}", s); diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.stderr b/src/tools/clippy/tests/ui/fallible_impl_from.stderr index cc3739031b76e..402494b39f30b 100644 --- a/src/tools/clippy/tests/ui/fallible_impl_from.stderr +++ b/src/tools/clippy/tests/ui/fallible_impl_from.stderr @@ -3,15 +3,15 @@ error: consider implementing `TryFrom` instead | LL | / impl From for Foo { LL | | +LL | | LL | | fn from(s: String) -> Self { -LL | | Foo(s.parse().unwrap()) -LL | | } +... | LL | | } | |_^ | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> tests/ui/fallible_impl_from.rs:9:13 + --> tests/ui/fallible_impl_from.rs:10:13 | LL | Foo(s.parse().unwrap()) | ^^^^^^^^^^^^^^^^^^ @@ -22,38 +22,37 @@ LL | #![deny(clippy::fallible_impl_from)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider implementing `TryFrom` instead - --> tests/ui/fallible_impl_from.rs:28:1 + --> tests/ui/fallible_impl_from.rs:29:1 | LL | / impl From for Invalid { LL | | +LL | | LL | | fn from(i: usize) -> Invalid { -LL | | if i != 42 { ... | LL | | } | |_^ | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> tests/ui/fallible_impl_from.rs:32:13 + --> tests/ui/fallible_impl_from.rs:34:13 | LL | panic!(); | ^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> tests/ui/fallible_impl_from.rs:38:1 + --> tests/ui/fallible_impl_from.rs:40:1 | LL | / impl From> for Invalid { LL | | +LL | | LL | | fn from(s: Option) -> Invalid { -LL | | let s = s.unwrap(); ... | LL | | } | |_^ | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> tests/ui/fallible_impl_from.rs:41:17 + --> tests/ui/fallible_impl_from.rs:44:17 | LL | let s = s.unwrap(); | ^^^^^^^^^^ @@ -64,28 +63,26 @@ LL | } else if s.parse::().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); | ^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: consider implementing `TryFrom` instead - --> tests/ui/fallible_impl_from.rs:57:1 + --> tests/ui/fallible_impl_from.rs:60:1 | LL | / impl<'a> From<&'a mut as ProjStrTrait>::ProjString> for Invalid { LL | | +LL | | LL | | fn from(s: &'a mut as ProjStrTrait>::ProjString) -> Invalid { -LL | | if s.parse::().ok().unwrap() != 42 { ... | LL | | } | |_^ | = help: `From` is intended for infallible conversions only. Use `TryFrom` if there's a possibility for the conversion to fail note: potential failure(s) - --> tests/ui/fallible_impl_from.rs:60:12 + --> tests/ui/fallible_impl_from.rs:64:12 | LL | if s.parse::().ok().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); | ^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs index 2a432751952d0..f3179b78ecb7e 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs @@ -55,6 +55,7 @@ fn main() { // wrong, produces first error in stderr let mut a: A = Default::default(); a.i = 42; + //~^ field_reassign_with_default // right let mut a: A = Default::default(); @@ -95,17 +96,20 @@ fn main() { // wrong, produces second error in stderr let mut a: A = Default::default(); a.j = 43; + //~^ field_reassign_with_default a.i = 42; // wrong, produces third error in stderr let mut a: A = Default::default(); a.i = 42; + //~^ field_reassign_with_default a.j = 43; a.j = 44; // wrong, produces fourth error in stderr let mut a = A::default(); a.i = 42; + //~^ field_reassign_with_default // wrong, but does not produce an error in stderr, because we can't produce a correct kind of // suggestion with current implementation @@ -116,10 +120,12 @@ fn main() { // wrong, produces the fifth error in stderr let mut a: A = Default::default(); a.i = Default::default(); + //~^ field_reassign_with_default // wrong, produces the sixth error in stderr let mut a: A = Default::default(); a.i = Default::default(); + //~^ field_reassign_with_default a.j = 45; // right, because an assignment refers to another field @@ -142,6 +148,7 @@ fn main() { // don't expand macros in the suggestion (#6522) let mut a: C = C::default(); a.i = vec![1]; + //~^ field_reassign_with_default // Don't lint in external macros external! { @@ -160,9 +167,11 @@ fn main() { // be sure suggestion is correct with generics let mut a: Wrapper = Default::default(); a.i = true; + //~^ field_reassign_with_default let mut a: WrapperMulti = Default::default(); a.i = 42; + //~^ field_reassign_with_default // Don't lint in macros inline!( @@ -234,6 +243,7 @@ mod issue6312 { fn new(name: &str) -> Self { let mut f = ImplDropAllCopy::default(); f.name = name.len(); + //~^ field_reassign_with_default f } fn close(&self) {} @@ -250,6 +260,7 @@ mod issue6312 { fn new(name: &str) -> Self { let mut f = NoDropAllCopy::default(); f.name = name.len(); + //~^ field_reassign_with_default f } } diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr index ae909475c6f2c..19382e671510a 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.stderr +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.stderr @@ -13,121 +13,121 @@ LL | let mut a: A = Default::default(); = help: to override `-D warnings` add `#[allow(clippy::field_reassign_with_default)]` error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:97:5 + --> tests/ui/field_reassign_with_default.rs:98:5 | LL | a.j = 43; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { j: 43, i: 42 }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:96:5 + --> tests/ui/field_reassign_with_default.rs:97:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:102:5 + --> tests/ui/field_reassign_with_default.rs:104:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, j: 44 }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:101:5 + --> tests/ui/field_reassign_with_default.rs:103:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:108:5 + --> tests/ui/field_reassign_with_default.rs:111:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `main::A { i: 42, ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:107:5 + --> tests/ui/field_reassign_with_default.rs:110:5 | LL | let mut a = A::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:118:5 + --> tests/ui/field_reassign_with_default.rs:122:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:117:5 + --> tests/ui/field_reassign_with_default.rs:121:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:122:5 + --> tests/ui/field_reassign_with_default.rs:127:5 | LL | a.i = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `main::A { i: Default::default(), j: 45 }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:121:5 + --> tests/ui/field_reassign_with_default.rs:126:5 | LL | let mut a: A = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:144:5 + --> tests/ui/field_reassign_with_default.rs:150:5 | LL | a.i = vec![1]; | ^^^^^^^^^^^^^^ | note: consider initializing the variable with `C { i: vec![1], ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:143:5 + --> tests/ui/field_reassign_with_default.rs:149:5 | LL | let mut a: C = C::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:162:5 + --> tests/ui/field_reassign_with_default.rs:169:5 | LL | a.i = true; | ^^^^^^^^^^^ | note: consider initializing the variable with `Wrapper:: { i: true }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:161:5 + --> tests/ui/field_reassign_with_default.rs:168:5 | LL | let mut a: Wrapper = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:165:5 + --> tests/ui/field_reassign_with_default.rs:173:5 | LL | a.i = 42; | ^^^^^^^^^ | note: consider initializing the variable with `WrapperMulti:: { i: 42, ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:164:5 + --> tests/ui/field_reassign_with_default.rs:172:5 | LL | let mut a: WrapperMulti = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:236:13 + --> tests/ui/field_reassign_with_default.rs:245:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::ImplDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:235:13 + --> tests/ui/field_reassign_with_default.rs:244:13 | LL | let mut f = ImplDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: field assignment outside of initializer for an instance created with Default::default() - --> tests/ui/field_reassign_with_default.rs:252:13 + --> tests/ui/field_reassign_with_default.rs:262:13 | LL | f.name = name.len(); | ^^^^^^^^^^^^^^^^^^^^ | note: consider initializing the variable with `issue6312::NoDropAllCopy { name: name.len(), ..Default::default() }` and removing relevant reassignments - --> tests/ui/field_reassign_with_default.rs:251:13 + --> tests/ui/field_reassign_with_default.rs:261:13 | LL | let mut f = NoDropAllCopy::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs index 5789dbf9b1d72..159cabad1b437 100644 --- a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs +++ b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.rs @@ -7,8 +7,11 @@ pub mod pub_module { private_field: bool, pub pub_field: bool, pub(crate) pub_crate_field: bool, + //~^ field_scoped_visibility_modifiers pub(in crate::pub_module) pub_in_path_field: bool, + //~^ field_scoped_visibility_modifiers pub(super) pub_super_field: bool, + //~^ field_scoped_visibility_modifiers #[allow(clippy::needless_pub_self)] pub(self) pub_self_field: bool, } diff --git a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr index beea6c92107c7..c0c202fd87af7 100644 --- a/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr +++ b/src/tools/clippy/tests/ui/field_scoped_visibility_modifiers.stderr @@ -9,7 +9,7 @@ LL | pub(crate) pub_crate_field: bool, = help: to override `-D warnings` add `#[allow(clippy::field_scoped_visibility_modifiers)]` error: scoped visibility modifier on a field - --> tests/ui/field_scoped_visibility_modifiers.rs:10:9 + --> tests/ui/field_scoped_visibility_modifiers.rs:11:9 | LL | pub(in crate::pub_module) pub_in_path_field: bool, | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pub(in crate::pub_module) pub_in_path_field: bool, = help: consider making the field private and adding a scoped visibility method for it error: scoped visibility modifier on a field - --> tests/ui/field_scoped_visibility_modifiers.rs:11:9 + --> tests/ui/field_scoped_visibility_modifiers.rs:13:9 | LL | pub(super) pub_super_field: bool, | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/filetype_is_file.rs b/src/tools/clippy/tests/ui/filetype_is_file.rs index 9e8a4c04324b0..8ca01b91210fb 100644 --- a/src/tools/clippy/tests/ui/filetype_is_file.rs +++ b/src/tools/clippy/tests/ui/filetype_is_file.rs @@ -7,19 +7,22 @@ fn main() -> std::io::Result<()> { // !filetype.is_dir() if fs::metadata("foo.txt")?.file_type().is_file() { - //~^ ERROR: `FileType::is_file()` only covers regular files + //~^ filetype_is_file + // read file } // positive of filetype.is_dir() if !fs::metadata("foo.txt")?.file_type().is_file() { - //~^ ERROR: `!FileType::is_file()` only denies regular files + //~^ filetype_is_file + // handle dir } // false positive of filetype.is_dir() if !fs::metadata("foo.txt")?.file_type().is_file().bitor(true) { - //~^ ERROR: `FileType::is_file()` only covers regular files + //~^ filetype_is_file + // ... } diff --git a/src/tools/clippy/tests/ui/filetype_is_file.stderr b/src/tools/clippy/tests/ui/filetype_is_file.stderr index 0c66910c1b616..b930ac929748c 100644 --- a/src/tools/clippy/tests/ui/filetype_is_file.stderr +++ b/src/tools/clippy/tests/ui/filetype_is_file.stderr @@ -9,7 +9,7 @@ LL | if fs::metadata("foo.txt")?.file_type().is_file() { = help: to override `-D warnings` add `#[allow(clippy::filetype_is_file)]` error: `!FileType::is_file()` only denies regular files - --> tests/ui/filetype_is_file.rs:15:8 + --> tests/ui/filetype_is_file.rs:16:8 | LL | if !fs::metadata("foo.txt")?.file_type().is_file() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | if !fs::metadata("foo.txt")?.file_type().is_file() { = help: use `FileType::is_dir()` instead error: `FileType::is_file()` only covers regular files - --> tests/ui/filetype_is_file.rs:21:9 + --> tests/ui/filetype_is_file.rs:23:9 | LL | if !fs::metadata("foo.txt")?.file_type().is_file().bitor(true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed index 6a1b81fdbcbe8..b3e112f19eb4a 100644 --- a/src/tools/clippy/tests/ui/filter_map_bool_then.fixed +++ b/src/tools/clippy/tests/ui/filter_map_bool_then.fixed @@ -17,24 +17,30 @@ struct NonCopy; fn main() { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1); + //~^ filter_map_bool_then v.clone().into_iter().filter(|&i| (i % 2 == 0)).map(|i| i + 1); + //~^ filter_map_bool_then v.clone() .into_iter() .filter(|&i| (i % 2 == 0)).map(|i| i + 1); + //~^ filter_map_bool_then v.clone() .into_iter() .filter(|&i| i != 1000) .filter(|&i| (i % 2 == 0)).map(|i| i + 1); + //~^ filter_map_bool_then v.iter() .copied() .filter(|&i| i != 1000) .filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1); + //~^ filter_map_bool_then // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`, // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`), // we can lint this and still get the same input type. // See: let v = vec![NonCopy, NonCopy]; v.clone().iter().filter(|&i| (i == &NonCopy)).map(|i| i); + //~^ filter_map_bool_then // Do not lint let v = vec![NonCopy, NonCopy]; v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i)); @@ -59,14 +65,17 @@ fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str fn issue11503() { let bools: &[bool] = &[true, false, false, true]; let _: Vec = bools.iter().enumerate().filter(|&(i, b)| *b).map(|(i, b)| i).collect(); + //~^ filter_map_bool_then // Need to insert multiple derefs if there is more than one layer of references let bools: &[&&bool] = &[&&true, &&false, &&false, &&true]; let _: Vec = bools.iter().enumerate().filter(|&(i, b)| ***b).map(|(i, b)| i).collect(); + //~^ filter_map_bool_then // Should also suggest derefs when going through a mutable reference let bools: &[&mut bool] = &[&mut true]; let _: Vec = bools.iter().enumerate().filter(|&(i, b)| **b).map(|(i, b)| i).collect(); + //~^ filter_map_bool_then // Should also suggest derefs when going through a custom deref struct DerefToBool; @@ -78,4 +87,5 @@ fn issue11503() { } let bools: &[&&DerefToBool] = &[&&DerefToBool]; let _: Vec = bools.iter().enumerate().filter(|&(i, b)| ****b).map(|(i, b)| i).collect(); + //~^ filter_map_bool_then } diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.rs b/src/tools/clippy/tests/ui/filter_map_bool_then.rs index a41e88f8805de..d996b3cb3c52a 100644 --- a/src/tools/clippy/tests/ui/filter_map_bool_then.rs +++ b/src/tools/clippy/tests/ui/filter_map_bool_then.rs @@ -17,24 +17,30 @@ struct NonCopy; fn main() { let v = vec![1, 2, 3, 4, 5, 6]; v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + //~^ filter_map_bool_then v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); + //~^ filter_map_bool_then v.clone() .into_iter() .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) }); + //~^ filter_map_bool_then v.clone() .into_iter() .filter(|&i| i != 1000) .filter_map(|i| (i % 2 == 0).then(|| i + 1)); + //~^ filter_map_bool_then v.iter() .copied() .filter(|&i| i != 1000) .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); + //~^ filter_map_bool_then // Despite this is non-copy, `is_copy` still returns true (at least now) because it's `&NonCopy`, // and any `&` is `Copy`. So since we can dereference it in `filter` (since it's then `&&NonCopy`), // we can lint this and still get the same input type. // See: let v = vec![NonCopy, NonCopy]; v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); + //~^ filter_map_bool_then // Do not lint let v = vec![NonCopy, NonCopy]; v.clone().into_iter().filter_map(|i| (i == NonCopy).then(|| i)); @@ -59,14 +65,17 @@ fn issue11309<'a>(iter: impl Iterator) -> Vec<&'a str fn issue11503() { let bools: &[bool] = &[true, false, false, true]; let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + //~^ filter_map_bool_then // Need to insert multiple derefs if there is more than one layer of references let bools: &[&&bool] = &[&&true, &&false, &&false, &&true]; let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + //~^ filter_map_bool_then // Should also suggest derefs when going through a mutable reference let bools: &[&mut bool] = &[&mut true]; let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + //~^ filter_map_bool_then // Should also suggest derefs when going through a custom deref struct DerefToBool; @@ -78,4 +87,5 @@ fn issue11503() { } let bools: &[&&DerefToBool] = &[&&DerefToBool]; let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); + //~^ filter_map_bool_then } diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr index 088b9ba128675..aeb1baeb35e6e 100644 --- a/src/tools/clippy/tests/ui/filter_map_bool_then.stderr +++ b/src/tools/clippy/tests/ui/filter_map_bool_then.stderr @@ -8,55 +8,55 @@ LL | v.clone().iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:20:27 + --> tests/ui/filter_map_bool_then.rs:21:27 | LL | v.clone().into_iter().filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:23:10 + --> tests/ui/filter_map_bool_then.rs:25:10 | LL | .filter_map(|i| -> Option<_> { (i % 2 == 0).then(|| i + 1) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:27:10 + --> tests/ui/filter_map_bool_then.rs:30:10 | LL | .filter_map(|i| (i % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:31:10 + --> tests/ui/filter_map_bool_then.rs:35:10 | LL | .filter_map(|i| (i.clone() % 2 == 0).then(|| i + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i.clone() % 2 == 0)).map(|i| i + 1)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:37:22 + --> tests/ui/filter_map_bool_then.rs:42:22 | LL | v.clone().iter().filter_map(|i| (i == &NonCopy).then(|| i)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&i| (i == &NonCopy)).map(|i| i)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:61:50 + --> tests/ui/filter_map_bool_then.rs:67:50 | LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| *b).map(|(i, b)| i)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:65:50 + --> tests/ui/filter_map_bool_then.rs:72:50 | LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| ***b).map(|(i, b)| i)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:69:50 + --> tests/ui/filter_map_bool_then.rs:77:50 | LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| **b).map(|(i, b)| i)` error: usage of `bool::then` in `filter_map` - --> tests/ui/filter_map_bool_then.rs:80:50 + --> tests/ui/filter_map_bool_then.rs:89:50 | LL | let _: Vec = bools.iter().enumerate().filter_map(|(i, b)| b.then(|| i)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `filter` then `map` instead: `filter(|&(i, b)| ****b).map(|(i, b)| i)` diff --git a/src/tools/clippy/tests/ui/filter_map_identity.fixed b/src/tools/clippy/tests/ui/filter_map_identity.fixed index fdd020fcd7738..c9e2c5f5049f3 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.fixed +++ b/src/tools/clippy/tests/ui/filter_map_identity.fixed @@ -26,59 +26,75 @@ fn main() { { // into_iter copy_vec_non_inferred().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity non_copy_vec().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity non_copy_vec().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity // we are forced to pass the type in the call. copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + #[rustfmt::skip] copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity + #[rustfmt::skip] copy_vec::().into_iter().flatten(); - //~^ ERROR: use of + //~^ filter_map_identity // 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 + //~^ filter_map_identity } } diff --git a/src/tools/clippy/tests/ui/filter_map_identity.rs b/src/tools/clippy/tests/ui/filter_map_identity.rs index a626de9f5bbd8..4c8d48f5221f1 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.rs +++ b/src/tools/clippy/tests/ui/filter_map_identity.rs @@ -26,59 +26,75 @@ fn main() { { // into_iter copy_vec_non_inferred().into_iter().filter_map(|x| x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().filter_map(std::convert::identity); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().filter_map(identity); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().filter_map(|x| return x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec_non_inferred().into_iter().filter_map(|x| return x); - //~^ ERROR: use of + //~^ filter_map_identity non_copy_vec().into_iter().filter_map(|x| x); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().filter_map(|x| x); - //~^ ERROR: use of + //~^ filter_map_identity non_copy_vec().into_iter().filter_map(std::convert::identity); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().filter_map(identity); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().filter_map(|x| return x); - //~^ ERROR: use of + //~^ filter_map_identity + non_copy_vec().into_iter().filter_map(|x| return x); - //~^ ERROR: use of + //~^ filter_map_identity copy_vec::().into_iter().filter_map(|x: Option<_>| x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().filter_map(|x: Option<_>| x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().filter_map(|x: Option<_>| return x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().filter_map(|x: Option<_>| return x); - //~^ ERROR: use of + //~^ filter_map_identity // we are forced to pass the type in the call. copy_vec::().into_iter().filter_map(|x: Option| x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().filter_map(|x: Option| x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().filter_map(|x: Option| return x); - //~^ ERROR: use of + //~^ filter_map_identity + copy_vec::().into_iter().filter_map(|x: Option| return x); - //~^ ERROR: use of + //~^ filter_map_identity + #[rustfmt::skip] copy_vec::().into_iter().filter_map(|x: Option| -> Option {{ x }}); - //~^ ERROR: use of + //~^ filter_map_identity + #[rustfmt::skip] copy_vec::().into_iter().filter_map(|x: Option| -> Option {{ return x }}); - //~^ ERROR: use of + //~^ filter_map_identity // 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 + //~^ filter_map_identity } } diff --git a/src/tools/clippy/tests/ui/filter_map_identity.stderr b/src/tools/clippy/tests/ui/filter_map_identity.stderr index 55068db4e9d03..26b6e0bc7b343 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.stderr +++ b/src/tools/clippy/tests/ui/filter_map_identity.stderr @@ -8,127 +8,127 @@ LL | copy_vec_non_inferred().into_iter().filter_map(|x| x); = 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:30:45 + --> tests/ui/filter_map_identity.rs:31:45 | 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:32:45 + --> tests/ui/filter_map_identity.rs:34:45 | 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:34:45 + --> tests/ui/filter_map_identity.rs:37: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:36:45 + --> tests/ui/filter_map_identity.rs:40: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 + --> tests/ui/filter_map_identity.rs:43: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 + --> tests/ui/filter_map_identity.rs:46: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 + --> tests/ui/filter_map_identity.rs:49: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 + --> tests/ui/filter_map_identity.rs:52: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 + --> tests/ui/filter_map_identity.rs:55: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 + --> tests/ui/filter_map_identity.rs:58: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 + --> tests/ui/filter_map_identity.rs:61: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 + --> tests/ui/filter_map_identity.rs:64: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 + --> 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:59:39 + --> tests/ui/filter_map_identity.rs:70: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 + --> tests/ui/filter_map_identity.rs:74: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 + --> tests/ui/filter_map_identity.rs:77: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 + --> tests/ui/filter_map_identity.rs:80: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 + --> tests/ui/filter_map_identity.rs:83: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 + --> tests/ui/filter_map_identity.rs:87: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 + --> tests/ui/filter_map_identity.rs:91: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 + --> tests/ui/filter_map_identity.rs:96:37 | LL | opaque::().into_iter().filter_map(|x| x); | ^^^^^^^^^^^^^^^^^ help: try: `flatten()` diff --git a/src/tools/clippy/tests/ui/filter_map_next.rs b/src/tools/clippy/tests/ui/filter_map_next.rs index 9077b8fca23e2..2a2237ed16cf2 100644 --- a/src/tools/clippy/tests/ui/filter_map_next.rs +++ b/src/tools/clippy/tests/ui/filter_map_next.rs @@ -5,8 +5,9 @@ fn main() { #[rustfmt::skip] let _: Option = vec![1, 2, 3, 4, 5, 6] - //~^ ERROR: called `filter_map(..).next()` on an `Iterator`. This is more succinctly e - //~| NOTE: `-D clippy::filter-map-next` implied by `-D warnings` + //~^ filter_map_next + + .into_iter() .filter_map(|x| { if x == 2 { diff --git a/src/tools/clippy/tests/ui/filter_map_next.stderr b/src/tools/clippy/tests/ui/filter_map_next.stderr index cd3ffe3aa7f01..974bb946d46af 100644 --- a/src/tools/clippy/tests/ui/filter_map_next.stderr +++ b/src/tools/clippy/tests/ui/filter_map_next.stderr @@ -3,9 +3,6 @@ error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly | LL | let _: Option = vec![1, 2, 3, 4, 5, 6] | __________________________^ -LL | | -LL | | -LL | | .into_iter() ... | LL | | }) LL | | .next(); diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed index 193ac3aea433f..285863ef340db 100644 --- a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed +++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed @@ -5,6 +5,7 @@ fn main() { let a = ["1", "lol", "3", "NaN", "5"]; let element: Option = a.iter().find_map(|s| s.parse().ok()); + //~^ filter_map_next assert_eq!(element, Some(1)); } @@ -18,4 +19,5 @@ fn msrv_1_29() { fn msrv_1_30() { let a = ["1", "lol", "3", "NaN", "5"]; let _: Option = a.iter().find_map(|s| s.parse().ok()); + //~^ filter_map_next } diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs index dab8d289817e8..af911689b7c72 100644 --- a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs +++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs @@ -5,6 +5,7 @@ fn main() { let a = ["1", "lol", "3", "NaN", "5"]; let element: Option = a.iter().filter_map(|s| s.parse().ok()).next(); + //~^ filter_map_next assert_eq!(element, Some(1)); } @@ -18,4 +19,5 @@ fn msrv_1_29() { fn msrv_1_30() { let a = ["1", "lol", "3", "NaN", "5"]; let _: Option = a.iter().filter_map(|s| s.parse().ok()).next(); + //~^ filter_map_next } diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr index 2c6148f3f4b6b..707dec8687b1f 100644 --- a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr +++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr @@ -8,7 +8,7 @@ LL | let element: Option = a.iter().filter_map(|s| s.parse().ok()).next = help: to override `-D warnings` add `#[allow(clippy::filter_map_next)]` error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead - --> tests/ui/filter_map_next_fixable.rs:20:26 + --> tests/ui/filter_map_next_fixable.rs:21:26 | LL | let _: Option = a.iter().filter_map(|s| s.parse().ok()).next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())` diff --git a/src/tools/clippy/tests/ui/find_map.rs b/src/tools/clippy/tests/ui/find_map.rs index bbd395d50ef22..aba1f2cbe581e 100644 --- a/src/tools/clippy/tests/ui/find_map.rs +++ b/src/tools/clippy/tests/ui/find_map.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::useless_vec)] diff --git a/src/tools/clippy/tests/ui/flat_map_identity.fixed b/src/tools/clippy/tests/ui/flat_map_identity.fixed index c142cf719808a..f62062326126f 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.fixed +++ b/src/tools/clippy/tests/ui/flat_map_identity.fixed @@ -6,10 +6,13 @@ use std::convert; fn main() { let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flatten(); + //~^ flat_map_identity let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flatten(); + //~^ flat_map_identity let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flatten(); + //~^ flat_map_identity } diff --git a/src/tools/clippy/tests/ui/flat_map_identity.rs b/src/tools/clippy/tests/ui/flat_map_identity.rs index 8505ba9005d37..c59e749474ee2 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.rs +++ b/src/tools/clippy/tests/ui/flat_map_identity.rs @@ -6,10 +6,13 @@ use std::convert; fn main() { let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flat_map(|x| x); + //~^ flat_map_identity let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flat_map(convert::identity); + //~^ flat_map_identity let iterator = [[0, 1], [2, 3], [4, 5]].iter(); let _ = iterator.flat_map(|x| return x); + //~^ flat_map_identity } diff --git a/src/tools/clippy/tests/ui/flat_map_identity.stderr b/src/tools/clippy/tests/ui/flat_map_identity.stderr index 496fd972a498f..75137f5d9e573 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.stderr +++ b/src/tools/clippy/tests/ui/flat_map_identity.stderr @@ -8,13 +8,13 @@ LL | let _ = iterator.flat_map(|x| x); = help: to override `-D warnings` add `#[allow(clippy::flat_map_identity)]` error: use of `flat_map` with an identity function - --> tests/ui/flat_map_identity.rs:11:22 + --> tests/ui/flat_map_identity.rs:12:22 | LL | let _ = iterator.flat_map(convert::identity); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` error: use of `flat_map` with an identity function - --> tests/ui/flat_map_identity.rs:14:22 + --> tests/ui/flat_map_identity.rs:16:22 | LL | let _ = iterator.flat_map(|x| return x); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `flatten()` diff --git a/src/tools/clippy/tests/ui/flat_map_option.fixed b/src/tools/clippy/tests/ui/flat_map_option.fixed index e08d9a14533b2..e65e77ab79dc4 100644 --- a/src/tools/clippy/tests/ui/flat_map_option.fixed +++ b/src/tools/clippy/tests/ui/flat_map_option.fixed @@ -5,7 +5,9 @@ fn main() { // yay let c = |x| Some(x); let _ = [1].iter().filter_map(c); + //~^ flat_map_option let _ = [1].iter().filter_map(Some); + //~^ flat_map_option // nay let _ = [1].iter().flat_map(|_| &Some(1)); diff --git a/src/tools/clippy/tests/ui/flat_map_option.rs b/src/tools/clippy/tests/ui/flat_map_option.rs index 4d0f32ac0fda7..6784100a4fc9b 100644 --- a/src/tools/clippy/tests/ui/flat_map_option.rs +++ b/src/tools/clippy/tests/ui/flat_map_option.rs @@ -5,7 +5,9 @@ fn main() { // yay let c = |x| Some(x); let _ = [1].iter().flat_map(c); + //~^ flat_map_option let _ = [1].iter().flat_map(Some); + //~^ flat_map_option // nay let _ = [1].iter().flat_map(|_| &Some(1)); diff --git a/src/tools/clippy/tests/ui/flat_map_option.stderr b/src/tools/clippy/tests/ui/flat_map_option.stderr index 6e151965fad53..7f5f2c14ec8ec 100644 --- a/src/tools/clippy/tests/ui/flat_map_option.stderr +++ b/src/tools/clippy/tests/ui/flat_map_option.stderr @@ -8,7 +8,7 @@ LL | let _ = [1].iter().flat_map(c); = help: to override `-D warnings` add `#[allow(clippy::flat_map_option)]` error: used `flat_map` where `filter_map` could be used instead - --> tests/ui/flat_map_option.rs:8:24 + --> tests/ui/flat_map_option.rs:9:24 | LL | let _ = [1].iter().flat_map(Some); | ^^^^^^^^ help: try: `filter_map` diff --git a/src/tools/clippy/tests/ui/float_arithmetic.rs b/src/tools/clippy/tests/ui/float_arithmetic.rs index 1647273c436d8..3c447bc94c666 100644 --- a/src/tools/clippy/tests/ui/float_arithmetic.rs +++ b/src/tools/clippy/tests/ui/float_arithmetic.rs @@ -13,58 +13,70 @@ fn main() { let mut f = 1.0f32; f * 2.0; - //~^ ERROR: floating-point arithmetic detected - //~| NOTE: `-D clippy::float-arithmetic` implied by `-D warnings` + //~^ float_arithmetic + + 1.0 + f; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + f * 2.0; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + f / 2.0; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + f - 2.0 * 4.2; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + -f; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + f += 1.0; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + f -= 1.0; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + f *= 2.0; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + f /= 2.0; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + } // also warn about floating point arith with references involved pub fn float_arith_ref() { 3.1_f32 + &1.2_f32; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + &3.4_f32 + 1.5_f32; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic + &3.5_f32 + &1.3_f32; - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic } pub fn float_foo(f: &f32) -> f32 { let a = 5.1; a + f - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic } pub fn float_bar(f1: &f32, f2: &f32) -> f32 { f1 + f2 - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic } pub fn float_baz(f1: f32, f2: &f32) -> f32 { f1 + f2 - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic } pub fn float_qux(f1: f32, f2: f32) -> f32 { (&f1 + &f2) - //~^ ERROR: floating-point arithmetic detected + //~^ float_arithmetic } diff --git a/src/tools/clippy/tests/ui/float_arithmetic.stderr b/src/tools/clippy/tests/ui/float_arithmetic.stderr index 66455f061455e..8704f7bbd7c4e 100644 --- a/src/tools/clippy/tests/ui/float_arithmetic.stderr +++ b/src/tools/clippy/tests/ui/float_arithmetic.stderr @@ -8,97 +8,97 @@ LL | f * 2.0; = help: to override `-D warnings` add `#[allow(clippy::float_arithmetic)]` error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:19:5 + --> tests/ui/float_arithmetic.rs:20:5 | LL | 1.0 + f; | ^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:21:5 + --> tests/ui/float_arithmetic.rs:23:5 | LL | f * 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:23:5 + --> tests/ui/float_arithmetic.rs:26:5 | LL | f / 2.0; | ^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:25:5 + --> tests/ui/float_arithmetic.rs:29:5 | LL | f - 2.0 * 4.2; | ^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:27:5 + --> tests/ui/float_arithmetic.rs:32:5 | LL | -f; | ^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:30:5 + --> tests/ui/float_arithmetic.rs:36:5 | LL | f += 1.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:32:5 + --> tests/ui/float_arithmetic.rs:39:5 | LL | f -= 1.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:34:5 + --> tests/ui/float_arithmetic.rs:42:5 | LL | f *= 2.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:36:5 + --> tests/ui/float_arithmetic.rs:45:5 | LL | f /= 2.0; | ^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:43:5 + --> tests/ui/float_arithmetic.rs:53:5 | LL | 3.1_f32 + &1.2_f32; | ^^^^^^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:45:5 + --> tests/ui/float_arithmetic.rs:56:5 | LL | &3.4_f32 + 1.5_f32; | ^^^^^^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:47:5 + --> tests/ui/float_arithmetic.rs:59:5 | LL | &3.5_f32 + &1.3_f32; | ^^^^^^^^^^^^^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:53:5 + --> tests/ui/float_arithmetic.rs:65:5 | LL | a + f | ^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:58:5 + --> tests/ui/float_arithmetic.rs:70:5 | LL | f1 + f2 | ^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:63:5 + --> tests/ui/float_arithmetic.rs:75:5 | LL | f1 + f2 | ^^^^^^^ error: floating-point arithmetic detected - --> tests/ui/float_arithmetic.rs:68:5 + --> tests/ui/float_arithmetic.rs:80:5 | LL | (&f1 + &f2) | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/float_cmp.rs b/src/tools/clippy/tests/ui/float_cmp.rs index a1dfd1954fced..ce0ffd8a21927 100644 --- a/src/tools/clippy/tests/ui/float_cmp.rs +++ b/src/tools/clippy/tests/ui/float_cmp.rs @@ -70,17 +70,19 @@ fn main() { ONE != 0.0; // no error, comparison with zero is ok twice(ONE) != ONE; ONE as f64 != 2.0; - //~^ ERROR: strict comparison of `f32` or `f64` + //~^ float_cmp + ONE as f64 != 0.0; // no error, comparison with zero is ok let x: f64 = 1.0; x == 1.0; - //~^ ERROR: strict comparison of `f32` or `f64` + //~^ float_cmp + x != 0f64; // no error, comparison with zero is ok twice(x) != twice(ONE as f64); - //~^ ERROR: strict comparison of `f32` or `f64` + //~^ float_cmp x < 0.0; // no errors, lower or greater comparisons need no fuzzyness x > 0.0; @@ -101,15 +103,16 @@ fn main() { ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; // ok, because lhs is zero regardless of i NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; - //~^ ERROR: strict comparison of `f32` or `f64` + //~^ float_cmp let a1: [f32; 1] = [0.0]; let a2: [f32; 1] = [1.1]; a1 == a2; - //~^ ERROR: strict comparison of `f32` or `f64` arrays + //~^ float_cmp + a1[0] == a2[0]; - //~^ ERROR: strict comparison of `f32` or `f64` + //~^ float_cmp // no errors - comparing signums is ok let x32 = 3.21f32; diff --git a/src/tools/clippy/tests/ui/float_cmp.stderr b/src/tools/clippy/tests/ui/float_cmp.stderr index d10da8a99a9d8..e573c0baeac26 100644 --- a/src/tools/clippy/tests/ui/float_cmp.stderr +++ b/src/tools/clippy/tests/ui/float_cmp.stderr @@ -8,31 +8,31 @@ LL | ONE as f64 != 2.0; = help: to override `-D warnings` add `#[allow(clippy::float_cmp)]` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:78:5 + --> tests/ui/float_cmp.rs:79:5 | LL | x == 1.0; | ^^^^^^^^ help: consider comparing them within some margin of error: `(x - 1.0).abs() < error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:82:5 + --> tests/ui/float_cmp.rs:84:5 | LL | twice(x) != twice(ONE as f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(twice(x) - twice(ONE as f64)).abs() > error_margin` error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:103:5 + --> tests/ui/float_cmp.rs:105:5 | LL | NON_ZERO_ARRAY[i] == NON_ZERO_ARRAY[j]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(NON_ZERO_ARRAY[i] - NON_ZERO_ARRAY[j]).abs() < error_margin` error: strict comparison of `f32` or `f64` arrays - --> tests/ui/float_cmp.rs:109:5 + --> tests/ui/float_cmp.rs:111:5 | LL | a1 == a2; | ^^^^^^^^ error: strict comparison of `f32` or `f64` - --> tests/ui/float_cmp.rs:111:5 + --> tests/ui/float_cmp.rs:114:5 | LL | a1[0] == a2[0]; | ^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(a1[0] - a2[0]).abs() < error_margin` diff --git a/src/tools/clippy/tests/ui/float_cmp_const.rs b/src/tools/clippy/tests/ui/float_cmp_const.rs index ba760a18f28a1..3af53f2e84a22 100644 --- a/src/tools/clippy/tests/ui/float_cmp_const.rs +++ b/src/tools/clippy/tests/ui/float_cmp_const.rs @@ -13,22 +13,27 @@ fn eq_one(x: f32) -> bool { fn main() { // has errors 1f32 == ONE; - //~^ ERROR: strict comparison of `f32` or `f64` constant + //~^ float_cmp_const + TWO == ONE; - //~^ ERROR: strict comparison of `f32` or `f64` constant + //~^ float_cmp_const + TWO != ONE; - //~^ ERROR: strict comparison of `f32` or `f64` constant + //~^ float_cmp_const + ONE + ONE == TWO; - //~^ ERROR: strict comparison of `f32` or `f64` constant + //~^ float_cmp_const + let x = 1; x as f32 == ONE; - //~^ ERROR: strict comparison of `f32` or `f64` constant + //~^ float_cmp_const let v = 0.9; v == ONE; - //~^ ERROR: strict comparison of `f32` or `f64` constant + //~^ float_cmp_const + v != ONE; - //~^ ERROR: strict comparison of `f32` or `f64` constant + //~^ float_cmp_const // no errors, lower than or greater than comparisons v < ONE; @@ -61,5 +66,5 @@ fn main() { // has errors NON_ZERO_ARRAY == NON_ZERO_ARRAY2; - //~^ ERROR: strict comparison of `f32` or `f64` constant arrays + //~^ float_cmp_const } diff --git a/src/tools/clippy/tests/ui/float_cmp_const.stderr b/src/tools/clippy/tests/ui/float_cmp_const.stderr index e0cd6faf4b3af..482a55a54be69 100644 --- a/src/tools/clippy/tests/ui/float_cmp_const.stderr +++ b/src/tools/clippy/tests/ui/float_cmp_const.stderr @@ -8,43 +8,43 @@ LL | 1f32 == ONE; = help: to override `-D warnings` add `#[allow(clippy::float_cmp_const)]` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:17:5 + --> tests/ui/float_cmp_const.rs:18:5 | LL | TWO == ONE; | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:19:5 + --> tests/ui/float_cmp_const.rs:21:5 | LL | TWO != ONE; | ^^^^^^^^^^ help: consider comparing them within some margin of error: `(TWO - ONE).abs() > error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:21:5 + --> tests/ui/float_cmp_const.rs:24:5 | LL | ONE + ONE == TWO; | ^^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(ONE + ONE - TWO).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:24:5 + --> tests/ui/float_cmp_const.rs:28:5 | LL | x as f32 == ONE; | ^^^^^^^^^^^^^^^ help: consider comparing them within some margin of error: `(x as f32 - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:28:5 + --> tests/ui/float_cmp_const.rs:32:5 | LL | v == ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() < error_margin` error: strict comparison of `f32` or `f64` constant - --> tests/ui/float_cmp_const.rs:30:5 + --> tests/ui/float_cmp_const.rs:35:5 | LL | v != ONE; | ^^^^^^^^ help: consider comparing them within some margin of error: `(v - ONE).abs() > error_margin` error: strict comparison of `f32` or `f64` constant arrays - --> tests/ui/float_cmp_const.rs:63:5 + --> tests/ui/float_cmp_const.rs:68:5 | LL | NON_ZERO_ARRAY == NON_ZERO_ARRAY2; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.rs b/src/tools/clippy/tests/ui/float_equality_without_abs.rs index 500b3035390fe..a1548db6710d1 100644 --- a/src/tools/clippy/tests/ui/float_equality_without_abs.rs +++ b/src/tools/clippy/tests/ui/float_equality_without_abs.rs @@ -5,8 +5,7 @@ pub fn is_roughly_equal(a: f32, b: f32) -> bool { (a - b) < f32::EPSILON - //~^ ERROR: float equality check without `.abs()` - //~| NOTE: `-D clippy::float-equality-without-abs` implied by `-D warnings` + //~^ float_equality_without_abs } pub fn main() { @@ -16,26 +15,34 @@ pub fn main() { let b = 0.0500001; let _ = (a - b) < f32::EPSILON; - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = a - b < f32::EPSILON; - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = a - b.abs() < f32::EPSILON; - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = (a as f64 - b as f64) < f64::EPSILON; - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = 1.0 - 2.0 < f32::EPSILON; - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs let _ = f32::EPSILON > (a - b); - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = f32::EPSILON > a - b; - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = f32::EPSILON > a - b.abs(); - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = f64::EPSILON > (a as f64 - b as f64); - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs + let _ = f32::EPSILON > 1.0 - 2.0; - //~^ ERROR: float equality check without `.abs()` + //~^ float_equality_without_abs // those are correct let _ = (a - b).abs() < f32::EPSILON; diff --git a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr index cdaaf0cdbcf7e..d4c89ce72ba9b 100644 --- a/src/tools/clippy/tests/ui/float_equality_without_abs.stderr +++ b/src/tools/clippy/tests/ui/float_equality_without_abs.stderr @@ -10,7 +10,7 @@ LL | (a - b) < f32::EPSILON = help: to override `-D warnings` add `#[allow(clippy::float_equality_without_abs)]` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:18:13 + --> tests/ui/float_equality_without_abs.rs:17:13 | LL | let _ = (a - b) < f32::EPSILON; | -------^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | let _ = a - b < f32::EPSILON; | help: add `.abs()`: `(a - b).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:22:13 + --> tests/ui/float_equality_without_abs.rs:23:13 | LL | let _ = a - b.abs() < f32::EPSILON; | -----------^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | let _ = a - b.abs() < f32::EPSILON; | help: add `.abs()`: `(a - b.abs()).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:24:13 + --> tests/ui/float_equality_without_abs.rs:26:13 | LL | let _ = (a as f64 - b as f64) < f64::EPSILON; | ---------------------^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | let _ = (a as f64 - b as f64) < f64::EPSILON; | help: add `.abs()`: `(a as f64 - b as f64).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:26:13 + --> tests/ui/float_equality_without_abs.rs:29:13 | LL | let _ = 1.0 - 2.0 < f32::EPSILON; | ---------^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | let _ = 1.0 - 2.0 < f32::EPSILON; | help: add `.abs()`: `(1.0 - 2.0).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:29:13 + --> tests/ui/float_equality_without_abs.rs:32:13 | LL | let _ = f32::EPSILON > (a - b); | ^^^^^^^^^^^^^^^------- @@ -58,7 +58,7 @@ LL | let _ = f32::EPSILON > (a - b); | help: add `.abs()`: `(a - b).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:31:13 + --> tests/ui/float_equality_without_abs.rs:35:13 | LL | let _ = f32::EPSILON > a - b; | ^^^^^^^^^^^^^^^----- @@ -66,7 +66,7 @@ LL | let _ = f32::EPSILON > a - b; | help: add `.abs()`: `(a - b).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:33:13 + --> tests/ui/float_equality_without_abs.rs:38:13 | LL | let _ = f32::EPSILON > a - b.abs(); | ^^^^^^^^^^^^^^^----------- @@ -74,7 +74,7 @@ LL | let _ = f32::EPSILON > a - b.abs(); | help: add `.abs()`: `(a - b.abs()).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:35:13 + --> tests/ui/float_equality_without_abs.rs:41:13 | LL | let _ = f64::EPSILON > (a as f64 - b as f64); | ^^^^^^^^^^^^^^^--------------------- @@ -82,7 +82,7 @@ LL | let _ = f64::EPSILON > (a as f64 - b as f64); | help: add `.abs()`: `(a as f64 - b as f64).abs()` error: float equality check without `.abs()` - --> tests/ui/float_equality_without_abs.rs:37:13 + --> tests/ui/float_equality_without_abs.rs:44:13 | LL | let _ = f32::EPSILON > 1.0 - 2.0; | ^^^^^^^^^^^^^^^--------- diff --git a/src/tools/clippy/tests/ui/floating_point_abs.fixed b/src/tools/clippy/tests/ui/floating_point_abs.fixed index 33183c7697243..e8d64a3d7c296 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.fixed +++ b/src/tools/clippy/tests/ui/floating_point_abs.fixed @@ -12,35 +12,43 @@ struct A { fn fake_abs1(num: f64) -> f64 { num.abs() + //~^ suboptimal_flops } fn fake_abs2(num: f64) -> f64 { num.abs() + //~^ suboptimal_flops } fn fake_abs3(a: A) -> f64 { a.a.abs() + //~^ suboptimal_flops } fn fake_abs4(num: f64) -> f64 { num.abs() + //~^ suboptimal_flops } fn fake_abs5(a: A) -> f64 { a.a.abs() + //~^ suboptimal_flops } fn fake_nabs1(num: f64) -> f64 { -num.abs() + //~^ suboptimal_flops } fn fake_nabs2(num: f64) -> f64 { -num.abs() + //~^ suboptimal_flops } fn fake_nabs3(a: A) -> A { A { a: -a.a.abs(), + //~^ suboptimal_flops b: a.b, } } diff --git a/src/tools/clippy/tests/ui/floating_point_abs.rs b/src/tools/clippy/tests/ui/floating_point_abs.rs index a08d5bbcef5ce..a27279b0662f5 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.rs +++ b/src/tools/clippy/tests/ui/floating_point_abs.rs @@ -12,35 +12,43 @@ struct A { fn fake_abs1(num: f64) -> f64 { if num >= 0.0 { num } else { -num } + //~^ suboptimal_flops } fn fake_abs2(num: f64) -> f64 { if 0.0 < num { num } else { -num } + //~^ suboptimal_flops } fn fake_abs3(a: A) -> f64 { if a.a > 0.0 { a.a } else { -a.a } + //~^ suboptimal_flops } fn fake_abs4(num: f64) -> f64 { if 0.0 >= num { -num } else { num } + //~^ suboptimal_flops } fn fake_abs5(a: A) -> f64 { if a.a < 0.0 { -a.a } else { a.a } + //~^ suboptimal_flops } fn fake_nabs1(num: f64) -> f64 { if num < 0.0 { num } else { -num } + //~^ suboptimal_flops } fn fake_nabs2(num: f64) -> f64 { if 0.0 >= num { num } else { -num } + //~^ suboptimal_flops } fn fake_nabs3(a: A) -> A { A { a: if a.a >= 0.0 { -a.a } else { a.a }, + //~^ suboptimal_flops b: a.b, } } diff --git a/src/tools/clippy/tests/ui/floating_point_abs.stderr b/src/tools/clippy/tests/ui/floating_point_abs.stderr index 0c1f68f3b7fd2..f031ac25114d1 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.stderr +++ b/src/tools/clippy/tests/ui/floating_point_abs.stderr @@ -8,43 +8,43 @@ LL | if num >= 0.0 { num } else { -num } = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:18:5 + --> tests/ui/floating_point_abs.rs:19:5 | LL | if 0.0 < num { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:22:5 + --> tests/ui/floating_point_abs.rs:24:5 | LL | if a.a > 0.0 { a.a } else { -a.a } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:26:5 + --> tests/ui/floating_point_abs.rs:29:5 | LL | if 0.0 >= num { -num } else { num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.abs()` error: manual implementation of `abs` method - --> tests/ui/floating_point_abs.rs:30:5 + --> tests/ui/floating_point_abs.rs:34:5 | LL | if a.a < 0.0 { -a.a } else { a.a } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.a.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:34:5 + --> tests/ui/floating_point_abs.rs:39:5 | LL | if num < 0.0 { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:38:5 + --> tests/ui/floating_point_abs.rs:44:5 | LL | if 0.0 >= num { num } else { -num } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-num.abs()` error: manual implementation of negation of `abs` method - --> tests/ui/floating_point_abs.rs:43:12 + --> tests/ui/floating_point_abs.rs:50:12 | LL | a: if a.a >= 0.0 { -a.a } else { a.a }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-a.a.abs()` diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs index 81e4e0380dad9..c4456bf870cd3 100644 --- a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs +++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![crate_type = "lib"] #![warn(clippy::imprecise_flops)] #![warn(clippy::suboptimal_flops)] diff --git a/src/tools/clippy/tests/ui/floating_point_exp.fixed b/src/tools/clippy/tests/ui/floating_point_exp.fixed index fbd91cbc9d703..72a6f4fcfbd35 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.fixed +++ b/src/tools/clippy/tests/ui/floating_point_exp.fixed @@ -6,15 +6,20 @@ fn main() { let x = 2f32; let _ = x.exp_m1(); + //~^ imprecise_flops let _ = x.exp_m1() + 2.0; + //~^ imprecise_flops let _ = (x as f32).exp_m1() + 2.0; + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = x.exp() - 2.0; let _ = x.exp() - 1.0 * 2.0; let x = 2f64; let _ = x.exp_m1(); + //~^ imprecise_flops let _ = x.exp_m1() + 2.0; + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = x.exp() - 2.0; let _ = x.exp() - 1.0 * 2.0; diff --git a/src/tools/clippy/tests/ui/floating_point_exp.rs b/src/tools/clippy/tests/ui/floating_point_exp.rs index 340bacaf56b5e..ce584c038a498 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.rs +++ b/src/tools/clippy/tests/ui/floating_point_exp.rs @@ -6,15 +6,20 @@ fn main() { let x = 2f32; let _ = x.exp() - 1.0; + //~^ imprecise_flops let _ = x.exp() - 1.0 + 2.0; + //~^ imprecise_flops let _ = (x as f32).exp() - 1.0 + 2.0; + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = x.exp() - 2.0; let _ = x.exp() - 1.0 * 2.0; let x = 2f64; let _ = x.exp() - 1.0; + //~^ imprecise_flops let _ = x.exp() - 1.0 + 2.0; + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = x.exp() - 2.0; let _ = x.exp() - 1.0 * 2.0; diff --git a/src/tools/clippy/tests/ui/floating_point_exp.stderr b/src/tools/clippy/tests/ui/floating_point_exp.stderr index 6ce67254abc96..7736a8e7ac366 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.stderr +++ b/src/tools/clippy/tests/ui/floating_point_exp.stderr @@ -8,25 +8,25 @@ LL | let _ = x.exp() - 1.0; = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:9:13 + --> tests/ui/floating_point_exp.rs:10:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:10:13 + --> tests/ui/floating_point_exp.rs:12:13 | LL | let _ = (x as f32).exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:16:13 + --> tests/ui/floating_point_exp.rs:19:13 | LL | let _ = x.exp() - 1.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` error: (e.pow(x) - 1) can be computed more accurately - --> tests/ui/floating_point_exp.rs:17:13 + --> tests/ui/floating_point_exp.rs:21:13 | LL | let _ = x.exp() - 1.0 + 2.0; | ^^^^^^^^^^^^^ help: consider using: `x.exp_m1()` diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.fixed b/src/tools/clippy/tests/ui/floating_point_hypot.fixed index 75a224440b0de..1fa684e78e0b0 100644 --- a/src/tools/clippy/tests/ui/floating_point_hypot.fixed +++ b/src/tools/clippy/tests/ui/floating_point_hypot.fixed @@ -4,8 +4,11 @@ fn main() { let x = 3f32; let y = 4f32; let _ = x.hypot(y); + //~^ imprecise_flops let _ = (x + 1f32).hypot(y); + //~^ imprecise_flops let _ = x.hypot(y); + //~^ imprecise_flops // Cases where the lint shouldn't be applied // TODO: linting this adds some complexity, but could be done let _ = x.mul_add(x, y * y).sqrt(); diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.rs b/src/tools/clippy/tests/ui/floating_point_hypot.rs index ed4dbf6382e71..9b4e74d28d0f2 100644 --- a/src/tools/clippy/tests/ui/floating_point_hypot.rs +++ b/src/tools/clippy/tests/ui/floating_point_hypot.rs @@ -4,8 +4,11 @@ fn main() { let x = 3f32; let y = 4f32; let _ = (x * x + y * y).sqrt(); + //~^ imprecise_flops let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt(); + //~^ imprecise_flops let _ = (x.powi(2) + y.powi(2)).sqrt(); + //~^ imprecise_flops // Cases where the lint shouldn't be applied // TODO: linting this adds some complexity, but could be done let _ = x.mul_add(x, y * y).sqrt(); diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.stderr b/src/tools/clippy/tests/ui/floating_point_hypot.stderr index 8942e86910da1..3526df2cf265d 100644 --- a/src/tools/clippy/tests/ui/floating_point_hypot.stderr +++ b/src/tools/clippy/tests/ui/floating_point_hypot.stderr @@ -8,13 +8,13 @@ LL | let _ = (x * x + y * y).sqrt(); = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: hypotenuse can be computed more accurately - --> tests/ui/floating_point_hypot.rs:7:13 + --> tests/ui/floating_point_hypot.rs:8:13 | LL | let _ = ((x + 1f32) * (x + 1f32) + y * y).sqrt(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 1f32).hypot(y)` error: hypotenuse can be computed more accurately - --> tests/ui/floating_point_hypot.rs:8:13 + --> tests/ui/floating_point_hypot.rs:10:13 | LL | let _ = (x.powi(2) + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.hypot(y)` diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed index 75e9c40a5218c..275c9b4a3ab9a 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.fixed +++ b/src/tools/clippy/tests/ui/floating_point_log.fixed @@ -9,31 +9,51 @@ const E: f32 = std::f32::consts::E; fn check_log_base() { let x = 1f32; let _ = x.log2(); + //~^ suboptimal_flops let _ = x.log10(); + //~^ suboptimal_flops let _ = x.ln(); + //~^ suboptimal_flops let _ = x.log2(); + //~^ suboptimal_flops let _ = x.ln(); + //~^ suboptimal_flops let _ = (x as f32).log2(); + //~^ suboptimal_flops let x = 1f64; let _ = x.log2(); + //~^ suboptimal_flops let _ = x.log10(); + //~^ suboptimal_flops let _ = x.ln(); + //~^ suboptimal_flops } fn check_ln1p() { let x = 1f32; let _ = 2.0f32.ln_1p(); + //~^ imprecise_flops let _ = 2.0f32.ln_1p(); + //~^ imprecise_flops let _ = x.ln_1p(); + //~^ imprecise_flops let _ = (x / 2.0).ln_1p(); + //~^ imprecise_flops let _ = x.powi(3).ln_1p(); + //~^ imprecise_flops let _ = (x.powi(3) / 2.0).ln_1p(); + //~^ imprecise_flops let _ = (std::f32::consts::E - 1.0).ln_1p(); + //~^ imprecise_flops let _ = x.ln_1p(); + //~^ imprecise_flops let _ = x.powi(3).ln_1p(); + //~^ imprecise_flops let _ = (x + 2.0).ln_1p(); + //~^ imprecise_flops let _ = (x / 2.0).ln_1p(); + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); @@ -42,14 +62,23 @@ fn check_ln1p() { let x = 1f64; let _ = 2.0f64.ln_1p(); + //~^ imprecise_flops let _ = 2.0f64.ln_1p(); + //~^ imprecise_flops let _ = x.ln_1p(); + //~^ imprecise_flops let _ = (x / 2.0).ln_1p(); + //~^ imprecise_flops let _ = x.powi(3).ln_1p(); + //~^ imprecise_flops let _ = x.ln_1p(); + //~^ imprecise_flops let _ = x.powi(3).ln_1p(); + //~^ imprecise_flops let _ = (x + 2.0).ln_1p(); + //~^ imprecise_flops let _ = (x / 2.0).ln_1p(); + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs index d68369a386184..a372ccbb9fb03 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.rs +++ b/src/tools/clippy/tests/ui/floating_point_log.rs @@ -9,31 +9,51 @@ const E: f32 = std::f32::consts::E; fn check_log_base() { let x = 1f32; let _ = x.log(2f32); + //~^ suboptimal_flops let _ = x.log(10f32); + //~^ suboptimal_flops let _ = x.log(std::f32::consts::E); + //~^ suboptimal_flops let _ = x.log(TWO); + //~^ suboptimal_flops let _ = x.log(E); + //~^ suboptimal_flops let _ = (x as f32).log(2f32); + //~^ suboptimal_flops let x = 1f64; let _ = x.log(2f64); + //~^ suboptimal_flops let _ = x.log(10f64); + //~^ suboptimal_flops let _ = x.log(std::f64::consts::E); + //~^ suboptimal_flops } fn check_ln1p() { let x = 1f32; let _ = (1f32 + 2.).ln(); + //~^ imprecise_flops let _ = (1f32 + 2.0).ln(); + //~^ imprecise_flops let _ = (1.0 + x).ln(); + //~^ imprecise_flops let _ = (1.0 + x / 2.0).ln(); + //~^ imprecise_flops let _ = (1.0 + x.powi(3)).ln(); + //~^ imprecise_flops let _ = (1.0 + x.powi(3) / 2.0).ln(); + //~^ imprecise_flops let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); + //~^ imprecise_flops let _ = (x + 1.0).ln(); + //~^ imprecise_flops let _ = (x.powi(3) + 1.0).ln(); + //~^ imprecise_flops let _ = (x + 2.0 + 1.0).ln(); + //~^ imprecise_flops let _ = (x / 2.0 + 1.0).ln(); + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); @@ -42,14 +62,23 @@ fn check_ln1p() { let x = 1f64; let _ = (1f64 + 2.).ln(); + //~^ imprecise_flops let _ = (1f64 + 2.0).ln(); + //~^ imprecise_flops let _ = (1.0 + x).ln(); + //~^ imprecise_flops let _ = (1.0 + x / 2.0).ln(); + //~^ imprecise_flops let _ = (1.0 + x.powi(3)).ln(); + //~^ imprecise_flops let _ = (x + 1.0).ln(); + //~^ imprecise_flops let _ = (x.powi(3) + 1.0).ln(); + //~^ imprecise_flops let _ = (x + 2.0 + 1.0).ln(); + //~^ imprecise_flops let _ = (x / 2.0 + 1.0).ln(); + //~^ imprecise_flops // Cases where the lint shouldn't be applied let _ = (1.0 + x + 2.0).ln(); let _ = (x + 1.0 + 2.0).ln(); diff --git a/src/tools/clippy/tests/ui/floating_point_log.stderr b/src/tools/clippy/tests/ui/floating_point_log.stderr index 19c28de8e39a1..e93b3af851cbe 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.stderr +++ b/src/tools/clippy/tests/ui/floating_point_log.stderr @@ -8,55 +8,55 @@ LL | let _ = x.log(2f32); = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:12:13 + --> tests/ui/floating_point_log.rs:13:13 | LL | let _ = x.log(10f32); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:13:13 + --> tests/ui/floating_point_log.rs:15:13 | LL | let _ = x.log(std::f32::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:14:13 + --> tests/ui/floating_point_log.rs:17:13 | LL | let _ = x.log(TWO); | ^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:15:13 + --> tests/ui/floating_point_log.rs:19:13 | LL | let _ = x.log(E); | ^^^^^^^^ help: consider using: `x.ln()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:16:13 + --> tests/ui/floating_point_log.rs:21:13 | LL | let _ = (x as f32).log(2f32); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:19:13 + --> tests/ui/floating_point_log.rs:25:13 | LL | let _ = x.log(2f64); | ^^^^^^^^^^^ help: consider using: `x.log2()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:20:13 + --> tests/ui/floating_point_log.rs:27:13 | LL | let _ = x.log(10f64); | ^^^^^^^^^^^^ help: consider using: `x.log10()` error: logarithm for bases 2, 10 and e can be computed more accurately - --> tests/ui/floating_point_log.rs:21:13 + --> tests/ui/floating_point_log.rs:29:13 | LL | let _ = x.log(std::f64::consts::E); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.ln()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:26:13 + --> tests/ui/floating_point_log.rs:35:13 | LL | let _ = (1f32 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` @@ -65,115 +65,115 @@ LL | let _ = (1f32 + 2.).ln(); = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:27:13 + --> tests/ui/floating_point_log.rs:37:13 | LL | let _ = (1f32 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f32.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:28:13 + --> tests/ui/floating_point_log.rs:39:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:29:13 + --> tests/ui/floating_point_log.rs:41:13 | LL | let _ = (1.0 + x / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:30:13 + --> tests/ui/floating_point_log.rs:43:13 | LL | let _ = (1.0 + x.powi(3)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:31:13 + --> tests/ui/floating_point_log.rs:45:13 | LL | let _ = (1.0 + x.powi(3) / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x.powi(3) / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:32:13 + --> tests/ui/floating_point_log.rs:47:13 | LL | let _ = (1.0 + (std::f32::consts::E - 1.0)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(std::f32::consts::E - 1.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:33:13 + --> tests/ui/floating_point_log.rs:49:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:34:13 + --> tests/ui/floating_point_log.rs:51:13 | LL | let _ = (x.powi(3) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:35:13 + --> tests/ui/floating_point_log.rs:53:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:36:13 + --> tests/ui/floating_point_log.rs:55:13 | LL | let _ = (x / 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:44:13 + --> tests/ui/floating_point_log.rs:64:13 | LL | let _ = (1f64 + 2.).ln(); | ^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:45:13 + --> tests/ui/floating_point_log.rs:66:13 | LL | let _ = (1f64 + 2.0).ln(); | ^^^^^^^^^^^^^^^^^ help: consider using: `2.0f64.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:46:13 + --> tests/ui/floating_point_log.rs:68:13 | LL | let _ = (1.0 + x).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:47:13 + --> tests/ui/floating_point_log.rs:70:13 | LL | let _ = (1.0 + x / 2.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:48:13 + --> tests/ui/floating_point_log.rs:72:13 | LL | let _ = (1.0 + x.powi(3)).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:49:13 + --> tests/ui/floating_point_log.rs:74:13 | LL | let _ = (x + 1.0).ln(); | ^^^^^^^^^^^^^^ help: consider using: `x.ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:50:13 + --> tests/ui/floating_point_log.rs:76:13 | LL | let _ = (x.powi(3) + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(3).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:51:13 + --> tests/ui/floating_point_log.rs:78:13 | LL | let _ = (x + 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x + 2.0).ln_1p()` error: ln(1 + x) can be computed more accurately - --> tests/ui/floating_point_log.rs:52:13 + --> tests/ui/floating_point_log.rs:80:13 | LL | let _ = (x / 2.0 + 1.0).ln(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x / 2.0).ln_1p()` diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.fixed b/src/tools/clippy/tests/ui/floating_point_logbase.fixed index 451673d109c64..d03882c774c05 100644 --- a/src/tools/clippy/tests/ui/floating_point_logbase.fixed +++ b/src/tools/clippy/tests/ui/floating_point_logbase.fixed @@ -5,10 +5,15 @@ fn main() { let x = 3f32; let y = 5f32; let _ = x.log(y); + //~^ suboptimal_flops let _ = (x as f32).log(y); + //~^ suboptimal_flops let _ = x.log(y); + //~^ suboptimal_flops let _ = x.log(y); + //~^ suboptimal_flops let _ = x.log(y); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.ln() / y.powf(3.2); let _ = x.powf(3.2) / y.powf(3.2); diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.rs b/src/tools/clippy/tests/ui/floating_point_logbase.rs index c309114599d94..c29f4deb37382 100644 --- a/src/tools/clippy/tests/ui/floating_point_logbase.rs +++ b/src/tools/clippy/tests/ui/floating_point_logbase.rs @@ -5,10 +5,15 @@ fn main() { let x = 3f32; let y = 5f32; let _ = x.ln() / y.ln(); + //~^ suboptimal_flops let _ = (x as f32).ln() / y.ln(); + //~^ suboptimal_flops let _ = x.log2() / y.log2(); + //~^ suboptimal_flops let _ = x.log10() / y.log10(); + //~^ suboptimal_flops let _ = x.log(5f32) / y.log(5f32); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.ln() / y.powf(3.2); let _ = x.powf(3.2) / y.powf(3.2); diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.stderr b/src/tools/clippy/tests/ui/floating_point_logbase.stderr index 8dfc57b133c68..1f30e5cbc1776 100644 --- a/src/tools/clippy/tests/ui/floating_point_logbase.stderr +++ b/src/tools/clippy/tests/ui/floating_point_logbase.stderr @@ -8,25 +8,25 @@ LL | let _ = x.ln() / y.ln(); = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: log base can be expressed more clearly - --> tests/ui/floating_point_logbase.rs:8:13 + --> tests/ui/floating_point_logbase.rs:9:13 | LL | let _ = (x as f32).ln() / y.ln(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).log(y)` error: log base can be expressed more clearly - --> tests/ui/floating_point_logbase.rs:9:13 + --> tests/ui/floating_point_logbase.rs:11:13 | LL | let _ = x.log2() / y.log2(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: log base can be expressed more clearly - --> tests/ui/floating_point_logbase.rs:10:13 + --> tests/ui/floating_point_logbase.rs:13:13 | LL | let _ = x.log10() / y.log10(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` error: log base can be expressed more clearly - --> tests/ui/floating_point_logbase.rs:11:13 + --> tests/ui/floating_point_logbase.rs:15:13 | LL | let _ = x.log(5f32) / y.log(5f32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.log(y)` diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed index 164aac2601a55..83aeddb2a1f4a 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed @@ -17,23 +17,36 @@ fn main() { let d: f64 = 0.0001; let _ = a.mul_add(b, c); + //~^ suboptimal_flops let _ = a.mul_add(b, -c); + //~^ suboptimal_flops let _ = a.mul_add(b, c); + //~^ suboptimal_flops let _ = a.mul_add(-b, c); + //~^ suboptimal_flops let _ = 2.0f64.mul_add(4.0, a); + //~^ suboptimal_flops let _ = 2.0f64.mul_add(4., a); + //~^ suboptimal_flops let _ = a.mul_add(b, c); + //~^ suboptimal_flops let _ = a.mul_add(b, c); + //~^ suboptimal_flops let _ = (a * b).mul_add(c, d); + //~^ suboptimal_flops let _ = a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c)) + c; + //~^ suboptimal_flops let _ = 1234.567_f64.mul_add(45.67834_f64, 0.0004_f64); + //~^ suboptimal_flops let _ = a.mul_add(a, b).sqrt(); + //~^ suboptimal_flops let u = 1usize; let _ = b.mul_add(-(u as f64), a); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs index ae024b7f224be..039ee8d053fc9 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs @@ -17,23 +17,36 @@ fn main() { let d: f64 = 0.0001; let _ = a * b + c; + //~^ suboptimal_flops let _ = a * b - c; + //~^ suboptimal_flops let _ = c + a * b; + //~^ suboptimal_flops let _ = c - a * b; + //~^ suboptimal_flops let _ = a + 2.0 * 4.0; + //~^ suboptimal_flops let _ = a + 2. * 4.; + //~^ suboptimal_flops let _ = (a * b) + c; + //~^ suboptimal_flops let _ = c + (a * b); + //~^ suboptimal_flops let _ = a * b * c + d; + //~^ suboptimal_flops let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; + //~^ suboptimal_flops let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; + //~^ suboptimal_flops let _ = (a * a + b).sqrt(); + //~^ suboptimal_flops let u = 1usize; let _ = a - (b * u as f64); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = (a * a + b * b).sqrt(); diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr index 9c75909f71584..6482127bcc00b 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr @@ -8,73 +8,73 @@ LL | let _ = a * b + c; = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:20:13 + --> tests/ui/floating_point_mul_add.rs:21:13 | LL | let _ = a * b - c; | ^^^^^^^^^ help: consider using: `a.mul_add(b, -c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:21:13 + --> tests/ui/floating_point_mul_add.rs:23:13 | LL | let _ = c + a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:22:13 + --> tests/ui/floating_point_mul_add.rs:25:13 | LL | let _ = c - a * b; | ^^^^^^^^^ help: consider using: `a.mul_add(-b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:23:13 + --> tests/ui/floating_point_mul_add.rs:27:13 | LL | let _ = a + 2.0 * 4.0; | ^^^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4.0, a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:24:13 + --> tests/ui/floating_point_mul_add.rs:29:13 | LL | let _ = a + 2. * 4.; | ^^^^^^^^^^^ help: consider using: `2.0f64.mul_add(4., a)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:26:13 + --> tests/ui/floating_point_mul_add.rs:32:13 | LL | let _ = (a * b) + c; | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:27:13 + --> tests/ui/floating_point_mul_add.rs:34:13 | LL | let _ = c + (a * b); | ^^^^^^^^^^^ help: consider using: `a.mul_add(b, c)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:28:13 + --> tests/ui/floating_point_mul_add.rs:36:13 | LL | let _ = a * b * c + d; | ^^^^^^^^^^^^^ help: consider using: `(a * b).mul_add(c, d)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:30:13 + --> tests/ui/floating_point_mul_add.rs:39:13 | LL | let _ = a.mul_add(b, c) * a.mul_add(b, c) + a.mul_add(b, c) + c; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `a.mul_add(b, c).mul_add(a.mul_add(b, c), a.mul_add(b, c))` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:31:13 + --> tests/ui/floating_point_mul_add.rs:41:13 | LL | let _ = 1234.567_f64 * 45.67834_f64 + 0.0004_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1234.567_f64.mul_add(45.67834_f64, 0.0004_f64)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:33:13 + --> tests/ui/floating_point_mul_add.rs:44:13 | LL | let _ = (a * a + b).sqrt(); | ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_mul_add.rs:36:13 + --> tests/ui/floating_point_mul_add.rs:48:13 | LL | let _ = a - (b * u as f64); | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)` diff --git a/src/tools/clippy/tests/ui/floating_point_powf.fixed b/src/tools/clippy/tests/ui/floating_point_powf.fixed index 25f09a6379515..293df9bfe9b92 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powf.fixed @@ -6,24 +6,43 @@ fn main() { let x = 3f32; let _ = x.exp2(); + //~^ suboptimal_flops let _ = 3.1f32.exp2(); + //~^ suboptimal_flops let _ = (-3.1f32).exp2(); + //~^ suboptimal_flops let _ = x.exp(); + //~^ suboptimal_flops let _ = 3.1f32.exp(); + //~^ suboptimal_flops let _ = (-3.1f32).exp(); + //~^ suboptimal_flops let _ = x.sqrt(); + //~^ suboptimal_flops let _ = x.cbrt(); + //~^ imprecise_flops let _ = (x as f32).cbrt(); + //~^ imprecise_flops let _ = x.powi(3); + //~^ suboptimal_flops let _ = x.powi(-2); + //~^ suboptimal_flops let _ = x.powi(16_777_215); + //~^ suboptimal_flops let _ = x.powi(-16_777_215); + //~^ suboptimal_flops let _ = (x as f32).powi(-16_777_215); + //~^ suboptimal_flops let _ = (x as f32).powi(3); + //~^ suboptimal_flops let _ = (1.5_f32 + 1.0).cbrt(); + //~^ imprecise_flops let _ = 1.5_f64.cbrt(); + //~^ imprecise_flops let _ = 1.5_f64.sqrt(); + //~^ suboptimal_flops let _ = 1.5_f64.powi(3); + //~^ suboptimal_flops macro_rules! m { ($e:expr) => { @@ -32,6 +51,7 @@ fn main() { } let _ = (1f32 + m!(2.0)).exp2(); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.powf(2.1); @@ -41,17 +61,29 @@ fn main() { let x = 3f64; let _ = x.exp2(); + //~^ suboptimal_flops let _ = 3.1f64.exp2(); + //~^ suboptimal_flops let _ = (-3.1f64).exp2(); + //~^ suboptimal_flops let _ = x.exp(); + //~^ suboptimal_flops let _ = 3.1f64.exp(); + //~^ suboptimal_flops let _ = (-3.1f64).exp(); + //~^ suboptimal_flops let _ = x.sqrt(); + //~^ suboptimal_flops let _ = x.cbrt(); + //~^ imprecise_flops let _ = x.powi(3); + //~^ suboptimal_flops let _ = x.powi(-2); + //~^ suboptimal_flops let _ = x.powi(-2_147_483_648); + //~^ suboptimal_flops let _ = x.powi(2_147_483_647); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/src/tools/clippy/tests/ui/floating_point_powf.rs b/src/tools/clippy/tests/ui/floating_point_powf.rs index 9e9878de4bad6..5b1940a369a56 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.rs +++ b/src/tools/clippy/tests/ui/floating_point_powf.rs @@ -6,24 +6,43 @@ fn main() { let x = 3f32; let _ = 2f32.powf(x); + //~^ suboptimal_flops let _ = 2f32.powf(3.1); + //~^ suboptimal_flops let _ = 2f32.powf(-3.1); + //~^ suboptimal_flops let _ = std::f32::consts::E.powf(x); + //~^ suboptimal_flops let _ = std::f32::consts::E.powf(3.1); + //~^ suboptimal_flops let _ = std::f32::consts::E.powf(-3.1); + //~^ suboptimal_flops let _ = x.powf(1.0 / 2.0); + //~^ suboptimal_flops let _ = x.powf(1.0 / 3.0); + //~^ imprecise_flops let _ = (x as f32).powf(1.0 / 3.0); + //~^ imprecise_flops let _ = x.powf(3.0); + //~^ suboptimal_flops let _ = x.powf(-2.0); + //~^ suboptimal_flops let _ = x.powf(16_777_215.0); + //~^ suboptimal_flops let _ = x.powf(-16_777_215.0); + //~^ suboptimal_flops let _ = (x as f32).powf(-16_777_215.0); + //~^ suboptimal_flops let _ = (x as f32).powf(3.0); + //~^ suboptimal_flops let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); + //~^ imprecise_flops let _ = 1.5_f64.powf(1.0 / 3.0); + //~^ imprecise_flops let _ = 1.5_f64.powf(1.0 / 2.0); + //~^ suboptimal_flops let _ = 1.5_f64.powf(3.0); + //~^ suboptimal_flops macro_rules! m { ($e:expr) => { @@ -32,6 +51,7 @@ fn main() { } let _ = 2f32.powf(1f32 + m!(2.0)); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.powf(2.1); @@ -41,17 +61,29 @@ fn main() { let x = 3f64; let _ = 2f64.powf(x); + //~^ suboptimal_flops let _ = 2f64.powf(3.1); + //~^ suboptimal_flops let _ = 2f64.powf(-3.1); + //~^ suboptimal_flops let _ = std::f64::consts::E.powf(x); + //~^ suboptimal_flops let _ = std::f64::consts::E.powf(3.1); + //~^ suboptimal_flops let _ = std::f64::consts::E.powf(-3.1); + //~^ suboptimal_flops let _ = x.powf(1.0 / 2.0); + //~^ suboptimal_flops let _ = x.powf(1.0 / 3.0); + //~^ imprecise_flops let _ = x.powf(3.0); + //~^ suboptimal_flops let _ = x.powf(-2.0); + //~^ suboptimal_flops let _ = x.powf(-2_147_483_648.0); + //~^ suboptimal_flops let _ = x.powf(2_147_483_647.0); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.powf(2.1); let _ = x.powf(-2.1); diff --git a/src/tools/clippy/tests/ui/floating_point_powf.stderr b/src/tools/clippy/tests/ui/floating_point_powf.stderr index c944f14fa34d2..dec30a94cc788 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powf.stderr @@ -8,43 +8,43 @@ LL | let _ = 2f32.powf(x); = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:9:13 + --> tests/ui/floating_point_powf.rs:10:13 | LL | let _ = 2f32.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:10:13 + --> tests/ui/floating_point_powf.rs:12:13 | LL | let _ = 2f32.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:11:13 + --> tests/ui/floating_point_powf.rs:14:13 | LL | let _ = std::f32::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:12:13 + --> tests/ui/floating_point_powf.rs:16:13 | LL | let _ = std::f32::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f32.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:13:13 + --> tests/ui/floating_point_powf.rs:18:13 | LL | let _ = std::f32::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f32).exp()` error: square-root of a number can be computed more efficiently and accurately - --> tests/ui/floating_point_powf.rs:14:13 + --> tests/ui/floating_point_powf.rs:20:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:15:13 + --> tests/ui/floating_point_powf.rs:22:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` @@ -53,145 +53,145 @@ LL | let _ = x.powf(1.0 / 3.0); = help: to override `-D warnings` add `#[allow(clippy::imprecise_flops)]` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:16:13 + --> tests/ui/floating_point_powf.rs:24:13 | LL | let _ = (x as f32).powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:17:13 + --> tests/ui/floating_point_powf.rs:26:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:18:13 + --> tests/ui/floating_point_powf.rs:28:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:19:13 + --> tests/ui/floating_point_powf.rs:30:13 | LL | let _ = x.powf(16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:20:13 + --> tests/ui/floating_point_powf.rs:32:13 | LL | let _ = x.powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:21:13 + --> tests/ui/floating_point_powf.rs:34:13 | LL | let _ = (x as f32).powf(-16_777_215.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(-16_777_215)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:22:13 + --> tests/ui/floating_point_powf.rs:36:13 | LL | let _ = (x as f32).powf(3.0); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x as f32).powi(3)` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:23:13 + --> tests/ui/floating_point_powf.rs:38:13 | LL | let _ = (1.5_f32 + 1.0).powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1.5_f32 + 1.0).cbrt()` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:24:13 + --> tests/ui/floating_point_powf.rs:40:13 | LL | let _ = 1.5_f64.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.cbrt()` error: square-root of a number can be computed more efficiently and accurately - --> tests/ui/floating_point_powf.rs:25:13 + --> tests/ui/floating_point_powf.rs:42:13 | LL | let _ = 1.5_f64.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.sqrt()` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:26:13 + --> tests/ui/floating_point_powf.rs:44:13 | LL | let _ = 1.5_f64.powf(3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:34:13 + --> tests/ui/floating_point_powf.rs:53:13 | LL | let _ = 2f32.powf(1f32 + m!(2.0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1f32 + m!(2.0)).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:43:13 + --> tests/ui/floating_point_powf.rs:63:13 | LL | let _ = 2f64.powf(x); | ^^^^^^^^^^^^ help: consider using: `x.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:44:13 + --> tests/ui/floating_point_powf.rs:65:13 | LL | let _ = 2f64.powf(3.1); | ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:45:13 + --> tests/ui/floating_point_powf.rs:67:13 | LL | let _ = 2f64.powf(-3.1); | ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:46:13 + --> tests/ui/floating_point_powf.rs:69:13 | LL | let _ = std::f64::consts::E.powf(x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:47:13 + --> tests/ui/floating_point_powf.rs:71:13 | LL | let _ = std::f64::consts::E.powf(3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()` error: exponent for bases 2 and e can be computed more accurately - --> tests/ui/floating_point_powf.rs:48:13 + --> tests/ui/floating_point_powf.rs:73:13 | LL | let _ = std::f64::consts::E.powf(-3.1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()` error: square-root of a number can be computed more efficiently and accurately - --> tests/ui/floating_point_powf.rs:49:13 + --> tests/ui/floating_point_powf.rs:75:13 | LL | let _ = x.powf(1.0 / 2.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()` error: cube-root of a number can be computed more accurately - --> tests/ui/floating_point_powf.rs:50:13 + --> tests/ui/floating_point_powf.rs:77:13 | LL | let _ = x.powf(1.0 / 3.0); | ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:51:13 + --> tests/ui/floating_point_powf.rs:79:13 | LL | let _ = x.powf(3.0); | ^^^^^^^^^^^ help: consider using: `x.powi(3)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:52:13 + --> tests/ui/floating_point_powf.rs:81:13 | LL | let _ = x.powf(-2.0); | ^^^^^^^^^^^^ help: consider using: `x.powi(-2)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:53:13 + --> tests/ui/floating_point_powf.rs:83:13 | LL | let _ = x.powf(-2_147_483_648.0); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)` error: exponentiation with integer powers can be computed more efficiently - --> tests/ui/floating_point_powf.rs:54:13 + --> tests/ui/floating_point_powf.rs:85:13 | LL | let _ = x.powf(2_147_483_647.0); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)` diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed index cb033c899f310..5f0618ab1c726 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed @@ -7,20 +7,34 @@ fn main() { let y = 4f32; let _ = x.mul_add(x, y); + //~^ suboptimal_flops let _ = x.mul_add(x, -y); + //~^ suboptimal_flops let _ = y.mul_add(y, x); + //~^ suboptimal_flops let _ = y.mul_add(-y, x); + //~^ suboptimal_flops let _ = (y as f32).mul_add(y as f32, x); + //~^ suboptimal_flops let _ = x.mul_add(x, y).sqrt(); + //~^ suboptimal_flops let _ = y.mul_add(y, x).sqrt(); + //~^ suboptimal_flops let _ = (x - 1.0).mul_add(x - 1.0, -y); + //~^ suboptimal_flops let _ = (x - 1.0).mul_add(x - 1.0, -y) + 3.0; + //~^ suboptimal_flops let _ = (x - 1.0).mul_add(x - 1.0, -(y + 3.0)); + //~^ suboptimal_flops let _ = (y + 1.0).mul_add(-(y + 1.0), x); + //~^ suboptimal_flops let _ = (3.0 * y).mul_add(-(3.0 * y), x); + //~^ suboptimal_flops let _ = (y + 1.0 + x).mul_add(-(y + 1.0 + x), x); + //~^ suboptimal_flops let _ = (y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.powi(2); diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs index f02e0e8ddb36b..bb97a8eddf332 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.rs +++ b/src/tools/clippy/tests/ui/floating_point_powi.rs @@ -7,20 +7,34 @@ fn main() { let y = 4f32; let _ = x.powi(2) + y; + //~^ suboptimal_flops let _ = x.powi(2) - y; + //~^ suboptimal_flops let _ = x + y.powi(2); + //~^ suboptimal_flops let _ = x - y.powi(2); + //~^ suboptimal_flops let _ = x + (y as f32).powi(2); + //~^ suboptimal_flops let _ = (x.powi(2) + y).sqrt(); + //~^ suboptimal_flops let _ = (x + y.powi(2)).sqrt(); + //~^ suboptimal_flops let _ = (x - 1.0).powi(2) - y; + //~^ suboptimal_flops let _ = (x - 1.0).powi(2) - y + 3.0; + //~^ suboptimal_flops let _ = (x - 1.0).powi(2) - (y + 3.0); + //~^ suboptimal_flops let _ = x - (y + 1.0).powi(2); + //~^ suboptimal_flops let _ = x - (3.0 * y).powi(2); + //~^ suboptimal_flops let _ = x - (y + 1.0 + x).powi(2); + //~^ suboptimal_flops let _ = x - (y + 1.0 + 2.0).powi(2); + //~^ suboptimal_flops // Cases where the lint shouldn't be applied let _ = x.powi(2); diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr index dfed20cb8c5a4..211589382911a 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr @@ -8,79 +8,79 @@ LL | let _ = x.powi(2) + y; = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:10:13 + --> tests/ui/floating_point_powi.rs:11:13 | LL | let _ = x.powi(2) - y; | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, -y)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:11:13 + --> tests/ui/floating_point_powi.rs:13:13 | LL | let _ = x + y.powi(2); | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:12:13 + --> tests/ui/floating_point_powi.rs:15:13 | LL | let _ = x - y.powi(2); | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(-y, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:13:13 + --> tests/ui/floating_point_powi.rs:17:13 | LL | let _ = x + (y as f32).powi(2); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y as f32).mul_add(y as f32, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:14:13 + --> tests/ui/floating_point_powi.rs:19:13 | LL | let _ = (x.powi(2) + y).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:15:13 + --> tests/ui/floating_point_powi.rs:21:13 | LL | let _ = (x + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:17:13 + --> tests/ui/floating_point_powi.rs:24:13 | LL | let _ = (x - 1.0).powi(2) - y; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:18:13 + --> tests/ui/floating_point_powi.rs:26:13 | LL | let _ = (x - 1.0).powi(2) - y + 3.0; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -y)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:19:13 + --> tests/ui/floating_point_powi.rs:28:13 | LL | let _ = (x - 1.0).powi(2) - (y + 3.0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(x - 1.0).mul_add(x - 1.0, -(y + 3.0))` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:20:13 + --> tests/ui/floating_point_powi.rs:30:13 | LL | let _ = x - (y + 1.0).powi(2); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0).mul_add(-(y + 1.0), x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:21:13 + --> tests/ui/floating_point_powi.rs:32:13 | LL | let _ = x - (3.0 * y).powi(2); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(3.0 * y).mul_add(-(3.0 * y), x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:22:13 + --> tests/ui/floating_point_powi.rs:34:13 | LL | let _ = x - (y + 1.0 + x).powi(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + x).mul_add(-(y + 1.0 + x), x)` error: multiply and add expressions can be calculated more efficiently and accurately - --> tests/ui/floating_point_powi.rs:23:13 + --> tests/ui/floating_point_powi.rs:36:13 | LL | let _ = x - (y + 1.0 + 2.0).powi(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(y + 1.0 + 2.0).mul_add(-(y + 1.0 + 2.0), x)` diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed index 2f93d233cb408..61f3ccc8bd02c 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.fixed +++ b/src/tools/clippy/tests/ui/floating_point_rad.fixed @@ -8,17 +8,25 @@ pub const fn const_context() { pub fn issue9391(degrees: i64) { let _ = (degrees as f64).to_radians(); + //~^ suboptimal_flops let _ = (degrees as f64).to_degrees(); + //~^ suboptimal_flops } fn main() { let x = 3f32; let _ = x.to_degrees(); + //~^ suboptimal_flops let _ = 90.0_f64.to_degrees(); + //~^ suboptimal_flops let _ = 90.5_f64.to_degrees(); + //~^ suboptimal_flops let _ = x.to_radians(); + //~^ suboptimal_flops let _ = 90.0_f64.to_radians(); + //~^ suboptimal_flops let _ = 90.5_f64.to_radians(); + //~^ suboptimal_flops // let _ = 90.5 * 80. * std::f32::consts::PI / 180f32; // Cases where the lint shouldn't be applied let _ = x * 90f32 / std::f32::consts::PI; diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs index 9690effc4e105..f57359e15fe14 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.rs +++ b/src/tools/clippy/tests/ui/floating_point_rad.rs @@ -8,17 +8,25 @@ pub const fn const_context() { pub fn issue9391(degrees: i64) { let _ = degrees as f64 * std::f64::consts::PI / 180.0; + //~^ suboptimal_flops let _ = degrees as f64 * 180.0 / std::f64::consts::PI; + //~^ suboptimal_flops } fn main() { let x = 3f32; let _ = x * 180f32 / std::f32::consts::PI; + //~^ suboptimal_flops let _ = 90. * 180f64 / std::f64::consts::PI; + //~^ suboptimal_flops let _ = 90.5 * 180f64 / std::f64::consts::PI; + //~^ suboptimal_flops let _ = x * std::f32::consts::PI / 180f32; + //~^ suboptimal_flops let _ = 90. * std::f32::consts::PI / 180f32; + //~^ suboptimal_flops let _ = 90.5 * std::f32::consts::PI / 180f32; + //~^ suboptimal_flops // let _ = 90.5 * 80. * std::f32::consts::PI / 180f32; // Cases where the lint shouldn't be applied let _ = x * 90f32 / std::f32::consts::PI; diff --git a/src/tools/clippy/tests/ui/floating_point_rad.stderr b/src/tools/clippy/tests/ui/floating_point_rad.stderr index b834f5374e0b3..b888edd59bfd1 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.stderr +++ b/src/tools/clippy/tests/ui/floating_point_rad.stderr @@ -8,43 +8,43 @@ LL | let _ = degrees as f64 * std::f64::consts::PI / 180.0; = help: to override `-D warnings` add `#[allow(clippy::suboptimal_flops)]` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:11:13 + --> tests/ui/floating_point_rad.rs:12:13 | LL | let _ = degrees as f64 * 180.0 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(degrees as f64).to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:16:13 + --> tests/ui/floating_point_rad.rs:18:13 | LL | let _ = x * 180f32 / std::f32::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:17:13 + --> tests/ui/floating_point_rad.rs:20:13 | LL | let _ = 90. * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_degrees()` error: conversion to degrees can be done more accurately - --> tests/ui/floating_point_rad.rs:18:13 + --> tests/ui/floating_point_rad.rs:22:13 | LL | let _ = 90.5 * 180f64 / std::f64::consts::PI; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_degrees()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:19:13 + --> tests/ui/floating_point_rad.rs:24:13 | LL | let _ = x * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.to_radians()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:20:13 + --> tests/ui/floating_point_rad.rs:26:13 | LL | let _ = 90. * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.0_f64.to_radians()` error: conversion to radians can be done more accurately - --> tests/ui/floating_point_rad.rs:21:13 + --> tests/ui/floating_point_rad.rs:28:13 | LL | let _ = 90.5 * std::f32::consts::PI / 180f32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `90.5_f64.to_radians()` diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.32bit.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast.32bit.stderr index 65991a3989ac6..2affd0b7d6e91 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast.32bit.stderr +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.32bit.stderr @@ -1,5 +1,5 @@ error: casting function pointer `foo` to `i8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:10:13 + --> tests/ui/fn_to_numeric_cast.rs:12:13 | LL | let _ = foo as i8; | ^^^^^^^^^ help: try: `foo as usize` @@ -8,13 +8,13 @@ LL | let _ = foo as i8; = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_with_truncation)]` error: casting function pointer `foo` to `i16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:11:13 + --> tests/ui/fn_to_numeric_cast.rs:14:13 | LL | let _ = foo as i16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i32` - --> tests/ui/fn_to_numeric_cast.rs:12:13 + --> tests/ui/fn_to_numeric_cast.rs:16:13 | LL | let _ = foo as i32; | ^^^^^^^^^^ help: try: `foo as usize` @@ -23,121 +23,121 @@ LL | let _ = foo as i32; = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast)]` error: casting function pointer `foo` to `i64` - --> tests/ui/fn_to_numeric_cast.rs:13:13 + --> tests/ui/fn_to_numeric_cast.rs:19:13 | LL | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i128` - --> tests/ui/fn_to_numeric_cast.rs:14:13 + --> tests/ui/fn_to_numeric_cast.rs:21:13 | LL | let _ = foo as i128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `isize` - --> tests/ui/fn_to_numeric_cast.rs:15:13 + --> tests/ui/fn_to_numeric_cast.rs:23:13 | LL | let _ = foo as isize; | ^^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:17:13 + --> tests/ui/fn_to_numeric_cast.rs:26:13 | LL | let _ = foo as u8; | ^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:18:13 + --> tests/ui/fn_to_numeric_cast.rs:28:13 | LL | let _ = foo as u16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u32` - --> tests/ui/fn_to_numeric_cast.rs:19:13 + --> tests/ui/fn_to_numeric_cast.rs:30:13 | LL | let _ = foo as u32; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u64` - --> tests/ui/fn_to_numeric_cast.rs:20:13 + --> tests/ui/fn_to_numeric_cast.rs:33:13 | LL | let _ = foo as u64; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u128` - --> tests/ui/fn_to_numeric_cast.rs:21:13 + --> tests/ui/fn_to_numeric_cast.rs:35:13 | LL | let _ = foo as u128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `abc` to `i8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:34:13 + --> tests/ui/fn_to_numeric_cast.rs:49:13 | LL | let _ = abc as i8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:35:13 + --> tests/ui/fn_to_numeric_cast.rs:51:13 | LL | let _ = abc as i16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i32` - --> tests/ui/fn_to_numeric_cast.rs:36:13 + --> tests/ui/fn_to_numeric_cast.rs:53:13 | LL | let _ = abc as i32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i64` - --> tests/ui/fn_to_numeric_cast.rs:37:13 + --> tests/ui/fn_to_numeric_cast.rs:56:13 | LL | let _ = abc as i64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i128` - --> tests/ui/fn_to_numeric_cast.rs:38:13 + --> tests/ui/fn_to_numeric_cast.rs:58:13 | LL | let _ = abc as i128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `isize` - --> tests/ui/fn_to_numeric_cast.rs:39:13 + --> tests/ui/fn_to_numeric_cast.rs:60:13 | LL | let _ = abc as isize; | ^^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:41:13 + --> tests/ui/fn_to_numeric_cast.rs:63:13 | LL | let _ = abc as u8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:42:13 + --> tests/ui/fn_to_numeric_cast.rs:65:13 | LL | let _ = abc as u16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u32` - --> tests/ui/fn_to_numeric_cast.rs:43:13 + --> tests/ui/fn_to_numeric_cast.rs:67:13 | LL | let _ = abc as u32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u64` - --> tests/ui/fn_to_numeric_cast.rs:44:13 + --> tests/ui/fn_to_numeric_cast.rs:70:13 | LL | let _ = abc as u64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u128` - --> tests/ui/fn_to_numeric_cast.rs:45:13 + --> tests/ui/fn_to_numeric_cast.rs:72:13 | LL | let _ = abc as u128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `f` to `i32` - --> tests/ui/fn_to_numeric_cast.rs:52:5 + --> tests/ui/fn_to_numeric_cast.rs:80:5 | LL | f as i32 | ^^^^^^^^ help: try: `f as usize` diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.64bit.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast.64bit.stderr index 58f55f19a745f..48961d14f2bba 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast.64bit.stderr +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.64bit.stderr @@ -1,5 +1,5 @@ error: casting function pointer `foo` to `i8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:10:13 + --> tests/ui/fn_to_numeric_cast.rs:12:13 | LL | let _ = foo as i8; | ^^^^^^^^^ help: try: `foo as usize` @@ -8,19 +8,19 @@ LL | let _ = foo as i8; = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast_with_truncation)]` error: casting function pointer `foo` to `i16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:11:13 + --> tests/ui/fn_to_numeric_cast.rs:14:13 | LL | let _ = foo as i16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i32`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:12:13 + --> tests/ui/fn_to_numeric_cast.rs:16:13 | LL | let _ = foo as i32; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `i64` - --> tests/ui/fn_to_numeric_cast.rs:13:13 + --> tests/ui/fn_to_numeric_cast.rs:19:13 | LL | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` @@ -29,115 +29,115 @@ LL | let _ = foo as i64; = help: to override `-D warnings` add `#[allow(clippy::fn_to_numeric_cast)]` error: casting function pointer `foo` to `i128` - --> tests/ui/fn_to_numeric_cast.rs:14:13 + --> tests/ui/fn_to_numeric_cast.rs:21:13 | LL | let _ = foo as i128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `isize` - --> tests/ui/fn_to_numeric_cast.rs:15:13 + --> tests/ui/fn_to_numeric_cast.rs:23:13 | LL | let _ = foo as isize; | ^^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:17:13 + --> tests/ui/fn_to_numeric_cast.rs:26:13 | LL | let _ = foo as u8; | ^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:18:13 + --> tests/ui/fn_to_numeric_cast.rs:28:13 | LL | let _ = foo as u16; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u32`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:19:13 + --> tests/ui/fn_to_numeric_cast.rs:30:13 | LL | let _ = foo as u32; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u64` - --> tests/ui/fn_to_numeric_cast.rs:20:13 + --> tests/ui/fn_to_numeric_cast.rs:33:13 | LL | let _ = foo as u64; | ^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `foo` to `u128` - --> tests/ui/fn_to_numeric_cast.rs:21:13 + --> tests/ui/fn_to_numeric_cast.rs:35:13 | LL | let _ = foo as u128; | ^^^^^^^^^^^ help: try: `foo as usize` error: casting function pointer `abc` to `i8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:34:13 + --> tests/ui/fn_to_numeric_cast.rs:49:13 | LL | let _ = abc as i8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:35:13 + --> tests/ui/fn_to_numeric_cast.rs:51:13 | LL | let _ = abc as i16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i32`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:36:13 + --> tests/ui/fn_to_numeric_cast.rs:53:13 | LL | let _ = abc as i32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i64` - --> tests/ui/fn_to_numeric_cast.rs:37:13 + --> tests/ui/fn_to_numeric_cast.rs:56:13 | LL | let _ = abc as i64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `i128` - --> tests/ui/fn_to_numeric_cast.rs:38:13 + --> tests/ui/fn_to_numeric_cast.rs:58:13 | LL | let _ = abc as i128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `isize` - --> tests/ui/fn_to_numeric_cast.rs:39:13 + --> tests/ui/fn_to_numeric_cast.rs:60:13 | LL | let _ = abc as isize; | ^^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u8`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:41:13 + --> tests/ui/fn_to_numeric_cast.rs:63:13 | LL | let _ = abc as u8; | ^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u16`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:42:13 + --> tests/ui/fn_to_numeric_cast.rs:65:13 | LL | let _ = abc as u16; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u32`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:43:13 + --> tests/ui/fn_to_numeric_cast.rs:67:13 | LL | let _ = abc as u32; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u64` - --> tests/ui/fn_to_numeric_cast.rs:44:13 + --> tests/ui/fn_to_numeric_cast.rs:70:13 | LL | let _ = abc as u64; | ^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `abc` to `u128` - --> tests/ui/fn_to_numeric_cast.rs:45:13 + --> tests/ui/fn_to_numeric_cast.rs:72:13 | LL | let _ = abc as u128; | ^^^^^^^^^^^ help: try: `abc as usize` error: casting function pointer `f` to `i32`, which truncates the value - --> tests/ui/fn_to_numeric_cast.rs:52:5 + --> tests/ui/fn_to_numeric_cast.rs:80:5 | LL | f as i32 | ^^^^^^^^ help: try: `f as usize` diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs index 9501eb5da4b20..f53cbacdb3771 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs @@ -1,4 +1,6 @@ -//@stderr-per-bitwidth +//@revisions: 32bit 64bit +//@[32bit]ignore-bitwidth: 64 +//@[64bit]ignore-bitwidth: 32 //@no-rustfix #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] @@ -8,17 +10,30 @@ fn foo() -> String { fn test_function_to_numeric_cast() { let _ = foo as i8; + //~^ fn_to_numeric_cast_with_truncation let _ = foo as i16; + //~^ fn_to_numeric_cast_with_truncation let _ = foo as i32; + //~[64bit]^ fn_to_numeric_cast_with_truncation + //~[32bit]^^ fn_to_numeric_cast let _ = foo as i64; + //~^ fn_to_numeric_cast let _ = foo as i128; + //~^ fn_to_numeric_cast let _ = foo as isize; + //~^ fn_to_numeric_cast let _ = foo as u8; + //~^ fn_to_numeric_cast_with_truncation let _ = foo as u16; + //~^ fn_to_numeric_cast_with_truncation let _ = foo as u32; + //~[64bit]^ fn_to_numeric_cast_with_truncation + //~[32bit]^^ fn_to_numeric_cast let _ = foo as u64; + //~^ fn_to_numeric_cast let _ = foo as u128; + //~^ fn_to_numeric_cast // Casting to usize is OK and should not warn let _ = foo as usize; @@ -32,17 +47,30 @@ fn test_function_var_to_numeric_cast() { let abc: fn() -> String = foo; let _ = abc as i8; + //~^ fn_to_numeric_cast_with_truncation let _ = abc as i16; + //~^ fn_to_numeric_cast_with_truncation let _ = abc as i32; + //~[64bit]^ fn_to_numeric_cast_with_truncation + //~[32bit]^^ fn_to_numeric_cast let _ = abc as i64; + //~^ fn_to_numeric_cast let _ = abc as i128; + //~^ fn_to_numeric_cast let _ = abc as isize; + //~^ fn_to_numeric_cast let _ = abc as u8; + //~^ fn_to_numeric_cast_with_truncation let _ = abc as u16; + //~^ fn_to_numeric_cast_with_truncation let _ = abc as u32; + //~[64bit]^ fn_to_numeric_cast_with_truncation + //~[32bit]^^ fn_to_numeric_cast let _ = abc as u64; + //~^ fn_to_numeric_cast let _ = abc as u128; + //~^ fn_to_numeric_cast // Casting to usize is OK and should not warn let _ = abc as usize; @@ -50,6 +78,8 @@ fn test_function_var_to_numeric_cast() { fn fn_with_fn_args(f: fn(i32) -> i32) -> i32 { f as i32 + //~[64bit]^ fn_to_numeric_cast_with_truncation + //~[32bit]^^ fn_to_numeric_cast } fn main() {} diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.rs index 95abc0ac68dd5..42f2128cd3783 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.rs +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.rs @@ -21,58 +21,67 @@ impl Trait for Struct {} fn fn_pointer_to_integer() { let _ = foo as i8; - //~^ ERROR: casting function pointer `foo` to `i8` - //~| NOTE: `-D clippy::fn-to-numeric-cast-any` implied by `-D warnings` + //~^ fn_to_numeric_cast_any + let _ = foo as i16; - //~^ ERROR: casting function pointer `foo` to `i16` + //~^ fn_to_numeric_cast_any + let _ = foo as i32; - //~^ ERROR: casting function pointer `foo` to `i32` + //~^ fn_to_numeric_cast_any + let _ = foo as i64; - //~^ ERROR: casting function pointer `foo` to `i64` + //~^ fn_to_numeric_cast_any + let _ = foo as i128; - //~^ ERROR: casting function pointer `foo` to `i128` + //~^ fn_to_numeric_cast_any + let _ = foo as isize; - //~^ ERROR: casting function pointer `foo` to `isize` + //~^ fn_to_numeric_cast_any let _ = foo as u8; - //~^ ERROR: casting function pointer `foo` to `u8` + //~^ fn_to_numeric_cast_any + let _ = foo as u16; - //~^ ERROR: casting function pointer `foo` to `u16` + //~^ fn_to_numeric_cast_any + let _ = foo as u32; - //~^ ERROR: casting function pointer `foo` to `u32` + //~^ fn_to_numeric_cast_any + let _ = foo as u64; - //~^ ERROR: casting function pointer `foo` to `u64` + //~^ fn_to_numeric_cast_any + let _ = foo as u128; - //~^ ERROR: casting function pointer `foo` to `u128` + //~^ fn_to_numeric_cast_any + let _ = foo as usize; - //~^ ERROR: casting function pointer `foo` to `usize` + //~^ fn_to_numeric_cast_any } fn static_method_to_integer() { let _ = Struct::static_method as usize; - //~^ ERROR: casting function pointer `Struct::static_method` to `usize` + //~^ fn_to_numeric_cast_any } fn fn_with_fn_arg(f: fn(i32) -> u32) -> usize { f as usize - //~^ ERROR: casting function pointer `f` to `usize` + //~^ fn_to_numeric_cast_any } fn fn_with_generic_static_trait_method() -> usize { T::static_method as usize - //~^ ERROR: casting function pointer `T::static_method` to `usize` + //~^ fn_to_numeric_cast_any } fn closure_to_fn_to_integer() { let clos = |x| x * 2_u32; let _ = (clos as fn(u32) -> u32) as usize; - //~^ ERROR: casting function pointer `(clos as fn(u32) -> u32)` to `usize` + //~^ fn_to_numeric_cast_any } fn fn_to_raw_ptr() { let _ = foo as *const (); - //~^ ERROR: casting function pointer `foo` to `*const ()` + //~^ fn_to_numeric_cast_any } fn cast_fn_to_self() { diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr index 0238e3a91369b..58fac2d406a0f 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_any.stderr @@ -23,7 +23,7 @@ LL | let _ = foo() as i16; | ++ error: casting function pointer `foo` to `i32` - --> tests/ui/fn_to_numeric_cast_any.rs:28:13 + --> tests/ui/fn_to_numeric_cast_any.rs:29:13 | LL | let _ = foo as i32; | ^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | let _ = foo() as i32; | ++ error: casting function pointer `foo` to `i64` - --> tests/ui/fn_to_numeric_cast_any.rs:30:13 + --> tests/ui/fn_to_numeric_cast_any.rs:32:13 | LL | let _ = foo as i64; | ^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | let _ = foo() as i64; | ++ error: casting function pointer `foo` to `i128` - --> tests/ui/fn_to_numeric_cast_any.rs:32:13 + --> tests/ui/fn_to_numeric_cast_any.rs:35:13 | LL | let _ = foo as i128; | ^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | let _ = foo() as i128; | ++ error: casting function pointer `foo` to `isize` - --> tests/ui/fn_to_numeric_cast_any.rs:34:13 + --> tests/ui/fn_to_numeric_cast_any.rs:38:13 | LL | let _ = foo as isize; | ^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL | let _ = foo() as isize; | ++ error: casting function pointer `foo` to `u8` - --> tests/ui/fn_to_numeric_cast_any.rs:37:13 + --> tests/ui/fn_to_numeric_cast_any.rs:41:13 | LL | let _ = foo as u8; | ^^^^^^^^^ @@ -78,7 +78,7 @@ LL | let _ = foo() as u8; | ++ error: casting function pointer `foo` to `u16` - --> tests/ui/fn_to_numeric_cast_any.rs:39:13 + --> tests/ui/fn_to_numeric_cast_any.rs:44:13 | LL | let _ = foo as u16; | ^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = foo() as u16; | ++ error: casting function pointer `foo` to `u32` - --> tests/ui/fn_to_numeric_cast_any.rs:41:13 + --> tests/ui/fn_to_numeric_cast_any.rs:47:13 | LL | let _ = foo as u32; | ^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | let _ = foo() as u32; | ++ error: casting function pointer `foo` to `u64` - --> tests/ui/fn_to_numeric_cast_any.rs:43:13 + --> tests/ui/fn_to_numeric_cast_any.rs:50:13 | LL | let _ = foo as u64; | ^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | let _ = foo() as u64; | ++ error: casting function pointer `foo` to `u128` - --> tests/ui/fn_to_numeric_cast_any.rs:45:13 + --> tests/ui/fn_to_numeric_cast_any.rs:53:13 | LL | let _ = foo as u128; | ^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | let _ = foo() as u128; | ++ error: casting function pointer `foo` to `usize` - --> tests/ui/fn_to_numeric_cast_any.rs:47:13 + --> tests/ui/fn_to_numeric_cast_any.rs:56:13 | LL | let _ = foo as usize; | ^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL | let _ = foo() as usize; | ++ error: casting function pointer `Struct::static_method` to `usize` - --> tests/ui/fn_to_numeric_cast_any.rs:52:13 + --> tests/ui/fn_to_numeric_cast_any.rs:61:13 | LL | let _ = Struct::static_method as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | let _ = Struct::static_method() as usize; | ++ error: casting function pointer `f` to `usize` - --> tests/ui/fn_to_numeric_cast_any.rs:57:5 + --> tests/ui/fn_to_numeric_cast_any.rs:66:5 | LL | f as usize | ^^^^^^^^^^ @@ -155,7 +155,7 @@ LL | f() as usize | ++ error: casting function pointer `T::static_method` to `usize` - --> tests/ui/fn_to_numeric_cast_any.rs:62:5 + --> tests/ui/fn_to_numeric_cast_any.rs:71:5 | LL | T::static_method as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | T::static_method() as usize | ++ error: casting function pointer `(clos as fn(u32) -> u32)` to `usize` - --> tests/ui/fn_to_numeric_cast_any.rs:69:13 + --> tests/ui/fn_to_numeric_cast_any.rs:78:13 | LL | let _ = (clos as fn(u32) -> u32) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,7 +177,7 @@ LL | let _ = (clos as fn(u32) -> u32)() as usize; | ++ error: casting function pointer `foo` to `*const ()` - --> tests/ui/fn_to_numeric_cast_any.rs:74:13 + --> tests/ui/fn_to_numeric_cast_any.rs:83:13 | LL | let _ = foo as *const (); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/for_kv_map.fixed b/src/tools/clippy/tests/ui/for_kv_map.fixed index 1733b29128fe5..2a68b7443fbf2 100644 --- a/src/tools/clippy/tests/ui/for_kv_map.fixed +++ b/src/tools/clippy/tests/ui/for_kv_map.fixed @@ -7,14 +7,15 @@ use std::rc::Rc; fn main() { let m: HashMap = HashMap::new(); for v in m.values() { - //~^ ERROR: you seem to want to iterate on a map's values - //~| NOTE: `-D clippy::for-kv-map` implied by `-D warnings` + //~^ for_kv_map + let _v = v; } let m: Rc> = Rc::new(HashMap::new()); for v in (*m).values() { - //~^ ERROR: you seem to want to iterate on a map's values + //~^ for_kv_map + let _v = v; // Here the `*` is not actually necessary, but the test tests that we don't // suggest @@ -23,27 +24,31 @@ fn main() { let mut m: HashMap = HashMap::new(); for v in m.values_mut() { - //~^ ERROR: you seem to want to iterate on a map's values + //~^ for_kv_map + let _v = v; } let m: &mut HashMap = &mut HashMap::new(); for v in (*m).values_mut() { - //~^ ERROR: you seem to want to iterate on a map's values + //~^ for_kv_map + let _v = v; } let m: HashMap = HashMap::new(); let rm = &m; for k in rm.keys() { - //~^ ERROR: you seem to want to iterate on a map's keys + //~^ for_kv_map + let _k = k; } let m: HashMap = HashMap::new(); let rm = &m; 'label: for k in rm.keys() { - //~^ ERROR: you seem to want to iterate on a map's keys + //~^ for_kv_map + let _k = k; if *k == 0u64 { break 'label; diff --git a/src/tools/clippy/tests/ui/for_kv_map.rs b/src/tools/clippy/tests/ui/for_kv_map.rs index de465a7c8e6e3..485a97815e3cf 100644 --- a/src/tools/clippy/tests/ui/for_kv_map.rs +++ b/src/tools/clippy/tests/ui/for_kv_map.rs @@ -7,14 +7,15 @@ use std::rc::Rc; fn main() { let m: HashMap = HashMap::new(); for (_, v) in &m { - //~^ ERROR: you seem to want to iterate on a map's values - //~| NOTE: `-D clippy::for-kv-map` implied by `-D warnings` + //~^ for_kv_map + let _v = v; } let m: Rc> = Rc::new(HashMap::new()); for (_, v) in &*m { - //~^ ERROR: you seem to want to iterate on a map's values + //~^ for_kv_map + let _v = v; // Here the `*` is not actually necessary, but the test tests that we don't // suggest @@ -23,27 +24,31 @@ fn main() { let mut m: HashMap = HashMap::new(); for (_, v) in &mut m { - //~^ ERROR: you seem to want to iterate on a map's values + //~^ for_kv_map + let _v = v; } let m: &mut HashMap = &mut HashMap::new(); for (_, v) in &mut *m { - //~^ ERROR: you seem to want to iterate on a map's values + //~^ for_kv_map + let _v = v; } let m: HashMap = HashMap::new(); let rm = &m; for (k, _value) in rm { - //~^ ERROR: you seem to want to iterate on a map's keys + //~^ for_kv_map + let _k = k; } let m: HashMap = HashMap::new(); let rm = &m; 'label: for (k, _value) in rm { - //~^ ERROR: you seem to want to iterate on a map's keys + //~^ for_kv_map + let _k = k; if *k == 0u64 { break 'label; diff --git a/src/tools/clippy/tests/ui/for_kv_map.stderr b/src/tools/clippy/tests/ui/for_kv_map.stderr index 11b61c8cbc64c..0bd474a10682b 100644 --- a/src/tools/clippy/tests/ui/for_kv_map.stderr +++ b/src/tools/clippy/tests/ui/for_kv_map.stderr @@ -25,7 +25,7 @@ LL + for v in (*m).values() { | error: you seem to want to iterate on a map's values - --> tests/ui/for_kv_map.rs:25:19 + --> tests/ui/for_kv_map.rs:26:19 | LL | for (_, v) in &mut m { | ^^^^^^ @@ -37,7 +37,7 @@ LL + for v in m.values_mut() { | error: you seem to want to iterate on a map's values - --> tests/ui/for_kv_map.rs:31:19 + --> tests/ui/for_kv_map.rs:33:19 | LL | for (_, v) in &mut *m { | ^^^^^^^ @@ -49,7 +49,7 @@ LL + for v in (*m).values_mut() { | error: you seem to want to iterate on a map's keys - --> tests/ui/for_kv_map.rs:38:24 + --> tests/ui/for_kv_map.rs:41:24 | LL | for (k, _value) in rm { | ^^ @@ -61,7 +61,7 @@ LL + for k in rm.keys() { | error: you seem to want to iterate on a map's keys - --> tests/ui/for_kv_map.rs:45:32 + --> tests/ui/for_kv_map.rs:49:32 | LL | 'label: for (k, _value) in rm { | ^^ diff --git a/src/tools/clippy/tests/ui/forget_non_drop.rs b/src/tools/clippy/tests/ui/forget_non_drop.rs index 2459f51a38dac..0235709b1f1ca 100644 --- a/src/tools/clippy/tests/ui/forget_non_drop.rs +++ b/src/tools/clippy/tests/ui/forget_non_drop.rs @@ -11,7 +11,7 @@ fn main() { struct Foo; // Lint forget(Foo); - //~^ ERROR: call to `std::mem::forget` with a value that does not implement `Drop`. Fo + //~^ forget_non_drop struct Bar; impl Drop for Bar { @@ -23,7 +23,8 @@ fn main() { struct Baz(T); // Lint forget(Baz(Foo)); - //~^ ERROR: call to `std::mem::forget` with a value that does not implement `Drop`. Fo + //~^ forget_non_drop + // Don't lint forget(Baz(Bar)); } diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed index 3dc8eb79ba284..16437c62094af 100644 --- a/src/tools/clippy/tests/ui/format.fixed +++ b/src/tools/clippy/tests/ui/format.fixed @@ -18,14 +18,19 @@ macro_rules! foo { fn main() { "foo".to_string(); + //~^ useless_format "{}".to_string(); + //~^ useless_format "{} abc {}".to_string(); + //~^ useless_format r##"foo {} " bar"##.to_string(); let _ = String::new(); + //~^ useless_format "foo".to_string(); + //~^ useless_format format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); format!("{:width$}", "foo", width = 8); @@ -34,6 +39,7 @@ fn main() { let arg = String::new(); arg.to_string(); + //~^ useless_format format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); format!("{:width$}", arg, width = 8); @@ -64,28 +70,36 @@ fn main() { format!("{:.prec$}", "foo", prec = 10); 42.to_string(); + //~^ useless_format let x = std::path::PathBuf::from("/bar/foo/qux"); x.display().to_string(); + //~^ useless_format // False positive let a = "foo".to_string(); let _ = Some(a + "bar"); + //~^ useless_format // Wrap it with braces let v: Vec = vec!["foo".to_string(), "bar".to_string()]; let _s: String = (&*v.join("\n")).to_string(); + //~^ useless_format format!("prepend {:+}", "s"); // Issue #8290 let x = "foo"; let _ = x.to_string(); + //~^ useless_format let _ = format!("{x:?}"); // Don't lint on debug let _ = x.to_string(); + //~^ useless_format // Issue #9234 let abc = "abc"; let _ = abc.to_string(); + //~^ useless_format let xx = "xx"; let _ = xx.to_string(); + //~^ useless_format } diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs index eaf33c2a6c924..06371378f27ed 100644 --- a/src/tools/clippy/tests/ui/format.rs +++ b/src/tools/clippy/tests/ui/format.rs @@ -18,16 +18,22 @@ macro_rules! foo { fn main() { format!("foo"); + //~^ useless_format format!("{{}}"); + //~^ useless_format format!("{{}} abc {{}}"); + //~^ useless_format format!( + //~^ useless_format r##"foo {{}} " bar"## ); let _ = format!(""); + //~^ useless_format format!("{}", "foo"); + //~^ useless_format format!("{:?}", "foo"); // Don't warn about `Debug`. format!("{:8}", "foo"); format!("{:width$}", "foo", width = 8); @@ -36,6 +42,7 @@ fn main() { let arg = String::new(); format!("{}", arg); + //~^ useless_format format!("{:?}", arg); // Don't warn about debug. format!("{:8}", arg); format!("{:width$}", arg, width = 8); @@ -66,28 +73,36 @@ fn main() { format!("{:.prec$}", "foo", prec = 10); format!("{}", 42.to_string()); + //~^ useless_format let x = std::path::PathBuf::from("/bar/foo/qux"); format!("{}", x.display().to_string()); + //~^ useless_format // False positive let a = "foo".to_string(); let _ = Some(format!("{}", a + "bar")); + //~^ useless_format // Wrap it with braces let v: Vec = vec!["foo".to_string(), "bar".to_string()]; let _s: String = format!("{}", &*v.join("\n")); + //~^ useless_format format!("prepend {:+}", "s"); // Issue #8290 let x = "foo"; let _ = format!("{x}"); + //~^ useless_format let _ = format!("{x:?}"); // Don't lint on debug let _ = format!("{y}", y = x); + //~^ useless_format // Issue #9234 let abc = "abc"; let _ = format!("{abc}"); + //~^ useless_format let xx = "xx"; let _ = format!("{xx}"); + //~^ useless_format } diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr index 1368c8cd77e01..da990d32cb80e 100644 --- a/src/tools/clippy/tests/ui/format.stderr +++ b/src/tools/clippy/tests/ui/format.stderr @@ -8,21 +8,22 @@ LL | format!("foo"); = help: to override `-D warnings` add `#[allow(clippy::useless_format)]` error: useless use of `format!` - --> tests/ui/format.rs:21:5 + --> tests/ui/format.rs:22:5 | LL | format!("{{}}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()` error: useless use of `format!` - --> tests/ui/format.rs:22:5 + --> tests/ui/format.rs:24:5 | LL | format!("{{}} abc {{}}"); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()` error: useless use of `format!` - --> tests/ui/format.rs:23:5 + --> tests/ui/format.rs:26:5 | LL | / format!( +LL | | LL | | r##"foo {{}} LL | | " bar"## LL | | ); @@ -35,67 +36,67 @@ LL ~ " bar"##.to_string(); | error: useless use of `format!` - --> tests/ui/format.rs:28:13 + --> tests/ui/format.rs:32:13 | LL | let _ = format!(""); | ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()` error: useless use of `format!` - --> tests/ui/format.rs:30:5 + --> tests/ui/format.rs:35:5 | LL | format!("{}", "foo"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()` error: useless use of `format!` - --> tests/ui/format.rs:38:5 + --> tests/ui/format.rs:44:5 | LL | format!("{}", arg); | ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:68:5 + --> tests/ui/format.rs:75:5 | LL | format!("{}", 42.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:70:5 + --> tests/ui/format.rs:78:5 | LL | format!("{}", x.display().to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()` error: useless use of `format!` - --> tests/ui/format.rs:74:18 + --> tests/ui/format.rs:83:18 | LL | let _ = Some(format!("{}", a + "bar")); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"` error: useless use of `format!` - --> tests/ui/format.rs:78:22 + --> tests/ui/format.rs:88:22 | LL | let _s: String = format!("{}", &*v.join("\n")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("\n")).to_string()` error: useless use of `format!` - --> tests/ui/format.rs:84:13 + --> tests/ui/format.rs:95:13 | LL | let _ = format!("{x}"); | ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:86:13 + --> tests/ui/format.rs:98:13 | LL | let _ = format!("{y}", y = x); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:90:13 + --> tests/ui/format.rs:103:13 | LL | let _ = format!("{abc}"); | ^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `abc.to_string()` error: useless use of `format!` - --> tests/ui/format.rs:92:13 + --> tests/ui/format.rs:106:13 | LL | let _ = format!("{xx}"); | ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `xx.to_string()` diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed index 20d1e3d905042..edfdaa23ca124 100644 --- a/src/tools/clippy/tests/ui/format_args.fixed +++ b/src/tools/clippy/tests/ui/format_args.fixed @@ -75,36 +75,58 @@ fn main() { let x_ref = &x; let _ = format!("error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args let _ = write!( stdout(), "error: something failed at {}", - Location::caller() + Location::caller(), + //~^ to_string_in_format_args ); let _ = writeln!( stdout(), "error: something failed at {}", - Location::caller() + Location::caller(), + //~^ to_string_in_format_args ); print!("error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args println!("error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args eprint!("error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args eprintln!("error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args let _ = format_args!("error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args assert!(true, "error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args assert_eq!(0, 0, "error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args assert_ne!(0, 0, "error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args panic!("error: something failed at {}", Location::caller()); + //~^ to_string_in_format_args println!("{}", *X(1)); + //~^ to_string_in_format_args println!("{}", ***Y(&X(1))); + //~^ to_string_in_format_args println!("{}", Z(1)); + //~^ to_string_in_format_args println!("{}", **x); + //~^ to_string_in_format_args println!("{}", ***x_ref); + //~^ to_string_in_format_args // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{bar}", foo = "foo", bar = "bar"); + //~^ to_string_in_format_args println!("{foo}{bar}", foo = "foo", bar = "bar"); + //~^ to_string_in_format_args println!("{foo}{bar}", bar = "bar", foo = "foo"); + //~^ to_string_in_format_args println!("{foo}{bar}", bar = "bar", foo = "foo"); + //~^ to_string_in_format_args println!("{}", my_other_macro!()); + //~^ to_string_in_format_args // negative tests println!("error: something failed at {}", Somewhere.to_string()); @@ -117,7 +139,9 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{foo:?}", foo = "foo".to_string()); print!("{}", (Location::caller())); + //~^ to_string_in_format_args print!("{}", ((Location::caller()))); + //~^ to_string_in_format_args } fn issue8643(vendor_id: usize, product_id: usize, name: &str) { @@ -146,6 +170,7 @@ mod issue_8855 { let b = A {}; let x = format!("{} {}", a, b); + //~^ to_string_in_format_args dbg!(x); let x = format!("{:>6} {:>6}", a, b.to_string()); @@ -160,6 +185,7 @@ mod issue_9256 { fn print_substring(original: &str) { assert!(original.len() > 10); println!("{}", &original[..10]); + //~^ to_string_in_format_args } fn main() { diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs index 18ab223db78a1..367560d577ddd 100644 --- a/src/tools/clippy/tests/ui/format_args.rs +++ b/src/tools/clippy/tests/ui/format_args.rs @@ -75,36 +75,58 @@ fn main() { let x_ref = &x; let _ = format!("error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args let _ = write!( stdout(), "error: something failed at {}", - Location::caller().to_string() + Location::caller().to_string(), + //~^ to_string_in_format_args ); let _ = writeln!( stdout(), "error: something failed at {}", - Location::caller().to_string() + Location::caller().to_string(), + //~^ to_string_in_format_args ); print!("error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args println!("error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args eprint!("error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args eprintln!("error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args let _ = format_args!("error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args assert!(true, "error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args panic!("error: something failed at {}", Location::caller().to_string()); + //~^ to_string_in_format_args println!("{}", X(1).to_string()); + //~^ to_string_in_format_args println!("{}", Y(&X(1)).to_string()); + //~^ to_string_in_format_args println!("{}", Z(1).to_string()); + //~^ to_string_in_format_args println!("{}", x.to_string()); + //~^ to_string_in_format_args println!("{}", x_ref.to_string()); + //~^ to_string_in_format_args // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); + //~^ to_string_in_format_args println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); + //~^ to_string_in_format_args println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); + //~^ to_string_in_format_args println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); + //~^ to_string_in_format_args println!("{}", my_other_macro!().to_string()); + //~^ to_string_in_format_args // negative tests println!("error: something failed at {}", Somewhere.to_string()); @@ -117,7 +139,9 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/7903 println!("{foo}{foo:?}", foo = "foo".to_string()); print!("{}", (Location::caller().to_string())); + //~^ to_string_in_format_args print!("{}", ((Location::caller()).to_string())); + //~^ to_string_in_format_args } fn issue8643(vendor_id: usize, product_id: usize, name: &str) { @@ -146,6 +170,7 @@ mod issue_8855 { let b = A {}; let x = format!("{} {}", a, b.to_string()); + //~^ to_string_in_format_args dbg!(x); let x = format!("{:>6} {:>6}", a, b.to_string()); @@ -160,6 +185,7 @@ mod issue_9256 { fn print_substring(original: &str) { assert!(original.len() > 10); println!("{}", original[..10].to_string()); + //~^ to_string_in_format_args } fn main() { diff --git a/src/tools/clippy/tests/ui/format_args.stderr b/src/tools/clippy/tests/ui/format_args.stderr index 91a45e2700811..589c341ce8590 100644 --- a/src/tools/clippy/tests/ui/format_args.stderr +++ b/src/tools/clippy/tests/ui/format_args.stderr @@ -8,151 +8,151 @@ LL | let _ = format!("error: something failed at {}", Location::caller().to_ = help: to override `-D warnings` add `#[allow(clippy::to_string_in_format_args)]` error: `to_string` applied to a type that implements `Display` in `write!` args - --> tests/ui/format_args.rs:81:27 + --> tests/ui/format_args.rs:82:27 | -LL | Location::caller().to_string() +LL | Location::caller().to_string(), | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `writeln!` args - --> tests/ui/format_args.rs:86:27 + --> tests/ui/format_args.rs:88:27 | -LL | Location::caller().to_string() +LL | Location::caller().to_string(), | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> tests/ui/format_args.rs:88:63 + --> tests/ui/format_args.rs:91:63 | LL | print!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:89:65 + --> tests/ui/format_args.rs:93:65 | LL | println!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprint!` args - --> tests/ui/format_args.rs:90:64 + --> tests/ui/format_args.rs:95:64 | LL | eprint!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `eprintln!` args - --> tests/ui/format_args.rs:91:66 + --> tests/ui/format_args.rs:97:66 | LL | eprintln!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format_args!` args - --> tests/ui/format_args.rs:92:77 + --> tests/ui/format_args.rs:99:77 | LL | let _ = format_args!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert!` args - --> tests/ui/format_args.rs:93:70 + --> tests/ui/format_args.rs:101:70 | LL | assert!(true, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_eq!` args - --> tests/ui/format_args.rs:94:73 + --> tests/ui/format_args.rs:103:73 | LL | assert_eq!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `assert_ne!` args - --> tests/ui/format_args.rs:95:73 + --> tests/ui/format_args.rs:105:73 | LL | assert_ne!(0, 0, "error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `panic!` args - --> tests/ui/format_args.rs:96:63 + --> tests/ui/format_args.rs:107:63 | LL | panic!("error: something failed at {}", Location::caller().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:97:20 + --> tests/ui/format_args.rs:109:20 | LL | println!("{}", X(1).to_string()); | ^^^^^^^^^^^^^^^^ help: use this: `*X(1)` error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:98:20 + --> tests/ui/format_args.rs:111:20 | LL | println!("{}", Y(&X(1)).to_string()); | ^^^^^^^^^^^^^^^^^^^^ help: use this: `***Y(&X(1))` error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:99:24 + --> tests/ui/format_args.rs:113:24 | LL | println!("{}", Z(1).to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:100:20 + --> tests/ui/format_args.rs:115:20 | LL | println!("{}", x.to_string()); | ^^^^^^^^^^^^^ help: use this: `**x` error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:101:20 + --> tests/ui/format_args.rs:117:20 | LL | println!("{}", x_ref.to_string()); | ^^^^^^^^^^^^^^^^^ help: use this: `***x_ref` error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:103:39 + --> tests/ui/format_args.rs:120:39 | LL | println!("{foo}{bar}", foo = "foo".to_string(), bar = "bar"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:104:52 + --> tests/ui/format_args.rs:122:52 | LL | println!("{foo}{bar}", foo = "foo", bar = "bar".to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:105:39 + --> tests/ui/format_args.rs:124:39 | LL | println!("{foo}{bar}", bar = "bar".to_string(), foo = "foo"); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:106:52 + --> tests/ui/format_args.rs:126:52 | LL | println!("{foo}{bar}", bar = "bar", foo = "foo".to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:107:37 + --> tests/ui/format_args.rs:128:37 | LL | println!("{}", my_other_macro!().to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> tests/ui/format_args.rs:119:37 + --> tests/ui/format_args.rs:141:37 | LL | print!("{}", (Location::caller().to_string())); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `print!` args - --> tests/ui/format_args.rs:120:39 + --> tests/ui/format_args.rs:143:39 | LL | print!("{}", ((Location::caller()).to_string())); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `format!` args - --> tests/ui/format_args.rs:148:38 + --> tests/ui/format_args.rs:172:38 | LL | let x = format!("{} {}", a, b.to_string()); | ^^^^^^^^^^^^ help: remove this error: `to_string` applied to a type that implements `Display` in `println!` args - --> tests/ui/format_args.rs:162:24 + --> tests/ui/format_args.rs:187:24 | LL | println!("{}", original[..10].to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use this: `&original[..10]` diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.rs b/src/tools/clippy/tests/ui/format_args_unfixable.rs index 7590de3751a8e..9e1d6a649c35d 100644 --- a/src/tools/clippy/tests/ui/format_args_unfixable.rs +++ b/src/tools/clippy/tests/ui/format_args_unfixable.rs @@ -2,7 +2,7 @@ #![allow(unused)] #![allow(clippy::assertions_on_constants, clippy::eq_op, clippy::uninlined_format_args)] -use std::io::{Error, ErrorKind, Write, stdout}; +use std::io::{Error, Write, stdout}; use std::ops::Deref; use std::panic::Location; @@ -20,53 +20,68 @@ macro_rules! my_other_macro { } fn main() { - let error = Error::new(ErrorKind::Other, "bad thing"); + let error = Error::other("bad thing"); let x = 'x'; println!("error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `println!` args + //~^ format_in_format_args + println!("{}: {}", error, format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `println!` args + //~^ format_in_format_args + println!("{:?}: {}", error, format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `println!` args + //~^ format_in_format_args + println!("{{}}: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `println!` args + //~^ format_in_format_args + println!(r#"error: "{}""#, format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `println!` args + //~^ format_in_format_args + println!("error: {}", format!(r#"something failed at "{}""#, Location::caller())); - //~^ ERROR: `format!` in `println!` args + //~^ format_in_format_args + println!("error: {}", format!("something failed at {} {0}", Location::caller())); - //~^ ERROR: `format!` in `println!` args + //~^ format_in_format_args + let _ = format!("error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `format!` args + //~^ format_in_format_args + let _ = write!( - //~^ ERROR: `format!` in `write!` args + //~^ format_in_format_args stdout(), "error: {}", format!("something failed at {}", Location::caller()) ); let _ = writeln!( - //~^ ERROR: `format!` in `writeln!` args + //~^ format_in_format_args stdout(), "error: {}", format!("something failed at {}", Location::caller()) ); print!("error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `print!` args + //~^ format_in_format_args + eprint!("error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `eprint!` args + //~^ format_in_format_args + eprintln!("error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `eprintln!` args + //~^ format_in_format_args + let _ = format_args!("error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `format_args!` args + //~^ format_in_format_args + assert!(true, "error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `assert!` args + //~^ format_in_format_args + assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `assert_eq!` args + //~^ format_in_format_args + assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `assert_ne!` args + //~^ format_in_format_args + panic!("error: {}", format!("something failed at {}", Location::caller())); - //~^ ERROR: `format!` in `panic!` args + //~^ format_in_format_args // negative tests println!("error: {}", format_args!("something failed at {}", Location::caller())); @@ -100,7 +115,7 @@ macro_rules! my_println2_args { } fn test2() { - let error = Error::new(ErrorKind::Other, "bad thing"); + let error = Error::other("bad thing"); // None of these should be linted without the config change my_println2!(true, "error: {}", format!("something failed at {}", Location::caller())); @@ -130,21 +145,27 @@ macro_rules! usr_println { } fn user_format() { - let error = Error::new(ErrorKind::Other, "bad thing"); + let error = Error::other("bad thing"); let x = 'x'; usr_println!(true, "error: {}", format!("boom at {}", Location::caller())); - //~^ ERROR: `format!` in `usr_println!` args + //~^ format_in_format_args + usr_println!(true, "{}: {}", error, format!("boom at {}", Location::caller())); - //~^ ERROR: `format!` in `usr_println!` args + //~^ format_in_format_args + usr_println!(true, "{:?}: {}", error, format!("boom at {}", Location::caller())); - //~^ ERROR: `format!` in `usr_println!` args + //~^ format_in_format_args + usr_println!(true, "{{}}: {}", format!("boom at {}", Location::caller())); - //~^ ERROR: `format!` in `usr_println!` args + //~^ format_in_format_args + usr_println!(true, r#"error: "{}""#, format!("boom at {}", Location::caller())); - //~^ ERROR: `format!` in `usr_println!` args + //~^ format_in_format_args + usr_println!(true, "error: {}", format!(r#"boom at "{}""#, Location::caller())); - //~^ ERROR: `format!` in `usr_println!` args + //~^ format_in_format_args + usr_println!(true, "error: {}", format!("boom at {} {0}", Location::caller())); - //~^ ERROR: `format!` in `usr_println!` args + //~^ format_in_format_args } diff --git a/src/tools/clippy/tests/ui/format_args_unfixable.stderr b/src/tools/clippy/tests/ui/format_args_unfixable.stderr index 1b4b683fd6c62..1271e80b60a7b 100644 --- a/src/tools/clippy/tests/ui/format_args_unfixable.stderr +++ b/src/tools/clippy/tests/ui/format_args_unfixable.stderr @@ -10,7 +10,7 @@ LL | println!("error: {}", format!("something failed at {}", Location::calle = help: to override `-D warnings` add `#[allow(clippy::format_in_format_args)]` error: `format!` in `println!` args - --> tests/ui/format_args_unfixable.rs:28:5 + --> tests/ui/format_args_unfixable.rs:29:5 | LL | println!("{}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | println!("{}: {}", error, format!("something failed at {}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> tests/ui/format_args_unfixable.rs:30:5 + --> tests/ui/format_args_unfixable.rs:32:5 | LL | println!("{:?}: {}", error, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | println!("{:?}: {}", error, format!("something failed at {}", Location: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> tests/ui/format_args_unfixable.rs:32:5 + --> tests/ui/format_args_unfixable.rs:35:5 | LL | println!("{{}}: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | println!("{{}}: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> tests/ui/format_args_unfixable.rs:34:5 + --> tests/ui/format_args_unfixable.rs:38:5 | LL | println!(r#"error: "{}""#, format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | println!(r#"error: "{}""#, format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> tests/ui/format_args_unfixable.rs:36:5 + --> tests/ui/format_args_unfixable.rs:41:5 | LL | println!("error: {}", format!(r#"something failed at "{}""#, Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | println!("error: {}", format!(r#"something failed at "{}""#, Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `println!` args - --> tests/ui/format_args_unfixable.rs:38:5 + --> tests/ui/format_args_unfixable.rs:44:5 | LL | println!("error: {}", format!("something failed at {} {0}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | println!("error: {}", format!("something failed at {} {0}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `format!` args - --> tests/ui/format_args_unfixable.rs:40:13 + --> tests/ui/format_args_unfixable.rs:47:13 | LL | let _ = format!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = format!("error: {}", format!("something failed at {}", Location = help: or consider changing `format!` to `format_args!` error: `format!` in `write!` args - --> tests/ui/format_args_unfixable.rs:42:13 + --> tests/ui/format_args_unfixable.rs:50:13 | LL | let _ = write!( | _____________^ @@ -88,7 +88,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `writeln!` args - --> tests/ui/format_args_unfixable.rs:48:13 + --> tests/ui/format_args_unfixable.rs:56:13 | LL | let _ = writeln!( | _____________^ @@ -103,7 +103,7 @@ LL | | ); = help: or consider changing `format!` to `format_args!` error: `format!` in `print!` args - --> tests/ui/format_args_unfixable.rs:54:5 + --> tests/ui/format_args_unfixable.rs:62:5 | LL | print!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL | print!("error: {}", format!("something failed at {}", Location::caller( = help: or consider changing `format!` to `format_args!` error: `format!` in `eprint!` args - --> tests/ui/format_args_unfixable.rs:56:5 + --> tests/ui/format_args_unfixable.rs:65:5 | LL | eprint!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | eprint!("error: {}", format!("something failed at {}", Location::caller = help: or consider changing `format!` to `format_args!` error: `format!` in `eprintln!` args - --> tests/ui/format_args_unfixable.rs:58:5 + --> tests/ui/format_args_unfixable.rs:68:5 | LL | eprintln!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -130,7 +130,7 @@ LL | eprintln!("error: {}", format!("something failed at {}", Location::call = help: or consider changing `format!` to `format_args!` error: `format!` in `format_args!` args - --> tests/ui/format_args_unfixable.rs:60:13 + --> tests/ui/format_args_unfixable.rs:71:13 | LL | let _ = format_args!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,7 +139,7 @@ LL | let _ = format_args!("error: {}", format!("something failed at {}", Loc = help: or consider changing `format!` to `format_args!` error: `format!` in `assert!` args - --> tests/ui/format_args_unfixable.rs:62:5 + --> tests/ui/format_args_unfixable.rs:74:5 | LL | assert!(true, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL | assert!(true, "error: {}", format!("something failed at {}", Location:: = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_eq!` args - --> tests/ui/format_args_unfixable.rs:64:5 + --> tests/ui/format_args_unfixable.rs:77:5 | LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL | assert_eq!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `assert_ne!` args - --> tests/ui/format_args_unfixable.rs:66:5 + --> tests/ui/format_args_unfixable.rs:80:5 | LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -166,7 +166,7 @@ LL | assert_ne!(0, 0, "error: {}", format!("something failed at {}", Locatio = help: or consider changing `format!` to `format_args!` error: `format!` in `panic!` args - --> tests/ui/format_args_unfixable.rs:68:5 + --> tests/ui/format_args_unfixable.rs:83:5 | LL | panic!("error: {}", format!("something failed at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +175,7 @@ LL | panic!("error: {}", format!("something failed at {}", Location::caller( = help: or consider changing `format!` to `format_args!` error: `format!` in `usr_println!` args - --> tests/ui/format_args_unfixable.rs:136:5 + --> tests/ui/format_args_unfixable.rs:151:5 | LL | usr_println!(true, "error: {}", format!("boom at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +184,7 @@ LL | usr_println!(true, "error: {}", format!("boom at {}", Location::caller( = help: or consider changing `format!` to `format_args!` error: `format!` in `usr_println!` args - --> tests/ui/format_args_unfixable.rs:138:5 + --> tests/ui/format_args_unfixable.rs:154:5 | LL | usr_println!(true, "{}: {}", error, format!("boom at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL | usr_println!(true, "{}: {}", error, format!("boom at {}", Location::cal = help: or consider changing `format!` to `format_args!` error: `format!` in `usr_println!` args - --> tests/ui/format_args_unfixable.rs:140:5 + --> tests/ui/format_args_unfixable.rs:157:5 | LL | usr_println!(true, "{:?}: {}", error, format!("boom at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -202,7 +202,7 @@ LL | usr_println!(true, "{:?}: {}", error, format!("boom at {}", Location::c = help: or consider changing `format!` to `format_args!` error: `format!` in `usr_println!` args - --> tests/ui/format_args_unfixable.rs:142:5 + --> tests/ui/format_args_unfixable.rs:160:5 | LL | usr_println!(true, "{{}}: {}", format!("boom at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -211,7 +211,7 @@ LL | usr_println!(true, "{{}}: {}", format!("boom at {}", Location::caller() = help: or consider changing `format!` to `format_args!` error: `format!` in `usr_println!` args - --> tests/ui/format_args_unfixable.rs:144:5 + --> tests/ui/format_args_unfixable.rs:163:5 | LL | usr_println!(true, r#"error: "{}""#, format!("boom at {}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +220,7 @@ LL | usr_println!(true, r#"error: "{}""#, format!("boom at {}", Location::ca = help: or consider changing `format!` to `format_args!` error: `format!` in `usr_println!` args - --> tests/ui/format_args_unfixable.rs:146:5 + --> tests/ui/format_args_unfixable.rs:166:5 | LL | usr_println!(true, "error: {}", format!(r#"boom at "{}""#, Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL | usr_println!(true, "error: {}", format!(r#"boom at "{}""#, Location::ca = help: or consider changing `format!` to `format_args!` error: `format!` in `usr_println!` args - --> tests/ui/format_args_unfixable.rs:148:5 + --> tests/ui/format_args_unfixable.rs:169:5 | LL | usr_println!(true, "error: {}", format!("boom at {} {0}", Location::caller())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/format_collect.rs b/src/tools/clippy/tests/ui/format_collect.rs index 26ebdc6c0cb61..8f8633a52d867 100644 --- a/src/tools/clippy/tests/ui/format_collect.rs +++ b/src/tools/clippy/tests/ui/format_collect.rs @@ -3,13 +3,14 @@ fn hex_encode(bytes: &[u8]) -> String { bytes.iter().map(|b| format!("{b:02X}")).collect() - //~^ ERROR: use of `format!` to build up a string from an iterator + //~^ format_collect } #[rustfmt::skip] fn hex_encode_deep(bytes: &[u8]) -> String { bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect() - //~^ ERROR: use of `format!` to build up a string from an iterator + //~^ format_collect + } macro_rules! fmt { @@ -24,7 +25,7 @@ fn from_macro(bytes: &[u8]) -> String { fn with_block() -> String { (1..10) - //~^ ERROR: use of `format!` to build up a string from an iterator + //~^ format_collect .map(|s| { let y = 1; format!("{s} {y}") diff --git a/src/tools/clippy/tests/ui/format_collect.stderr b/src/tools/clippy/tests/ui/format_collect.stderr index 863b457a7905c..343e38a87b711 100644 --- a/src/tools/clippy/tests/ui/format_collect.stderr +++ b/src/tools/clippy/tests/ui/format_collect.stderr @@ -37,7 +37,7 @@ LL | bytes.iter().map(|b| {{{{{ format!("{b:02X}") }}}}}).collect() = note: this can be written more efficiently by appending to a `String` directly error: use of `format!` to build up a string from an iterator - --> tests/ui/format_collect.rs:26:5 + --> tests/ui/format_collect.rs:27:5 | LL | / (1..10) LL | | @@ -49,12 +49,12 @@ LL | | .collect() | |__________________^ | help: call `fold` instead - --> tests/ui/format_collect.rs:28:10 + --> tests/ui/format_collect.rs:29:10 | LL | .map(|s| { | ^^^ help: ... and use the `write!` macro here - --> tests/ui/format_collect.rs:30:13 + --> tests/ui/format_collect.rs:31:13 | LL | format!("{s} {y}") | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/format_push_string.rs b/src/tools/clippy/tests/ui/format_push_string.rs index 735ae3393289e..056ef59ff0e2b 100644 --- a/src/tools/clippy/tests/ui/format_push_string.rs +++ b/src/tools/clippy/tests/ui/format_push_string.rs @@ -3,9 +3,10 @@ fn main() { let mut string = String::new(); string += &format!("{:?}", 1234); - //~^ ERROR: `format!(..)` appended to existing `String` + //~^ format_push_string + string.push_str(&format!("{:?}", 5678)); - //~^ ERROR: `format!(..)` appended to existing `String` + //~^ format_push_string } mod issue9493 { @@ -13,7 +14,8 @@ mod issue9493 { let mut hex = String::with_capacity(vector.len() * 2); for byte in vector { hex += &(if upper { - //~^ ERROR: `format!(..)` appended to existing `String` + //~^ format_push_string + format!("{byte:02X}") } else { format!("{byte:02x}") @@ -26,14 +28,15 @@ mod issue9493 { let mut s = String::new(); // if let s += &(if let Some(_a) = Some(1234) { - //~^ ERROR: `format!(..)` appended to existing `String` + //~^ format_push_string + format!("{}", 1234) } else { format!("{}", 1234) }); // match s += &(match Some(1234) { - //~^ ERROR: `format!(..)` appended to existing `String` + //~^ format_push_string Some(_) => format!("{}", 1234), None => format!("{}", 1234), }); diff --git a/src/tools/clippy/tests/ui/format_push_string.stderr b/src/tools/clippy/tests/ui/format_push_string.stderr index a9520600f52a4..bba2a8947c43f 100644 --- a/src/tools/clippy/tests/ui/format_push_string.stderr +++ b/src/tools/clippy/tests/ui/format_push_string.stderr @@ -9,7 +9,7 @@ LL | string += &format!("{:?}", 1234); = help: to override `-D warnings` add `#[allow(clippy::format_push_string)]` error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:7:5 + --> tests/ui/format_push_string.rs:8:5 | LL | string.push_str(&format!("{:?}", 5678)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,10 +17,11 @@ LL | string.push_str(&format!("{:?}", 5678)); = help: consider using `write!` to avoid the extra allocation error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:15:13 + --> tests/ui/format_push_string.rs:16:13 | LL | / hex += &(if upper { LL | | +LL | | LL | | format!("{byte:02X}") LL | | } else { LL | | format!("{byte:02x}") @@ -30,10 +31,11 @@ LL | | }); = help: consider using `write!` to avoid the extra allocation error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:28:9 + --> tests/ui/format_push_string.rs:30:9 | LL | / s += &(if let Some(_a) = Some(1234) { LL | | +LL | | LL | | format!("{}", 1234) LL | | } else { LL | | format!("{}", 1234) @@ -43,7 +45,7 @@ LL | | }); = help: consider using `write!` to avoid the extra allocation error: `format!(..)` appended to existing `String` - --> tests/ui/format_push_string.rs:35:9 + --> tests/ui/format_push_string.rs:38:9 | LL | / s += &(match Some(1234) { LL | | diff --git a/src/tools/clippy/tests/ui/formatting.rs b/src/tools/clippy/tests/ui/formatting.rs index 312fa2aa40ad2..4e84dcf7d5b70 100644 --- a/src/tools/clippy/tests/ui/formatting.rs +++ b/src/tools/clippy/tests/ui/formatting.rs @@ -14,16 +14,19 @@ fn main() { // weird op_eq formatting: let mut a = 42; a =- 35; - //~^ ERROR: this looks like you are trying to use `.. -= ..`, but you really are doing - //~| NOTE: to remove this lint, use either `-=` or `= -` + //~^ suspicious_assignment_formatting + + a =* &191; - //~^ ERROR: this looks like you are trying to use `.. *= ..`, but you really are doing - //~| NOTE: to remove this lint, use either `*=` or `= *` + //~^ suspicious_assignment_formatting + + let mut b = true; b =! false; - //~^ ERROR: this looks like you are trying to use `.. != ..`, but you really are doing - //~| NOTE: to remove this lint, use either `!=` or `= !` + //~^ suspicious_assignment_formatting + + // those are ok: a = -35; @@ -33,14 +36,16 @@ fn main() { // possible missing comma in an array let _ = &[ -1, -2, -3 // <= no comma here - //~^ ERROR: possibly missing a comma here - //~| NOTE: to remove this lint, add a comma or write the expr in a single line + //~^ possible_missing_comma + + -4, -5, -6 ]; let _ = &[ -1, -2, -3 // <= no comma here - //~^ ERROR: possibly missing a comma here - //~| NOTE: to remove this lint, add a comma or write the expr in a single line + //~^ possible_missing_comma + + *4, -5, -6 ]; @@ -78,8 +83,9 @@ fn main() { // lint if it doesn't let _ = &[ -1 - //~^ ERROR: possibly missing a comma here - //~| NOTE: to remove this lint, add a comma or write the expr in a single line + //~^ possible_missing_comma + + -4, ]; } diff --git a/src/tools/clippy/tests/ui/formatting.stderr b/src/tools/clippy/tests/ui/formatting.stderr index e823e6512b8df..972bd3a6a2e65 100644 --- a/src/tools/clippy/tests/ui/formatting.stderr +++ b/src/tools/clippy/tests/ui/formatting.stderr @@ -9,7 +9,7 @@ LL | a =- 35; = help: to override `-D warnings` add `#[allow(clippy::suspicious_assignment_formatting)]` error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)` - --> tests/ui/formatting.rs:19:6 + --> tests/ui/formatting.rs:20:6 | LL | a =* &191; | ^^^^ @@ -17,7 +17,7 @@ LL | a =* &191; = note: to remove this lint, use either `*=` or `= *` error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)` - --> tests/ui/formatting.rs:24:6 + --> tests/ui/formatting.rs:26:6 | LL | b =! false; | ^^^^ @@ -25,7 +25,7 @@ LL | b =! false; = note: to remove this lint, use either `!=` or `= !` error: possibly missing a comma here - --> tests/ui/formatting.rs:35:19 + --> tests/ui/formatting.rs:38:19 | LL | -1, -2, -3 // <= no comma here | ^ @@ -35,7 +35,7 @@ LL | -1, -2, -3 // <= no comma here = help: to override `-D warnings` add `#[allow(clippy::possible_missing_comma)]` error: possibly missing a comma here - --> tests/ui/formatting.rs:41:19 + --> tests/ui/formatting.rs:45:19 | LL | -1, -2, -3 // <= no comma here | ^ @@ -43,7 +43,7 @@ LL | -1, -2, -3 // <= no comma here = note: to remove this lint, add a comma or write the expr in a single line error: possibly missing a comma here - --> tests/ui/formatting.rs:80:11 + --> tests/ui/formatting.rs:85:11 | LL | -1 | ^ diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.fixed b/src/tools/clippy/tests/ui/four_forward_slashes.fixed index 6d31c543d7274..6f387b67ccbf4 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes.fixed +++ b/src/tools/clippy/tests/ui/four_forward_slashes.fixed @@ -1,4 +1,3 @@ - //@aux-build:proc_macros.rs #![feature(custom_inner_attributes)] #![allow(unused)] @@ -10,14 +9,17 @@ extern crate proc_macros; /// whoops +//~^ four_forward_slashes fn a() {} /// whoops +//~^ four_forward_slashes #[allow(dead_code)] fn b() {} /// whoops /// two borked comments! +//~^^ four_forward_slashes #[track_caller] fn c() {} @@ -25,10 +27,12 @@ fn d() {} #[test] /// between attributes +//~^ four_forward_slashes #[allow(dead_code)] fn g() {} /// not very start of contents + //~^ four_forward_slashes fn h() {} fn i() { diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.rs b/src/tools/clippy/tests/ui/four_forward_slashes.rs index 458b8de53e15b..fae07e7d6094b 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes.rs +++ b/src/tools/clippy/tests/ui/four_forward_slashes.rs @@ -1,4 +1,3 @@ - //@aux-build:proc_macros.rs #![feature(custom_inner_attributes)] #![allow(unused)] @@ -10,14 +9,17 @@ extern crate proc_macros; //// whoops +//~^ four_forward_slashes fn a() {} //// whoops +//~^ four_forward_slashes #[allow(dead_code)] fn b() {} //// whoops //// two borked comments! +//~^^ four_forward_slashes #[track_caller] fn c() {} @@ -25,10 +27,12 @@ fn d() {} #[test] //// between attributes +//~^ four_forward_slashes #[allow(dead_code)] fn g() {} //// not very start of contents + //~^ four_forward_slashes fn h() {} fn i() { diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.stderr b/src/tools/clippy/tests/ui/four_forward_slashes.stderr index d5bf71fadc7d6..95c860b29fba5 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes.stderr +++ b/src/tools/clippy/tests/ui/four_forward_slashes.stderr @@ -1,7 +1,8 @@ error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't - --> tests/ui/four_forward_slashes.rs:12:1 + --> tests/ui/four_forward_slashes.rs:11:1 | LL | / //// whoops +LL | | LL | | fn a() {} | |_^ | @@ -10,7 +11,7 @@ LL | | fn a() {} help: make this a doc comment by removing one `/` | LL - //// whoops -LL - fn a() {} +LL - LL + /// whoops | @@ -18,6 +19,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d --> tests/ui/four_forward_slashes.rs:15:1 | LL | / //// whoops +LL | | LL | | #[allow(dead_code)] LL | | fn b() {} | |_^ @@ -25,15 +27,16 @@ LL | | fn b() {} help: make this a doc comment by removing one `/` | LL - //// whoops -LL - #[allow(dead_code)] +LL - LL + /// whoops | error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't - --> tests/ui/four_forward_slashes.rs:19:1 + --> tests/ui/four_forward_slashes.rs:20:1 | LL | / //// whoops LL | | //// two borked comments! +LL | | LL | | #[track_caller] LL | | fn c() {} | |_^ @@ -45,9 +48,10 @@ LL ~ /// two borked comments! | error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't - --> tests/ui/four_forward_slashes.rs:27:1 + --> tests/ui/four_forward_slashes.rs:29:1 | LL | / //// between attributes +LL | | LL | | #[allow(dead_code)] LL | | fn g() {} | |_^ @@ -55,21 +59,22 @@ LL | | fn g() {} help: make this a doc comment by removing one `/` | LL - //// between attributes -LL - #[allow(dead_code)] +LL - LL + /// between attributes | error: this item has comments with 4 forward slashes (`////`). These look like doc comments, but they aren't - --> tests/ui/four_forward_slashes.rs:31:1 + --> tests/ui/four_forward_slashes.rs:34:1 | LL | / //// not very start of contents +LL | | LL | | fn h() {} | |_^ | help: make this a doc comment by removing one `/` | LL - //// not very start of contents -LL - fn h() {} +LL - LL + /// not very start of contents | diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed index 5ef40015d88b6..34604a6461b93 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed +++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.fixed @@ -1,4 +1,5 @@ /// borked doc comment on the first line. doesn't combust! +//~^ four_forward_slashes fn a() {} // This test's entire purpose is to make sure we don't panic if the comment with four slashes diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs index 9c835e745f654..150e9ba2711cc 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs +++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.rs @@ -1,4 +1,5 @@ //// borked doc comment on the first line. doesn't combust! +//~^ four_forward_slashes fn a() {} // This test's entire purpose is to make sure we don't panic if the comment with four slashes diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr index 83bfb60eb16fc..6fcd3e2c1b730 100644 --- a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr +++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr @@ -2,6 +2,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d --> tests/ui/four_forward_slashes_first_line.rs:1:1 | LL | / //// borked doc comment on the first line. doesn't combust! +LL | | LL | | fn a() {} | |_^ | @@ -10,7 +11,7 @@ LL | | fn a() {} help: make this a doc comment by removing one `/` | LL - //// borked doc comment on the first line. doesn't combust! -LL - fn a() {} +LL - LL + /// borked doc comment on the first line. doesn't combust! | diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed index 67da45a348f97..8618004efb89f 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed @@ -15,46 +15,61 @@ impl FromIterator for Foo { impl<'a> FromIterator<&'a bool> for Foo { fn from_iter>(iter: T) -> Self { iter.into_iter().copied().collect::() + //~^ from_iter_instead_of_collect } } fn main() { let iter_expr = std::iter::repeat(5).take(5); let _ = iter_expr.collect::>(); + //~^ from_iter_instead_of_collect let _ = vec![5, 5, 5, 5].iter().enumerate().collect::>(); + //~^ from_iter_instead_of_collect Vec::from_iter(vec![42u32]); let a = vec![0, 1, 2]; assert_eq!(a, (0..3).collect::>()); + //~^ from_iter_instead_of_collect assert_eq!(a, (0..3).collect::>()); + //~^ from_iter_instead_of_collect let mut b = (0..3).collect::>(); + //~^ from_iter_instead_of_collect b.push_back(4); let mut b = (0..3).collect::>(); + //~^ from_iter_instead_of_collect b.push_back(4); { use std::collections; let mut b = (0..3).collect::>(); + //~^ from_iter_instead_of_collect b.push_back(4); } let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; let bm = values.iter().cloned().collect::>(); + //~^ from_iter_instead_of_collect let mut bar = bm.range(0..2).collect::>(); + //~^ from_iter_instead_of_collect bar.insert(&4, &'e'); let mut bts = (0..3).collect::>(); + //~^ from_iter_instead_of_collect bts.insert(2); { use std::collections; let _ = (0..3).collect::>(); + //~^ from_iter_instead_of_collect let _ = (0..3).collect::>(); + //~^ from_iter_instead_of_collect } for _i in [1, 2, 3].iter().collect::>() {} + //~^ from_iter_instead_of_collect for _i in [1, 2, 3].iter().collect::>() {} + //~^ from_iter_instead_of_collect } diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs index 423a7454bed7b..c46397e8ff560 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs @@ -15,46 +15,61 @@ impl FromIterator for Foo { impl<'a> FromIterator<&'a bool> for Foo { fn from_iter>(iter: T) -> Self { >::from_iter(iter.into_iter().copied()) + //~^ from_iter_instead_of_collect } } fn main() { let iter_expr = std::iter::repeat(5).take(5); let _ = Vec::from_iter(iter_expr); + //~^ from_iter_instead_of_collect let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); + //~^ from_iter_instead_of_collect Vec::from_iter(vec![42u32]); let a = vec![0, 1, 2]; assert_eq!(a, Vec::from_iter(0..3)); + //~^ from_iter_instead_of_collect assert_eq!(a, Vec::::from_iter(0..3)); + //~^ from_iter_instead_of_collect let mut b = VecDeque::from_iter(0..3); + //~^ from_iter_instead_of_collect b.push_back(4); let mut b = VecDeque::::from_iter(0..3); + //~^ from_iter_instead_of_collect b.push_back(4); { use std::collections; let mut b = collections::VecDeque::::from_iter(0..3); + //~^ from_iter_instead_of_collect b.push_back(4); } let values = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]; let bm = BTreeMap::from_iter(values.iter().cloned()); + //~^ from_iter_instead_of_collect let mut bar = BTreeMap::from_iter(bm.range(0..2)); + //~^ from_iter_instead_of_collect bar.insert(&4, &'e'); let mut bts = BTreeSet::from_iter(0..3); + //~^ from_iter_instead_of_collect bts.insert(2); { use std::collections; let _ = collections::BTreeSet::from_iter(0..3); + //~^ from_iter_instead_of_collect let _ = collections::BTreeSet::::from_iter(0..3); + //~^ from_iter_instead_of_collect } for _i in Vec::from_iter([1, 2, 3].iter()) {} + //~^ from_iter_instead_of_collect for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} + //~^ from_iter_instead_of_collect } diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr index 0824a526b793d..b46d97af152f6 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr @@ -8,85 +8,85 @@ LL | >::from_iter(iter.into_iter().copied()) = help: to override `-D warnings` add `#[allow(clippy::from_iter_instead_of_collect)]` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:23:13 + --> tests/ui/from_iter_instead_of_collect.rs:24:13 | LL | let _ = Vec::from_iter(iter_expr); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:25:13 + --> tests/ui/from_iter_instead_of_collect.rs:27:13 | LL | let _ = HashMap::::from_iter(vec![5, 5, 5, 5].iter().enumerate()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:30:19 + --> tests/ui/from_iter_instead_of_collect.rs:33:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:31:19 + --> tests/ui/from_iter_instead_of_collect.rs:35:19 | LL | assert_eq!(a, Vec::::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:33:17 + --> tests/ui/from_iter_instead_of_collect.rs:38:17 | LL | let mut b = VecDeque::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:36:17 + --> tests/ui/from_iter_instead_of_collect.rs:42:17 | LL | let mut b = VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:41:21 + --> tests/ui/from_iter_instead_of_collect.rs:48:21 | LL | let mut b = collections::VecDeque::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:46:14 + --> tests/ui/from_iter_instead_of_collect.rs:54:14 | LL | let bm = BTreeMap::from_iter(values.iter().cloned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:47:19 + --> tests/ui/from_iter_instead_of_collect.rs:56:19 | LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:50:19 + --> tests/ui/from_iter_instead_of_collect.rs:60:19 | LL | let mut bts = BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:54:17 + --> tests/ui/from_iter_instead_of_collect.rs:65:17 | LL | let _ = collections::BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:55:17 + --> tests/ui/from_iter_instead_of_collect.rs:67:17 | LL | let _ = collections::BTreeSet::::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:58:15 + --> tests/ui/from_iter_instead_of_collect.rs:71:15 | LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` error: usage of `FromIterator::from_iter` - --> tests/ui/from_iter_instead_of_collect.rs:59:15 + --> tests/ui/from_iter_instead_of_collect.rs:73:15 | LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::>()` diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed index a33c1ea5738b9..7d6780a0e02c8 100644 --- a/src/tools/clippy/tests/ui/from_over_into.fixed +++ b/src/tools/clippy/tests/ui/from_over_into.fixed @@ -7,6 +7,7 @@ struct StringWrapper(String); impl From for StringWrapper { + //~^ from_over_into fn from(val: String) -> Self { StringWrapper(val) } @@ -15,6 +16,7 @@ impl From for StringWrapper { struct SelfType(String); impl From for SelfType { + //~^ from_over_into fn from(val: String) -> Self { SelfType(String::new()) } @@ -30,6 +32,7 @@ impl X { struct SelfKeywords; impl From for SelfKeywords { + //~^ from_over_into fn from(val: X) -> Self { let _ = X; let _ = X::FOO; @@ -42,6 +45,7 @@ impl From for SelfKeywords { struct ExplicitPaths(bool); impl core::convert::From for bool { + //~^ from_over_into fn from(mut val: crate::ExplicitPaths) -> Self { let in_closure = || val.0; @@ -62,6 +66,7 @@ impl From for A { struct PathInExpansion; impl From for String { + //~^ from_over_into fn from(val: PathInExpansion) -> Self { // non self/Self paths in expansions are fine panic!() @@ -84,6 +89,7 @@ fn msrv_1_41() { struct FromOverInto(Vec); impl From> for FromOverInto { + //~^ from_over_into fn from(val: Vec) -> Self { FromOverInto(val) } @@ -94,6 +100,7 @@ fn issue_12138() { struct Hello; impl From for () { + //~^ from_over_into fn from(val: Hello) {} } } diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs index 6cd811ae401e2..387ddde359c16 100644 --- a/src/tools/clippy/tests/ui/from_over_into.rs +++ b/src/tools/clippy/tests/ui/from_over_into.rs @@ -7,6 +7,7 @@ struct StringWrapper(String); impl Into for String { + //~^ from_over_into fn into(self) -> StringWrapper { StringWrapper(self) } @@ -15,6 +16,7 @@ impl Into for String { struct SelfType(String); impl Into for String { + //~^ from_over_into fn into(self) -> SelfType { SelfType(Self::new()) } @@ -30,6 +32,7 @@ impl X { struct SelfKeywords; impl Into for X { + //~^ from_over_into fn into(self) -> SelfKeywords { let _ = Self; let _ = Self::FOO; @@ -42,6 +45,7 @@ impl Into for X { struct ExplicitPaths(bool); impl core::convert::Into for crate::ExplicitPaths { + //~^ from_over_into fn into(mut self) -> bool { let in_closure = || self.0; @@ -62,6 +66,7 @@ impl From for A { struct PathInExpansion; impl Into for PathInExpansion { + //~^ from_over_into fn into(self) -> String { // non self/Self paths in expansions are fine panic!() @@ -84,6 +89,7 @@ fn msrv_1_41() { struct FromOverInto(Vec); impl Into> for Vec { + //~^ from_over_into fn into(self) -> FromOverInto { FromOverInto(self) } @@ -94,6 +100,7 @@ fn issue_12138() { struct Hello; impl Into<()> for Hello { + //~^ from_over_into fn into(self) {} } } diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr index f913ae0bb5067..a564bccbaf71f 100644 --- a/src/tools/clippy/tests/ui/from_over_into.stderr +++ b/src/tools/clippy/tests/ui/from_over_into.stderr @@ -9,12 +9,13 @@ LL | impl Into for String { help: replace the `Into` implementation with `From` | LL ~ impl From for StringWrapper { +LL | LL ~ fn from(val: String) -> Self { LL ~ StringWrapper(val) | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into.rs:17:1 + --> tests/ui/from_over_into.rs:18:1 | LL | impl Into for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,12 +23,13 @@ LL | impl Into for String { help: replace the `Into` implementation with `From` | LL ~ impl From for SelfType { +LL | LL ~ fn from(val: String) -> Self { LL ~ SelfType(String::new()) | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into.rs:32:1 + --> tests/ui/from_over_into.rs:34:1 | LL | impl Into for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,6 +37,7 @@ LL | impl Into for X { help: replace the `Into` implementation with `From` | LL ~ impl From for SelfKeywords { +LL | LL ~ fn from(val: X) -> Self { LL ~ let _ = X; LL ~ let _ = X::FOO; @@ -42,7 +45,7 @@ LL ~ let _: X = val; | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into.rs:44:1 + --> tests/ui/from_over_into.rs:47:1 | LL | impl core::convert::Into for crate::ExplicitPaths { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,6 +55,7 @@ LL | impl core::convert::Into for crate::ExplicitPaths { help: replace the `Into` implementation with `From` | LL ~ impl core::convert::From for bool { +LL | LL ~ fn from(mut val: crate::ExplicitPaths) -> Self { LL ~ let in_closure = || val.0; LL | @@ -60,7 +64,7 @@ LL ~ val.0 | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into.rs:64:1 + --> tests/ui/from_over_into.rs:68:1 | LL | impl Into for PathInExpansion { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,11 +74,12 @@ LL | impl Into for PathInExpansion { help: replace the `Into` implementation with `From` | LL ~ impl From for String { +LL | LL ~ fn from(val: PathInExpansion) -> Self { | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into.rs:86:5 + --> tests/ui/from_over_into.rs:91:5 | LL | impl Into> for Vec { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,12 +87,13 @@ LL | impl Into> for Vec { help: replace the `Into` implementation with `From>` | LL ~ impl From> for FromOverInto { +LL | LL ~ fn from(val: Vec) -> Self { LL ~ FromOverInto(val) | error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into.rs:96:5 + --> tests/ui/from_over_into.rs:102:5 | LL | impl Into<()> for Hello { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,6 +103,7 @@ LL | impl Into<()> for Hello { help: replace the `Into` implementation with `From` | LL ~ impl From for () { +LL | LL ~ fn from(val: Hello) {} | diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs index 0c1f39f93fd33..de90c7c21a65d 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.rs +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.rs @@ -9,7 +9,8 @@ macro_rules! in_macro { } impl Into for String { - //~^ ERROR: an implementation of `From` is preferred since it gives you `Into<_>` for free + //~^ from_over_into + fn into(self) -> InMacro { InMacro(in_macro!()) } @@ -18,7 +19,8 @@ impl Into for String { struct WeirdUpperSelf; impl Into for &'static [u8] { - //~^ ERROR: an implementation of `From` is preferred since it gives you `Into<_>` for free + //~^ from_over_into + fn into(self) -> WeirdUpperSelf { let _ = Self::default(); WeirdUpperSelf @@ -28,7 +30,8 @@ impl Into for &'static [u8] { struct ContainsVal; impl Into for ContainsVal { - //~^ ERROR: an implementation of `From` is preferred since it gives you `Into<_>` for free + //~^ from_over_into + fn into(self) -> u8 { let val = 1; val + 1 @@ -40,7 +43,8 @@ pub struct Lval(T); pub struct Rval(T); impl Into> for Lval { - //~^ ERROR: an implementation of `From` is preferred since it gives you `Into<_>` for free + //~^ from_over_into + fn into(self) -> Rval { Rval(self) } diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr index 1776b86e40dd3..0e9264a153bb2 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr @@ -9,7 +9,7 @@ LL | impl Into for String { = help: to override `-D warnings` add `#[allow(clippy::from_over_into)]` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into_unfixable.rs:20:1 + --> tests/ui/from_over_into_unfixable.rs:21:1 | LL | impl Into for &'static [u8] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | impl Into for &'static [u8] { = help: replace the `Into` implementation with `From<&'static [u8]>` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into_unfixable.rs:30:1 + --> tests/ui/from_over_into_unfixable.rs:32:1 | LL | impl Into for ContainsVal { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | impl Into for ContainsVal { = help: replace the `Into` implementation with `From` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true - --> tests/ui/from_over_into_unfixable.rs:42:1 + --> tests/ui/from_over_into_unfixable.rs:45:1 | LL | impl Into> for Lval { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/from_raw_with_void_ptr.rs b/src/tools/clippy/tests/ui/from_raw_with_void_ptr.rs index 81472070eb4ce..3903138844339 100644 --- a/src/tools/clippy/tests/ui/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/tests/ui/from_raw_with_void_ptr.rs @@ -9,7 +9,7 @@ fn main() { // must lint let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void; let _ = unsafe { Box::from_raw(ptr) }; - //~^ ERROR: creating a `Box` from a void raw pointer + //~^ from_raw_with_void_ptr // shouldn't be linted let _ = unsafe { Box::from_raw(ptr as *mut usize) }; @@ -21,20 +21,20 @@ fn main() { // must lint let ptr = Rc::into_raw(Rc::new(42usize)) as *mut c_void; let _ = unsafe { Rc::from_raw(ptr) }; - //~^ ERROR: creating a `Rc` from a void raw pointer + //~^ from_raw_with_void_ptr // must lint let ptr = Arc::into_raw(Arc::new(42usize)) as *mut c_void; let _ = unsafe { Arc::from_raw(ptr) }; - //~^ ERROR: creating a `Arc` from a void raw pointer + //~^ from_raw_with_void_ptr // must lint let ptr = std::rc::Weak::into_raw(Rc::downgrade(&Rc::new(42usize))) as *mut c_void; let _ = unsafe { std::rc::Weak::from_raw(ptr) }; - //~^ ERROR: creating a `Weak` from a void raw pointer + //~^ from_raw_with_void_ptr // must lint let ptr = std::sync::Weak::into_raw(Arc::downgrade(&Arc::new(42usize))) as *mut c_void; let _ = unsafe { std::sync::Weak::from_raw(ptr) }; - //~^ ERROR: creating a `Weak` from a void raw pointer + //~^ from_raw_with_void_ptr } diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed index 6c582190b4424..4b8fd778685e0 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed +++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed @@ -26,26 +26,30 @@ impl std::ops::Add for Test { fn main() -> Result<(), Box> { // all of these should trigger the lint "30".parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` - //~| NOTE: `-D clippy::from-str-radix-10` implied by `-D warnings` + //~^ from_str_radix_10 + "24".parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + "100".parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + "7".parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + ("10".to_owned() + "5").parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + (Test + Test).parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 let string = "300"; string.parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 let stringier = "400".to_string(); stringier.parse::()?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 // none of these should trigger the lint u16::from_str_radix("20", 3)?; diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs index 0df6a0a202ae7..89002b11a9950 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.rs +++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs @@ -26,26 +26,30 @@ impl std::ops::Add for Test { fn main() -> Result<(), Box> { // all of these should trigger the lint u32::from_str_radix("30", 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` - //~| NOTE: `-D clippy::from-str-radix-10` implied by `-D warnings` + //~^ from_str_radix_10 + i64::from_str_radix("24", 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + isize::from_str_radix("100", 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + u8::from_str_radix("7", 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + u16::from_str_radix(&("10".to_owned() + "5"), 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 + i128::from_str_radix(Test + Test, 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 let string = "300"; i32::from_str_radix(string, 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 let stringier = "400".to_string(); i32::from_str_radix(&stringier, 10)?; - //~^ ERROR: this call to `from_str_radix` can be replaced with a call to `str::parse` + //~^ from_str_radix_10 // none of these should trigger the lint u16::from_str_radix("20", 3)?; diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr index 4aa84eca26120..c693e8f50ff68 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr +++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr @@ -14,37 +14,37 @@ LL | i64::from_str_radix("24", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:33:5 + --> tests/ui/from_str_radix_10.rs:34:5 | LL | isize::from_str_radix("100", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:35:5 + --> tests/ui/from_str_radix_10.rs:37:5 | LL | u8::from_str_radix("7", 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:37:5 + --> tests/ui/from_str_radix_10.rs:40:5 | LL | u16::from_str_radix(&("10".to_owned() + "5"), 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:39:5 + --> tests/ui/from_str_radix_10.rs:43:5 | LL | i128::from_str_radix(Test + Test, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:43:5 + --> tests/ui/from_str_radix_10.rs:47:5 | LL | i32::from_str_radix(string, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::()` error: this call to `from_str_radix` can be replaced with a call to `str::parse` - --> tests/ui/from_str_radix_10.rs:47:5 + --> tests/ui/from_str_radix_10.rs:51:5 | LL | i32::from_str_radix(&stringier, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::()` diff --git a/src/tools/clippy/tests/ui/functions.rs b/src/tools/clippy/tests/ui/functions.rs index 0aef60959593b..9c1ca8bf93009 100644 --- a/src/tools/clippy/tests/ui/functions.rs +++ b/src/tools/clippy/tests/ui/functions.rs @@ -6,12 +6,12 @@ fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} -//~^ ERROR: this function has too many arguments (8/7) -//~| NOTE: `-D clippy::too-many-arguments` implied by `-D warnings` +//~^ too_many_arguments #[rustfmt::skip] fn bad_multiline( -//~^ ERROR: this function has too many arguments (8/7) +//~^ too_many_arguments + one: u32, two: u32, three: &str, @@ -46,7 +46,7 @@ extern "C" fn extern_fn( pub trait Foo { fn good(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool); fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()); - //~^ ERROR: this function has too many arguments (8/7) + //~^ too_many_arguments fn ptr(p: *const u8); } @@ -56,7 +56,7 @@ pub struct Bar; impl Bar { fn good_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool) {} fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} - //~^ ERROR: this function has too many arguments (8/7) + //~^ too_many_arguments } // ok, we don’t want to warn implementations @@ -66,12 +66,13 @@ impl Foo for Bar { fn ptr(p: *const u8) { println!("{}", unsafe { *p }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked - //~| NOTE: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` + //~^ not_unsafe_ptr_arg_deref + println!("{:?}", unsafe { p.as_ref() }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked + //~^ not_unsafe_ptr_arg_deref + unsafe { std::ptr::read(p) }; - //~^ ERROR: this public function might dereference a raw pointer but is not marked + //~^ not_unsafe_ptr_arg_deref } } @@ -83,22 +84,26 @@ fn private(p: *const u8) { pub fn public(p: *const u8) { println!("{}", unsafe { *p }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked `un + //~^ not_unsafe_ptr_arg_deref + println!("{:?}", unsafe { p.as_ref() }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked `un + //~^ not_unsafe_ptr_arg_deref + unsafe { std::ptr::read(p) }; - //~^ ERROR: this public function might dereference a raw pointer but is not marked `un + //~^ not_unsafe_ptr_arg_deref } type Alias = *const u8; pub fn type_alias(p: Alias) { println!("{}", unsafe { *p }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked `un + //~^ not_unsafe_ptr_arg_deref + println!("{:?}", unsafe { p.as_ref() }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked `un + //~^ not_unsafe_ptr_arg_deref + unsafe { std::ptr::read(p) }; - //~^ ERROR: this public function might dereference a raw pointer but is not marked `un + //~^ not_unsafe_ptr_arg_deref } impl Bar { @@ -108,11 +113,13 @@ impl Bar { pub fn public(self, p: *const u8) { println!("{}", unsafe { *p }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked + //~^ not_unsafe_ptr_arg_deref + println!("{:?}", unsafe { p.as_ref() }); - //~^ ERROR: this public function might dereference a raw pointer but is not marked + //~^ not_unsafe_ptr_arg_deref + unsafe { std::ptr::read(p) }; - //~^ ERROR: this public function might dereference a raw pointer but is not marked + //~^ not_unsafe_ptr_arg_deref } pub fn public_ok(self, p: *const u8) { diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr index 8fdceb8d8cd07..c8770023f77a0 100644 --- a/src/tools/clippy/tests/ui/functions.stderr +++ b/src/tools/clippy/tests/ui/functions.stderr @@ -8,12 +8,12 @@ LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f = help: to override `-D warnings` add `#[allow(clippy::too_many_arguments)]` error: this function has too many arguments (8/7) - --> tests/ui/functions.rs:13:1 + --> tests/ui/functions.rs:12:1 | LL | / fn bad_multiline( LL | | +LL | | LL | | one: u32, -LL | | two: u32, ... | LL | | eight: () LL | | ) { @@ -47,61 +47,61 @@ LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:73:33 + --> tests/ui/functions.rs:74:33 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:85:30 + --> tests/ui/functions.rs:86:30 | LL | println!("{}", unsafe { *p }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:87:31 + --> tests/ui/functions.rs:89:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:89:29 + --> tests/ui/functions.rs:92:29 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:96:30 + --> tests/ui/functions.rs:99:30 | LL | println!("{}", unsafe { *p }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:98:31 + --> tests/ui/functions.rs:102:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:100:29 + --> tests/ui/functions.rs:105:29 | LL | unsafe { std::ptr::read(p) }; | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:110:34 + --> tests/ui/functions.rs:115:34 | LL | println!("{}", unsafe { *p }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:112:35 + --> tests/ui/functions.rs:118:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ error: this public function might dereference a raw pointer but is not marked `unsafe` - --> tests/ui/functions.rs:114:33 + --> tests/ui/functions.rs:121:33 | LL | unsafe { std::ptr::read(p) }; | ^ diff --git a/src/tools/clippy/tests/ui/functions_maxlines.rs b/src/tools/clippy/tests/ui/functions_maxlines.rs index a3496f56d4a62..e0990dadaaa91 100644 --- a/src/tools/clippy/tests/ui/functions_maxlines.rs +++ b/src/tools/clippy/tests/ui/functions_maxlines.rs @@ -56,8 +56,8 @@ fn good_lines() { } fn bad_lines() { - //~^ ERROR: this function has too many lines (102/100) - //~| NOTE: `-D clippy::too-many-lines` implied by `-D warnings` + //~^ too_many_lines + println!("Dont get confused by braces: {{}}"); println!("This is bad."); println!("This is bad."); diff --git a/src/tools/clippy/tests/ui/future_not_send.rs b/src/tools/clippy/tests/ui/future_not_send.rs index 626ee6de9e4fb..662ecb9c955de 100644 --- a/src/tools/clippy/tests/ui/future_not_send.rs +++ b/src/tools/clippy/tests/ui/future_not_send.rs @@ -6,12 +6,14 @@ use std::rc::Rc; use std::sync::Arc; async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { - //~^ ERROR: future cannot be sent between threads safely + //~^ future_not_send + async { true }.await } pub async fn public_future(rc: Rc<[u8]>) { - //~^ ERROR: future cannot be sent between threads safely + //~^ future_not_send + async { true }.await; } @@ -20,12 +22,13 @@ pub async fn public_send(arc: Arc<[u8]>) -> bool { } async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { - //~^ ERROR: future cannot be sent between threads safely + //~^ future_not_send + true } pub async fn public_future2(rc: Rc<[u8]>) {} -//~^ ERROR: future cannot be sent between threads safely +//~^ future_not_send pub async fn public_send2(arc: Arc<[u8]>) -> bool { false @@ -37,13 +40,15 @@ struct Dummy { impl Dummy { async fn private_future(&self) -> usize { - //~^ ERROR: future cannot be sent between threads safely + //~^ future_not_send + async { true }.await; self.rc.len() } pub async fn public_future(&self) { - //~^ ERROR: future cannot be sent between threads safely + //~^ future_not_send + self.private_future().await; } @@ -54,7 +59,7 @@ impl Dummy { } async fn generic_future(t: T) -> T -//~^ ERROR: future cannot be sent between threads safely +//~^ future_not_send where T: Send, { @@ -76,7 +81,8 @@ async fn maybe_send_generic_future2 Fut, Fut: Future>(f: F) { } async fn generic_future_always_unsend(_: Rc) { - //~^ ERROR: future cannot be sent between threads safely + //~^ future_not_send + async { true }.await; } diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr index 3807c74701368..e366dc2d21958 100644 --- a/src/tools/clippy/tests/ui/future_not_send.stderr +++ b/src/tools/clippy/tests/ui/future_not_send.stderr @@ -5,11 +5,11 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:10:20 + --> tests/ui/future_not_send.rs:11:20 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` -LL | +... LL | async { true }.await | ^^^^^ await occurs here, with `rc` maybe used later = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` @@ -23,84 +23,84 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell) -> bool { = help: to override `-D warnings` add `#[allow(clippy::future_not_send)]` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:13:1 + --> tests/ui/future_not_send.rs:14:1 | LL | pub async fn public_future(rc: Rc<[u8]>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:15:20 + --> tests/ui/future_not_send.rs:17:20 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` -LL | +... LL | async { true }.await; | ^^^^^ await occurs here, with `rc` maybe used later = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:22:1 + --> tests/ui/future_not_send.rs:24:1 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send` | note: captured value is not `Send` - --> tests/ui/future_not_send.rs:22:26 + --> tests/ui/future_not_send.rs:24:26 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui/future_not_send.rs:22:40 + --> tests/ui/future_not_send.rs:24:40 | LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell) -> bool { | ^^^^ has type `&std::cell::Cell` which is not `Send`, because `std::cell::Cell` is not `Sync` = note: `std::cell::Cell` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:27:1 + --> tests/ui/future_not_send.rs:30:1 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send` | note: captured value is not `Send` - --> tests/ui/future_not_send.rs:27:29 + --> tests/ui/future_not_send.rs:30:29 | LL | pub async fn public_future2(rc: Rc<[u8]>) {} | ^^ has type `std::rc::Rc<[u8]>` which is not `Send` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:39:5 + --> tests/ui/future_not_send.rs:42:5 | LL | async fn private_future(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:41:24 + --> tests/ui/future_not_send.rs:45:24 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` -LL | +... LL | async { true }.await; | ^^^^^ await occurs here, with `&self` maybe used later = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:45:5 + --> tests/ui/future_not_send.rs:49:5 | LL | pub async fn public_future(&self) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send` | note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync` - --> tests/ui/future_not_send.rs:45:32 + --> tests/ui/future_not_send.rs:49:32 | LL | pub async fn public_future(&self) { | ^^^^^ has type `&Dummy` which is not `Send`, because `Dummy` is not `Sync` = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:56:1 + --> tests/ui/future_not_send.rs:61:1 | LL | / async fn generic_future(t: T) -> T LL | | @@ -109,7 +109,7 @@ LL | | T: Send, | |____________^ future returned by `generic_future` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:62:20 + --> tests/ui/future_not_send.rs:67:20 | LL | let rt = &t; | -- has type `&T` which is not `Send` @@ -118,17 +118,17 @@ LL | async { true }.await; = note: `T` doesn't implement `std::marker::Sync` error: future cannot be sent between threads safely - --> tests/ui/future_not_send.rs:78:1 + --> tests/ui/future_not_send.rs:83:1 | LL | async fn generic_future_always_unsend(_: Rc) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `generic_future_always_unsend` is not `Send` | note: future is not `Send` as this value is used across an await - --> tests/ui/future_not_send.rs:80:20 + --> tests/ui/future_not_send.rs:86:20 | LL | async fn generic_future_always_unsend(_: Rc) { | - has type `std::rc::Rc` which is not `Send` -LL | +... LL | async { true }.await; | ^^^^^ await occurs here, with `_` maybe used later = note: `std::rc::Rc` doesn't implement `std::marker::Send` diff --git a/src/tools/clippy/tests/ui/get_first.fixed b/src/tools/clippy/tests/ui/get_first.fixed index 710ebab1ef2dd..584080defa1e4 100644 --- a/src/tools/clippy/tests/ui/get_first.fixed +++ b/src/tools/clippy/tests/ui/get_first.fixed @@ -15,25 +15,29 @@ impl Bar { fn main() { let x = vec![2, 3, 5]; let _ = x.first(); - //~^ ERROR: accessing first element with `x.get(0)` + //~^ get_first + let _ = x.get(1); let _ = x[0]; let y = [2, 3, 5]; let _ = y.first(); - //~^ ERROR: accessing first element with `y.get(0)` + //~^ get_first + let _ = y.get(1); let _ = y[0]; let z = &[2, 3, 5]; let _ = z.first(); - //~^ ERROR: accessing first element with `z.get(0)` + //~^ get_first + let _ = z.get(1); let _ = z[0]; let vecdeque: VecDeque<_> = x.iter().cloned().collect(); let _ = vecdeque.front(); - //~^ ERROR: accessing first element with `vecdeque.get(0)` + //~^ get_first + let _ = vecdeque.get(1); let hashmap: HashMap = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); @@ -46,5 +50,5 @@ fn main() { let non_primitives = [vec![1, 2], vec![3, 4]]; let _ = non_primitives.first(); - //~^ ERROR: accessing first element with `non_primitives.get(0)` + //~^ get_first } diff --git a/src/tools/clippy/tests/ui/get_first.rs b/src/tools/clippy/tests/ui/get_first.rs index ad2ba6ce2c3b6..f01fbdf43c6dd 100644 --- a/src/tools/clippy/tests/ui/get_first.rs +++ b/src/tools/clippy/tests/ui/get_first.rs @@ -15,25 +15,29 @@ impl Bar { fn main() { let x = vec![2, 3, 5]; let _ = x.get(0); - //~^ ERROR: accessing first element with `x.get(0)` + //~^ get_first + let _ = x.get(1); let _ = x[0]; let y = [2, 3, 5]; let _ = y.get(0); - //~^ ERROR: accessing first element with `y.get(0)` + //~^ get_first + let _ = y.get(1); let _ = y[0]; let z = &[2, 3, 5]; let _ = z.get(0); - //~^ ERROR: accessing first element with `z.get(0)` + //~^ get_first + let _ = z.get(1); let _ = z[0]; let vecdeque: VecDeque<_> = x.iter().cloned().collect(); let _ = vecdeque.get(0); - //~^ ERROR: accessing first element with `vecdeque.get(0)` + //~^ get_first + let _ = vecdeque.get(1); let hashmap: HashMap = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]); @@ -46,5 +50,5 @@ fn main() { let non_primitives = [vec![1, 2], vec![3, 4]]; let _ = non_primitives.get(0); - //~^ ERROR: accessing first element with `non_primitives.get(0)` + //~^ get_first } diff --git a/src/tools/clippy/tests/ui/get_first.stderr b/src/tools/clippy/tests/ui/get_first.stderr index 155d341b5a77d..4e19ebbc75892 100644 --- a/src/tools/clippy/tests/ui/get_first.stderr +++ b/src/tools/clippy/tests/ui/get_first.stderr @@ -8,25 +8,25 @@ LL | let _ = x.get(0); = help: to override `-D warnings` add `#[allow(clippy::get_first)]` error: accessing first element with `y.get(0)` - --> tests/ui/get_first.rs:23:13 + --> tests/ui/get_first.rs:24:13 | LL | let _ = y.get(0); | ^^^^^^^^ help: try: `y.first()` error: accessing first element with `z.get(0)` - --> tests/ui/get_first.rs:29:13 + --> tests/ui/get_first.rs:31:13 | LL | let _ = z.get(0); | ^^^^^^^^ help: try: `z.first()` error: accessing first element with `vecdeque.get(0)` - --> tests/ui/get_first.rs:35:13 + --> tests/ui/get_first.rs:38:13 | LL | let _ = vecdeque.get(0); | ^^^^^^^^^^^^^^^ help: try: `vecdeque.front()` error: accessing first element with `non_primitives.get(0)` - --> tests/ui/get_first.rs:48:13 + --> tests/ui/get_first.rs:52:13 | LL | let _ = non_primitives.get(0); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()` diff --git a/src/tools/clippy/tests/ui/get_last_with_len.fixed b/src/tools/clippy/tests/ui/get_last_with_len.fixed index 377906cb24481..15b6e1666af2b 100644 --- a/src/tools/clippy/tests/ui/get_last_with_len.fixed +++ b/src/tools/clippy/tests/ui/get_last_with_len.fixed @@ -6,6 +6,7 @@ use std::collections::VecDeque; fn dont_use_last() { let x = vec![2, 3, 5]; let _ = x.last(); + //~^ get_last_with_len } fn indexing_two_from_end() { @@ -30,18 +31,23 @@ struct S { fn in_field(s: &S) { let _ = s.field.last(); + //~^ get_last_with_len } fn main() { let slice = &[1, 2, 3]; let _ = slice.last(); + //~^ get_last_with_len let array = [4, 5, 6]; let _ = array.last(); + //~^ get_last_with_len let deq = VecDeque::from([7, 8, 9]); let _ = deq.back(); + //~^ get_last_with_len let nested = [[1]]; let _ = nested[0].last(); + //~^ get_last_with_len } diff --git a/src/tools/clippy/tests/ui/get_last_with_len.rs b/src/tools/clippy/tests/ui/get_last_with_len.rs index 2735932043a35..5b132e001e7ba 100644 --- a/src/tools/clippy/tests/ui/get_last_with_len.rs +++ b/src/tools/clippy/tests/ui/get_last_with_len.rs @@ -6,6 +6,7 @@ use std::collections::VecDeque; fn dont_use_last() { let x = vec![2, 3, 5]; let _ = x.get(x.len() - 1); + //~^ get_last_with_len } fn indexing_two_from_end() { @@ -30,18 +31,23 @@ struct S { fn in_field(s: &S) { let _ = s.field.get(s.field.len() - 1); + //~^ get_last_with_len } fn main() { let slice = &[1, 2, 3]; let _ = slice.get(slice.len() - 1); + //~^ get_last_with_len let array = [4, 5, 6]; let _ = array.get(array.len() - 1); + //~^ get_last_with_len let deq = VecDeque::from([7, 8, 9]); let _ = deq.get(deq.len() - 1); + //~^ get_last_with_len let nested = [[1]]; let _ = nested[0].get(nested[0].len() - 1); + //~^ get_last_with_len } diff --git a/src/tools/clippy/tests/ui/get_last_with_len.stderr b/src/tools/clippy/tests/ui/get_last_with_len.stderr index ba08f5db7cfae..83a03a438e44c 100644 --- a/src/tools/clippy/tests/ui/get_last_with_len.stderr +++ b/src/tools/clippy/tests/ui/get_last_with_len.stderr @@ -8,31 +8,31 @@ LL | let _ = x.get(x.len() - 1); = help: to override `-D warnings` add `#[allow(clippy::get_last_with_len)]` error: accessing last element with `s.field.get(s.field.len() - 1)` - --> tests/ui/get_last_with_len.rs:32:13 + --> tests/ui/get_last_with_len.rs:33:13 | LL | let _ = s.field.get(s.field.len() - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.field.last()` error: accessing last element with `slice.get(slice.len() - 1)` - --> tests/ui/get_last_with_len.rs:37:13 + --> tests/ui/get_last_with_len.rs:39:13 | LL | let _ = slice.get(slice.len() - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `slice.last()` error: accessing last element with `array.get(array.len() - 1)` - --> tests/ui/get_last_with_len.rs:40:13 + --> tests/ui/get_last_with_len.rs:43:13 | LL | let _ = array.get(array.len() - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array.last()` error: accessing last element with `deq.get(deq.len() - 1)` - --> tests/ui/get_last_with_len.rs:43:13 + --> tests/ui/get_last_with_len.rs:47:13 | LL | let _ = deq.get(deq.len() - 1); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `deq.back()` error: accessing last element with `nested[0].get(nested[0].len() - 1)` - --> tests/ui/get_last_with_len.rs:46:13 + --> tests/ui/get_last_with_len.rs:51:13 | LL | let _ = nested[0].get(nested[0].len() - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `nested[0].last()` diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed index 2dd3c30a4e29b..3115c1462f5ab 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.fixed +++ b/src/tools/clippy/tests/ui/get_unwrap.fixed @@ -35,23 +35,45 @@ fn main() { { // Test `get().unwrap()` let _ = &boxed_slice[1]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_slice[0]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_vec[0]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_vecdeque[0]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_hashmap[&1]; + //~^ get_unwrap + //~| unwrap_used let _ = &some_btreemap[&1]; + //~^ get_unwrap + //~| unwrap_used #[allow(clippy::unwrap_used)] let _ = false_positive.get(0).unwrap(); // Test with deref let _: u8 = boxed_slice[1]; + //~^ get_unwrap + //~| unwrap_used } { // Test `get_mut().unwrap()` boxed_slice[0] = 1; + //~^ get_unwrap + //~| unwrap_used some_slice[0] = 1; + //~^ get_unwrap + //~| unwrap_used some_vec[0] = 1; + //~^ get_unwrap + //~| unwrap_used some_vecdeque[0] = 1; + //~^ get_unwrap + //~| unwrap_used // Check false positives #[allow(clippy::unwrap_used)] { @@ -64,7 +86,11 @@ fn main() { { // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()` let _ = some_vec[0..1].to_vec(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vec[0..1].to_vec(); + //~^ get_unwrap + //~| unwrap_used } } mod issue9909 { @@ -76,12 +102,15 @@ mod issue9909 { // include a borrow in the suggestion, even if the argument is not just a numeric literal let _x: &i32 = &f[1 + 2]; + //~^ get_unwrap // don't include a borrow here let _x = f[1 + 2].to_string(); + //~^ get_unwrap // don't include a borrow here let _x = f[1 + 2].abs(); + //~^ get_unwrap } // original code: @@ -99,6 +128,7 @@ mod issue9909 { let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); let a = x.last_mut().unwrap(); let b = &mut rest[linidx(j, k) - linidx(i, k) - 1]; + //~^ get_unwrap ::std::mem::swap(a, b); } } diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs index 94226564cacb5..963238a889836 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.rs +++ b/src/tools/clippy/tests/ui/get_unwrap.rs @@ -35,23 +35,45 @@ fn main() { { // Test `get().unwrap()` let _ = boxed_slice.get(1).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_slice.get(0).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vec.get(0).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vecdeque.get(0).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_hashmap.get(&1).unwrap(); + //~^ get_unwrap + //~| unwrap_used let _ = some_btreemap.get(&1).unwrap(); + //~^ get_unwrap + //~| unwrap_used #[allow(clippy::unwrap_used)] let _ = false_positive.get(0).unwrap(); // Test with deref let _: u8 = *boxed_slice.get(1).unwrap(); + //~^ get_unwrap + //~| unwrap_used } { // Test `get_mut().unwrap()` *boxed_slice.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used *some_slice.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used *some_vec.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used *some_vecdeque.get_mut(0).unwrap() = 1; + //~^ get_unwrap + //~| unwrap_used // Check false positives #[allow(clippy::unwrap_used)] { @@ -64,7 +86,11 @@ fn main() { { // Test `get().unwrap().foo()` and `get_mut().unwrap().bar()` let _ = some_vec.get(0..1).unwrap().to_vec(); + //~^ get_unwrap + //~| unwrap_used let _ = some_vec.get_mut(0..1).unwrap().to_vec(); + //~^ get_unwrap + //~| unwrap_used } } mod issue9909 { @@ -76,12 +102,15 @@ mod issue9909 { // include a borrow in the suggestion, even if the argument is not just a numeric literal let _x: &i32 = f.get(1 + 2).unwrap(); + //~^ get_unwrap // don't include a borrow here let _x = f.get(1 + 2).unwrap().to_string(); + //~^ get_unwrap // don't include a borrow here let _x = f.get(1 + 2).unwrap().abs(); + //~^ get_unwrap } // original code: @@ -99,6 +128,7 @@ mod issue9909 { let (x, rest) = mat.split_at_mut(linidx(i, k) + 1); let a = x.last_mut().unwrap(); let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); + //~^ get_unwrap ::std::mem::swap(a, b); } } diff --git a/src/tools/clippy/tests/ui/get_unwrap.stderr b/src/tools/clippy/tests/ui/get_unwrap.stderr index fc6c0b9299c47..72a575654af9d 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.stderr +++ b/src/tools/clippy/tests/ui/get_unwrap.stderr @@ -27,7 +27,7 @@ LL | let _ = boxed_slice.get(1).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:38:17 + --> tests/ui/get_unwrap.rs:40:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ LL + let _ = &some_slice[0]; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:38:17 + --> tests/ui/get_unwrap.rs:40:17 | LL | let _ = some_slice.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | let _ = some_slice.get(0).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec - --> tests/ui/get_unwrap.rs:39:17 + --> tests/ui/get_unwrap.rs:43:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL + let _ = &some_vec[0]; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:39:17 + --> tests/ui/get_unwrap.rs:43:17 | LL | let _ = some_vec.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL | let _ = some_vec.get(0).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a VecDeque - --> tests/ui/get_unwrap.rs:40:17 + --> tests/ui/get_unwrap.rs:46:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL + let _ = &some_vecdeque[0]; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:40:17 + --> tests/ui/get_unwrap.rs:46:17 | LL | let _ = some_vecdeque.get(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | let _ = some_vecdeque.get(0).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a HashMap - --> tests/ui/get_unwrap.rs:41:17 + --> tests/ui/get_unwrap.rs:49:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -102,7 +102,7 @@ LL + let _ = &some_hashmap[&1]; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:41:17 + --> tests/ui/get_unwrap.rs:49:17 | LL | let _ = some_hashmap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | let _ = some_hashmap.get(&1).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a BTreeMap - --> tests/ui/get_unwrap.rs:42:17 + --> tests/ui/get_unwrap.rs:52:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -123,7 +123,7 @@ LL + let _ = &some_btreemap[&1]; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:42:17 + --> tests/ui/get_unwrap.rs:52:17 | LL | let _ = some_btreemap.get(&1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | let _ = some_btreemap.get(&1).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:46:21 + --> tests/ui/get_unwrap.rs:58:21 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL + let _: u8 = boxed_slice[1]; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:46:22 + --> tests/ui/get_unwrap.rs:58:22 | LL | let _: u8 = *boxed_slice.get(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL | let _: u8 = *boxed_slice.get(1).unwrap(); = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:51:9 + --> tests/ui/get_unwrap.rs:65:9 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -165,7 +165,7 @@ LL + boxed_slice[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:51:10 + --> tests/ui/get_unwrap.rs:65:10 | LL | *boxed_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,7 +174,7 @@ LL | *boxed_slice.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:52:9 + --> tests/ui/get_unwrap.rs:68:9 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -186,7 +186,7 @@ LL + some_slice[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:52:10 + --> tests/ui/get_unwrap.rs:68:10 | LL | *some_slice.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -195,7 +195,7 @@ LL | *some_slice.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec - --> tests/ui/get_unwrap.rs:53:9 + --> tests/ui/get_unwrap.rs:71:9 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -207,7 +207,7 @@ LL + some_vec[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:53:10 + --> tests/ui/get_unwrap.rs:71:10 | LL | *some_vec.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -216,7 +216,7 @@ LL | *some_vec.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a VecDeque - --> tests/ui/get_unwrap.rs:54:9 + --> tests/ui/get_unwrap.rs:74:9 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -228,7 +228,7 @@ LL + some_vecdeque[0] = 1; | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:54:10 + --> tests/ui/get_unwrap.rs:74:10 | LL | *some_vecdeque.get_mut(0).unwrap() = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -237,7 +237,7 @@ LL | *some_vecdeque.get_mut(0).unwrap() = 1; = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a Vec - --> tests/ui/get_unwrap.rs:66:17 + --> tests/ui/get_unwrap.rs:88:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -249,7 +249,7 @@ LL + let _ = some_vec[0..1].to_vec(); | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:66:17 + --> tests/ui/get_unwrap.rs:88:17 | LL | let _ = some_vec.get(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -258,7 +258,7 @@ LL | let _ = some_vec.get(0..1).unwrap().to_vec(); = help: consider using `expect()` to provide a better panic message error: called `.get_mut().unwrap()` on a Vec - --> tests/ui/get_unwrap.rs:67:17 + --> tests/ui/get_unwrap.rs:91:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -270,7 +270,7 @@ LL + let _ = some_vec[0..1].to_vec(); | error: used `unwrap()` on an `Option` value - --> tests/ui/get_unwrap.rs:67:17 + --> tests/ui/get_unwrap.rs:91:17 | LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | let _ = some_vec.get_mut(0..1).unwrap().to_vec(); = help: consider using `expect()` to provide a better panic message error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:78:24 + --> tests/ui/get_unwrap.rs:104:24 | LL | let _x: &i32 = f.get(1 + 2).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -291,7 +291,7 @@ LL + let _x: &i32 = &f[1 + 2]; | error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:81:18 + --> tests/ui/get_unwrap.rs:108:18 | LL | let _x = f.get(1 + 2).unwrap().to_string(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -303,7 +303,7 @@ LL + let _x = f[1 + 2].to_string(); | error: called `.get().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:84:18 + --> tests/ui/get_unwrap.rs:112:18 | LL | let _x = f.get(1 + 2).unwrap().abs(); | ^^^^^^^^^^^^^^^^^^^^^ @@ -315,7 +315,7 @@ LL + let _x = f[1 + 2].abs(); | error: called `.get_mut().unwrap()` on a slice - --> tests/ui/get_unwrap.rs:101:33 + --> tests/ui/get_unwrap.rs:130:33 | LL | let b = rest.get_mut(linidx(j, k) - linidx(i, k) - 1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed index 2e8e2366de6f6..a1b556029987a 100644 --- a/src/tools/clippy/tests/ui/identity_op.fixed +++ b/src/tools/clippy/tests/ui/identity_op.fixed @@ -42,45 +42,58 @@ fn main() { let x = 0; x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x + 1; x; - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 + x; x - ZERO; //no error, as we skip lookups (for now) x; - //~^ ERROR: this operation has no effect + //~^ identity_op + ((ZERO)) | x; //no error, as we skip lookups (for now) x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x / ONE; //no error, as we skip lookups (for now) x / 2; //no false positive x & NEG_ONE; //no error, as we skip lookups (for now) x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let u: u8 = 0; u; - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 << 0; // no error, this case is allowed, see issue 3430 42; - //~^ ERROR: this operation has no effect + //~^ identity_op + 1; - //~^ ERROR: this operation has no effect + //~^ identity_op + 42; - //~^ ERROR: this operation has no effect + //~^ identity_op + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let mut a = A(String::new()); let b = a << 0; // no error: non-integer @@ -88,15 +101,20 @@ fn main() { 1 * Meter; // no error: non-integer 2; - //~^ ERROR: this operation has no effect + //~^ identity_op + -2; - //~^ ERROR: this operation has no effect + //~^ identity_op + 2 + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + -2 + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x + 1; - //~^ ERROR: this operation has no effect + //~^ identity_op + (x + 1) % 3; // no error 4 % 3; // no error 4 % -3; // no error @@ -105,63 +123,85 @@ fn main() { let a = 0; let b = true; (if b { 1 } else { 2 }); - //~^ ERROR: this operation has no effect + //~^ identity_op + (if b { 1 } else { 2 }) + if b { 3 } else { 4 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + (match a { 0 => 10, _ => 20 }); - //~^ ERROR: this operation has no effect + //~^ identity_op + (match a { 0 => 10, _ => 20 }) + match a { 0 => 30, _ => 40 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + (if b { 1 } else { 2 }) + match a { 0 => 30, _ => 40 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + (match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + ((if b { 1 } else { 2 })); - //~^ ERROR: this operation has no effect + //~^ identity_op + ({ a }) + 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + ({ a } * 2); - //~^ ERROR: this operation has no effect + //~^ identity_op + (loop { let mut c = 0; if c == 10 { break c; } c += 1; }) + { a * 2 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + fn f(_: i32) { todo!(); } f(a + { 8 * 5 }); - //~^ ERROR: this operation has no effect + //~^ identity_op + f(if b { 1 } else { 2 } + 3); - //~^ ERROR: this operation has no effect + //~^ identity_op + const _: i32 = { 2 * 4 } + 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + const _: i32 = { 1 + 2 * 3 } + 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + a as usize; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _ = a as usize; - //~^ ERROR: this operation has no effect + //~^ identity_op + ({ a } as usize); - //~^ ERROR: this operation has no effect + //~^ identity_op + 2 * { a }; - //~^ ERROR: this operation has no effect + //~^ identity_op + (({ a } + 4)); - //~^ ERROR: this operation has no effect + //~^ identity_op + 1; - //~^ ERROR: this operation has no effect + //~^ identity_op + // Issue #9904 let x = 0i32; let _: i32 = x; - //~^ ERROR: this operation has no effect + //~^ identity_op + } pub fn decide(a: bool, b: bool) -> u32 { (if a { 1 } else { 2 }) + if b { 3 } else { 5 } + //~^ identity_op } /// The following tests are from / for issue #12050 @@ -173,43 +213,51 @@ fn issue_12050() { { let x = &0i32; let _: i32 = *x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = *x; - //~^ ERROR: this operation has no effect + //~^ identity_op } { let x = &&0i32; let _: i32 = **x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let x = &&0i32; let _: i32 = **x; - //~^ ERROR: this operation has no effect + //~^ identity_op } { // this is just silly let x = &&&0i32; let _: i32 = ***x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = ***x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let x = 0i32; let _: i32 = *&x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = **&&x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = *&*&x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = **&&*&x; - //~^ ERROR: this operation has no effect + //~^ identity_op } { // this is getting ridiculous, but we should still see the same // error message so let's just keep going let x = &0i32; let _: i32 = ***&&*&x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = ***&&*&x; - //~^ ERROR: this operation has no effect + //~^ identity_op } } @@ -218,41 +266,49 @@ fn issue_13470() { let y = 1i32; // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works let _: u64 = (x + y) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op + // both of the next two lines should look the same after rustfix let _: u64 = 1u64 & (x + y) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op + // Same as above, but with extra redundant parenthesis let _: u64 = 1u64 & ((x + y)) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op + // Should maintain parenthesis even if the surrounding expr has the same precedence let _: u64 = 5u64 + ((x + y)) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op // If we don't maintain the parens here, the behavior changes let _ = -(x + y); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Similarly, we need to maintain parens here let _ = -(x / y); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Maintain parenthesis if the parent expr is of higher precedence let _ = 2i32 * (x + y); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Maintain parenthesis if the parent expr is the same precedence // as not all operations are associative let _ = 2i32 - (x - y); - //~^ ERROR: this operation has no effect + //~^ identity_op + // But make sure that inner parens still exist let z = 1i32; let _ = 2 + (x + (y * z)); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Maintain parenthesis if the parent expr is of lower precedence // This is for clarity, and clippy will not warn on these being unnecessary let _ = 2i32 + (x * y); - //~^ ERROR: this operation has no effect + //~^ identity_op let x = 1i16; let y = 1i16; let _: u64 = 1u64 + ((x as i32 + y as i32) as u64); - //~^ ERROR: this operation has no effect + //~^ identity_op } diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs index 3e20fa6f2b89d..f603e1078e4ec 100644 --- a/src/tools/clippy/tests/ui/identity_op.rs +++ b/src/tools/clippy/tests/ui/identity_op.rs @@ -42,45 +42,58 @@ fn main() { let x = 0; x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + x + (1 - 1); - //~^ ERROR: this operation has no effect + //~^ identity_op + x + 1; 0 + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 + x; x - ZERO; //no error, as we skip lookups (for now) x | (0); - //~^ ERROR: this operation has no effect + //~^ identity_op + ((ZERO)) | x; //no error, as we skip lookups (for now) x * 1; - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 * x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x / ONE; //no error, as we skip lookups (for now) x / 2; //no false positive x & NEG_ONE; //no error, as we skip lookups (for now) -1 & x; - //~^ ERROR: this operation has no effect + //~^ identity_op + let u: u8 = 0; u & 255; - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 << 0; // no error, this case is allowed, see issue 3430 42 << 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 >> 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + 42 >> 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + &x >> 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + x >> &0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let mut a = A(String::new()); let b = a << 0; // no error: non-integer @@ -88,15 +101,20 @@ fn main() { 1 * Meter; // no error: non-integer 2 % 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + -2 % 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + 2 % -3 + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + -2 % -3 + x; - //~^ ERROR: this operation has no effect + //~^ identity_op + x + 1 % 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + (x + 1) % 3; // no error 4 % 3; // no error 4 % -3; // no error @@ -105,63 +123,85 @@ fn main() { let a = 0; let b = true; 0 + if b { 1 } else { 2 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + match a { 0 => 10, _ => 20 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + (if b { 1 } else { 2 }) + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + { a } + 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + { a } * 2; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 }; - //~^ ERROR: this operation has no effect + //~^ identity_op + fn f(_: i32) { todo!(); } f(1 * a + { 8 * 5 }); - //~^ ERROR: this operation has no effect + //~^ identity_op + f(0 + if b { 1 } else { 2 } + 3); - //~^ ERROR: this operation has no effect + //~^ identity_op + const _: i32 = { 2 * 4 } + 0 + 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + const _: i32 = 0 + { 1 + 2 * 3 } + 3; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + a as usize; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _ = 0 + a as usize; - //~^ ERROR: this operation has no effect + //~^ identity_op + 0 + { a } as usize; - //~^ ERROR: this operation has no effect + //~^ identity_op + 2 * (0 + { a }); - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 * ({ a } + 4); - //~^ ERROR: this operation has no effect + //~^ identity_op + 1 * 1; - //~^ ERROR: this operation has no effect + //~^ identity_op + // Issue #9904 let x = 0i32; let _: i32 = &x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + } pub fn decide(a: bool, b: bool) -> u32 { 0 + if a { 1 } else { 2 } + if b { 3 } else { 5 } + //~^ identity_op } /// The following tests are from / for issue #12050 @@ -173,43 +213,51 @@ fn issue_12050() { { let x = &0i32; let _: i32 = *x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op } { let x = &&0i32; let _: i32 = **x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let x = &&0i32; let _: i32 = *x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op } { // this is just silly let x = &&&0i32; let _: i32 = ***x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = **x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let x = 0i32; let _: i32 = *&x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = **&&x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = *&*&x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = **&&*&x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op } { // this is getting ridiculous, but we should still see the same // error message so let's just keep going let x = &0i32; let _: i32 = **&&*&x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op + let _: i32 = **&&*&x + 0; - //~^ ERROR: this operation has no effect + //~^ identity_op } } @@ -218,41 +266,49 @@ fn issue_13470() { let y = 1i32; // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works let _: u64 = (x + y + 0i32) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op + // both of the next two lines should look the same after rustfix let _: u64 = 1u64 & (x + y + 0i32) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op + // Same as above, but with extra redundant parenthesis let _: u64 = 1u64 & ((x + y) + 0i32) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op + // Should maintain parenthesis even if the surrounding expr has the same precedence let _: u64 = 5u64 + ((x + y) + 0i32) as u64; - //~^ ERROR: this operation has no effect + //~^ identity_op // If we don't maintain the parens here, the behavior changes let _ = -(x + y + 0i32); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Similarly, we need to maintain parens here let _ = -(x / y / 1i32); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Maintain parenthesis if the parent expr is of higher precedence let _ = 2i32 * (x + y + 0i32); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Maintain parenthesis if the parent expr is the same precedence // as not all operations are associative let _ = 2i32 - (x - y - 0i32); - //~^ ERROR: this operation has no effect + //~^ identity_op + // But make sure that inner parens still exist let z = 1i32; let _ = 2 + (x + (y * z) + 0); - //~^ ERROR: this operation has no effect + //~^ identity_op + // Maintain parenthesis if the parent expr is of lower precedence // This is for clarity, and clippy will not warn on these being unnecessary let _ = 2i32 + (x * y * 1i32); - //~^ ERROR: this operation has no effect + //~^ identity_op let x = 1i16; let y = 1i16; let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); - //~^ ERROR: this operation has no effect + //~^ identity_op } diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr index 99a58ef2c1b5b..8f9c2b603c49c 100644 --- a/src/tools/clippy/tests/ui/identity_op.stderr +++ b/src/tools/clippy/tests/ui/identity_op.stderr @@ -8,373 +8,373 @@ LL | x + 0; = help: to override `-D warnings` add `#[allow(clippy::identity_op)]` error: this operation has no effect - --> tests/ui/identity_op.rs:46:5 + --> tests/ui/identity_op.rs:47:5 | LL | x + (1 - 1); | ^^^^^^^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:49:5 + --> tests/ui/identity_op.rs:51:5 | LL | 0 + x; | ^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:53:5 + --> tests/ui/identity_op.rs:56:5 | LL | x | (0); | ^^^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:57:5 + --> tests/ui/identity_op.rs:61:5 | LL | x * 1; | ^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:59:5 + --> tests/ui/identity_op.rs:64:5 | LL | 1 * x; | ^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:66:5 + --> tests/ui/identity_op.rs:72:5 | LL | -1 & x; | ^^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:70:5 + --> tests/ui/identity_op.rs:77:5 | LL | u & 255; | ^^^^^^^ help: consider reducing it to: `u` error: this operation has no effect - --> tests/ui/identity_op.rs:74:5 + --> tests/ui/identity_op.rs:82:5 | LL | 42 << 0; | ^^^^^^^ help: consider reducing it to: `42` error: this operation has no effect - --> tests/ui/identity_op.rs:76:5 + --> tests/ui/identity_op.rs:85:5 | LL | 1 >> 0; | ^^^^^^ help: consider reducing it to: `1` error: this operation has no effect - --> tests/ui/identity_op.rs:78:5 + --> tests/ui/identity_op.rs:88:5 | LL | 42 >> 0; | ^^^^^^^ help: consider reducing it to: `42` error: this operation has no effect - --> tests/ui/identity_op.rs:80:5 + --> tests/ui/identity_op.rs:91:5 | LL | &x >> 0; | ^^^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:82:5 + --> tests/ui/identity_op.rs:94:5 | LL | x >> &0; | ^^^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:90:5 + --> tests/ui/identity_op.rs:103:5 | LL | 2 % 3; | ^^^^^ help: consider reducing it to: `2` error: this operation has no effect - --> tests/ui/identity_op.rs:92:5 + --> tests/ui/identity_op.rs:106:5 | LL | -2 % 3; | ^^^^^^ help: consider reducing it to: `-2` error: this operation has no effect - --> tests/ui/identity_op.rs:94:5 + --> tests/ui/identity_op.rs:109:5 | LL | 2 % -3 + x; | ^^^^^^ help: consider reducing it to: `2` error: this operation has no effect - --> tests/ui/identity_op.rs:96:5 + --> tests/ui/identity_op.rs:112:5 | LL | -2 % -3 + x; | ^^^^^^^ help: consider reducing it to: `-2` error: this operation has no effect - --> tests/ui/identity_op.rs:98:9 + --> tests/ui/identity_op.rs:115:9 | LL | x + 1 % 3; | ^^^^^ help: consider reducing it to: `1` error: this operation has no effect - --> tests/ui/identity_op.rs:107:5 + --> tests/ui/identity_op.rs:125:5 | LL | 0 + if b { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })` error: this operation has no effect - --> tests/ui/identity_op.rs:109:5 + --> tests/ui/identity_op.rs:128:5 | LL | 0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })` error: this operation has no effect - --> tests/ui/identity_op.rs:111:5 + --> tests/ui/identity_op.rs:131:5 | LL | 0 + match a { 0 => 10, _ => 20 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })` error: this operation has no effect - --> tests/ui/identity_op.rs:113:5 + --> tests/ui/identity_op.rs:134:5 | LL | 0 + match a { 0 => 10, _ => 20 } + match a { 0 => 30, _ => 40 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })` error: this operation has no effect - --> tests/ui/identity_op.rs:115:5 + --> tests/ui/identity_op.rs:137:5 | LL | 0 + if b { 1 } else { 2 } + match a { 0 => 30, _ => 40 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })` error: this operation has no effect - --> tests/ui/identity_op.rs:117:5 + --> tests/ui/identity_op.rs:140:5 | LL | 0 + match a { 0 => 10, _ => 20 } + if b { 3 } else { 4 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(match a { 0 => 10, _ => 20 })` error: this operation has no effect - --> tests/ui/identity_op.rs:119:5 + --> tests/ui/identity_op.rs:143:5 | LL | (if b { 1 } else { 2 }) + 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((if b { 1 } else { 2 }))` error: this operation has no effect - --> tests/ui/identity_op.rs:122:5 + --> tests/ui/identity_op.rs:147:5 | LL | 0 + { a } + 3; | ^^^^^^^^^ help: consider reducing it to: `({ a })` error: this operation has no effect - --> tests/ui/identity_op.rs:124:5 + --> tests/ui/identity_op.rs:150:5 | LL | 0 + { a } * 2; | ^^^^^^^^^^^^^ help: consider reducing it to: `({ a } * 2)` error: this operation has no effect - --> tests/ui/identity_op.rs:126:5 + --> tests/ui/identity_op.rs:153:5 | LL | 0 + loop { let mut c = 0; if c == 10 { break c; } c += 1; } + { a * 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(loop { let mut c = 0; if c == 10 { break c; } c += 1; })` error: this operation has no effect - --> tests/ui/identity_op.rs:133:7 + --> tests/ui/identity_op.rs:161:7 | LL | f(1 * a + { 8 * 5 }); | ^^^^^ help: consider reducing it to: `a` error: this operation has no effect - --> tests/ui/identity_op.rs:135:7 + --> tests/ui/identity_op.rs:164:7 | LL | f(0 + if b { 1 } else { 2 } + 3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `if b { 1 } else { 2 }` error: this operation has no effect - --> tests/ui/identity_op.rs:138:20 + --> tests/ui/identity_op.rs:168:20 | LL | const _: i32 = { 2 * 4 } + 0 + 3; | ^^^^^^^^^^^^^ help: consider reducing it to: `{ 2 * 4 }` error: this operation has no effect - --> tests/ui/identity_op.rs:140:20 + --> tests/ui/identity_op.rs:171:20 | LL | const _: i32 = 0 + { 1 + 2 * 3 } + 3; | ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `{ 1 + 2 * 3 }` error: this operation has no effect - --> tests/ui/identity_op.rs:143:5 + --> tests/ui/identity_op.rs:175:5 | LL | 0 + a as usize; | ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize` error: this operation has no effect - --> tests/ui/identity_op.rs:145:13 + --> tests/ui/identity_op.rs:178:13 | LL | let _ = 0 + a as usize; | ^^^^^^^^^^^^^^ help: consider reducing it to: `a as usize` error: this operation has no effect - --> tests/ui/identity_op.rs:147:5 + --> tests/ui/identity_op.rs:181:5 | LL | 0 + { a } as usize; | ^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `({ a } as usize)` error: this operation has no effect - --> tests/ui/identity_op.rs:150:9 + --> tests/ui/identity_op.rs:185:9 | LL | 2 * (0 + { a }); | ^^^^^^^^^^^ help: consider reducing it to: `{ a }` error: this operation has no effect - --> tests/ui/identity_op.rs:152:5 + --> tests/ui/identity_op.rs:188:5 | LL | 1 * ({ a } + 4); | ^^^^^^^^^^^^^^^ help: consider reducing it to: `(({ a } + 4))` error: this operation has no effect - --> tests/ui/identity_op.rs:154:5 + --> tests/ui/identity_op.rs:191:5 | LL | 1 * 1; | ^^^^^ help: consider reducing it to: `1` error: this operation has no effect - --> tests/ui/identity_op.rs:159:18 + --> tests/ui/identity_op.rs:197:18 | LL | let _: i32 = &x + 0; | ^^^^^^ help: consider reducing it to: `x` error: this operation has no effect - --> tests/ui/identity_op.rs:164:5 + --> tests/ui/identity_op.rs:203:5 | LL | 0 + if a { 1 } else { 2 } + if b { 3 } else { 5 } | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if a { 1 } else { 2 })` error: this operation has no effect - --> tests/ui/identity_op.rs:175:22 + --> tests/ui/identity_op.rs:215:22 | LL | let _: i32 = *x + 0; | ^^^^^^ help: consider reducing it to: `*x` error: this operation has no effect - --> tests/ui/identity_op.rs:177:22 + --> tests/ui/identity_op.rs:218:22 | LL | let _: i32 = x + 0; | ^^^^^ help: consider reducing it to: `*x` error: this operation has no effect - --> tests/ui/identity_op.rs:182:22 + --> tests/ui/identity_op.rs:223:22 | LL | let _: i32 = **x + 0; | ^^^^^^^ help: consider reducing it to: `**x` error: this operation has no effect - --> tests/ui/identity_op.rs:185:22 + --> tests/ui/identity_op.rs:227:22 | LL | let _: i32 = *x + 0; | ^^^^^^ help: consider reducing it to: `**x` error: this operation has no effect - --> tests/ui/identity_op.rs:191:22 + --> tests/ui/identity_op.rs:233:22 | LL | let _: i32 = ***x + 0; | ^^^^^^^^ help: consider reducing it to: `***x` error: this operation has no effect - --> tests/ui/identity_op.rs:193:22 + --> tests/ui/identity_op.rs:236:22 | LL | let _: i32 = **x + 0; | ^^^^^^^ help: consider reducing it to: `***x` error: this operation has no effect - --> tests/ui/identity_op.rs:196:22 + --> tests/ui/identity_op.rs:240:22 | LL | let _: i32 = *&x + 0; | ^^^^^^^ help: consider reducing it to: `*&x` error: this operation has no effect - --> tests/ui/identity_op.rs:198:22 + --> tests/ui/identity_op.rs:243:22 | LL | let _: i32 = **&&x + 0; | ^^^^^^^^^ help: consider reducing it to: `**&&x` error: this operation has no effect - --> tests/ui/identity_op.rs:200:22 + --> tests/ui/identity_op.rs:246:22 | LL | let _: i32 = *&*&x + 0; | ^^^^^^^^^ help: consider reducing it to: `*&*&x` error: this operation has no effect - --> tests/ui/identity_op.rs:202:22 + --> tests/ui/identity_op.rs:249:22 | LL | let _: i32 = **&&*&x + 0; | ^^^^^^^^^^^ help: consider reducing it to: `**&&*&x` error: this operation has no effect - --> tests/ui/identity_op.rs:209:22 + --> tests/ui/identity_op.rs:256:22 | LL | let _: i32 = **&&*&x + 0; | ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x` error: this operation has no effect - --> tests/ui/identity_op.rs:211:22 + --> tests/ui/identity_op.rs:259:22 | LL | let _: i32 = **&&*&x + 0; | ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x` error: this operation has no effect - --> tests/ui/identity_op.rs:220:18 + --> tests/ui/identity_op.rs:268:18 | LL | let _: u64 = (x + y + 0i32) as u64; | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` error: this operation has no effect - --> tests/ui/identity_op.rs:223:25 + --> tests/ui/identity_op.rs:272:25 | LL | let _: u64 = 1u64 & (x + y + 0i32) as u64; | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` error: this operation has no effect - --> tests/ui/identity_op.rs:226:25 + --> tests/ui/identity_op.rs:276:25 | LL | let _: u64 = 1u64 & ((x + y) + 0i32) as u64; | ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))` error: this operation has no effect - --> tests/ui/identity_op.rs:229:25 + --> tests/ui/identity_op.rs:280:25 | LL | let _: u64 = 5u64 + ((x + y) + 0i32) as u64; | ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))` error: this operation has no effect - --> tests/ui/identity_op.rs:233:14 + --> tests/ui/identity_op.rs:284:14 | LL | let _ = -(x + y + 0i32); | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` error: this operation has no effect - --> tests/ui/identity_op.rs:236:14 + --> tests/ui/identity_op.rs:288:14 | LL | let _ = -(x / y / 1i32); | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x / y)` error: this operation has no effect - --> tests/ui/identity_op.rs:239:20 + --> tests/ui/identity_op.rs:292:20 | LL | let _ = 2i32 * (x + y + 0i32); | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)` error: this operation has no effect - --> tests/ui/identity_op.rs:243:20 + --> tests/ui/identity_op.rs:297:20 | LL | let _ = 2i32 - (x - y - 0i32); | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x - y)` error: this operation has no effect - --> tests/ui/identity_op.rs:247:17 + --> tests/ui/identity_op.rs:302:17 | LL | let _ = 2 + (x + (y * z) + 0); | ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(x + (y * z))` error: this operation has no effect - --> tests/ui/identity_op.rs:251:20 + --> tests/ui/identity_op.rs:307:20 | LL | let _ = 2i32 + (x * y * 1i32); | ^^^^^^^^^^^^^^ help: consider reducing it to: `(x * y)` error: this operation has no effect - --> tests/ui/identity_op.rs:256:25 + --> tests/ui/identity_op.rs:312:25 | LL | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)` diff --git a/src/tools/clippy/tests/ui/if_let_mutex.edition2021.stderr b/src/tools/clippy/tests/ui/if_let_mutex.edition2021.stderr index 984d6adbb2a4e..58afd03c8c24f 100644 --- a/src/tools/clippy/tests/ui/if_let_mutex.edition2021.stderr +++ b/src/tools/clippy/tests/ui/if_let_mutex.edition2021.stderr @@ -1,5 +1,5 @@ error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:16:5 + --> tests/ui/if_let_mutex.rs:17:5 | LL | if let Err(locked) = m.lock() { | ^ - this Mutex will remain locked for the entire `if let`-block... @@ -19,7 +19,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::if_let_mutex)]` error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:29:5 + --> tests/ui/if_let_mutex.rs:30:5 | LL | if let Some(locked) = m.lock().unwrap().deref() { | ^ - this Mutex will remain locked for the entire `if let`-block... @@ -37,7 +37,7 @@ LL | | }; = help: move the lock call outside of the `if let ...` expression error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:51:5 + --> tests/ui/if_let_mutex.rs:52:5 | LL | if let Ok(i) = mutex.lock() { | ^ ----- this Mutex will remain locked for the entire `if let`-block... @@ -54,7 +54,7 @@ LL | | }; = help: move the lock call outside of the `if let ...` expression error: calling `Mutex::lock` inside the scope of another `Mutex::lock` causes a deadlock - --> tests/ui/if_let_mutex.rs:60:5 + --> tests/ui/if_let_mutex.rs:61:5 | LL | if let Ok(_) = m1.lock() { | ^ -- this Mutex will remain locked for the entire `if let`-block... diff --git a/src/tools/clippy/tests/ui/if_let_mutex.rs b/src/tools/clippy/tests/ui/if_let_mutex.rs index 80eee29398907..72058ea33ee70 100644 --- a/src/tools/clippy/tests/ui/if_let_mutex.rs +++ b/src/tools/clippy/tests/ui/if_let_mutex.rs @@ -3,6 +3,7 @@ //@revisions: edition2021 edition2024 //@[edition2021] edition:2021 //@[edition2024] edition:2024 +//@[edition2024] check-pass #![warn(clippy::if_let_mutex)] #![allow(clippy::redundant_pattern_matching)] @@ -62,6 +63,7 @@ fn multiple_mutexes(m1: &Mutex<()>, m2: &Mutex<()>) { } else { m1.lock(); } + //~[edition2021]^^^^^ if_let_mutex } fn main() {} diff --git a/src/tools/clippy/tests/ui/if_not_else.fixed b/src/tools/clippy/tests/ui/if_not_else.fixed index 11d1e13179c48..d26a15156cd89 100644 --- a/src/tools/clippy/tests/ui/if_not_else.fixed +++ b/src/tools/clippy/tests/ui/if_not_else.fixed @@ -12,13 +12,15 @@ fn main() { if bla() { println!("Bunny"); } else { - //~^ ERROR: unnecessary boolean `not` operation + //~^ if_not_else + println!("Bugs"); } if 4 == 5 { println!("Bunny"); } else { - //~^ ERROR: unnecessary `!=` operation + //~^ if_not_else + println!("Bugs"); } if !foo() { @@ -32,6 +34,7 @@ fn main() { if (foo() && bla()) { println!("both true"); } else { + //~^ if_not_else #[cfg(not(debug_assertions))] println!("not debug"); #[cfg(debug_assertions)] @@ -50,6 +53,7 @@ fn with_comments() { if foo() { println!("foo"); /* foo */ } else { + //~^ if_not_else /* foo is false */ println!("foo is false"); } @@ -57,6 +61,7 @@ fn with_comments() { if bla() { println!("bla"); // bla } else { + //~^ if_not_else // bla is false println!("bla"); } @@ -67,6 +72,7 @@ fn with_annotations() { if foo() { println!("foo"); /* foo */ } else { + //~^ if_not_else /* foo is false */ println!("foo is false"); } diff --git a/src/tools/clippy/tests/ui/if_not_else.rs b/src/tools/clippy/tests/ui/if_not_else.rs index fcc67e163e8a4..6171cf1164955 100644 --- a/src/tools/clippy/tests/ui/if_not_else.rs +++ b/src/tools/clippy/tests/ui/if_not_else.rs @@ -10,13 +10,15 @@ fn bla() -> bool { fn main() { if !bla() { - //~^ ERROR: unnecessary boolean `not` operation + //~^ if_not_else + println!("Bugs"); } else { println!("Bunny"); } if 4 != 5 { - //~^ ERROR: unnecessary `!=` operation + //~^ if_not_else + println!("Bugs"); } else { println!("Bunny"); @@ -30,6 +32,7 @@ fn main() { } if !(foo() && bla()) { + //~^ if_not_else #[cfg(not(debug_assertions))] println!("not debug"); #[cfg(debug_assertions)] @@ -48,6 +51,7 @@ fn main() { fn with_comments() { if !foo() { + //~^ if_not_else /* foo is false */ println!("foo is false"); } else { @@ -55,6 +59,7 @@ fn with_comments() { } if !bla() { + //~^ if_not_else // bla is false println!("bla"); } else { @@ -65,6 +70,7 @@ fn with_comments() { fn with_annotations() { #[cfg(debug_assertions)] if !foo() { + //~^ if_not_else /* foo is false */ println!("foo is false"); } else { diff --git a/src/tools/clippy/tests/ui/if_not_else.stderr b/src/tools/clippy/tests/ui/if_not_else.stderr index b01cb5af11f74..f44dd0aabc863 100644 --- a/src/tools/clippy/tests/ui/if_not_else.stderr +++ b/src/tools/clippy/tests/ui/if_not_else.stderr @@ -3,6 +3,7 @@ error: unnecessary boolean `not` operation | LL | / if !bla() { LL | | +LL | | LL | | println!("Bugs"); LL | | } else { LL | | println!("Bunny"); @@ -17,15 +18,17 @@ LL ~ if bla() { LL + println!("Bunny"); LL + } else { LL + +LL + LL + println!("Bugs"); LL + } | error: unnecessary `!=` operation - --> tests/ui/if_not_else.rs:18:5 + --> tests/ui/if_not_else.rs:19:5 | LL | / if 4 != 5 { LL | | +LL | | LL | | println!("Bugs"); LL | | } else { LL | | println!("Bunny"); @@ -38,17 +41,18 @@ LL ~ if 4 == 5 { LL + println!("Bunny"); LL + } else { LL + +LL + LL + println!("Bugs"); LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:32:5 + --> tests/ui/if_not_else.rs:34:5 | LL | / if !(foo() && bla()) { +LL | | LL | | #[cfg(not(debug_assertions))] LL | | println!("not debug"); -LL | | #[cfg(debug_assertions)] ... | LL | | println!("both true"); LL | | } @@ -59,6 +63,7 @@ help: try LL ~ if (foo() && bla()) { LL + println!("both true"); LL + } else { +LL + LL + #[cfg(not(debug_assertions))] LL + println!("not debug"); LL + #[cfg(debug_assertions)] @@ -74,9 +79,10 @@ LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:50:5 + --> tests/ui/if_not_else.rs:53:5 | LL | / if !foo() { +LL | | LL | | /* foo is false */ LL | | println!("foo is false"); LL | | } else { @@ -89,15 +95,17 @@ help: try LL ~ if foo() { LL + println!("foo"); /* foo */ LL + } else { +LL + LL + /* foo is false */ LL + println!("foo is false"); LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:57:5 + --> tests/ui/if_not_else.rs:61:5 | LL | / if !bla() { +LL | | LL | | // bla is false LL | | println!("bla"); LL | | } else { @@ -110,15 +118,17 @@ help: try LL ~ if bla() { LL + println!("bla"); // bla LL + } else { +LL + LL + // bla is false LL + println!("bla"); LL + } | error: unnecessary boolean `not` operation - --> tests/ui/if_not_else.rs:67:5 + --> tests/ui/if_not_else.rs:72:5 | LL | / if !foo() { +LL | | LL | | /* foo is false */ LL | | println!("foo is false"); LL | | } else { @@ -131,6 +141,7 @@ help: try LL ~ if foo() { LL + println!("foo"); /* foo */ LL + } else { +LL + LL + /* foo is false */ LL + println!("foo is false"); LL + } diff --git a/src/tools/clippy/tests/ui/if_not_else_bittest.rs b/src/tools/clippy/tests/ui/if_not_else_bittest.rs index 586ce6ce1bcc1..205823c5a8abb 100644 --- a/src/tools/clippy/tests/ui/if_not_else_bittest.rs +++ b/src/tools/clippy/tests/ui/if_not_else_bittest.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(clippy::if_not_else)] fn show_permissions(flags: u32) { diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs index d53e1383d845c..6d2e63e7299a8 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else.rs @@ -37,7 +37,7 @@ fn if_same_then_else() { 0..=10; foo(); } - //~^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks + //~^^^^^^^^^^^^^^^^^ if_same_then_else if true { Foo { bar: 42 }; @@ -65,10 +65,10 @@ fn if_same_then_else() { } let _ = if true { 0.0 } else { 0.0 }; - //~^ ERROR: this `if` has identical blocks + //~^ if_same_then_else let _ = if true { -0.0 } else { -0.0 }; - //~^ ERROR: this `if` has identical blocks + //~^ if_same_then_else let _ = if true { 0.0 } else { -0.0 }; @@ -80,7 +80,7 @@ fn if_same_then_else() { } let _ = if true { 42 } else { 42 }; - //~^ ERROR: this `if` has identical blocks + //~^ if_same_then_else if true { let bar = if true { 42 } else { 43 }; @@ -97,7 +97,7 @@ fn if_same_then_else() { } bar + 1; } - //~^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks + //~^^^^^^^^^^^^^^^ if_same_then_else if true { let _ = match 42 { @@ -240,6 +240,7 @@ mod issue_11213 { } else { 0_u8.is_power_of_two() } + //~^^^^^ if_same_then_else } } diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs index e23c77b082744..5b74aecdacbe5 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs @@ -31,21 +31,21 @@ fn if_same_then_else2() -> Result<&'static str, ()> { } } } - //~^^^^^^^^^^^^^^^^^^^ ERROR: this `if` has identical blocks + //~^^^^^^^^^^^^^^^^^^^ if_same_then_else if true { if let Some(a) = Some(42) {} } else { if let Some(a) = Some(42) {} } - //~^^^^^ ERROR: this `if` has identical blocks + //~^^^^^ if_same_then_else if true { if let (1, .., 3) = (1, 2, 3) {} } else { if let (1, .., 3) = (1, 2, 3) {} } - //~^^^^^ ERROR: this `if` has identical blocks + //~^^^^^ if_same_then_else if true { if let (1, .., 3) = (1, 2, 3) {} @@ -91,14 +91,14 @@ fn if_same_then_else2() -> Result<&'static str, ()> { // Same NaNs let _ = if true { f32::NAN } else { f32::NAN }; - //~^ ERROR: this `if` has identical blocks + //~^ if_same_then_else if true { Ok("foo")?; } else { Ok("foo")?; } - //~^^^^^ ERROR: this `if` has identical blocks + //~^^^^^ if_same_then_else if true { let foo = ""; @@ -124,7 +124,7 @@ fn if_same_then_else2() -> Result<&'static str, ()> { let foo = ""; return Ok(&foo[0..]); } - //~^^^^^^^ ERROR: this `if` has identical blocks + //~^^^^^^^ if_same_then_else // False positive `if_same_then_else`: `let (x, y)` vs. `let (y, x)`; see issue #3559. if true { diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed index 1f47dddcbc40a..f774608712d1a 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.fixed +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.fixed @@ -11,12 +11,12 @@ fn main() { // Should issue an error. Binary expression `o < 32` should be parenthesized. let x = Some(5); let _ = x.and_then(|o| (o < 32).then_some(o)); - //~^ ERROR: this could be simplified with `bool::then_some` + //~^ if_then_some_else_none // Should issue an error. Unary expression `!x` should be parenthesized. let x = true; let _ = (!x).then_some(0); - //~^ ERROR: this could be simplified with `bool::then_some` + //~^ if_then_some_else_none // Should not issue an error since the `else` block has a statement besides `None`. let _ = if foo() { @@ -115,6 +115,7 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { fn issue13407(s: &str) -> Option { (s == "1").then(|| true) + //~^ if_then_some_else_none } const fn issue12103(x: u32) -> Option { diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.rs b/src/tools/clippy/tests/ui/if_then_some_else_none.rs index 499f008fb876d..8b8ff0a6ea006 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.rs +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.rs @@ -4,7 +4,8 @@ fn main() { // Should issue an error. let _ = if foo() { - //~^ ERROR: this could be simplified with `bool::then` + //~^ if_then_some_else_none + println!("true!"); Some("foo") } else { @@ -13,7 +14,8 @@ fn main() { // Should issue an error when macros are used. let _ = if matches!(true, true) { - //~^ ERROR: this could be simplified with `bool::then` + //~^ if_then_some_else_none + println!("true!"); Some(matches!(true, false)) } else { @@ -23,12 +25,12 @@ fn main() { // Should issue an error. Binary expression `o < 32` should be parenthesized. let x = Some(5); let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); - //~^ ERROR: this could be simplified with `bool::then_some` + //~^ if_then_some_else_none // Should issue an error. Unary expression `!x` should be parenthesized. let x = true; let _ = if !x { Some(0) } else { None }; - //~^ ERROR: this could be simplified with `bool::then_some` + //~^ if_then_some_else_none // Should not issue an error since the `else` block has a statement besides `None`. let _ = if foo() { @@ -84,7 +86,8 @@ fn _msrv_1_49() { #[clippy::msrv = "1.50"] fn _msrv_1_50() { let _ = if foo() { - //~^ ERROR: this could be simplified with `bool::then` + //~^ if_then_some_else_none + println!("true!"); Some(150) } else { @@ -133,6 +136,7 @@ fn issue11394(b: bool, v: Result<(), ()>) -> Result<(), ()> { fn issue13407(s: &str) -> Option { if s == "1" { Some(true) } else { None } + //~^ if_then_some_else_none } const fn issue12103(x: u32) -> Option { diff --git a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr index e7bc66b3ee881..71285574ef242 100644 --- a/src/tools/clippy/tests/ui/if_then_some_else_none.stderr +++ b/src/tools/clippy/tests/ui/if_then_some_else_none.stderr @@ -4,9 +4,9 @@ error: this could be simplified with `bool::then` LL | let _ = if foo() { | _____________^ LL | | +LL | | LL | | println!("true!"); -LL | | Some("foo") -LL | | } else { +... | LL | | None LL | | }; | |_____^ help: try: `foo().then(|| { println!("true!"); "foo" })` @@ -15,45 +15,45 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::if_then_some_else_none)]` error: this could be simplified with `bool::then` - --> tests/ui/if_then_some_else_none.rs:15:13 + --> tests/ui/if_then_some_else_none.rs:16:13 | LL | let _ = if matches!(true, true) { | _____________^ LL | | +LL | | LL | | println!("true!"); -LL | | Some(matches!(true, false)) -LL | | } else { +... | LL | | None LL | | }; | |_____^ help: try: `matches!(true, true).then(|| { println!("true!"); matches!(true, false) })` error: this could be simplified with `bool::then_some` - --> tests/ui/if_then_some_else_none.rs:25:28 + --> tests/ui/if_then_some_else_none.rs:27:28 | LL | let _ = x.and_then(|o| if o < 32 { Some(o) } else { None }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(o < 32).then_some(o)` error: this could be simplified with `bool::then_some` - --> tests/ui/if_then_some_else_none.rs:30:13 + --> tests/ui/if_then_some_else_none.rs:32:13 | LL | let _ = if !x { Some(0) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(!x).then_some(0)` error: this could be simplified with `bool::then` - --> tests/ui/if_then_some_else_none.rs:86:13 + --> tests/ui/if_then_some_else_none.rs:88:13 | LL | let _ = if foo() { | _____________^ LL | | +LL | | LL | | println!("true!"); -LL | | Some(150) -LL | | } else { +... | LL | | None LL | | }; | |_____^ help: try: `foo().then(|| { println!("true!"); 150 })` error: this could be simplified with `bool::then` - --> tests/ui/if_then_some_else_none.rs:135:5 + --> tests/ui/if_then_some_else_none.rs:138:5 | LL | if s == "1" { Some(true) } else { None } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(s == "1").then(|| true)` diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs index ad77346b75f24..6ecb7cb1eba9d 100644 --- a/src/tools/clippy/tests/ui/ifs_same_cond.rs +++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs @@ -12,18 +12,18 @@ fn ifs_same_cond() { if b { } else if b { - //~^ ERROR: this `if` has the same condition as a previous `if` + //~^ ifs_same_cond } if a == 1 { } else if a == 1 { - //~^ ERROR: this `if` has the same condition as a previous `if` + //~^ ifs_same_cond } if 2 * a == 1 { } else if 2 * a == 2 { } else if 2 * a == 1 { - //~^ ERROR: this `if` has the same condition as a previous `if` + //~^ ifs_same_cond } else if a == 1 { } @@ -56,7 +56,8 @@ fn issue10272() { let a = String::from("ha"); if a.contains("ah") { } else if a.contains("ah") { - //~^ ERROR: this `if` has the same condition as a previous `if` + //~^ ifs_same_cond + // Trigger this lint } else if a.contains("ha") { } else if a == "wow" { diff --git a/src/tools/clippy/tests/ui/impl.rs b/src/tools/clippy/tests/ui/impl.rs index 7f452cb46e068..1b9e4a5cdee13 100644 --- a/src/tools/clippy/tests/ui/impl.rs +++ b/src/tools/clippy/tests/ui/impl.rs @@ -8,7 +8,8 @@ impl MyStruct { } impl MyStruct { - //~^ ERROR: multiple implementations of this structure + //~^ multiple_inherent_impl + fn second() {} } @@ -23,7 +24,8 @@ mod submod { } impl super::MyStruct { - //~^ ERROR: multiple implementations of this structure + //~^ multiple_inherent_impl + fn third() {} } } @@ -44,7 +46,8 @@ impl WithArgs { fn f2() {} } impl WithArgs { - //~^ ERROR: multiple implementations of this structure + //~^ multiple_inherent_impl + fn f3() {} } @@ -66,6 +69,6 @@ impl OneAllowedImpl {} #[allow(clippy::multiple_inherent_impl)] impl OneAllowedImpl {} impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed. -//~^ ERROR: multiple implementations of this structure +//~^ multiple_inherent_impl fn main() {} diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr index bb906957a0d33..355927b782537 100644 --- a/src/tools/clippy/tests/ui/impl.stderr +++ b/src/tools/clippy/tests/ui/impl.stderr @@ -3,6 +3,7 @@ error: multiple implementations of this structure | LL | / impl MyStruct { LL | | +LL | | LL | | fn second() {} LL | | } | |_^ @@ -18,10 +19,11 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::multiple_inherent_impl)]` error: multiple implementations of this structure - --> tests/ui/impl.rs:25:5 + --> tests/ui/impl.rs:26:5 | LL | / impl super::MyStruct { LL | | +LL | | LL | | fn third() {} LL | | } | |_____^ @@ -35,16 +37,17 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:46:1 + --> tests/ui/impl.rs:48:1 | LL | / impl WithArgs { LL | | +LL | | LL | | fn f3() {} LL | | } | |_^ | note: first implementation here - --> tests/ui/impl.rs:43:1 + --> tests/ui/impl.rs:45:1 | LL | / impl WithArgs { LL | | fn f2() {} @@ -52,13 +55,13 @@ LL | | } | |_^ error: multiple implementations of this structure - --> tests/ui/impl.rs:68:1 + --> tests/ui/impl.rs:71:1 | LL | impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed. | ^^^^^^^^^^^^^^^^^^^^^^ | note: first implementation here - --> tests/ui/impl.rs:65:1 + --> tests/ui/impl.rs:68:1 | LL | impl OneAllowedImpl {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr b/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr index 7328f563ce13d..c327ce3f7ca12 100644 --- a/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr +++ b/src/tools/clippy/tests/ui/impl_hash_with_borrow_str_and_bytes.stderr @@ -23,7 +23,6 @@ LL | #[derive(Hash)] = note: ... as (`hash("abc") != hash("abc".as_bytes())` = help: consider either removing one of the `Borrow` implementations (`Borrow` or `Borrow<[u8]>`) ... = help: ... or not implementing `Hash` for this type - = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info) error: the semantics of `Borrow` around `Hash` can't be satisfied when both `Borrow` and `Borrow<[u8]>` are implemented --> tests/ui/impl_hash_with_borrow_str_and_bytes.rs:117:6 diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.rs b/src/tools/clippy/tests/ui/impl_trait_in_params.rs index a6251a370d1d0..2039f6339a878 100644 --- a/src/tools/clippy/tests/ui/impl_trait_in_params.rs +++ b/src/tools/clippy/tests/ui/impl_trait_in_params.rs @@ -7,9 +7,10 @@ pub trait AnotherTrait {} // Should warn pub fn a(_: impl Trait) {} -//~^ ERROR: `impl Trait` used as a function parameter +//~^ impl_trait_in_params + pub fn c(_: C, _: impl Trait) {} -//~^ ERROR: `impl Trait` used as a function parameter +//~^ impl_trait_in_params // Shouldn't warn @@ -33,10 +34,12 @@ trait Private { struct S; impl S { - pub fn h(_: impl Trait) {} //~ ERROR: `impl Trait` used as a function parameter + pub fn h(_: impl Trait) {} + //~^ impl_trait_in_params fn i(_: impl Trait) {} pub fn j(_: J) {} - pub fn k>(_: K, _: impl AnotherTrait) {} //~ ERROR: `impl Trait` used as a function parameter + pub fn k>(_: K, _: impl AnotherTrait) {} + //~^ impl_trait_in_params } // Trying with traits diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr index 0ec0a34ea8db9..c904d5843c93f 100644 --- a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr +++ b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr @@ -12,7 +12,7 @@ LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {} | +++++++++++++++++++++++++++++++ error: `impl Trait` used as a function parameter - --> tests/ui/impl_trait_in_params.rs:11:29 + --> tests/ui/impl_trait_in_params.rs:12:29 | LL | pub fn c(_: C, _: impl Trait) {} | ^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | pub fn c(_: C, _: impl Trait) {} | +++++++++++++++++++++++++++++++ error: `impl Trait` used as a function parameter - --> tests/ui/impl_trait_in_params.rs:36:17 + --> tests/ui/impl_trait_in_params.rs:37:17 | LL | pub fn h(_: impl Trait) {} | ^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | pub fn h<{ /* Generic name */ }: Trait>(_: impl Trait) {} | +++++++++++++++++++++++++++++++ error: `impl Trait` used as a function parameter - --> tests/ui/impl_trait_in_params.rs:39:45 + --> tests/ui/impl_trait_in_params.rs:41:45 | LL | pub fn k>(_: K, _: impl AnotherTrait) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/implicit_clone.fixed b/src/tools/clippy/tests/ui/implicit_clone.fixed index 98556b4dd303b..d60d1cb0ec04a 100644 --- a/src/tools/clippy/tests/ui/implicit_clone.fixed +++ b/src/tools/clippy/tests/ui/implicit_clone.fixed @@ -63,12 +63,15 @@ fn main() { let vec = vec![5]; let _ = return_owned_from_slice(&vec); let _ = vec.clone(); + //~^ implicit_clone let _ = vec.clone(); + //~^ implicit_clone let vec_ref = &vec; let _ = return_owned_from_slice(vec_ref); let _ = vec_ref.to_owned(); let _ = vec_ref.clone(); + //~^ implicit_clone // we expect no lint for this let _ = weird::to_vec(&vec); @@ -81,10 +84,12 @@ fn main() { let str = "hello world".to_string(); let _ = str.clone(); + //~^ implicit_clone // testing w/ an arbitrary type let kitten = Kitten {}; let _ = kitten.clone(); + //~^ implicit_clone let _ = own_same_from_ref(&kitten); // this shouldn't lint let _ = kitten.to_vec(); @@ -95,11 +100,15 @@ fn main() { let pathbuf = PathBuf::new(); let _ = pathbuf.clone(); + //~^ implicit_clone let _ = pathbuf.clone(); + //~^ implicit_clone let os_string = OsString::from("foo"); let _ = os_string.clone(); + //~^ implicit_clone let _ = os_string.clone(); + //~^ implicit_clone // we expect no lints for this let os_str = OsStr::new("foo"); @@ -111,9 +120,11 @@ fn main() { let pathbuf_ref = &pathbuf_ref; let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf` let _ = (*pathbuf_ref).clone(); + //~^ implicit_clone let pathbuf_ref = &pathbuf_ref; let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf` let _ = (**pathbuf_ref).clone(); + //~^ implicit_clone struct NoClone; impl ToOwned for NoClone { diff --git a/src/tools/clippy/tests/ui/implicit_clone.rs b/src/tools/clippy/tests/ui/implicit_clone.rs index a064bd23a338a..b96828f28c82e 100644 --- a/src/tools/clippy/tests/ui/implicit_clone.rs +++ b/src/tools/clippy/tests/ui/implicit_clone.rs @@ -63,12 +63,15 @@ fn main() { let vec = vec![5]; let _ = return_owned_from_slice(&vec); let _ = vec.to_owned(); + //~^ implicit_clone let _ = vec.to_vec(); + //~^ implicit_clone let vec_ref = &vec; let _ = return_owned_from_slice(vec_ref); let _ = vec_ref.to_owned(); let _ = vec_ref.to_vec(); + //~^ implicit_clone // we expect no lint for this let _ = weird::to_vec(&vec); @@ -81,10 +84,12 @@ fn main() { let str = "hello world".to_string(); let _ = str.to_owned(); + //~^ implicit_clone // testing w/ an arbitrary type let kitten = Kitten {}; let _ = kitten.to_owned(); + //~^ implicit_clone let _ = own_same_from_ref(&kitten); // this shouldn't lint let _ = kitten.to_vec(); @@ -95,11 +100,15 @@ fn main() { let pathbuf = PathBuf::new(); let _ = pathbuf.to_owned(); + //~^ implicit_clone let _ = pathbuf.to_path_buf(); + //~^ implicit_clone let os_string = OsString::from("foo"); let _ = os_string.to_owned(); + //~^ implicit_clone let _ = os_string.to_os_string(); + //~^ implicit_clone // we expect no lints for this let os_str = OsStr::new("foo"); @@ -111,9 +120,11 @@ fn main() { let pathbuf_ref = &pathbuf_ref; let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf` let _ = pathbuf_ref.to_path_buf(); + //~^ implicit_clone let pathbuf_ref = &pathbuf_ref; let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf` let _ = pathbuf_ref.to_path_buf(); + //~^ implicit_clone struct NoClone; impl ToOwned for NoClone { diff --git a/src/tools/clippy/tests/ui/implicit_clone.stderr b/src/tools/clippy/tests/ui/implicit_clone.stderr index 31c212eba2c8d..1eb6ff1fe429a 100644 --- a/src/tools/clippy/tests/ui/implicit_clone.stderr +++ b/src/tools/clippy/tests/ui/implicit_clone.stderr @@ -8,61 +8,61 @@ LL | let _ = vec.to_owned(); = help: to override `-D warnings` add `#[allow(clippy::implicit_clone)]` error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type - --> tests/ui/implicit_clone.rs:66:13 + --> tests/ui/implicit_clone.rs:67:13 | LL | let _ = vec.to_vec(); | ^^^^^^^^^^^^ help: consider using: `vec.clone()` error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type - --> tests/ui/implicit_clone.rs:71:13 + --> tests/ui/implicit_clone.rs:73:13 | LL | let _ = vec_ref.to_vec(); | ^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()` error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type - --> tests/ui/implicit_clone.rs:83:13 + --> tests/ui/implicit_clone.rs:86:13 | LL | let _ = str.to_owned(); | ^^^^^^^^^^^^^^ help: consider using: `str.clone()` error: implicitly cloning a `Kitten` by calling `to_owned` on its dereferenced type - --> tests/ui/implicit_clone.rs:87:13 + --> tests/ui/implicit_clone.rs:91:13 | LL | let _ = kitten.to_owned(); | ^^^^^^^^^^^^^^^^^ help: consider using: `kitten.clone()` error: implicitly cloning a `PathBuf` by calling `to_owned` on its dereferenced type - --> tests/ui/implicit_clone.rs:97:13 + --> tests/ui/implicit_clone.rs:102:13 | LL | let _ = pathbuf.to_owned(); | ^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()` error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type - --> tests/ui/implicit_clone.rs:98:13 + --> tests/ui/implicit_clone.rs:104:13 | LL | let _ = pathbuf.to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()` error: implicitly cloning a `OsString` by calling `to_owned` on its dereferenced type - --> tests/ui/implicit_clone.rs:101:13 + --> tests/ui/implicit_clone.rs:108:13 | LL | let _ = os_string.to_owned(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()` error: implicitly cloning a `OsString` by calling `to_os_string` on its dereferenced type - --> tests/ui/implicit_clone.rs:102:13 + --> tests/ui/implicit_clone.rs:110:13 | LL | let _ = os_string.to_os_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()` error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type - --> tests/ui/implicit_clone.rs:113:13 + --> tests/ui/implicit_clone.rs:122:13 | LL | let _ = pathbuf_ref.to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(*pathbuf_ref).clone()` error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type - --> tests/ui/implicit_clone.rs:116:13 + --> tests/ui/implicit_clone.rs:126:13 | LL | let _ = pathbuf_ref.to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()` diff --git a/src/tools/clippy/tests/ui/implicit_hasher.fixed b/src/tools/clippy/tests/ui/implicit_hasher.fixed index 971746ae95d73..bea5b9afc43ac 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.fixed +++ b/src/tools/clippy/tests/ui/implicit_hasher.fixed @@ -13,6 +13,7 @@ pub trait Foo: Sized { } impl Foo for HashMap { + //~^ implicit_hasher fn make() -> (Self, Self) { // OK, don't suggest to modify these let _: HashMap = HashMap::new(); @@ -22,11 +23,13 @@ impl Foo for HashMap } } impl Foo for (HashMap,) { + //~^ implicit_hasher fn make() -> (Self, Self) { ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),)) } } impl Foo for HashMap { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) } @@ -44,11 +47,13 @@ impl Foo for HashMap { } impl Foo for HashSet { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) } } impl Foo for HashSet { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) } @@ -66,14 +71,17 @@ impl Foo for HashSet { } pub fn map(map: &mut HashMap) {} +//~^ implicit_hasher pub fn set(set: &mut HashSet) {} +//~^ implicit_hasher #[inline_macros] pub mod gen_ { use super::*; inline! { impl Foo for HashMap { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) } @@ -98,5 +106,6 @@ external! { // #7712 pub async fn election_vote(_data: HashMap) {} +//~^ implicit_hasher fn main() {} diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs index b34aa1f81374e..afdf4da61650b 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.rs +++ b/src/tools/clippy/tests/ui/implicit_hasher.rs @@ -13,6 +13,7 @@ pub trait Foo: Sized { } impl Foo for HashMap { + //~^ implicit_hasher fn make() -> (Self, Self) { // OK, don't suggest to modify these let _: HashMap = HashMap::new(); @@ -22,11 +23,13 @@ impl Foo for HashMap { } } impl Foo for (HashMap,) { + //~^ implicit_hasher fn make() -> (Self, Self) { ((HashMap::new(),), (HashMap::with_capacity(10),)) } } impl Foo for HashMap { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashMap::new(), HashMap::with_capacity(10)) } @@ -44,11 +47,13 @@ impl Foo for HashMap { } impl Foo for HashSet { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashSet::new(), HashSet::with_capacity(10)) } } impl Foo for HashSet { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashSet::new(), HashSet::with_capacity(10)) } @@ -66,14 +71,17 @@ impl Foo for HashSet { } pub fn map(map: &mut HashMap) {} +//~^ implicit_hasher pub fn set(set: &mut HashSet) {} +//~^ implicit_hasher #[inline_macros] pub mod gen_ { use super::*; inline! { impl Foo for HashMap { + //~^ implicit_hasher fn make() -> (Self, Self) { (HashMap::new(), HashMap::with_capacity(10)) } @@ -98,5 +106,6 @@ external! { // #7712 pub async fn election_vote(_data: HashMap) {} +//~^ implicit_hasher fn main() {} diff --git a/src/tools/clippy/tests/ui/implicit_hasher.stderr b/src/tools/clippy/tests/ui/implicit_hasher.stderr index 01d08a1bd9b2a..6735998ed6541 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.stderr +++ b/src/tools/clippy/tests/ui/implicit_hasher.stderr @@ -12,14 +12,14 @@ LL | #![deny(clippy::implicit_hasher)] help: add a type parameter for `BuildHasher` | LL ~ impl Foo for HashMap { -LL | fn make() -> (Self, Self) { +LL | ... LL | LL ~ (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) | error: impl for `HashMap` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:24:36 + --> tests/ui/implicit_hasher.rs:25:36 | LL | impl Foo for (HashMap,) { | ^^^^^^^^^^^^^ @@ -27,12 +27,13 @@ LL | impl Foo for (HashMap,) { help: add a type parameter for `BuildHasher` | LL ~ impl Foo for (HashMap,) { +LL | LL | fn make() -> (Self, Self) { LL ~ ((HashMap::default(),), (HashMap::with_capacity_and_hasher(10, Default::default()),)) | error: impl for `HashMap` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:29:19 + --> tests/ui/implicit_hasher.rs:31:19 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,12 +41,13 @@ LL | impl Foo for HashMap { help: add a type parameter for `BuildHasher` | LL ~ impl Foo for HashMap { +LL | LL | fn make() -> (Self, Self) { LL ~ (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) | error: impl for `HashSet` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:46:32 + --> tests/ui/implicit_hasher.rs:49:32 | LL | impl Foo for HashSet { | ^^^^^^^^^^ @@ -53,12 +55,13 @@ LL | impl Foo for HashSet { help: add a type parameter for `BuildHasher` | LL ~ impl Foo for HashSet { +LL | LL | fn make() -> (Self, Self) { LL ~ (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) | error: impl for `HashSet` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:51:19 + --> tests/ui/implicit_hasher.rs:55:19 | LL | impl Foo for HashSet { | ^^^^^^^^^^^^^^^ @@ -66,12 +69,13 @@ LL | impl Foo for HashSet { help: add a type parameter for `BuildHasher` | LL ~ impl Foo for HashSet { +LL | LL | fn make() -> (Self, Self) { LL ~ (HashSet::default(), HashSet::with_capacity_and_hasher(10, Default::default())) | error: parameter of type `HashMap` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:68:22 + --> tests/ui/implicit_hasher.rs:73:22 | LL | pub fn map(map: &mut HashMap) {} | ^^^^^^^^^^^^^^^^^ @@ -82,7 +86,7 @@ LL | pub fn map(map: &mut HashMap) {} | +++++++++++++++++++++++++++++ +++ error: parameter of type `HashSet` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:70:22 + --> tests/ui/implicit_hasher.rs:76:22 | LL | pub fn set(set: &mut HashSet) {} | ^^^^^^^^^^^^ @@ -93,7 +97,7 @@ LL | pub fn set(set: &mut HashSet) {} | +++++++++++++++++++++++++++++ +++ error: impl for `HashMap` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:76:43 + --> tests/ui/implicit_hasher.rs:83:43 | LL | impl Foo for HashMap { | ^^^^^^^^^^^^^ @@ -102,12 +106,13 @@ LL | impl Foo for HashMap { help: add a type parameter for `BuildHasher` | LL ~ impl Foo for HashMap { +LL | LL | fn make() -> (Self, Self) { LL ~ (HashMap::default(), HashMap::with_capacity_and_hasher(10, Default::default())) | error: parameter of type `HashMap` should be generalized over different hashers - --> tests/ui/implicit_hasher.rs:100:35 + --> tests/ui/implicit_hasher.rs:108:35 | LL | pub async fn election_vote(_data: HashMap) {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed index 56fe29b4e677c..1cb639b60a9af 100644 --- a/src/tools/clippy/tests/ui/implicit_return.fixed +++ b/src/tools/clippy/tests/ui/implicit_return.fixed @@ -13,17 +13,22 @@ fn test_end_of_fn() -> bool { } return true + //~^ implicit_return } fn test_if_block() -> bool { if true { return true } else { return false } + //~^ implicit_return + //~| implicit_return } #[rustfmt::skip] fn test_match(x: bool) -> bool { match x { true => return false, + //~^ implicit_return false => { return true }, + //~^ implicit_return } } @@ -37,6 +42,7 @@ fn test_match_with_unreachable(x: bool) -> bool { fn test_loop() -> bool { loop { return true; + //~^ implicit_return } } @@ -44,6 +50,7 @@ fn test_loop_with_block() -> bool { loop { { return true; + //~^ implicit_return } } } @@ -52,6 +59,7 @@ fn test_loop_with_nests() -> bool { loop { if true { return true; + //~^ implicit_return } else { let _ = true; } @@ -70,7 +78,9 @@ fn test_loop_with_if_let() -> bool { fn test_closure() { #[rustfmt::skip] let _ = || { return true }; + //~^ implicit_return let _ = || return true; + //~^ implicit_return } fn test_panic() -> bool { @@ -79,6 +89,7 @@ fn test_panic() -> bool { fn test_return_macro() -> String { return format!("test {}", "test") + //~^ implicit_return } fn macro_branch_test() -> bool { @@ -88,17 +99,20 @@ fn macro_branch_test() -> bool { }; } return m!(true, false) + //~^ implicit_return } fn loop_test() -> bool { 'outer: loop { if true { return true; + //~^ implicit_return } let _ = loop { if false { return false; + //~^ implicit_return } if true { break true; @@ -117,6 +131,7 @@ fn loop_macro_test() -> bool { m!(true); } } +//~^^^^ implicit_return fn divergent_test() -> bool { fn diverge() -> ! { @@ -128,6 +143,7 @@ fn divergent_test() -> bool { // issue #6940 async fn foo() -> bool { return true + //~^ implicit_return } fn main() {} diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs index f066ce20cfd1c..99d75e4987e47 100644 --- a/src/tools/clippy/tests/ui/implicit_return.rs +++ b/src/tools/clippy/tests/ui/implicit_return.rs @@ -13,17 +13,22 @@ fn test_end_of_fn() -> bool { } true + //~^ implicit_return } fn test_if_block() -> bool { if true { true } else { false } + //~^ implicit_return + //~| implicit_return } #[rustfmt::skip] fn test_match(x: bool) -> bool { match x { true => false, + //~^ implicit_return false => { true }, + //~^ implicit_return } } @@ -37,6 +42,7 @@ fn test_match_with_unreachable(x: bool) -> bool { fn test_loop() -> bool { loop { break true; + //~^ implicit_return } } @@ -44,6 +50,7 @@ fn test_loop_with_block() -> bool { loop { { break true; + //~^ implicit_return } } } @@ -52,6 +59,7 @@ fn test_loop_with_nests() -> bool { loop { if true { break true; + //~^ implicit_return } else { let _ = true; } @@ -70,7 +78,9 @@ fn test_loop_with_if_let() -> bool { fn test_closure() { #[rustfmt::skip] let _ = || { true }; + //~^ implicit_return let _ = || true; + //~^ implicit_return } fn test_panic() -> bool { @@ -79,6 +89,7 @@ fn test_panic() -> bool { fn test_return_macro() -> String { format!("test {}", "test") + //~^ implicit_return } fn macro_branch_test() -> bool { @@ -88,17 +99,20 @@ fn macro_branch_test() -> bool { }; } m!(true, false) + //~^ implicit_return } fn loop_test() -> bool { 'outer: loop { if true { break true; + //~^ implicit_return } let _ = loop { if false { break 'outer false; + //~^ implicit_return } if true { break true; @@ -117,6 +131,7 @@ fn loop_macro_test() -> bool { m!(true); } } +//~^^^^ implicit_return fn divergent_test() -> bool { fn diverge() -> ! { @@ -128,6 +143,7 @@ fn divergent_test() -> bool { // issue #6940 async fn foo() -> bool { true + //~^ implicit_return } fn main() {} diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr index 936a779fa747d..02044df47ac3c 100644 --- a/src/tools/clippy/tests/ui/implicit_return.stderr +++ b/src/tools/clippy/tests/ui/implicit_return.stderr @@ -12,7 +12,7 @@ LL | return true | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:19:15 + --> tests/ui/implicit_return.rs:20:15 | LL | if true { true } else { false } | ^^^^ @@ -23,7 +23,7 @@ LL | if true { return true } else { false } | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:19:29 + --> tests/ui/implicit_return.rs:20:29 | LL | if true { true } else { false } | ^^^^^ @@ -34,7 +34,7 @@ LL | if true { true } else { return false } | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:25:17 + --> tests/ui/implicit_return.rs:28:17 | LL | true => false, | ^^^^^ @@ -45,7 +45,7 @@ LL | true => return false, | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:26:20 + --> tests/ui/implicit_return.rs:30:20 | LL | false => { true }, | ^^^^ @@ -56,7 +56,7 @@ LL | false => { return true }, | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:39:9 + --> tests/ui/implicit_return.rs:44:9 | LL | break true; | ^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + return true; | error: missing `return` statement - --> tests/ui/implicit_return.rs:46:13 + --> tests/ui/implicit_return.rs:52:13 | LL | break true; | ^^^^^^^^^^ @@ -80,7 +80,7 @@ LL + return true; | error: missing `return` statement - --> tests/ui/implicit_return.rs:54:13 + --> tests/ui/implicit_return.rs:61:13 | LL | break true; | ^^^^^^^^^^ @@ -92,7 +92,7 @@ LL + return true; | error: missing `return` statement - --> tests/ui/implicit_return.rs:72:18 + --> tests/ui/implicit_return.rs:80:18 | LL | let _ = || { true }; | ^^^^ @@ -103,7 +103,7 @@ LL | let _ = || { return true }; | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:73:16 + --> tests/ui/implicit_return.rs:82:16 | LL | let _ = || true; | ^^^^ @@ -114,7 +114,7 @@ LL | let _ = || return true; | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:81:5 + --> tests/ui/implicit_return.rs:91:5 | LL | format!("test {}", "test") | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +125,7 @@ LL | return format!("test {}", "test") | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:90:5 + --> tests/ui/implicit_return.rs:101:5 | LL | m!(true, false) | ^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | return m!(true, false) | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:96:13 + --> tests/ui/implicit_return.rs:108:13 | LL | break true; | ^^^^^^^^^^ @@ -148,7 +148,7 @@ LL + return true; | error: missing `return` statement - --> tests/ui/implicit_return.rs:101:17 + --> tests/ui/implicit_return.rs:114:17 | LL | break 'outer false; | ^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL + return false; | error: missing `return` statement - --> tests/ui/implicit_return.rs:116:5 + --> tests/ui/implicit_return.rs:130:5 | LL | / loop { LL | | m!(true); @@ -173,7 +173,7 @@ LL | return loop { | ++++++ error: missing `return` statement - --> tests/ui/implicit_return.rs:130:5 + --> tests/ui/implicit_return.rs:145:5 | LL | true | ^^^^ diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.rs b/src/tools/clippy/tests/ui/implicit_saturating_add.rs index 94513f34c2621..d9d035bdcd31b 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_add.rs +++ b/src/tools/clippy/tests/ui/implicit_saturating_add.rs @@ -19,10 +19,12 @@ fn main() { } if u_8 != u8::MAX { + //~^ implicit_saturating_add u_8 += 1; } if u_8 < u8::MAX { + //~^ implicit_saturating_add u_8 += 1; } @@ -31,86 +33,107 @@ fn main() { } if u_16 != u16::MAX { + //~^ implicit_saturating_add u_16 += 1; } if u_16 < u16::MAX { + //~^ implicit_saturating_add u_16 += 1; } if u16::MAX > u_16 { + //~^ implicit_saturating_add u_16 += 1; } if u_32 != u32::MAX { + //~^ implicit_saturating_add u_32 += 1; } if u_32 < u32::MAX { + //~^ implicit_saturating_add u_32 += 1; } if u32::MAX > u_32 { + //~^ implicit_saturating_add u_32 += 1; } if u_64 != u64::MAX { + //~^ implicit_saturating_add u_64 += 1; } if u_64 < u64::MAX { + //~^ implicit_saturating_add u_64 += 1; } if u64::MAX > u_64 { + //~^ implicit_saturating_add u_64 += 1; } if i_8 != i8::MAX { + //~^ implicit_saturating_add i_8 += 1; } if i_8 < i8::MAX { + //~^ implicit_saturating_add i_8 += 1; } if i8::MAX > i_8 { + //~^ implicit_saturating_add i_8 += 1; } if i_16 != i16::MAX { + //~^ implicit_saturating_add i_16 += 1; } if i_16 < i16::MAX { + //~^ implicit_saturating_add i_16 += 1; } if i16::MAX > i_16 { + //~^ implicit_saturating_add i_16 += 1; } if i_32 != i32::MAX { + //~^ implicit_saturating_add i_32 += 1; } if i_32 < i32::MAX { + //~^ implicit_saturating_add i_32 += 1; } if i32::MAX > i_32 { + //~^ implicit_saturating_add i_32 += 1; } if i_64 != i64::MAX { + //~^ implicit_saturating_add i_64 += 1; } if i_64 < i64::MAX { + //~^ implicit_saturating_add i_64 += 1; } if i64::MAX > i_64 { + //~^ implicit_saturating_add i_64 += 1; } @@ -147,6 +170,7 @@ fn main() { if u_32 < 42 { println!("brace yourself!"); } else if u_32 < u32::MAX { + //~^ implicit_saturating_add u_32 += 1; } } diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.stderr b/src/tools/clippy/tests/ui/implicit_saturating_add.stderr index 4fb9282bc91db..8ae7dc4b884b3 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_add.stderr +++ b/src/tools/clippy/tests/ui/implicit_saturating_add.stderr @@ -2,6 +2,7 @@ error: manual saturating add detected --> tests/ui/implicit_saturating_add.rs:21:5 | LL | / if u_8 != u8::MAX { +LL | | LL | | u_8 += 1; LL | | } | |_____^ help: use instead: `u_8 = u_8.saturating_add(1);` @@ -10,186 +11,209 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_add)]` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:25:5 + --> tests/ui/implicit_saturating_add.rs:26:5 | LL | / if u_8 < u8::MAX { +LL | | LL | | u_8 += 1; LL | | } | |_____^ help: use instead: `u_8 = u_8.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:33:5 + --> tests/ui/implicit_saturating_add.rs:35:5 | LL | / if u_16 != u16::MAX { +LL | | LL | | u_16 += 1; LL | | } | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:37:5 + --> tests/ui/implicit_saturating_add.rs:40:5 | LL | / if u_16 < u16::MAX { +LL | | LL | | u_16 += 1; LL | | } | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:41:5 + --> tests/ui/implicit_saturating_add.rs:45:5 | LL | / if u16::MAX > u_16 { +LL | | LL | | u_16 += 1; LL | | } | |_____^ help: use instead: `u_16 = u_16.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:45:5 + --> tests/ui/implicit_saturating_add.rs:50:5 | LL | / if u_32 != u32::MAX { +LL | | LL | | u_32 += 1; LL | | } | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:49:5 + --> tests/ui/implicit_saturating_add.rs:55:5 | LL | / if u_32 < u32::MAX { +LL | | LL | | u_32 += 1; LL | | } | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:53:5 + --> tests/ui/implicit_saturating_add.rs:60:5 | LL | / if u32::MAX > u_32 { +LL | | LL | | u_32 += 1; LL | | } | |_____^ help: use instead: `u_32 = u_32.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:57:5 + --> tests/ui/implicit_saturating_add.rs:65:5 | LL | / if u_64 != u64::MAX { +LL | | LL | | u_64 += 1; LL | | } | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:61:5 + --> tests/ui/implicit_saturating_add.rs:70:5 | LL | / if u_64 < u64::MAX { +LL | | LL | | u_64 += 1; LL | | } | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:65:5 + --> tests/ui/implicit_saturating_add.rs:75:5 | LL | / if u64::MAX > u_64 { +LL | | LL | | u_64 += 1; LL | | } | |_____^ help: use instead: `u_64 = u_64.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:69:5 + --> tests/ui/implicit_saturating_add.rs:80:5 | LL | / if i_8 != i8::MAX { +LL | | LL | | i_8 += 1; LL | | } | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:73:5 + --> tests/ui/implicit_saturating_add.rs:85:5 | LL | / if i_8 < i8::MAX { +LL | | LL | | i_8 += 1; LL | | } | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:77:5 + --> tests/ui/implicit_saturating_add.rs:90:5 | LL | / if i8::MAX > i_8 { +LL | | LL | | i_8 += 1; LL | | } | |_____^ help: use instead: `i_8 = i_8.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:81:5 + --> tests/ui/implicit_saturating_add.rs:95:5 | LL | / if i_16 != i16::MAX { +LL | | LL | | i_16 += 1; LL | | } | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:85:5 + --> tests/ui/implicit_saturating_add.rs:100:5 | LL | / if i_16 < i16::MAX { +LL | | LL | | i_16 += 1; LL | | } | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:89:5 + --> tests/ui/implicit_saturating_add.rs:105:5 | LL | / if i16::MAX > i_16 { +LL | | LL | | i_16 += 1; LL | | } | |_____^ help: use instead: `i_16 = i_16.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:93:5 + --> tests/ui/implicit_saturating_add.rs:110:5 | LL | / if i_32 != i32::MAX { +LL | | LL | | i_32 += 1; LL | | } | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:97:5 + --> tests/ui/implicit_saturating_add.rs:115:5 | LL | / if i_32 < i32::MAX { +LL | | LL | | i_32 += 1; LL | | } | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:101:5 + --> tests/ui/implicit_saturating_add.rs:120:5 | LL | / if i32::MAX > i_32 { +LL | | LL | | i_32 += 1; LL | | } | |_____^ help: use instead: `i_32 = i_32.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:105:5 + --> tests/ui/implicit_saturating_add.rs:125:5 | LL | / if i_64 != i64::MAX { +LL | | LL | | i_64 += 1; LL | | } | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:109:5 + --> tests/ui/implicit_saturating_add.rs:130:5 | LL | / if i_64 < i64::MAX { +LL | | LL | | i_64 += 1; LL | | } | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:113:5 + --> tests/ui/implicit_saturating_add.rs:135:5 | LL | / if i64::MAX > i_64 { +LL | | LL | | i_64 += 1; LL | | } | |_____^ help: use instead: `i_64 = i_64.saturating_add(1);` error: manual saturating add detected - --> tests/ui/implicit_saturating_add.rs:149:12 + --> tests/ui/implicit_saturating_add.rs:172:12 | LL | } else if u_32 < u32::MAX { | ____________^ +LL | | LL | | u_32 += 1; LL | | } | |_____^ help: use instead: `{u_32 = u_32.saturating_add(1); }` diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs index e371e37fb2f65..140cf0338602d 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs @@ -25,6 +25,7 @@ fn main() { // Lint if u_8 > 0 { + //~^ implicit_saturating_sub u_8 = u_8 - 1; } @@ -32,6 +33,7 @@ fn main() { 10 => { // Lint if u_8 > 0 { + //~^ implicit_saturating_sub u_8 -= 1; } }, @@ -46,6 +48,7 @@ fn main() { // Lint if u_16 > 0 { + //~^ implicit_saturating_sub u_16 -= 1; } @@ -56,6 +59,7 @@ fn main() { // Lint if u_32 != 0 { + //~^ implicit_saturating_sub u_32 -= 1; } @@ -77,16 +81,19 @@ fn main() { // Lint if u_64 > 0 { + //~^ implicit_saturating_sub u_64 -= 1; } // Lint if 0 < u_64 { + //~^ implicit_saturating_sub u_64 -= 1; } // Lint if 0 != u_64 { + //~^ implicit_saturating_sub u_64 -= 1; } @@ -108,6 +115,7 @@ fn main() { // Lint if u_usize > 0 { + //~^ implicit_saturating_sub u_usize -= 1; } @@ -120,21 +128,25 @@ fn main() { // Lint if i_8 > i8::MIN { + //~^ implicit_saturating_sub i_8 -= 1; } // Lint if i_8 > i8::MIN { + //~^ implicit_saturating_sub i_8 -= 1; } // Lint if i_8 != i8::MIN { + //~^ implicit_saturating_sub i_8 -= 1; } // Lint if i_8 != i8::MIN { + //~^ implicit_saturating_sub i_8 -= 1; } @@ -145,21 +157,25 @@ fn main() { // Lint if i_16 > i16::MIN { + //~^ implicit_saturating_sub i_16 -= 1; } // Lint if i_16 > i16::MIN { + //~^ implicit_saturating_sub i_16 -= 1; } // Lint if i_16 != i16::MIN { + //~^ implicit_saturating_sub i_16 -= 1; } // Lint if i_16 != i16::MIN { + //~^ implicit_saturating_sub i_16 -= 1; } @@ -170,21 +186,25 @@ fn main() { // Lint if i_32 > i32::MIN { + //~^ implicit_saturating_sub i_32 -= 1; } // Lint if i_32 > i32::MIN { + //~^ implicit_saturating_sub i_32 -= 1; } // Lint if i_32 != i32::MIN { + //~^ implicit_saturating_sub i_32 -= 1; } // Lint if i_32 != i32::MIN { + //~^ implicit_saturating_sub i_32 -= 1; } @@ -195,16 +215,19 @@ fn main() { // Lint if i64::MIN < i_64 { + //~^ implicit_saturating_sub i_64 -= 1; } // Lint if i64::MIN != i_64 { + //~^ implicit_saturating_sub i_64 -= 1; } // Lint if i64::MIN < i_64 { + //~^ implicit_saturating_sub i_64 -= 1; } @@ -273,6 +296,7 @@ fn regression_13524(a: usize, b: usize, c: bool) -> usize { if c { 123 } else if a >= b { + //~^ implicit_saturating_sub 0 } else { b - a diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr index 6131985122805..f9c94d3ad8416 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.stderr @@ -2,6 +2,7 @@ error: implicitly performing saturating subtraction --> tests/ui/implicit_saturating_sub.rs:27:5 | LL | / if u_8 > 0 { +LL | | LL | | u_8 = u_8 - 1; LL | | } | |_____^ help: try: `u_8 = u_8.saturating_sub(1);` @@ -10,186 +11,209 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:34:13 + --> tests/ui/implicit_saturating_sub.rs:35:13 | LL | / if u_8 > 0 { +LL | | LL | | u_8 -= 1; LL | | } | |_____________^ help: try: `u_8 = u_8.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:48:5 + --> tests/ui/implicit_saturating_sub.rs:50:5 | LL | / if u_16 > 0 { +LL | | LL | | u_16 -= 1; LL | | } | |_____^ help: try: `u_16 = u_16.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:58:5 + --> tests/ui/implicit_saturating_sub.rs:61:5 | LL | / if u_32 != 0 { +LL | | LL | | u_32 -= 1; LL | | } | |_____^ help: try: `u_32 = u_32.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:79:5 + --> tests/ui/implicit_saturating_sub.rs:83:5 | LL | / if u_64 > 0 { +LL | | LL | | u_64 -= 1; LL | | } | |_____^ help: try: `u_64 = u_64.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:84:5 + --> tests/ui/implicit_saturating_sub.rs:89:5 | LL | / if 0 < u_64 { +LL | | LL | | u_64 -= 1; LL | | } | |_____^ help: try: `u_64 = u_64.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:89:5 + --> tests/ui/implicit_saturating_sub.rs:95:5 | LL | / if 0 != u_64 { +LL | | LL | | u_64 -= 1; LL | | } | |_____^ help: try: `u_64 = u_64.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:110:5 + --> tests/ui/implicit_saturating_sub.rs:117:5 | LL | / if u_usize > 0 { +LL | | LL | | u_usize -= 1; LL | | } | |_____^ help: try: `u_usize = u_usize.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:122:5 + --> tests/ui/implicit_saturating_sub.rs:130:5 | LL | / if i_8 > i8::MIN { +LL | | LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:127:5 + --> tests/ui/implicit_saturating_sub.rs:136:5 | LL | / if i_8 > i8::MIN { +LL | | LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:132:5 + --> tests/ui/implicit_saturating_sub.rs:142:5 | LL | / if i_8 != i8::MIN { +LL | | LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:137:5 + --> tests/ui/implicit_saturating_sub.rs:148:5 | LL | / if i_8 != i8::MIN { +LL | | LL | | i_8 -= 1; LL | | } | |_____^ help: try: `i_8 = i_8.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:147:5 + --> tests/ui/implicit_saturating_sub.rs:159:5 | LL | / if i_16 > i16::MIN { +LL | | LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:152:5 + --> tests/ui/implicit_saturating_sub.rs:165:5 | LL | / if i_16 > i16::MIN { +LL | | LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:157:5 + --> tests/ui/implicit_saturating_sub.rs:171:5 | LL | / if i_16 != i16::MIN { +LL | | LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:162:5 + --> tests/ui/implicit_saturating_sub.rs:177:5 | LL | / if i_16 != i16::MIN { +LL | | LL | | i_16 -= 1; LL | | } | |_____^ help: try: `i_16 = i_16.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:172:5 + --> tests/ui/implicit_saturating_sub.rs:188:5 | LL | / if i_32 > i32::MIN { +LL | | LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:177:5 + --> tests/ui/implicit_saturating_sub.rs:194:5 | LL | / if i_32 > i32::MIN { +LL | | LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:182:5 + --> tests/ui/implicit_saturating_sub.rs:200:5 | LL | / if i_32 != i32::MIN { +LL | | LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:187:5 + --> tests/ui/implicit_saturating_sub.rs:206:5 | LL | / if i_32 != i32::MIN { +LL | | LL | | i_32 -= 1; LL | | } | |_____^ help: try: `i_32 = i_32.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:197:5 + --> tests/ui/implicit_saturating_sub.rs:217:5 | LL | / if i64::MIN < i_64 { +LL | | LL | | i_64 -= 1; LL | | } | |_____^ help: try: `i_64 = i_64.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:202:5 + --> tests/ui/implicit_saturating_sub.rs:223:5 | LL | / if i64::MIN != i_64 { +LL | | LL | | i_64 -= 1; LL | | } | |_____^ help: try: `i_64 = i_64.saturating_sub(1);` error: implicitly performing saturating subtraction - --> tests/ui/implicit_saturating_sub.rs:207:5 + --> tests/ui/implicit_saturating_sub.rs:229:5 | LL | / if i64::MIN < i_64 { +LL | | LL | | i_64 -= 1; LL | | } | |_____^ help: try: `i_64 = i_64.saturating_sub(1);` error: manual arithmetic check found - --> tests/ui/implicit_saturating_sub.rs:275:12 + --> tests/ui/implicit_saturating_sub.rs:298:12 | LL | } else if a >= b { | ____________^ +LL | | LL | | 0 LL | | } else { LL | | b - a diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed index 6fd4cbd80fe4e..4fe3fa4eab516 100644 --- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed +++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed @@ -11,6 +11,7 @@ fn normal_deref(x: T) -> impl Deref { // Deref implied by DerefMut fn deref_derefmut(x: T) -> impl DerefMut { + //~^ implied_bounds_in_impls Box::new(x) } @@ -28,14 +29,19 @@ impl GenericSubtrait<(), i32, V> for () {} impl GenericSubtrait<(), i64, V> for () {} fn generics_implied() -> impl GenericSubtrait +//~^ implied_bounds_in_impls where (): GenericSubtrait, { } fn generics_implied_multi() -> impl GenericSubtrait<(), i32, V> {} +//~^ implied_bounds_in_impls +//~| implied_bounds_in_impls fn generics_implied_multi2() -> impl GenericSubtrait<(), T, V> +//~^ implied_bounds_in_impls +//~| implied_bounds_in_impls where (): GenericSubtrait<(), T, V> + GenericTrait, { @@ -46,21 +52,25 @@ fn generics_different() -> impl GenericTrait + GenericSubtrait<(), i64, ()> // i32 == i32, GenericSubtrait<_, i32, _> does imply GenericTrait, lint fn generics_same() -> impl GenericSubtrait<(), i32, ()> {} +//~^ implied_bounds_in_impls trait SomeTrait { // Check that it works in trait declarations. fn f() -> impl DerefMut; + //~^ implied_bounds_in_impls } struct SomeStruct; impl SomeStruct { // Check that it works in inherent impl blocks. fn f() -> impl DerefMut { + //~^ implied_bounds_in_impls Box::new(123) } } impl SomeTrait for SomeStruct { // Check that it works in trait impls. fn f() -> impl DerefMut { + //~^ implied_bounds_in_impls Box::new(42) } } @@ -72,7 +82,9 @@ mod issue11422 { // `PartialOrd` has a default generic parameter and does not need to be explicitly specified. // This needs special handling. fn default_generic_param1() -> impl PartialOrd + Debug {} + //~^ implied_bounds_in_impls fn default_generic_param2() -> impl PartialOrd + Debug {} + //~^ implied_bounds_in_impls // Referring to `Self` in the supertrait clause needs special handling. trait Trait1 {} @@ -86,11 +98,13 @@ mod issue11422 { mod issue11435 { // Associated type needs to be included on DoubleEndedIterator in the suggestion fn my_iter() -> impl DoubleEndedIterator { + //~^ implied_bounds_in_impls 0..5 } // Removing the `Clone` bound should include the `+` behind it in its remove suggestion fn f() -> impl Copy { + //~^ implied_bounds_in_impls 1 } @@ -105,6 +119,7 @@ mod issue11435 { // When the other trait has generics, it shouldn't add another pair of `<>` fn f2() -> impl Trait2 {} + //~^ implied_bounds_in_impls trait Trait3 { type X; @@ -120,6 +135,7 @@ mod issue11435 { // Associated type `X` is specified, but `Y` is not, so only that associated type should be moved // over fn f3() -> impl Trait4 {} + //~^ implied_bounds_in_impls } fn issue11880() { @@ -147,14 +163,19 @@ fn issue11880() { // X::T is never constrained in the first place, so it can be omitted // and left unconstrained fn f3() -> impl Y {} + //~^ implied_bounds_in_impls fn f4() -> impl Y {} + //~^ implied_bounds_in_impls fn f5() -> impl Y {} + //~^ implied_bounds_in_impls } fn apit(_: impl DerefMut) {} +//~^ implied_bounds_in_impls trait Rpitit { fn f() -> impl DerefMut; + //~^ implied_bounds_in_impls } trait Atpit { @@ -163,12 +184,15 @@ trait Atpit { } impl Atpit for () { type Assoc = impl DerefMut; + //~^ implied_bounds_in_impls fn define() -> Self::Assoc { &mut [] as &mut [()] } } type Tait = impl DerefMut; +//~^ implied_bounds_in_impls +#[define_opaque(Tait)] fn define() -> Tait { &mut [] as &mut [()] } diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs index 52076c9f998ef..6cc824db11072 100644 --- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs +++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs @@ -11,6 +11,7 @@ fn normal_deref(x: T) -> impl Deref { // Deref implied by DerefMut fn deref_derefmut(x: T) -> impl Deref + DerefMut { + //~^ implied_bounds_in_impls Box::new(x) } @@ -28,14 +29,19 @@ impl GenericSubtrait<(), i32, V> for () {} impl GenericSubtrait<(), i64, V> for () {} fn generics_implied() -> impl GenericTrait + GenericSubtrait +//~^ implied_bounds_in_impls where (): GenericSubtrait, { } fn generics_implied_multi() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), i32, V> {} +//~^ implied_bounds_in_impls +//~| implied_bounds_in_impls fn generics_implied_multi2() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), T, V> +//~^ implied_bounds_in_impls +//~| implied_bounds_in_impls where (): GenericSubtrait<(), T, V> + GenericTrait, { @@ -46,21 +52,25 @@ fn generics_different() -> impl GenericTrait + GenericSubtrait<(), i64, ()> // i32 == i32, GenericSubtrait<_, i32, _> does imply GenericTrait, lint fn generics_same() -> impl GenericTrait + GenericSubtrait<(), i32, ()> {} +//~^ implied_bounds_in_impls trait SomeTrait { // Check that it works in trait declarations. fn f() -> impl Deref + DerefMut; + //~^ implied_bounds_in_impls } struct SomeStruct; impl SomeStruct { // Check that it works in inherent impl blocks. fn f() -> impl Deref + DerefMut { + //~^ implied_bounds_in_impls Box::new(123) } } impl SomeTrait for SomeStruct { // Check that it works in trait impls. fn f() -> impl Deref + DerefMut { + //~^ implied_bounds_in_impls Box::new(42) } } @@ -72,7 +82,9 @@ mod issue11422 { // `PartialOrd` has a default generic parameter and does not need to be explicitly specified. // This needs special handling. fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {} + //~^ implied_bounds_in_impls fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {} + //~^ implied_bounds_in_impls // Referring to `Self` in the supertrait clause needs special handling. trait Trait1 {} @@ -86,11 +98,13 @@ mod issue11422 { mod issue11435 { // Associated type needs to be included on DoubleEndedIterator in the suggestion fn my_iter() -> impl Iterator + DoubleEndedIterator { + //~^ implied_bounds_in_impls 0..5 } // Removing the `Clone` bound should include the `+` behind it in its remove suggestion fn f() -> impl Copy + Clone { + //~^ implied_bounds_in_impls 1 } @@ -105,6 +119,7 @@ mod issue11435 { // When the other trait has generics, it shouldn't add another pair of `<>` fn f2() -> impl Trait1 + Trait2 {} + //~^ implied_bounds_in_impls trait Trait3 { type X; @@ -120,6 +135,7 @@ mod issue11435 { // Associated type `X` is specified, but `Y` is not, so only that associated type should be moved // over fn f3() -> impl Trait3 + Trait4 {} + //~^ implied_bounds_in_impls } fn issue11880() { @@ -147,14 +163,19 @@ fn issue11880() { // X::T is never constrained in the first place, so it can be omitted // and left unconstrained fn f3() -> impl X + Y {} + //~^ implied_bounds_in_impls fn f4() -> impl X + Y {} + //~^ implied_bounds_in_impls fn f5() -> impl X + Y {} + //~^ implied_bounds_in_impls } fn apit(_: impl Deref + DerefMut) {} +//~^ implied_bounds_in_impls trait Rpitit { fn f() -> impl Deref + DerefMut; + //~^ implied_bounds_in_impls } trait Atpit { @@ -163,12 +184,15 @@ trait Atpit { } impl Atpit for () { type Assoc = impl Deref + DerefMut; + //~^ implied_bounds_in_impls fn define() -> Self::Assoc { &mut [] as &mut [()] } } type Tait = impl Deref + DerefMut; +//~^ implied_bounds_in_impls +#[define_opaque(Tait)] fn define() -> Tait { &mut [] as &mut [()] } diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr index 805532a568020..e2888d86f3151 100644 --- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr +++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr @@ -13,7 +13,7 @@ LL + fn deref_derefmut(x: T) -> impl DerefMut { | error: this bound is already specified as the supertrait of `GenericSubtrait` - --> tests/ui/implied_bounds_in_impls.rs:30:37 + --> tests/ui/implied_bounds_in_impls.rs:31:37 | LL | fn generics_implied() -> impl GenericTrait + GenericSubtrait | ^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + fn generics_implied() -> impl GenericSubtrait | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> tests/ui/implied_bounds_in_impls.rs:36:40 + --> tests/ui/implied_bounds_in_impls.rs:38:40 | LL | fn generics_implied_multi() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + fn generics_implied_multi() -> impl GenericTrait2 + GenericSubtrait<( | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>` - --> tests/ui/implied_bounds_in_impls.rs:36:60 + --> tests/ui/implied_bounds_in_impls.rs:38:60 | LL | fn generics_implied_multi() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), i32, V> {} | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + fn generics_implied_multi() -> impl GenericTrait + GenericSubtrait< | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> tests/ui/implied_bounds_in_impls.rs:38:44 + --> tests/ui/implied_bounds_in_impls.rs:42:44 | LL | fn generics_implied_multi2() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + fn generics_implied_multi2() -> impl GenericTrait2 + GenericSubtra | error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>` - --> tests/ui/implied_bounds_in_impls.rs:38:62 + --> tests/ui/implied_bounds_in_impls.rs:42:62 | LL | fn generics_implied_multi2() -> impl GenericTrait + GenericTrait2 + GenericSubtrait<(), T, V> | ^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + fn generics_implied_multi2() -> impl GenericTrait + GenericSubtrai | error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, ()>` - --> tests/ui/implied_bounds_in_impls.rs:48:28 + --> tests/ui/implied_bounds_in_impls.rs:54:28 | LL | fn generics_same() -> impl GenericTrait + GenericSubtrait<(), i32, ()> {} | ^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + fn generics_same() -> impl GenericSubtrait<(), i32, ()> {} | error: this bound is already specified as the supertrait of `DerefMut` - --> tests/ui/implied_bounds_in_impls.rs:52:20 + --> tests/ui/implied_bounds_in_impls.rs:59:20 | LL | fn f() -> impl Deref + DerefMut; | ^^^^^ @@ -97,7 +97,7 @@ LL + fn f() -> impl DerefMut; | error: this bound is already specified as the supertrait of `DerefMut` - --> tests/ui/implied_bounds_in_impls.rs:57:20 + --> tests/ui/implied_bounds_in_impls.rs:65:20 | LL | fn f() -> impl Deref + DerefMut { | ^^^^^ @@ -109,7 +109,7 @@ LL + fn f() -> impl DerefMut { | error: this bound is already specified as the supertrait of `DerefMut` - --> tests/ui/implied_bounds_in_impls.rs:63:20 + --> tests/ui/implied_bounds_in_impls.rs:72:20 | LL | fn f() -> impl Deref + DerefMut { | ^^^^^ @@ -121,7 +121,7 @@ LL + fn f() -> impl DerefMut { | error: this bound is already specified as the supertrait of `PartialOrd` - --> tests/ui/implied_bounds_in_impls.rs:74:41 + --> tests/ui/implied_bounds_in_impls.rs:84:41 | LL | fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {} | ^^^^^^^^^ @@ -133,7 +133,7 @@ LL + fn default_generic_param1() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `PartialOrd` - --> tests/ui/implied_bounds_in_impls.rs:75:54 + --> tests/ui/implied_bounds_in_impls.rs:86:54 | LL | fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {} | ^^^^^^^^^ @@ -145,7 +145,7 @@ LL + fn default_generic_param2() -> impl PartialOrd + Debug {} | error: this bound is already specified as the supertrait of `DoubleEndedIterator` - --> tests/ui/implied_bounds_in_impls.rs:88:26 + --> tests/ui/implied_bounds_in_impls.rs:100:26 | LL | fn my_iter() -> impl Iterator + DoubleEndedIterator { | ^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + fn my_iter() -> impl DoubleEndedIterator { | error: this bound is already specified as the supertrait of `Copy` - --> tests/ui/implied_bounds_in_impls.rs:93:27 + --> tests/ui/implied_bounds_in_impls.rs:106:27 | LL | fn f() -> impl Copy + Clone { | ^^^^^ @@ -169,7 +169,7 @@ LL + fn f() -> impl Copy { | error: this bound is already specified as the supertrait of `Trait2` - --> tests/ui/implied_bounds_in_impls.rs:107:21 + --> tests/ui/implied_bounds_in_impls.rs:121:21 | LL | fn f2() -> impl Trait1 + Trait2 {} | ^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + fn f2() -> impl Trait2 {} | error: this bound is already specified as the supertrait of `Trait4` - --> tests/ui/implied_bounds_in_impls.rs:122:21 + --> tests/ui/implied_bounds_in_impls.rs:137:21 | LL | fn f3() -> impl Trait3 + Trait4 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + fn f3() -> impl Trait4 {} | error: this bound is already specified as the supertrait of `Y` - --> tests/ui/implied_bounds_in_impls.rs:149:21 + --> tests/ui/implied_bounds_in_impls.rs:165:21 | LL | fn f3() -> impl X + Y {} | ^ @@ -205,7 +205,7 @@ LL + fn f3() -> impl Y {} | error: this bound is already specified as the supertrait of `Y` - --> tests/ui/implied_bounds_in_impls.rs:150:21 + --> tests/ui/implied_bounds_in_impls.rs:167:21 | LL | fn f4() -> impl X + Y {} | ^ @@ -217,7 +217,7 @@ LL + fn f4() -> impl Y {} | error: this bound is already specified as the supertrait of `Y` - --> tests/ui/implied_bounds_in_impls.rs:151:21 + --> tests/ui/implied_bounds_in_impls.rs:169:21 | LL | fn f5() -> impl X + Y {} | ^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + fn f5() -> impl Y {} | error: this bound is already specified as the supertrait of `DerefMut` - --> tests/ui/implied_bounds_in_impls.rs:154:17 + --> tests/ui/implied_bounds_in_impls.rs:173:17 | LL | fn apit(_: impl Deref + DerefMut) {} | ^^^^^ @@ -241,7 +241,7 @@ LL + fn apit(_: impl DerefMut) {} | error: this bound is already specified as the supertrait of `DerefMut` - --> tests/ui/implied_bounds_in_impls.rs:157:20 + --> tests/ui/implied_bounds_in_impls.rs:177:20 | LL | fn f() -> impl Deref + DerefMut; | ^^^^^ @@ -253,7 +253,7 @@ LL + fn f() -> impl DerefMut; | error: this bound is already specified as the supertrait of `DerefMut` - --> tests/ui/implied_bounds_in_impls.rs:165:23 + --> tests/ui/implied_bounds_in_impls.rs:186:23 | LL | type Assoc = impl Deref + DerefMut; | ^^^^^ @@ -265,7 +265,7 @@ LL + type Assoc = impl DerefMut; | error: this bound is already specified as the supertrait of `DerefMut` - --> tests/ui/implied_bounds_in_impls.rs:171:18 + --> tests/ui/implied_bounds_in_impls.rs:193:18 | LL | type Tait = impl Deref + DerefMut; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.rs b/src/tools/clippy/tests/ui/incompatible_msrv.rs index c23df223d5088..b4fea4cae5edf 100644 --- a/src/tools/clippy/tests/ui/incompatible_msrv.rs +++ b/src/tools/clippy/tests/ui/incompatible_msrv.rs @@ -11,14 +11,15 @@ use std::time::Duration; fn foo() { let mut map: HashMap<&str, u32> = HashMap::new(); assert_eq!(map.entry("poneyland").key(), &"poneyland"); - //~^ ERROR: is `1.3.0` but this item is stable since `1.10.0` + //~^ incompatible_msrv + if let Entry::Vacant(v) = map.entry("poneyland") { v.into_key(); - //~^ ERROR: is `1.3.0` but this item is stable since `1.12.0` + //~^ incompatible_msrv } // Should warn for `sleep` but not for `Duration` (which was added in `1.3.0`). sleep(Duration::new(1, 0)); - //~^ ERROR: is `1.3.0` but this item is stable since `1.4.0` + //~^ incompatible_msrv } #[test] diff --git a/src/tools/clippy/tests/ui/incompatible_msrv.stderr b/src/tools/clippy/tests/ui/incompatible_msrv.stderr index 34f01c3e14a17..56c9eae5aafa7 100644 --- a/src/tools/clippy/tests/ui/incompatible_msrv.stderr +++ b/src/tools/clippy/tests/ui/incompatible_msrv.stderr @@ -8,13 +8,13 @@ LL | assert_eq!(map.entry("poneyland").key(), &"poneyland"); = help: to override `-D warnings` add `#[allow(clippy::incompatible_msrv)]` error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.12.0` - --> tests/ui/incompatible_msrv.rs:16:11 + --> tests/ui/incompatible_msrv.rs:17:11 | LL | v.into_key(); | ^^^^^^^^^^ error: current MSRV (Minimum Supported Rust Version) is `1.3.0` but this item is stable since `1.4.0` - --> tests/ui/incompatible_msrv.rs:20:5 + --> tests/ui/incompatible_msrv.rs:21:5 | LL | sleep(Duration::new(1, 0)); | ^^^^^ diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed index 3f1dfbbae97bd..23d2d7cc0aa40 100644 --- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed +++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed @@ -23,15 +23,25 @@ fn main() { 1.123_456_7_f32, ); let bad = (123_456, 12_345_678, 1_234_567, 1_234.567_8_f32, 1.234_567_8_f32); + //~^ inconsistent_digit_grouping + //~| inconsistent_digit_grouping + //~| inconsistent_digit_grouping + //~| inconsistent_digit_grouping + //~| inconsistent_digit_grouping // Test padding let _ = 0x0010_0000; + //~^ unreadable_literal let _ = 0x0100_0000; + //~^ unreadable_literal let _ = 0x1000_0000; + //~^ unreadable_literal let _ = 0x0001_0000_0000_u64; + //~^ unreadable_literal // Test suggestion when fraction has no digits let _: f32 = 123_456.; + //~^ inconsistent_digit_grouping // Test UUID formatted literal let _: u128 = 0x12345678_1234_1234_1234_123456789012; diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs index ac47ae1759483..a172c5450ef89 100644 --- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs +++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs @@ -23,15 +23,25 @@ fn main() { 1.123_456_7_f32, ); let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f32); + //~^ inconsistent_digit_grouping + //~| inconsistent_digit_grouping + //~| inconsistent_digit_grouping + //~| inconsistent_digit_grouping + //~| inconsistent_digit_grouping // Test padding let _ = 0x100000; + //~^ unreadable_literal let _ = 0x1000000; + //~^ unreadable_literal let _ = 0x10000000; + //~^ unreadable_literal let _ = 0x100000000_u64; + //~^ unreadable_literal // Test suggestion when fraction has no digits let _: f32 = 1_23_456.; + //~^ inconsistent_digit_grouping // Test UUID formatted literal let _: u128 = 0x12345678_1234_1234_1234_123456789012; diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr index 173b824935c8f..be54de5e7c168 100644 --- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.stderr @@ -32,7 +32,7 @@ LL | let bad = (1_23_456, 1_234_5678, 1234_567, 1_234.5678_f32, 1.234_5678_f | ^^^^^^^^^^^^^^ help: consider: `1.234_567_8_f32` error: long literal lacking separators - --> tests/ui/inconsistent_digit_grouping.rs:28:13 + --> tests/ui/inconsistent_digit_grouping.rs:33:13 | LL | let _ = 0x100000; | ^^^^^^^^ help: consider: `0x0010_0000` @@ -44,25 +44,25 @@ LL | #[deny(clippy::unreadable_literal)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: long literal lacking separators - --> tests/ui/inconsistent_digit_grouping.rs:29:13 + --> tests/ui/inconsistent_digit_grouping.rs:35:13 | LL | let _ = 0x1000000; | ^^^^^^^^^ help: consider: `0x0100_0000` error: long literal lacking separators - --> tests/ui/inconsistent_digit_grouping.rs:30:13 + --> tests/ui/inconsistent_digit_grouping.rs:37:13 | LL | let _ = 0x10000000; | ^^^^^^^^^^ help: consider: `0x1000_0000` error: long literal lacking separators - --> tests/ui/inconsistent_digit_grouping.rs:31:13 + --> tests/ui/inconsistent_digit_grouping.rs:39:13 | LL | let _ = 0x100000000_u64; | ^^^^^^^^^^^^^^^ help: consider: `0x0001_0000_0000_u64` error: digits grouped inconsistently by underscores - --> tests/ui/inconsistent_digit_grouping.rs:34:18 + --> tests/ui/inconsistent_digit_grouping.rs:43:18 | LL | let _: f32 = 1_23_456.; | ^^^^^^^^^ help: consider: `123_456.` diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed index 67bd3e4d2797e..66232c0b9d8ef 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed @@ -34,6 +34,7 @@ mod without_base { // Should lint. Foo { x, y, z }; + //~^ inconsistent_struct_constructor // Should NOT lint. // issue #7069. @@ -65,6 +66,7 @@ mod with_base { z, ..Default::default() }; + //~^^^^ inconsistent_struct_constructor // Should NOT lint because the order is consistent with the definition. Foo { diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs index d49f236b9b07b..8dd228e72ed78 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs @@ -34,6 +34,7 @@ mod without_base { // Should lint. Foo { y, x, z }; + //~^ inconsistent_struct_constructor // Should NOT lint. // issue #7069. @@ -65,6 +66,7 @@ mod with_base { x, ..Default::default() }; + //~^^^^ inconsistent_struct_constructor // Should NOT lint because the order is consistent with the definition. Foo { diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr index c145eb2a239e7..2f48a011d26f3 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.stderr @@ -8,7 +8,7 @@ LL | Foo { y, x, z }; = help: to override `-D warnings` add `#[allow(clippy::inconsistent_struct_constructor)]` error: struct constructor field order is inconsistent with struct definition field order - --> tests/ui/inconsistent_struct_constructor.rs:64:13 + --> tests/ui/inconsistent_struct_constructor.rs:65:13 | LL | / z, LL | | x, diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed index ea8e56e18b085..e19aa4acb4c12 100644 --- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed +++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.fixed @@ -12,21 +12,24 @@ fn lintable_examples() { // Try with reference let slice: Option<&[u32]> = Some(&[1, 2, 3]); if let Some([slice_0, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice_0); } // Try with copy let slice: Option<[u32; 3]> = Some([1, 2, 3]); if let Some([slice_0, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice_0); } // Try with long slice and small indices let slice: Option<[u32; 9]> = Some([1, 2, 3, 4, 5, 6, 7, 8, 9]); if let Some([slice_0, _, slice_2, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice_2); println!("{}", slice_0); } @@ -34,7 +37,8 @@ fn lintable_examples() { // Multiple bindings let slice_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([5, 6, 7]); if let SomeEnum::One([slice_0, ..]) | SomeEnum::Three([slice_0, ..]) = slice_wrapped { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice_0); } @@ -42,8 +46,9 @@ fn lintable_examples() { let a_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([9, 5, 1]); let b_wrapped: Option<[u32; 2]> = Some([4, 6]); if let (SomeEnum::Three([_, _, a_2, ..]), Some([_, b_1, ..])) = (a_wrapped, b_wrapped) { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - //~| ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + //~| index_refutable_slice + println!("{} -> {}", a_2, b_1); } @@ -51,7 +56,8 @@ fn lintable_examples() { // borrowed and `String` doesn't implement copy let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); if let Some([_, ref slice_1, ..]) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{:?}", slice_1); } println!("{:?}", slice); @@ -60,7 +66,8 @@ fn lintable_examples() { // a reference let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); if let Some([slice_0, ..]) = &slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{:?}", slice_0); } println!("{:?}", slice); @@ -130,7 +137,8 @@ fn check_slice_in_struct() { // Test 1: Field access if let Some([slice_0, ..]) = wrap.inner { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + if wrap.is_awesome { println!("This is awesome! {}", slice_0); } @@ -138,7 +146,8 @@ fn check_slice_in_struct() { // Test 2: function access if let Some([slice_0, ..]) = wrap.inner { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + if wrap.is_super_awesome() { println!("This is super awesome! {}", slice_0); } diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs index 1c1d1c4cbe46b..2903935685541 100644 --- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs +++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.rs @@ -12,21 +12,24 @@ fn lintable_examples() { // Try with reference let slice: Option<&[u32]> = Some(&[1, 2, 3]); if let Some(slice) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice[0]); } // Try with copy let slice: Option<[u32; 3]> = Some([1, 2, 3]); if let Some(slice) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice[0]); } // Try with long slice and small indices let slice: Option<[u32; 9]> = Some([1, 2, 3, 4, 5, 6, 7, 8, 9]); if let Some(slice) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice[2]); println!("{}", slice[0]); } @@ -34,7 +37,8 @@ fn lintable_examples() { // Multiple bindings let slice_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([5, 6, 7]); if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{}", slice[0]); } @@ -42,8 +46,9 @@ fn lintable_examples() { let a_wrapped: SomeEnum<[u32; 3]> = SomeEnum::One([9, 5, 1]); let b_wrapped: Option<[u32; 2]> = Some([4, 6]); if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { - //~^ ERROR: this binding can be a slice pattern to avoid indexing - //~| ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + //~| index_refutable_slice + println!("{} -> {}", a[2], b[1]); } @@ -51,7 +56,8 @@ fn lintable_examples() { // borrowed and `String` doesn't implement copy let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); if let Some(ref slice) = slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{:?}", slice[1]); } println!("{:?}", slice); @@ -60,7 +66,8 @@ fn lintable_examples() { // a reference let slice: Option<[String; 2]> = Some([String::from("1"), String::from("2")]); if let Some(slice) = &slice { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + println!("{:?}", slice[0]); } println!("{:?}", slice); @@ -130,7 +137,8 @@ fn check_slice_in_struct() { // Test 1: Field access if let Some(slice) = wrap.inner { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + if wrap.is_awesome { println!("This is awesome! {}", slice[0]); } @@ -138,7 +146,8 @@ fn check_slice_in_struct() { // Test 2: function access if let Some(slice) = wrap.inner { - //~^ ERROR: this binding can be a slice pattern to avoid indexing + //~^ index_refutable_slice + if wrap.is_super_awesome() { println!("This is super awesome! {}", slice[0]); } diff --git a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr index 14ee2e54cab10..04bc9838d0c22 100644 --- a/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr +++ b/src/tools/clippy/tests/ui/index_refutable_slice/if_let_slice_binding.stderr @@ -13,11 +13,12 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let Some([slice_0, ..]) = slice { LL | +LL | LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:21:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:22:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -26,11 +27,12 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let Some([slice_0, ..]) = slice { LL | +LL | LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:28:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:30:17 | LL | if let Some(slice) = slice { | ^^^^^ @@ -39,12 +41,13 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let Some([slice_0, _, slice_2, ..]) = slice { LL | +LL | LL ~ println!("{}", slice_2); LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:36:26 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:39:26 | LL | if let SomeEnum::One(slice) | SomeEnum::Three(slice) = slice_wrapped { | ^^^^^ @@ -53,11 +56,12 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let SomeEnum::One([slice_0, ..]) | SomeEnum::Three([slice_0, ..]) = slice_wrapped { LL | +LL | LL ~ println!("{}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:29 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:48:29 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -67,11 +71,12 @@ help: replace the binding and indexed access with a slice pattern LL ~ if let (SomeEnum::Three([_, _, a_2, ..]), Some(b)) = (a_wrapped, b_wrapped) { LL | LL | +LL | LL ~ println!("{} -> {}", a_2, b[1]); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:44:38 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:48:38 | LL | if let (SomeEnum::Three(a), Some(b)) = (a_wrapped, b_wrapped) { | ^ @@ -81,11 +86,12 @@ help: replace the binding and indexed access with a slice pattern LL ~ if let (SomeEnum::Three(a), Some([_, b_1, ..])) = (a_wrapped, b_wrapped) { LL | LL | +LL | LL ~ println!("{} -> {}", a[2], b_1); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:53:21 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:58:21 | LL | if let Some(ref slice) = slice { | ^^^^^ @@ -94,11 +100,12 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let Some([_, ref slice_1, ..]) = slice { LL | +LL | LL ~ println!("{:?}", slice_1); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:62:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:68:17 | LL | if let Some(slice) = &slice { | ^^^^^ @@ -107,11 +114,12 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let Some([slice_0, ..]) = &slice { LL | +LL | LL ~ println!("{:?}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:132:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:139:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ @@ -120,12 +128,13 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let Some([slice_0, ..]) = wrap.inner { LL | +LL | LL | if wrap.is_awesome { LL ~ println!("This is awesome! {}", slice_0); | error: this binding can be a slice pattern to avoid indexing - --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:140:17 + --> tests/ui/index_refutable_slice/if_let_slice_binding.rs:148:17 | LL | if let Some(slice) = wrap.inner { | ^^^^^ @@ -134,6 +143,7 @@ help: replace the binding and indexed access with a slice pattern | LL ~ if let Some([slice_0, ..]) = wrap.inner { LL | +LL | LL | if wrap.is_super_awesome() { LL ~ println!("This is super awesome! {}", slice_0); | diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index 2af5fcc82a9bf..cfa1c2f7c75fa 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs @@ -49,8 +49,10 @@ fn main() { //~^ ERROR: indexing may panic // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. x[4]; + //~^ out_of_bounds_indexing // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. x[1 << 3]; + //~^ out_of_bounds_indexing // Ok, should not produce stderr. x[0]; @@ -66,12 +68,14 @@ fn main() { // This should be linted, since `suppress-restriction-lint-in-const` default is false. const { &ARR[idx4()] }; //~^ ERROR: indexing may panic + //~| ERROR: evaluation of `main let y = &x; // Ok, referencing shouldn't affect this lint. See the issue 6021 y[0]; // Ok, rustc will handle references too. y[4]; + //~^ out_of_bounds_indexing let v = vec![0; 5]; v[0]; @@ -87,6 +91,7 @@ fn main() { const M: usize = 3; // Ok, let rustc's `unconditional_panic` lint handle `usize` indexing on arrays. x[N]; + //~^ out_of_bounds_indexing // Ok, should not produce stderr. x[M]; v[N]; @@ -96,4 +101,5 @@ fn main() { let slice = &x; let _ = x[4]; + //~^ out_of_bounds_indexing } diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 71677584d25bb..50ee9b9edc75b 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -10,13 +10,13 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` error[E0080]: evaluation of `main::{constant#3}` failed - --> tests/ui/indexing_slicing_index.rs:67:14 + --> tests/ui/indexing_slicing_index.rs:69:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ index out of bounds: the length is 2 but the index is 4 note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:67:5 + --> tests/ui/indexing_slicing_index.rs:69:5 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -39,13 +39,13 @@ LL | x[4]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:53:5 + --> tests/ui/indexing_slicing_index.rs:54:5 | LL | x[1 << 3]; | ^^^^^^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:64:14 + --> tests/ui/indexing_slicing_index.rs:66:14 | LL | const { &ARR[idx()] }; | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | const { &ARR[idx()] }; = note: the suggestion might not be applicable in constant blocks error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:67:14 + --> tests/ui/indexing_slicing_index.rs:69:14 | LL | const { &ARR[idx4()] }; | ^^^^^^^^^^^ @@ -63,13 +63,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:74:5 + --> tests/ui/indexing_slicing_index.rs:77:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:77:5 + --> tests/ui/indexing_slicing_index.rs:81:5 | LL | v[0]; | ^^^^ @@ -77,7 +77,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:79:5 + --> tests/ui/indexing_slicing_index.rs:83:5 | LL | v[10]; | ^^^^^ @@ -85,7 +85,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:81:5 + --> tests/ui/indexing_slicing_index.rs:85:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +93,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:89:5 + --> tests/ui/indexing_slicing_index.rs:93:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:92:5 + --> tests/ui/indexing_slicing_index.rs:97:5 | LL | v[N]; | ^^^^ @@ -107,7 +107,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:94:5 + --> tests/ui/indexing_slicing_index.rs:99:5 | LL | v[M]; | ^^^^ @@ -115,7 +115,7 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:98:13 + --> tests/ui/indexing_slicing_index.rs:103:13 | LL | let _ = x[4]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.rs b/src/tools/clippy/tests/ui/indexing_slicing_slice.rs index f37bcc4aa0caf..cad77f56d03a0 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_slice.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.rs @@ -113,22 +113,21 @@ fn main() { let index_from: usize = 2; let index_to: usize = 3; &x[index..]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &x[..index]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &x[index_from..index_to]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &x[index_from..][..index_to]; - //~^ ERROR: slicing may panic - //~| ERROR: slicing may panic + //~^ indexing_slicing + //~| indexing_slicing &x[5..][..10]; - //~^ ERROR: slicing may panic - //~| ERROR: range is out of bounds - //~| NOTE: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` + //~^ indexing_slicing + //~| out_of_bounds_indexing &x[0..][..3]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &x[1..][..5]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &x[0..].get(..3); // Ok, should not produce stderr. &x[0..3]; // Ok, should not produce stderr. @@ -136,22 +135,22 @@ fn main() { let y = &x; &y[1..2]; &y[0..=4]; - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing &y[..=4]; - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing &y[..]; // Ok, should not produce stderr. let v = vec![0; 5]; &v[10..100]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &x[10..][..100]; - //~^ ERROR: slicing may panic - //~| ERROR: range is out of bounds + //~^ indexing_slicing + //~| out_of_bounds_indexing &v[10..]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &v[..100]; - //~^ ERROR: slicing may panic + //~^ indexing_slicing &v[..]; // Ok, should not produce stderr. @@ -169,12 +168,15 @@ fn main() { // Lint on this, because `get` does exist with same signature map_with_get[true]; + //~^ indexing_slicing let s = S::(1); s[0]; + //~^ indexing_slicing let y = Y::(1); y[0]; + //~^ indexing_slicing let z = Z::(1); z[0]; diff --git a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr index 1e72506746ecb..e3ef89823e3d1 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_slice.stderr @@ -58,7 +58,7 @@ LL | &x[5..][..10]; = help: to override `-D warnings` add `#[allow(clippy::out_of_bounds_indexing)]` error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:128:6 + --> tests/ui/indexing_slicing_slice.rs:127:6 | LL | &x[0..][..3]; | ^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | &x[0..][..3]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:130:6 + --> tests/ui/indexing_slicing_slice.rs:129:6 | LL | &x[1..][..5]; | ^^^^^^^^^^^ @@ -74,19 +74,19 @@ LL | &x[1..][..5]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:138:12 + --> tests/ui/indexing_slicing_slice.rs:137:12 | LL | &y[0..=4]; | ^ error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:140:11 + --> tests/ui/indexing_slicing_slice.rs:139:11 | LL | &y[..=4]; | ^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:146:6 + --> tests/ui/indexing_slicing_slice.rs:145:6 | LL | &v[10..100]; | ^^^^^^^^^^ @@ -94,7 +94,7 @@ LL | &v[10..100]; = help: consider using `.get(n..m)` or `.get_mut(n..m)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:148:6 + --> tests/ui/indexing_slicing_slice.rs:147:6 | LL | &x[10..][..100]; | ^^^^^^^^^^^^^^ @@ -102,13 +102,13 @@ LL | &x[10..][..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: range is out of bounds - --> tests/ui/indexing_slicing_slice.rs:148:8 + --> tests/ui/indexing_slicing_slice.rs:147:8 | LL | &x[10..][..100]; | ^^ error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:151:6 + --> tests/ui/indexing_slicing_slice.rs:150:6 | LL | &v[10..]; | ^^^^^^^ @@ -116,7 +116,7 @@ LL | &v[10..]; = help: consider using `.get(n..)` or .get_mut(n..)` instead error: slicing may panic - --> tests/ui/indexing_slicing_slice.rs:153:6 + --> tests/ui/indexing_slicing_slice.rs:152:6 | LL | &v[..100]; | ^^^^^^^^ @@ -124,7 +124,7 @@ LL | &v[..100]; = help: consider using `.get(..n)`or `.get_mut(..n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:171:5 + --> tests/ui/indexing_slicing_slice.rs:170:5 | LL | map_with_get[true]; | ^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | s[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_slice.rs:177:5 + --> tests/ui/indexing_slicing_slice.rs:178:5 | LL | y[0]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.fixed b/src/tools/clippy/tests/ui/ineffective_open_options.fixed index 88489dc46bbb4..03b73f99961a6 100644 --- a/src/tools/clippy/tests/ui/ineffective_open_options.fixed +++ b/src/tools/clippy/tests/ui/ineffective_open_options.fixed @@ -5,7 +5,8 @@ use std::fs::OpenOptions; fn main() { let file = OpenOptions::new() .create(true) - //~ ERROR: unnecessary use of `.write(true)` + + //~^ ineffective_open_options .append(true) .open("dump.json") .unwrap(); @@ -13,7 +14,8 @@ fn main() { let file = OpenOptions::new() .create(true) .append(true) - //~ ERROR: unnecessary use of `.write(true)` + + //~^ ineffective_open_options .open("dump.json") .unwrap(); diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.rs b/src/tools/clippy/tests/ui/ineffective_open_options.rs index db8bca3e2acdb..e333a71490fb6 100644 --- a/src/tools/clippy/tests/ui/ineffective_open_options.rs +++ b/src/tools/clippy/tests/ui/ineffective_open_options.rs @@ -5,7 +5,8 @@ use std::fs::OpenOptions; fn main() { let file = OpenOptions::new() .create(true) - .write(true) //~ ERROR: unnecessary use of `.write(true)` + .write(true) + //~^ ineffective_open_options .append(true) .open("dump.json") .unwrap(); @@ -13,7 +14,8 @@ fn main() { let file = OpenOptions::new() .create(true) .append(true) - .write(true) //~ ERROR: unnecessary use of `.write(true)` + .write(true) + //~^ ineffective_open_options .open("dump.json") .unwrap(); diff --git a/src/tools/clippy/tests/ui/ineffective_open_options.stderr b/src/tools/clippy/tests/ui/ineffective_open_options.stderr index 0d6933bb449e8..42bb0438dcee8 100644 --- a/src/tools/clippy/tests/ui/ineffective_open_options.stderr +++ b/src/tools/clippy/tests/ui/ineffective_open_options.stderr @@ -8,7 +8,7 @@ LL | .write(true) = help: to override `-D warnings` add `#[allow(clippy::ineffective_open_options)]` error: unnecessary use of `.write(true)` because there is `.append(true)` - --> tests/ui/ineffective_open_options.rs:16:9 + --> tests/ui/ineffective_open_options.rs:17:9 | LL | .write(true) | ^^^^^^^^^^^^ help: remove `.write(true)` diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.fixed b/src/tools/clippy/tests/ui/inefficient_to_string.fixed index 1e19323113c5e..a0d34e58a9255 100644 --- a/src/tools/clippy/tests/ui/inefficient_to_string.fixed +++ b/src/tools/clippy/tests/ui/inefficient_to_string.fixed @@ -8,7 +8,9 @@ fn main() { let rrrstr: &&&str = &rrstr; let _: String = rstr.to_string(); let _: String = (*rrstr).to_string(); + //~^ inefficient_to_string let _: String = (**rrrstr).to_string(); + //~^ inefficient_to_string let string: String = String::from("hello"); let rstring: &String = &string; @@ -17,7 +19,9 @@ fn main() { let _: String = string.to_string(); let _: String = rstring.to_string(); let _: String = (*rrstring).to_string(); + //~^ inefficient_to_string let _: String = (**rrrstring).to_string(); + //~^ inefficient_to_string let cow: Cow<'_, str> = Cow::Borrowed("hello"); let rcow: &Cow<'_, str> = &cow; @@ -26,5 +30,7 @@ fn main() { let _: String = cow.to_string(); let _: String = rcow.to_string(); let _: String = (*rrcow).to_string(); + //~^ inefficient_to_string let _: String = (**rrrcow).to_string(); + //~^ inefficient_to_string } diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.rs b/src/tools/clippy/tests/ui/inefficient_to_string.rs index f027bae6fe34f..cbe90d4a125b0 100644 --- a/src/tools/clippy/tests/ui/inefficient_to_string.rs +++ b/src/tools/clippy/tests/ui/inefficient_to_string.rs @@ -8,7 +8,9 @@ fn main() { let rrrstr: &&&str = &rrstr; let _: String = rstr.to_string(); let _: String = rrstr.to_string(); + //~^ inefficient_to_string let _: String = rrrstr.to_string(); + //~^ inefficient_to_string let string: String = String::from("hello"); let rstring: &String = &string; @@ -17,7 +19,9 @@ fn main() { let _: String = string.to_string(); let _: String = rstring.to_string(); let _: String = rrstring.to_string(); + //~^ inefficient_to_string let _: String = rrrstring.to_string(); + //~^ inefficient_to_string let cow: Cow<'_, str> = Cow::Borrowed("hello"); let rcow: &Cow<'_, str> = &cow; @@ -26,5 +30,7 @@ fn main() { let _: String = cow.to_string(); let _: String = rcow.to_string(); let _: String = rrcow.to_string(); + //~^ inefficient_to_string let _: String = rrrcow.to_string(); + //~^ inefficient_to_string } diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.stderr b/src/tools/clippy/tests/ui/inefficient_to_string.stderr index e71e667cf0cfe..8593c0addc5f8 100644 --- a/src/tools/clippy/tests/ui/inefficient_to_string.stderr +++ b/src/tools/clippy/tests/ui/inefficient_to_string.stderr @@ -12,7 +12,7 @@ LL | #![deny(clippy::inefficient_to_string)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `to_string` on `&&&str` - --> tests/ui/inefficient_to_string.rs:11:21 + --> tests/ui/inefficient_to_string.rs:12:21 | LL | let _: String = rrrstr.to_string(); | ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstr).to_string()` @@ -20,7 +20,7 @@ LL | let _: String = rrrstr.to_string(); = help: `&&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString` error: calling `to_string` on `&&std::string::String` - --> tests/ui/inefficient_to_string.rs:19:21 + --> tests/ui/inefficient_to_string.rs:21:21 | LL | let _: String = rrstring.to_string(); | ^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstring).to_string()` @@ -28,7 +28,7 @@ LL | let _: String = rrstring.to_string(); = help: `&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString` error: calling `to_string` on `&&&std::string::String` - --> tests/ui/inefficient_to_string.rs:20:21 + --> tests/ui/inefficient_to_string.rs:23:21 | LL | let _: String = rrrstring.to_string(); | ^^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstring).to_string()` @@ -36,7 +36,7 @@ LL | let _: String = rrrstring.to_string(); = help: `&&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString` error: calling `to_string` on `&&std::borrow::Cow<'_, str>` - --> tests/ui/inefficient_to_string.rs:28:21 + --> tests/ui/inefficient_to_string.rs:32:21 | LL | let _: String = rrcow.to_string(); | ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrcow).to_string()` @@ -44,7 +44,7 @@ LL | let _: String = rrcow.to_string(); = help: `&std::borrow::Cow<'_, str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<'_, str>` has a fast specialization of `ToString` error: calling `to_string` on `&&&std::borrow::Cow<'_, str>` - --> tests/ui/inefficient_to_string.rs:29:21 + --> tests/ui/inefficient_to_string.rs:34:21 | LL | let _: String = rrrcow.to_string(); | ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrcow).to_string()` diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs index 7cc7cb9d68781..5db30ebca88fa 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs @@ -26,6 +26,7 @@ fn infallible_destructuring_match_enum() { // This should lint! let data = match wrapper { + //~^ infallible_destructuring_match SingleVariantEnum::Variant(i) => i, }; @@ -58,6 +59,7 @@ fn infallible_destructuring_match_struct() { // This should lint! let data = match wrapper { + //~^ infallible_destructuring_match TupleStruct(i) => i, }; @@ -82,6 +84,7 @@ fn infallible_destructuring_match_struct_with_noncopy() { // This should lint! (keeping `ref` in the suggestion) let data = match wrapper { + //~^ infallible_destructuring_match TupleStructWithNonCopy(ref n) => n, }; @@ -101,6 +104,7 @@ fn never_enum() { // This should lint! let data = match wrapper { + //~^ infallible_destructuring_match Ok(i) => i, }; diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr index b709fd8630e99..1e784bc598bf9 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.stderr @@ -2,6 +2,7 @@ error: you seem to be trying to use `match` to destructure a single infallible p --> tests/ui/infallible_destructuring_match.rs:28:5 | LL | / let data = match wrapper { +LL | | LL | | SingleVariantEnum::Variant(i) => i, LL | | }; | |______^ help: try: `let SingleVariantEnum::Variant(data) = wrapper;` @@ -10,25 +11,28 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::infallible_destructuring_match)]` error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let` - --> tests/ui/infallible_destructuring_match.rs:60:5 + --> tests/ui/infallible_destructuring_match.rs:61:5 | LL | / let data = match wrapper { +LL | | LL | | TupleStruct(i) => i, LL | | }; | |______^ help: try: `let TupleStruct(data) = wrapper;` error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let` - --> tests/ui/infallible_destructuring_match.rs:84:5 + --> tests/ui/infallible_destructuring_match.rs:86:5 | LL | / let data = match wrapper { +LL | | LL | | TupleStructWithNonCopy(ref n) => n, LL | | }; | |______^ help: try: `let TupleStructWithNonCopy(ref data) = wrapper;` error: you seem to be trying to use `match` to destructure a single infallible pattern. Consider using `let` - --> tests/ui/infallible_destructuring_match.rs:103:5 + --> tests/ui/infallible_destructuring_match.rs:106:5 | LL | / let data = match wrapper { +LL | | LL | | Ok(i) => i, LL | | }; | |______^ help: try: `let Ok(data) = wrapper;` diff --git a/src/tools/clippy/tests/ui/infinite_iter.rs b/src/tools/clippy/tests/ui/infinite_iter.rs index 178e300ff5bf4..002a791a65793 100644 --- a/src/tools/clippy/tests/ui/infinite_iter.rs +++ b/src/tools/clippy/tests/ui/infinite_iter.rs @@ -9,13 +9,16 @@ fn square_is_lower_64(x: &u32) -> bool { #[deny(clippy::infinite_iter)] fn infinite_iters() { repeat(0_u8).collect::>(); - //~^ ERROR: infinite iteration detected + //~^ infinite_iter + // infinite iter (0..8_u32).take_while(square_is_lower_64).cycle().count(); - //~^ ERROR: infinite iteration detected + //~^ infinite_iter + // infinite iter (0..8_u64).chain(0..).max(); - //~^ ERROR: infinite iteration detected + //~^ infinite_iter + // infinite iter (0_usize..) .chain([0usize, 1, 2].iter().cloned()) @@ -23,7 +26,7 @@ fn infinite_iters() { .min(); // infinite iter (0..8_u32) - //~^ ERROR: infinite iteration detected + //~^ infinite_iter .rev() .cycle() .map(|x| x + 1_u32) @@ -32,10 +35,12 @@ fn infinite_iters() { (0..3_u32).flat_map(|x| x..).sum::(); // infinite iter (0_usize..).flat_map(|x| 0..x).product::(); - //~^ ERROR: infinite iteration detected + //~^ infinite_iter + // infinite iter (0_u64..).filter(|x| x % 2 == 0).last(); - //~^ ERROR: infinite iteration detected + //~^ infinite_iter + // not an infinite, because ranges are double-ended (0..42_u64).by_ref().last(); // iterator is not exhausted @@ -46,13 +51,15 @@ fn infinite_iters() { fn potential_infinite_iters() { // maybe infinite iter (0..).zip((0..).take_while(square_is_lower_64)).count(); - //~^ ERROR: possible infinite iteration detected + //~^ maybe_infinite_iter + // maybe infinite iter repeat(42).take_while(|x| *x == 42).chain(0..42).max(); - //~^ ERROR: possible infinite iteration detected + //~^ maybe_infinite_iter + // maybe infinite iter (1..) - //~^ ERROR: possible infinite iteration detected + //~^ maybe_infinite_iter .scan(0, |state, x| { *state += x; Some(*state) @@ -60,16 +67,19 @@ fn potential_infinite_iters() { .min(); // maybe infinite iter (0..).find(|x| *x == 24); - //~^ ERROR: possible infinite iteration detected + //~^ maybe_infinite_iter + // maybe infinite iter (0..).position(|x| x == 24); - //~^ ERROR: possible infinite iteration detected + //~^ maybe_infinite_iter + // maybe infinite iter (0..).any(|x| x == 24); - //~^ ERROR: possible infinite iteration detected + //~^ maybe_infinite_iter + // maybe infinite iter (0..).all(|x| x == 24); - //~^ ERROR: possible infinite iteration detected + //~^ maybe_infinite_iter // not infinite (0..).zip(0..42).take_while(|&(x, _)| x != 42).count(); @@ -95,8 +105,7 @@ mod finite_collect { fn check_collect() { // Infinite iter let _: HashSet = (0..).collect(); - //~^ ERROR: infinite iteration detected - //~| NOTE: `#[deny(clippy::infinite_iter)]` on by default + //~^ infinite_iter // Some data structures don't collect infinitely, such as `ArrayVec` let _: C = (0..).collect(); diff --git a/src/tools/clippy/tests/ui/infinite_iter.stderr b/src/tools/clippy/tests/ui/infinite_iter.stderr index e33d83b75edb0..47133a2ea62e1 100644 --- a/src/tools/clippy/tests/ui/infinite_iter.stderr +++ b/src/tools/clippy/tests/ui/infinite_iter.stderr @@ -11,19 +11,19 @@ LL | #[deny(clippy::infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> tests/ui/infinite_iter.rs:14:5 + --> tests/ui/infinite_iter.rs:15:5 | LL | (0..8_u32).take_while(square_is_lower_64).cycle().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> tests/ui/infinite_iter.rs:17:5 + --> tests/ui/infinite_iter.rs:19:5 | LL | (0..8_u64).chain(0..).max(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> tests/ui/infinite_iter.rs:25:5 + --> tests/ui/infinite_iter.rs:28:5 | LL | / (0..8_u32) LL | | @@ -34,37 +34,37 @@ LL | | .for_each(|x| println!("{}", x)); | |________________________________________^ error: infinite iteration detected - --> tests/ui/infinite_iter.rs:34:5 + --> tests/ui/infinite_iter.rs:37:5 | LL | (0_usize..).flat_map(|x| 0..x).product::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> tests/ui/infinite_iter.rs:37:5 + --> tests/ui/infinite_iter.rs:41:5 | LL | (0_u64..).filter(|x| x % 2 == 0).last(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> tests/ui/infinite_iter.rs:48:5 + --> tests/ui/infinite_iter.rs:53:5 | LL | (0..).zip((0..).take_while(square_is_lower_64)).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> tests/ui/infinite_iter.rs:45:8 + --> tests/ui/infinite_iter.rs:50:8 | LL | #[deny(clippy::maybe_infinite_iter)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> tests/ui/infinite_iter.rs:51:5 + --> tests/ui/infinite_iter.rs:57:5 | LL | repeat(42).take_while(|x| *x == 42).chain(0..42).max(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> tests/ui/infinite_iter.rs:54:5 + --> tests/ui/infinite_iter.rs:61:5 | LL | / (1..) LL | | @@ -76,31 +76,31 @@ LL | | .min(); | |______________^ error: possible infinite iteration detected - --> tests/ui/infinite_iter.rs:62:5 + --> tests/ui/infinite_iter.rs:69:5 | LL | (0..).find(|x| *x == 24); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> tests/ui/infinite_iter.rs:65:5 + --> tests/ui/infinite_iter.rs:73:5 | LL | (0..).position(|x| x == 24); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> tests/ui/infinite_iter.rs:68:5 + --> tests/ui/infinite_iter.rs:77:5 | LL | (0..).any(|x| x == 24); | ^^^^^^^^^^^^^^^^^^^^^^ error: possible infinite iteration detected - --> tests/ui/infinite_iter.rs:71:5 + --> tests/ui/infinite_iter.rs:81:5 | LL | (0..).all(|x| x == 24); | ^^^^^^^^^^^^^^^^^^^^^^ error: infinite iteration detected - --> tests/ui/infinite_iter.rs:97:31 + --> tests/ui/infinite_iter.rs:107:31 | LL | let _: HashSet = (0..).collect(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/infinite_loop.rs b/src/tools/clippy/tests/ui/infinite_loop.rs index 765c670114746..4a0968918bfbe 100644 --- a/src/tools/clippy/tests/ui/infinite_loop.rs +++ b/src/tools/clippy/tests/ui/infinite_loop.rs @@ -20,15 +20,15 @@ fn immutable_condition() { // Should warn when all vars mentioned are immutable let y = 0; while y < 10 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + println!("KO - y is immutable"); } let x = 0; while y < 10 && x < 3 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + let mut k = 1; k += 2; println!("KO - x and y immutable"); @@ -36,8 +36,8 @@ fn immutable_condition() { let cond = false; while !cond { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + println!("KO - cond immutable"); } @@ -82,21 +82,21 @@ fn unused_var() { let (mut i, mut j) = (0, 0); while i < 3 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + j = 3; println!("KO - i not mentioned"); } while i < 3 && j > 0 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + println!("KO - i and j not mentioned"); } while i < 3 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + let mut i = 5; fn_mutref(&mut i); println!("KO - shadowed"); @@ -112,15 +112,15 @@ fn used_immutable() { let mut i = 0; while i < 3 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + fn_constref(&i); println!("KO - const reference"); } while i < 3 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + fn_val(i); println!("KO - passed by value"); } @@ -187,8 +187,8 @@ impl Counter { fn print_n(&self, n: usize) { while self.count < n { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + println!("KO - {} is not mutated", self.count); } } @@ -197,8 +197,8 @@ impl Counter { fn while_loop_with_break_and_return() { let y = 0; while y < 10 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + if y == 0 { break; } @@ -206,8 +206,8 @@ fn while_loop_with_break_and_return() { } while y < 10 { - //~^ ERROR: variables in the condition are not mutated in the loop body - //~| NOTE: this may lead to an infinite or to a never running loop + //~^ while_immutable_condition + if y == 0 { return; } diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs index d7be6f9ce7e9d..eaa8d00880682 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.rs +++ b/src/tools/clippy/tests/ui/infinite_loops.rs @@ -11,18 +11,18 @@ fn do_something() {} fn no_break() { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop do_something(); } } fn all_inf() { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop do_something(); } } @@ -36,7 +36,7 @@ fn no_break_return_some_ty() -> Option { return None; } loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop do_something(); } } @@ -49,6 +49,7 @@ fn no_break_never_ret() -> ! { fn no_break_never_ret_noise() { loop { + //~^ infinite_loop fn inner_fn() -> ! { std::process::exit(0); } @@ -92,7 +93,7 @@ fn has_indirect_break_2(stop_num: i32) { fn break_inner_but_not_outer_1(cond: bool) { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop loop { if cond { break; @@ -103,7 +104,7 @@ fn break_inner_but_not_outer_1(cond: bool) { fn break_inner_but_not_outer_2(cond: bool) { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop 'inner: loop { loop { if cond { @@ -117,7 +118,7 @@ fn break_inner_but_not_outer_2(cond: bool) { fn break_outer_but_not_inner() { loop { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop do_something(); } break; @@ -140,7 +141,7 @@ fn break_wrong_loop(cond: bool) { // 'inner has statement to break 'outer loop, but it was broken out of early by a labeled child loop 'outer: loop { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop 'inner: loop { loop { loop { @@ -180,7 +181,7 @@ enum Foo { fn match_like() { let opt: Option = Some(1); loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop match opt { Some(v) => { println!("{v}"); @@ -221,12 +222,12 @@ fn match_like() { } loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop let _x = matches!(result, Ok(v) if v != 0).then_some(0); } loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop // This `return` does not return the function, so it doesn't count let _x = matches!(result, Ok(v) if v != 0).then(|| { if true { @@ -331,7 +332,7 @@ fn exit_directly(cond: bool) { trait MyTrait { fn problematic_trait_method() { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop do_something(); } } @@ -341,7 +342,7 @@ trait MyTrait { impl MyTrait for String { fn could_be_problematic() { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop do_something(); } } @@ -350,7 +351,7 @@ impl MyTrait for String { fn inf_loop_in_closure() { let _loop_forever = || { loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop do_something(); } }; @@ -364,6 +365,7 @@ fn inf_loop_in_closure() { fn inf_loop_in_res() -> Result<(), i32> { Ok(loop { + //~^ infinite_loop do_something() }) } @@ -406,15 +408,16 @@ fn continue_outer() { // This should lint as we continue the loop itself 'infinite: loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop loop { continue 'infinite; } } // This should lint as we continue an inner loop loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop 'inner: loop { + //~^ infinite_loop loop { continue 'inner; } @@ -423,7 +426,7 @@ fn continue_outer() { // This should lint as we continue the loop itself loop { - //~^ ERROR: infinite loop detected + //~^ infinite_loop continue; } } diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr index 3b5705d5f21da..4d02636ef4aef 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.stderr +++ b/src/tools/clippy/tests/ui/infinite_loops.stderr @@ -74,9 +74,11 @@ error: infinite loop detected --> tests/ui/infinite_loops.rs:51:5 | LL | / loop { +LL | | LL | | fn inner_fn() -> ! { LL | | std::process::exit(0); -... | +LL | | } +LL | | do_something(); LL | | } | |_____^ | @@ -86,7 +88,7 @@ LL | fn no_break_never_ret_noise() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:94:5 + --> tests/ui/infinite_loops.rs:95:5 | LL | / loop { LL | | @@ -102,7 +104,7 @@ LL | fn break_inner_but_not_outer_1(cond: bool) -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:105:5 + --> tests/ui/infinite_loops.rs:106:5 | LL | / loop { LL | | @@ -118,7 +120,7 @@ LL | fn break_inner_but_not_outer_2(cond: bool) -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:119:9 + --> tests/ui/infinite_loops.rs:120:9 | LL | / loop { LL | | @@ -132,7 +134,7 @@ LL | fn break_outer_but_not_inner() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:142:9 + --> tests/ui/infinite_loops.rs:143:9 | LL | / loop { LL | | @@ -148,7 +150,7 @@ LL | fn break_wrong_loop(cond: bool) -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:182:5 + --> tests/ui/infinite_loops.rs:183:5 | LL | / loop { LL | | @@ -164,7 +166,7 @@ LL | fn match_like() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:223:5 + --> tests/ui/infinite_loops.rs:224:5 | LL | / loop { LL | | @@ -178,7 +180,7 @@ LL | fn match_like() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:228:5 + --> tests/ui/infinite_loops.rs:229:5 | LL | / loop { LL | | @@ -195,7 +197,7 @@ LL | fn match_like() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:333:9 + --> tests/ui/infinite_loops.rs:334:9 | LL | / loop { LL | | @@ -209,7 +211,7 @@ LL | fn problematic_trait_method() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:343:9 + --> tests/ui/infinite_loops.rs:344:9 | LL | / loop { LL | | @@ -223,7 +225,7 @@ LL | fn could_be_problematic() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:352:9 + --> tests/ui/infinite_loops.rs:353:9 | LL | / loop { LL | | @@ -237,10 +239,11 @@ LL | let _loop_forever = || -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:366:8 + --> tests/ui/infinite_loops.rs:367:8 | LL | Ok(loop { | ________^ +LL | | LL | | do_something() LL | | }) | |_____^ @@ -248,7 +251,7 @@ LL | | }) = help: if this is not intended, try adding a `break` or `return` condition in the loop error: infinite loop detected - --> tests/ui/infinite_loops.rs:408:5 + --> tests/ui/infinite_loops.rs:410:5 | LL | / 'infinite: loop { LL | | @@ -264,12 +267,11 @@ LL | fn continue_outer() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:415:5 + --> tests/ui/infinite_loops.rs:417:5 | LL | / loop { LL | | LL | | 'inner: loop { -LL | | loop { ... | LL | | } | |_____^ @@ -280,9 +282,10 @@ LL | fn continue_outer() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:417:9 + --> tests/ui/infinite_loops.rs:419:9 | LL | / 'inner: loop { +LL | | LL | | loop { LL | | continue 'inner; LL | | } @@ -295,7 +298,7 @@ LL | fn continue_outer() -> ! { | ++++ error: infinite loop detected - --> tests/ui/infinite_loops.rs:425:5 + --> tests/ui/infinite_loops.rs:428:5 | LL | / loop { LL | | diff --git a/src/tools/clippy/tests/ui/inherent_to_string.rs b/src/tools/clippy/tests/ui/inherent_to_string.rs index 7b938cdd758c3..30977f2d93ac6 100644 --- a/src/tools/clippy/tests/ui/inherent_to_string.rs +++ b/src/tools/clippy/tests/ui/inherent_to_string.rs @@ -20,7 +20,8 @@ struct J; impl A { // Should be detected; emit warning fn to_string(&self) -> String { - //~^ ERROR: implementation of inherent method `to_string(&self) -> String` for type `A + //~^ inherent_to_string + "A.to_string()".to_string() } @@ -45,7 +46,8 @@ impl B { impl C { // Should be detected and emit error as C also implements Display fn to_string(&self) -> String { - //~^ ERROR: type `C` implements inherent method `to_string(&self) -> String` which sha + //~^ inherent_to_string_shadow_display + "C.to_string()".to_string() } } diff --git a/src/tools/clippy/tests/ui/inherent_to_string.stderr b/src/tools/clippy/tests/ui/inherent_to_string.stderr index eb22525a24919..f1d415a457558 100644 --- a/src/tools/clippy/tests/ui/inherent_to_string.stderr +++ b/src/tools/clippy/tests/ui/inherent_to_string.stderr @@ -3,6 +3,7 @@ error: implementation of inherent method `to_string(&self) -> String` for type ` | LL | / fn to_string(&self) -> String { LL | | +LL | | LL | | "A.to_string()".to_string() LL | | } | |_____^ @@ -12,10 +13,11 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::inherent_to_string)]` error: type `C` implements inherent method `to_string(&self) -> String` which shadows the implementation of `Display` - --> tests/ui/inherent_to_string.rs:47:5 + --> tests/ui/inherent_to_string.rs:48:5 | LL | / fn to_string(&self) -> String { LL | | +LL | | LL | | "C.to_string()".to_string() LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/init_numbered_fields.fixed b/src/tools/clippy/tests/ui/init_numbered_fields.fixed index dca4e8da4d2f7..b4c5fa83ce956 100644 --- a/src/tools/clippy/tests/ui/init_numbered_fields.fixed +++ b/src/tools/clippy/tests/ui/init_numbered_fields.fixed @@ -39,6 +39,7 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec(vec![0, 1, 2, 3]); + //~^ init_numbered_fields { struct S(i32, i32); diff --git a/src/tools/clippy/tests/ui/init_numbered_fields.rs b/src/tools/clippy/tests/ui/init_numbered_fields.rs index 8cb34705b4f67..ae5dfe889575b 100644 --- a/src/tools/clippy/tests/ui/init_numbered_fields.rs +++ b/src/tools/clippy/tests/ui/init_numbered_fields.rs @@ -15,6 +15,7 @@ fn main() { // This should lint let _ = TupleStruct { + //~^ init_numbered_fields 0: 1u32, 1: 42, 2: 23u8, @@ -22,6 +23,7 @@ fn main() { // This should also lint and order the fields correctly let _ = TupleStruct { + //~^ init_numbered_fields 0: 1u32, 2: 2u8, 1: 3u32, @@ -47,6 +49,7 @@ fn main() { struct TupleStructVec(Vec); let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; + //~^ init_numbered_fields { struct S(i32, i32); diff --git a/src/tools/clippy/tests/ui/init_numbered_fields.stderr b/src/tools/clippy/tests/ui/init_numbered_fields.stderr index f176e0c2ff301..89828b7e2fce2 100644 --- a/src/tools/clippy/tests/ui/init_numbered_fields.stderr +++ b/src/tools/clippy/tests/ui/init_numbered_fields.stderr @@ -3,6 +3,7 @@ error: used a field initializer for a tuple struct | LL | let _ = TupleStruct { | _____________^ +LL | | LL | | 0: 1u32, LL | | 1: 42, LL | | 2: 23u8, @@ -13,10 +14,11 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::init_numbered_fields)]` error: used a field initializer for a tuple struct - --> tests/ui/init_numbered_fields.rs:24:13 + --> tests/ui/init_numbered_fields.rs:25:13 | LL | let _ = TupleStruct { | _____________^ +LL | | LL | | 0: 1u32, LL | | 2: 2u8, LL | | 1: 3u32, @@ -24,7 +26,7 @@ LL | | }; | |_____^ help: use tuple initialization: `TupleStruct(1u32, 3u32, 2u8)` error: used a field initializer for a tuple struct - --> tests/ui/init_numbered_fields.rs:49:13 + --> tests/ui/init_numbered_fields.rs:51:13 | LL | let _ = TupleStructVec { 0: vec![0, 1, 2, 3] }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use tuple initialization: `TupleStructVec(vec![0, 1, 2, 3])` diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.fixed b/src/tools/clippy/tests/ui/inline_fn_without_body.fixed index acd808ed49bb7..3567209b41f7d 100644 --- a/src/tools/clippy/tests/ui/inline_fn_without_body.fixed +++ b/src/tools/clippy/tests/ui/inline_fn_without_body.fixed @@ -2,10 +2,13 @@ #![allow(clippy::inline_always)] trait Foo { + //~^ inline_fn_without_body fn default_inline(); + //~^ inline_fn_without_body fn always_inline(); + //~^ inline_fn_without_body fn never_inline(); #[inline] diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.rs b/src/tools/clippy/tests/ui/inline_fn_without_body.rs index af81feaa374a7..9ca90e637f15b 100644 --- a/src/tools/clippy/tests/ui/inline_fn_without_body.rs +++ b/src/tools/clippy/tests/ui/inline_fn_without_body.rs @@ -3,12 +3,15 @@ trait Foo { #[inline] + //~^ inline_fn_without_body fn default_inline(); #[inline(always)] + //~^ inline_fn_without_body fn always_inline(); #[inline(never)] + //~^ inline_fn_without_body fn never_inline(); #[inline] diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.stderr b/src/tools/clippy/tests/ui/inline_fn_without_body.stderr index 89db710fabe77..61bc5505ea301 100644 --- a/src/tools/clippy/tests/ui/inline_fn_without_body.stderr +++ b/src/tools/clippy/tests/ui/inline_fn_without_body.stderr @@ -3,26 +3,26 @@ error: use of `#[inline]` on trait method `default_inline` which has no body | LL | #[inline] | _____-^^^^^^^^ -LL | | fn default_inline(); +LL | | | |____- help: remove | = note: `-D clippy::inline-fn-without-body` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::inline_fn_without_body)]` error: use of `#[inline]` on trait method `always_inline` which has no body - --> tests/ui/inline_fn_without_body.rs:8:5 + --> tests/ui/inline_fn_without_body.rs:9:5 | LL | #[inline(always)] | _____-^^^^^^^^^^^^^^^^ -LL | | fn always_inline(); +LL | | | |____- help: remove error: use of `#[inline]` on trait method `never_inline` which has no body - --> tests/ui/inline_fn_without_body.rs:11:5 + --> tests/ui/inline_fn_without_body.rs:13:5 | LL | #[inline(never)] | _____-^^^^^^^^^^^^^^^ -LL | | fn never_inline(); +LL | | | |____- help: remove error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/inspect_for_each.rs b/src/tools/clippy/tests/ui/inspect_for_each.rs index 974690eaa8e4f..8bfd9cec66dc5 100644 --- a/src/tools/clippy/tests/ui/inspect_for_each.rs +++ b/src/tools/clippy/tests/ui/inspect_for_each.rs @@ -5,7 +5,8 @@ fn main() { let mut b: Vec = Vec::new(); a.into_iter().inspect(|x| assert!(*x > 0)).for_each(|x| { - //~^ ERROR: called `inspect(..).for_each(..)` on an `Iterator` + //~^ inspect_for_each + let y = do_some(x); let z = do_more(y); b.push(z); diff --git a/src/tools/clippy/tests/ui/inspect_for_each.stderr b/src/tools/clippy/tests/ui/inspect_for_each.stderr index 3c2dee15ebd5b..6a715c9c4efca 100644 --- a/src/tools/clippy/tests/ui/inspect_for_each.stderr +++ b/src/tools/clippy/tests/ui/inspect_for_each.stderr @@ -4,6 +4,7 @@ error: called `inspect(..).for_each(..)` on an `Iterator` LL | a.into_iter().inspect(|x| assert!(*x > 0)).for_each(|x| { | ___________________^ LL | | +LL | | LL | | let y = do_some(x); LL | | let z = do_more(y); LL | | b.push(z); diff --git a/src/tools/clippy/tests/ui/int_plus_one.fixed b/src/tools/clippy/tests/ui/int_plus_one.fixed index 77d9cd3f773a9..a1aba6bf7f645 100644 --- a/src/tools/clippy/tests/ui/int_plus_one.fixed +++ b/src/tools/clippy/tests/ui/int_plus_one.fixed @@ -5,10 +5,14 @@ fn main() { let y = 0i32; let _ = x > y; + //~^ int_plus_one let _ = y < x; + //~^ int_plus_one let _ = x > y; + //~^ int_plus_one let _ = y < x; + //~^ int_plus_one let _ = x > y; // should be ok let _ = y < x; // should be ok diff --git a/src/tools/clippy/tests/ui/int_plus_one.rs b/src/tools/clippy/tests/ui/int_plus_one.rs index 57c87819dbfe9..f804fc9047de8 100644 --- a/src/tools/clippy/tests/ui/int_plus_one.rs +++ b/src/tools/clippy/tests/ui/int_plus_one.rs @@ -5,10 +5,14 @@ fn main() { let y = 0i32; let _ = x >= y + 1; + //~^ int_plus_one let _ = y + 1 <= x; + //~^ int_plus_one let _ = x - 1 >= y; + //~^ int_plus_one let _ = y <= x - 1; + //~^ int_plus_one let _ = x > y; // should be ok let _ = y < x; // should be ok diff --git a/src/tools/clippy/tests/ui/int_plus_one.stderr b/src/tools/clippy/tests/ui/int_plus_one.stderr index cedac14f350d4..052706028141d 100644 --- a/src/tools/clippy/tests/ui/int_plus_one.stderr +++ b/src/tools/clippy/tests/ui/int_plus_one.stderr @@ -8,19 +8,19 @@ LL | let _ = x >= y + 1; = help: to override `-D warnings` add `#[allow(clippy::int_plus_one)]` error: unnecessary `>= y + 1` or `x - 1 >=` - --> tests/ui/int_plus_one.rs:8:13 + --> tests/ui/int_plus_one.rs:9:13 | LL | let _ = y + 1 <= x; | ^^^^^^^^^^ help: change it to: `y < x` error: unnecessary `>= y + 1` or `x - 1 >=` - --> tests/ui/int_plus_one.rs:10:13 + --> tests/ui/int_plus_one.rs:12:13 | LL | let _ = x - 1 >= y; | ^^^^^^^^^^ help: change it to: `x > y` error: unnecessary `>= y + 1` or `x - 1 >=` - --> tests/ui/int_plus_one.rs:11:13 + --> tests/ui/int_plus_one.rs:14:13 | LL | let _ = y <= x - 1; | ^^^^^^^^^^ help: change it to: `y < x` diff --git a/src/tools/clippy/tests/ui/integer_division.rs b/src/tools/clippy/tests/ui/integer_division.rs index 137548fecf4a8..632fedc9e8fe3 100644 --- a/src/tools/clippy/tests/ui/integer_division.rs +++ b/src/tools/clippy/tests/ui/integer_division.rs @@ -3,10 +3,13 @@ fn main() { let two = 2; let n = 1 / 2; - //~^ ERROR: integer division + //~^ integer_division + let o = 1 / two; - //~^ ERROR: integer division + //~^ integer_division + let p = two / 4; - //~^ ERROR: integer division + //~^ integer_division + let x = 1. / 2.0; } diff --git a/src/tools/clippy/tests/ui/integer_division.stderr b/src/tools/clippy/tests/ui/integer_division.stderr index 5f0d905a48b63..0fe2021a1a9ca 100644 --- a/src/tools/clippy/tests/ui/integer_division.stderr +++ b/src/tools/clippy/tests/ui/integer_division.stderr @@ -9,7 +9,7 @@ LL | let n = 1 / 2; = help: to override `-D warnings` add `#[allow(clippy::integer_division)]` error: integer division - --> tests/ui/integer_division.rs:7:13 + --> tests/ui/integer_division.rs:8:13 | LL | let o = 1 / two; | ^^^^^^^ @@ -17,7 +17,7 @@ LL | let o = 1 / two; = help: division of integers may cause loss of precision. consider using floats error: integer division - --> tests/ui/integer_division.rs:9:13 + --> tests/ui/integer_division.rs:11:13 | LL | let p = two / 4; | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/integer_division_remainder_used.rs b/src/tools/clippy/tests/ui/integer_division_remainder_used.rs index 5d1b02095d181..4d3a7c5eaa156 100644 --- a/src/tools/clippy/tests/ui/integer_division_remainder_used.rs +++ b/src/tools/clippy/tests/ui/integer_division_remainder_used.rs @@ -8,6 +8,7 @@ impl std::ops::Div for CustomOps { fn div(self, rhs: Self) -> Self::Output { Self(self.0 / rhs.0) + //~^ integer_division_remainder_used } } impl std::ops::Rem for CustomOps { @@ -15,6 +16,7 @@ impl std::ops::Rem for CustomOps { fn rem(self, rhs: Self) -> Self::Output { Self(self.0 % rhs.0) + //~^ integer_division_remainder_used } } @@ -23,12 +25,19 @@ fn main() { let a = 10; let b = 5; let c = a / b; + //~^ integer_division_remainder_used let d = a % b; + //~^ integer_division_remainder_used let e = &a / b; + //~^ integer_division_remainder_used let f = a % &b; + //~^ integer_division_remainder_used let g = &a / &b; + //~^ integer_division_remainder_used let h = &10 % b; + //~^ integer_division_remainder_used let i = a / &4; + //~^ integer_division_remainder_used // should not trigger on custom Div and Rem let w = CustomOps(3); diff --git a/src/tools/clippy/tests/ui/integer_division_remainder_used.stderr b/src/tools/clippy/tests/ui/integer_division_remainder_used.stderr index 8adfda28893da..ea9f0e716c7d4 100644 --- a/src/tools/clippy/tests/ui/integer_division_remainder_used.stderr +++ b/src/tools/clippy/tests/ui/integer_division_remainder_used.stderr @@ -8,49 +8,49 @@ LL | Self(self.0 / rhs.0) = help: to override `-D warnings` add `#[allow(clippy::integer_division_remainder_used)]` error: use of % has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:17:14 + --> tests/ui/integer_division_remainder_used.rs:18:14 | LL | Self(self.0 % rhs.0) | ^^^^^^^^^^^^^^ error: use of / has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:25:13 + --> tests/ui/integer_division_remainder_used.rs:27:13 | LL | let c = a / b; | ^^^^^ error: use of % has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:26:13 + --> tests/ui/integer_division_remainder_used.rs:29:13 | LL | let d = a % b; | ^^^^^ error: use of / has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:27:13 + --> tests/ui/integer_division_remainder_used.rs:31:13 | LL | let e = &a / b; | ^^^^^^ error: use of % has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:28:13 + --> tests/ui/integer_division_remainder_used.rs:33:13 | LL | let f = a % &b; | ^^^^^^ error: use of / has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:29:13 + --> tests/ui/integer_division_remainder_used.rs:35:13 | LL | let g = &a / &b; | ^^^^^^^ error: use of % has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:30:13 + --> tests/ui/integer_division_remainder_used.rs:37:13 | LL | let h = &10 % b; | ^^^^^^^ error: use of / has been disallowed in this context - --> tests/ui/integer_division_remainder_used.rs:31:13 + --> tests/ui/integer_division_remainder_used.rs:39:13 | LL | let i = a / &4; | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed index 72b39c982bf71..7626569fd422f 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed @@ -10,34 +10,60 @@ fn main() { for _ in &vec![X, X] {} let _ = vec![1, 2, 3].into_iter(); - let _ = (&vec![1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter() - let _ = std::rc::Rc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter() - let _ = std::sync::Arc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter() + let _ = (&vec![1, 2, 3]).iter(); + //~^ into_iter_on_ref + let _ = std::rc::Rc::from(&[X][..]).iter(); + //~^ into_iter_on_ref + let _ = std::sync::Arc::from(&[X][..]).iter(); + //~^ into_iter_on_ref - let _ = (&&&&&&&[1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&&&&mut &&&[1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut &mut &mut [1, 2, 3]).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&&&&&&&[1, 2, 3]).iter(); + //~^ into_iter_on_ref + let _ = (&&&&mut &&&[1, 2, 3]).iter(); + //~^ into_iter_on_ref + let _ = (&mut &mut &mut [1, 2, 3]).iter_mut(); + //~^ into_iter_on_ref - let _ = (&Some(4)).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut Some(5)).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&Ok::<_, i32>(6)).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut Err::(7)).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&Vec::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut Vec::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&BTreeMap::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut BTreeMap::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&VecDeque::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut VecDeque::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&LinkedList::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut LinkedList::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&HashMap::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut HashMap::::new()).iter_mut(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&Some(4)).iter(); + //~^ into_iter_on_ref + let _ = (&mut Some(5)).iter_mut(); + //~^ into_iter_on_ref + let _ = (&Ok::<_, i32>(6)).iter(); + //~^ into_iter_on_ref + let _ = (&mut Err::(7)).iter_mut(); + //~^ into_iter_on_ref + let _ = (&Vec::::new()).iter(); + //~^ into_iter_on_ref + let _ = (&mut Vec::::new()).iter_mut(); + //~^ into_iter_on_ref + let _ = (&BTreeMap::::new()).iter(); + //~^ into_iter_on_ref + let _ = (&mut BTreeMap::::new()).iter_mut(); + //~^ into_iter_on_ref + let _ = (&VecDeque::::new()).iter(); + //~^ into_iter_on_ref + let _ = (&mut VecDeque::::new()).iter_mut(); + //~^ into_iter_on_ref + let _ = (&LinkedList::::new()).iter(); + //~^ into_iter_on_ref + let _ = (&mut LinkedList::::new()).iter_mut(); + //~^ into_iter_on_ref + let _ = (&HashMap::::new()).iter(); + //~^ into_iter_on_ref + let _ = (&mut HashMap::::new()).iter_mut(); + //~^ into_iter_on_ref - let _ = (&BTreeSet::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&BinaryHeap::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = (&HashSet::::new()).iter(); //~ ERROR: equivalent to `.iter() - let _ = std::path::Path::new("12/34").iter(); //~ ERROR: equivalent to `.iter() - let _ = std::path::PathBuf::from("12/34").iter(); //~ ERROR: equivalent to `.iter() + let _ = (&BTreeSet::::new()).iter(); + //~^ into_iter_on_ref + let _ = (&BinaryHeap::::new()).iter(); + //~^ into_iter_on_ref + let _ = (&HashSet::::new()).iter(); + //~^ into_iter_on_ref + let _ = std::path::Path::new("12/34").iter(); + //~^ into_iter_on_ref + let _ = std::path::PathBuf::from("12/34").iter(); + //~^ into_iter_on_ref - let _ = (&[1, 2, 3]).iter().next(); //~ ERROR: equivalent to `.iter() + let _ = (&[1, 2, 3]).iter().next(); + //~^ into_iter_on_ref } diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs index 5ba224720d340..286a62c69ce5c 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs @@ -10,34 +10,60 @@ fn main() { for _ in &vec![X, X] {} let _ = vec![1, 2, 3].into_iter(); - let _ = (&vec![1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&vec![1, 2, 3]).into_iter(); + //~^ into_iter_on_ref + let _ = std::rc::Rc::from(&[X][..]).into_iter(); + //~^ into_iter_on_ref + let _ = std::sync::Arc::from(&[X][..]).into_iter(); + //~^ into_iter_on_ref - let _ = (&&&&&&&[1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&&&&&&&[1, 2, 3]).into_iter(); + //~^ into_iter_on_ref + let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); + //~^ into_iter_on_ref - let _ = (&Some(4)).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut Some(5)).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&Ok::<_, i32>(6)).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut Err::(7)).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&Vec::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut Vec::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&BTreeMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut BTreeMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&VecDeque::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut VecDeque::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&LinkedList::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut LinkedList::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() - let _ = (&HashMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&mut HashMap::::new()).into_iter(); //~ ERROR: equivalent to `.iter_mut() + let _ = (&Some(4)).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut Some(5)).into_iter(); + //~^ into_iter_on_ref + let _ = (&Ok::<_, i32>(6)).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut Err::(7)).into_iter(); + //~^ into_iter_on_ref + let _ = (&Vec::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut Vec::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&BTreeMap::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut BTreeMap::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&VecDeque::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut VecDeque::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&LinkedList::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut LinkedList::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&HashMap::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&mut HashMap::::new()).into_iter(); + //~^ into_iter_on_ref - let _ = (&BTreeSet::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&BinaryHeap::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = (&HashSet::::new()).into_iter(); //~ ERROR: equivalent to `.iter() - let _ = std::path::Path::new("12/34").into_iter(); //~ ERROR: equivalent to `.iter() - let _ = std::path::PathBuf::from("12/34").into_iter(); //~ ERROR: equivalent to `.iter() + let _ = (&BTreeSet::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&BinaryHeap::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = (&HashSet::::new()).into_iter(); + //~^ into_iter_on_ref + let _ = std::path::Path::new("12/34").into_iter(); + //~^ into_iter_on_ref + let _ = std::path::PathBuf::from("12/34").into_iter(); + //~^ into_iter_on_ref - let _ = (&[1, 2, 3]).into_iter().next(); //~ ERROR: equivalent to `.iter() + let _ = (&[1, 2, 3]).into_iter().next(); + //~^ into_iter_on_ref } diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr index 64d814074da46..57ff097a6ca24 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr @@ -8,151 +8,151 @@ LL | let _ = (&vec![1, 2, 3]).into_iter(); = help: to override `-D warnings` add `#[allow(clippy::into_iter_on_ref)]` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` - --> tests/ui/into_iter_on_ref.rs:14:41 + --> tests/ui/into_iter_on_ref.rs:15:41 | LL | let _ = std::rc::Rc::from(&[X][..]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice` - --> tests/ui/into_iter_on_ref.rs:15:44 + --> tests/ui/into_iter_on_ref.rs:17:44 | LL | let _ = std::sync::Arc::from(&[X][..]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:17:32 + --> tests/ui/into_iter_on_ref.rs:20:32 | LL | let _ = (&&&&&&&[1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:18:36 + --> tests/ui/into_iter_on_ref.rs:22:36 | LL | let _ = (&&&&mut &&&[1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:19:40 + --> tests/ui/into_iter_on_ref.rs:24:40 | LL | let _ = (&mut &mut &mut [1, 2, 3]).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option` - --> tests/ui/into_iter_on_ref.rs:21:24 + --> tests/ui/into_iter_on_ref.rs:27:24 | LL | let _ = (&Some(4)).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option` - --> tests/ui/into_iter_on_ref.rs:22:28 + --> tests/ui/into_iter_on_ref.rs:29:28 | LL | let _ = (&mut Some(5)).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result` - --> tests/ui/into_iter_on_ref.rs:23:32 + --> tests/ui/into_iter_on_ref.rs:31:32 | LL | let _ = (&Ok::<_, i32>(6)).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result` - --> tests/ui/into_iter_on_ref.rs:24:37 + --> tests/ui/into_iter_on_ref.rs:33:37 | LL | let _ = (&mut Err::(7)).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec` - --> tests/ui/into_iter_on_ref.rs:25:34 + --> tests/ui/into_iter_on_ref.rs:35:34 | LL | let _ = (&Vec::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec` - --> tests/ui/into_iter_on_ref.rs:26:38 + --> tests/ui/into_iter_on_ref.rs:37:38 | LL | let _ = (&mut Vec::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap` - --> tests/ui/into_iter_on_ref.rs:27:44 + --> tests/ui/into_iter_on_ref.rs:39:44 | LL | let _ = (&BTreeMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap` - --> tests/ui/into_iter_on_ref.rs:28:48 + --> tests/ui/into_iter_on_ref.rs:41:48 | LL | let _ = (&mut BTreeMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque` - --> tests/ui/into_iter_on_ref.rs:29:39 + --> tests/ui/into_iter_on_ref.rs:43:39 | LL | let _ = (&VecDeque::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque` - --> tests/ui/into_iter_on_ref.rs:30:43 + --> tests/ui/into_iter_on_ref.rs:45:43 | LL | let _ = (&mut VecDeque::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList` - --> tests/ui/into_iter_on_ref.rs:31:41 + --> tests/ui/into_iter_on_ref.rs:47:41 | LL | let _ = (&LinkedList::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList` - --> tests/ui/into_iter_on_ref.rs:32:45 + --> tests/ui/into_iter_on_ref.rs:49:45 | LL | let _ = (&mut LinkedList::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap` - --> tests/ui/into_iter_on_ref.rs:33:43 + --> tests/ui/into_iter_on_ref.rs:51:43 | LL | let _ = (&HashMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap` - --> tests/ui/into_iter_on_ref.rs:34:47 + --> tests/ui/into_iter_on_ref.rs:53:47 | LL | let _ = (&mut HashMap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter_mut` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet` - --> tests/ui/into_iter_on_ref.rs:36:39 + --> tests/ui/into_iter_on_ref.rs:56:39 | LL | let _ = (&BTreeSet::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap` - --> tests/ui/into_iter_on_ref.rs:37:41 + --> tests/ui/into_iter_on_ref.rs:58:41 | LL | let _ = (&BinaryHeap::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet` - --> tests/ui/into_iter_on_ref.rs:38:38 + --> tests/ui/into_iter_on_ref.rs:60:38 | LL | let _ = (&HashSet::::new()).into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path` - --> tests/ui/into_iter_on_ref.rs:39:43 + --> tests/ui/into_iter_on_ref.rs:62:43 | LL | let _ = std::path::Path::new("12/34").into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf` - --> tests/ui/into_iter_on_ref.rs:40:47 + --> tests/ui/into_iter_on_ref.rs:64:47 | LL | let _ = std::path::PathBuf::from("12/34").into_iter(); | ^^^^^^^^^ help: call directly: `iter` error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array` - --> tests/ui/into_iter_on_ref.rs:42:26 + --> tests/ui/into_iter_on_ref.rs:67:26 | LL | let _ = (&[1, 2, 3]).into_iter().next(); | ^^^^^^^^^ help: call directly: `iter` diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs index 109259d6975c7..45e34b3930ad0 100644 --- a/src/tools/clippy/tests/ui/into_iter_without_iter.rs +++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs @@ -7,7 +7,7 @@ use std::iter::IntoIterator; pub struct S1; impl<'a> IntoIterator for &'a S1 { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + //~^ into_iter_without_iter type IntoIter = std::slice::Iter<'a, u8>; type Item = &'a u8; fn into_iter(self) -> Self::IntoIter { @@ -15,7 +15,7 @@ impl<'a> IntoIterator for &'a S1 { } } impl<'a> IntoIterator for &'a mut S1 { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + //~^ into_iter_without_iter type IntoIter = std::slice::IterMut<'a, u8>; type Item = &'a mut u8; fn into_iter(self) -> Self::IntoIter { @@ -25,7 +25,7 @@ impl<'a> IntoIterator for &'a mut S1 { pub struct S2(T); impl<'a, T> IntoIterator for &'a S2 { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method + //~^ into_iter_without_iter type IntoIter = std::slice::Iter<'a, T>; type Item = &'a T; fn into_iter(self) -> Self::IntoIter { @@ -33,7 +33,7 @@ impl<'a, T> IntoIterator for &'a S2 { } } impl<'a, T> IntoIterator for &'a mut S2 { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + //~^ into_iter_without_iter type IntoIter = std::slice::IterMut<'a, T>; type Item = &'a mut T; fn into_iter(self) -> Self::IntoIter { @@ -84,7 +84,7 @@ impl<'a, T> IntoIterator for &S4<'a, T> { } impl<'a, T> IntoIterator for &mut S4<'a, T> { - //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method + //~^ into_iter_without_iter type IntoIter = std::slice::IterMut<'a, T>; type Item = &'a mut T; fn into_iter(self) -> Self::IntoIter { @@ -118,6 +118,7 @@ pub struct Issue12037; macro_rules! generate_impl { () => { impl<'a> IntoIterator for &'a Issue12037 { + //~^ into_iter_without_iter type IntoIter = std::slice::Iter<'a, u8>; type Item = &'a u8; fn into_iter(self) -> Self::IntoIter { diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.stderr b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr index cde1b60c2abcf..a033ff645f49a 100644 --- a/src/tools/clippy/tests/ui/into_iter_without_iter.stderr +++ b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr @@ -109,9 +109,9 @@ error: `IntoIterator` implemented for a reference type without an `iter` method --> tests/ui/into_iter_without_iter.rs:120:9 | LL | / impl<'a> IntoIterator for &'a Issue12037 { +LL | | LL | | type IntoIter = std::slice::Iter<'a, u8>; LL | | type Item = &'a u8; -LL | | fn into_iter(self) -> Self::IntoIter { ... | LL | | } | |_________^ diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed index ba225102c984b..ce78e89ee829c 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed @@ -1,44 +1,66 @@ fn main() { unsafe { let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage struct A; // zero sized struct assert_eq!(std::mem::size_of::(), 0); let _a: A = std::ptr::read(std::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read(std::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_unaligned(std::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_unaligned(std::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_volatile(std::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_volatile(std::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::replace(std::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); std::ptr::swap::(std::ptr::NonNull::dangling().as_ptr(), &mut A); + //~^ invalid_null_ptr_usage std::ptr::swap::(&mut A, std::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage std::ptr::swap_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), &mut A, 0); + //~^ invalid_null_ptr_usage std::ptr::swap_nonoverlapping::(&mut A, std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage std::ptr::write(std::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage std::ptr::write_unaligned(std::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage std::ptr::write_volatile(std::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage std::ptr::write_bytes::(std::ptr::NonNull::dangling().as_ptr(), 42, 0); + //~^ invalid_null_ptr_usage } } diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs index 480b6642a3e3a..361865fbd9601 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs @@ -1,44 +1,66 @@ fn main() { unsafe { let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy_nonoverlapping::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage struct A; // zero sized struct assert_eq!(std::mem::size_of::(), 0); let _a: A = std::ptr::read(std::ptr::null()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read(std::ptr::null_mut()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_unaligned(std::ptr::null()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_unaligned(std::ptr::null_mut()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_volatile(std::ptr::null()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::read_volatile(std::ptr::null_mut()); + //~^ invalid_null_ptr_usage let _a: A = std::ptr::replace(std::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage let _slice: *const [usize] = std::ptr::slice_from_raw_parts(std::ptr::null_mut(), 0); // shouldn't lint let _slice: *const [usize] = std::ptr::slice_from_raw_parts_mut(std::ptr::null_mut(), 0); std::ptr::swap::(std::ptr::null_mut(), &mut A); + //~^ invalid_null_ptr_usage std::ptr::swap::(&mut A, std::ptr::null_mut()); + //~^ invalid_null_ptr_usage std::ptr::swap_nonoverlapping::(std::ptr::null_mut(), &mut A, 0); + //~^ invalid_null_ptr_usage std::ptr::swap_nonoverlapping::(&mut A, std::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage std::ptr::write(std::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage std::ptr::write_unaligned(std::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage std::ptr::write_volatile(std::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage std::ptr::write_bytes::(std::ptr::null_mut(), 42, 0); + //~^ invalid_null_ptr_usage } } diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr index 613a2cc36885c..3f9d15b904018 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.stderr @@ -7,127 +7,127 @@ LL | let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null(), = note: `#[deny(clippy::invalid_null_ptr_usage)]` on by default error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:4:59 + --> tests/ui/invalid_null_ptr_usage.rs:5:59 | LL | let _slice: &[usize] = std::slice::from_raw_parts(std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:6:63 + --> tests/ui/invalid_null_ptr_usage.rs:8:63 | LL | let _slice: &[usize] = std::slice::from_raw_parts_mut(std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:8:33 + --> tests/ui/invalid_null_ptr_usage.rs:11:33 | LL | std::ptr::copy::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:9:73 + --> tests/ui/invalid_null_ptr_usage.rs:13:73 | LL | std::ptr::copy::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:11:48 + --> tests/ui/invalid_null_ptr_usage.rs:16:48 | LL | std::ptr::copy_nonoverlapping::(std::ptr::null(), std::ptr::NonNull::dangling().as_ptr(), 0); | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:12:88 + --> tests/ui/invalid_null_ptr_usage.rs:18:88 | LL | std::ptr::copy_nonoverlapping::(std::ptr::NonNull::dangling().as_ptr(), std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:17:36 + --> tests/ui/invalid_null_ptr_usage.rs:24:36 | LL | let _a: A = std::ptr::read(std::ptr::null()); | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:18:36 + --> tests/ui/invalid_null_ptr_usage.rs:26:36 | LL | let _a: A = std::ptr::read(std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:20:46 + --> tests/ui/invalid_null_ptr_usage.rs:29:46 | LL | let _a: A = std::ptr::read_unaligned(std::ptr::null()); | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:21:46 + --> tests/ui/invalid_null_ptr_usage.rs:31:46 | LL | let _a: A = std::ptr::read_unaligned(std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:23:45 + --> tests/ui/invalid_null_ptr_usage.rs:34:45 | LL | let _a: A = std::ptr::read_volatile(std::ptr::null()); | ^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:24:45 + --> tests/ui/invalid_null_ptr_usage.rs:36:45 | LL | let _a: A = std::ptr::read_volatile(std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:26:39 + --> tests/ui/invalid_null_ptr_usage.rs:39:39 | LL | let _a: A = std::ptr::replace(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:30:29 + --> tests/ui/invalid_null_ptr_usage.rs:44:29 | LL | std::ptr::swap::(std::ptr::null_mut(), &mut A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:31:37 + --> tests/ui/invalid_null_ptr_usage.rs:46:37 | LL | std::ptr::swap::(&mut A, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:33:44 + --> tests/ui/invalid_null_ptr_usage.rs:49:44 | LL | std::ptr::swap_nonoverlapping::(std::ptr::null_mut(), &mut A, 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:34:52 + --> tests/ui/invalid_null_ptr_usage.rs:51:52 | LL | std::ptr::swap_nonoverlapping::(&mut A, std::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:36:25 + --> tests/ui/invalid_null_ptr_usage.rs:54:25 | LL | std::ptr::write(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:38:35 + --> tests/ui/invalid_null_ptr_usage.rs:57:35 | LL | std::ptr::write_unaligned(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:40:34 + --> tests/ui/invalid_null_ptr_usage.rs:60:34 | LL | std::ptr::write_volatile(std::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage.rs:42:40 + --> tests/ui/invalid_null_ptr_usage.rs:63:40 | LL | std::ptr::write_bytes::(std::ptr::null_mut(), 42, 0); | ^^^^^^^^^^^^^^^^^^^^ help: change this to: `std::ptr::NonNull::dangling().as_ptr()` diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed index 2bbfe72742426..df7ab166187de 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.fixed @@ -14,44 +14,66 @@ fn panic(info: &PanicInfo) -> ! { fn main() { unsafe { let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage struct A; // zero sized struct assert_eq!(core::mem::size_of::(), 0); let _a: A = core::ptr::read(core::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read(core::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_unaligned(core::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_volatile(core::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::replace(core::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage let _slice: *const [usize] = core::ptr::slice_from_raw_parts(core::ptr::null_mut(), 0); // shouldn't lint let _slice: *const [usize] = core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut(), 0); core::ptr::swap::(core::ptr::NonNull::dangling().as_ptr(), &mut A); + //~^ invalid_null_ptr_usage core::ptr::swap::(&mut A, core::ptr::NonNull::dangling().as_ptr()); + //~^ invalid_null_ptr_usage core::ptr::swap_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), &mut A, 0); + //~^ invalid_null_ptr_usage core::ptr::swap_nonoverlapping::(&mut A, core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage core::ptr::write(core::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage core::ptr::write_unaligned(core::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage core::ptr::write_volatile(core::ptr::NonNull::dangling().as_ptr(), A); + //~^ invalid_null_ptr_usage core::ptr::write_bytes::(core::ptr::NonNull::dangling().as_ptr(), 42, 0); + //~^ invalid_null_ptr_usage } } diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs index cbce44f7c0d9b..38ddfff055353 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.rs @@ -14,44 +14,66 @@ fn panic(info: &PanicInfo) -> ! { fn main() { unsafe { let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy_nonoverlapping::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); + //~^ invalid_null_ptr_usage core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage struct A; // zero sized struct assert_eq!(core::mem::size_of::(), 0); let _a: A = core::ptr::read(core::ptr::null()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read(core::ptr::null_mut()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_unaligned(core::ptr::null()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_unaligned(core::ptr::null_mut()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_volatile(core::ptr::null()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::read_volatile(core::ptr::null_mut()); + //~^ invalid_null_ptr_usage let _a: A = core::ptr::replace(core::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage let _slice: *const [usize] = core::ptr::slice_from_raw_parts(core::ptr::null_mut(), 0); // shouldn't lint let _slice: *const [usize] = core::ptr::slice_from_raw_parts_mut(core::ptr::null_mut(), 0); core::ptr::swap::(core::ptr::null_mut(), &mut A); + //~^ invalid_null_ptr_usage core::ptr::swap::(&mut A, core::ptr::null_mut()); + //~^ invalid_null_ptr_usage core::ptr::swap_nonoverlapping::(core::ptr::null_mut(), &mut A, 0); + //~^ invalid_null_ptr_usage core::ptr::swap_nonoverlapping::(&mut A, core::ptr::null_mut(), 0); + //~^ invalid_null_ptr_usage core::ptr::write(core::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage core::ptr::write_unaligned(core::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage core::ptr::write_volatile(core::ptr::null_mut(), A); + //~^ invalid_null_ptr_usage core::ptr::write_bytes::(core::ptr::null_mut(), 42, 0); + //~^ invalid_null_ptr_usage } } diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr index df0d40e9e072c..b5dd21ce6248f 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage_no_std.stderr @@ -7,127 +7,127 @@ LL | let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null( = note: `#[deny(clippy::invalid_null_ptr_usage)]` on by default error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:17:60 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:18:60 | LL | let _slice: &[usize] = core::slice::from_raw_parts(core::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:19:64 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:21:64 | LL | let _slice: &[usize] = core::slice::from_raw_parts_mut(core::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:21:34 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:24:34 | LL | core::ptr::copy::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:22:75 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:26:75 | LL | core::ptr::copy::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:24:49 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:29:49 | LL | core::ptr::copy_nonoverlapping::(core::ptr::null(), core::ptr::NonNull::dangling().as_ptr(), 0); | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:25:90 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:31:90 | LL | core::ptr::copy_nonoverlapping::(core::ptr::NonNull::dangling().as_ptr(), core::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:30:37 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:37:37 | LL | let _a: A = core::ptr::read(core::ptr::null()); | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:31:37 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:39:37 | LL | let _a: A = core::ptr::read(core::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:33:47 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:42:47 | LL | let _a: A = core::ptr::read_unaligned(core::ptr::null()); | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:34:47 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:44:47 | LL | let _a: A = core::ptr::read_unaligned(core::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:36:46 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:47:46 | LL | let _a: A = core::ptr::read_volatile(core::ptr::null()); | ^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:37:46 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:49:46 | LL | let _a: A = core::ptr::read_volatile(core::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:39:40 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:52:40 | LL | let _a: A = core::ptr::replace(core::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:43:30 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:57:30 | LL | core::ptr::swap::(core::ptr::null_mut(), &mut A); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:44:38 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:59:38 | LL | core::ptr::swap::(&mut A, core::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:46:45 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:62:45 | LL | core::ptr::swap_nonoverlapping::(core::ptr::null_mut(), &mut A, 0); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:47:53 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:64:53 | LL | core::ptr::swap_nonoverlapping::(&mut A, core::ptr::null_mut(), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:49:26 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:67:26 | LL | core::ptr::write(core::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:51:36 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:70:36 | LL | core::ptr::write_unaligned(core::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:53:35 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:73:35 | LL | core::ptr::write_volatile(core::ptr::null_mut(), A); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` error: pointer must be non-null - --> tests/ui/invalid_null_ptr_usage_no_std.rs:55:41 + --> tests/ui/invalid_null_ptr_usage_no_std.rs:76:41 | LL | core::ptr::write_bytes::(core::ptr::null_mut(), 42, 0); | ^^^^^^^^^^^^^^^^^^^^^ help: change this to: `core::ptr::NonNull::dangling().as_ptr()` diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs index a9db15f209733..4f3194869f430 100644 --- a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.rs @@ -19,61 +19,81 @@ fn main() { // always false, since no u8 can be > 300 (u8 as u32) > 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is - //~| NOTE: `-D clippy::invalid-upcast-comparisons` implied by `-D warnings` + //~^ invalid_upcast_comparisons + (u8 as i32) > 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + (u8 as u32) == 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + (u8 as i32) == 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 < (u8 as u32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 < (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 == (u8 as u32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 == (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + // inverted of the above (u8 as u32) <= 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + (u8 as i32) <= 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + (u8 as u32) != 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + (u8 as i32) != 300; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 >= (u8 as u32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 >= (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 != (u8 as u32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 300 != (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons // always false, since u8 -> i32 doesn't wrap (u8 as i32) < 0; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + -5 != (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + // inverted of the above (u8 as i32) >= 0; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + -5 == (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons // always false, since no u8 can be 1337 1337 == (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 1337 == (u8 as u32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + // inverted of the above 1337 != (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + 1337 != (u8 as u32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons // Those are Ok: (u8 as u32) > 20; @@ -88,9 +108,11 @@ fn main() { (u8 as i8) == -1; (u8 as i8) != -1; (u8 as i32) > -1; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + (u8 as i32) < -1; - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons + (u32 as i32) < -5; (u32 as i32) < 10; @@ -107,7 +129,7 @@ fn main() { -5 > (u32 as i32); -5 >= (u8 as i32); - //~^ ERROR: because of the numeric bounds on `u8` prior to casting, this expression is + //~^ invalid_upcast_comparisons -5 == (u32 as i32); } diff --git a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr index b1fbe29515775..ef36f18eabc9a 100644 --- a/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr +++ b/src/tools/clippy/tests/ui/invalid_upcast_comparisons.stderr @@ -14,151 +14,151 @@ LL | (u8 as i32) > 300; | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:26:5 + --> tests/ui/invalid_upcast_comparisons.rs:27:5 | LL | (u8 as u32) == 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:28:5 + --> tests/ui/invalid_upcast_comparisons.rs:30:5 | LL | (u8 as i32) == 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:30:5 + --> tests/ui/invalid_upcast_comparisons.rs:33:5 | LL | 300 < (u8 as u32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:32:5 + --> tests/ui/invalid_upcast_comparisons.rs:36:5 | LL | 300 < (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:34:5 + --> tests/ui/invalid_upcast_comparisons.rs:39:5 | LL | 300 == (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:36:5 + --> tests/ui/invalid_upcast_comparisons.rs:42:5 | LL | 300 == (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:39:5 + --> tests/ui/invalid_upcast_comparisons.rs:46:5 | LL | (u8 as u32) <= 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:41:5 + --> tests/ui/invalid_upcast_comparisons.rs:49:5 | LL | (u8 as i32) <= 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:43:5 + --> tests/ui/invalid_upcast_comparisons.rs:52:5 | LL | (u8 as u32) != 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:45:5 + --> tests/ui/invalid_upcast_comparisons.rs:55:5 | LL | (u8 as i32) != 300; | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:47:5 + --> tests/ui/invalid_upcast_comparisons.rs:58:5 | LL | 300 >= (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:49:5 + --> tests/ui/invalid_upcast_comparisons.rs:61:5 | LL | 300 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:51:5 + --> tests/ui/invalid_upcast_comparisons.rs:64:5 | LL | 300 != (u8 as u32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:53:5 + --> tests/ui/invalid_upcast_comparisons.rs:67:5 | LL | 300 != (u8 as i32); | ^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:57:5 + --> tests/ui/invalid_upcast_comparisons.rs:71:5 | LL | (u8 as i32) < 0; | ^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:59:5 + --> tests/ui/invalid_upcast_comparisons.rs:74:5 | LL | -5 != (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:62:5 + --> tests/ui/invalid_upcast_comparisons.rs:78:5 | LL | (u8 as i32) >= 0; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:64:5 + --> tests/ui/invalid_upcast_comparisons.rs:81:5 | LL | -5 == (u8 as i32); | ^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:68:5 + --> tests/ui/invalid_upcast_comparisons.rs:85:5 | LL | 1337 == (u8 as i32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:70:5 + --> tests/ui/invalid_upcast_comparisons.rs:88:5 | LL | 1337 == (u8 as u32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:73:5 + --> tests/ui/invalid_upcast_comparisons.rs:92:5 | LL | 1337 != (u8 as i32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:75:5 + --> tests/ui/invalid_upcast_comparisons.rs:95:5 | LL | 1337 != (u8 as u32); | ^^^^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always true - --> tests/ui/invalid_upcast_comparisons.rs:90:5 + --> tests/ui/invalid_upcast_comparisons.rs:110:5 | LL | (u8 as i32) > -1; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:92:5 + --> tests/ui/invalid_upcast_comparisons.rs:113:5 | LL | (u8 as i32) < -1; | ^^^^^^^^^^^^^^^^ error: because of the numeric bounds on `u8` prior to casting, this expression is always false - --> tests/ui/invalid_upcast_comparisons.rs:109:5 + --> tests/ui/invalid_upcast_comparisons.rs:131:5 | LL | -5 >= (u8 as i32); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/io_other_error.fixed b/src/tools/clippy/tests/ui/io_other_error.fixed new file mode 100644 index 0000000000000..0054c56fb6282 --- /dev/null +++ b/src/tools/clippy/tests/ui/io_other_error.fixed @@ -0,0 +1,55 @@ +#![warn(clippy::io_other_error)] +use std::fmt; + +#[derive(Debug)] +struct E; + +impl std::error::Error for E {} +impl fmt::Display for E { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("E") + } +} + +macro_rules! o { + {} => { std::io::ErrorKind::Other }; +} + +macro_rules! e { + { $kind:expr } => { std::io::Error::new($kind, E) }; +} + +fn main() { + let _err = std::io::Error::other(E); + //~^ ERROR: this can be `std::io::Error::other(_)` + let other = std::io::ErrorKind::Other; + let _err = std::io::Error::other(E); + //~^ ERROR: this can be `std::io::Error::other(_)` + + // not other + let _err = std::io::Error::new(std::io::ErrorKind::TimedOut, E); + + // from expansion + let _err = e!(other); + let _err = std::io::Error::new(o!(), E); + let _err = e!(o!()); + + paths::short(); + under_msrv(); +} + +mod paths { + use std::io::{self, Error, ErrorKind}; + + pub fn short() { + let _err = Error::other(super::E); + //~^ ERROR: this can be `std::io::Error::other(_)` + let _err = io::Error::other(super::E); + //~^ ERROR: this can be `std::io::Error::other(_)` + } +} + +#[clippy::msrv = "1.73"] +fn under_msrv() { + let _err = std::io::Error::new(std::io::ErrorKind::Other, E); +} diff --git a/src/tools/clippy/tests/ui/io_other_error.rs b/src/tools/clippy/tests/ui/io_other_error.rs new file mode 100644 index 0000000000000..8529fb9a77f98 --- /dev/null +++ b/src/tools/clippy/tests/ui/io_other_error.rs @@ -0,0 +1,55 @@ +#![warn(clippy::io_other_error)] +use std::fmt; + +#[derive(Debug)] +struct E; + +impl std::error::Error for E {} +impl fmt::Display for E { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("E") + } +} + +macro_rules! o { + {} => { std::io::ErrorKind::Other }; +} + +macro_rules! e { + { $kind:expr } => { std::io::Error::new($kind, E) }; +} + +fn main() { + let _err = std::io::Error::new(std::io::ErrorKind::Other, E); + //~^ ERROR: this can be `std::io::Error::other(_)` + let other = std::io::ErrorKind::Other; + let _err = std::io::Error::new(other, E); + //~^ ERROR: this can be `std::io::Error::other(_)` + + // not other + let _err = std::io::Error::new(std::io::ErrorKind::TimedOut, E); + + // from expansion + let _err = e!(other); + let _err = std::io::Error::new(o!(), E); + let _err = e!(o!()); + + paths::short(); + under_msrv(); +} + +mod paths { + use std::io::{self, Error, ErrorKind}; + + pub fn short() { + let _err = Error::new(ErrorKind::Other, super::E); + //~^ ERROR: this can be `std::io::Error::other(_)` + let _err = io::Error::new(io::ErrorKind::Other, super::E); + //~^ ERROR: this can be `std::io::Error::other(_)` + } +} + +#[clippy::msrv = "1.73"] +fn under_msrv() { + let _err = std::io::Error::new(std::io::ErrorKind::Other, E); +} diff --git a/src/tools/clippy/tests/ui/io_other_error.stderr b/src/tools/clippy/tests/ui/io_other_error.stderr new file mode 100644 index 0000000000000..e79e05ecd406b --- /dev/null +++ b/src/tools/clippy/tests/ui/io_other_error.stderr @@ -0,0 +1,52 @@ +error: this can be `std::io::Error::other(_)` + --> tests/ui/io_other_error.rs:23:16 + | +LL | let _err = std::io::Error::new(std::io::ErrorKind::Other, E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::io-other-error` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::io_other_error)]` +help: use `std::io::Error::other` + | +LL - let _err = std::io::Error::new(std::io::ErrorKind::Other, E); +LL + let _err = std::io::Error::other(E); + | + +error: this can be `std::io::Error::other(_)` + --> tests/ui/io_other_error.rs:26:16 + | +LL | let _err = std::io::Error::new(other, E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `std::io::Error::other` + | +LL - let _err = std::io::Error::new(other, E); +LL + let _err = std::io::Error::other(E); + | + +error: this can be `std::io::Error::other(_)` + --> tests/ui/io_other_error.rs:45:20 + | +LL | let _err = Error::new(ErrorKind::Other, super::E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `std::io::Error::other` + | +LL - let _err = Error::new(ErrorKind::Other, super::E); +LL + let _err = Error::other(super::E); + | + +error: this can be `std::io::Error::other(_)` + --> tests/ui/io_other_error.rs:47:20 + | +LL | let _err = io::Error::new(io::ErrorKind::Other, super::E); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use `std::io::Error::other` + | +LL - let _err = io::Error::new(io::ErrorKind::Other, super::E); +LL + let _err = io::Error::other(super::E); + | + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed b/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed index 62953ff74cfcf..b0509ed2a751d 100644 --- a/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed +++ b/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed @@ -7,8 +7,11 @@ fn main() { // Should trigger the lint. let _ = c.is_ascii_digit(); + //~^ is_digit_ascii_radix let _ = c.is_ascii_hexdigit(); + //~^ is_digit_ascii_radix let _ = c.is_ascii_hexdigit(); + //~^ is_digit_ascii_radix // Should not trigger the lint. let _ = c.is_digit(11); diff --git a/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs b/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs index 229f530f611df..68d4b56063b51 100644 --- a/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs +++ b/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs @@ -7,8 +7,11 @@ fn main() { // Should trigger the lint. let _ = c.is_digit(10); + //~^ is_digit_ascii_radix let _ = c.is_digit(16); + //~^ is_digit_ascii_radix let _ = c.is_digit(0x10); + //~^ is_digit_ascii_radix // Should not trigger the lint. let _ = c.is_digit(11); diff --git a/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr b/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr index f26183ddab84d..b6e53eb5829f3 100644 --- a/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr +++ b/src/tools/clippy/tests/ui/is_digit_ascii_radix.stderr @@ -8,13 +8,13 @@ LL | let _ = c.is_digit(10); = help: to override `-D warnings` add `#[allow(clippy::is_digit_ascii_radix)]` error: use of `char::is_digit` with literal radix of 16 - --> tests/ui/is_digit_ascii_radix.rs:10:13 + --> tests/ui/is_digit_ascii_radix.rs:11:13 | LL | let _ = c.is_digit(16); | ^^^^^^^^^^^^^^ help: try: `c.is_ascii_hexdigit()` error: use of `char::is_digit` with literal radix of 16 - --> tests/ui/is_digit_ascii_radix.rs:11:13 + --> tests/ui/is_digit_ascii_radix.rs:13:13 | LL | let _ = c.is_digit(0x10); | ^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_hexdigit()` diff --git a/src/tools/clippy/tests/ui/issue-111399.rs b/src/tools/clippy/tests/ui/issue-111399.rs index b65e6c7261a57..2a6436b4b4eb5 100644 --- a/src/tools/clippy/tests/ui/issue-111399.rs +++ b/src/tools/clippy/tests/ui/issue-111399.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(inherent_associated_types)] #![allow(incomplete_features)] diff --git a/src/tools/clippy/tests/ui/issue-7447.rs b/src/tools/clippy/tests/ui/issue-7447.rs index 7e7ef209d4852..452011de1195e 100644 --- a/src/tools/clippy/tests/ui/issue-7447.rs +++ b/src/tools/clippy/tests/ui/issue-7447.rs @@ -24,8 +24,8 @@ pub struct ByteView<'a> { fn main() { byte_view(panic!()); - //~^ ERROR: sub-expression diverges - //~| NOTE: `-D clippy::diverging-sub-expression` implied by `-D warnings` + //~^ diverging_sub_expression + group_entries(panic!()); - //~^ ERROR: sub-expression diverges + //~^ diverging_sub_expression } diff --git a/src/tools/clippy/tests/ui/issue-7447.stderr b/src/tools/clippy/tests/ui/issue-7447.stderr index 5e28c1423840f..09a75c6b8d299 100644 --- a/src/tools/clippy/tests/ui/issue-7447.stderr +++ b/src/tools/clippy/tests/ui/issue-7447.stderr @@ -6,15 +6,12 @@ LL | byte_view(panic!()); | = note: `-D clippy::diverging-sub-expression` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::diverging_sub_expression)]` - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: sub-expression diverges --> tests/ui/issue-7447.rs:29:19 | LL | group_entries(panic!()); | ^^^^^^^^ - | - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/issue_2356.fixed b/src/tools/clippy/tests/ui/issue_2356.fixed index 892aa4e34216c..46ba653eba2cf 100644 --- a/src/tools/clippy/tests/ui/issue_2356.fixed +++ b/src/tools/clippy/tests/ui/issue_2356.fixed @@ -15,6 +15,7 @@ impl Foo { fn foo2>(mut it: I) { for e in it { + //~^ while_let_on_iterator println!("{:?}", e); } } diff --git a/src/tools/clippy/tests/ui/issue_2356.rs b/src/tools/clippy/tests/ui/issue_2356.rs index da0eead15b392..defe2584a93e1 100644 --- a/src/tools/clippy/tests/ui/issue_2356.rs +++ b/src/tools/clippy/tests/ui/issue_2356.rs @@ -15,6 +15,7 @@ impl Foo { fn foo2>(mut it: I) { while let Some(e) = it.next() { + //~^ while_let_on_iterator println!("{:?}", e); } } diff --git a/src/tools/clippy/tests/ui/issue_4266.rs b/src/tools/clippy/tests/ui/issue_4266.rs index 23453207b4e5e..664f0b84a2077 100644 --- a/src/tools/clippy/tests/ui/issue_4266.rs +++ b/src/tools/clippy/tests/ui/issue_4266.rs @@ -2,13 +2,14 @@ #![allow(clippy::uninlined_format_args)] async fn sink1<'a>(_: &'a str) {} // lint -//~^ ERROR: the following explicit lifetimes could be elided: 'a -//~| NOTE: `-D clippy::needless-lifetimes` implied by `-D warnings` +//~^ needless_lifetimes + async fn sink1_elided(_: &str) {} // ok // lint async fn one_to_one<'a>(s: &'a str) -> &'a str { - //~^ ERROR: the following explicit lifetimes could be elided: 'a + //~^ needless_lifetimes + s } @@ -29,7 +30,8 @@ struct Foo; impl Foo { // ok pub async fn new(&mut self) -> Self { - //~^ ERROR: methods called `new` usually take no `self` + //~^ wrong_self_convention + Foo {} } } diff --git a/src/tools/clippy/tests/ui/issue_4266.stderr b/src/tools/clippy/tests/ui/issue_4266.stderr index 63c568a153b2e..0e181025430f3 100644 --- a/src/tools/clippy/tests/ui/issue_4266.stderr +++ b/src/tools/clippy/tests/ui/issue_4266.stderr @@ -14,7 +14,7 @@ LL | async fn one_to_one<'a>(s: &'a str) -> &'a str { | ^^ ^^ ^^ error: methods called `new` usually take no `self` - --> tests/ui/issue_4266.rs:31:22 + --> tests/ui/issue_4266.rs:32:22 | LL | pub async fn new(&mut self) -> Self { | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/items_after_statement.rs b/src/tools/clippy/tests/ui/items_after_statement.rs index 943e7c1167605..b97c831f37ecc 100644 --- a/src/tools/clippy/tests/ui/items_after_statement.rs +++ b/src/tools/clippy/tests/ui/items_after_statement.rs @@ -11,8 +11,8 @@ fn ok() { fn last() { foo(); fn foo() { - //~^ ERROR: adding items after statements is confusing, since items exist from the sta - //~| NOTE: `-D clippy::items-after-statements` implied by `-D warnings` + //~^ items_after_statements + println!("foo"); } } @@ -20,7 +20,8 @@ fn last() { fn main() { foo(); fn foo() { - //~^ ERROR: adding items after statements is confusing, since items exist from the sta + //~^ items_after_statements + println!("foo"); } foo(); @@ -34,6 +35,7 @@ fn mac() { () => {{ a = 6; fn say_something() { + //~^ items_after_statements println!("something"); } }}; diff --git a/src/tools/clippy/tests/ui/items_after_statement.stderr b/src/tools/clippy/tests/ui/items_after_statement.stderr index 0f1989d4c9fc5..7a5ae2c8d47d2 100644 --- a/src/tools/clippy/tests/ui/items_after_statement.stderr +++ b/src/tools/clippy/tests/ui/items_after_statement.stderr @@ -16,14 +16,16 @@ error: adding items after statements is confusing, since items exist from the st | LL | / fn foo() { LL | | +LL | | LL | | println!("foo"); LL | | } | |_____^ error: adding items after statements is confusing, since items exist from the start of the scope - --> tests/ui/items_after_statement.rs:36:13 + --> tests/ui/items_after_statement.rs:37:13 | LL | / fn say_something() { +LL | | LL | | println!("something"); LL | | } | |_____________^ diff --git a/src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs b/src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs index d9c0aef88c8cf..54a04988cda0f 100644 --- a/src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs +++ b/src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build:../auxiliary/proc_macros.rs extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs index 6a757aef48e79..d756be5b433e7 100644 --- a/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs +++ b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs @@ -1,3 +1,4 @@ +//@ check-pass //@compile-flags: --test #![allow(unused)] #![warn(clippy::items_after_test_module)] diff --git a/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs b/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs index 7132e71764eb0..6ca100c07f968 100644 --- a/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs +++ b/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs @@ -1,3 +1,4 @@ +//@error-in-other-file: #[path = "auxiliary/submodule.rs"] mod submodule; diff --git a/src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs b/src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs index 8ab9e8200f18a..8618710654a52 100644 --- a/src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs +++ b/src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs @@ -1,3 +1,5 @@ +//@ check-pass + #[cfg(test)] mod tests { #[test] diff --git a/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed b/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed index d444100a76b92..f036b368a6676 100644 --- a/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed +++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed @@ -17,6 +17,7 @@ macro_rules! should_lint { #[allow(clippy::allow_attributes)] #[cfg(test)] mod tests { + //~^ items_after_test_module #[test] fn hi() {} } diff --git a/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs index 57da01639cca6..de0cbb120330e 100644 --- a/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs +++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs @@ -10,6 +10,7 @@ fn should_not_lint() {} #[allow(clippy::allow_attributes)] #[cfg(test)] mod tests { + //~^ items_after_test_module #[test] fn hi() {} } diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed index 1d623642a7133..e9fb44e89598e 100644 --- a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed +++ b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed @@ -6,11 +6,13 @@ use std::collections::{HashSet, VecDeque}; fn main() { let v = [1, 2, 3, 4, 5]; let v2: Vec = v.to_vec(); + //~^ iter_cloned_collect let v3: HashSet = v.iter().cloned().collect(); let v4: VecDeque = v.iter().cloned().collect(); // Handle macro expansion in suggestion let _: Vec = vec![1, 2, 3].to_vec(); + //~^ iter_cloned_collect // Issue #3704 unsafe { @@ -21,7 +23,9 @@ fn main() { // Issue #6808 let arr: [u8; 64] = [0; 64]; let _: Vec<_> = arr.to_vec(); + //~^ iter_cloned_collect // Issue #6703 let _: Vec = v.to_vec(); + //~^ iter_cloned_collect } diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.rs b/src/tools/clippy/tests/ui/iter_cloned_collect.rs index 091bd9eaf081e..c9b8abcc9a0d0 100644 --- a/src/tools/clippy/tests/ui/iter_cloned_collect.rs +++ b/src/tools/clippy/tests/ui/iter_cloned_collect.rs @@ -6,16 +6,19 @@ use std::collections::{HashSet, VecDeque}; fn main() { let v = [1, 2, 3, 4, 5]; let v2: Vec = v.iter().cloned().collect(); + //~^ iter_cloned_collect let v3: HashSet = v.iter().cloned().collect(); let v4: VecDeque = v.iter().cloned().collect(); // Handle macro expansion in suggestion let _: Vec = vec![1, 2, 3].iter().cloned().collect(); + //~^ iter_cloned_collect // Issue #3704 unsafe { let _: Vec = std::ffi::CStr::from_ptr(std::ptr::null()) .to_bytes() + //~^ iter_cloned_collect .iter() .cloned() .collect(); @@ -24,7 +27,9 @@ fn main() { // Issue #6808 let arr: [u8; 64] = [0; 64]; let _: Vec<_> = arr.iter().cloned().collect(); + //~^ iter_cloned_collect // Issue #6703 let _: Vec = v.iter().copied().collect(); + //~^ iter_cloned_collect } diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr index e8d82ec2c1b39..119698cb46343 100644 --- a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr +++ b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr @@ -8,29 +8,30 @@ LL | let v2: Vec = v.iter().cloned().collect(); = help: to override `-D warnings` add `#[allow(clippy::iter_cloned_collect)]` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> tests/ui/iter_cloned_collect.rs:13:38 + --> tests/ui/iter_cloned_collect.rs:14:38 | LL | let _: Vec = vec![1, 2, 3].iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> tests/ui/iter_cloned_collect.rs:18:24 + --> tests/ui/iter_cloned_collect.rs:20:24 | LL | .to_bytes() | ________________________^ +LL | | LL | | .iter() LL | | .cloned() LL | | .collect(); | |______________________^ help: try: `.to_vec()` error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> tests/ui/iter_cloned_collect.rs:26:24 + --> tests/ui/iter_cloned_collect.rs:29:24 | LL | let _: Vec<_> = arr.iter().cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` error: called `iter().copied().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable - --> tests/ui/iter_cloned_collect.rs:29:26 + --> tests/ui/iter_cloned_collect.rs:33:26 | LL | let _: Vec = v.iter().copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()` diff --git a/src/tools/clippy/tests/ui/iter_count.fixed b/src/tools/clippy/tests/ui/iter_count.fixed index 75c007bb0c997..2e187e5bfa754 100644 --- a/src/tools/clippy/tests/ui/iter_count.fixed +++ b/src/tools/clippy/tests/ui/iter_count.fixed @@ -52,32 +52,57 @@ fn main() { binary_heap.push(1); &vec[..].len(); + //~^ iter_count vec.len(); + //~^ iter_count boxed_slice.len(); + //~^ iter_count vec_deque.len(); + //~^ iter_count hash_set.len(); + //~^ iter_count hash_map.len(); + //~^ iter_count b_tree_map.len(); + //~^ iter_count b_tree_set.len(); + //~^ iter_count linked_list.len(); + //~^ iter_count binary_heap.len(); + //~^ iter_count vec.len(); + //~^ iter_count &vec[..].len(); + //~^ iter_count vec_deque.len(); + //~^ iter_count hash_map.len(); + //~^ iter_count b_tree_map.len(); + //~^ iter_count linked_list.len(); + //~^ iter_count &vec[..].len(); + //~^ iter_count vec.len(); + //~^ iter_count vec_deque.len(); + //~^ iter_count hash_set.len(); + //~^ iter_count hash_map.len(); + //~^ iter_count b_tree_map.len(); + //~^ iter_count b_tree_set.len(); + //~^ iter_count linked_list.len(); + //~^ iter_count binary_heap.len(); + //~^ iter_count // Make sure we don't lint for non-relevant types. let false_positive = HasIter; diff --git a/src/tools/clippy/tests/ui/iter_count.rs b/src/tools/clippy/tests/ui/iter_count.rs index cd8207b2c5dc8..e941892136ecb 100644 --- a/src/tools/clippy/tests/ui/iter_count.rs +++ b/src/tools/clippy/tests/ui/iter_count.rs @@ -52,32 +52,57 @@ fn main() { binary_heap.push(1); &vec[..].iter().count(); + //~^ iter_count vec.iter().count(); + //~^ iter_count boxed_slice.iter().count(); + //~^ iter_count vec_deque.iter().count(); + //~^ iter_count hash_set.iter().count(); + //~^ iter_count hash_map.iter().count(); + //~^ iter_count b_tree_map.iter().count(); + //~^ iter_count b_tree_set.iter().count(); + //~^ iter_count linked_list.iter().count(); + //~^ iter_count binary_heap.iter().count(); + //~^ iter_count vec.iter_mut().count(); + //~^ iter_count &vec[..].iter_mut().count(); + //~^ iter_count vec_deque.iter_mut().count(); + //~^ iter_count hash_map.iter_mut().count(); + //~^ iter_count b_tree_map.iter_mut().count(); + //~^ iter_count linked_list.iter_mut().count(); + //~^ iter_count &vec[..].into_iter().count(); + //~^ iter_count vec.into_iter().count(); + //~^ iter_count vec_deque.into_iter().count(); + //~^ iter_count hash_set.into_iter().count(); + //~^ iter_count hash_map.into_iter().count(); + //~^ iter_count b_tree_map.into_iter().count(); + //~^ iter_count b_tree_set.into_iter().count(); + //~^ iter_count linked_list.into_iter().count(); + //~^ iter_count binary_heap.into_iter().count(); + //~^ iter_count // Make sure we don't lint for non-relevant types. let false_positive = HasIter; diff --git a/src/tools/clippy/tests/ui/iter_count.stderr b/src/tools/clippy/tests/ui/iter_count.stderr index b703310731f34..a5ccefd9048d9 100644 --- a/src/tools/clippy/tests/ui/iter_count.stderr +++ b/src/tools/clippy/tests/ui/iter_count.stderr @@ -8,145 +8,145 @@ LL | &vec[..].iter().count(); = help: to override `-D warnings` add `#[allow(clippy::iter_count)]` error: called `.iter().count()` on a `Vec` - --> tests/ui/iter_count.rs:55:5 + --> tests/ui/iter_count.rs:56:5 | LL | vec.iter().count(); | ^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter().count()` on a `slice` - --> tests/ui/iter_count.rs:56:5 + --> tests/ui/iter_count.rs:58:5 | LL | boxed_slice.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `boxed_slice.len()` error: called `.iter().count()` on a `VecDeque` - --> tests/ui/iter_count.rs:57:5 + --> tests/ui/iter_count.rs:60:5 | LL | vec_deque.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.iter().count()` on a `HashSet` - --> tests/ui/iter_count.rs:58:5 + --> tests/ui/iter_count.rs:62:5 | LL | hash_set.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` error: called `.iter().count()` on a `HashMap` - --> tests/ui/iter_count.rs:59:5 + --> tests/ui/iter_count.rs:64:5 | LL | hash_map.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.iter().count()` on a `BTreeMap` - --> tests/ui/iter_count.rs:60:5 + --> tests/ui/iter_count.rs:66:5 | LL | b_tree_map.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.iter().count()` on a `BTreeSet` - --> tests/ui/iter_count.rs:61:5 + --> tests/ui/iter_count.rs:68:5 | LL | b_tree_set.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` error: called `.iter().count()` on a `LinkedList` - --> tests/ui/iter_count.rs:62:5 + --> tests/ui/iter_count.rs:70:5 | LL | linked_list.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.iter().count()` on a `BinaryHeap` - --> tests/ui/iter_count.rs:63:5 + --> tests/ui/iter_count.rs:72:5 | LL | binary_heap.iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` error: called `.iter_mut().count()` on a `Vec` - --> tests/ui/iter_count.rs:65:5 + --> tests/ui/iter_count.rs:75:5 | LL | vec.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.iter_mut().count()` on a `slice` - --> tests/ui/iter_count.rs:66:6 + --> tests/ui/iter_count.rs:77:6 | LL | &vec[..].iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.iter_mut().count()` on a `VecDeque` - --> tests/ui/iter_count.rs:67:5 + --> tests/ui/iter_count.rs:79:5 | LL | vec_deque.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.iter_mut().count()` on a `HashMap` - --> tests/ui/iter_count.rs:68:5 + --> tests/ui/iter_count.rs:81:5 | LL | hash_map.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.iter_mut().count()` on a `BTreeMap` - --> tests/ui/iter_count.rs:69:5 + --> tests/ui/iter_count.rs:83:5 | LL | b_tree_map.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.iter_mut().count()` on a `LinkedList` - --> tests/ui/iter_count.rs:70:5 + --> tests/ui/iter_count.rs:85:5 | LL | linked_list.iter_mut().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.into_iter().count()` on a `slice` - --> tests/ui/iter_count.rs:72:6 + --> tests/ui/iter_count.rs:88:6 | LL | &vec[..].into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec[..].len()` error: called `.into_iter().count()` on a `Vec` - --> tests/ui/iter_count.rs:73:5 + --> tests/ui/iter_count.rs:90:5 | LL | vec.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.len()` error: called `.into_iter().count()` on a `VecDeque` - --> tests/ui/iter_count.rs:74:5 + --> tests/ui/iter_count.rs:92:5 | LL | vec_deque.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec_deque.len()` error: called `.into_iter().count()` on a `HashSet` - --> tests/ui/iter_count.rs:75:5 + --> tests/ui/iter_count.rs:94:5 | LL | hash_set.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_set.len()` error: called `.into_iter().count()` on a `HashMap` - --> tests/ui/iter_count.rs:76:5 + --> tests/ui/iter_count.rs:96:5 | LL | hash_map.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `hash_map.len()` error: called `.into_iter().count()` on a `BTreeMap` - --> tests/ui/iter_count.rs:77:5 + --> tests/ui/iter_count.rs:98:5 | LL | b_tree_map.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_map.len()` error: called `.into_iter().count()` on a `BTreeSet` - --> tests/ui/iter_count.rs:78:5 + --> tests/ui/iter_count.rs:100:5 | LL | b_tree_set.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b_tree_set.len()` error: called `.into_iter().count()` on a `LinkedList` - --> tests/ui/iter_count.rs:79:5 + --> tests/ui/iter_count.rs:102:5 | LL | linked_list.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `linked_list.len()` error: called `.into_iter().count()` on a `BinaryHeap` - --> tests/ui/iter_count.rs:80:5 + --> tests/ui/iter_count.rs:104:5 | LL | binary_heap.into_iter().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `binary_heap.len()` diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed b/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed index 80db8b29c18ee..3223e19d23a78 100644 --- a/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed +++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.fixed @@ -9,51 +9,54 @@ fn main() { { let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok + let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok + #[rustfmt::skip] let _ = vec![Ok(1), Err(2)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } { let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok #[rustfmt::skip] let _ = vec![Ok(1), Err(2)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } { let _ = vec![Ok(1), Err(2), Ok(3)] .into_iter() .flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok let _ = vec![Ok(1), Err(2), Ok(3)] .into_iter() .flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok + #[rustfmt::skip] let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } { let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok #[rustfmt::skip] let _ = vec![Ok(1), Err(2)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } } diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.rs b/src/tools/clippy/tests/ui/iter_filter_is_ok.rs index 89b083b84f329..973653819850d 100644 --- a/src/tools/clippy/tests/ui/iter_filter_is_ok.rs +++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.rs @@ -9,51 +9,54 @@ fn main() { { let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok + let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok + #[rustfmt::skip] let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } { let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok #[rustfmt::skip] let _ = vec![Ok(1), Err(2)].into_iter().filter(|&o| { o.is_ok() }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } { let _ = vec![Ok(1), Err(2), Ok(3)] .into_iter() .filter(std::result::Result::is_ok); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok let _ = vec![Ok(1), Err(2), Ok(3)] .into_iter() .filter(|a| std::result::Result::is_ok(a)); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok + #[rustfmt::skip] let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| { std::result::Result::is_ok(a) }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } { let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok #[rustfmt::skip] let _ = vec![Ok(1), Err(2)].into_iter().filter(|ref o| { o.is_ok() }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_ok } } diff --git a/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr b/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr index 0aff60224e0e0..b7fd0d25cc235 100644 --- a/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr +++ b/src/tools/clippy/tests/ui/iter_filter_is_ok.stderr @@ -8,67 +8,67 @@ LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(Result::is_ok = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_ok)]` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:13:56 + --> tests/ui/iter_filter_is_ok.rs:14:56 | LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| a.is_ok()); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:16:49 + --> tests/ui/iter_filter_is_ok.rs:18:49 | LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|o| { o.is_ok() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:21:56 + --> tests/ui/iter_filter_is_ok.rs:23:56 | LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:24:56 + --> tests/ui/iter_filter_is_ok.rs:26:56 | LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|&a| a.is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:28:49 + --> tests/ui/iter_filter_is_ok.rs:30:49 | LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|&o| { o.is_ok() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:35:14 + --> tests/ui/iter_filter_is_ok.rs:37:14 | LL | .filter(std::result::Result::is_ok); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:40:14 + --> tests/ui/iter_filter_is_ok.rs:42:14 | LL | .filter(|a| std::result::Result::is_ok(a)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:43:56 + --> tests/ui/iter_filter_is_ok.rs:46:56 | LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|a| { std::result::Result::is_ok(a) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:48:56 + --> tests/ui/iter_filter_is_ok.rs:51:56 | LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:51:56 + --> tests/ui/iter_filter_is_ok.rs:54:56 | LL | let _ = vec![Ok(1), Err(2), Ok(3)].into_iter().filter(|ref a| a.is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_ok` on iterator over `Result`s - --> tests/ui/iter_filter_is_ok.rs:55:49 + --> tests/ui/iter_filter_is_ok.rs:58:49 | LL | let _ = vec![Ok(1), Err(2)].into_iter().filter(|ref o| { o.is_ok() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.fixed b/src/tools/clippy/tests/ui/iter_filter_is_some.fixed index 8a818c0c6728d..99e764e957fb0 100644 --- a/src/tools/clippy/tests/ui/iter_filter_is_some.fixed +++ b/src/tools/clippy/tests/ui/iter_filter_is_some.fixed @@ -13,45 +13,48 @@ use std::collections::HashMap; fn main() { { let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some + let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some + #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } { let _ = vec![Some(1), None, Some(3)] .into_iter() .flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some let _ = vec![Some(1), None, Some(3)] .into_iter() .flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some + #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } { let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } { let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().flatten(); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } } diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.rs b/src/tools/clippy/tests/ui/iter_filter_is_some.rs index 9eda93a259218..ecb7a04ab4dff 100644 --- a/src/tools/clippy/tests/ui/iter_filter_is_some.rs +++ b/src/tools/clippy/tests/ui/iter_filter_is_some.rs @@ -13,45 +13,48 @@ use std::collections::HashMap; fn main() { { let _ = vec![Some(1), None, Some(3)].into_iter().filter(Option::is_some); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some + let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| a.is_some()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some + #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| { o.is_some() }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } { let _ = vec![Some(1), None, Some(3)] .into_iter() .filter(std::option::Option::is_some); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some let _ = vec![Some(1), None, Some(3)] .into_iter() .filter(|a| std::option::Option::is_some(a)); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some + #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| { std::option::Option::is_some(a) }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } { let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&a| a.is_some()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&o| { o.is_some() }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } { let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref a| a.is_some()); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some #[rustfmt::skip] let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref o| { o.is_some() }); - //~^ HELP: consider using `flatten` instead + //~^ iter_filter_is_some } } diff --git a/src/tools/clippy/tests/ui/iter_filter_is_some.stderr b/src/tools/clippy/tests/ui/iter_filter_is_some.stderr index 54aff892b1f0f..cd01a3e05cd0d 100644 --- a/src/tools/clippy/tests/ui/iter_filter_is_some.stderr +++ b/src/tools/clippy/tests/ui/iter_filter_is_some.stderr @@ -8,55 +8,55 @@ LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(Option::is_ = help: to override `-D warnings` add `#[allow(clippy::iter_filter_is_some)]` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:17:58 + --> tests/ui/iter_filter_is_some.rs:18:58 | LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| a.is_some()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:20:58 + --> tests/ui/iter_filter_is_some.rs:22:58 | LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|o| { o.is_some() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:27:14 + --> tests/ui/iter_filter_is_some.rs:29:14 | LL | .filter(std::option::Option::is_some); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:32:14 + --> tests/ui/iter_filter_is_some.rs:34:14 | LL | .filter(|a| std::option::Option::is_some(a)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:35:58 + --> tests/ui/iter_filter_is_some.rs:38:58 | LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|a| { std::option::Option::is_some(a) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:40:58 + --> tests/ui/iter_filter_is_some.rs:43:58 | LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&a| a.is_some()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:44:58 + --> tests/ui/iter_filter_is_some.rs:47:58 | LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|&o| { o.is_some() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:49:58 + --> tests/ui/iter_filter_is_some.rs:52:58 | LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref a| a.is_some()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `is_some` on iterator over `Option` - --> tests/ui/iter_filter_is_some.rs:53:58 + --> tests/ui/iter_filter_is_some.rs:56:58 | LL | let _ = vec![Some(1), None, Some(3)].into_iter().filter(|ref o| { o.is_some() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed index 2cbf972fca5fb..7fcab6592e26c 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.fixed +++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed @@ -12,17 +12,26 @@ fn main() { let map: HashMap = HashMap::new(); let _ = map.keys().collect::>(); + //~^ iter_kv_map let _ = map.values().collect::>(); + //~^ iter_kv_map let _ = map.values().map(|v| v + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_keys().collect::>(); + //~^ iter_kv_map let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_values().collect::>(); + //~^ iter_kv_map let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().values().collect::>(); + //~^ iter_kv_map let _ = map.keys().filter(|x| *x % 2 == 0).count(); + //~^ iter_kv_map // Don't lint let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); @@ -33,13 +42,17 @@ fn main() { // Lint let _ = map.keys().map(|key| key * 9).count(); + //~^ iter_kv_map let _ = map.values().map(|value| value * 17).count(); + //~^ iter_kv_map // Preserve the ref in the fix. let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + //~^ iter_kv_map // Preserve the mut in the fix. let _ = map + //~^ iter_kv_map .clone().into_values().map(|mut val| { val += 2; val @@ -48,21 +61,31 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_values().count(); + //~^ iter_kv_map let map: BTreeMap = BTreeMap::new(); let _ = map.keys().collect::>(); + //~^ iter_kv_map let _ = map.values().collect::>(); + //~^ iter_kv_map let _ = map.values().map(|v| v + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_keys().collect::>(); + //~^ iter_kv_map let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_values().collect::>(); + //~^ iter_kv_map let _ = map.clone().into_values().map(|val| val + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().values().collect::>(); + //~^ iter_kv_map let _ = map.keys().filter(|x| *x % 2 == 0).count(); + //~^ iter_kv_map // Don't lint let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); @@ -73,13 +96,17 @@ fn main() { // Lint let _ = map.keys().map(|key| key * 9).count(); + //~^ iter_kv_map let _ = map.values().map(|value| value * 17).count(); + //~^ iter_kv_map // Preserve the ref in the fix. let _ = map.clone().into_values().map(|ref val| ref_acceptor(val)).count(); + //~^ iter_kv_map // Preserve the mut in the fix. let _ = map + //~^ iter_kv_map .clone().into_values().map(|mut val| { val += 2; val @@ -88,6 +115,7 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_values().count(); + //~^ iter_kv_map } #[clippy::msrv = "1.53"] @@ -103,11 +131,13 @@ fn msrv_1_53() { // Lint let _ = map.keys().collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map + let _ = map.values().collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map + let _ = map.values().map(|v| v + 2).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map } #[clippy::msrv = "1.54"] @@ -116,19 +146,23 @@ fn msrv_1_54() { let map: HashMap = HashMap::new(); let _ = map.clone().into_keys().collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map + let _ = map.clone().into_keys().map(|key| key + 2).collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map let _ = map.clone().into_values().collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map + let _ = map.clone().into_values().map(|val| val + 2).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map let _ = map.keys().collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map + let _ = map.values().collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map + let _ = map.values().map(|v| v + 2).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map } diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs index 6a9a4267a7657..b590aef7b8031 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.rs +++ b/src/tools/clippy/tests/ui/iter_kv_map.rs @@ -12,17 +12,26 @@ fn main() { let map: HashMap = HashMap::new(); let _ = map.iter().map(|(key, _)| key).collect::>(); + //~^ iter_kv_map let _ = map.iter().map(|(_, value)| value).collect::>(); + //~^ iter_kv_map let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + //~^ iter_kv_map let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + //~^ iter_kv_map // Don't lint let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); @@ -33,13 +42,17 @@ fn main() { // Lint let _ = map.iter().map(|(key, _value)| key * 9).count(); + //~^ iter_kv_map let _ = map.iter().map(|(_key, value)| value * 17).count(); + //~^ iter_kv_map // Preserve the ref in the fix. let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + //~^ iter_kv_map // Preserve the mut in the fix. let _ = map + //~^ iter_kv_map .clone() .into_iter() .map(|(_, mut val)| { @@ -50,21 +63,31 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + //~^ iter_kv_map let map: BTreeMap = BTreeMap::new(); let _ = map.iter().map(|(key, _)| key).collect::>(); + //~^ iter_kv_map let _ = map.iter().map(|(_, value)| value).collect::>(); + //~^ iter_kv_map let _ = map.iter().map(|(_, v)| v + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); + //~^ iter_kv_map let _ = map.clone().iter().map(|(_, val)| val).collect::>(); + //~^ iter_kv_map let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); + //~^ iter_kv_map // Don't lint let _ = map.iter().filter(|(_, val)| *val % 2 == 0).map(|(key, _)| key).count(); @@ -75,13 +98,17 @@ fn main() { // Lint let _ = map.iter().map(|(key, _value)| key * 9).count(); + //~^ iter_kv_map let _ = map.iter().map(|(_key, value)| value * 17).count(); + //~^ iter_kv_map // Preserve the ref in the fix. let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); + //~^ iter_kv_map // Preserve the mut in the fix. let _ = map + //~^ iter_kv_map .clone() .into_iter() .map(|(_, mut val)| { @@ -92,6 +119,7 @@ fn main() { // Don't let a mut interfere. let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); + //~^ iter_kv_map } #[clippy::msrv = "1.53"] @@ -107,11 +135,13 @@ fn msrv_1_53() { // Lint let _ = map.iter().map(|(key, _)| key).collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map + let _ = map.iter().map(|(_, value)| value).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map } #[clippy::msrv = "1.54"] @@ -120,19 +150,23 @@ fn msrv_1_54() { let map: HashMap = HashMap::new(); let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map + let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map + let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map let _ = map.iter().map(|(key, _)| key).collect::>(); - //~^ ERROR: iterating on a map's keys + //~^ iter_kv_map + let _ = map.iter().map(|(_, value)| value).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map + let _ = map.iter().map(|(_, v)| v + 2).collect::>(); - //~^ ERROR: iterating on a map's values + //~^ iter_kv_map } diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr index ad23dba55cb6a..00d566ed14a28 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.stderr +++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr @@ -8,80 +8,80 @@ LL | let _ = map.iter().map(|(key, _)| key).collect::>(); = help: to override `-D warnings` add `#[allow(clippy::iter_kv_map)]` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:15:13 + --> tests/ui/iter_kv_map.rs:16:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:16:13 + --> tests/ui/iter_kv_map.rs:18:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:18:13 + --> tests/ui/iter_kv_map.rs:21:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:19:13 + --> tests/ui/iter_kv_map.rs:23:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:21:13 + --> tests/ui/iter_kv_map.rs:26:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:22:13 + --> tests/ui/iter_kv_map.rs:28:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:24:13 + --> tests/ui/iter_kv_map.rs:31:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:25:13 + --> tests/ui/iter_kv_map.rs:33:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:35:13 + --> tests/ui/iter_kv_map.rs:44:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:36:13 + --> tests/ui/iter_kv_map.rs:46:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:39:13 + --> tests/ui/iter_kv_map.rs:50:13 | LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:42:13 + --> tests/ui/iter_kv_map.rs:54:13 | LL | let _ = map | _____________^ +LL | | LL | | .clone() LL | | .into_iter() -LL | | .map(|(_, mut val)| { -LL | | val += 2; +... | LL | | val LL | | }) | |__________^ @@ -89,6 +89,7 @@ LL | | }) help: try | LL ~ let _ = map +LL + LL + .clone().into_values().map(|mut val| { LL + val += 2; LL + val @@ -96,92 +97,92 @@ LL + }) | error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:52:13 + --> tests/ui/iter_kv_map.rs:65:13 | LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:56:13 + --> tests/ui/iter_kv_map.rs:70:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:57:13 + --> tests/ui/iter_kv_map.rs:72:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:58:13 + --> tests/ui/iter_kv_map.rs:74:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:60:13 + --> tests/ui/iter_kv_map.rs:77:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:61:13 + --> tests/ui/iter_kv_map.rs:79:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:63:13 + --> tests/ui/iter_kv_map.rs:82:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:64:13 + --> tests/ui/iter_kv_map.rs:84:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:66:13 + --> tests/ui/iter_kv_map.rs:87:13 | LL | let _ = map.clone().iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:67:13 + --> tests/ui/iter_kv_map.rs:89:13 | LL | let _ = map.iter().map(|(key, _)| key).filter(|x| *x % 2 == 0).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:77:13 + --> tests/ui/iter_kv_map.rs:100:13 | LL | let _ = map.iter().map(|(key, _value)| key * 9).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys().map(|key| key * 9)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:78:13 + --> tests/ui/iter_kv_map.rs:102:13 | LL | let _ = map.iter().map(|(_key, value)| value * 17).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|value| value * 17)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:81:13 + --> tests/ui/iter_kv_map.rs:106:13 | LL | let _ = map.clone().into_iter().map(|(_, ref val)| ref_acceptor(val)).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|ref val| ref_acceptor(val))` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:84:13 + --> tests/ui/iter_kv_map.rs:110:13 | LL | let _ = map | _____________^ +LL | | LL | | .clone() LL | | .into_iter() -LL | | .map(|(_, mut val)| { -LL | | val += 2; +... | LL | | val LL | | }) | |__________^ @@ -189,6 +190,7 @@ LL | | }) help: try | LL ~ let _ = map +LL + LL + .clone().into_values().map(|mut val| { LL + val += 2; LL + val @@ -196,67 +198,67 @@ LL + }) | error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:94:13 + --> tests/ui/iter_kv_map.rs:121:13 | LL | let _ = map.clone().into_iter().map(|(_, mut val)| val).count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:109:13 + --> tests/ui/iter_kv_map.rs:137:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:111:13 + --> tests/ui/iter_kv_map.rs:140:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:113:13 + --> tests/ui/iter_kv_map.rs:143:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:122:13 + --> tests/ui/iter_kv_map.rs:152:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys()` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:124:13 + --> tests/ui/iter_kv_map.rs:155:13 | LL | let _ = map.clone().into_iter().map(|(key, _)| key + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_keys().map(|key| key + 2)` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:127:13 + --> tests/ui/iter_kv_map.rs:158:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:129:13 + --> tests/ui/iter_kv_map.rs:161:13 | LL | let _ = map.clone().into_iter().map(|(_, val)| val + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.clone().into_values().map(|val| val + 2)` error: iterating on a map's keys - --> tests/ui/iter_kv_map.rs:132:13 + --> tests/ui/iter_kv_map.rs:164:13 | LL | let _ = map.iter().map(|(key, _)| key).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.keys()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:134:13 + --> tests/ui/iter_kv_map.rs:167:13 | LL | let _ = map.iter().map(|(_, value)| value).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values()` error: iterating on a map's values - --> tests/ui/iter_kv_map.rs:136:13 + --> tests/ui/iter_kv_map.rs:170:13 | LL | let _ = map.iter().map(|(_, v)| v + 2).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)` diff --git a/src/tools/clippy/tests/ui/iter_next_loop.rs b/src/tools/clippy/tests/ui/iter_next_loop.rs index d425f4da0e81d..32711c7ef6239 100644 --- a/src/tools/clippy/tests/ui/iter_next_loop.rs +++ b/src/tools/clippy/tests/ui/iter_next_loop.rs @@ -4,6 +4,7 @@ fn main() { let x = [1, 2, 3, 4]; for _ in x.iter().next() {} + //~^ iter_next_loop struct Unrelated(&'static [u8]); impl Unrelated { diff --git a/src/tools/clippy/tests/ui/iter_next_slice.fixed b/src/tools/clippy/tests/ui/iter_next_slice.fixed index 83be12c4e2549..2e7b4e632840e 100644 --- a/src/tools/clippy/tests/ui/iter_next_slice.fixed +++ b/src/tools/clippy/tests/ui/iter_next_slice.fixed @@ -7,15 +7,19 @@ fn main() { let v = vec![1, 2, 3]; let _ = s.first(); + //~^ iter_next_slice // Should be replaced by s.first() let _ = s.get(2); + //~^ iter_next_slice // Should be replaced by s.get(2) let _ = v.get(5); + //~^ iter_next_slice // Should be replaced by v.get(5) let _ = v.first(); + //~^ iter_next_slice // Should be replaced by v.first() let o = Some(5); diff --git a/src/tools/clippy/tests/ui/iter_next_slice.rs b/src/tools/clippy/tests/ui/iter_next_slice.rs index 1b257514d23ec..b2e047f5d8172 100644 --- a/src/tools/clippy/tests/ui/iter_next_slice.rs +++ b/src/tools/clippy/tests/ui/iter_next_slice.rs @@ -7,15 +7,19 @@ fn main() { let v = vec![1, 2, 3]; let _ = s.iter().next(); + //~^ iter_next_slice // Should be replaced by s.first() let _ = s[2..].iter().next(); + //~^ iter_next_slice // Should be replaced by s.get(2) let _ = v[5..].iter().next(); + //~^ iter_next_slice // Should be replaced by v.get(5) let _ = v.iter().next(); + //~^ iter_next_slice // Should be replaced by v.first() let o = Some(5); diff --git a/src/tools/clippy/tests/ui/iter_next_slice.stderr b/src/tools/clippy/tests/ui/iter_next_slice.stderr index 55cce2b9103da..0a22ab7f6a153 100644 --- a/src/tools/clippy/tests/ui/iter_next_slice.stderr +++ b/src/tools/clippy/tests/ui/iter_next_slice.stderr @@ -8,19 +8,19 @@ LL | let _ = s.iter().next(); = help: to override `-D warnings` add `#[allow(clippy::iter_next_slice)]` error: using `.iter().next()` on a Slice without end index - --> tests/ui/iter_next_slice.rs:12:13 + --> tests/ui/iter_next_slice.rs:13:13 | LL | let _ = s[2..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `s.get(2)` error: using `.iter().next()` on a Slice without end index - --> tests/ui/iter_next_slice.rs:15:13 + --> tests/ui/iter_next_slice.rs:17:13 | LL | let _ = v[5..].iter().next(); | ^^^^^^^^^^^^^^^^^^^^ help: try calling: `v.get(5)` error: using `.iter().next()` on an array - --> tests/ui/iter_next_slice.rs:18:13 + --> tests/ui/iter_next_slice.rs:21:13 | LL | let _ = v.iter().next(); | ^^^^^^^^^^^^^^^ help: try calling: `v.first()` diff --git a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs index e694bc7ac62fb..5c8c8eb4a43d4 100644 --- a/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs +++ b/src/tools/clippy/tests/ui/iter_not_returning_iterator.rs @@ -28,13 +28,14 @@ struct Counter2 { impl Data2 { fn iter(&self) -> Counter2 { - //~^ ERROR: this method is named `iter` but its return type does not implement `Iterat - //~| NOTE: `-D clippy::iter-not-returning-iterator` implied by `-D warnings` + //~^ iter_not_returning_iterator + todo!() } fn iter_mut(&self) -> Counter2 { - //~^ ERROR: this method is named `iter_mut` but its return type does not implement `It + //~^ iter_not_returning_iterator + todo!() } } @@ -51,7 +52,7 @@ impl Iterator for Counter { trait Iter { type I; fn iter(&self) -> Self::I; - //~^ ERROR: this method is named `iter` but its return type does not implement `Iterat + //~^ iter_not_returning_iterator } impl Iter for () { diff --git a/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr b/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr index c3ee8bae772d5..74ee8325d53e1 100644 --- a/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr +++ b/src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr @@ -14,7 +14,7 @@ LL | fn iter_mut(&self) -> Counter2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this method is named `iter` but its return type does not implement `Iterator` - --> tests/ui/iter_not_returning_iterator.rs:53:5 + --> tests/ui/iter_not_returning_iterator.rs:54:5 | LL | fn iter(&self) -> Self::I; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/iter_nth.fixed b/src/tools/clippy/tests/ui/iter_nth.fixed index aff3731a88372..5650903a5dcbb 100644 --- a/src/tools/clippy/tests/ui/iter_nth.fixed +++ b/src/tools/clippy/tests/ui/iter_nth.fixed @@ -32,24 +32,32 @@ fn iter_nth() { { // Make sure we lint `.iter()` for relevant types. let bad_vec = some_vec.get(3); + //~^ iter_nth let bad_slice = &some_vec[..].get(3); + //~^ iter_nth let bad_boxed_slice = boxed_slice.get(3); + //~^ iter_nth let bad_vec_deque = some_vec_deque.get(3); + //~^ iter_nth } { // Make sure we lint `.iter_mut()` for relevant types. let bad_vec = some_vec.get_mut(3); + //~^ iter_nth } { let bad_slice = &some_vec[..].get_mut(3); + //~^ iter_nth } { let bad_vec_deque = some_vec_deque.get_mut(3); + //~^ iter_nth } let vec_ref = &Vec::::new(); vec_ref.get(3); + //~^ iter_nth // Make sure we don't lint for non-relevant types. let false_positive = HasIter; diff --git a/src/tools/clippy/tests/ui/iter_nth.rs b/src/tools/clippy/tests/ui/iter_nth.rs index 89d68044dddac..cfd0629420e15 100644 --- a/src/tools/clippy/tests/ui/iter_nth.rs +++ b/src/tools/clippy/tests/ui/iter_nth.rs @@ -32,24 +32,32 @@ fn iter_nth() { { // Make sure we lint `.iter()` for relevant types. let bad_vec = some_vec.iter().nth(3); + //~^ iter_nth let bad_slice = &some_vec[..].iter().nth(3); + //~^ iter_nth let bad_boxed_slice = boxed_slice.iter().nth(3); + //~^ iter_nth let bad_vec_deque = some_vec_deque.iter().nth(3); + //~^ iter_nth } { // Make sure we lint `.iter_mut()` for relevant types. let bad_vec = some_vec.iter_mut().nth(3); + //~^ iter_nth } { let bad_slice = &some_vec[..].iter_mut().nth(3); + //~^ iter_nth } { let bad_vec_deque = some_vec_deque.iter_mut().nth(3); + //~^ iter_nth } let vec_ref = &Vec::::new(); vec_ref.iter().nth(3); + //~^ iter_nth // Make sure we don't lint for non-relevant types. let false_positive = HasIter; diff --git a/src/tools/clippy/tests/ui/iter_nth.stderr b/src/tools/clippy/tests/ui/iter_nth.stderr index 1167a604ecdcb..76ddfd9684e27 100644 --- a/src/tools/clippy/tests/ui/iter_nth.stderr +++ b/src/tools/clippy/tests/ui/iter_nth.stderr @@ -13,7 +13,7 @@ LL + let bad_vec = some_vec.get(3); | error: called `.iter().nth()` on a slice - --> tests/ui/iter_nth.rs:35:26 + --> tests/ui/iter_nth.rs:36:26 | LL | let bad_slice = &some_vec[..].iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let bad_slice = &some_vec[..].get(3); | error: called `.iter().nth()` on a slice - --> tests/ui/iter_nth.rs:36:31 + --> tests/ui/iter_nth.rs:38:31 | LL | let bad_boxed_slice = boxed_slice.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let bad_boxed_slice = boxed_slice.get(3); | error: called `.iter().nth()` on a `VecDeque` - --> tests/ui/iter_nth.rs:37:29 + --> tests/ui/iter_nth.rs:40:29 | LL | let bad_vec_deque = some_vec_deque.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + let bad_vec_deque = some_vec_deque.get(3); | error: called `.iter_mut().nth()` on a `Vec` - --> tests/ui/iter_nth.rs:42:23 + --> tests/ui/iter_nth.rs:46:23 | LL | let bad_vec = some_vec.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let bad_vec = some_vec.get_mut(3); | error: called `.iter_mut().nth()` on a slice - --> tests/ui/iter_nth.rs:45:26 + --> tests/ui/iter_nth.rs:50:26 | LL | let bad_slice = &some_vec[..].iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + let bad_slice = &some_vec[..].get_mut(3); | error: called `.iter_mut().nth()` on a `VecDeque` - --> tests/ui/iter_nth.rs:48:29 + --> tests/ui/iter_nth.rs:54:29 | LL | let bad_vec_deque = some_vec_deque.iter_mut().nth(3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + let bad_vec_deque = some_vec_deque.get_mut(3); | error: called `.iter().nth()` on a `Vec` - --> tests/ui/iter_nth.rs:52:5 + --> tests/ui/iter_nth.rs:59:5 | LL | vec_ref.iter().nth(3); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.fixed b/src/tools/clippy/tests/ui/iter_nth_zero.fixed index a3cdb2e59bff2..07153db90c196 100644 --- a/src/tools/clippy/tests/ui/iter_nth_zero.fixed +++ b/src/tools/clippy/tests/ui/iter_nth_zero.fixed @@ -16,16 +16,19 @@ fn main() { let mut s = HashSet::new(); s.insert(1); let _x = s.iter().next(); + //~^ iter_nth_zero let mut s2 = HashSet::new(); s2.insert(2); let mut iter = s2.iter(); let _y = iter.next(); + //~^ iter_nth_zero let mut s3 = HashSet::new(); s3.insert(3); let mut iter2 = s3.iter(); let _unwrapped = iter2.next().unwrap(); + //~^ iter_nth_zero } struct Issue9820; diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.rs b/src/tools/clippy/tests/ui/iter_nth_zero.rs index 64229b5128a39..45d008cd70408 100644 --- a/src/tools/clippy/tests/ui/iter_nth_zero.rs +++ b/src/tools/clippy/tests/ui/iter_nth_zero.rs @@ -16,16 +16,19 @@ fn main() { let mut s = HashSet::new(); s.insert(1); let _x = s.iter().nth(0); + //~^ iter_nth_zero let mut s2 = HashSet::new(); s2.insert(2); let mut iter = s2.iter(); let _y = iter.nth(0); + //~^ iter_nth_zero let mut s3 = HashSet::new(); s3.insert(3); let mut iter2 = s3.iter(); let _unwrapped = iter2.nth(0).unwrap(); + //~^ iter_nth_zero } struct Issue9820; diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.stderr b/src/tools/clippy/tests/ui/iter_nth_zero.stderr index b5e5cf45c26bf..edd44838b7ec5 100644 --- a/src/tools/clippy/tests/ui/iter_nth_zero.stderr +++ b/src/tools/clippy/tests/ui/iter_nth_zero.stderr @@ -8,13 +8,13 @@ LL | let _x = s.iter().nth(0); = help: to override `-D warnings` add `#[allow(clippy::iter_nth_zero)]` error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent - --> tests/ui/iter_nth_zero.rs:23:14 + --> tests/ui/iter_nth_zero.rs:24:14 | LL | let _y = iter.nth(0); | ^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `iter.next()` error: called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent - --> tests/ui/iter_nth_zero.rs:28:22 + --> tests/ui/iter_nth_zero.rs:30:22 | LL | let _unwrapped = iter2.nth(0).unwrap(); | ^^^^^^^^^^^^ help: try calling `.next()` instead of `.nth(0)`: `iter2.next()` diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed index 0f28b48d9ab8b..0c2100034e184 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed @@ -3,11 +3,17 @@ fn array() { assert_eq!(std::iter::empty().next(), Option::::None); + //~^ iter_on_empty_collections assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + //~^ iter_on_empty_collections assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + //~^ iter_on_empty_collections assert_eq!(std::iter::empty().next(), Option::::None); + //~^ iter_on_empty_collections assert_eq!(std::iter::empty().next(), Option::<&mut i32>::None); + //~^ iter_on_empty_collections assert_eq!(std::iter::empty().next(), Option::<&i32>::None); + //~^ iter_on_empty_collections // Don't trigger on non-iter methods let _: Option = None.clone(); @@ -26,6 +32,7 @@ fn array() { // Don't trigger when the empty collection iter is relied upon for its concrete type // But do trigger if it is just an iterator, despite being an argument to a method for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain(std::iter::empty()) { + //~^ iter_on_empty_collections println!("{i}"); } diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs index 702da514df7d2..0fb7a32d3691f 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs @@ -3,11 +3,17 @@ fn array() { assert_eq!([].into_iter().next(), Option::::None); + //~^ iter_on_empty_collections assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); + //~^ iter_on_empty_collections assert_eq!([].iter().next(), Option::<&i32>::None); + //~^ iter_on_empty_collections assert_eq!(None.into_iter().next(), Option::::None); + //~^ iter_on_empty_collections assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); + //~^ iter_on_empty_collections assert_eq!(None.iter().next(), Option::<&i32>::None); + //~^ iter_on_empty_collections // Don't trigger on non-iter methods let _: Option = None.clone(); @@ -26,6 +32,7 @@ fn array() { // Don't trigger when the empty collection iter is relied upon for its concrete type // But do trigger if it is just an iterator, despite being an argument to a method for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain([].iter()) { + //~^ iter_on_empty_collections println!("{i}"); } diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr b/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr index da9caa6925bd9..2803999cc7359 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.stderr @@ -8,37 +8,37 @@ LL | assert_eq!([].into_iter().next(), Option::::None); = help: to override `-D warnings` add `#[allow(clippy::iter_on_empty_collections)]` error: `iter_mut` call on an empty collection - --> tests/ui/iter_on_empty_collections.rs:6:16 + --> tests/ui/iter_on_empty_collections.rs:7:16 | LL | assert_eq!([].iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter` call on an empty collection - --> tests/ui/iter_on_empty_collections.rs:7:16 + --> tests/ui/iter_on_empty_collections.rs:9:16 | LL | assert_eq!([].iter().next(), Option::<&i32>::None); | ^^^^^^^^^ help: try: `std::iter::empty()` error: `into_iter` call on an empty collection - --> tests/ui/iter_on_empty_collections.rs:8:16 + --> tests/ui/iter_on_empty_collections.rs:11:16 | LL | assert_eq!(None.into_iter().next(), Option::::None); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter_mut` call on an empty collection - --> tests/ui/iter_on_empty_collections.rs:9:16 + --> tests/ui/iter_on_empty_collections.rs:13:16 | LL | assert_eq!(None.iter_mut().next(), Option::<&mut i32>::None); | ^^^^^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter` call on an empty collection - --> tests/ui/iter_on_empty_collections.rs:10:16 + --> tests/ui/iter_on_empty_collections.rs:15:16 | LL | assert_eq!(None.iter().next(), Option::<&i32>::None); | ^^^^^^^^^^^ help: try: `std::iter::empty()` error: `iter` call on an empty collection - --> tests/ui/iter_on_empty_collections.rs:28:66 + --> tests/ui/iter_on_empty_collections.rs:34:66 | LL | for i in smth.as_ref().map_or([].iter(), |s| s.iter()).chain([].iter()) { | ^^^^^^^^^ help: try: `std::iter::empty()` diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.fixed b/src/tools/clippy/tests/ui/iter_on_single_items.fixed index 117ec8429c375..b43fad6449c18 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.fixed +++ b/src/tools/clippy/tests/ui/iter_on_single_items.fixed @@ -3,11 +3,17 @@ fn array() { assert_eq!(std::iter::once(123).next(), Some(123)); + //~^ iter_on_single_items assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + //~^ iter_on_single_items assert_eq!(std::iter::once(&123).next(), Some(&123)); + //~^ iter_on_single_items assert_eq!(std::iter::once(123).next(), Some(123)); + //~^ iter_on_single_items assert_eq!(std::iter::once(&mut 123).next(), Some(&mut 123)); + //~^ iter_on_single_items assert_eq!(std::iter::once(&123).next(), Some(&123)); + //~^ iter_on_single_items // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.rs b/src/tools/clippy/tests/ui/iter_on_single_items.rs index d059370d996c1..625c96d3ef1f2 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.rs +++ b/src/tools/clippy/tests/ui/iter_on_single_items.rs @@ -3,11 +3,17 @@ fn array() { assert_eq!([123].into_iter().next(), Some(123)); + //~^ iter_on_single_items assert_eq!([123].iter_mut().next(), Some(&mut 123)); + //~^ iter_on_single_items assert_eq!([123].iter().next(), Some(&123)); + //~^ iter_on_single_items assert_eq!(Some(123).into_iter().next(), Some(123)); + //~^ iter_on_single_items assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); + //~^ iter_on_single_items assert_eq!(Some(123).iter().next(), Some(&123)); + //~^ iter_on_single_items // Don't trigger on non-iter methods let _: Option = Some("test".to_string()).clone(); diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.stderr b/src/tools/clippy/tests/ui/iter_on_single_items.stderr index 0252c859581b6..536e9eb36d88a 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.stderr +++ b/src/tools/clippy/tests/ui/iter_on_single_items.stderr @@ -8,31 +8,31 @@ LL | assert_eq!([123].into_iter().next(), Some(123)); = help: to override `-D warnings` add `#[allow(clippy::iter_on_single_items)]` error: `iter_mut` call on a collection with only one item - --> tests/ui/iter_on_single_items.rs:6:16 + --> tests/ui/iter_on_single_items.rs:7:16 | LL | assert_eq!([123].iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` error: `iter` call on a collection with only one item - --> tests/ui/iter_on_single_items.rs:7:16 + --> tests/ui/iter_on_single_items.rs:9:16 | LL | assert_eq!([123].iter().next(), Some(&123)); | ^^^^^^^^^^^^ help: try: `std::iter::once(&123)` error: `into_iter` call on a collection with only one item - --> tests/ui/iter_on_single_items.rs:8:16 + --> tests/ui/iter_on_single_items.rs:11:16 | LL | assert_eq!(Some(123).into_iter().next(), Some(123)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(123)` error: `iter_mut` call on a collection with only one item - --> tests/ui/iter_on_single_items.rs:9:16 + --> tests/ui/iter_on_single_items.rs:13:16 | LL | assert_eq!(Some(123).iter_mut().next(), Some(&mut 123)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&mut 123)` error: `iter` call on a collection with only one item - --> tests/ui/iter_on_single_items.rs:10:16 + --> tests/ui/iter_on_single_items.rs:15:16 | LL | assert_eq!(Some(123).iter().next(), Some(&123)); | ^^^^^^^^^^^^^^^^ help: try: `std::iter::once(&123)` diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.rs b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs index 3cfe6e82fc1e3..b34e4ad782409 100644 --- a/src/tools/clippy/tests/ui/iter_out_of_bounds.rs +++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.rs @@ -10,57 +10,60 @@ fn opaque_empty_iter() -> impl Iterator { fn main() { #[allow(clippy::never_loop)] for _ in [1, 2, 3].iter().skip(4) { - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds + unreachable!(); } for (i, _) in [1, 2, 3].iter().take(4).enumerate() { - //~^ ERROR: this `.take()` call takes more items than the iterator will produce + //~^ iter_out_of_bounds + assert!(i <= 2); } #[allow(clippy::needless_borrow)] for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} - //~^ ERROR: this `.take()` call takes more items than the iterator will produce + //~^ iter_out_of_bounds for _ in [1, 2, 3].iter().skip(4) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds for _ in [1; 3].iter().skip(4) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds // Should not lint for _ in opaque_empty_iter().skip(1) {} for _ in vec![1, 2, 3].iter().skip(4) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds for _ in vec![1; 3].iter().skip(4) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds let x = [1, 2, 3]; for _ in x.iter().skip(4) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds let n = 4; for _ in x.iter().skip(n) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds let empty = std::iter::empty::; for _ in empty().skip(1) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds for _ in empty().take(1) {} - //~^ ERROR: this `.take()` call takes more items than the iterator will produce + //~^ iter_out_of_bounds for _ in std::iter::once(1).skip(2) {} - //~^ ERROR: this `.skip()` call skips more items than the iterator will produce + //~^ iter_out_of_bounds for _ in std::iter::once(1).take(2) {} - //~^ ERROR: this `.take()` call takes more items than the iterator will produce + //~^ iter_out_of_bounds for x in [].iter().take(1) { - //~^ ERROR: this `.take()` call takes more items than the iterator will produce + //~^ iter_out_of_bounds + let _: &i32 = x; } diff --git a/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr index 96df04251fc9e..19ac60b9d0ac0 100644 --- a/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr +++ b/src/tools/clippy/tests/ui/iter_out_of_bounds.stderr @@ -12,7 +12,7 @@ LL | #![deny(clippy::iter_out_of_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:16:19 + --> tests/ui/iter_out_of_bounds.rs:17:19 | LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | for (i, _) in [1, 2, 3].iter().take(4).enumerate() { = note: this operation is useless and the returned iterator will simply yield the same items error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:22:14 + --> tests/ui/iter_out_of_bounds.rs:24:14 | LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | for _ in (&&&&&&[1, 2, 3]).iter().take(4) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:25:14 + --> tests/ui/iter_out_of_bounds.rs:27:14 | LL | for _ in [1, 2, 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | for _ in [1, 2, 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:28:14 + --> tests/ui/iter_out_of_bounds.rs:30:14 | LL | for _ in [1; 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | for _ in [1; 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:34:14 + --> tests/ui/iter_out_of_bounds.rs:36:14 | LL | for _ in vec![1, 2, 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | for _ in vec![1, 2, 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:37:14 + --> tests/ui/iter_out_of_bounds.rs:39:14 | LL | for _ in vec![1; 3].iter().skip(4) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | for _ in vec![1; 3].iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:41:14 + --> tests/ui/iter_out_of_bounds.rs:43:14 | LL | for _ in x.iter().skip(4) {} | ^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | for _ in x.iter().skip(4) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:45:14 + --> tests/ui/iter_out_of_bounds.rs:47:14 | LL | for _ in x.iter().skip(n) {} | ^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL | for _ in x.iter().skip(n) {} = note: this operation is useless and will create an empty iterator error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:50:14 + --> tests/ui/iter_out_of_bounds.rs:52:14 | LL | for _ in empty().skip(1) {} | ^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | for _ in empty().skip(1) {} = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:53:14 + --> tests/ui/iter_out_of_bounds.rs:55:14 | LL | for _ in empty().take(1) {} | ^^^^^^^^^^^^^^^ @@ -92,7 +92,7 @@ LL | for _ in empty().take(1) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.skip()` call skips more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:56:14 + --> tests/ui/iter_out_of_bounds.rs:58:14 | LL | for _ in std::iter::once(1).skip(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | for _ in std::iter::once(1).skip(2) {} = note: this operation is useless and will create an empty iterator error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:59:14 + --> tests/ui/iter_out_of_bounds.rs:61:14 | LL | for _ in std::iter::once(1).take(2) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | for _ in std::iter::once(1).take(2) {} = note: this operation is useless and the returned iterator will simply yield the same items error: this `.take()` call takes more items than the iterator will produce - --> tests/ui/iter_out_of_bounds.rs:62:14 + --> tests/ui/iter_out_of_bounds.rs:64:14 | LL | for x in [].iter().take(1) { | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/iter_over_hash_type.rs b/src/tools/clippy/tests/ui/iter_over_hash_type.rs index 65bae1df42188..914cc9df0de99 100644 --- a/src/tools/clippy/tests/ui/iter_over_hash_type.rs +++ b/src/tools/clippy/tests/ui/iter_over_hash_type.rs @@ -16,46 +16,59 @@ fn main() { // test hashset for x in &hash_set { + //~^ iter_over_hash_type let _ = x; } for x in hash_set.iter() { + //~^ iter_over_hash_type let _ = x; } for x in hash_set.clone() { + //~^ iter_over_hash_type let _ = x; } for x in hash_set.drain() { + //~^ iter_over_hash_type let _ = x; } // test hashmap for (x, y) in &hash_map { + //~^ iter_over_hash_type let _ = (x, y); } for x in hash_map.keys() { + //~^ iter_over_hash_type let _ = x; } for x in hash_map.values() { + //~^ iter_over_hash_type let _ = x; } for x in hash_map.values_mut() { + //~^ iter_over_hash_type *x += 1; } for x in hash_map.iter() { + //~^ iter_over_hash_type let _ = x; } for x in hash_map.clone() { + //~^ iter_over_hash_type let _ = x; } for x in hash_map.drain() { + //~^ iter_over_hash_type let _ = x; } // test type-aliased hashers for x in fx_hash_set { + //~^ iter_over_hash_type let _ = x; } for x in fx_hash_map { + //~^ iter_over_hash_type let _ = x; } diff --git a/src/tools/clippy/tests/ui/iter_over_hash_type.stderr b/src/tools/clippy/tests/ui/iter_over_hash_type.stderr index 6afe69ee20e1d..1bc6f4588d44b 100644 --- a/src/tools/clippy/tests/ui/iter_over_hash_type.stderr +++ b/src/tools/clippy/tests/ui/iter_over_hash_type.stderr @@ -2,6 +2,7 @@ error: iteration over unordered hash-based type --> tests/ui/iter_over_hash_type.rs:18:5 | LL | / for x in &hash_set { +LL | | LL | | let _ = x; LL | | } | |_____^ @@ -10,97 +11,109 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::iter_over_hash_type)]` error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:21:5 + --> tests/ui/iter_over_hash_type.rs:22:5 | LL | / for x in hash_set.iter() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:24:5 + --> tests/ui/iter_over_hash_type.rs:26:5 | LL | / for x in hash_set.clone() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:27:5 + --> tests/ui/iter_over_hash_type.rs:30:5 | LL | / for x in hash_set.drain() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:32:5 + --> tests/ui/iter_over_hash_type.rs:36:5 | LL | / for (x, y) in &hash_map { +LL | | LL | | let _ = (x, y); LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:35:5 + --> tests/ui/iter_over_hash_type.rs:40:5 | LL | / for x in hash_map.keys() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:38:5 + --> tests/ui/iter_over_hash_type.rs:44:5 | LL | / for x in hash_map.values() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:41:5 + --> tests/ui/iter_over_hash_type.rs:48:5 | LL | / for x in hash_map.values_mut() { +LL | | LL | | *x += 1; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:44:5 + --> tests/ui/iter_over_hash_type.rs:52:5 | LL | / for x in hash_map.iter() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:47:5 + --> tests/ui/iter_over_hash_type.rs:56:5 | LL | / for x in hash_map.clone() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:50:5 + --> tests/ui/iter_over_hash_type.rs:60:5 | LL | / for x in hash_map.drain() { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:55:5 + --> tests/ui/iter_over_hash_type.rs:66:5 | LL | / for x in fx_hash_set { +LL | | LL | | let _ = x; LL | | } | |_____^ error: iteration over unordered hash-based type - --> tests/ui/iter_over_hash_type.rs:58:5 + --> tests/ui/iter_over_hash_type.rs:70:5 | LL | / for x in fx_hash_map { +LL | | LL | | let _ = x; LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed index d7d3d299349ee..9999126902903 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed @@ -10,36 +10,49 @@ fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; let _: Option = vec.iter().last().cloned(); + //~^ iter_overeager_cloned let _: Option = vec.iter().chain(vec.iter()).next().cloned(); + //~^ iter_overeager_cloned let _: usize = vec.iter().filter(|x| x == &"2").count(); + //~^ redundant_clone let _: Vec<_> = vec.iter().take(2).cloned().collect(); + //~^ iter_overeager_cloned let _: Vec<_> = vec.iter().skip(2).cloned().collect(); + //~^ iter_overeager_cloned let _ = vec.iter().filter(|x| x == &"2").nth(2).cloned(); + //~^ iter_overeager_cloned let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] + //~^ iter_overeager_cloned .iter() .flatten().cloned(); let _ = vec.iter().filter(|&x| x.starts_with('2')).cloned(); + //~^ iter_overeager_cloned let _ = vec.iter().find(|&x| x == "2").cloned(); + //~^ iter_overeager_cloned { let f = |x: &String| x.starts_with('2'); let _ = vec.iter().filter(|&x| f(x)).cloned(); + //~^ iter_overeager_cloned let _ = vec.iter().find(|&x| f(x)).cloned(); + //~^ iter_overeager_cloned } { let vec: Vec<(String, String)> = vec![]; let f = move |x: &(String, String)| x.0.starts_with('2'); let _ = vec.iter().filter(|&x| f(x)).cloned(); + //~^ iter_overeager_cloned let _ = vec.iter().find(|&x| f(x)).cloned(); + //~^ iter_overeager_cloned } fn test_move<'a>( @@ -47,6 +60,7 @@ fn main() { target: String, ) -> impl Iterator + 'a { iter.filter(move |&(&a, b)| a == 1 && b == &target).cloned() + //~^ iter_overeager_cloned } { @@ -58,19 +72,24 @@ fn main() { fn bar<'a>(iter: impl Iterator> + 'a, target: String) -> impl Iterator> + 'a { iter.filter(move |&S { a, b }| **a == 1 && b == &target).cloned() + //~^ iter_overeager_cloned } } let _ = vec.iter().map(|x| x.len()); + //~^ redundant_clone // This would fail if changed. let _ = vec.iter().cloned().map(|x| x + "2"); let _ = vec.iter().for_each(|x| assert!(!x.is_empty())); + //~^ redundant_clone let _ = vec.iter().all(|x| x.len() == 1); + //~^ redundant_clone let _ = vec.iter().any(|x| x.len() == 1); + //~^ redundant_clone // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs index 45e1349febd06..6a860dad5afd8 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs @@ -10,37 +10,50 @@ fn main() { let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()]; let _: Option = vec.iter().cloned().last(); + //~^ iter_overeager_cloned let _: Option = vec.iter().chain(vec.iter()).cloned().next(); + //~^ iter_overeager_cloned let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); + //~^ redundant_clone let _: Vec<_> = vec.iter().cloned().take(2).collect(); + //~^ iter_overeager_cloned let _: Vec<_> = vec.iter().cloned().skip(2).collect(); + //~^ iter_overeager_cloned let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); + //~^ iter_overeager_cloned let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] + //~^ iter_overeager_cloned .iter() .cloned() .flatten(); let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); + //~^ iter_overeager_cloned let _ = vec.iter().cloned().find(|x| x == "2"); + //~^ iter_overeager_cloned { let f = |x: &String| x.starts_with('2'); let _ = vec.iter().cloned().filter(f); + //~^ iter_overeager_cloned let _ = vec.iter().cloned().find(f); + //~^ iter_overeager_cloned } { let vec: Vec<(String, String)> = vec![]; let f = move |x: &(String, String)| x.0.starts_with('2'); let _ = vec.iter().cloned().filter(f); + //~^ iter_overeager_cloned let _ = vec.iter().cloned().find(f); + //~^ iter_overeager_cloned } fn test_move<'a>( @@ -48,6 +61,7 @@ fn main() { target: String, ) -> impl Iterator + 'a { iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) + //~^ iter_overeager_cloned } { @@ -59,19 +73,24 @@ fn main() { fn bar<'a>(iter: impl Iterator> + 'a, target: String) -> impl Iterator> + 'a { iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target) + //~^ iter_overeager_cloned } } let _ = vec.iter().cloned().map(|x| x.len()); + //~^ redundant_clone // This would fail if changed. let _ = vec.iter().cloned().map(|x| x + "2"); let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); + //~^ redundant_clone let _ = vec.iter().cloned().all(|x| x.len() == 1); + //~^ redundant_clone let _ = vec.iter().cloned().any(|x| x.len() == 1); + //~^ redundant_clone // Should probably stay as it is. let _ = [0, 1, 2, 3, 4].iter().cloned().take(10); diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr index e6680266f1076..f3239b59582e3 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr @@ -10,7 +10,7 @@ LL | let _: Option = vec.iter().cloned().last(); = help: to override `-D warnings` add `#[allow(clippy::iter_overeager_cloned)]` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:14:29 + --> tests/ui/iter_overeager_cloned.rs:15:29 | LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- @@ -18,7 +18,7 @@ LL | let _: Option = vec.iter().chain(vec.iter()).cloned().next(); | help: try: `.next().cloned()` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:16:20 + --> tests/ui/iter_overeager_cloned.rs:18:20 | LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------- @@ -29,7 +29,7 @@ LL | let _: usize = vec.iter().filter(|x| x == &"2").cloned().count(); = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:18:21 + --> tests/ui/iter_overeager_cloned.rs:21:21 | LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); | ^^^^^^^^^^----------------- @@ -37,7 +37,7 @@ LL | let _: Vec<_> = vec.iter().cloned().take(2).collect(); | help: try: `.take(2).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:20:21 + --> tests/ui/iter_overeager_cloned.rs:24:21 | LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); | ^^^^^^^^^^----------------- @@ -45,7 +45,7 @@ LL | let _: Vec<_> = vec.iter().cloned().skip(2).collect(); | help: try: `.skip(2).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:22:13 + --> tests/ui/iter_overeager_cloned.rs:27:13 | LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------- @@ -53,10 +53,11 @@ LL | let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2); | help: try: `.nth(2).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:24:13 + --> tests/ui/iter_overeager_cloned.rs:30:13 | LL | let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))] | _____________^ +LL | | LL | | .iter() LL | | .cloned() LL | | .flatten(); @@ -69,7 +70,7 @@ LL ~ .flatten().cloned(); | error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:29:13 + --> tests/ui/iter_overeager_cloned.rs:36:13 | LL | let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); | ^^^^^^^^^^---------------------------------------- @@ -77,7 +78,7 @@ LL | let _ = vec.iter().cloned().filter(|x| x.starts_with('2')); | help: try: `.filter(|&x| x.starts_with('2')).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:31:13 + --> tests/ui/iter_overeager_cloned.rs:39:13 | LL | let _ = vec.iter().cloned().find(|x| x == "2"); | ^^^^^^^^^^---------------------------- @@ -85,7 +86,7 @@ LL | let _ = vec.iter().cloned().find(|x| x == "2"); | help: try: `.find(|&x| x == "2").cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:35:17 + --> tests/ui/iter_overeager_cloned.rs:44:17 | LL | let _ = vec.iter().cloned().filter(f); | ^^^^^^^^^^------------------- @@ -93,7 +94,7 @@ LL | let _ = vec.iter().cloned().filter(f); | help: try: `.filter(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:36:17 + --> tests/ui/iter_overeager_cloned.rs:46:17 | LL | let _ = vec.iter().cloned().find(f); | ^^^^^^^^^^----------------- @@ -101,7 +102,7 @@ LL | let _ = vec.iter().cloned().find(f); | help: try: `.find(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:42:17 + --> tests/ui/iter_overeager_cloned.rs:53:17 | LL | let _ = vec.iter().cloned().filter(f); | ^^^^^^^^^^------------------- @@ -109,7 +110,7 @@ LL | let _ = vec.iter().cloned().filter(f); | help: try: `.filter(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:43:17 + --> tests/ui/iter_overeager_cloned.rs:55:17 | LL | let _ = vec.iter().cloned().find(f); | ^^^^^^^^^^----------------- @@ -117,7 +118,7 @@ LL | let _ = vec.iter().cloned().find(f); | help: try: `.find(|&x| f(x)).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:50:9 + --> tests/ui/iter_overeager_cloned.rs:63:9 | LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) | ^^^^------------------------------------------------------- @@ -125,7 +126,7 @@ LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target) | help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()` error: unnecessarily eager cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:61:13 + --> tests/ui/iter_overeager_cloned.rs:75:13 | LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target) | ^^^^------------------------------------------------------------ @@ -133,7 +134,7 @@ LL | iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target | help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:65:13 + --> tests/ui/iter_overeager_cloned.rs:80:13 | LL | let _ = vec.iter().cloned().map(|x| x.len()); | ^^^^^^^^^^-------------------------- @@ -141,7 +142,7 @@ LL | let _ = vec.iter().cloned().map(|x| x.len()); | help: try: `.map(|x| x.len())` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:70:13 + --> tests/ui/iter_overeager_cloned.rs:86:13 | LL | let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); | ^^^^^^^^^^---------------------------------------------- @@ -149,7 +150,7 @@ LL | let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty())); | help: try: `.for_each(|x| assert!(!x.is_empty()))` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:72:13 + --> tests/ui/iter_overeager_cloned.rs:89:13 | LL | let _ = vec.iter().cloned().all(|x| x.len() == 1); | ^^^^^^^^^^------------------------------- @@ -157,7 +158,7 @@ LL | let _ = vec.iter().cloned().all(|x| x.len() == 1); | help: try: `.all(|x| x.len() == 1)` error: unneeded cloning of iterator items - --> tests/ui/iter_overeager_cloned.rs:74:13 + --> tests/ui/iter_overeager_cloned.rs:92:13 | LL | let _ = vec.iter().cloned().any(|x| x.len() == 1); | ^^^^^^^^^^------------------------------- diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed index 3e41b36324902..1d6a07f2d8280 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.fixed +++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed @@ -15,9 +15,13 @@ use option_helpers::IteratorFalsePositives; fn main() { let some_vec = vec![0, 1, 2, 3]; let _ = some_vec.iter().nth(42); + //~^ iter_skip_next let _ = some_vec.iter().cycle().nth(42); + //~^ iter_skip_next let _ = (1..10).nth(10); + //~^ iter_skip_next let _ = &some_vec[..].iter().nth(3); + //~^ iter_skip_next let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.skip(42).next(); let _ = foo.filter().skip(42).next(); @@ -26,13 +30,16 @@ fn main() { let test_string = "1|1 2"; let mut sp = test_string.split('|').map(|s| s.trim()); let _: Vec<&str> = sp.nth(1).unwrap().split(' ').collect(); + //~^ iter_skip_next if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) { let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect(); + //~^ iter_skip_next }; fn check(mut s: T) where T: Iterator, { let _: Vec<&str> = s.nth(1).unwrap().split(' ').collect(); + //~^ iter_skip_next } } diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs index 6d96441ca96f5..7570e17a0925e 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.rs +++ b/src/tools/clippy/tests/ui/iter_skip_next.rs @@ -15,9 +15,13 @@ use option_helpers::IteratorFalsePositives; fn main() { let some_vec = vec![0, 1, 2, 3]; let _ = some_vec.iter().skip(42).next(); + //~^ iter_skip_next let _ = some_vec.iter().cycle().skip(42).next(); + //~^ iter_skip_next let _ = (1..10).skip(10).next(); + //~^ iter_skip_next let _ = &some_vec[..].iter().skip(3).next(); + //~^ iter_skip_next let foo = IteratorFalsePositives { foo: 0 }; let _ = foo.skip(42).next(); let _ = foo.filter().skip(42).next(); @@ -26,13 +30,16 @@ fn main() { let test_string = "1|1 2"; let mut sp = test_string.split('|').map(|s| s.trim()); let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); + //~^ iter_skip_next if let Some(mut s) = Some(test_string.split('|').map(|s| s.trim())) { let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + //~^ iter_skip_next }; fn check(mut s: T) where T: Iterator, { let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); + //~^ iter_skip_next } } diff --git a/src/tools/clippy/tests/ui/iter_skip_next.stderr b/src/tools/clippy/tests/ui/iter_skip_next.stderr index 0fa04465ff156..9f6d708c2f41d 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.stderr +++ b/src/tools/clippy/tests/ui/iter_skip_next.stderr @@ -8,37 +8,37 @@ LL | let _ = some_vec.iter().skip(42).next(); = help: to override `-D warnings` add `#[allow(clippy::iter_skip_next)]` error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next.rs:18:36 + --> tests/ui/iter_skip_next.rs:19:36 | LL | let _ = some_vec.iter().cycle().skip(42).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(42)` error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next.rs:19:20 + --> tests/ui/iter_skip_next.rs:21:20 | LL | let _ = (1..10).skip(10).next(); | ^^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(10)` error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next.rs:20:33 + --> tests/ui/iter_skip_next.rs:23:33 | LL | let _ = &some_vec[..].iter().skip(3).next(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(3)` error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next.rs:28:26 + --> tests/ui/iter_skip_next.rs:32:26 | LL | let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next.rs:30:29 + --> tests/ui/iter_skip_next.rs:35:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next.rs:36:29 + --> tests/ui/iter_skip_next.rs:42:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` diff --git a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs index 6c98bdc8c8808..3f855b54d12a3 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs +++ b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.rs @@ -7,16 +7,17 @@ fn main() { let test_string = "1|1 2"; let sp = test_string.split('|').map(|s| s.trim()); let _: Vec<&str> = sp.skip(1).next().unwrap().split(' ').collect(); - //~^ ERROR: called `skip(..).next()` on an iterator + //~^ iter_skip_next + if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) { let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); - //~^ ERROR: called `skip(..).next()` on an iterator + //~^ iter_skip_next }; fn check(s: T) where T: Iterator, { let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); - //~^ ERROR: called `skip(..).next()` on an iterator + //~^ iter_skip_next } } diff --git a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr index 9bfffb07ca62d..44c5c1f854428 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr +++ b/src/tools/clippy/tests/ui/iter_skip_next_unfixable.stderr @@ -13,25 +13,25 @@ LL | let sp = test_string.split('|').map(|s| s.trim()); = help: to override `-D warnings` add `#[allow(clippy::iter_skip_next)]` error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next_unfixable.rs:12:29 + --> tests/ui/iter_skip_next_unfixable.rs:13:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` | help: for this change `s` has to be mutable - --> tests/ui/iter_skip_next_unfixable.rs:11:17 + --> tests/ui/iter_skip_next_unfixable.rs:12:17 | LL | if let Some(s) = Some(test_string.split('|').map(|s| s.trim())) { | ^ error: called `skip(..).next()` on an iterator - --> tests/ui/iter_skip_next_unfixable.rs:19:29 + --> tests/ui/iter_skip_next_unfixable.rs:20:29 | LL | let _: Vec<&str> = s.skip(1).next().unwrap().split(' ').collect(); | ^^^^^^^^^^^^^^^ help: use `nth` instead: `.nth(1)` | help: for this change `s` has to be mutable - --> tests/ui/iter_skip_next_unfixable.rs:15:17 + --> tests/ui/iter_skip_next_unfixable.rs:16:17 | LL | fn check(s: T) | ^ diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.fixed b/src/tools/clippy/tests/ui/iter_skip_zero.fixed index 447d07100e953..498af9bb4ff62 100644 --- a/src/tools/clippy/tests/ui/iter_skip_zero.fixed +++ b/src/tools/clippy/tests/ui/iter_skip_zero.fixed @@ -9,9 +9,14 @@ use std::iter::once; fn main() { let _ = [1, 2, 3].iter().skip(1); + //~^ iter_skip_zero let _ = vec![1, 2, 3].iter().skip(1); + //~^ iter_skip_zero let _ = once([1, 2, 3]).skip(1); + //~^ iter_skip_zero let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(1)).skip(1); + //~^ iter_skip_zero + //~| iter_skip_zero // Don't lint let _ = [1, 2, 3].iter().skip(1); let _ = vec![1, 2, 3].iter().skip(1); diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.rs b/src/tools/clippy/tests/ui/iter_skip_zero.rs index ba63c3981808e..f168e91099539 100644 --- a/src/tools/clippy/tests/ui/iter_skip_zero.rs +++ b/src/tools/clippy/tests/ui/iter_skip_zero.rs @@ -9,9 +9,14 @@ use std::iter::once; fn main() { let _ = [1, 2, 3].iter().skip(0); + //~^ iter_skip_zero let _ = vec![1, 2, 3].iter().skip(0); + //~^ iter_skip_zero let _ = once([1, 2, 3]).skip(0); + //~^ iter_skip_zero let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0); + //~^ iter_skip_zero + //~| iter_skip_zero // Don't lint let _ = [1, 2, 3].iter().skip(1); let _ = vec![1, 2, 3].iter().skip(1); diff --git a/src/tools/clippy/tests/ui/iter_skip_zero.stderr b/src/tools/clippy/tests/ui/iter_skip_zero.stderr index ef46db8433778..235074374aa1c 100644 --- a/src/tools/clippy/tests/ui/iter_skip_zero.stderr +++ b/src/tools/clippy/tests/ui/iter_skip_zero.stderr @@ -9,7 +9,7 @@ LL | let _ = [1, 2, 3].iter().skip(0); = help: to override `-D warnings` add `#[allow(clippy::iter_skip_zero)]` error: usage of `.skip(0)` - --> tests/ui/iter_skip_zero.rs:12:39 + --> tests/ui/iter_skip_zero.rs:13:39 | LL | let _ = vec![1, 2, 3].iter().skip(0); | ^ help: if you meant to skip the first element, use: `1` @@ -17,7 +17,7 @@ LL | let _ = vec![1, 2, 3].iter().skip(0); = note: this call to `skip` does nothing and is useless; remove it error: usage of `.skip(0)` - --> tests/ui/iter_skip_zero.rs:13:34 + --> tests/ui/iter_skip_zero.rs:15:34 | LL | let _ = once([1, 2, 3]).skip(0); | ^ help: if you meant to skip the first element, use: `1` @@ -25,7 +25,7 @@ LL | let _ = once([1, 2, 3]).skip(0); = note: this call to `skip` does nothing and is useless; remove it error: usage of `.skip(0)` - --> tests/ui/iter_skip_zero.rs:14:71 + --> tests/ui/iter_skip_zero.rs:17:71 | LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0); | ^ help: if you meant to skip the first element, use: `1` @@ -33,7 +33,7 @@ LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0); = note: this call to `skip` does nothing and is useless; remove it error: usage of `.skip(0)` - --> tests/ui/iter_skip_zero.rs:14:62 + --> tests/ui/iter_skip_zero.rs:17:62 | LL | let _ = vec![1, 2, 3].iter().chain([1, 2, 3].iter().skip(0)).skip(0); | ^ help: if you meant to skip the first element, use: `1` diff --git a/src/tools/clippy/tests/ui/iter_with_drain.fixed b/src/tools/clippy/tests/ui/iter_with_drain.fixed index a03efceed4caa..b0661ffb981b1 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.fixed +++ b/src/tools/clippy/tests/ui/iter_with_drain.fixed @@ -8,20 +8,26 @@ use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; fn full() { let mut a = vec!["aaa".to_string(), "bbb".to_string()]; let mut a: BinaryHeap<_> = a.into_iter().collect(); + //~^ iter_with_drain let mut a: HashSet<_> = a.drain().collect(); let mut a: VecDeque<_> = a.drain().collect(); let mut a: Vec<_> = a.into_iter().collect(); + //~^ iter_with_drain let mut a: HashMap<_, _> = a.into_iter().map(|x| (x.clone(), x)).collect(); + //~^ iter_with_drain let _: Vec<(String, String)> = a.drain().collect(); } fn closed() { let mut a = vec!["aaa".to_string(), "bbb".to_string()]; let mut a: BinaryHeap<_> = a.into_iter().collect(); + //~^ iter_with_drain let mut a: HashSet<_> = a.drain().collect(); let mut a: VecDeque<_> = a.drain().collect(); let mut a: Vec<_> = a.into_iter().collect(); + //~^ iter_with_drain let mut a: HashMap<_, _> = a.into_iter().map(|x| (x.clone(), x)).collect(); + //~^ iter_with_drain let _: Vec<(String, String)> = a.drain().collect(); } diff --git a/src/tools/clippy/tests/ui/iter_with_drain.rs b/src/tools/clippy/tests/ui/iter_with_drain.rs index a8cd47f83d04d..746b0f9a5eda3 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.rs +++ b/src/tools/clippy/tests/ui/iter_with_drain.rs @@ -8,20 +8,26 @@ use std::collections::{BinaryHeap, HashMap, HashSet, VecDeque}; fn full() { let mut a = vec!["aaa".to_string(), "bbb".to_string()]; let mut a: BinaryHeap<_> = a.drain(..).collect(); + //~^ iter_with_drain let mut a: HashSet<_> = a.drain().collect(); let mut a: VecDeque<_> = a.drain().collect(); let mut a: Vec<_> = a.drain(..).collect(); + //~^ iter_with_drain let mut a: HashMap<_, _> = a.drain(..).map(|x| (x.clone(), x)).collect(); + //~^ iter_with_drain let _: Vec<(String, String)> = a.drain().collect(); } fn closed() { let mut a = vec!["aaa".to_string(), "bbb".to_string()]; let mut a: BinaryHeap<_> = a.drain(0..).collect(); + //~^ iter_with_drain let mut a: HashSet<_> = a.drain().collect(); let mut a: VecDeque<_> = a.drain().collect(); let mut a: Vec<_> = a.drain(..a.len()).collect(); + //~^ iter_with_drain let mut a: HashMap<_, _> = a.drain(0..a.len()).map(|x| (x.clone(), x)).collect(); + //~^ iter_with_drain let _: Vec<(String, String)> = a.drain().collect(); } diff --git a/src/tools/clippy/tests/ui/iter_with_drain.stderr b/src/tools/clippy/tests/ui/iter_with_drain.stderr index 265e18c263be8..370658961b9b5 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.stderr +++ b/src/tools/clippy/tests/ui/iter_with_drain.stderr @@ -8,31 +8,31 @@ LL | let mut a: BinaryHeap<_> = a.drain(..).collect(); = help: to override `-D warnings` add `#[allow(clippy::iter_with_drain)]` error: `drain(..)` used on a `VecDeque` - --> tests/ui/iter_with_drain.rs:13:27 + --> tests/ui/iter_with_drain.rs:14:27 | LL | let mut a: Vec<_> = a.drain(..).collect(); | ^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `Vec` - --> tests/ui/iter_with_drain.rs:14:34 + --> tests/ui/iter_with_drain.rs:16:34 | LL | let mut a: HashMap<_, _> = a.drain(..).map(|x| (x.clone(), x)).collect(); | ^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `Vec` - --> tests/ui/iter_with_drain.rs:20:34 + --> tests/ui/iter_with_drain.rs:23:34 | LL | let mut a: BinaryHeap<_> = a.drain(0..).collect(); | ^^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `VecDeque` - --> tests/ui/iter_with_drain.rs:23:27 + --> tests/ui/iter_with_drain.rs:27:27 | LL | let mut a: Vec<_> = a.drain(..a.len()).collect(); | ^^^^^^^^^^^^^^^^ help: try: `into_iter()` error: `drain(..)` used on a `Vec` - --> tests/ui/iter_with_drain.rs:24:34 + --> tests/ui/iter_with_drain.rs:29:34 | LL | let mut a: HashMap<_, _> = a.drain(0..a.len()).map(|x| (x.clone(), x)).collect(); | ^^^^^^^^^^^^^^^^^ help: try: `into_iter()` diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.rs b/src/tools/clippy/tests/ui/iter_without_into_iter.rs index d5b28e45453b4..dc3149be2cb4b 100644 --- a/src/tools/clippy/tests/ui/iter_without_into_iter.rs +++ b/src/tools/clippy/tests/ui/iter_without_into_iter.rs @@ -7,11 +7,11 @@ extern crate proc_macros; pub struct S1; impl S1 { pub fn iter(&self) -> std::slice::Iter<'_, u8> { - //~^ ERROR: `iter` method without an `IntoIterator` impl + //~^ iter_without_into_iter [].iter() } pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { - //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + //~^ iter_without_into_iter [].iter_mut() } } @@ -27,11 +27,11 @@ impl S2 { pub struct S3<'a>(&'a mut [u8]); impl<'a> S3<'a> { pub fn iter(&self) -> std::slice::Iter<'_, u8> { - //~^ ERROR: `iter` method without an `IntoIterator` impl + //~^ iter_without_into_iter self.0.iter() } pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> { - //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + //~^ iter_without_into_iter self.0.iter_mut() } } @@ -68,6 +68,7 @@ impl S7 { pub struct S8(T); impl S8 { pub fn iter(&self) -> std::slice::Iter<'static, T> { + //~^ iter_without_into_iter todo!() } } @@ -76,11 +77,11 @@ impl S8 { pub struct S9(T); impl S9 { pub fn iter(&self) -> std::slice::Iter<'_, T> { - //~^ ERROR: `iter` method without an `IntoIterator` impl + //~^ iter_without_into_iter todo!() } pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { - //~^ ERROR: `iter_mut` method without an `IntoIterator` impl + //~^ iter_without_into_iter todo!() } } @@ -129,6 +130,7 @@ macro_rules! generate_impl { () => { impl Issue12037 { fn iter(&self) -> std::slice::Iter<'_, u8> { + //~^ iter_without_into_iter todo!() } } diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr index d748c85003bbf..8f86bee09670f 100644 --- a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr +++ b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr @@ -88,6 +88,7 @@ error: `iter` method without an `IntoIterator` impl for `&S8` --> tests/ui/iter_without_into_iter.rs:70:5 | LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> { +LL | | LL | | todo!() LL | | } | |_____^ @@ -105,7 +106,7 @@ LL + } | error: `iter` method without an `IntoIterator` impl for `&S9` - --> tests/ui/iter_without_into_iter.rs:78:5 + --> tests/ui/iter_without_into_iter.rs:79:5 | LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> { LL | | @@ -126,7 +127,7 @@ LL + } | error: `iter_mut` method without an `IntoIterator` impl for `&mut S9` - --> tests/ui/iter_without_into_iter.rs:82:5 + --> tests/ui/iter_without_into_iter.rs:83:5 | LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> { LL | | @@ -147,9 +148,10 @@ LL + } | error: `iter` method without an `IntoIterator` impl for `&Issue12037` - --> tests/ui/iter_without_into_iter.rs:131:13 + --> tests/ui/iter_without_into_iter.rs:132:13 | LL | / fn iter(&self) -> std::slice::Iter<'_, u8> { +LL | | LL | | todo!() LL | | } | |_____________^ diff --git a/src/tools/clippy/tests/ui/iterator_step_by_zero.rs b/src/tools/clippy/tests/ui/iterator_step_by_zero.rs index 0b51842df2e39..a729101bd4036 100644 --- a/src/tools/clippy/tests/ui/iterator_step_by_zero.rs +++ b/src/tools/clippy/tests/ui/iterator_step_by_zero.rs @@ -2,12 +2,13 @@ #[warn(clippy::iterator_step_by_zero)] fn main() { let _ = vec!["A", "B", "B"].iter().step_by(0); - //~^ ERROR: `Iterator::step_by(0)` will panic at runtime - //~| NOTE: `-D clippy::iterator-step-by-zero` implied by `-D warnings` + //~^ iterator_step_by_zero + let _ = "XXX".chars().step_by(0); - //~^ ERROR: `Iterator::step_by(0)` will panic at runtime + //~^ iterator_step_by_zero + let _ = (0..1).step_by(0); - //~^ ERROR: `Iterator::step_by(0)` will panic at runtime + //~^ iterator_step_by_zero // No error, not an iterator. let y = NotIterator; @@ -17,18 +18,19 @@ fn main() { let _ = (0..1).step_by(1); let _ = (1..).step_by(0); - //~^ ERROR: `Iterator::step_by(0)` will panic at runtime + //~^ iterator_step_by_zero + let _ = (1..=2).step_by(0); - //~^ ERROR: `Iterator::step_by(0)` will panic at runtime + //~^ iterator_step_by_zero let x = 0..1; let _ = x.step_by(0); - //~^ ERROR: `Iterator::step_by(0)` will panic at runtime + //~^ iterator_step_by_zero // check const eval let v1 = vec![1, 2, 3]; let _ = v1.iter().step_by(2 / 3); - //~^ ERROR: `Iterator::step_by(0)` will panic at runtime + //~^ iterator_step_by_zero } struct NotIterator; diff --git a/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr b/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr index 4156642d6dbb8..0ff916b6dd5eb 100644 --- a/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr +++ b/src/tools/clippy/tests/ui/iterator_step_by_zero.stderr @@ -14,31 +14,31 @@ LL | let _ = "XXX".chars().step_by(0); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> tests/ui/iterator_step_by_zero.rs:9:13 + --> tests/ui/iterator_step_by_zero.rs:10:13 | LL | let _ = (0..1).step_by(0); | ^^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> tests/ui/iterator_step_by_zero.rs:19:13 + --> tests/ui/iterator_step_by_zero.rs:20:13 | LL | let _ = (1..).step_by(0); | ^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> tests/ui/iterator_step_by_zero.rs:21:13 + --> tests/ui/iterator_step_by_zero.rs:23:13 | LL | let _ = (1..=2).step_by(0); | ^^^^^^^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> tests/ui/iterator_step_by_zero.rs:25:13 + --> tests/ui/iterator_step_by_zero.rs:27:13 | LL | let _ = x.step_by(0); | ^^^^^^^^^^^^ error: `Iterator::step_by(0)` will panic at runtime - --> tests/ui/iterator_step_by_zero.rs:30:13 + --> tests/ui/iterator_step_by_zero.rs:32:13 | LL | let _ = v1.iter().step_by(2 / 3); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/join_absolute_paths.rs b/src/tools/clippy/tests/ui/join_absolute_paths.rs index efa77a0492e61..144c9147c2a1b 100644 --- a/src/tools/clippy/tests/ui/join_absolute_paths.rs +++ b/src/tools/clippy/tests/ui/join_absolute_paths.rs @@ -8,19 +8,19 @@ use std::path::{Path, PathBuf}; fn main() { let path = Path::new("/bin"); path.join("/sh"); - //~^ ERROR: argument to `Path::join` starts with a path separator + //~^ join_absolute_paths let path = Path::new("C:\\Users"); path.join("\\user"); - //~^ ERROR: argument to `Path::join` starts with a path separator + //~^ join_absolute_paths let path = PathBuf::from("/bin"); path.join("/sh"); - //~^ ERROR: argument to `Path::join` starts with a path separator + //~^ join_absolute_paths let path = PathBuf::from("/bin"); path.join(r#"/sh"#); - //~^ ERROR: argument to `Path::join` starts with a path separator + //~^ join_absolute_paths let path: &[&str] = &["/bin"]; path.join("/sh"); diff --git a/src/tools/clippy/tests/ui/large_const_arrays.fixed b/src/tools/clippy/tests/ui/large_const_arrays.fixed index e5b28cb6a9ddb..7c3868fc8ffd7 100644 --- a/src/tools/clippy/tests/ui/large_const_arrays.fixed +++ b/src/tools/clippy/tests/ui/large_const_arrays.fixed @@ -8,9 +8,13 @@ pub struct S { // Should lint pub(crate) static FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000]; +//~^ large_const_arrays pub static FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; +//~^ large_const_arrays static FOO_COMPUTED: [u32; 1_000 * 100] = [0u32; 1_000 * 100]; +//~^ large_const_arrays static FOO: [u32; 1_000_000] = [0u32; 1_000_000]; +//~^ large_const_arrays // Good pub(crate) const G_FOO_PUB_CRATE: [u32; 250] = [0u32; 250]; @@ -21,11 +25,17 @@ const G_FOO: [u32; 250] = [0u32; 250]; fn main() { // Should lint pub static BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; + //~^ large_const_arrays static BAR: [u32; 1_000_000] = [0u32; 1_000_000]; + //~^ large_const_arrays pub static BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + //~^ large_const_arrays static BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + //~^ large_const_arrays pub static BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000]; + //~^ large_const_arrays static BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; + //~^ large_const_arrays // Good pub const G_BAR_PUB: [u32; 250] = [0u32; 250]; diff --git a/src/tools/clippy/tests/ui/large_const_arrays.rs b/src/tools/clippy/tests/ui/large_const_arrays.rs index b9593225da2f7..3e811520f0632 100644 --- a/src/tools/clippy/tests/ui/large_const_arrays.rs +++ b/src/tools/clippy/tests/ui/large_const_arrays.rs @@ -8,9 +8,13 @@ pub struct S { // Should lint pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000]; +//~^ large_const_arrays pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; +//~^ large_const_arrays const FOO_COMPUTED: [u32; 1_000 * 100] = [0u32; 1_000 * 100]; +//~^ large_const_arrays const FOO: [u32; 1_000_000] = [0u32; 1_000_000]; +//~^ large_const_arrays // Good pub(crate) const G_FOO_PUB_CRATE: [u32; 250] = [0u32; 250]; @@ -21,11 +25,17 @@ const G_FOO: [u32; 250] = [0u32; 250]; fn main() { // Should lint pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; + //~^ large_const_arrays const BAR: [u32; 1_000_000] = [0u32; 1_000_000]; + //~^ large_const_arrays pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + //~^ large_const_arrays const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000]; + //~^ large_const_arrays pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000]; + //~^ large_const_arrays const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; + //~^ large_const_arrays // Good pub const G_BAR_PUB: [u32; 250] = [0u32; 250]; diff --git a/src/tools/clippy/tests/ui/large_const_arrays.stderr b/src/tools/clippy/tests/ui/large_const_arrays.stderr index 2711220539085..56cddeaf628d2 100644 --- a/src/tools/clippy/tests/ui/large_const_arrays.stderr +++ b/src/tools/clippy/tests/ui/large_const_arrays.stderr @@ -10,7 +10,7 @@ LL | pub(crate) const FOO_PUB_CRATE: [u32; 1_000_000] = [0u32; 1_000_000]; = help: to override `-D warnings` add `#[allow(clippy::large_const_arrays)]` error: large array defined as const - --> tests/ui/large_const_arrays.rs:11:1 + --> tests/ui/large_const_arrays.rs:12:1 | LL | pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | pub const FOO_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:12:1 + --> tests/ui/large_const_arrays.rs:14:1 | LL | const FOO_COMPUTED: [u32; 1_000 * 100] = [0u32; 1_000 * 100]; | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | const FOO_COMPUTED: [u32; 1_000 * 100] = [0u32; 1_000 * 100]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:13:1 + --> tests/ui/large_const_arrays.rs:16:1 | LL | const FOO: [u32; 1_000_000] = [0u32; 1_000_000]; | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | const FOO: [u32; 1_000_000] = [0u32; 1_000_000]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:23:5 + --> tests/ui/large_const_arrays.rs:27:5 | LL | pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | pub const BAR_PUB: [u32; 1_000_000] = [0u32; 1_000_000]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:24:5 + --> tests/ui/large_const_arrays.rs:29:5 | LL | const BAR: [u32; 1_000_000] = [0u32; 1_000_000]; | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -50,7 +50,7 @@ LL | const BAR: [u32; 1_000_000] = [0u32; 1_000_000]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:25:5 + --> tests/ui/large_const_arrays.rs:31:5 | LL | pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000]; | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,7 +58,7 @@ LL | pub const BAR_STRUCT_PUB: [S; 5_000] = [S { data: [0; 32] }; 5_000]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:26:5 + --> tests/ui/large_const_arrays.rs:33:5 | LL | const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000]; | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | const BAR_STRUCT: [S; 5_000] = [S { data: [0; 32] }; 5_000]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:27:5 + --> tests/ui/large_const_arrays.rs:35:5 | LL | pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000]; | ^^^^-----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL | pub const BAR_S_PUB: [Option<&str>; 200_000] = [Some("str"); 200_000]; | help: make this a static item: `static` error: large array defined as const - --> tests/ui/large_const_arrays.rs:28:5 + --> tests/ui/large_const_arrays.rs:37:5 | LL | const BAR_S: [Option<&str>; 200_000] = [Some("str"); 200_000]; | -----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/large_digit_groups.fixed b/src/tools/clippy/tests/ui/large_digit_groups.fixed index cdb001e47e2bd..0ad2ebf522b82 100644 --- a/src/tools/clippy/tests/ui/large_digit_groups.fixed +++ b/src/tools/clippy/tests/ui/large_digit_groups.fixed @@ -20,10 +20,15 @@ fn main() { let _bad = ( 0b1_10110_i64, 0xdead_beef_usize, + //~^ unusual_byte_groupings 123_456_f32, + //~^ large_digit_groups 123_456.12_f32, + //~^ large_digit_groups 123_456.123_45_f64, + //~^ large_digit_groups 123_456.123_456_f64, + //~^ large_digit_groups ); // Ignore literals in macros let _ = mac!(); diff --git a/src/tools/clippy/tests/ui/large_digit_groups.rs b/src/tools/clippy/tests/ui/large_digit_groups.rs index 3c30c86702848..1cf489fd69b2b 100644 --- a/src/tools/clippy/tests/ui/large_digit_groups.rs +++ b/src/tools/clippy/tests/ui/large_digit_groups.rs @@ -20,10 +20,15 @@ fn main() { let _bad = ( 0b1_10110_i64, 0xd_e_adbee_f_usize, + //~^ unusual_byte_groupings 1_23456_f32, + //~^ large_digit_groups 1_23456.12_f32, + //~^ large_digit_groups 1_23456.12345_f64, + //~^ large_digit_groups 1_23456.12345_6_f64, + //~^ large_digit_groups ); // Ignore literals in macros let _ = mac!(); diff --git a/src/tools/clippy/tests/ui/large_digit_groups.stderr b/src/tools/clippy/tests/ui/large_digit_groups.stderr index da34a91bc3bcf..281a6267c8d65 100644 --- a/src/tools/clippy/tests/ui/large_digit_groups.stderr +++ b/src/tools/clippy/tests/ui/large_digit_groups.stderr @@ -8,7 +8,7 @@ LL | 0xd_e_adbee_f_usize, = help: to override `-D warnings` add `#[allow(clippy::unusual_byte_groupings)]` error: digit groups should be smaller - --> tests/ui/large_digit_groups.rs:23:9 + --> tests/ui/large_digit_groups.rs:24:9 | LL | 1_23456_f32, | ^^^^^^^^^^^ help: consider: `123_456_f32` @@ -17,19 +17,19 @@ LL | 1_23456_f32, = help: to override `-D warnings` add `#[allow(clippy::large_digit_groups)]` error: digit groups should be smaller - --> tests/ui/large_digit_groups.rs:24:9 + --> tests/ui/large_digit_groups.rs:26:9 | LL | 1_23456.12_f32, | ^^^^^^^^^^^^^^ help: consider: `123_456.12_f32` error: digit groups should be smaller - --> tests/ui/large_digit_groups.rs:25:9 + --> tests/ui/large_digit_groups.rs:28:9 | LL | 1_23456.12345_f64, | ^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_45_f64` error: digit groups should be smaller - --> tests/ui/large_digit_groups.rs:26:9 + --> tests/ui/large_digit_groups.rs:30:9 | LL | 1_23456.12345_6_f64, | ^^^^^^^^^^^^^^^^^^^ help: consider: `123_456.123_456_f64` diff --git a/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr index ff4f1a7f312cb..80ca5daa1d573 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr +++ b/src/tools/clippy/tests/ui/large_enum_variant.32bit.stderr @@ -1,7 +1,8 @@ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:11:1 + --> tests/ui/large_enum_variant.rs:13:1 | LL | / enum LargeEnum { +LL | | LL | | A(i32), | | ------ the second-largest variant contains at least 4 bytes LL | | B([i32; 8000]), @@ -13,13 +14,15 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::large_enum_variant)]` help: consider boxing the large fields to reduce the total size of the enum | -LL | B(Box<[i32; 8000]>), - | ~~~~~~~~~~~~~~~~ +LL - B([i32; 8000]), +LL + B(Box<[i32; 8000]>), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:35:1 + --> tests/ui/large_enum_variant.rs:38:1 | LL | / enum LargeEnum2 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | ContainingLargeEnum(LargeEnum), @@ -29,13 +32,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | ContainingLargeEnum(Box), - | ~~~~~~~~~~~~~~ +LL - ContainingLargeEnum(LargeEnum), +LL + ContainingLargeEnum(Box), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:40:1 + --> tests/ui/large_enum_variant.rs:44:1 | LL | / enum LargeEnum3 { +LL | | LL | | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), | | --------------------------------------------------------- the largest variant contains at least 70004 bytes LL | | VoidVariant, @@ -46,13 +51,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), - | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ +LL - ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), +LL + ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:46:1 + --> tests/ui/large_enum_variant.rs:51:1 | LL | / enum LargeEnum4 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | StructLikeLarge { x: [i32; 8000], y: i32 }, @@ -62,13 +69,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, - | ~~~~~~~~~~~~~~~~ +LL - StructLikeLarge { x: [i32; 8000], y: i32 }, +LL + StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:51:1 + --> tests/ui/large_enum_variant.rs:57:1 | LL | / enum LargeEnum5 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | StructLikeLarge2 { x: [i32; 8000] }, @@ -78,13 +87,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | StructLikeLarge2 { x: Box<[i32; 8000]> }, - | ~~~~~~~~~~~~~~~~ +LL - StructLikeLarge2 { x: [i32; 8000] }, +LL + StructLikeLarge2 { x: Box<[i32; 8000]> }, + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:67:1 + --> tests/ui/large_enum_variant.rs:74:1 | LL | / enum LargeEnum7 { +LL | | LL | | A, LL | | B([u8; 1255]), | | ------------- the largest variant contains at least 1255 bytes @@ -95,13 +106,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | B(Box<[u8; 1255]>), - | ~~~~~~~~~~~~~~~ +LL - B([u8; 1255]), +LL + B(Box<[u8; 1255]>), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:73:1 + --> tests/ui/large_enum_variant.rs:81:1 | LL | / enum LargeEnum8 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), @@ -111,13 +124,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), - | ~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~ +LL - ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), +LL + ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]>, [i32; 30]), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:78:1 + --> tests/ui/large_enum_variant.rs:87:1 | LL | / enum LargeEnum9 { +LL | | LL | | A(Struct<()>), | | ------------- the second-largest variant contains at least 4 bytes LL | | B(Struct2), @@ -127,13 +142,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | B(Box), - | ~~~~~~~~~~~~ +LL - B(Struct2), +LL + B(Box), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:83:1 + --> tests/ui/large_enum_variant.rs:93:1 | LL | / enum LargeEnumOk2 { +LL | | LL | | A(T), | | ---- the second-largest variant contains at least 0 bytes LL | | B(Struct2), @@ -143,13 +160,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | B(Box), - | ~~~~~~~~~~~~ +LL - B(Struct2), +LL + B(Box), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:88:1 + --> tests/ui/large_enum_variant.rs:99:1 | LL | / enum LargeEnumOk3 { +LL | | LL | | A(Struct), | | ------------ the second-largest variant contains at least 4 bytes LL | | B(Struct2), @@ -159,13 +178,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | B(Box), - | ~~~~~~~~~~~~ +LL - B(Struct2), +LL + B(Box), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:103:1 + --> tests/ui/large_enum_variant.rs:115:1 | LL | / enum CopyableLargeEnum { +LL | | LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes LL | | B([u64; 8000]), @@ -174,20 +195,21 @@ LL | | } | |_^ the entire enum is at least 64004 bytes | note: boxing a variant would require the type no longer be `Copy` - --> tests/ui/large_enum_variant.rs:103:6 + --> tests/ui/large_enum_variant.rs:115:6 | LL | enum CopyableLargeEnum { | ^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> tests/ui/large_enum_variant.rs:105:5 + --> tests/ui/large_enum_variant.rs:118:5 | LL | B([u64; 8000]), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:108:1 + --> tests/ui/large_enum_variant.rs:121:1 | LL | / enum ManuallyCopyLargeEnum { +LL | | LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes LL | | B([u64; 8000]), @@ -196,20 +218,21 @@ LL | | } | |_^ the entire enum is at least 64004 bytes | note: boxing a variant would require the type no longer be `Copy` - --> tests/ui/large_enum_variant.rs:108:6 + --> tests/ui/large_enum_variant.rs:121:6 | LL | enum ManuallyCopyLargeEnum { | ^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> tests/ui/large_enum_variant.rs:110:5 + --> tests/ui/large_enum_variant.rs:124:5 | LL | B([u64; 8000]), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:121:1 + --> tests/ui/large_enum_variant.rs:135:1 | LL | / enum SomeGenericPossiblyCopyEnum { +LL | | LL | | A(bool, std::marker::PhantomData), | | ------------------------------------ the second-largest variant contains at least 1 bytes LL | | B([u64; 4000]), @@ -218,20 +241,21 @@ LL | | } | |_^ the entire enum is at least 32004 bytes | note: boxing a variant would require the type no longer be `Copy` - --> tests/ui/large_enum_variant.rs:121:6 + --> tests/ui/large_enum_variant.rs:135:6 | LL | enum SomeGenericPossiblyCopyEnum { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> tests/ui/large_enum_variant.rs:123:5 + --> tests/ui/large_enum_variant.rs:138:5 | LL | B([u64; 4000]), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:134:1 + --> tests/ui/large_enum_variant.rs:149:1 | LL | / enum LargeEnumWithGenerics { +LL | | LL | | Small, | | ----- the second-largest variant carries no data at all LL | | Large((T, [u8; 512])), @@ -241,13 +265,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | Large(Box<(T, [u8; 512])>), - | ~~~~~~~~~~~~~~~~~~~ +LL - Large((T, [u8; 512])), +LL + Large(Box<(T, [u8; 512])>), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:143:1 + --> tests/ui/large_enum_variant.rs:159:1 | LL | / enum WithGenerics { +LL | | LL | | Large([Foo; 64]), | | --------------------- the largest variant contains at least 512 bytes LL | | Small(u8), @@ -257,13 +283,15 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | Large(Box<[Foo; 64]>), - | ~~~~~~~~~~~~~~~~~~~ +LL - Large([Foo; 64]), +LL + Large(Box<[Foo; 64]>), + | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:153:1 + --> tests/ui/large_enum_variant.rs:170:1 | LL | / enum LargeEnumOfConst { +LL | | LL | | Ok, | | -- the second-largest variant carries no data at all LL | | Error(PossiblyLargeEnumWithConst<256>), @@ -273,8 +301,45 @@ LL | | } | help: consider boxing the large fields to reduce the total size of the enum | -LL | Error(Box>), - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL - Error(PossiblyLargeEnumWithConst<256>), +LL + Error(Box>), + | + +error: large size difference between variants + --> tests/ui/large_enum_variant.rs:176:1 + | +LL | / enum WithRecursion { +LL | | +LL | | Large([u64; 64]), + | | ---------------- the largest variant contains at least 512 bytes +LL | | Recursive(Box), + | | ----------------------------- the second-largest variant contains at least 4 bytes +LL | | } + | |_^ the entire enum is at least 516 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL - Large([u64; 64]), +LL + Large(Box<[u64; 64]>), + | + +error: large size difference between variants + --> tests/ui/large_enum_variant.rs:187:1 + | +LL | / enum LargeEnumWithGenericsAndRecursive { +LL | | +LL | | Ok(), + | | ---- the second-largest variant carries no data at all +LL | | Error(WithRecursionAndGenerics), + | | ------------------------------------ the largest variant contains at least 516 bytes +LL | | } + | |_^ the entire enum is at least 516 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL - Error(WithRecursionAndGenerics), +LL + Error(Box>), + | -error: aborting due to 16 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr index 60653b4abfb50..559bdf2a2f50c 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr +++ b/src/tools/clippy/tests/ui/large_enum_variant.64bit.stderr @@ -1,7 +1,8 @@ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:11:1 + --> tests/ui/large_enum_variant.rs:13:1 | LL | / enum LargeEnum { +LL | | LL | | A(i32), | | ------ the second-largest variant contains at least 4 bytes LL | | B([i32; 8000]), @@ -18,9 +19,10 @@ LL + B(Box<[i32; 8000]>), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:35:1 + --> tests/ui/large_enum_variant.rs:38:1 | LL | / enum LargeEnum2 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | ContainingLargeEnum(LargeEnum), @@ -35,9 +37,10 @@ LL + ContainingLargeEnum(Box), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:40:1 + --> tests/ui/large_enum_variant.rs:44:1 | LL | / enum LargeEnum3 { +LL | | LL | | ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), | | --------------------------------------------------------- the largest variant contains at least 70004 bytes LL | | VoidVariant, @@ -53,9 +56,10 @@ LL + ContainingMoreThanOneField(i32, Box<[i32; 8000]>, Box<[i32; 9500]>), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:46:1 + --> tests/ui/large_enum_variant.rs:51:1 | LL | / enum LargeEnum4 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | StructLikeLarge { x: [i32; 8000], y: i32 }, @@ -70,9 +74,10 @@ LL + StructLikeLarge { x: Box<[i32; 8000]>, y: i32 }, | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:51:1 + --> tests/ui/large_enum_variant.rs:57:1 | LL | / enum LargeEnum5 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | StructLikeLarge2 { x: [i32; 8000] }, @@ -87,9 +92,10 @@ LL + StructLikeLarge2 { x: Box<[i32; 8000]> }, | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:67:1 + --> tests/ui/large_enum_variant.rs:74:1 | LL | / enum LargeEnum7 { +LL | | LL | | A, LL | | B([u8; 1255]), | | ------------- the largest variant contains at least 1255 bytes @@ -105,9 +111,10 @@ LL + B(Box<[u8; 1255]>), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:73:1 + --> tests/ui/large_enum_variant.rs:81:1 | LL | / enum LargeEnum8 { +LL | | LL | | VariantOk(i32, u32), | | ------------------- the second-largest variant contains at least 8 bytes LL | | ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), @@ -122,9 +129,10 @@ LL + ContainingMoreThanOneField(Box<[i32; 8000]>, [i32; 2], Box<[i32; 9500]> | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:78:1 + --> tests/ui/large_enum_variant.rs:87:1 | LL | / enum LargeEnum9 { +LL | | LL | | A(Struct<()>), | | ------------- the second-largest variant contains at least 4 bytes LL | | B(Struct2), @@ -139,9 +147,10 @@ LL + B(Box), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:83:1 + --> tests/ui/large_enum_variant.rs:93:1 | LL | / enum LargeEnumOk2 { +LL | | LL | | A(T), | | ---- the second-largest variant contains at least 0 bytes LL | | B(Struct2), @@ -156,9 +165,10 @@ LL + B(Box), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:88:1 + --> tests/ui/large_enum_variant.rs:99:1 | LL | / enum LargeEnumOk3 { +LL | | LL | | A(Struct), | | ------------ the second-largest variant contains at least 4 bytes LL | | B(Struct2), @@ -173,9 +183,10 @@ LL + B(Box), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:103:1 + --> tests/ui/large_enum_variant.rs:115:1 | LL | / enum CopyableLargeEnum { +LL | | LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes LL | | B([u64; 8000]), @@ -184,20 +195,21 @@ LL | | } | |_^ the entire enum is at least 64008 bytes | note: boxing a variant would require the type no longer be `Copy` - --> tests/ui/large_enum_variant.rs:103:6 + --> tests/ui/large_enum_variant.rs:115:6 | LL | enum CopyableLargeEnum { | ^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> tests/ui/large_enum_variant.rs:105:5 + --> tests/ui/large_enum_variant.rs:118:5 | LL | B([u64; 8000]), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:108:1 + --> tests/ui/large_enum_variant.rs:121:1 | LL | / enum ManuallyCopyLargeEnum { +LL | | LL | | A(bool), | | ------- the second-largest variant contains at least 1 bytes LL | | B([u64; 8000]), @@ -206,20 +218,21 @@ LL | | } | |_^ the entire enum is at least 64008 bytes | note: boxing a variant would require the type no longer be `Copy` - --> tests/ui/large_enum_variant.rs:108:6 + --> tests/ui/large_enum_variant.rs:121:6 | LL | enum ManuallyCopyLargeEnum { | ^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> tests/ui/large_enum_variant.rs:110:5 + --> tests/ui/large_enum_variant.rs:124:5 | LL | B([u64; 8000]), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:121:1 + --> tests/ui/large_enum_variant.rs:135:1 | LL | / enum SomeGenericPossiblyCopyEnum { +LL | | LL | | A(bool, std::marker::PhantomData), | | ------------------------------------ the second-largest variant contains at least 1 bytes LL | | B([u64; 4000]), @@ -228,20 +241,21 @@ LL | | } | |_^ the entire enum is at least 32008 bytes | note: boxing a variant would require the type no longer be `Copy` - --> tests/ui/large_enum_variant.rs:121:6 + --> tests/ui/large_enum_variant.rs:135:6 | LL | enum SomeGenericPossiblyCopyEnum { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider boxing the large fields to reduce the total size of the enum - --> tests/ui/large_enum_variant.rs:123:5 + --> tests/ui/large_enum_variant.rs:138:5 | LL | B([u64; 4000]), | ^^^^^^^^^^^^^^ error: large size difference between variants - --> tests/ui/large_enum_variant.rs:134:1 + --> tests/ui/large_enum_variant.rs:149:1 | LL | / enum LargeEnumWithGenerics { +LL | | LL | | Small, | | ----- the second-largest variant carries no data at all LL | | Large((T, [u8; 512])), @@ -256,9 +270,10 @@ LL + Large(Box<(T, [u8; 512])>), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:143:1 + --> tests/ui/large_enum_variant.rs:159:1 | LL | / enum WithGenerics { +LL | | LL | | Large([Foo; 64]), | | --------------------- the largest variant contains at least 512 bytes LL | | Small(u8), @@ -273,9 +288,10 @@ LL + Large(Box<[Foo; 64]>), | error: large size difference between variants - --> tests/ui/large_enum_variant.rs:153:1 + --> tests/ui/large_enum_variant.rs:170:1 | LL | / enum LargeEnumOfConst { +LL | | LL | | Ok, | | -- the second-largest variant carries no data at all LL | | Error(PossiblyLargeEnumWithConst<256>), @@ -289,5 +305,77 @@ LL - Error(PossiblyLargeEnumWithConst<256>), LL + Error(Box>), | -error: aborting due to 16 previous errors +error: large size difference between variants + --> tests/ui/large_enum_variant.rs:176:1 + | +LL | / enum WithRecursion { +LL | | +LL | | Large([u64; 64]), + | | ---------------- the largest variant contains at least 512 bytes +LL | | Recursive(Box), + | | ----------------------------- the second-largest variant contains at least 8 bytes +LL | | } + | |_^ the entire enum is at least 520 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL - Large([u64; 64]), +LL + Large(Box<[u64; 64]>), + | + +error: large size difference between variants + --> tests/ui/large_enum_variant.rs:187:1 + | +LL | / enum LargeEnumWithGenericsAndRecursive { +LL | | +LL | | Ok(), + | | ---- the second-largest variant carries no data at all +LL | | Error(WithRecursionAndGenerics), + | | ------------------------------------ the largest variant contains at least 520 bytes +LL | | } + | |_^ the entire enum is at least 520 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL - Error(WithRecursionAndGenerics), +LL + Error(Box>), + | + +error: large size difference between variants + --> tests/ui/large_enum_variant.rs:223:5 + | +LL | / enum NoWarnings { +LL | | +LL | | BigBoi(PublishWithBytes), + | | ------------------------ the largest variant contains at least 296 bytes +LL | | _SmallBoi(u8), + | | ------------- the second-largest variant contains at least 1 bytes +LL | | } + | |_____^ the entire enum is at least 296 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL - BigBoi(PublishWithBytes), +LL + BigBoi(Box), + | + +error: large size difference between variants + --> tests/ui/large_enum_variant.rs:229:5 + | +LL | / enum MakesClippyAngry { +LL | | +LL | | BigBoi(PublishWithVec), + | | ---------------------- the largest variant contains at least 224 bytes +LL | | _SmallBoi(u8), + | | ------------- the second-largest variant contains at least 1 bytes +LL | | } + | |_____^ the entire enum is at least 224 bytes + | +help: consider boxing the large fields to reduce the total size of the enum + | +LL - BigBoi(PublishWithVec), +LL + BigBoi(Box), + | + +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/large_enum_variant.rs b/src/tools/clippy/tests/ui/large_enum_variant.rs index 3625c011dbfa1..9cf6318ca342b 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.rs +++ b/src/tools/clippy/tests/ui/large_enum_variant.rs @@ -1,6 +1,8 @@ -//@stderr-per-bitwidth +//@revisions: 32bit 64bit //@aux-build:proc_macros.rs //@no-rustfix +//@[32bit]ignore-bitwidth: 64 +//@[64bit]ignore-bitwidth: 32 #![allow(dead_code)] #![allow(unused_variables)] #![warn(clippy::large_enum_variant)] @@ -9,6 +11,7 @@ extern crate proc_macros; use proc_macros::external; enum LargeEnum { + //~^ large_enum_variant A(i32), B([i32; 8000]), } @@ -33,22 +36,26 @@ enum LargeEnumGeneric { } enum LargeEnum2 { + //~^ large_enum_variant VariantOk(i32, u32), ContainingLargeEnum(LargeEnum), } enum LargeEnum3 { + //~^ large_enum_variant ContainingMoreThanOneField(i32, [i32; 8000], [i32; 9500]), VoidVariant, StructLikeLittle { x: i32, y: i32 }, } enum LargeEnum4 { + //~^ large_enum_variant VariantOk(i32, u32), StructLikeLarge { x: [i32; 8000], y: i32 }, } enum LargeEnum5 { + //~^ large_enum_variant VariantOk(i32, u32), StructLikeLarge2 { x: [i32; 8000] }, } @@ -65,27 +72,32 @@ enum LargeEnum6 { } enum LargeEnum7 { + //~^ large_enum_variant A, B([u8; 1255]), C([u8; 200]), } enum LargeEnum8 { + //~^ large_enum_variant VariantOk(i32, u32), ContainingMoreThanOneField([i32; 8000], [i32; 2], [i32; 9500], [i32; 30]), } enum LargeEnum9 { + //~^ large_enum_variant A(Struct<()>), B(Struct2), } enum LargeEnumOk2 { + //~^ large_enum_variant A(T), B(Struct2), } enum LargeEnumOk3 { + //~^ large_enum_variant A(Struct), B(Struct2), } @@ -101,11 +113,13 @@ struct Struct2 { #[derive(Copy, Clone)] enum CopyableLargeEnum { + //~^ large_enum_variant A(bool), B([u64; 8000]), } enum ManuallyCopyLargeEnum { + //~^ large_enum_variant A(bool), B([u64; 8000]), } @@ -119,6 +133,7 @@ impl Clone for ManuallyCopyLargeEnum { impl Copy for ManuallyCopyLargeEnum {} enum SomeGenericPossiblyCopyEnum { + //~^ large_enum_variant A(bool, std::marker::PhantomData), B([u64; 4000]), } @@ -132,6 +147,7 @@ impl Clone for SomeGenericPossiblyCopyEnum { impl Copy for SomeGenericPossiblyCopyEnum {} enum LargeEnumWithGenerics { + //~^ large_enum_variant Small, Large((T, [u8; 512])), } @@ -141,6 +157,7 @@ struct Foo { } enum WithGenerics { + //~^ large_enum_variant Large([Foo; 64]), Small(u8), } @@ -151,10 +168,28 @@ enum PossiblyLargeEnumWithConst { } enum LargeEnumOfConst { + //~^ large_enum_variant Ok, Error(PossiblyLargeEnumWithConst<256>), } +enum WithRecursion { + //~^ large_enum_variant + Large([u64; 64]), + Recursive(Box), +} + +enum WithRecursionAndGenerics { + Large([T; 64]), + Recursive(Box>), +} + +enum LargeEnumWithGenericsAndRecursive { + //~^ large_enum_variant + Ok(), + Error(WithRecursionAndGenerics), +} + fn main() { external!( enum LargeEnumInMacro { @@ -163,3 +198,67 @@ fn main() { } ); } + +mod issue11915 { + use std::sync::atomic::AtomicPtr; + + pub struct Bytes { + ptr: *const u8, + len: usize, + // inlined "trait object" + data: AtomicPtr<()>, + vtable: &'static Vtable, + } + pub(crate) struct Vtable { + /// fn(data, ptr, len) + pub clone: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Bytes, + /// fn(data, ptr, len) + /// + /// takes `Bytes` to value + pub to_vec: unsafe fn(&AtomicPtr<()>, *const u8, usize) -> Vec, + /// fn(data, ptr, len) + pub drop: unsafe fn(&mut AtomicPtr<()>, *const u8, usize), + } + + enum NoWarnings { + //~[64bit]^ large_enum_variant + BigBoi(PublishWithBytes), + _SmallBoi(u8), + } + + enum MakesClippyAngry { + //~[64bit]^ large_enum_variant + BigBoi(PublishWithVec), + _SmallBoi(u8), + } + + struct PublishWithBytes { + _dup: bool, + _retain: bool, + _topic: Bytes, + __topic: Bytes, + ___topic: Bytes, + ____topic: Bytes, + _pkid: u16, + _payload: Bytes, + __payload: Bytes, + ___payload: Bytes, + ____payload: Bytes, + _____payload: Bytes, + } + + struct PublishWithVec { + _dup: bool, + _retain: bool, + _topic: Vec, + __topic: Vec, + ___topic: Vec, + ____topic: Vec, + _pkid: u16, + _payload: Vec, + __payload: Vec, + ___payload: Vec, + ____payload: Vec, + _____payload: Vec, + } +} diff --git a/src/tools/clippy/tests/ui/large_futures.fixed b/src/tools/clippy/tests/ui/large_futures.fixed index 1e87859f45263..c2159c58de1ec 100644 --- a/src/tools/clippy/tests/ui/large_futures.fixed +++ b/src/tools/clippy/tests/ui/large_futures.fixed @@ -8,21 +8,21 @@ async fn big_fut(_arg: [u8; 1024 * 16]) {} async fn wait() { let f = async { Box::pin(big_fut([0u8; 1024 * 16])).await; - //~^ ERROR: large future with a size of 16385 bytes - //~| NOTE: `-D clippy::large-futures` implied by `-D warnings` + //~^ large_futures }; Box::pin(f).await - //~^ ERROR: large future with a size of 16386 bytes + //~^ large_futures } async fn calls_fut(fut: impl std::future::Future) { loop { Box::pin(wait()).await; - //~^ ERROR: large future with a size of 16387 bytes + //~^ large_futures + if true { return fut.await; } else { Box::pin(wait()).await; - //~^ ERROR: large future with a size of 16387 bytes + //~^ large_futures } } } @@ -30,9 +30,10 @@ async fn calls_fut(fut: impl std::future::Future) { pub async fn test() { let fut = big_fut([0u8; 1024 * 16]); Box::pin(foo()).await; - //~^ ERROR: large future with a size of 65540 bytes + //~^ large_futures + Box::pin(calls_fut(fut)).await; - //~^ ERROR: large future with a size of 49159 bytes + //~^ large_futures } pub fn foo() -> impl std::future::Future { @@ -45,7 +46,8 @@ pub fn foo() -> impl std::future::Future { pub async fn lines() { Box::pin(async { - //~^ ERROR: large future with a size of 65540 bytes + //~^ large_futures + let x = [0i32; 1024 * 16]; async {}.await; println!("{:?}", x); @@ -57,6 +59,7 @@ pub async fn macro_expn() { macro_rules! macro_ { () => { Box::pin(async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; println!("macro: {:?}", x); diff --git a/src/tools/clippy/tests/ui/large_futures.rs b/src/tools/clippy/tests/ui/large_futures.rs index 3f4ea2ebf8bbe..567f6344afeac 100644 --- a/src/tools/clippy/tests/ui/large_futures.rs +++ b/src/tools/clippy/tests/ui/large_futures.rs @@ -8,21 +8,21 @@ async fn big_fut(_arg: [u8; 1024 * 16]) {} async fn wait() { let f = async { big_fut([0u8; 1024 * 16]).await; - //~^ ERROR: large future with a size of 16385 bytes - //~| NOTE: `-D clippy::large-futures` implied by `-D warnings` + //~^ large_futures }; f.await - //~^ ERROR: large future with a size of 16386 bytes + //~^ large_futures } async fn calls_fut(fut: impl std::future::Future) { loop { wait().await; - //~^ ERROR: large future with a size of 16387 bytes + //~^ large_futures + if true { return fut.await; } else { wait().await; - //~^ ERROR: large future with a size of 16387 bytes + //~^ large_futures } } } @@ -30,9 +30,10 @@ async fn calls_fut(fut: impl std::future::Future) { pub async fn test() { let fut = big_fut([0u8; 1024 * 16]); foo().await; - //~^ ERROR: large future with a size of 65540 bytes + //~^ large_futures + calls_fut(fut).await; - //~^ ERROR: large future with a size of 49159 bytes + //~^ large_futures } pub fn foo() -> impl std::future::Future { @@ -45,7 +46,8 @@ pub fn foo() -> impl std::future::Future { pub async fn lines() { async { - //~^ ERROR: large future with a size of 65540 bytes + //~^ large_futures + let x = [0i32; 1024 * 16]; async {}.await; println!("{:?}", x); @@ -57,6 +59,7 @@ pub async fn macro_expn() { macro_rules! macro_ { () => { async { + //~^ large_futures let x = [0i32; 1024 * 16]; async {}.await; println!("macro: {:?}", x); diff --git a/src/tools/clippy/tests/ui/large_futures.stderr b/src/tools/clippy/tests/ui/large_futures.stderr index 00082e579c597..fd6ba4e3563de 100644 --- a/src/tools/clippy/tests/ui/large_futures.stderr +++ b/src/tools/clippy/tests/ui/large_futures.stderr @@ -8,13 +8,13 @@ LL | big_fut([0u8; 1024 * 16]).await; = help: to override `-D warnings` add `#[allow(clippy::large_futures)]` error: large future with a size of 16386 bytes - --> tests/ui/large_futures.rs:14:5 + --> tests/ui/large_futures.rs:13:5 | LL | f.await | ^ help: consider `Box::pin` on it: `Box::pin(f)` error: large future with a size of 16387 bytes - --> tests/ui/large_futures.rs:19:9 + --> tests/ui/large_futures.rs:18:9 | LL | wait().await; | ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())` @@ -32,16 +32,17 @@ LL | foo().await; | ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())` error: large future with a size of 49159 bytes - --> tests/ui/large_futures.rs:34:5 + --> tests/ui/large_futures.rs:35:5 | LL | calls_fut(fut).await; | ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))` error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:47:5 + --> tests/ui/large_futures.rs:48:5 | LL | / async { LL | | +LL | | LL | | let x = [0i32; 1024 * 16]; LL | | async {}.await; LL | | println!("{:?}", x); @@ -52,6 +53,7 @@ help: consider `Box::pin` on it | LL ~ Box::pin(async { LL + +LL + LL + let x = [0i32; 1024 * 16]; LL + async {}.await; LL + println!("{:?}", x); @@ -59,9 +61,10 @@ LL + }) | error: large future with a size of 65540 bytes - --> tests/ui/large_futures.rs:59:13 + --> tests/ui/large_futures.rs:61:13 | LL | / async { +LL | | LL | | let x = [0i32; 1024 * 16]; LL | | async {}.await; LL | | println!("macro: {:?}", x); @@ -75,6 +78,7 @@ LL | macro_!().await help: consider `Box::pin` on it | LL ~ Box::pin(async { +LL + LL + let x = [0i32; 1024 * 16]; LL + async {}.await; LL + println!("macro: {:?}", x); diff --git a/src/tools/clippy/tests/ui/large_stack_frames.rs b/src/tools/clippy/tests/ui/large_stack_frames.rs index e6c030b8a9e80..3ed124f69ef35 100644 --- a/src/tools/clippy/tests/ui/large_stack_frames.rs +++ b/src/tools/clippy/tests/ui/large_stack_frames.rs @@ -25,7 +25,8 @@ impl Default for ArrayDefault { } fn many_small_arrays() { - //~^ ERROR: this function may allocate + //~^ large_stack_frames + let x = [0u8; 500_000]; let x2 = [0u8; 500_000]; let x3 = [0u8; 500_000]; @@ -35,18 +36,21 @@ fn many_small_arrays() { } fn large_return_value() -> ArrayDefault<1_000_000> { - //~^ ERROR: this function may allocate 1000000 bytes on the stack + //~^ large_stack_frames + Default::default() } fn large_fn_arg(x: ArrayDefault<1_000_000>) { - //~^ ERROR: this function may allocate + //~^ large_stack_frames + black_box(&x); } fn has_large_closure() { let f = || black_box(&[0u8; 1_000_000]); - //~^ ERROR: this function may allocate + //~^ large_stack_frames + f(); } diff --git a/src/tools/clippy/tests/ui/large_stack_frames.stderr b/src/tools/clippy/tests/ui/large_stack_frames.stderr index f2e0a127f5f50..0ff49e9f5b372 100644 --- a/src/tools/clippy/tests/ui/large_stack_frames.stderr +++ b/src/tools/clippy/tests/ui/large_stack_frames.stderr @@ -13,7 +13,7 @@ LL | let x5 = [0u8; 500_000]; = help: to override `-D warnings` add `#[allow(clippy::large_stack_frames)]` error: this function may allocate 1000000 bytes on the stack - --> tests/ui/large_stack_frames.rs:37:4 + --> tests/ui/large_stack_frames.rs:38:4 | LL | fn large_return_value() -> ArrayDefault<1_000_000> { | ^^^^^^^^^^^^^^^^^^ ----------------------- this is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>` @@ -21,7 +21,7 @@ LL | fn large_return_value() -> ArrayDefault<1_000_000> { = note: 1000000 bytes is larger than Clippy's configured `stack-size-threshold` of 512000 error: this function may allocate 100$PTR bytes on the stack - --> tests/ui/large_stack_frames.rs:42:4 + --> tests/ui/large_stack_frames.rs:44:4 | LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) { | ^^^^^^^^^^^^ - `x` is the largest part, at 1000000 bytes for type `ArrayDefault<1000000>` @@ -29,7 +29,7 @@ LL | fn large_fn_arg(x: ArrayDefault<1_000_000>) { = note: 100$PTR bytes is larger than Clippy's configured `stack-size-threshold` of 512000 error: this function may allocate 100$PTR bytes on the stack - --> tests/ui/large_stack_frames.rs:48:13 + --> tests/ui/large_stack_frames.rs:51:13 | LL | let f = || black_box(&[0u8; 1_000_000]); | ^^^^^^^^^^^^^^----------------^ diff --git a/src/tools/clippy/tests/ui/large_types_passed_by_value.rs b/src/tools/clippy/tests/ui/large_types_passed_by_value.rs index 78994a2988a22..562a46306e065 100644 --- a/src/tools/clippy/tests/ui/large_types_passed_by_value.rs +++ b/src/tools/clippy/tests/ui/large_types_passed_by_value.rs @@ -18,19 +18,25 @@ fn not_copy(a: Large) {} fn by_ref(a: &Large, b: &LargeAndCopy) {} fn mutable(mut a: LargeAndCopy) {} fn bad(a: LargeAndCopy) {} +//~^ large_types_passed_by_value pub fn bad_but_pub(a: LargeAndCopy) {} impl LargeAndCopy { fn self_is_ok(self) {} fn other_is_not_ok(self, other: LargeAndCopy) {} + //~^ large_types_passed_by_value fn unless_other_can_change(self, mut other: LargeAndCopy) {} pub fn or_were_in_public(self, other: LargeAndCopy) {} } trait LargeTypeDevourer { fn devoure_array(&self, array: [u8; 6666]); + //~^ large_types_passed_by_value fn devoure_tuple(&self, tup: (LargeAndCopy, LargeAndCopy)); + //~^ large_types_passed_by_value fn devoure_array_and_tuple_wow(&self, array: [u8; 6666], tup: (LargeAndCopy, LargeAndCopy)); + //~^ large_types_passed_by_value + //~| large_types_passed_by_value } pub trait PubLargeTypeDevourer { @@ -56,10 +62,12 @@ fn foo_always(x: LargeAndCopy) { } #[inline(never)] fn foo_never(x: LargeAndCopy) { + //~^ large_types_passed_by_value todo!(); } #[inline] fn foo(x: LargeAndCopy) { + //~^ large_types_passed_by_value todo!(); } diff --git a/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr b/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr index 5b42ab9e02ac4..0ad68bc326e02 100644 --- a/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr +++ b/src/tools/clippy/tests/ui/large_types_passed_by_value.stderr @@ -8,43 +8,43 @@ LL | fn bad(a: LargeAndCopy) {} = help: to override `-D warnings` add `#[allow(clippy::large_types_passed_by_value)]` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) - --> tests/ui/large_types_passed_by_value.rs:25:37 + --> tests/ui/large_types_passed_by_value.rs:26:37 | LL | fn other_is_not_ok(self, other: LargeAndCopy) {} | ^^^^^^^^^^^^ help: consider passing by reference instead: `&LargeAndCopy` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) - --> tests/ui/large_types_passed_by_value.rs:31:36 + --> tests/ui/large_types_passed_by_value.rs:33:36 | LL | fn devoure_array(&self, array: [u8; 6666]); | ^^^^^^^^^^ help: consider passing by reference instead: `&[u8; 6666]` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) - --> tests/ui/large_types_passed_by_value.rs:32:34 + --> tests/ui/large_types_passed_by_value.rs:35:34 | LL | fn devoure_tuple(&self, tup: (LargeAndCopy, LargeAndCopy)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider passing by reference instead: `&(LargeAndCopy, LargeAndCopy)` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) - --> tests/ui/large_types_passed_by_value.rs:33:50 + --> tests/ui/large_types_passed_by_value.rs:37:50 | LL | fn devoure_array_and_tuple_wow(&self, array: [u8; 6666], tup: (LargeAndCopy, LargeAndCopy)); | ^^^^^^^^^^ help: consider passing by reference instead: `&[u8; 6666]` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) - --> tests/ui/large_types_passed_by_value.rs:33:67 + --> tests/ui/large_types_passed_by_value.rs:37:67 | LL | fn devoure_array_and_tuple_wow(&self, array: [u8; 6666], tup: (LargeAndCopy, LargeAndCopy)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider passing by reference instead: `&(LargeAndCopy, LargeAndCopy)` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) - --> tests/ui/large_types_passed_by_value.rs:58:17 + --> tests/ui/large_types_passed_by_value.rs:64:17 | LL | fn foo_never(x: LargeAndCopy) { | ^^^^^^^^^^^^ help: consider passing by reference instead: `&LargeAndCopy` error: this argument (N byte) is passed by value, but might be more efficient if passed by reference (limit: N byte) - --> tests/ui/large_types_passed_by_value.rs:62:11 + --> tests/ui/large_types_passed_by_value.rs:69:11 | LL | fn foo(x: LargeAndCopy) { | ^^^^^^^^^^^^ help: consider passing by reference instead: `&LargeAndCopy` diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed index 3a2294ef4c59b..30bb549a9d654 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.fixed @@ -1,4 +1,5 @@ //@aux-build:proc_macros.rs +//@require-annotations-for-level: WARN #![allow(clippy::no_effect, deprecated, unused)] #![allow(clippy::legacy_numeric_constants)] // For imports. diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs index 6cb3e694ea145..d3878199055f5 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.rs +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.rs @@ -1,4 +1,5 @@ //@aux-build:proc_macros.rs +//@require-annotations-for-level: WARN #![allow(clippy::no_effect, deprecated, unused)] #![allow(clippy::legacy_numeric_constants)] // For imports. diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr index 91dfe79d55bab..4d69b8165a34b 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants.stderr @@ -1,5 +1,5 @@ error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:31:5 + --> tests/ui/legacy_numeric_constants.rs:32:5 | LL | std::f32::EPSILON; | ^^^^^^^^^^^^^^^^^ @@ -13,7 +13,7 @@ LL + f32::EPSILON; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:34:5 + --> tests/ui/legacy_numeric_constants.rs:35:5 | LL | std::u8::MIN; | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + u8::MIN; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:37:5 + --> tests/ui/legacy_numeric_constants.rs:38:5 | LL | std::usize::MIN; | ^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + usize::MIN; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:40:5 + --> tests/ui/legacy_numeric_constants.rs:41:5 | LL | std::u32::MAX; | ^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + u32::MAX; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:43:5 + --> tests/ui/legacy_numeric_constants.rs:44:5 | LL | core::u32::MAX; | ^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + u32::MAX; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:46:5 + --> tests/ui/legacy_numeric_constants.rs:47:5 | LL | MAX; | ^^^ @@ -72,7 +72,7 @@ LL | u32::MAX; | +++++ error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:49:10 + --> tests/ui/legacy_numeric_constants.rs:50:10 | LL | i32::max_value(); | ^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL + i32::MAX; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:52:9 + --> tests/ui/legacy_numeric_constants.rs:53:9 | LL | u8::max_value(); | ^^^^^^^^^^^ @@ -96,7 +96,7 @@ LL + u8::MAX; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:55:9 + --> tests/ui/legacy_numeric_constants.rs:56:9 | LL | u8::min_value(); | ^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + u8::MIN; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:58:5 + --> tests/ui/legacy_numeric_constants.rs:59:5 | LL | ::std::u8::MIN; | ^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + u8::MIN; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:61:27 + --> tests/ui/legacy_numeric_constants.rs:62:27 | LL | ::std::primitive::u8::min_value(); | ^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL + ::std::primitive::u8::MIN; | error: usage of a legacy numeric method - --> tests/ui/legacy_numeric_constants.rs:64:26 + --> tests/ui/legacy_numeric_constants.rs:65:26 | LL | std::primitive::i32::max_value(); | ^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL + std::primitive::i32::MAX; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:67:5 + --> tests/ui/legacy_numeric_constants.rs:68:5 | LL | self::a::u128::MAX; | ^^^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL + u128::MAX; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:17:25 + --> tests/ui/legacy_numeric_constants.rs:18:25 | LL | let x = std::u64::MAX; | ^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL + let x = u64::MAX; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:81:14 + --> tests/ui/legacy_numeric_constants.rs:82:14 | LL | [(0, "", std::i128::MAX)]; | ^^^^^^^^^^^^^^ @@ -184,7 +184,7 @@ LL + [(0, "", i128::MAX)]; | error: usage of a legacy numeric constant - --> tests/ui/legacy_numeric_constants.rs:115:5 + --> tests/ui/legacy_numeric_constants.rs:116:5 | LL | std::u32::MAX; | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs index 86738ede210cb..9bf0f7f355aee 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.rs @@ -1,4 +1,5 @@ //@no-rustfix +//@require-annotations-for-level: WARN //@aux-build:proc_macros.rs #![allow(clippy::no_effect, deprecated, unused)] #![warn(clippy::legacy_numeric_constants)] diff --git a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr index 2edcf71883627..96e6c9ef97598 100644 --- a/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr +++ b/src/tools/clippy/tests/ui/legacy_numeric_constants_unfixable.stderr @@ -1,5 +1,5 @@ error: importing legacy numeric constants - --> tests/ui/legacy_numeric_constants_unfixable.rs:9:5 + --> tests/ui/legacy_numeric_constants_unfixable.rs:10:5 | LL | use std::u128 as _; | ^^^^^^^^^ @@ -9,7 +9,7 @@ LL | use std::u128 as _; = 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:14:24 | LL | pub use std::{mem, u128}; | ^^^^ @@ -18,7 +18,7 @@ LL | pub use std::{mem, u128}; = 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:30:9 | LL | use std::u32::MAX; | ^^^^^^^^^^^^^ @@ -26,7 +26,7 @@ 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:33:9 | LL | use std::u8::MIN; | ^^^^^^^^^^^^ @@ -34,7 +34,7 @@ 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:37:9 | LL | use std::u32; | ^^^^^^^^ @@ -43,7 +43,7 @@ LL | use std::u32; = 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:41:9 | LL | use std::f32::MIN_POSITIVE; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:45:9 | LL | use std::i16::*; | ^^^^^^^^ @@ -59,7 +59,7 @@ 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:22:17 | LL | use std::u32; | ^^^^^^^^ @@ -72,7 +72,7 @@ LL | b!(); = 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 + --> tests/ui/legacy_numeric_constants_unfixable.rs:77:9 | LL | use std::u32::MAX; | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs index d623601110e27..011833072d762 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty.rs +++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs @@ -5,8 +5,8 @@ pub struct PubOne; impl PubOne { pub fn len(&self) -> isize { - //~^ ERROR: struct `PubOne` has a public `len` method, but no `is_empty` method - //~| NOTE: `-D clippy::len-without-is-empty` implied by `-D warnings` + //~^ len_without_is_empty + 1 } } @@ -55,7 +55,8 @@ impl PubAllowedStruct { } pub trait PubTraitsToo { - //~^ ERROR: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_empty` + //~^ len_without_is_empty + fn len(&self) -> isize; } @@ -69,7 +70,8 @@ pub struct HasIsEmpty; impl HasIsEmpty { pub fn len(&self) -> isize { - //~^ ERROR: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` me + //~^ len_without_is_empty + 1 } @@ -82,7 +84,8 @@ pub struct HasWrongIsEmpty; impl HasWrongIsEmpty { pub fn len(&self) -> isize { - //~^ ERROR: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` met + //~^ len_without_is_empty + 1 } @@ -95,7 +98,8 @@ pub struct MismatchedSelf; impl MismatchedSelf { pub fn len(self) -> isize { - //~^ ERROR: struct `MismatchedSelf` has a public `len` method, but the `is_empty` meth + //~^ len_without_is_empty + 1 } @@ -175,7 +179,8 @@ pub trait InheritingEmpty: Empty { pub trait Foo: Sized {} pub trait DependsOnFoo: Foo { - //~^ ERROR: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` + //~^ len_without_is_empty + fn len(&mut self) -> usize; } @@ -221,7 +226,8 @@ impl OptionalLen2 { pub struct OptionalLen3; impl OptionalLen3 { pub fn len(&self) -> usize { - //~^ ERROR: struct `OptionalLen3` has a public `len` method, but the `is_empty` method + //~^ len_without_is_empty + 0 } @@ -234,8 +240,9 @@ impl OptionalLen3 { pub struct ResultLen; impl ResultLen { pub fn len(&self) -> Result { - //~^ ERROR: struct `ResultLen` has a public `len` method, but the `is_empty` method ha - //~| ERROR: this returns a `Result<_, ()>` + //~^ len_without_is_empty + //~| result_unit_err + Ok(0) } @@ -248,12 +255,14 @@ impl ResultLen { pub struct ResultLen2; impl ResultLen2 { pub fn len(&self) -> Result { - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err + Ok(0) } pub fn is_empty(&self) -> Result { - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err + Ok(true) } } @@ -261,7 +270,8 @@ impl ResultLen2 { pub struct ResultLen3; impl ResultLen3 { pub fn len(&self) -> Result { - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err + Ok(0) } @@ -303,7 +313,8 @@ impl AsyncLenWithoutIsEmpty { } pub async fn len(&self) -> usize { - //~^ ERROR: struct `AsyncLenWithoutIsEmpty` has a public `len` method, but no `is_empt + //~^ len_without_is_empty + usize::from(!self.async_task().await) } } @@ -316,7 +327,8 @@ impl AsyncOptionLenWithoutIsEmpty { } pub async fn len(&self) -> Option { - //~^ ERROR: struct `AsyncOptionLenWithoutIsEmpty` has a public `len` method, but no `i + //~^ len_without_is_empty + None } } @@ -338,7 +350,8 @@ impl AsyncResultLenWithoutIsEmpty { } pub async fn len(&self) -> Result { - //~^ ERROR: struct `AsyncResultLenWithoutIsEmpty` has a public `len` method, but no `i + //~^ len_without_is_empty + Err(()) } } @@ -454,7 +467,8 @@ pub struct Aliased2; pub type Alias2 = Aliased2; impl Alias2 { pub fn len(&self) -> usize { - //~^ ERROR: type `Alias2` has a public `len` method, but no `is_empty` method + //~^ len_without_is_empty + todo!() } } diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.stderr b/src/tools/clippy/tests/ui/len_without_is_empty.stderr index 11d0d855fc0b8..748a55712f882 100644 --- a/src/tools/clippy/tests/ui/len_without_is_empty.stderr +++ b/src/tools/clippy/tests/ui/len_without_is_empty.stderr @@ -12,85 +12,87 @@ error: trait `PubTraitsToo` has a `len` method but no (possibly inherited) `is_e | LL | / pub trait PubTraitsToo { LL | | +LL | | LL | | fn len(&self) -> isize; LL | | } | |_^ error: struct `HasIsEmpty` has a public `len` method, but a private `is_empty` method - --> tests/ui/len_without_is_empty.rs:71:5 + --> tests/ui/len_without_is_empty.rs:72:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> tests/ui/len_without_is_empty.rs:76:5 + --> tests/ui/len_without_is_empty.rs:78:5 | LL | fn is_empty(&self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct `HasWrongIsEmpty` has a public `len` method, but the `is_empty` method has an unexpected signature - --> tests/ui/len_without_is_empty.rs:84:5 + --> tests/ui/len_without_is_empty.rs:86:5 | LL | pub fn len(&self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> tests/ui/len_without_is_empty.rs:89:5 + --> tests/ui/len_without_is_empty.rs:92:5 | LL | pub fn is_empty(&self, x: u32) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` error: struct `MismatchedSelf` has a public `len` method, but the `is_empty` method has an unexpected signature - --> tests/ui/len_without_is_empty.rs:97:5 + --> tests/ui/len_without_is_empty.rs:100:5 | LL | pub fn len(self) -> isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> tests/ui/len_without_is_empty.rs:102:5 + --> tests/ui/len_without_is_empty.rs:106:5 | LL | pub fn is_empty(&self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(self) -> bool` error: trait `DependsOnFoo` has a `len` method but no (possibly inherited) `is_empty` method - --> tests/ui/len_without_is_empty.rs:177:1 + --> tests/ui/len_without_is_empty.rs:181:1 | LL | / pub trait DependsOnFoo: Foo { LL | | +LL | | LL | | fn len(&mut self) -> usize; LL | | } | |_^ error: struct `OptionalLen3` has a public `len` method, but the `is_empty` method has an unexpected signature - --> tests/ui/len_without_is_empty.rs:223:5 + --> tests/ui/len_without_is_empty.rs:228:5 | LL | pub fn len(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> tests/ui/len_without_is_empty.rs:229:5 + --> tests/ui/len_without_is_empty.rs:235:5 | LL | pub fn is_empty(&self) -> Option { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` error: struct `ResultLen` has a public `len` method, but the `is_empty` method has an unexpected signature - --> tests/ui/len_without_is_empty.rs:236:5 + --> tests/ui/len_without_is_empty.rs:242:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `is_empty` defined here - --> tests/ui/len_without_is_empty.rs:243:5 + --> tests/ui/len_without_is_empty.rs:250:5 | LL | pub fn is_empty(&self) -> Option { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: expected signature: `(&self) -> bool` or `(&self) -> Result error: this returns a `Result<_, ()>` - --> tests/ui/len_without_is_empty.rs:236:5 + --> tests/ui/len_without_is_empty.rs:242:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +102,7 @@ LL | pub fn len(&self) -> Result { = help: to override `-D warnings` add `#[allow(clippy::result_unit_err)]` error: this returns a `Result<_, ()>` - --> tests/ui/len_without_is_empty.rs:250:5 + --> tests/ui/len_without_is_empty.rs:257:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +110,7 @@ LL | pub fn len(&self) -> Result { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> tests/ui/len_without_is_empty.rs:255:5 + --> tests/ui/len_without_is_empty.rs:263:5 | LL | pub fn is_empty(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -116,7 +118,7 @@ LL | pub fn is_empty(&self) -> Result { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> tests/ui/len_without_is_empty.rs:263:5 + --> tests/ui/len_without_is_empty.rs:272:5 | LL | pub fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,25 +126,25 @@ LL | pub fn len(&self) -> Result { = help: use a custom `Error` type instead error: struct `AsyncLenWithoutIsEmpty` has a public `len` method, but no `is_empty` method - --> tests/ui/len_without_is_empty.rs:305:5 + --> tests/ui/len_without_is_empty.rs:315:5 | LL | pub async fn len(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct `AsyncOptionLenWithoutIsEmpty` has a public `len` method, but no `is_empty` method - --> tests/ui/len_without_is_empty.rs:318:5 + --> tests/ui/len_without_is_empty.rs:329:5 | LL | pub async fn len(&self) -> Option { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: struct `AsyncResultLenWithoutIsEmpty` has a public `len` method, but no `is_empty` method - --> tests/ui/len_without_is_empty.rs:340:5 + --> tests/ui/len_without_is_empty.rs:352:5 | LL | pub async fn len(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: type `Alias2` has a public `len` method, but no `is_empty` method - --> tests/ui/len_without_is_empty.rs:456:5 + --> tests/ui/len_without_is_empty.rs:469:5 | LL | pub fn len(&self) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed index c9c476ba4214b..b8573ef13b0e8 100644 --- a/src/tools/clippy/tests/ui/len_zero.fixed +++ b/src/tools/clippy/tests/ui/len_zero.fixed @@ -86,10 +86,12 @@ impl Deref for DerefToString { fn main() { let x = [1, 2]; if x.is_empty() { + //~^ len_zero println!("This should not happen!"); } if "".is_empty() {} + //~^ len_zero let s = "Hello, world!"; let s1 = &s; @@ -99,16 +101,24 @@ fn main() { let s5 = &s4; let s6 = &s5; println!("{}", s1.is_empty()); + //~^ comparison_to_empty println!("{}", s2.is_empty()); + //~^ comparison_to_empty println!("{}", s3.is_empty()); + //~^ comparison_to_empty println!("{}", s4.is_empty()); + //~^ comparison_to_empty println!("{}", s5.is_empty()); + //~^ comparison_to_empty println!("{}", (s6).is_empty()); + //~^ comparison_to_empty let d2s = DerefToDerefToString {}; println!("{}", (**d2s).is_empty()); + //~^ comparison_to_empty println!("{}", std::borrow::Cow::Borrowed("").is_empty()); + //~^ comparison_to_empty let y = One; if y.len() == 0 { @@ -124,18 +134,23 @@ fn main() { let has_is_empty = HasIsEmpty; if has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if !has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if !has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if !has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if has_is_empty.len() > 1 { @@ -147,18 +162,23 @@ fn main() { println!("This can happen."); } if has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if !has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if !has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if !has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if has_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } if 1 < has_is_empty.len() { @@ -173,6 +193,7 @@ fn main() { let with_is_empty: &dyn WithIsEmpty = &Wither; if with_is_empty.is_empty() { + //~^ len_zero println!("Or this!"); } assert!(!with_is_empty.is_empty()); @@ -185,11 +206,14 @@ fn main() { // issue #10529 (!has_is_empty.is_empty()).then(|| println!("This can happen.")); + //~^ len_zero (has_is_empty.is_empty()).then(|| println!("Or this!")); + //~^ len_zero } fn test_slice(b: &[u8]) { if !b.is_empty() {} + //~^ len_zero } // issue #11992 @@ -224,9 +248,12 @@ fn binop_with_macros() { if has_is_empty.len() == compare_to!(1) {} if has_is_empty.is_empty() {} + //~^ len_zero if has_is_empty.is_empty() {} + //~^ len_zero (!has_is_empty.is_empty()).then(|| println!("This can happen.")); + //~^ len_zero } fn no_infinite_recursion() -> bool { diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs index 610a5448d10eb..ef3c49c1ab309 100644 --- a/src/tools/clippy/tests/ui/len_zero.rs +++ b/src/tools/clippy/tests/ui/len_zero.rs @@ -86,10 +86,12 @@ impl Deref for DerefToString { fn main() { let x = [1, 2]; if x.len() == 0 { + //~^ len_zero println!("This should not happen!"); } if "".len() == 0 {} + //~^ len_zero let s = "Hello, world!"; let s1 = &s; @@ -99,16 +101,24 @@ fn main() { let s5 = &s4; let s6 = &s5; println!("{}", *s1 == ""); + //~^ comparison_to_empty println!("{}", **s2 == ""); + //~^ comparison_to_empty println!("{}", ***s3 == ""); + //~^ comparison_to_empty println!("{}", ****s4 == ""); + //~^ comparison_to_empty println!("{}", *****s5 == ""); + //~^ comparison_to_empty println!("{}", ******(s6) == ""); + //~^ comparison_to_empty let d2s = DerefToDerefToString {}; println!("{}", &**d2s == ""); + //~^ comparison_to_empty println!("{}", std::borrow::Cow::Borrowed("") == ""); + //~^ comparison_to_empty let y = One; if y.len() == 0 { @@ -124,18 +134,23 @@ fn main() { let has_is_empty = HasIsEmpty; if has_is_empty.len() == 0 { + //~^ len_zero println!("Or this!"); } if has_is_empty.len() != 0 { + //~^ len_zero println!("Or this!"); } if has_is_empty.len() > 0 { + //~^ len_zero println!("Or this!"); } if has_is_empty.len() < 1 { + //~^ len_zero println!("Or this!"); } if has_is_empty.len() >= 1 { + //~^ len_zero println!("Or this!"); } if has_is_empty.len() > 1 { @@ -147,18 +162,23 @@ fn main() { println!("This can happen."); } if 0 == has_is_empty.len() { + //~^ len_zero println!("Or this!"); } if 0 != has_is_empty.len() { + //~^ len_zero println!("Or this!"); } if 0 < has_is_empty.len() { + //~^ len_zero println!("Or this!"); } if 1 <= has_is_empty.len() { + //~^ len_zero println!("Or this!"); } if 1 > has_is_empty.len() { + //~^ len_zero println!("Or this!"); } if 1 < has_is_empty.len() { @@ -173,6 +193,7 @@ fn main() { let with_is_empty: &dyn WithIsEmpty = &Wither; if with_is_empty.len() == 0 { + //~^ len_zero println!("Or this!"); } assert!(!with_is_empty.is_empty()); @@ -185,11 +206,14 @@ fn main() { // issue #10529 (has_is_empty.len() > 0).then(|| println!("This can happen.")); + //~^ len_zero (has_is_empty.len() == 0).then(|| println!("Or this!")); + //~^ len_zero } fn test_slice(b: &[u8]) { if b.len() != 0 {} + //~^ len_zero } // issue #11992 @@ -224,9 +248,12 @@ fn binop_with_macros() { if has_is_empty.len() == compare_to!(1) {} if has_is_empty.len() == compare_to!(0) {} + //~^ len_zero if has_is_empty.len() == zero!() {} + //~^ len_zero (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen.")); + //~^ len_zero } fn no_infinite_recursion() -> bool { diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr index 8d6b57e4b6d4a..25052f39ad33a 100644 --- a/src/tools/clippy/tests/ui/len_zero.stderr +++ b/src/tools/clippy/tests/ui/len_zero.stderr @@ -8,13 +8,13 @@ LL | if x.len() == 0 { = help: to override `-D warnings` add `#[allow(clippy::len_zero)]` error: length comparison to zero - --> tests/ui/len_zero.rs:92:8 + --> tests/ui/len_zero.rs:93:8 | LL | if "".len() == 0 {} | ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `"".is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:101:20 + --> tests/ui/len_zero.rs:103:20 | LL | println!("{}", *s1 == ""); | ^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s1.is_empty()` @@ -23,145 +23,145 @@ LL | println!("{}", *s1 == ""); = help: to override `-D warnings` add `#[allow(clippy::comparison_to_empty)]` error: comparison to empty slice - --> tests/ui/len_zero.rs:102:20 + --> tests/ui/len_zero.rs:105:20 | LL | println!("{}", **s2 == ""); | ^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s2.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:103:20 + --> tests/ui/len_zero.rs:107:20 | LL | println!("{}", ***s3 == ""); | ^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s3.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:104:20 + --> tests/ui/len_zero.rs:109:20 | LL | println!("{}", ****s4 == ""); | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s4.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:105:20 + --> tests/ui/len_zero.rs:111:20 | LL | println!("{}", *****s5 == ""); | ^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s5.is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:106:20 + --> tests/ui/len_zero.rs:113:20 | LL | println!("{}", ******(s6) == ""); | ^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(s6).is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:109:20 + --> tests/ui/len_zero.rs:117:20 | LL | println!("{}", &**d2s == ""); | ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()` error: comparison to empty slice - --> tests/ui/len_zero.rs:111:20 + --> tests/ui/len_zero.rs:120:20 | LL | println!("{}", std::borrow::Cow::Borrowed("") == ""); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `std::borrow::Cow::Borrowed("").is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:126:8 + --> tests/ui/len_zero.rs:136:8 | LL | if has_is_empty.len() == 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:129:8 + --> tests/ui/len_zero.rs:140:8 | LL | if has_is_empty.len() != 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:132:8 + --> tests/ui/len_zero.rs:144:8 | LL | if has_is_empty.len() > 0 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:135:8 + --> tests/ui/len_zero.rs:148:8 | LL | if has_is_empty.len() < 1 { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:138:8 + --> tests/ui/len_zero.rs:152:8 | LL | if has_is_empty.len() >= 1 { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:149:8 + --> tests/ui/len_zero.rs:164:8 | LL | if 0 == has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:152:8 + --> tests/ui/len_zero.rs:168:8 | LL | if 0 != has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:155:8 + --> tests/ui/len_zero.rs:172:8 | LL | if 0 < has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:158:8 + --> tests/ui/len_zero.rs:176:8 | LL | if 1 <= has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to one - --> tests/ui/len_zero.rs:161:8 + --> tests/ui/len_zero.rs:180:8 | LL | if 1 > has_is_empty.len() { | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:175:8 + --> tests/ui/len_zero.rs:195:8 | LL | if with_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:187:6 + --> tests/ui/len_zero.rs:208:6 | LL | (has_is_empty.len() > 0).then(|| println!("This can happen.")); | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:188:6 + --> tests/ui/len_zero.rs:210:6 | LL | (has_is_empty.len() == 0).then(|| println!("Or this!")); | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:192:8 + --> tests/ui/len_zero.rs:215:8 | LL | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()` error: length comparison to zero - --> tests/ui/len_zero.rs:226:8 + --> tests/ui/len_zero.rs:250: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:227:8 + --> tests/ui/len_zero.rs:252: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:229:6 + --> tests/ui/len_zero.rs:255: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()` diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.fixed b/src/tools/clippy/tests/ui/len_zero_ranges.fixed index 1fdeb2c7a37b9..d5b514d98113f 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.fixed +++ b/src/tools/clippy/tests/ui/len_zero_ranges.fixed @@ -5,10 +5,12 @@ mod issue_3807 { fn suggestion_is_fine_range() { let _ = (0..42).is_empty(); + //~^ len_zero } fn suggestion_is_fine_range_inclusive() { let _ = (0_u8..=42).is_empty(); + //~^ len_zero } } diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.rs b/src/tools/clippy/tests/ui/len_zero_ranges.rs index a5c9a969aaa65..98c97ca02457a 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.rs +++ b/src/tools/clippy/tests/ui/len_zero_ranges.rs @@ -5,10 +5,12 @@ mod issue_3807 { fn suggestion_is_fine_range() { let _ = (0..42).len() == 0; + //~^ len_zero } fn suggestion_is_fine_range_inclusive() { let _ = (0_u8..=42).len() == 0; + //~^ len_zero } } diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.stderr b/src/tools/clippy/tests/ui/len_zero_ranges.stderr index 0b2991e15ea32..10845bcade47d 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.stderr +++ b/src/tools/clippy/tests/ui/len_zero_ranges.stderr @@ -8,7 +8,7 @@ LL | let _ = (0..42).len() == 0; = help: to override `-D warnings` add `#[allow(clippy::len_zero)]` error: length comparison to zero - --> tests/ui/len_zero_ranges.rs:11:17 + --> tests/ui/len_zero_ranges.rs:12:17 | LL | let _ = (0_u8..=42).len() == 0; | ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(0_u8..=42).is_empty()` diff --git a/src/tools/clippy/tests/ui/let_and_return.edition2021.fixed b/src/tools/clippy/tests/ui/let_and_return.edition2021.fixed new file mode 100644 index 0000000000000..70d503018e0fe --- /dev/null +++ b/src/tools/clippy/tests/ui/let_and_return.edition2021.fixed @@ -0,0 +1,264 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +#![allow(unused)] +#![warn(clippy::let_and_return)] + +use std::cell::RefCell; + +fn test() -> i32 { + let _y = 0; // no warning + + 5 + //~^ let_and_return +} + +fn test_inner() -> i32 { + if true { + + 5 + //~^ let_and_return + } else { + 0 + } +} + +fn test_nowarn_1() -> i32 { + let mut x = 5; + x += 1; + x +} + +fn test_nowarn_2() -> i32 { + let x = 5; + x + 1 +} + +fn test_nowarn_3() -> (i32, i32) { + // this should technically warn, but we do not compare complex patterns + let (x, y) = (5, 9); + (x, y) +} + +fn test_nowarn_4() -> i32 { + // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type + let x: i32 = 5; + x +} + +fn test_nowarn_5(x: i16) -> u16 { + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let x = x as u16; + x +} + +// False positive example +trait Decode { + fn decode(d: D) -> Result + where + Self: Sized; +} + +macro_rules! tuple_encode { + ($($x:ident),*) => ( + impl<$($x: Decode),*> Decode for ($($x),*) { + #[inline] + #[allow(non_snake_case)] + fn decode(mut d: D) -> Result { + // Shouldn't trigger lint + Ok(($({let $x = Decode::decode(&mut d)?; $x }),*)) + } + } + ); +} + +fn issue_3792() -> String { + use std::io::{self, BufRead, Stdin}; + + let stdin = io::stdin(); + // `Stdin::lock` returns `StdinLock<'static>` so `line` doesn't borrow from `stdin` + // https://github.com/rust-lang/rust/pull/93965 + + stdin.lock().lines().next().unwrap().unwrap() + //~^ let_and_return +} + +tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); + +mod no_lint_if_stmt_borrows { + use std::cell::RefCell; + use std::rc::{Rc, Weak}; + struct Bar; + + impl Bar { + fn new() -> Self { + Bar {} + } + fn baz(&self) -> u32 { + 0 + } + } + + fn issue_3324(value: Weak>) -> u32 { + let value = value.upgrade().unwrap(); + let ret = value.borrow().baz(); + ret + //~[edition2024]^ let_and_return + } + + fn borrows_in_closure(value: Weak>) -> u32 { + fn f(mut x: impl FnMut() -> u32) -> impl FnMut() -> u32 { + x + } + + let value = value.upgrade().unwrap(); + let ret = f(|| value.borrow().baz())(); + ret + //~[edition2024]^ let_and_return + } + + mod free_function { + struct Inner; + + struct Foo<'a> { + inner: &'a Inner, + } + + impl Drop for Foo<'_> { + fn drop(&mut self) {} + } + + impl<'a> Foo<'a> { + fn new(inner: &'a Inner) -> Self { + Self { inner } + } + + fn value(&self) -> i32 { + 42 + } + } + + fn some_foo(inner: &Inner) -> Foo<'_> { + Foo { inner } + } + + fn test() -> i32 { + let x = Inner {}; + let value = some_foo(&x).value(); + value + //~[edition2024]^ let_and_return + } + + fn test2() -> i32 { + let x = Inner {}; + let value = Foo::new(&x).value(); + value + //~[edition2024]^ let_and_return + } + } +} + +mod issue_5729 { + use std::sync::Arc; + + trait Foo {} + + trait FooStorage { + fn foo_cloned(&self) -> Arc; + } + + struct FooStorageImpl { + foo: Arc, + } + + impl FooStorage for FooStorageImpl { + fn foo_cloned(&self) -> Arc { + + (Arc::clone(&self.foo)) as _ + //~^ let_and_return + } + } +} + +mod issue_11335 { + pub enum E { + A(T), + B(T), + } + + impl E { + pub fn inner(&self) -> &T { + + + (match self { + E::A(x) => x, + E::B(x) => x, + }) as _ + //~^ let_and_return + } + } +} + +// https://github.com/rust-lang/rust-clippy/issues/11167 +macro_rules! fn_in_macro { + ($b:block) => { + fn f() -> usize $b + } +} +fn_in_macro!({ + return 1; +}); + +fn issue9150() -> usize { + let x = 1; + #[cfg(any())] + panic!("can't see me"); + x +} + +fn issue12801() { + fn left_is_if() -> String { + + (if true { "a".to_string() } else { "b".to_string() } + "c") + //~^ let_and_return + } + + fn no_par_needed() -> String { + + "c".to_string() + if true { "a" } else { "b" } + //~^ let_and_return + } + + fn conjunctive_blocks() -> String { + + ({ "a".to_string() } + "b" + { "c" } + "d") + //~^ let_and_return + } + + #[allow(clippy::overly_complex_bool_expr)] + fn other_ops() { + let _ = || { + + (if true { 2 } else { 3 } << 4) + //~^ let_and_return + }; + let _ = || { + + ({ true } || { false } && { 2 <= 3 }) + //~^ let_and_return + }; + } +} + +fn issue14164() -> Result { + let v = std::cell::RefCell::new(Some(vec![1])); + let r = match &*v.borrow() { + Some(v) => Ok(Ok(v[0])), + None => Ok(Ok(0)), + }?; + r + //~[edition2024]^ let_and_return +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/let_and_return.edition2021.stderr b/src/tools/clippy/tests/ui/let_and_return.edition2021.stderr new file mode 100644 index 0000000000000..f9536d1b54776 --- /dev/null +++ b/src/tools/clippy/tests/ui/let_and_return.edition2021.stderr @@ -0,0 +1,152 @@ +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:13:5 + | +LL | let x = 5; + | ---------- unnecessary `let` binding +LL | x + | ^ + | + = note: `-D clippy::let-and-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]` +help: return the expression directly + | +LL ~ +LL ~ 5 + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:20:9 + | +LL | let x = 5; + | ---------- unnecessary `let` binding +LL | x + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ 5 + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:83:5 + | +LL | let line = stdin.lock().lines().next().unwrap().unwrap(); + | --------------------------------------------------------- unnecessary `let` binding +LL | line + | ^^^^ + | +help: return the expression directly + | +LL ~ +LL ~ stdin.lock().lines().next().unwrap().unwrap() + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:178:13 + | +LL | let clone = Arc::clone(&self.foo); + | ---------------------------------- unnecessary `let` binding +LL | clone + | ^^^^^ + | +help: return the expression directly + | +LL ~ +LL ~ (Arc::clone(&self.foo)) as _ + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:197:13 + | +LL | / let result = match self { +LL | | E::A(x) => x, +LL | | E::B(x) => x, +LL | | }; + | |______________- unnecessary `let` binding +LL | +LL | result + | ^^^^^^ + | +help: return the expression directly + | +LL ~ +LL | +LL ~ (match self { +LL + E::A(x) => x, +LL + E::B(x) => x, +LL + }) as _ + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:223:9 + | +LL | let s = if true { "a".to_string() } else { "b".to_string() } + "c"; + | ------------------------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ (if true { "a".to_string() } else { "b".to_string() } + "c") + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:229:9 + | +LL | let s = "c".to_string() + if true { "a" } else { "b" }; + | ------------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ "c".to_string() + if true { "a" } else { "b" } + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:235:9 + | +LL | let s = { "a".to_string() } + "b" + { "c" } + "d"; + | -------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ ({ "a".to_string() } + "b" + { "c" } + "d") + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:243:13 + | +LL | let s = if true { 2 } else { 3 } << 4; + | -------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ (if true { 2 } else { 3 } << 4) + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:248:13 + | +LL | let s = { true } || { false } && { 2 <= 3 }; + | -------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ ({ true } || { false } && { 2 <= 3 }) + | + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/let_and_return.edition2024.fixed b/src/tools/clippy/tests/ui/let_and_return.edition2024.fixed new file mode 100644 index 0000000000000..9990c3b712055 --- /dev/null +++ b/src/tools/clippy/tests/ui/let_and_return.edition2024.fixed @@ -0,0 +1,264 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +#![allow(unused)] +#![warn(clippy::let_and_return)] + +use std::cell::RefCell; + +fn test() -> i32 { + let _y = 0; // no warning + + 5 + //~^ let_and_return +} + +fn test_inner() -> i32 { + if true { + + 5 + //~^ let_and_return + } else { + 0 + } +} + +fn test_nowarn_1() -> i32 { + let mut x = 5; + x += 1; + x +} + +fn test_nowarn_2() -> i32 { + let x = 5; + x + 1 +} + +fn test_nowarn_3() -> (i32, i32) { + // this should technically warn, but we do not compare complex patterns + let (x, y) = (5, 9); + (x, y) +} + +fn test_nowarn_4() -> i32 { + // this should technically warn, but not b/c of clippy::let_and_return, but b/c of useless type + let x: i32 = 5; + x +} + +fn test_nowarn_5(x: i16) -> u16 { + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] + let x = x as u16; + x +} + +// False positive example +trait Decode { + fn decode(d: D) -> Result + where + Self: Sized; +} + +macro_rules! tuple_encode { + ($($x:ident),*) => ( + impl<$($x: Decode),*> Decode for ($($x),*) { + #[inline] + #[allow(non_snake_case)] + fn decode(mut d: D) -> Result { + // Shouldn't trigger lint + Ok(($({let $x = Decode::decode(&mut d)?; $x }),*)) + } + } + ); +} + +fn issue_3792() -> String { + use std::io::{self, BufRead, Stdin}; + + let stdin = io::stdin(); + // `Stdin::lock` returns `StdinLock<'static>` so `line` doesn't borrow from `stdin` + // https://github.com/rust-lang/rust/pull/93965 + + stdin.lock().lines().next().unwrap().unwrap() + //~^ let_and_return +} + +tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); + +mod no_lint_if_stmt_borrows { + use std::cell::RefCell; + use std::rc::{Rc, Weak}; + struct Bar; + + impl Bar { + fn new() -> Self { + Bar {} + } + fn baz(&self) -> u32 { + 0 + } + } + + fn issue_3324(value: Weak>) -> u32 { + let value = value.upgrade().unwrap(); + + value.borrow().baz() + //~[edition2024]^ let_and_return + } + + fn borrows_in_closure(value: Weak>) -> u32 { + fn f(mut x: impl FnMut() -> u32) -> impl FnMut() -> u32 { + x + } + + let value = value.upgrade().unwrap(); + + f(|| value.borrow().baz())() + //~[edition2024]^ let_and_return + } + + mod free_function { + struct Inner; + + struct Foo<'a> { + inner: &'a Inner, + } + + impl Drop for Foo<'_> { + fn drop(&mut self) {} + } + + impl<'a> Foo<'a> { + fn new(inner: &'a Inner) -> Self { + Self { inner } + } + + fn value(&self) -> i32 { + 42 + } + } + + fn some_foo(inner: &Inner) -> Foo<'_> { + Foo { inner } + } + + fn test() -> i32 { + let x = Inner {}; + + some_foo(&x).value() + //~[edition2024]^ let_and_return + } + + fn test2() -> i32 { + let x = Inner {}; + + Foo::new(&x).value() + //~[edition2024]^ let_and_return + } + } +} + +mod issue_5729 { + use std::sync::Arc; + + trait Foo {} + + trait FooStorage { + fn foo_cloned(&self) -> Arc; + } + + struct FooStorageImpl { + foo: Arc, + } + + impl FooStorage for FooStorageImpl { + fn foo_cloned(&self) -> Arc { + + (Arc::clone(&self.foo)) as _ + //~^ let_and_return + } + } +} + +mod issue_11335 { + pub enum E { + A(T), + B(T), + } + + impl E { + pub fn inner(&self) -> &T { + + + (match self { + E::A(x) => x, + E::B(x) => x, + }) as _ + //~^ let_and_return + } + } +} + +// https://github.com/rust-lang/rust-clippy/issues/11167 +macro_rules! fn_in_macro { + ($b:block) => { + fn f() -> usize $b + } +} +fn_in_macro!({ + return 1; +}); + +fn issue9150() -> usize { + let x = 1; + #[cfg(any())] + panic!("can't see me"); + x +} + +fn issue12801() { + fn left_is_if() -> String { + + (if true { "a".to_string() } else { "b".to_string() } + "c") + //~^ let_and_return + } + + fn no_par_needed() -> String { + + "c".to_string() + if true { "a" } else { "b" } + //~^ let_and_return + } + + fn conjunctive_blocks() -> String { + + ({ "a".to_string() } + "b" + { "c" } + "d") + //~^ let_and_return + } + + #[allow(clippy::overly_complex_bool_expr)] + fn other_ops() { + let _ = || { + + (if true { 2 } else { 3 } << 4) + //~^ let_and_return + }; + let _ = || { + + ({ true } || { false } && { 2 <= 3 }) + //~^ let_and_return + }; + } +} + +fn issue14164() -> Result { + let v = std::cell::RefCell::new(Some(vec![1])); + + match &*v.borrow() { + Some(v) => Ok(Ok(v[0])), + None => Ok(Ok(0)), + }? + //~[edition2024]^ let_and_return +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/let_and_return.edition2024.stderr b/src/tools/clippy/tests/ui/let_and_return.edition2024.stderr new file mode 100644 index 0000000000000..ca378fa432327 --- /dev/null +++ b/src/tools/clippy/tests/ui/let_and_return.edition2024.stderr @@ -0,0 +1,228 @@ +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:13:5 + | +LL | let x = 5; + | ---------- unnecessary `let` binding +LL | x + | ^ + | + = note: `-D clippy::let-and-return` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::let_and_return)]` +help: return the expression directly + | +LL ~ +LL ~ 5 + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:20:9 + | +LL | let x = 5; + | ---------- unnecessary `let` binding +LL | x + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ 5 + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:83:5 + | +LL | let line = stdin.lock().lines().next().unwrap().unwrap(); + | --------------------------------------------------------- unnecessary `let` binding +LL | line + | ^^^^ + | +help: return the expression directly + | +LL ~ +LL ~ stdin.lock().lines().next().unwrap().unwrap() + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:106:9 + | +LL | let ret = value.borrow().baz(); + | ------------------------------- unnecessary `let` binding +LL | ret + | ^^^ + | +help: return the expression directly + | +LL ~ +LL ~ value.borrow().baz() + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:117:9 + | +LL | let ret = f(|| value.borrow().baz())(); + | --------------------------------------- unnecessary `let` binding +LL | ret + | ^^^ + | +help: return the expression directly + | +LL ~ +LL ~ f(|| value.borrow().baz())() + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:149:13 + | +LL | let value = some_foo(&x).value(); + | --------------------------------- unnecessary `let` binding +LL | value + | ^^^^^ + | +help: return the expression directly + | +LL ~ +LL ~ some_foo(&x).value() + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:156:13 + | +LL | let value = Foo::new(&x).value(); + | --------------------------------- unnecessary `let` binding +LL | value + | ^^^^^ + | +help: return the expression directly + | +LL ~ +LL ~ Foo::new(&x).value() + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:178:13 + | +LL | let clone = Arc::clone(&self.foo); + | ---------------------------------- unnecessary `let` binding +LL | clone + | ^^^^^ + | +help: return the expression directly + | +LL ~ +LL ~ (Arc::clone(&self.foo)) as _ + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:197:13 + | +LL | / let result = match self { +LL | | E::A(x) => x, +LL | | E::B(x) => x, +LL | | }; + | |______________- unnecessary `let` binding +LL | +LL | result + | ^^^^^^ + | +help: return the expression directly + | +LL ~ +LL | +LL ~ (match self { +LL + E::A(x) => x, +LL + E::B(x) => x, +LL + }) as _ + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:223:9 + | +LL | let s = if true { "a".to_string() } else { "b".to_string() } + "c"; + | ------------------------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ (if true { "a".to_string() } else { "b".to_string() } + "c") + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:229:9 + | +LL | let s = "c".to_string() + if true { "a" } else { "b" }; + | ------------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ "c".to_string() + if true { "a" } else { "b" } + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:235:9 + | +LL | let s = { "a".to_string() } + "b" + { "c" } + "d"; + | -------------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ ({ "a".to_string() } + "b" + { "c" } + "d") + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:243:13 + | +LL | let s = if true { 2 } else { 3 } << 4; + | -------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ (if true { 2 } else { 3 } << 4) + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:248:13 + | +LL | let s = { true } || { false } && { 2 <= 3 }; + | -------------------------------------------- unnecessary `let` binding +LL | s + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ ({ true } || { false } && { 2 <= 3 }) + | + +error: returning the result of a `let` binding from a block + --> tests/ui/let_and_return.rs:260:5 + | +LL | / let r = match &*v.borrow() { +LL | | Some(v) => Ok(Ok(v[0])), +LL | | None => Ok(Ok(0)), +LL | | }?; + | |_______- unnecessary `let` binding +LL | r + | ^ + | +help: return the expression directly + | +LL ~ +LL ~ match &*v.borrow() { +LL + Some(v) => Ok(Ok(v[0])), +LL + None => Ok(Ok(0)), +LL + }? + | + +error: aborting due to 15 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 b68b41cdca237..e22e66eb522e6 100644 --- a/src/tools/clippy/tests/ui/let_and_return.fixed +++ b/src/tools/clippy/tests/ui/let_and_return.fixed @@ -244,4 +244,14 @@ fn issue12801() { } } +// Do not lint +fn issue14164() -> Result { + let v = std::cell::RefCell::new(Some(vec![1])); + let r = match &*v.borrow() { + Some(v) => Ok(Ok(v[0])), + None => Ok(Ok(0)), + }?; + r +} + 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 6b9035f942880..48c20cdd60dbe 100644 --- a/src/tools/clippy/tests/ui/let_and_return.rs +++ b/src/tools/clippy/tests/ui/let_and_return.rs @@ -1,3 +1,7 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + #![allow(unused)] #![warn(clippy::let_and_return)] @@ -7,15 +11,14 @@ fn test() -> i32 { let _y = 0; // no warning let x = 5; x - //~^ ERROR: returning the result of a `let` binding from a block - //~| NOTE: `-D clippy::let-and-return` implied by `-D warnings` + //~^ let_and_return } fn test_inner() -> i32 { if true { let x = 5; x - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } else { 0 } @@ -78,7 +81,7 @@ fn issue_3792() -> String { // https://github.com/rust-lang/rust/pull/93965 let line = stdin.lock().lines().next().unwrap().unwrap(); line - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); @@ -101,6 +104,7 @@ mod no_lint_if_stmt_borrows { let value = value.upgrade().unwrap(); let ret = value.borrow().baz(); ret + //~[edition2024]^ let_and_return } fn borrows_in_closure(value: Weak>) -> u32 { @@ -111,6 +115,7 @@ mod no_lint_if_stmt_borrows { let value = value.upgrade().unwrap(); let ret = f(|| value.borrow().baz())(); ret + //~[edition2024]^ let_and_return } mod free_function { @@ -142,12 +147,14 @@ mod no_lint_if_stmt_borrows { let x = Inner {}; let value = some_foo(&x).value(); value + //~[edition2024]^ let_and_return } fn test2() -> i32 { let x = Inner {}; let value = Foo::new(&x).value(); value + //~[edition2024]^ let_and_return } } } @@ -169,7 +176,7 @@ mod issue_5729 { fn foo_cloned(&self) -> Arc { let clone = Arc::clone(&self.foo); clone - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } } } @@ -188,7 +195,7 @@ mod issue_11335 { }; result - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } } } @@ -214,19 +221,19 @@ fn issue12801() { fn left_is_if() -> String { let s = if true { "a".to_string() } else { "b".to_string() } + "c"; s - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } fn no_par_needed() -> String { let s = "c".to_string() + if true { "a" } else { "b" }; s - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } fn conjunctive_blocks() -> String { let s = { "a".to_string() } + "b" + { "c" } + "d"; s - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return } #[allow(clippy::overly_complex_bool_expr)] @@ -234,14 +241,24 @@ fn issue12801() { let _ = || { let s = if true { 2 } else { 3 } << 4; s - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return }; let _ = || { let s = { true } || { false } && { 2 <= 3 }; s - //~^ ERROR: returning the result of a `let` binding from a block + //~^ let_and_return }; } } +fn issue14164() -> Result { + let v = std::cell::RefCell::new(Some(vec![1])); + let r = match &*v.borrow() { + Some(v) => Ok(Ok(v[0])), + None => Ok(Ok(0)), + }?; + r + //~[edition2024]^ let_and_return +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs index a29d35880b8df..2db206212aa5d 100644 --- a/src/tools/clippy/tests/ui/let_if_seq.rs +++ b/src/tools/clippy/tests/ui/let_if_seq.rs @@ -75,15 +75,15 @@ fn main() { issue985_alt(); let mut foo = 0; - //~^ ERROR: `if _ { .. } else { .. }` is an expression - //~| NOTE: you might not need `mut` at all + //~^ useless_let_if_seq + if f() { foo = 42; } let mut bar = 0; - //~^ ERROR: `if _ { .. } else { .. }` is an expression - //~| NOTE: you might not need `mut` at all + //~^ useless_let_if_seq + if f() { f(); bar = 42; @@ -92,7 +92,8 @@ fn main() { } let quz; - //~^ ERROR: `if _ { .. } else { .. }` is an expression + //~^ useless_let_if_seq + if f() { quz = 42; } else { @@ -122,8 +123,8 @@ fn main() { // baz needs to be mut let mut baz = 0; - //~^ ERROR: `if _ { .. } else { .. }` is an expression - //~| NOTE: you might not need `mut` at all + //~^ useless_let_if_seq + if f() { baz = 42; } diff --git a/src/tools/clippy/tests/ui/let_if_seq.stderr b/src/tools/clippy/tests/ui/let_if_seq.stderr index 41930108fb1ab..f59d42bf4c8dc 100644 --- a/src/tools/clippy/tests/ui/let_if_seq.stderr +++ b/src/tools/clippy/tests/ui/let_if_seq.stderr @@ -32,15 +32,15 @@ error: `if _ { .. } else { .. }` is an expression | LL | / let quz; LL | | +LL | | LL | | if f() { -LL | | quz = 42; -LL | | } else { +... | LL | | quz = 0; LL | | } | |_____^ help: it is more idiomatic to write: `let quz = if f() { 42 } else { 0 };` error: `if _ { .. } else { .. }` is an expression - --> tests/ui/let_if_seq.rs:124:5 + --> tests/ui/let_if_seq.rs:125:5 | LL | / let mut baz = 0; LL | | diff --git a/src/tools/clippy/tests/ui/let_underscore_future.rs b/src/tools/clippy/tests/ui/let_underscore_future.rs index c2185e9785d84..6347c792280e9 100644 --- a/src/tools/clippy/tests/ui/let_underscore_future.rs +++ b/src/tools/clippy/tests/ui/let_underscore_future.rs @@ -12,12 +12,13 @@ fn do_something_to_future(future: &mut impl Future) {} fn main() { let _ = some_async_fn(); - //~^ ERROR: non-binding `let` on a future + //~^ let_underscore_future + let _ = custom(); - //~^ ERROR: non-binding `let` on a future + //~^ let_underscore_future let mut future = some_async_fn(); do_something_to_future(&mut future); let _ = future; - //~^ ERROR: non-binding `let` on a future + //~^ let_underscore_future } diff --git a/src/tools/clippy/tests/ui/let_underscore_future.stderr b/src/tools/clippy/tests/ui/let_underscore_future.stderr index 66aeb5035394d..baa489551d4a3 100644 --- a/src/tools/clippy/tests/ui/let_underscore_future.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_future.stderr @@ -9,7 +9,7 @@ LL | let _ = some_async_fn(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_future)]` error: non-binding `let` on a future - --> tests/ui/let_underscore_future.rs:16:5 + --> tests/ui/let_underscore_future.rs:17:5 | LL | let _ = custom(); | ^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = custom(); = help: consider awaiting the future or dropping explicitly with `std::mem::drop` error: non-binding `let` on a future - --> tests/ui/let_underscore_future.rs:21:5 + --> tests/ui/let_underscore_future.rs:22:5 | LL | let _ = future; | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.rs b/src/tools/clippy/tests/ui/let_underscore_must_use.rs index 3290d087724e6..5cf31ec63c66f 100644 --- a/src/tools/clippy/tests/ui/let_underscore_must_use.rs +++ b/src/tools/clippy/tests/ui/let_underscore_must_use.rs @@ -65,42 +65,47 @@ impl Trait for S { fn main() { let _ = f(); - //~^ ERROR: non-binding `let` on a result of a `#[must_use]` function + //~^ let_underscore_must_use + let _ = g(); - //~^ ERROR: non-binding `let` on an expression with `#[must_use]` type + //~^ let_underscore_must_use + let _ = h(); let _ = l(0_u32); - //~^ ERROR: non-binding `let` on a result of a `#[must_use]` function + //~^ let_underscore_must_use let s = S {}; let _ = s.f(); - //~^ ERROR: non-binding `let` on a result of a `#[must_use]` function + //~^ let_underscore_must_use + let _ = s.g(); - //~^ ERROR: non-binding `let` on an expression with `#[must_use]` type + //~^ let_underscore_must_use + let _ = s.k(); let _ = S::h(); - //~^ ERROR: non-binding `let` on a result of a `#[must_use]` function + //~^ let_underscore_must_use + let _ = S::p(); - //~^ ERROR: non-binding `let` on an expression with `#[must_use]` type + //~^ let_underscore_must_use let _ = S::a(); - //~^ ERROR: non-binding `let` on a result of a `#[must_use]` function + //~^ let_underscore_must_use let _ = if true { Ok(()) } else { Err(()) }; - //~^ ERROR: non-binding `let` on an expression with `#[must_use]` type + //~^ let_underscore_must_use let a = Result::<(), ()>::Ok(()); let _ = a.is_ok(); - //~^ ERROR: non-binding `let` on a result of a `#[must_use]` function + //~^ let_underscore_must_use let _ = a.map(|_| ()); - //~^ ERROR: non-binding `let` on an expression with `#[must_use]` type + //~^ let_underscore_must_use let _ = a; - //~^ ERROR: non-binding `let` on an expression with `#[must_use]` type + //~^ let_underscore_must_use #[allow(clippy::let_underscore_must_use)] let _ = a; diff --git a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr index e8785b92b8158..130ea11646fd1 100644 --- a/src/tools/clippy/tests/ui/let_underscore_must_use.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_must_use.stderr @@ -9,7 +9,7 @@ LL | let _ = f(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_must_use)]` error: non-binding `let` on an expression with `#[must_use]` type - --> tests/ui/let_underscore_must_use.rs:69:5 + --> tests/ui/let_underscore_must_use.rs:70:5 | LL | let _ = g(); | ^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = g(); = help: consider explicitly using expression value error: non-binding `let` on a result of a `#[must_use]` function - --> tests/ui/let_underscore_must_use.rs:72:5 + --> tests/ui/let_underscore_must_use.rs:74:5 | LL | let _ = l(0_u32); | ^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = l(0_u32); = help: consider explicitly using function result error: non-binding `let` on a result of a `#[must_use]` function - --> tests/ui/let_underscore_must_use.rs:77:5 + --> tests/ui/let_underscore_must_use.rs:79:5 | LL | let _ = s.f(); | ^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | let _ = s.f(); = help: consider explicitly using function result error: non-binding `let` on an expression with `#[must_use]` type - --> tests/ui/let_underscore_must_use.rs:79:5 + --> tests/ui/let_underscore_must_use.rs:82:5 | LL | let _ = s.g(); | ^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | let _ = s.g(); = help: consider explicitly using expression value error: non-binding `let` on a result of a `#[must_use]` function - --> tests/ui/let_underscore_must_use.rs:83:5 + --> tests/ui/let_underscore_must_use.rs:87:5 | LL | let _ = S::h(); | ^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let _ = S::h(); = help: consider explicitly using function result error: non-binding `let` on an expression with `#[must_use]` type - --> tests/ui/let_underscore_must_use.rs:85:5 + --> tests/ui/let_underscore_must_use.rs:90:5 | LL | let _ = S::p(); | ^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | let _ = S::p(); = help: consider explicitly using expression value error: non-binding `let` on a result of a `#[must_use]` function - --> tests/ui/let_underscore_must_use.rs:88:5 + --> tests/ui/let_underscore_must_use.rs:93:5 | LL | let _ = S::a(); | ^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = S::a(); = help: consider explicitly using function result error: non-binding `let` on an expression with `#[must_use]` type - --> tests/ui/let_underscore_must_use.rs:91:5 + --> tests/ui/let_underscore_must_use.rs:96:5 | LL | let _ = if true { Ok(()) } else { Err(()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let _ = if true { Ok(()) } else { Err(()) }; = help: consider explicitly using expression value error: non-binding `let` on a result of a `#[must_use]` function - --> tests/ui/let_underscore_must_use.rs:96:5 + --> tests/ui/let_underscore_must_use.rs:101:5 | LL | let _ = a.is_ok(); | ^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _ = a.is_ok(); = help: consider explicitly using function result error: non-binding `let` on an expression with `#[must_use]` type - --> tests/ui/let_underscore_must_use.rs:99:5 + --> tests/ui/let_underscore_must_use.rs:104:5 | LL | let _ = a.map(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _ = a.map(|_| ()); = help: consider explicitly using expression value error: non-binding `let` on an expression with `#[must_use]` type - --> tests/ui/let_underscore_must_use.rs:102:5 + --> tests/ui/let_underscore_must_use.rs:107:5 | LL | let _ = a; | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs index 6275b6f970a1c..26ba8682dc2d5 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.rs +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs @@ -49,11 +49,16 @@ with_span!( fn main() { let _ = a(); + //~^ let_underscore_untyped let _ = b(1); + //~^ let_underscore_untyped let _ = c(); let _ = d(&1); + //~^ let_underscore_untyped let _ = e(); + //~^ let_underscore_untyped let _ = f(); + //~^ let_underscore_untyped let _ = g(); let closure = || {}; diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr index 1dd51e1e59b10..86cdd5c662cc1 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr @@ -13,49 +13,49 @@ LL | let _ = a(); = help: to override `-D warnings` add `#[allow(clippy::let_underscore_untyped)]` error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:52:5 + --> tests/ui/let_underscore_untyped.rs:53:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:52:10 + --> tests/ui/let_underscore_untyped.rs:53:10 | LL | let _ = b(1); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:54:5 + --> tests/ui/let_underscore_untyped.rs:56:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:54:10 + --> tests/ui/let_underscore_untyped.rs:56:10 | LL | let _ = d(&1); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:55:5 + --> tests/ui/let_underscore_untyped.rs:58:5 | LL | let _ = e(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:55:10 + --> tests/ui/let_underscore_untyped.rs:58:10 | LL | let _ = e(); | ^ error: non-binding `let` without a type annotation - --> tests/ui/let_underscore_untyped.rs:56:5 + --> tests/ui/let_underscore_untyped.rs:60:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> tests/ui/let_underscore_untyped.rs:56:10 + --> tests/ui/let_underscore_untyped.rs:60:10 | LL | let _ = f(); | ^ diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed index 3456e274f6a4d..5e7a2ad37a846 100644 --- a/src/tools/clippy/tests/ui/let_unit.fixed +++ b/src/tools/clippy/tests/ui/let_unit.fixed @@ -9,6 +9,7 @@ macro_rules! let_and_return { fn main() { println!("x"); + //~^ let_unit_value let _y = 1; // this is fine let _z = ((), 1); // this as well if true { @@ -57,6 +58,7 @@ fn multiline_sugg() { let v: Vec = vec![2]; v + //~^ let_unit_value .into_iter() .map(|i| i * 2) .filter(|i| i % 2 == 0) @@ -106,6 +108,7 @@ fn _returns_generic() { let x: () = if true { f() } else { f2(0) }; match Some(0) { + //~^ let_unit_value None => f2(1), Some(0) => f(), Some(1) => f2(3), @@ -187,6 +190,7 @@ pub fn issue12594() { fn actual_test() { // create first a unit value'd value returns_unit(); + //~^ let_unit_value returns_result(()).unwrap(); returns_result(()).unwrap(); // make sure we replace only the first variable diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs index e2dafbcb77146..7b06f6940121d 100644 --- a/src/tools/clippy/tests/ui/let_unit.rs +++ b/src/tools/clippy/tests/ui/let_unit.rs @@ -9,6 +9,7 @@ macro_rules! let_and_return { fn main() { let _x = println!("x"); + //~^ let_unit_value let _y = 1; // this is fine let _z = ((), 1); // this as well if true { @@ -57,6 +58,7 @@ fn multiline_sugg() { let v: Vec = vec![2]; let _ = v + //~^ let_unit_value .into_iter() .map(|i| i * 2) .filter(|i| i % 2 == 0) @@ -106,6 +108,7 @@ fn _returns_generic() { let x: () = if true { f() } else { f2(0) }; let x = match Some(0) { + //~^ let_unit_value None => f2(1), Some(0) => f(), Some(1) => f2(3), @@ -187,6 +190,7 @@ pub fn issue12594() { fn actual_test() { // create first a unit value'd value let res = returns_unit(); + //~^ let_unit_value returns_result(res).unwrap(); returns_result(res).unwrap(); // make sure we replace only the first variable diff --git a/src/tools/clippy/tests/ui/let_unit.stderr b/src/tools/clippy/tests/ui/let_unit.stderr index a2f368f22e5bb..d7d01d304cad2 100644 --- a/src/tools/clippy/tests/ui/let_unit.stderr +++ b/src/tools/clippy/tests/ui/let_unit.stderr @@ -8,13 +8,13 @@ LL | let _x = println!("x"); = help: to override `-D warnings` add `#[allow(clippy::let_unit_value)]` error: this let-binding has unit value - --> tests/ui/let_unit.rs:59:5 + --> tests/ui/let_unit.rs:60:5 | LL | / let _ = v +LL | | LL | | .into_iter() LL | | .map(|i| i * 2) -LL | | .filter(|i| i % 2 == 0) -LL | | .map(|_| ()) +... | LL | | .next() LL | | .unwrap(); | |__________________^ @@ -22,6 +22,7 @@ LL | | .unwrap(); help: omit the `let` binding | LL ~ v +LL + LL + .into_iter() LL + .map(|i| i * 2) LL + .filter(|i| i % 2 == 0) @@ -31,9 +32,10 @@ LL + .unwrap(); | error: this let-binding has unit value - --> tests/ui/let_unit.rs:108:5 + --> tests/ui/let_unit.rs:110:5 | LL | / let x = match Some(0) { +LL | | LL | | None => f2(1), LL | | Some(0) => f(), LL | | Some(1) => f2(3), @@ -44,6 +46,7 @@ LL | | }; help: omit the `let` binding | LL ~ match Some(0) { +LL + LL + None => f2(1), LL + Some(0) => f(), LL + Some(1) => f2(3), @@ -52,7 +55,7 @@ LL + }; | error: this let-binding has unit value - --> tests/ui/let_unit.rs:189:9 + --> tests/ui/let_unit.rs:192:9 | LL | let res = returns_unit(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,6 +63,7 @@ LL | let res = returns_unit(); help: omit the `let` binding and replace variable usages with `()` | LL ~ returns_unit(); +LL | LL ~ returns_result(()).unwrap(); LL ~ returns_result(()).unwrap(); | diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.rs b/src/tools/clippy/tests/ui/let_with_type_underscore.rs index ae1a480bcfc55..a7c2f598b56df 100644 --- a/src/tools/clippy/tests/ui/let_with_type_underscore.rs +++ b/src/tools/clippy/tests/ui/let_with_type_underscore.rs @@ -13,9 +13,13 @@ fn func() -> &'static str { fn main() { // Will lint let x: _ = 1; + //~^ let_with_type_underscore let _: _ = 2; + //~^ let_with_type_underscore let x: _ = func(); + //~^ let_with_type_underscore let x: _; + //~^ let_with_type_underscore x = (); let x = 1; // Will not lint, Rust infers this to an integer before Clippy @@ -23,6 +27,7 @@ fn main() { let x: Vec<_> = Vec::::new(); let x: [_; 1] = [1]; let x : _ = 1; + //~^ let_with_type_underscore // Do not lint from procedural macros proc_macros::with_span! { diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr index 29ec25a5b2acc..2284d1fe2e48a 100644 --- a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr +++ b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr @@ -13,49 +13,49 @@ LL | let x: _ = 1; = help: to override `-D warnings` add `#[allow(clippy::let_with_type_underscore)]` error: variable declared with type underscore - --> tests/ui/let_with_type_underscore.rs:16:5 + --> tests/ui/let_with_type_underscore.rs:17:5 | LL | let _: _ = 2; | ^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:16:10 + --> tests/ui/let_with_type_underscore.rs:17:10 | LL | let _: _ = 2; | ^^^ error: variable declared with type underscore - --> tests/ui/let_with_type_underscore.rs:17:5 + --> tests/ui/let_with_type_underscore.rs:19:5 | LL | let x: _ = func(); | ^^^^^^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:17:10 + --> tests/ui/let_with_type_underscore.rs:19:10 | LL | let x: _ = func(); | ^^^ error: variable declared with type underscore - --> tests/ui/let_with_type_underscore.rs:18:5 + --> tests/ui/let_with_type_underscore.rs:21:5 | LL | let x: _; | ^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:18:10 + --> tests/ui/let_with_type_underscore.rs:21:10 | LL | let x: _; | ^^^ error: variable declared with type underscore - --> tests/ui/let_with_type_underscore.rs:25:5 + --> tests/ui/let_with_type_underscore.rs:29:5 | LL | let x : _ = 1; | ^^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> tests/ui/let_with_type_underscore.rs:25:10 + --> tests/ui/let_with_type_underscore.rs:29:10 | LL | let x : _ = 1; | ^^^^ diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed b/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed index 621115cc13258..977e31c744a2c 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed @@ -7,20 +7,26 @@ fn main() -> io::Result<()> { let f = std::fs::File::open("/")?; // Lint BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().map_while(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok let s = "foo\nbar\nbaz\n"; // Lint io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint io::stdin().lines().map_while(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Do not lint (not a `Lines` iterator) io::stdin() .lines() @@ -31,3 +37,10 @@ fn main() -> io::Result<()> { io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ()); Ok(()) } + +#[clippy::msrv = "1.56"] +fn msrv_check() { + let _lines = BufReader::new(std::fs::File::open("some-path").unwrap()) + .lines() + .filter_map(Result::ok); +} diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.rs b/src/tools/clippy/tests/ui/lines_filter_map_ok.rs index a86efbd668623..2196075bc4455 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.rs +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.rs @@ -7,20 +7,26 @@ fn main() -> io::Result<()> { let f = std::fs::File::open("/")?; // Lint BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint let f = std::fs::File::open("/")?; BufReader::new(f).lines().flatten().for_each(|_| ()); + //~^ lines_filter_map_ok let s = "foo\nbar\nbaz\n"; // Lint io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); + //~^ lines_filter_map_ok // Lint io::stdin().lines().flatten().for_each(|_| ()); + //~^ lines_filter_map_ok // Do not lint (not a `Lines` iterator) io::stdin() .lines() @@ -31,3 +37,10 @@ fn main() -> io::Result<()> { io::stdin().lines().filter_map(|x| x.err()).for_each(|_| ()); Ok(()) } + +#[clippy::msrv = "1.56"] +fn msrv_check() { + let _lines = BufReader::new(std::fs::File::open("some-path").unwrap()) + .lines() + .filter_map(Result::ok); +} diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr b/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr index 558c0532be95a..f9038eec9fb21 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.stderr @@ -13,61 +13,61 @@ LL | BufReader::new(f).lines().filter_map(Result::ok).for_each(|_| ()); = help: to override `-D warnings` add `#[allow(clippy::lines_filter_map_ok)]` error: `flat_map()` will run forever if the iterator repeatedly produces an `Err` - --> tests/ui/lines_filter_map_ok.rs:12:31 + --> tests/ui/lines_filter_map_ok.rs:13:31 | LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> tests/ui/lines_filter_map_ok.rs:12:5 + --> tests/ui/lines_filter_map_ok.rs:13:5 | LL | BufReader::new(f).lines().flat_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `flatten()` will run forever if the iterator repeatedly produces an `Err` - --> tests/ui/lines_filter_map_ok.rs:15:31 + --> tests/ui/lines_filter_map_ok.rs:17:31 | LL | BufReader::new(f).lines().flatten().for_each(|_| ()); | ^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> tests/ui/lines_filter_map_ok.rs:15:5 + --> tests/ui/lines_filter_map_ok.rs:17:5 | LL | BufReader::new(f).lines().flatten().for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` - --> tests/ui/lines_filter_map_ok.rs:19:25 + --> tests/ui/lines_filter_map_ok.rs:22:25 | LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> tests/ui/lines_filter_map_ok.rs:19:5 + --> tests/ui/lines_filter_map_ok.rs:22:5 | LL | io::stdin().lines().filter_map(Result::ok).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^ error: `filter_map()` will run forever if the iterator repeatedly produces an `Err` - --> tests/ui/lines_filter_map_ok.rs:21:25 + --> tests/ui/lines_filter_map_ok.rs:25:25 | LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> tests/ui/lines_filter_map_ok.rs:21:5 + --> tests/ui/lines_filter_map_ok.rs:25:5 | LL | io::stdin().lines().filter_map(|x| x.ok()).for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^ error: `flatten()` will run forever if the iterator repeatedly produces an `Err` - --> tests/ui/lines_filter_map_ok.rs:23:25 + --> tests/ui/lines_filter_map_ok.rs:28:25 | LL | io::stdin().lines().flatten().for_each(|_| ()); | ^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error - --> tests/ui/lines_filter_map_ok.rs:23:5 + --> tests/ui/lines_filter_map_ok.rs:28:5 | LL | io::stdin().lines().flatten().for_each(|_| ()); | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/linkedlist.rs b/src/tools/clippy/tests/ui/linkedlist.rs index e1e6cff980979..64a9ba0029da4 100644 --- a/src/tools/clippy/tests/ui/linkedlist.rs +++ b/src/tools/clippy/tests/ui/linkedlist.rs @@ -6,17 +6,20 @@ extern crate alloc; use alloc::collections::linked_list::LinkedList; const C: LinkedList = LinkedList::new(); -//~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data structu +//~^ linkedlist + static S: LinkedList = LinkedList::new(); -//~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data structu +//~^ linkedlist trait Foo { type Baz = LinkedList; - //~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data str + //~^ linkedlist + fn foo(_: LinkedList); - //~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data str + //~^ linkedlist + const BAR: Option>; - //~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data str + //~^ linkedlist } // Ok, we don’t want to warn for implementations; see issue #605. @@ -27,20 +30,22 @@ impl Foo for LinkedList { pub struct Bar { priv_linked_list_field: LinkedList, - //~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data str + //~^ linkedlist pub pub_linked_list_field: LinkedList, } impl Bar { fn foo(_: LinkedList) {} - //~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data str + //~^ linkedlist } // All of these test should be trigger the lint because they are not // part of the public api fn test(my_favorite_linked_list: LinkedList) {} -//~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data structu +//~^ linkedlist + fn test_ret() -> Option> { - //~^ ERROR: you seem to be using a `LinkedList`! Perhaps you meant some other data structu + //~^ linkedlist + None } fn test_local_not_linted() { diff --git a/src/tools/clippy/tests/ui/linkedlist.stderr b/src/tools/clippy/tests/ui/linkedlist.stderr index d19176c7b0d21..419fbcc7e1884 100644 --- a/src/tools/clippy/tests/ui/linkedlist.stderr +++ b/src/tools/clippy/tests/ui/linkedlist.stderr @@ -9,7 +9,7 @@ LL | const C: LinkedList = LinkedList::new(); = help: to override `-D warnings` add `#[allow(clippy::linkedlist)]` error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:10:11 + --> tests/ui/linkedlist.rs:11:11 | LL | static S: LinkedList = LinkedList::new(); | ^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | static S: LinkedList = LinkedList::new(); = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:14:16 + --> tests/ui/linkedlist.rs:15:16 | LL | type Baz = LinkedList; | ^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | type Baz = LinkedList; = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:16:15 + --> tests/ui/linkedlist.rs:18:15 | LL | fn foo(_: LinkedList); | ^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | fn foo(_: LinkedList); = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:18:23 + --> tests/ui/linkedlist.rs:21:23 | LL | const BAR: Option>; | ^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | const BAR: Option>; = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:29:29 + --> tests/ui/linkedlist.rs:32:29 | LL | priv_linked_list_field: LinkedList, | ^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | priv_linked_list_field: LinkedList, = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:34:15 + --> tests/ui/linkedlist.rs:37:15 | LL | fn foo(_: LinkedList) {} | ^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | fn foo(_: LinkedList) {} = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:40:34 + --> tests/ui/linkedlist.rs:43:34 | LL | fn test(my_favorite_linked_list: LinkedList) {} | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | fn test(my_favorite_linked_list: LinkedList) {} = help: a `VecDeque` might work error: you seem to be using a `LinkedList`! Perhaps you meant some other data structure? - --> tests/ui/linkedlist.rs:42:25 + --> tests/ui/linkedlist.rs:46:25 | LL | fn test_ret() -> Option> { | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.rs b/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.rs index f257c66f59d36..d54cceae53eb5 100644 --- a/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.rs +++ b/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.rs @@ -1,6 +1,31 @@ #![warn(clippy::literal_string_with_formatting_args)] #![allow(clippy::unnecessary_literal_unwrap)] +// Regression test for . +// It's not supposed to emit the lint in this case (in `assert!` expansion). +fn compiler_macro() { + fn parse(_: &str) -> Result<(), i32> { + unimplemented!() + } + + assert!( + parse( + #[allow(clippy::literal_string_with_formatting_args)] + "foo {:}" + ) + .is_err() + ); + let value = 0; + assert!(format!("{value}").is_ascii()); +} + +// Regression test for . +fn regression_14007() { + let s = "{и}"; + let ш = 12; + let s = "{ш}"; //~ literal_string_with_formatting_args +} + fn main() { let x: Option = None; let y = "hello"; @@ -13,8 +38,10 @@ fn main() { x.expect(r"{y:?} {y:?} "); //~ literal_string_with_formatting_args x.expect(r"{y:?} y:?}"); //~ literal_string_with_formatting_args x.expect(r##" {y:?} {y:?} "##); //~ literal_string_with_formatting_args + assert!("{y}".is_ascii()); //~ literal_string_with_formatting_args // Ensure that it doesn't try to go in the middle of a unicode character. - x.expect("———{:?}"); //~ literal_string_with_formatting_args + x.expect("———{:?}"); + //~^ literal_string_with_formatting_args // Should not lint! format!("{y:?}"); @@ -25,6 +52,8 @@ fn main() { x.expect("{{y:?}"); x.expect(" {0}"); // If it only contains an integer, we ignore it. x.expect(r##" {x:?} "##); // `x` doesn't exist so we shoud not lint + // + //~^^ literal_string_with_formatting_args x.expect("{y:...}"); let _ = "fn main {\n\ }"; diff --git a/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.stderr b/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.stderr index 32a84f600da72..55425d01c587f 100644 --- a/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.stderr +++ b/src/tools/clippy/tests/ui/literal_string_with_formatting_arg.stderr @@ -1,71 +1,83 @@ error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:7:15 + --> tests/ui/literal_string_with_formatting_arg.rs:26:14 | -LL | x.expect("{y} {}"); - | ^^^ +LL | let s = "{ш}"; + | ^^^ | = note: `-D clippy::literal-string-with-formatting-args` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::literal_string_with_formatting_args)]` error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:8:16 + --> tests/ui/literal_string_with_formatting_arg.rs:32:15 + | +LL | x.expect("{y} {}"); + | ^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:33:16 | LL | x.expect(" {y} bla"); | ^^^ error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:9:15 + --> tests/ui/literal_string_with_formatting_arg.rs:34:15 | LL | x.expect("{:?}"); | ^^^^ error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:10:15 + --> tests/ui/literal_string_with_formatting_arg.rs:35:15 | LL | x.expect("{y:?}"); | ^^^^^ error: these look like formatting arguments but are not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:11:16 + --> tests/ui/literal_string_with_formatting_arg.rs:36:16 | LL | x.expect(" {y:?} {y:?} "); | ^^^^^ ^^^^^ error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:12:23 + --> tests/ui/literal_string_with_formatting_arg.rs:37:23 | LL | x.expect(" {y:..} {y:?} "); | ^^^^^ error: these look like formatting arguments but are not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:13:16 + --> tests/ui/literal_string_with_formatting_arg.rs:38:16 | LL | x.expect(r"{y:?} {y:?} "); | ^^^^^ ^^^^^ error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:14:16 + --> tests/ui/literal_string_with_formatting_arg.rs:39:16 | LL | x.expect(r"{y:?} y:?}"); | ^^^^^ error: these look like formatting arguments but are not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:15:19 + --> tests/ui/literal_string_with_formatting_arg.rs:40:19 | LL | x.expect(r##" {y:?} {y:?} "##); | ^^^^^ ^^^^^ error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:17:18 + --> tests/ui/literal_string_with_formatting_arg.rs:41:14 + | +LL | assert!("{y}".is_ascii()); + | ^^^ + +error: this looks like a formatting argument but it is not part of a formatting macro + --> tests/ui/literal_string_with_formatting_arg.rs:43:18 | LL | x.expect("———{:?}"); | ^^^^ error: this looks like a formatting argument but it is not part of a formatting macro - --> tests/ui/literal_string_with_formatting_arg.rs:27:19 + --> tests/ui/literal_string_with_formatting_arg.rs:54:19 | LL | x.expect(r##" {x:?} "##); // `x` doesn't exist so we shoud not lint | ^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/literals.rs b/src/tools/clippy/tests/ui/literals.rs index c275b04d886bb..d21d49310a077 100644 --- a/src/tools/clippy/tests/ui/literals.rs +++ b/src/tools/clippy/tests/ui/literals.rs @@ -11,32 +11,35 @@ fn main() { let ok1 = 0xABCD; let ok3 = 0xab_cd; let ok4 = 0xab_cd_i32; - //~^ ERROR: integer type suffix should not be separated by an underscore - //~| NOTE: `-D clippy::separated-literal-suffix` implied by `-D warnings` + //~^ separated_literal_suffix + let ok5 = 0xAB_CD_u32; - //~^ ERROR: integer type suffix should not be separated by an underscore + //~^ separated_literal_suffix + let ok5 = 0xAB_CD_isize; - //~^ ERROR: integer type suffix should not be separated by an underscore + //~^ separated_literal_suffix + let fail1 = 0xabCD; - //~^ ERROR: inconsistent casing in hexadecimal literal - //~| NOTE: `-D clippy::mixed-case-hex-literals` implied by `-D warnings` + //~^ mixed_case_hex_literals + let fail2 = 0xabCD_u32; - //~^ ERROR: integer type suffix should not be separated by an underscore - //~| ERROR: inconsistent casing in hexadecimal literal + //~^ separated_literal_suffix + //~| mixed_case_hex_literals + let fail2 = 0xabCD_isize; - //~^ ERROR: integer type suffix should not be separated by an underscore - //~| ERROR: inconsistent casing in hexadecimal literal + //~^ separated_literal_suffix + //~| mixed_case_hex_literals + let fail_multi_zero = 000_123usize; - //~^ ERROR: integer type suffix should be separated by an underscore - //~| NOTE: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` - //~| ERROR: this is a decimal constant - //~| NOTE: `-D clippy::zero-prefixed-literal` implied by `-D warnings` + //~^ unseparated_literal_suffix + //~| zero_prefixed_literal let ok9 = 0; let ok10 = 0_i64; - //~^ ERROR: integer type suffix should not be separated by an underscore + //~^ separated_literal_suffix + let fail8 = 0123; - //~^ ERROR: this is a decimal constant + //~^ zero_prefixed_literal let ok11 = 0o123; let ok12 = 0b10_1010; @@ -46,20 +49,22 @@ fn main() { let ok15 = 0xab_cabc_abca_bcab_cabc; let ok16 = 0xFE_BAFE_ABAB_ABCD; let ok17 = 0x123_4567_8901_usize; - //~^ ERROR: integer type suffix should not be separated by an underscore + //~^ separated_literal_suffix + let ok18 = 0xF; let fail19 = 12_3456_21; - //~^ ERROR: digits grouped inconsistently by underscores - //~| NOTE: `-D clippy::inconsistent-digit-grouping` implied by `-D warnings` + //~^ inconsistent_digit_grouping + let fail22 = 3__4___23; - //~^ ERROR: digits grouped inconsistently by underscores + //~^ inconsistent_digit_grouping + let fail23 = 3__16___23; - //~^ ERROR: digits grouped inconsistently by underscores + //~^ inconsistent_digit_grouping let fail24 = 0xAB_ABC_AB; - //~^ ERROR: digits of hex, binary or octal literal not in groups of equal size - //~| NOTE: `-D clippy::unusual-byte-groupings` implied by `-D warnings` + //~^ unusual_byte_groupings + let fail25 = 0b01_100_101; let ok26 = 0x6_A0_BF; let ok27 = 0b1_0010_0101; @@ -68,9 +73,11 @@ fn main() { fn issue9651() { // lint but octal form is not possible here let _ = 08; - //~^ ERROR: this is a decimal constant + //~^ zero_prefixed_literal + let _ = 09; - //~^ ERROR: this is a decimal constant + //~^ zero_prefixed_literal + let _ = 089; - //~^ ERROR: this is a decimal constant + //~^ zero_prefixed_literal } diff --git a/src/tools/clippy/tests/ui/literals.stderr b/src/tools/clippy/tests/ui/literals.stderr index 576b38a47d2de..d65cd3c89ebbe 100644 --- a/src/tools/clippy/tests/ui/literals.stderr +++ b/src/tools/clippy/tests/ui/literals.stderr @@ -14,13 +14,13 @@ LL | let ok5 = 0xAB_CD_u32; | ^^^^^^^^^^^ help: remove the underscore: `0xAB_CDu32` error: integer type suffix should not be separated by an underscore - --> tests/ui/literals.rs:18:15 + --> tests/ui/literals.rs:19:15 | LL | let ok5 = 0xAB_CD_isize; | ^^^^^^^^^^^^^ help: remove the underscore: `0xAB_CDisize` error: inconsistent casing in hexadecimal literal - --> tests/ui/literals.rs:20:17 + --> tests/ui/literals.rs:22:17 | LL | let fail1 = 0xabCD; | ^^^^^^ @@ -29,31 +29,31 @@ LL | let fail1 = 0xabCD; = help: to override `-D warnings` add `#[allow(clippy::mixed_case_hex_literals)]` error: integer type suffix should not be separated by an underscore - --> tests/ui/literals.rs:23:17 + --> tests/ui/literals.rs:25:17 | LL | let fail2 = 0xabCD_u32; | ^^^^^^^^^^ help: remove the underscore: `0xabCDu32` error: inconsistent casing in hexadecimal literal - --> tests/ui/literals.rs:23:17 + --> tests/ui/literals.rs:25:17 | LL | let fail2 = 0xabCD_u32; | ^^^^^^^^^^ error: integer type suffix should not be separated by an underscore - --> tests/ui/literals.rs:26:17 + --> tests/ui/literals.rs:29:17 | LL | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ help: remove the underscore: `0xabCDisize` error: inconsistent casing in hexadecimal literal - --> tests/ui/literals.rs:26:17 + --> tests/ui/literals.rs:29:17 | LL | let fail2 = 0xabCD_isize; | ^^^^^^^^^^^^ error: integer type suffix should be separated by an underscore - --> tests/ui/literals.rs:29:27 + --> tests/ui/literals.rs:33:27 | LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ help: add an underscore: `000_123_usize` @@ -62,7 +62,7 @@ LL | let fail_multi_zero = 000_123usize; = help: to override `-D warnings` add `#[allow(clippy::unseparated_literal_suffix)]` error: this is a decimal constant - --> tests/ui/literals.rs:29:27 + --> tests/ui/literals.rs:33:27 | LL | let fail_multi_zero = 000_123usize; | ^^^^^^^^^^^^ @@ -81,13 +81,13 @@ LL + let fail_multi_zero = 0o123usize; | error: integer type suffix should not be separated by an underscore - --> tests/ui/literals.rs:36:16 + --> tests/ui/literals.rs:38:16 | LL | let ok10 = 0_i64; | ^^^^^ help: remove the underscore: `0i64` error: this is a decimal constant - --> tests/ui/literals.rs:38:17 + --> tests/ui/literals.rs:41:17 | LL | let fail8 = 0123; | ^^^^ @@ -103,13 +103,13 @@ LL | let fail8 = 0o123; | + error: integer type suffix should not be separated by an underscore - --> tests/ui/literals.rs:48:16 + --> tests/ui/literals.rs:51:16 | LL | let ok17 = 0x123_4567_8901_usize; | ^^^^^^^^^^^^^^^^^^^^^ help: remove the underscore: `0x123_4567_8901usize` error: digits grouped inconsistently by underscores - --> tests/ui/literals.rs:52:18 + --> tests/ui/literals.rs:56:18 | LL | let fail19 = 12_3456_21; | ^^^^^^^^^^ help: consider: `12_345_621` @@ -118,19 +118,19 @@ LL | let fail19 = 12_3456_21; = help: to override `-D warnings` add `#[allow(clippy::inconsistent_digit_grouping)]` error: digits grouped inconsistently by underscores - --> tests/ui/literals.rs:55:18 + --> tests/ui/literals.rs:59:18 | LL | let fail22 = 3__4___23; | ^^^^^^^^^ help: consider: `3_423` error: digits grouped inconsistently by underscores - --> tests/ui/literals.rs:57:18 + --> tests/ui/literals.rs:62:18 | LL | let fail23 = 3__16___23; | ^^^^^^^^^^ help: consider: `31_623` error: digits of hex, binary or octal literal not in groups of equal size - --> tests/ui/literals.rs:60:18 + --> tests/ui/literals.rs:65:18 | LL | let fail24 = 0xAB_ABC_AB; | ^^^^^^^^^^^ help: consider: `0x0ABA_BCAB` @@ -139,7 +139,7 @@ LL | let fail24 = 0xAB_ABC_AB; = help: to override `-D warnings` add `#[allow(clippy::unusual_byte_groupings)]` error: this is a decimal constant - --> tests/ui/literals.rs:70:13 + --> tests/ui/literals.rs:75:13 | LL | let _ = 08; | ^^ @@ -151,7 +151,7 @@ LL + let _ = 8; | error: this is a decimal constant - --> tests/ui/literals.rs:72:13 + --> tests/ui/literals.rs:78:13 | LL | let _ = 09; | ^^ @@ -163,7 +163,7 @@ LL + let _ = 9; | error: this is a decimal constant - --> tests/ui/literals.rs:74:13 + --> tests/ui/literals.rs:81:13 | LL | let _ = 089; | ^^^ diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.fixed b/src/tools/clippy/tests/ui/lossy_float_literal.fixed index cc8c0b4a0d170..925a1465cc30d 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.fixed +++ b/src/tools/clippy/tests/ui/lossy_float_literal.fixed @@ -12,17 +12,28 @@ fn main() { let _: f16 = -4_097.0; let _: f32 = 16_777_216.0; + //~^ lossy_float_literal let _: f32 = 16_777_220.0; + //~^ lossy_float_literal let _: f32 = 16_777_220.0; + //~^ lossy_float_literal let _: f32 = 16_777_220.0; + //~^ lossy_float_literal let _ = 16_777_220_f32; + //~^ lossy_float_literal let _: f32 = -16_777_220.0; + //~^ lossy_float_literal let _: f64 = 9_007_199_254_740_992.0; + //~^ lossy_float_literal let _: f64 = 9_007_199_254_740_992.0; + //~^ lossy_float_literal let _: f64 = 9_007_199_254_740_992.0; + //~^ lossy_float_literal let _ = 9_007_199_254_740_992_f64; + //~^ lossy_float_literal let _: f64 = -9_007_199_254_740_992.0; + //~^ lossy_float_literal let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.0; let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.; diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.rs b/src/tools/clippy/tests/ui/lossy_float_literal.rs index c84eef396d58a..7341388d4816d 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.rs +++ b/src/tools/clippy/tests/ui/lossy_float_literal.rs @@ -12,17 +12,28 @@ fn main() { let _: f16 = -4_097.0; let _: f32 = 16_777_217.0; + //~^ lossy_float_literal let _: f32 = 16_777_219.0; + //~^ lossy_float_literal let _: f32 = 16_777_219.; + //~^ lossy_float_literal let _: f32 = 16_777_219.000; + //~^ lossy_float_literal let _ = 16_777_219f32; + //~^ lossy_float_literal let _: f32 = -16_777_219.0; + //~^ lossy_float_literal let _: f64 = 9_007_199_254_740_993.0; + //~^ lossy_float_literal let _: f64 = 9_007_199_254_740_993.; + //~^ lossy_float_literal let _: f64 = 9_007_199_254_740_993.00; + //~^ lossy_float_literal let _ = 9_007_199_254_740_993f64; + //~^ lossy_float_literal let _: f64 = -9_007_199_254_740_993.0; + //~^ lossy_float_literal let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.0; let _: f128 = 10_384_593_717_069_655_257_060_992_658_440_193.; diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.stderr b/src/tools/clippy/tests/ui/lossy_float_literal.stderr index 118351a62d00c..33b650b19c8a5 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.stderr +++ b/src/tools/clippy/tests/ui/lossy_float_literal.stderr @@ -13,7 +13,7 @@ LL + let _: f32 = 16_777_216.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:15:18 + --> tests/ui/lossy_float_literal.rs:16:18 | LL | let _: f32 = 16_777_219.0; | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let _: f32 = 16_777_220.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:16:18 + --> tests/ui/lossy_float_literal.rs:18:18 | LL | let _: f32 = 16_777_219.; | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let _: f32 = 16_777_220.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:17:18 + --> tests/ui/lossy_float_literal.rs:20:18 | LL | let _: f32 = 16_777_219.000; | ^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + let _: f32 = 16_777_220.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:18:13 + --> tests/ui/lossy_float_literal.rs:22:13 | LL | let _ = 16_777_219f32; | ^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let _ = 16_777_220_f32; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:19:19 + --> tests/ui/lossy_float_literal.rs:24:19 | LL | let _: f32 = -16_777_219.0; | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + let _: f32 = -16_777_220.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:21:18 + --> tests/ui/lossy_float_literal.rs:27:18 | LL | let _: f64 = 9_007_199_254_740_993.0; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + let _: f64 = 9_007_199_254_740_992.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:22:18 + --> tests/ui/lossy_float_literal.rs:29:18 | LL | let _: f64 = 9_007_199_254_740_993.; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + let _: f64 = 9_007_199_254_740_992.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:23:18 + --> tests/ui/lossy_float_literal.rs:31:18 | LL | let _: f64 = 9_007_199_254_740_993.00; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + let _: f64 = 9_007_199_254_740_992.0; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:24:13 + --> tests/ui/lossy_float_literal.rs:33:13 | LL | let _ = 9_007_199_254_740_993f64; | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + let _ = 9_007_199_254_740_992_f64; | error: literal cannot be represented as the underlying type without loss of precision - --> tests/ui/lossy_float_literal.rs:25:19 + --> tests/ui/lossy_float_literal.rs:35:19 | LL | let _: f64 = -9_007_199_254_740_993.0; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 28844fab74793..d12222fce3ebb 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -16,12 +16,16 @@ extern crate proc_macro_derive as mini_mac; mod a { use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro}; + //~^ macro_use_imports use mac; use mini_mac::ClippyMiniMacroTest; + //~^ macro_use_imports use mini_mac; use mac::{inner::mut_mut, inner::try_err}; + //~^ macro_use_imports use mac::inner; use mac::inner::nested::string_add; + //~^ macro_use_imports use mac::inner::nested; #[derive(ClippyMiniMacroTest)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index 5381f29598987..3baa9f8b5e59e 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -16,12 +16,16 @@ extern crate proc_macro_derive as mini_mac; mod a { #[macro_use] + //~^ macro_use_imports use mac; #[macro_use] + //~^ macro_use_imports use mini_mac; #[macro_use] + //~^ macro_use_imports use mac::inner; #[macro_use] + //~^ macro_use_imports use mac::inner::nested; #[derive(ClippyMiniMacroTest)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index ea0670d366675..cdef5bc79e0ca 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -8,19 +8,19 @@ LL | #[macro_use] = help: to override `-D warnings` add `#[allow(clippy::macro_use_imports)]` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> tests/ui/macro_use_imports.rs:22:5 + --> tests/ui/macro_use_imports.rs:24:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::mut_mut, inner::try_err};` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> tests/ui/macro_use_imports.rs:24:5 + --> tests/ui/macro_use_imports.rs:27:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> tests/ui/macro_use_imports.rs:20:5 + --> tests/ui/macro_use_imports.rs:21:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` diff --git a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs index 60cce1d24a289..115b30d3877fe 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build:macro_rules.rs //@aux-build:macro_use_helper.rs //@aux-build:proc_macro_derive.rs diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check-2.rs b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.rs index e97e3bdfef769..749d15f1cbd81 100644 --- a/src/tools/clippy/tests/ui/manual_arithmetic_check-2.rs +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.rs @@ -7,18 +7,22 @@ fn main() { let b = 13u32; let result = if a > b { b - a } else { 0 }; - //~^ ERROR: inverted arithmetic check before subtraction + //~^ inverted_saturating_sub + let result = if b < a { b - a } else { 0 }; - //~^ ERROR: inverted arithmetic check before subtraction + //~^ inverted_saturating_sub let result = if a > b { 0 } else { a - b }; - //~^ ERROR: inverted arithmetic check before subtraction + //~^ inverted_saturating_sub + let result = if a >= b { 0 } else { a - b }; - //~^ ERROR: inverted arithmetic check before subtraction + //~^ inverted_saturating_sub + let result = if b < a { 0 } else { a - b }; - //~^ ERROR: inverted arithmetic check before subtraction + //~^ inverted_saturating_sub + let result = if b <= a { 0 } else { a - b }; - //~^ ERROR: inverted arithmetic check before subtraction + //~^ inverted_saturating_sub let af = 12f32; let bf = 13f32; diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check-2.stderr b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.stderr index 4121aa7464f05..8841210befda7 100644 --- a/src/tools/clippy/tests/ui/manual_arithmetic_check-2.stderr +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check-2.stderr @@ -12,61 +12,61 @@ LL | let result = if a > b { b - a } else { 0 }; = note: `#[deny(clippy::inverted_saturating_sub)]` on by default error: inverted arithmetic check before subtraction - --> tests/ui/manual_arithmetic_check-2.rs:11:23 + --> tests/ui/manual_arithmetic_check-2.rs:12:23 | LL | let result = if b < a { b - a } else { 0 }; | ^ ----- help: try replacing it with: `a - b` | note: this subtraction underflows when `b < a` - --> tests/ui/manual_arithmetic_check-2.rs:11:29 + --> tests/ui/manual_arithmetic_check-2.rs:12:29 | LL | let result = if b < a { b - a } else { 0 }; | ^^^^^ error: inverted arithmetic check before subtraction - --> tests/ui/manual_arithmetic_check-2.rs:14:23 + --> tests/ui/manual_arithmetic_check-2.rs:15:23 | LL | let result = if a > b { 0 } else { a - b }; | ^ ----- help: try replacing it with: `b - a` | note: this subtraction underflows when `a < b` - --> tests/ui/manual_arithmetic_check-2.rs:14:40 + --> tests/ui/manual_arithmetic_check-2.rs:15:40 | LL | let result = if a > b { 0 } else { a - b }; | ^^^^^ error: inverted arithmetic check before subtraction - --> tests/ui/manual_arithmetic_check-2.rs:16:23 + --> tests/ui/manual_arithmetic_check-2.rs:18:23 | LL | let result = if a >= b { 0 } else { a - b }; | ^^ ----- help: try replacing it with: `b - a` | note: this subtraction underflows when `a < b` - --> tests/ui/manual_arithmetic_check-2.rs:16:41 + --> tests/ui/manual_arithmetic_check-2.rs:18:41 | LL | let result = if a >= b { 0 } else { a - b }; | ^^^^^ error: inverted arithmetic check before subtraction - --> tests/ui/manual_arithmetic_check-2.rs:18:23 + --> tests/ui/manual_arithmetic_check-2.rs:21:23 | LL | let result = if b < a { 0 } else { a - b }; | ^ ----- help: try replacing it with: `b - a` | note: this subtraction underflows when `a < b` - --> tests/ui/manual_arithmetic_check-2.rs:18:40 + --> tests/ui/manual_arithmetic_check-2.rs:21:40 | LL | let result = if b < a { 0 } else { a - b }; | ^^^^^ error: inverted arithmetic check before subtraction - --> tests/ui/manual_arithmetic_check-2.rs:20:23 + --> tests/ui/manual_arithmetic_check-2.rs:24:23 | LL | let result = if b <= a { 0 } else { a - b }; | ^^ ----- help: try replacing it with: `b - a` | note: this subtraction underflows when `a < b` - --> tests/ui/manual_arithmetic_check-2.rs:20:41 + --> tests/ui/manual_arithmetic_check-2.rs:24:41 | LL | let result = if b <= a { 0 } else { a - b }; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check.fixed b/src/tools/clippy/tests/ui/manual_arithmetic_check.fixed index 29ecbb9ad2adb..99ed1faf90a6c 100644 --- a/src/tools/clippy/tests/ui/manual_arithmetic_check.fixed +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check.fixed @@ -7,14 +7,16 @@ fn main() { let c = 8u32; let result = a.saturating_sub(b); - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub + let result = a.saturating_sub(b); - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub let result = a.saturating_sub(b); - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub + let result = a.saturating_sub(b); - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub // Should not warn! let result = if a > b { a - b } else { a - c }; diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check.rs b/src/tools/clippy/tests/ui/manual_arithmetic_check.rs index 69554c6b61caa..cf202fa35a6a6 100644 --- a/src/tools/clippy/tests/ui/manual_arithmetic_check.rs +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check.rs @@ -7,14 +7,16 @@ fn main() { let c = 8u32; let result = if a > b { a - b } else { 0 }; - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub + let result = if b < a { a - b } else { 0 }; - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub let result = if a < b { 0 } else { a - b }; - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub + let result = if b > a { 0 } else { a - b }; - //~^ ERROR: manual arithmetic check found + //~^ implicit_saturating_sub // Should not warn! let result = if a > b { a - b } else { a - c }; diff --git a/src/tools/clippy/tests/ui/manual_arithmetic_check.stderr b/src/tools/clippy/tests/ui/manual_arithmetic_check.stderr index b0cf73cd9151d..b1598a5d06dc1 100644 --- a/src/tools/clippy/tests/ui/manual_arithmetic_check.stderr +++ b/src/tools/clippy/tests/ui/manual_arithmetic_check.stderr @@ -8,19 +8,19 @@ LL | let result = if a > b { a - b } else { 0 }; = help: to override `-D warnings` add `#[allow(clippy::implicit_saturating_sub)]` error: manual arithmetic check found - --> tests/ui/manual_arithmetic_check.rs:11:18 + --> tests/ui/manual_arithmetic_check.rs:12:18 | LL | let result = if b < a { a - b } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` error: manual arithmetic check found - --> tests/ui/manual_arithmetic_check.rs:14:18 + --> tests/ui/manual_arithmetic_check.rs:15:18 | LL | let result = if a < b { 0 } else { a - b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` error: manual arithmetic check found - --> tests/ui/manual_arithmetic_check.rs:16:18 + --> tests/ui/manual_arithmetic_check.rs:18:18 | LL | let result = if b > a { 0 } else { a - b }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.saturating_sub(b)` diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr index dfccf7e99396c..8cedf2c68636a 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr @@ -2,76 +2,155 @@ error: only a `panic!` in `if`-then statement --> tests/ui/manual_assert.rs:32:5 | LL | / if !a.is_empty() { +LL | | LL | | panic!("qaqaq{:?}", a); LL | | } - | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);` + | |_____^ | = note: `-D clippy::manual-assert` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]` +help: try instead + | +LL - if !a.is_empty() { +LL - +LL - panic!("qaqaq{:?}", a); +LL - } +LL + assert!(a.is_empty(), "qaqaq{:?}", a); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:35:5 + --> tests/ui/manual_assert.rs:36:5 | LL | / if !a.is_empty() { +LL | | LL | | panic!("qwqwq"); LL | | } - | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");` + | |_____^ + | +help: try instead + | +LL - if !a.is_empty() { +LL - +LL - panic!("qwqwq"); +LL - } +LL + assert!(a.is_empty(), "qwqwq"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:52:5 + --> tests/ui/manual_assert.rs:54:5 | LL | / if b.is_empty() { +LL | | LL | | panic!("panic1"); LL | | } - | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");` + | |_____^ + | +help: try instead + | +LL - if b.is_empty() { +LL - +LL - panic!("panic1"); +LL - } +LL + assert!(!b.is_empty(), "panic1"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:55:5 + --> tests/ui/manual_assert.rs:58:5 | LL | / if b.is_empty() && a.is_empty() { +LL | | LL | | panic!("panic2"); LL | | } - | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + | |_____^ + | +help: try instead + | +LL - if b.is_empty() && a.is_empty() { +LL - +LL - panic!("panic2"); +LL - } +LL + assert!(!(b.is_empty() && a.is_empty()), "panic2"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:58:5 + --> tests/ui/manual_assert.rs:62:5 | LL | / if a.is_empty() && !b.is_empty() { +LL | | LL | | panic!("panic3"); LL | | } - | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + | |_____^ + | +help: try instead + | +LL - if a.is_empty() && !b.is_empty() { +LL - +LL - panic!("panic3"); +LL - } +LL + assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:61:5 + --> tests/ui/manual_assert.rs:66:5 | LL | / if b.is_empty() || a.is_empty() { +LL | | LL | | panic!("panic4"); LL | | } - | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + | |_____^ + | +help: try instead + | +LL - if b.is_empty() || a.is_empty() { +LL - +LL - panic!("panic4"); +LL - } +LL + assert!(!(b.is_empty() || a.is_empty()), "panic4"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:64:5 + --> tests/ui/manual_assert.rs:70:5 | LL | / if a.is_empty() || !b.is_empty() { +LL | | LL | | panic!("panic5"); LL | | } - | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + | |_____^ + | +help: try instead + | +LL - if a.is_empty() || !b.is_empty() { +LL - +LL - panic!("panic5"); +LL - } +LL + assert!(!(a.is_empty() || !b.is_empty()), "panic5"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:67:5 + --> tests/ui/manual_assert.rs:74:5 | LL | / if a.is_empty() { +LL | | LL | | panic!("with expansion {}", one!()) LL | | } - | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());` + | |_____^ + | +help: try instead + | +LL - if a.is_empty() { +LL - +LL - panic!("with expansion {}", one!()) +LL - } +LL + assert!(!a.is_empty(), "with expansion {}", one!()); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:79:5 + --> tests/ui/manual_assert.rs:87:5 | LL | / if a > 2 { +LL | | LL | | // comment LL | | /* this is a -LL | | multiline ... | LL | | panic!("panic with comment") // comment after `panic!` LL | | } @@ -80,6 +159,7 @@ LL | | } help: try instead | LL - if a > 2 { +LL - LL - // comment LL - /* this is a LL - multiline @@ -91,13 +171,23 @@ LL + assert!(!(a > 2), "panic with comment"); | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:93:25 + --> tests/ui/manual_assert.rs:102:25 | LL | const BAR: () = if N == 0 { | _________________________^ +LL | | LL | | panic!() LL | | }; - | |_________^ help: try instead: `assert!(!(N == 0), )` + | |_________^ + | +help: try instead + | +LL - const BAR: () = if N == 0 { +LL - +LL - panic!() +LL - }; +LL + const BAR: () = assert!(!(N == 0), ); + | error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr index dfccf7e99396c..8cedf2c68636a 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.stderr @@ -2,76 +2,155 @@ error: only a `panic!` in `if`-then statement --> tests/ui/manual_assert.rs:32:5 | LL | / if !a.is_empty() { +LL | | LL | | panic!("qaqaq{:?}", a); LL | | } - | |_____^ help: try instead: `assert!(a.is_empty(), "qaqaq{:?}", a);` + | |_____^ | = note: `-D clippy::manual-assert` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_assert)]` +help: try instead + | +LL - if !a.is_empty() { +LL - +LL - panic!("qaqaq{:?}", a); +LL - } +LL + assert!(a.is_empty(), "qaqaq{:?}", a); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:35:5 + --> tests/ui/manual_assert.rs:36:5 | LL | / if !a.is_empty() { +LL | | LL | | panic!("qwqwq"); LL | | } - | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");` + | |_____^ + | +help: try instead + | +LL - if !a.is_empty() { +LL - +LL - panic!("qwqwq"); +LL - } +LL + assert!(a.is_empty(), "qwqwq"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:52:5 + --> tests/ui/manual_assert.rs:54:5 | LL | / if b.is_empty() { +LL | | LL | | panic!("panic1"); LL | | } - | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");` + | |_____^ + | +help: try instead + | +LL - if b.is_empty() { +LL - +LL - panic!("panic1"); +LL - } +LL + assert!(!b.is_empty(), "panic1"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:55:5 + --> tests/ui/manual_assert.rs:58:5 | LL | / if b.is_empty() && a.is_empty() { +LL | | LL | | panic!("panic2"); LL | | } - | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");` + | |_____^ + | +help: try instead + | +LL - if b.is_empty() && a.is_empty() { +LL - +LL - panic!("panic2"); +LL - } +LL + assert!(!(b.is_empty() && a.is_empty()), "panic2"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:58:5 + --> tests/ui/manual_assert.rs:62:5 | LL | / if a.is_empty() && !b.is_empty() { +LL | | LL | | panic!("panic3"); LL | | } - | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");` + | |_____^ + | +help: try instead + | +LL - if a.is_empty() && !b.is_empty() { +LL - +LL - panic!("panic3"); +LL - } +LL + assert!(!(a.is_empty() && !b.is_empty()), "panic3"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:61:5 + --> tests/ui/manual_assert.rs:66:5 | LL | / if b.is_empty() || a.is_empty() { +LL | | LL | | panic!("panic4"); LL | | } - | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");` + | |_____^ + | +help: try instead + | +LL - if b.is_empty() || a.is_empty() { +LL - +LL - panic!("panic4"); +LL - } +LL + assert!(!(b.is_empty() || a.is_empty()), "panic4"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:64:5 + --> tests/ui/manual_assert.rs:70:5 | LL | / if a.is_empty() || !b.is_empty() { +LL | | LL | | panic!("panic5"); LL | | } - | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");` + | |_____^ + | +help: try instead + | +LL - if a.is_empty() || !b.is_empty() { +LL - +LL - panic!("panic5"); +LL - } +LL + assert!(!(a.is_empty() || !b.is_empty()), "panic5"); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:67:5 + --> tests/ui/manual_assert.rs:74:5 | LL | / if a.is_empty() { +LL | | LL | | panic!("with expansion {}", one!()) LL | | } - | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());` + | |_____^ + | +help: try instead + | +LL - if a.is_empty() { +LL - +LL - panic!("with expansion {}", one!()) +LL - } +LL + assert!(!a.is_empty(), "with expansion {}", one!()); + | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:79:5 + --> tests/ui/manual_assert.rs:87:5 | LL | / if a > 2 { +LL | | LL | | // comment LL | | /* this is a -LL | | multiline ... | LL | | panic!("panic with comment") // comment after `panic!` LL | | } @@ -80,6 +159,7 @@ LL | | } help: try instead | LL - if a > 2 { +LL - LL - // comment LL - /* this is a LL - multiline @@ -91,13 +171,23 @@ LL + assert!(!(a > 2), "panic with comment"); | error: only a `panic!` in `if`-then statement - --> tests/ui/manual_assert.rs:93:25 + --> tests/ui/manual_assert.rs:102:25 | LL | const BAR: () = if N == 0 { | _________________________^ +LL | | LL | | panic!() LL | | }; - | |_________^ help: try instead: `assert!(!(N == 0), )` + | |_________^ + | +help: try instead + | +LL - const BAR: () = if N == 0 { +LL - +LL - panic!() +LL - }; +LL + const BAR: () = 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 6337920a3eea1..46a42c3d00af5 100644 --- a/src/tools/clippy/tests/ui/manual_assert.rs +++ b/src/tools/clippy/tests/ui/manual_assert.rs @@ -30,9 +30,11 @@ fn main() { panic!("qaqaq{:?}", a); } if !a.is_empty() { + //~^ manual_assert panic!("qaqaq{:?}", a); } if !a.is_empty() { + //~^ manual_assert panic!("qwqwq"); } if a.len() == 3 { @@ -50,21 +52,27 @@ fn main() { } let b = vec![1, 2, 3]; if b.is_empty() { + //~^ manual_assert panic!("panic1"); } if b.is_empty() && a.is_empty() { + //~^ manual_assert panic!("panic2"); } if a.is_empty() && !b.is_empty() { + //~^ manual_assert panic!("panic3"); } if b.is_empty() || a.is_empty() { + //~^ manual_assert panic!("panic4"); } if a.is_empty() || !b.is_empty() { + //~^ manual_assert panic!("panic5"); } if a.is_empty() { + //~^ manual_assert panic!("with expansion {}", one!()) } if a.is_empty() { @@ -77,6 +85,7 @@ fn main() { fn issue7730(a: u8) { // Suggestion should preserve comment if a > 2 { + //~^ manual_assert // comment /* this is a multiline @@ -91,6 +100,7 @@ fn issue12505() { impl Foo { const BAR: () = if N == 0 { + //~^ manual_assert panic!() }; } diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed index dc1cb8e11fca6..ad0266d39e982 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.fixed +++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed @@ -113,4 +113,30 @@ pub(crate) async fn issue_10450_2() -> i32 { 42 } pub(self) async fn issue_10450_3() -> i32 { 42 } +macro_rules! issue_12407 { + ( + $( + $(#[$m:meta])* + $v:vis $(override($($overrides:tt),* $(,)?))? fn $name:ident $([$($params:tt)*])? ( + $($arg_name:ident: $arg_typ:ty),* $(,)? + ) $(-> $ret_ty:ty)? = $e:expr; + )* + ) => { + $( + $(#[$m])* + $v $($($overrides)*)? fn $name$(<$($params)*>)?( + $($arg_name: $arg_typ),* + ) $(-> $ret_ty)? { + $e + } + )* + }; +} + +issue_12407! { + fn _hello() -> impl Future = async {}; + fn non_async() = println!("hello"); + fn foo() = non_async(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs index 9ca7654a36882..fe367b4bc7b9b 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.rs +++ b/src/tools/clippy/tests/ui/manual_async_fn.rs @@ -4,34 +4,41 @@ use std::future::Future; fn fut() -> impl Future { + //~^ manual_async_fn async { 42 } } #[rustfmt::skip] fn fut2() ->impl Future { +//~^ manual_async_fn async { 42 } } #[rustfmt::skip] fn fut3()-> impl Future { +//~^ manual_async_fn async { 42 } } fn empty_fut() -> impl Future { + //~^ manual_async_fn async {} } #[rustfmt::skip] fn empty_fut2() ->impl Future { +//~^ manual_async_fn async {} } #[rustfmt::skip] fn empty_fut3()-> impl Future { +//~^ manual_async_fn async {} } fn core_fut() -> impl core::future::Future { + //~^ manual_async_fn async move { 42 } } @@ -54,6 +61,7 @@ async fn already_async() -> impl Future { struct S; impl S { fn inh_fut() -> impl Future { + //~^ manual_async_fn async { // NOTE: this code is here just to check that the indentation is correct in the suggested fix let a = 42; @@ -89,6 +97,7 @@ impl S { // Tests related to lifetime capture fn elided(_: &i32) -> impl Future + '_ { + //~^ manual_async_fn async { 42 } } @@ -99,6 +108,7 @@ fn elided_not_bound(_: &i32) -> impl Future { #[allow(clippy::needless_lifetimes)] fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { + //~^ manual_async_fn async { 42 } } @@ -128,15 +138,44 @@ mod issue_5765 { } pub fn issue_10450() -> impl Future { + //~^ manual_async_fn async { 42 } } pub(crate) fn issue_10450_2() -> impl Future { + //~^ manual_async_fn async { 42 } } pub(self) fn issue_10450_3() -> impl Future { + //~^ manual_async_fn async { 42 } } +macro_rules! issue_12407 { + ( + $( + $(#[$m:meta])* + $v:vis $(override($($overrides:tt),* $(,)?))? fn $name:ident $([$($params:tt)*])? ( + $($arg_name:ident: $arg_typ:ty),* $(,)? + ) $(-> $ret_ty:ty)? = $e:expr; + )* + ) => { + $( + $(#[$m])* + $v $($($overrides)*)? fn $name$(<$($params)*>)?( + $($arg_name: $arg_typ),* + ) $(-> $ret_ty)? { + $e + } + )* + }; +} + +issue_12407! { + fn _hello() -> impl Future = async {}; + fn non_async() = println!("hello"); + fn foo() = non_async(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_async_fn.stderr b/src/tools/clippy/tests/ui/manual_async_fn.stderr index a7cfc30fb69c5..54a9b1d40a118 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.stderr +++ b/src/tools/clippy/tests/ui/manual_async_fn.stderr @@ -13,7 +13,7 @@ LL + async fn fut() -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:11:1 + --> tests/ui/manual_async_fn.rs:12:1 | LL | fn fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + async fn fut2() -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:16:1 + --> tests/ui/manual_async_fn.rs:18:1 | LL | fn fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + async fn fut3() -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:20:1 + --> tests/ui/manual_async_fn.rs:23:1 | LL | fn empty_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + async fn empty_fut() {} | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:25:1 + --> tests/ui/manual_async_fn.rs:29:1 | LL | fn empty_fut2() ->impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + async fn empty_fut2() {} | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:30:1 + --> tests/ui/manual_async_fn.rs:35:1 | LL | fn empty_fut3()-> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + async fn empty_fut3() {} | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:34:1 + --> tests/ui/manual_async_fn.rs:40:1 | LL | fn core_fut() -> impl core::future::Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + async fn core_fut() -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:56:5 + --> tests/ui/manual_async_fn.rs:63:5 | LL | fn inh_fut() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL + } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:91:1 + --> tests/ui/manual_async_fn.rs:99:1 | LL | fn elided(_: &i32) -> impl Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + async fn elided(_: &i32) -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:101:1 + --> tests/ui/manual_async_fn.rs:110:1 | LL | fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future + 'a + 'b { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL + async fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:130:1 + --> tests/ui/manual_async_fn.rs:140:1 | LL | pub fn issue_10450() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL + pub async fn issue_10450() -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:134:1 + --> tests/ui/manual_async_fn.rs:145:1 | LL | pub(crate) fn issue_10450_2() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL + pub(crate) async fn issue_10450_2() -> i32 { 42 } | error: this function can be simplified using the `async fn` syntax - --> tests/ui/manual_async_fn.rs:138:1 + --> tests/ui/manual_async_fn.rs:150:1 | LL | pub(self) fn issue_10450_3() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_bits.fixed b/src/tools/clippy/tests/ui/manual_bits.fixed index 8e5cb7d38b9ba..db2ad2ace6256 100644 --- a/src/tools/clippy/tests/ui/manual_bits.fixed +++ b/src/tools/clippy/tests/ui/manual_bits.fixed @@ -12,32 +12,56 @@ use std::mem::{size_of, size_of_val}; fn main() { i8::BITS as usize; + //~^ manual_bits i16::BITS as usize; + //~^ manual_bits i32::BITS as usize; + //~^ manual_bits i64::BITS as usize; + //~^ manual_bits i128::BITS as usize; + //~^ manual_bits isize::BITS as usize; + //~^ manual_bits u8::BITS as usize; + //~^ manual_bits u16::BITS as usize; + //~^ manual_bits u32::BITS as usize; + //~^ manual_bits u64::BITS as usize; + //~^ manual_bits u128::BITS as usize; + //~^ manual_bits usize::BITS as usize; + //~^ manual_bits i8::BITS as usize; + //~^ manual_bits i16::BITS as usize; + //~^ manual_bits i32::BITS as usize; + //~^ manual_bits i64::BITS as usize; + //~^ manual_bits i128::BITS as usize; + //~^ manual_bits isize::BITS as usize; + //~^ manual_bits u8::BITS as usize; + //~^ manual_bits u16::BITS as usize; + //~^ manual_bits u32::BITS as usize; + //~^ manual_bits u64::BITS as usize; + //~^ manual_bits u128::BITS as usize; + //~^ manual_bits usize::BITS as usize; + //~^ manual_bits size_of::() * 4; 4 * size_of::(); @@ -48,13 +72,18 @@ fn main() { type Word = u32; Word::BITS as usize; + //~^ manual_bits type Bool = bool; size_of::() * 8; let _: u32 = u128::BITS as u32; + //~^ manual_bits let _: u32 = u128::BITS.try_into().unwrap(); + //~^ manual_bits let _ = (u128::BITS as usize).pow(5); + //~^ manual_bits let _ = &(u128::BITS as usize); + //~^ manual_bits } fn should_not_lint() { diff --git a/src/tools/clippy/tests/ui/manual_bits.rs b/src/tools/clippy/tests/ui/manual_bits.rs index 5e492ed15d211..6d1f0de1c19db 100644 --- a/src/tools/clippy/tests/ui/manual_bits.rs +++ b/src/tools/clippy/tests/ui/manual_bits.rs @@ -12,32 +12,56 @@ use std::mem::{size_of, size_of_val}; fn main() { size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits size_of::() * 8; + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits 8 * size_of::(); + //~^ manual_bits size_of::() * 4; 4 * size_of::(); @@ -48,13 +72,18 @@ fn main() { type Word = u32; size_of::() * 8; + //~^ manual_bits type Bool = bool; size_of::() * 8; let _: u32 = (size_of::() * 8) as u32; + //~^ manual_bits let _: u32 = (size_of::() * 8).try_into().unwrap(); + //~^ manual_bits let _ = (size_of::() * 8).pow(5); + //~^ manual_bits let _ = &(size_of::() * 8); + //~^ manual_bits } fn should_not_lint() { diff --git a/src/tools/clippy/tests/ui/manual_bits.stderr b/src/tools/clippy/tests/ui/manual_bits.stderr index 4383aa49df9b4..a50975ed474ec 100644 --- a/src/tools/clippy/tests/ui/manual_bits.stderr +++ b/src/tools/clippy/tests/ui/manual_bits.stderr @@ -8,169 +8,169 @@ LL | size_of::() * 8; = help: to override `-D warnings` add `#[allow(clippy::manual_bits)]` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:15:5 + --> tests/ui/manual_bits.rs:16:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:16:5 + --> tests/ui/manual_bits.rs:18:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:17:5 + --> tests/ui/manual_bits.rs:20:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:18:5 + --> tests/ui/manual_bits.rs:22:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:19:5 + --> tests/ui/manual_bits.rs:24:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:21:5 + --> tests/ui/manual_bits.rs:27:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:22:5 + --> tests/ui/manual_bits.rs:29:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:23:5 + --> tests/ui/manual_bits.rs:31:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:24:5 + --> tests/ui/manual_bits.rs:33:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:25:5 + --> tests/ui/manual_bits.rs:35:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:26:5 + --> tests/ui/manual_bits.rs:37:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:28:5 + --> tests/ui/manual_bits.rs:40:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:29:5 + --> tests/ui/manual_bits.rs:42:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:30:5 + --> tests/ui/manual_bits.rs:44:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:31:5 + --> tests/ui/manual_bits.rs:46:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:32:5 + --> tests/ui/manual_bits.rs:48:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:33:5 + --> tests/ui/manual_bits.rs:50:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:35:5 + --> tests/ui/manual_bits.rs:53:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:36:5 + --> tests/ui/manual_bits.rs:55:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:37:5 + --> tests/ui/manual_bits.rs:57:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:38:5 + --> tests/ui/manual_bits.rs:59:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:39:5 + --> tests/ui/manual_bits.rs:61:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:40:5 + --> tests/ui/manual_bits.rs:63:5 | LL | 8 * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:50:5 + --> tests/ui/manual_bits.rs:74:5 | LL | size_of::() * 8; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `Word::BITS as usize` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:54:18 + --> tests/ui/manual_bits.rs:79:18 | LL | let _: u32 = (size_of::() * 8) as u32; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:55:18 + --> tests/ui/manual_bits.rs:81:18 | LL | let _: u32 = (size_of::() * 8).try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:56:13 + --> tests/ui/manual_bits.rs:83:13 | LL | let _ = (size_of::() * 8).pow(5); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)` error: usage of `mem::size_of::()` to obtain the size of `T` in bits - --> tests/ui/manual_bits.rs:57:14 + --> tests/ui/manual_bits.rs:85:14 | LL | let _ = &(size_of::() * 8); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(u128::BITS as usize)` diff --git a/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.fixed b/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.fixed index 391c63bb4b89c..3ffaef0386cec 100644 --- a/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.fixed +++ b/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.fixed @@ -1,6 +1,7 @@ //@revisions: edition2018 edition2021 //@[edition2018] edition:2018 //@[edition2021] edition:2021 +//@[edition2018] check-pass #![warn(clippy::manual_c_str_literals)] #![allow(clippy::no_effect)] @@ -32,29 +33,42 @@ fn pre_stabilization() { #[clippy::msrv = "1.77.0"] fn post_stabilization() { c"foo"; + //~[edition2021]^ manual_c_str_literals } fn main() { c"foo"; + //~[edition2021]^ manual_c_str_literals c"foo"; + //~[edition2021]^ manual_c_str_literals c"foo"; + //~[edition2021]^ manual_c_str_literals c"foo\\0sdsd"; + //~[edition2021]^ manual_c_str_literals CStr::from_bytes_with_nul(br"foo\\0sdsd\0").unwrap(); CStr::from_bytes_with_nul(br"foo\x00").unwrap(); CStr::from_bytes_with_nul(br##"foo#a\0"##).unwrap(); unsafe { c"foo" }; + //~[edition2021]^ manual_c_str_literals unsafe { c"foo" }; + //~[edition2021]^ manual_c_str_literals let _: *const _ = c"foo".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _: *const _ = c"foo".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _: *const _ = "foo".as_ptr(); // not a C-string let _: *const _ = "".as_ptr(); let _: *const _ = c"foo".as_ptr().cast::(); + //~[edition2021]^ manual_c_str_literals let _ = "电脑".as_ptr(); let _ = "电脑\\".as_ptr(); let _ = c"电脑\\".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _ = c"电脑".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _ = c"电脑".as_ptr(); + //~[edition2021]^ manual_c_str_literals // Macro cases, don't lint: cstr!("foo"); diff --git a/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.stderr b/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.stderr index beab29ccdda02..2119bbc5b425f 100644 --- a/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.stderr +++ b/src/tools/clippy/tests/ui/manual_c_str_literals.edition2021.stderr @@ -1,5 +1,5 @@ error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:34:5 + --> tests/ui/manual_c_str_literals.rs:35:5 | LL | CStr::from_bytes_with_nul(b"foo\0"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` @@ -8,73 +8,73 @@ LL | CStr::from_bytes_with_nul(b"foo\0"); = help: to override `-D warnings` add `#[allow(clippy::manual_c_str_literals)]` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:38:5 + --> tests/ui/manual_c_str_literals.rs:40:5 | LL | CStr::from_bytes_with_nul(b"foo\0"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:39:5 + --> tests/ui/manual_c_str_literals.rs:42:5 | LL | CStr::from_bytes_with_nul(b"foo\x00"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:40:5 + --> tests/ui/manual_c_str_literals.rs:44:5 | LL | CStr::from_bytes_with_nul(b"foo\0").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::new` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:41:5 + --> tests/ui/manual_c_str_literals.rs:46:5 | LL | CStr::from_bytes_with_nul(b"foo\\0sdsd\0").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo\\0sdsd"` error: calling `CStr::from_ptr` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:46:14 + --> tests/ui/manual_c_str_literals.rs:52:14 | LL | unsafe { CStr::from_ptr(b"foo\0".as_ptr().cast()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: calling `CStr::from_ptr` with a byte string literal - --> tests/ui/manual_c_str_literals.rs:47:14 + --> tests/ui/manual_c_str_literals.rs:54:14 | LL | unsafe { CStr::from_ptr(b"foo\0".as_ptr() as *const _) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:48:23 + --> tests/ui/manual_c_str_literals.rs:56:23 | LL | let _: *const _ = b"foo\0".as_ptr(); | ^^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:49:23 + --> tests/ui/manual_c_str_literals.rs:58:23 | LL | let _: *const _ = "foo\0".as_ptr(); | ^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:52:23 + --> tests/ui/manual_c_str_literals.rs:62:23 | LL | let _: *const _ = b"foo\0".as_ptr().cast::(); | ^^^^^^^^ help: use a `c""` literal: `c"foo"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:55:13 + --> tests/ui/manual_c_str_literals.rs:66:13 | LL | let _ = "电脑\\\0".as_ptr(); | ^^^^^^^^^^ help: use a `c""` literal: `c"电脑\\"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:56:13 + --> tests/ui/manual_c_str_literals.rs:68:13 | LL | let _ = "电脑\0".as_ptr(); | ^^^^^^^^ help: use a `c""` literal: `c"电脑"` error: manually constructing a nul-terminated string - --> tests/ui/manual_c_str_literals.rs:57:13 + --> tests/ui/manual_c_str_literals.rs:70:13 | LL | let _ = "电脑\x00".as_ptr(); | ^^^^^^^^^^ help: use a `c""` literal: `c"电脑"` diff --git a/src/tools/clippy/tests/ui/manual_c_str_literals.rs b/src/tools/clippy/tests/ui/manual_c_str_literals.rs index 39b622580774d..ec3b8e5877245 100644 --- a/src/tools/clippy/tests/ui/manual_c_str_literals.rs +++ b/src/tools/clippy/tests/ui/manual_c_str_literals.rs @@ -1,6 +1,7 @@ //@revisions: edition2018 edition2021 //@[edition2018] edition:2018 //@[edition2021] edition:2021 +//@[edition2018] check-pass #![warn(clippy::manual_c_str_literals)] #![allow(clippy::no_effect)] @@ -32,29 +33,42 @@ fn pre_stabilization() { #[clippy::msrv = "1.77.0"] fn post_stabilization() { CStr::from_bytes_with_nul(b"foo\0"); + //~[edition2021]^ manual_c_str_literals } fn main() { CStr::from_bytes_with_nul(b"foo\0"); + //~[edition2021]^ manual_c_str_literals CStr::from_bytes_with_nul(b"foo\x00"); + //~[edition2021]^ manual_c_str_literals CStr::from_bytes_with_nul(b"foo\0").unwrap(); + //~[edition2021]^ manual_c_str_literals CStr::from_bytes_with_nul(b"foo\\0sdsd\0").unwrap(); + //~[edition2021]^ manual_c_str_literals CStr::from_bytes_with_nul(br"foo\\0sdsd\0").unwrap(); CStr::from_bytes_with_nul(br"foo\x00").unwrap(); CStr::from_bytes_with_nul(br##"foo#a\0"##).unwrap(); unsafe { CStr::from_ptr(b"foo\0".as_ptr().cast()) }; + //~[edition2021]^ manual_c_str_literals unsafe { CStr::from_ptr(b"foo\0".as_ptr() as *const _) }; + //~[edition2021]^ manual_c_str_literals let _: *const _ = b"foo\0".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _: *const _ = "foo\0".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _: *const _ = "foo".as_ptr(); // not a C-string let _: *const _ = "".as_ptr(); let _: *const _ = b"foo\0".as_ptr().cast::(); + //~[edition2021]^ manual_c_str_literals let _ = "电脑".as_ptr(); let _ = "电脑\\".as_ptr(); let _ = "电脑\\\0".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _ = "电脑\0".as_ptr(); + //~[edition2021]^ manual_c_str_literals let _ = "电脑\x00".as_ptr(); + //~[edition2021]^ manual_c_str_literals // Macro cases, don't lint: cstr!("foo"); diff --git a/src/tools/clippy/tests/ui/manual_clamp.fixed b/src/tools/clippy/tests/ui/manual_clamp.fixed index 8d57cbbf51bfa..2450a4f4c6115 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.fixed +++ b/src/tools/clippy/tests/ui/manual_clamp.fixed @@ -150,12 +150,10 @@ fn const_main() { 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 + //~^ manual_clamp let x5 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp let x6 = input.clamp(CONST_MIN, CONST_MAX); @@ -187,54 +185,53 @@ fn const_main() { let input: i32 = cmp_min_max(1); // These can only be detected if exactly one of the arguments to the inner function is const. let x16 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x17 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x18 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x19 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x20 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x21 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x22 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x23 = input.clamp(CONST_MIN, CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let input: f64 = cmp_min_max(1) as f64; let x24 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp + let x25 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp + let x26 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp + let x27 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp + let x28 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp + let x29 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp + let x30 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp + let x31 = input.clamp(CONST_F64_MIN, 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() + //~^ manual_clamp } let mut x32 = input; x32 = x32.clamp(CONST_MIN, CONST_MAX); diff --git a/src/tools/clippy/tests/ui/manual_clamp.rs b/src/tools/clippy/tests/ui/manual_clamp.rs index 4d2a0c47bbd7c..ee341d50768f8 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.rs +++ b/src/tools/clippy/tests/ui/manual_clamp.rs @@ -142,8 +142,8 @@ 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 + //~^ manual_clamp + CONST_MAX } else if CONST_MIN > input { CONST_MIN @@ -152,8 +152,8 @@ fn const_main() { }; let x1 = if input > CONST_MAX { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + CONST_MAX } else if input < CONST_MIN { CONST_MIN @@ -162,8 +162,8 @@ fn const_main() { }; let x2 = if input < CONST_MIN { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + CONST_MIN } else if input > CONST_MAX { CONST_MAX @@ -172,8 +172,8 @@ fn const_main() { }; let x3 = if CONST_MIN > input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + CONST_MIN } else if CONST_MAX < input { CONST_MAX @@ -182,32 +182,27 @@ fn const_main() { }; let x4 = input.max(CONST_MIN).min(CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp let x5 = input.min(CONST_MAX).max(CONST_MIN); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp let x6 = match input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp 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 + //~^ manual_clamp 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 + //~^ manual_clamp x if CONST_MAX < x => CONST_MAX, x if CONST_MIN > x => CONST_MIN, x => x, @@ -215,8 +210,8 @@ fn const_main() { let mut x9 = input; if x9 < CONST_MIN { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + x9 = CONST_MIN; } if x9 > CONST_MAX { @@ -224,8 +219,7 @@ fn const_main() { } let x10 = match input { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp x if CONST_MIN > x => CONST_MIN, x if CONST_MAX < x => CONST_MAX, x => x, @@ -234,8 +228,8 @@ fn const_main() { 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 + //~^ manual_clamp + x11 = CONST_MAX; } if x11 < CONST_MIN { @@ -244,8 +238,8 @@ fn const_main() { let mut x12 = input; if CONST_MIN > x12 { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + x12 = CONST_MIN; } if CONST_MAX < x12 { @@ -254,8 +248,8 @@ fn const_main() { let mut x13 = input; if CONST_MAX < x13 { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + x13 = CONST_MAX; } if CONST_MIN > x13 { @@ -263,8 +257,8 @@ fn const_main() { } let x14 = if input > CONST_MAX { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + CONST_MAX } else if input < CONST_MIN { CONST_MIN @@ -274,8 +268,8 @@ fn const_main() { { 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 + //~^ manual_clamp + CONST_F64_MAX } else if input < CONST_F64_MIN { CONST_F64_MIN @@ -287,59 +281,58 @@ fn const_main() { let input: i32 = cmp_min_max(1); // These can only be detected if exactly one of the arguments to the inner function is const. let x16 = cmp_max(cmp_min(input, CONST_MAX), CONST_MIN); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x17 = cmp_min(cmp_max(input, CONST_MIN), CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x18 = cmp_max(CONST_MIN, cmp_min(input, CONST_MAX)); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x19 = cmp_min(CONST_MAX, cmp_max(input, CONST_MIN)); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x20 = cmp_max(cmp_min(CONST_MAX, input), CONST_MIN); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x21 = cmp_min(cmp_max(CONST_MIN, input), CONST_MAX); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x22 = cmp_max(CONST_MIN, cmp_min(CONST_MAX, input)); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let x23 = cmp_min(CONST_MAX, cmp_max(CONST_MIN, input)); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + let input: f64 = cmp_min_max(1) as f64; let x24 = f64::max(f64::min(input, CONST_F64_MAX), CONST_F64_MIN); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() + //~^ manual_clamp + let x25 = f64::min(f64::max(input, CONST_F64_MIN), 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() + //~^ manual_clamp + let x26 = f64::max(CONST_F64_MIN, f64::min(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() + //~^ manual_clamp + let x27 = f64::min(CONST_F64_MAX, f64::max(input, CONST_F64_MIN)); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() + //~^ manual_clamp + let x28 = f64::max(f64::min(CONST_F64_MAX, input), CONST_F64_MIN); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() + //~^ manual_clamp + let x29 = f64::min(f64::max(CONST_F64_MIN, 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() + //~^ manual_clamp + let x30 = f64::max(CONST_F64_MIN, f64::min(CONST_F64_MAX, input)); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() + //~^ manual_clamp + let x31 = f64::min(CONST_F64_MAX, f64::max(CONST_F64_MIN, input)); - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min, min.is_nan(), or max.is_nan() + //~^ manual_clamp } let mut x32 = input; if x32 < CONST_MIN { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + x32 = CONST_MIN; } else if x32 > CONST_MAX { x32 = CONST_MAX; @@ -368,8 +361,8 @@ fn const_main() { // It's important this be the last set of statements let mut x35 = input; if CONST_MAX < x35 { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + x35 = CONST_MAX; } if CONST_MIN > x35 { @@ -530,8 +523,8 @@ fn msrv_1_49() { fn msrv_1_50() { let input = 0; let _ = if input > CONST_MAX { - //~^ ERROR: clamp-like pattern without using clamp function - //~| NOTE: clamp will panic if max < min + //~^ manual_clamp + CONST_MAX } else if input < CONST_MIN { CONST_MIN diff --git a/src/tools/clippy/tests/ui/manual_clamp.stderr b/src/tools/clippy/tests/ui/manual_clamp.stderr index 459d46796d875..4a0e4fa516469 100644 --- a/src/tools/clippy/tests/ui/manual_clamp.stderr +++ b/src/tools/clippy/tests/ui/manual_clamp.stderr @@ -1,5 +1,5 @@ error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:217:5 + --> tests/ui/manual_clamp.rs:212:5 | LL | / if x9 < CONST_MIN { LL | | @@ -15,7 +15,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_clamp)]` error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:236:5 + --> tests/ui/manual_clamp.rs:230:5 | LL | / if x11 > CONST_MAX { LL | | @@ -29,7 +29,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:246:5 + --> tests/ui/manual_clamp.rs:240:5 | LL | / if CONST_MIN > x12 { LL | | @@ -43,7 +43,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:256:5 + --> tests/ui/manual_clamp.rs:250:5 | LL | / if CONST_MAX < x13 { LL | | @@ -57,7 +57,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:370:5 + --> tests/ui/manual_clamp.rs:363:5 | LL | / if CONST_MAX < x35 { LL | | @@ -139,7 +139,7 @@ LL | let x4 = input.max(CONST_MIN).min(CONST_MAX); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:188:14 + --> tests/ui/manual_clamp.rs:187:14 | LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with clamp: `input.clamp(CONST_MIN, CONST_MAX)` @@ -147,12 +147,11 @@ LL | let x5 = input.min(CONST_MAX).max(CONST_MIN); = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:192:14 + --> tests/ui/manual_clamp.rs:190:14 | LL | let x6 = match input { | ______________^ LL | | -LL | | LL | | x if x > CONST_MAX => CONST_MAX, LL | | x if x < CONST_MIN => CONST_MIN, LL | | x => x, @@ -162,12 +161,11 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:200:14 + --> tests/ui/manual_clamp.rs:197:14 | LL | let x7 = match input { | ______________^ LL | | -LL | | LL | | x if x < CONST_MIN => CONST_MIN, LL | | x if x > CONST_MAX => CONST_MAX, LL | | x => x, @@ -177,12 +175,11 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:208:14 + --> tests/ui/manual_clamp.rs:204:14 | LL | let x8 = match input { | ______________^ LL | | -LL | | LL | | x if CONST_MAX < x => CONST_MAX, LL | | x if CONST_MIN > x => CONST_MIN, LL | | x => x, @@ -192,12 +189,11 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:226:15 + --> tests/ui/manual_clamp.rs:221:15 | LL | let x10 = match input { | _______________^ LL | | -LL | | LL | | x if CONST_MIN > x => CONST_MIN, LL | | x if CONST_MAX < x => CONST_MAX, LL | | x => x, @@ -207,7 +203,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:265:15 + --> tests/ui/manual_clamp.rs:259:15 | LL | let x14 = if input > CONST_MAX { | _______________^ @@ -222,7 +218,7 @@ LL | | }; = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:276:19 + --> tests/ui/manual_clamp.rs:270:19 | LL | let x15 = if input > CONST_F64_MAX { | ___________________^ @@ -238,7 +234,7 @@ LL | | }; = note: clamp returns NaN if the input is NaN error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:289:19 + --> tests/ui/manual_clamp.rs:283: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 +242,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:292:19 + --> tests/ui/manual_clamp.rs:286: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 +250,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:295:19 + --> tests/ui/manual_clamp.rs:289: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 +258,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:298:19 + --> tests/ui/manual_clamp.rs:292: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 +266,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:301:19 + --> tests/ui/manual_clamp.rs:295: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 +274,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:304:19 + --> tests/ui/manual_clamp.rs:298: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 +282,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:307:19 + --> tests/ui/manual_clamp.rs:301: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 +290,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:310:19 + --> tests/ui/manual_clamp.rs:304: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 +298,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:314:19 + --> tests/ui/manual_clamp.rs:308: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 +307,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:317:19 + --> tests/ui/manual_clamp.rs:311: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 +316,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:320:19 + --> tests/ui/manual_clamp.rs:314: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 +325,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:323:19 + --> tests/ui/manual_clamp.rs:317: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 +334,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:326:19 + --> tests/ui/manual_clamp.rs:320: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 +343,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:329:19 + --> tests/ui/manual_clamp.rs:323: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 +352,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:332:19 + --> tests/ui/manual_clamp.rs:326: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 +361,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:335:19 + --> tests/ui/manual_clamp.rs:329: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,7 +370,7 @@ 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:340:5 + --> tests/ui/manual_clamp.rs:333:5 | LL | / if x32 < CONST_MIN { LL | | @@ -388,7 +384,7 @@ LL | | } = note: clamp will panic if max < min error: clamp-like pattern without using clamp function - --> tests/ui/manual_clamp.rs:532:13 + --> tests/ui/manual_clamp.rs:525:13 | LL | let _ = if input > CONST_MAX { | _____________^ diff --git a/src/tools/clippy/tests/ui/manual_contains.fixed b/src/tools/clippy/tests/ui/manual_contains.fixed new file mode 100644 index 0000000000000..d26c948a7817c --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_contains.fixed @@ -0,0 +1,98 @@ +#![warn(clippy::manual_contains)] +#![allow(clippy::eq_op, clippy::useless_vec)] + +fn should_lint() { + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.contains(&4); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.contains(&4); + //~^ manual_contains + + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.contains(&10); + //~^ manual_contains + + let num = 14; + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.contains(&num); + //~^ manual_contains + + let num = 14; + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.contains(&num); + //~^ manual_contains + + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.contains(&4); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.contains(&4); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let a = &4; + let _ = values.contains(a); + //~^ manual_contains + + let vec = vec!["1", "2", "3", "4", "5", "6"]; + let values = &vec[..]; + let _ = values.contains(&"4"); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.contains(&(4 + 1)); + //~^ manual_contains +} + +fn should_not_lint() { + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.iter().any(|&v| v > 10); + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.iter().any(|&v| v % 2 == 0); + let _ = values.iter().any(|&v| v * 2 == 6); + let _ = values.iter().any(|&v| v == v); + let _ = values.iter().any(|&v| 4 == 4); + let _ = values.contains(&4); + + let a = 1; + let b = 2; + let _ = values.iter().any(|&v| a == b); + let _ = values.iter().any(|&v| a == 4); + + let vec: Vec = vec!["1", "2", "3", "4", "5", "6"] + .iter() + .map(|&x| x.to_string()) + .collect(); + let values = &vec[..]; + let _ = values.iter().any(|v| v == "4"); + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let mut counter = 0; + let mut count = || { + counter += 1; + counter + }; + let _ = values.iter().any(|&v| v == count()); + let _ = values.iter().any(|&v| v == v * 2); +} + +fn foo(values: &[u8]) -> bool { + values.contains(&10) + //~^ manual_contains +} + +fn bar(values: [u8; 3]) -> bool { + values.contains(&10) + //~^ manual_contains +} diff --git a/src/tools/clippy/tests/ui/manual_contains.rs b/src/tools/clippy/tests/ui/manual_contains.rs new file mode 100644 index 0000000000000..fe67d2ee5d5c6 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_contains.rs @@ -0,0 +1,98 @@ +#![warn(clippy::manual_contains)] +#![allow(clippy::eq_op, clippy::useless_vec)] + +fn should_lint() { + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.iter().any(|&v| v == 4); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.iter().any(|&v| v == 4); + //~^ manual_contains + + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.iter().any(|&v| v == 10); + //~^ manual_contains + + let num = 14; + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.iter().any(|&v| v == num); + //~^ manual_contains + + let num = 14; + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.iter().any(|&v| num == v); + //~^ manual_contains + + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.iter().any(|v| *v == 4); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.iter().any(|&v| 4 == v); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let a = &4; + let _ = values.iter().any(|v| *v == *a); + //~^ manual_contains + + let vec = vec!["1", "2", "3", "4", "5", "6"]; + let values = &vec[..]; + let _ = values.iter().any(|&v| v == "4"); + //~^ manual_contains + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.iter().any(|&v| v == 4 + 1); + //~^ manual_contains +} + +fn should_not_lint() { + let values: [u8; 6] = [3, 14, 15, 92, 6, 5]; + let _ = values.iter().any(|&v| v > 10); + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let _ = values.iter().any(|&v| v % 2 == 0); + let _ = values.iter().any(|&v| v * 2 == 6); + let _ = values.iter().any(|&v| v == v); + let _ = values.iter().any(|&v| 4 == 4); + let _ = values.contains(&4); + + let a = 1; + let b = 2; + let _ = values.iter().any(|&v| a == b); + let _ = values.iter().any(|&v| a == 4); + + let vec: Vec = vec!["1", "2", "3", "4", "5", "6"] + .iter() + .map(|&x| x.to_string()) + .collect(); + let values = &vec[..]; + let _ = values.iter().any(|v| v == "4"); + + let vec: Vec = vec![1, 2, 3, 4, 5, 6]; + let values = &vec[..]; + let mut counter = 0; + let mut count = || { + counter += 1; + counter + }; + let _ = values.iter().any(|&v| v == count()); + let _ = values.iter().any(|&v| v == v * 2); +} + +fn foo(values: &[u8]) -> bool { + values.iter().any(|&v| v == 10) + //~^ manual_contains +} + +fn bar(values: [u8; 3]) -> bool { + values.iter().any(|&v| v == 10) + //~^ manual_contains +} diff --git a/src/tools/clippy/tests/ui/manual_contains.stderr b/src/tools/clippy/tests/ui/manual_contains.stderr new file mode 100644 index 0000000000000..e6e2dea560c60 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_contains.stderr @@ -0,0 +1,77 @@ +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:7:13 + | +LL | let _ = values.iter().any(|&v| v == 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)` + | + = note: `-D clippy::manual-contains` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_contains)]` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:12:13 + | +LL | let _ = values.iter().any(|&v| v == 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:16:13 + | +LL | let _ = values.iter().any(|&v| v == 10); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&10)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:21:13 + | +LL | let _ = values.iter().any(|&v| v == num); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&num)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:26:13 + | +LL | let _ = values.iter().any(|&v| num == v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&num)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:30:13 + | +LL | let _ = values.iter().any(|v| *v == 4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:35:13 + | +LL | let _ = values.iter().any(|&v| 4 == v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&4)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:41:13 + | +LL | let _ = values.iter().any(|v| *v == *a); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(a)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:46:13 + | +LL | let _ = values.iter().any(|&v| v == "4"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&"4")` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:51:13 + | +LL | let _ = values.iter().any(|&v| v == 4 + 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&(4 + 1))` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:91:5 + | +LL | values.iter().any(|&v| v == 10) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&10)` + +error: using `contains()` instead of `iter().any()` is more efficient + --> tests/ui/manual_contains.rs:96:5 + | +LL | values.iter().any(|&v| v == 10) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `values.contains(&10)` + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed index f6eb5a9784acc..57fe8917afe88 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed +++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed @@ -6,12 +6,17 @@ fn main() { let z = 11_u32; // Lint - let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` - let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` - let _ = x.div_ceil(y); //~ ERROR: manually reimplementing `div_ceil` - - let _ = 7_u32.div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` - let _ = (7_i32 as u32).div_ceil(4); //~ ERROR: manually reimplementing `div_ceil` + let _ = x.div_ceil(y); + //~^ manual_div_ceil + let _ = x.div_ceil(y); + //~^ manual_div_ceil + let _ = x.div_ceil(y); + //~^ manual_div_ceil + + let _ = 7_u32.div_ceil(4); + //~^ manual_div_ceil + let _ = (7_i32 as u32).div_ceil(4); + //~^ manual_div_ceil // No lint let _ = (x + (y - 2)) / y; @@ -32,29 +37,40 @@ fn main() { fn issue_13843() { let x = 3usize; let _ = 2048_usize.div_ceil(x); + //~^ manual_div_ceil let x = 5usize; let _ = 2048usize.div_ceil(x); + //~^ manual_div_ceil let x = 5usize; let _ = 2048_usize.div_ceil(x); + //~^ manual_div_ceil let x = 2048usize; let _ = x.div_ceil(4); + //~^ manual_div_ceil let _: u32 = 2048_u32.div_ceil(6); + //~^ manual_div_ceil let _: usize = 2048_usize.div_ceil(6); + //~^ manual_div_ceil let _: u32 = 0x2048_u32.div_ceil(0x6); + //~^ manual_div_ceil let _ = 2048_u32.div_ceil(6u32); + //~^ manual_div_ceil let _ = 1_000_000_u32.div_ceil(6u32); + //~^ manual_div_ceil } fn issue_13950() { let x = 33u32; let _ = x.div_ceil(8); + //~^ manual_div_ceil let _ = x.div_ceil(8); + //~^ manual_div_ceil let y = -33i32; let _ = (y + -8) / -7; diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs index 2f063afe787dd..ec343513e5ce3 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.rs +++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs @@ -6,12 +6,17 @@ fn main() { let z = 11_u32; // Lint - let _ = (x + (y - 1)) / y; //~ ERROR: manually reimplementing `div_ceil` - let _ = ((y - 1) + x) / y; //~ ERROR: manually reimplementing `div_ceil` - let _ = (x + y - 1) / y; //~ ERROR: manually reimplementing `div_ceil` - - let _ = (7_u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` - let _ = (7_i32 as u32 + (4 - 1)) / 4; //~ ERROR: manually reimplementing `div_ceil` + let _ = (x + (y - 1)) / y; + //~^ manual_div_ceil + let _ = ((y - 1) + x) / y; + //~^ manual_div_ceil + let _ = (x + y - 1) / y; + //~^ manual_div_ceil + + let _ = (7_u32 + (4 - 1)) / 4; + //~^ manual_div_ceil + let _ = (7_i32 as u32 + (4 - 1)) / 4; + //~^ manual_div_ceil // No lint let _ = (x + (y - 2)) / y; @@ -32,29 +37,40 @@ fn main() { fn issue_13843() { let x = 3usize; let _ = (2048 + x - 1) / x; + //~^ manual_div_ceil let x = 5usize; let _ = (2048usize + x - 1) / x; + //~^ manual_div_ceil let x = 5usize; let _ = (2048_usize + x - 1) / x; + //~^ manual_div_ceil let x = 2048usize; let _ = (x + 4 - 1) / 4; + //~^ manual_div_ceil let _: u32 = (2048 + 6 - 1) / 6; + //~^ manual_div_ceil let _: usize = (2048 + 6 - 1) / 6; + //~^ manual_div_ceil let _: u32 = (0x2048 + 0x6 - 1) / 0x6; + //~^ manual_div_ceil let _ = (2048 + 6u32 - 1) / 6u32; + //~^ manual_div_ceil let _ = (1_000_000 + 6u32 - 1) / 6u32; + //~^ manual_div_ceil } fn issue_13950() { let x = 33u32; let _ = (x + 7) / 8; + //~^ manual_div_ceil let _ = (7 + x) / 8; + //~^ manual_div_ceil let y = -33i32; let _ = (y + -8) / -7; diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr index 0bac5d8ef1c12..8e14ab274269a 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr +++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr @@ -8,91 +8,91 @@ LL | let _ = (x + (y - 1)) / y; = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:10:13 + --> tests/ui/manual_div_ceil.rs:11:13 | LL | let _ = ((y - 1) + x) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:11:13 + --> tests/ui/manual_div_ceil.rs:13:13 | LL | let _ = (x + y - 1) / y; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:13:13 + --> tests/ui/manual_div_ceil.rs:16:13 | LL | let _ = (7_u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:14:13 + --> tests/ui/manual_div_ceil.rs:18:13 | LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:34:13 + --> tests/ui/manual_div_ceil.rs:39:13 | LL | let _ = (2048 + x - 1) / x; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:37:13 + --> tests/ui/manual_div_ceil.rs:43:13 | LL | let _ = (2048usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:40:13 + --> tests/ui/manual_div_ceil.rs:47:13 | LL | let _ = (2048_usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:43:13 + --> tests/ui/manual_div_ceil.rs:51:13 | LL | let _ = (x + 4 - 1) / 4; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:45:18 + --> tests/ui/manual_div_ceil.rs:54:18 | LL | let _: u32 = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:46:20 + --> tests/ui/manual_div_ceil.rs:56:20 | LL | let _: usize = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:47:18 + --> tests/ui/manual_div_ceil.rs:58:18 | LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:49:13 + --> tests/ui/manual_div_ceil.rs:61:13 | LL | let _ = (2048 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:51:13 + --> tests/ui/manual_div_ceil.rs:64:13 | LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:56:13 + --> tests/ui/manual_div_ceil.rs:70:13 | LL | let _ = (x + 7) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:57:13 + --> tests/ui/manual_div_ceil.rs:72:13 | LL | let _ = (7 + x) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed index 01c58151bc946..f55999c5ad080 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.fixed @@ -9,13 +9,20 @@ fn main() { // Lint. let _ = x.div_ceil(y); + //~^ manual_div_ceil let _ = x.div_ceil(y); + //~^ manual_div_ceil let _ = x.div_ceil(y); + //~^ manual_div_ceil let _ = 7_i32.div_ceil(4); + //~^ manual_div_ceil let _ = (7_i32 as u32).div_ceil(4); + //~^ manual_div_ceil let _ = (7_u32 as i32).div_ceil(4); + //~^ manual_div_ceil let _ = z_u.div_ceil(4); + //~^ manual_div_ceil // No lint. let _ = (x + (y - 2)) / y; @@ -27,37 +34,53 @@ fn main() { fn issue_13843() { let x = 3usize; let _ = 2048_usize.div_ceil(x); + //~^ manual_div_ceil let x = 5usize; let _ = 2048usize.div_ceil(x); + //~^ manual_div_ceil let x = 5usize; let _ = 2048_usize.div_ceil(x); + //~^ manual_div_ceil let x = 2048usize; let _ = x.div_ceil(4); + //~^ manual_div_ceil let _ = 2048_i32.div_ceil(4); + //~^ manual_div_ceil let _: u32 = 2048_u32.div_ceil(6); + //~^ manual_div_ceil let _: usize = 2048_usize.div_ceil(6); + //~^ manual_div_ceil let _: u32 = 0x2048_u32.div_ceil(0x6); + //~^ manual_div_ceil let _ = 2048_u32.div_ceil(6u32); + //~^ manual_div_ceil let x = -2; let _ = (-2048_i32).div_ceil(x); + //~^ manual_div_ceil let _ = 1_000_000_u32.div_ceil(6u32); + //~^ manual_div_ceil } fn issue_13950() { let x = 33u32; let _ = x.div_ceil(8); + //~^ manual_div_ceil let _ = x.div_ceil(8); + //~^ manual_div_ceil let y = -33i32; let _ = y.div_ceil(-7); + //~^ manual_div_ceil let _ = y.div_ceil(-7); + //~^ manual_div_ceil let _ = y.div_ceil(-7); + //~^ manual_div_ceil } diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs index 048ff401581f7..8a895f634cb45 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.rs @@ -9,13 +9,20 @@ fn main() { // Lint. let _ = (x + (y - 1)) / y; + //~^ manual_div_ceil let _ = ((y - 1) + x) / y; + //~^ manual_div_ceil let _ = (x + y - 1) / y; + //~^ manual_div_ceil let _ = (7_i32 + (4 - 1)) / 4; + //~^ manual_div_ceil let _ = (7_i32 as u32 + (4 - 1)) / 4; + //~^ manual_div_ceil let _ = (7_u32 as i32 + (4 - 1)) / 4; + //~^ manual_div_ceil let _ = (z_u + (4 - 1)) / 4; + //~^ manual_div_ceil // No lint. let _ = (x + (y - 2)) / y; @@ -27,37 +34,53 @@ fn main() { fn issue_13843() { let x = 3usize; let _ = (2048 + x - 1) / x; + //~^ manual_div_ceil let x = 5usize; let _ = (2048usize + x - 1) / x; + //~^ manual_div_ceil let x = 5usize; let _ = (2048_usize + x - 1) / x; + //~^ manual_div_ceil let x = 2048usize; let _ = (x + 4 - 1) / 4; + //~^ manual_div_ceil let _ = (2048 + 4 - 1) / 4; + //~^ manual_div_ceil let _: u32 = (2048 + 6 - 1) / 6; + //~^ manual_div_ceil let _: usize = (2048 + 6 - 1) / 6; + //~^ manual_div_ceil let _: u32 = (0x2048 + 0x6 - 1) / 0x6; + //~^ manual_div_ceil let _ = (2048 + 6u32 - 1) / 6u32; + //~^ manual_div_ceil let x = -2; let _ = (-2048 + x - 1) / x; + //~^ manual_div_ceil let _ = (1_000_000 + 6u32 - 1) / 6u32; + //~^ manual_div_ceil } fn issue_13950() { let x = 33u32; let _ = (x + 7) / 8; + //~^ manual_div_ceil let _ = (7 + x) / 8; + //~^ manual_div_ceil let y = -33i32; let _ = (y + -8) / -7; + //~^ manual_div_ceil let _ = (-8 + y) / -7; + //~^ manual_div_ceil let _ = (y - 8) / -7; + //~^ manual_div_ceil } diff --git a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr index 807cfd82724e5..e1160d9629963 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr +++ b/src/tools/clippy/tests/ui/manual_div_ceil_with_feature.stderr @@ -8,133 +8,133 @@ LL | let _ = (x + (y - 1)) / y; = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:12:13 + --> tests/ui/manual_div_ceil_with_feature.rs:13:13 | LL | let _ = ((y - 1) + x) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:13:13 + --> tests/ui/manual_div_ceil_with_feature.rs:15:13 | LL | let _ = (x + y - 1) / y; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:15:13 + --> tests/ui/manual_div_ceil_with_feature.rs:18:13 | LL | let _ = (7_i32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_i32.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:16:13 + --> tests/ui/manual_div_ceil_with_feature.rs:20:13 | LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:17:13 + --> tests/ui/manual_div_ceil_with_feature.rs:22:13 | LL | let _ = (7_u32 as i32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_u32 as i32).div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:18:13 + --> tests/ui/manual_div_ceil_with_feature.rs:24:13 | LL | let _ = (z_u + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `z_u.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:29:13 + --> tests/ui/manual_div_ceil_with_feature.rs:36:13 | LL | let _ = (2048 + x - 1) / x; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:32:13 + --> tests/ui/manual_div_ceil_with_feature.rs:40:13 | LL | let _ = (2048usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:35:13 + --> tests/ui/manual_div_ceil_with_feature.rs:44:13 | LL | let _ = (2048_usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:38:13 + --> tests/ui/manual_div_ceil_with_feature.rs:48:13 | LL | let _ = (x + 4 - 1) / 4; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:40:13 + --> tests/ui/manual_div_ceil_with_feature.rs:51:13 | LL | let _ = (2048 + 4 - 1) / 4; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_i32.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:42:18 + --> tests/ui/manual_div_ceil_with_feature.rs:54:18 | LL | let _: u32 = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:43:20 + --> tests/ui/manual_div_ceil_with_feature.rs:56:20 | LL | let _: usize = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:44:18 + --> tests/ui/manual_div_ceil_with_feature.rs:58:18 | LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:46:13 + --> tests/ui/manual_div_ceil_with_feature.rs:61:13 | LL | let _ = (2048 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:49:13 + --> tests/ui/manual_div_ceil_with_feature.rs:65:13 | LL | let _ = (-2048 + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(-2048_i32).div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:51:13 + --> tests/ui/manual_div_ceil_with_feature.rs:68:13 | LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:56:13 + --> tests/ui/manual_div_ceil_with_feature.rs:74:13 | LL | let _ = (x + 7) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:57:13 + --> tests/ui/manual_div_ceil_with_feature.rs:76:13 | LL | let _ = (7 + x) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:60:13 + --> tests/ui/manual_div_ceil_with_feature.rs:80:13 | LL | let _ = (y + -8) / -7; | ^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:61:13 + --> tests/ui/manual_div_ceil_with_feature.rs:82:13 | LL | let _ = (-8 + y) / -7; | ^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil_with_feature.rs:62:13 + --> tests/ui/manual_div_ceil_with_feature.rs:84:13 | LL | let _ = (y - 8) / -7; | ^^^^^^^^^^^^ help: consider using `.div_ceil()`: `y.div_ceil(-7)` diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs index 0ac6cbefc4ecb..a9d0c35f8bb72 100644 --- a/src/tools/clippy/tests/ui/manual_filter.rs +++ b/src/tools/clippy/tests/ui/manual_filter.rs @@ -3,6 +3,7 @@ fn main() { match Some(0) { + //~^ manual_filter None => None, Some(x) => { if x > 0 { @@ -14,6 +15,7 @@ fn main() { }; match Some(1) { + //~^ manual_filter Some(x) => { if x > 0 { None @@ -25,6 +27,7 @@ fn main() { }; match Some(2) { + //~^ manual_filter Some(x) => { if x > 0 { None @@ -36,6 +39,7 @@ fn main() { }; match Some(3) { + //~^ manual_filter Some(x) => { if x > 0 { Some(x) @@ -48,6 +52,7 @@ fn main() { let y = Some(4); match y { + //~^ manual_filter // Some(4) None => None, Some(x) => { @@ -60,6 +65,7 @@ fn main() { }; match Some(5) { + //~^ manual_filter Some(x) => { if x > 0 { Some(x) @@ -71,6 +77,7 @@ fn main() { }; match Some(6) { + //~^ manual_filter Some(ref x) => { if x > &0 { Some(x) @@ -83,6 +90,7 @@ fn main() { let external_cond = true; match Some(String::new()) { + //~^ manual_filter Some(x) => { if external_cond { Some(x) @@ -94,12 +102,14 @@ fn main() { }; if let Some(x) = Some(7) { + //~^ manual_filter if external_cond { Some(x) } else { None } } else { None }; match &Some(8) { + //~^ manual_filter &Some(x) => { if x != 0 { Some(x) @@ -111,6 +121,7 @@ fn main() { }; match Some(9) { + //~^ manual_filter Some(x) => { if x > 10 && x < 100 { Some(x) @@ -137,6 +148,7 @@ fn main() { #[allow(clippy::blocks_in_conditions)] match Some(11) { + //~^ manual_filter // Lint, statement is preserved by `.filter` Some(x) => { if { @@ -181,6 +193,7 @@ fn main() { true } let _ = match Some(14) { + //~^ manual_filter Some(x) => { if unsafe { f(x) } { Some(x) @@ -191,6 +204,7 @@ fn main() { None => None, }; let _ = match Some(15) { + //~^ manual_filter Some(x) => unsafe { if f(x) { Some(x) } else { None } }, None => None, }; @@ -199,6 +213,7 @@ fn main() { if let Some(_) = Some(16) { Some(16) } else if let Some(x) = Some(16) { + //~^ manual_filter // Lint starting from here if x % 2 == 0 { Some(x) } else { None } } else { diff --git a/src/tools/clippy/tests/ui/manual_filter.stderr b/src/tools/clippy/tests/ui/manual_filter.stderr index 3add706d7f73c..63463997f4357 100644 --- a/src/tools/clippy/tests/ui/manual_filter.stderr +++ b/src/tools/clippy/tests/ui/manual_filter.stderr @@ -2,9 +2,9 @@ error: manual implementation of `Option::filter` --> tests/ui/manual_filter.rs:5:5 | LL | / match Some(0) { +LL | | LL | | None => None, LL | | Some(x) => { -LL | | if x > 0 { ... | LL | | }, LL | | }; @@ -14,93 +14,94 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::manual_filter)]` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:16:5 + --> tests/ui/manual_filter.rs:17:5 | LL | / match Some(1) { +LL | | LL | | Some(x) => { LL | | if x > 0 { -LL | | None ... | LL | | None => None, LL | | }; | |_____^ help: try: `Some(1).filter(|&x| x <= 0)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:27:5 + --> tests/ui/manual_filter.rs:29:5 | LL | / match Some(2) { +LL | | LL | | Some(x) => { LL | | if x > 0 { -LL | | None ... | LL | | _ => None, LL | | }; | |_____^ help: try: `Some(2).filter(|&x| x <= 0)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:38:5 + --> tests/ui/manual_filter.rs:41:5 | LL | / match Some(3) { +LL | | LL | | Some(x) => { LL | | if x > 0 { -LL | | Some(x) ... | LL | | None => None, LL | | }; | |_____^ help: try: `Some(3).filter(|&x| x > 0)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:50:5 + --> tests/ui/manual_filter.rs:54:5 | LL | / match y { +LL | | LL | | // Some(4) LL | | None => None, -LL | | Some(x) => { ... | LL | | }, LL | | }; | |_____^ help: try: `y.filter(|&x| x <= 0)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:62:5 + --> tests/ui/manual_filter.rs:67:5 | LL | / match Some(5) { +LL | | LL | | Some(x) => { LL | | if x > 0 { -LL | | Some(x) ... | LL | | _ => None, LL | | }; | |_____^ help: try: `Some(5).filter(|&x| x > 0)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:73:5 + --> tests/ui/manual_filter.rs:79:5 | LL | / match Some(6) { +LL | | LL | | Some(ref x) => { LL | | if x > &0 { -LL | | Some(x) ... | LL | | _ => None, LL | | }; | |_____^ help: try: `Some(6).as_ref().filter(|&x| x > &0)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:85:5 + --> tests/ui/manual_filter.rs:92:5 | LL | / match Some(String::new()) { +LL | | LL | | Some(x) => { LL | | if external_cond { -LL | | Some(x) ... | LL | | _ => None, LL | | }; | |_____^ help: try: `Some(String::new()).filter(|x| external_cond)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:96:5 + --> tests/ui/manual_filter.rs:104:5 | LL | / if let Some(x) = Some(7) { +LL | | LL | | if external_cond { Some(x) } else { None } LL | | } else { LL | | None @@ -108,36 +109,36 @@ LL | | }; | |_____^ help: try: `Some(7).filter(|&x| external_cond)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:102:5 + --> tests/ui/manual_filter.rs:111:5 | LL | / match &Some(8) { +LL | | LL | | &Some(x) => { LL | | if x != 0 { -LL | | Some(x) ... | LL | | _ => None, LL | | }; | |_____^ help: try: `Some(8).filter(|&x| x != 0)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:113:5 + --> tests/ui/manual_filter.rs:123:5 | LL | / match Some(9) { +LL | | LL | | Some(x) => { LL | | if x > 10 && x < 100 { -LL | | Some(x) ... | LL | | None => None, LL | | }; | |_____^ help: try: `Some(9).filter(|&x| x > 10 && x < 100)` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:139:5 + --> tests/ui/manual_filter.rs:150:5 | LL | / match Some(11) { +LL | | LL | | // Lint, statement is preserved by `.filter` LL | | Some(x) => { -LL | | if { ... | LL | | None => None, LL | | }; @@ -152,33 +153,35 @@ LL ~ }); | error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:183:13 + --> tests/ui/manual_filter.rs:195:13 | LL | let _ = match Some(14) { | _____________^ +LL | | LL | | Some(x) => { LL | | if unsafe { f(x) } { -LL | | Some(x) ... | LL | | None => None, LL | | }; | |_____^ help: try: `Some(14).filter(|&x| unsafe { f(x) })` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:193:13 + --> tests/ui/manual_filter.rs:206:13 | LL | let _ = match Some(15) { | _____________^ +LL | | LL | | Some(x) => unsafe { if f(x) { Some(x) } else { None } }, LL | | None => None, LL | | }; | |_____^ help: try: `Some(15).filter(|&x| unsafe { f(x) })` error: manual implementation of `Option::filter` - --> tests/ui/manual_filter.rs:201:12 + --> tests/ui/manual_filter.rs:215:12 | LL | } else if let Some(x) = Some(16) { | ____________^ +LL | | LL | | // Lint starting from here LL | | if x % 2 == 0 { Some(x) } else { None } LL | | } else { diff --git a/src/tools/clippy/tests/ui/manual_filter_map.fixed b/src/tools/clippy/tests/ui/manual_filter_map.fixed index a44c46c145c6c..caf82289031f7 100644 --- a/src/tools/clippy/tests/ui/manual_filter_map.fixed +++ b/src/tools/clippy/tests/ui/manual_filter_map.fixed @@ -7,12 +7,15 @@ fn main() { // is_some(), unwrap() let _ = (0..).filter_map(|a| to_opt(a)); + //~^ manual_filter_map // ref pattern, expect() let _ = (0..).filter_map(|a| to_opt(a)); + //~^ manual_filter_map // is_ok(), unwrap_or() let _ = (0..).filter_map(|a| to_res(a).ok()); + //~^ manual_filter_map let _ = (1..5) .filter_map(|y| *to_ref(to_opt(y))); @@ -28,17 +31,28 @@ fn main() { #[rustfmt::skip] fn simple_equal() { iter::>().find_map(|x| x.cloned()); + //~^ manual_find_map iter::<&Option<&u8>>().find_map(|x| x.cloned()); + //~^ manual_find_map iter::<&Option>().find_map(|x| x.as_deref()); + //~^ manual_find_map iter::>().find_map(|y| to_ref(y).cloned()); + //~^ manual_find_map iter::>().find_map(|x| x.ok()); + //~^ manual_find_map iter::<&Result>().find_map(|x| x.ok()); + //~^ manual_find_map iter::<&&Result>().find_map(|x| x.ok()); + //~^ manual_find_map iter::>().find_map(|x| x.cloned().ok()); + //~^ manual_find_map iter::<&Result<&u8, ()>>().find_map(|x| x.cloned().ok()); + //~^ manual_find_map iter::<&Result>().find_map(|x| x.as_deref().ok()); + //~^ manual_find_map iter::>().find_map(|y| to_ref(y).cloned().ok()); + //~^ manual_find_map } fn no_lint() { diff --git a/src/tools/clippy/tests/ui/manual_filter_map.rs b/src/tools/clippy/tests/ui/manual_filter_map.rs index e72d0c4305b34..013c88da6b36f 100644 --- a/src/tools/clippy/tests/ui/manual_filter_map.rs +++ b/src/tools/clippy/tests/ui/manual_filter_map.rs @@ -7,42 +7,60 @@ fn main() { // is_some(), unwrap() let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + //~^ manual_filter_map // ref pattern, expect() let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + //~^ manual_filter_map // is_ok(), unwrap_or() let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + //~^ manual_filter_map let _ = (1..5) .filter(|&x| to_ref(to_opt(x)).is_some()) + //~^ manual_filter_map .map(|y| to_ref(to_opt(y)).unwrap()); let _ = (1..5) .filter(|x| to_ref(to_opt(*x)).is_some()) + //~^ manual_filter_map .map(|y| to_ref(to_opt(y)).unwrap()); let _ = (1..5) .filter(|&x| to_ref(to_res(x)).is_ok()) + //~^ manual_filter_map .map(|y| to_ref(to_res(y)).unwrap()); let _ = (1..5) .filter(|x| to_ref(to_res(*x)).is_ok()) + //~^ manual_filter_map .map(|y| to_ref(to_res(y)).unwrap()); } #[rustfmt::skip] fn simple_equal() { iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); + //~^ manual_find_map iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + //~^ manual_find_map iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); + //~^ manual_find_map iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + //~^ manual_find_map iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + //~^ manual_find_map iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); + //~^ manual_find_map iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); + //~^ manual_find_map } fn no_lint() { @@ -91,46 +109,55 @@ fn issue_8920() { let _ = vec .iter() .filter(|f| f.option_field.is_some()) + //~^ manual_filter_map .map(|f| f.option_field.clone().unwrap()); let _ = vec .iter() .filter(|f| f.ref_field.is_some()) + //~^ manual_filter_map .map(|f| f.ref_field.cloned().unwrap()); let _ = vec .iter() .filter(|f| f.ref_field.is_some()) + //~^ manual_filter_map .map(|f| f.ref_field.copied().unwrap()); let _ = vec .iter() .filter(|f| f.result_field.is_ok()) + //~^ manual_filter_map .map(|f| f.result_field.clone().unwrap()); let _ = vec .iter() .filter(|f| f.result_field.is_ok()) + //~^ manual_filter_map .map(|f| f.result_field.as_ref().unwrap()); let _ = vec .iter() .filter(|f| f.result_field.is_ok()) + //~^ manual_filter_map .map(|f| f.result_field.as_deref().unwrap()); let _ = vec .iter_mut() .filter(|f| f.result_field.is_ok()) + //~^ manual_filter_map .map(|f| f.result_field.as_mut().unwrap()); let _ = vec .iter_mut() .filter(|f| f.result_field.is_ok()) + //~^ manual_filter_map .map(|f| f.result_field.as_deref_mut().unwrap()); let _ = vec .iter() .filter(|f| f.result_field.is_ok()) + //~^ manual_filter_map .map(|f| f.result_field.to_owned().unwrap()); } @@ -144,6 +171,7 @@ fn issue8010() { let iter = [Enum::A(123), Enum::B].into_iter(); let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x { + //~^ manual_filter_map Enum::A(s) => s, _ => unreachable!(), }); @@ -154,6 +182,7 @@ fn issue8010() { let _x = iter .clone() .filter(|x| matches!(x, Enum::A(_))) + //~^ manual_filter_map .map(|x| if let Enum::A(s) = x { s } else { unreachable!() }); #[allow(clippy::unused_unit)] let _x = iter diff --git a/src/tools/clippy/tests/ui/manual_filter_map.stderr b/src/tools/clippy/tests/ui/manual_filter_map.stderr index 2e50567278319..07c894bf0e663 100644 --- a/src/tools/clippy/tests/ui/manual_filter_map.stderr +++ b/src/tools/clippy/tests/ui/manual_filter_map.stderr @@ -13,87 +13,91 @@ LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap = help: to override `-D warnings` add `#[allow(clippy::manual_filter_map)]` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:12:19 + --> tests/ui/manual_filter_map.rs:13:19 | LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:12:31 + --> tests/ui/manual_filter_map.rs:13:31 | LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:15:19 + --> tests/ui/manual_filter_map.rs:17:19 | LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:15:31 + --> tests/ui/manual_filter_map.rs:17:31 | LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:18:10 + --> tests/ui/manual_filter_map.rs:21:10 | LL | .filter(|&x| to_ref(to_opt(x)).is_some()) | __________^ +LL | | LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:18:22 + --> tests/ui/manual_filter_map.rs:21:22 | LL | .filter(|&x| to_ref(to_opt(x)).is_some()) | ^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:21:10 + --> tests/ui/manual_filter_map.rs:25:10 | LL | .filter(|x| to_ref(to_opt(*x)).is_some()) | __________^ +LL | | LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:21:21 + --> tests/ui/manual_filter_map.rs:25:21 | LL | .filter(|x| to_ref(to_opt(*x)).is_some()) | ^^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:25:10 + --> tests/ui/manual_filter_map.rs:30:10 | LL | .filter(|&x| to_ref(to_res(x)).is_ok()) | __________^ +LL | | LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:25:22 + --> tests/ui/manual_filter_map.rs:30:22 | LL | .filter(|&x| to_ref(to_res(x)).is_ok()) | ^^^^^^^^^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:28:10 + --> tests/ui/manual_filter_map.rs:34:10 | LL | .filter(|x| to_ref(to_res(*x)).is_ok()) | __________^ +LL | | LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:28:21 + --> tests/ui/manual_filter_map.rs:34:21 | LL | .filter(|x| to_ref(to_res(*x)).is_ok()) | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:34:27 + --> tests/ui/manual_filter_map.rs:41:27 | LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` @@ -102,164 +106,175 @@ LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap() = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:35:28 + --> tests/ui/manual_filter_map.rs:43:28 | LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:36:31 + --> tests/ui/manual_filter_map.rs:45:31 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:37:31 + --> tests/ui/manual_filter_map.rs:47:31 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:37:41 + --> tests/ui/manual_filter_map.rs:47:41 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:39:30 + --> tests/ui/manual_filter_map.rs:50:30 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:40:31 + --> tests/ui/manual_filter_map.rs:52:31 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:41:32 + --> tests/ui/manual_filter_map.rs:54:32 | LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:42:31 + --> tests/ui/manual_filter_map.rs:56:31 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:43:32 + --> tests/ui/manual_filter_map.rs:58:32 | LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:44:35 + --> tests/ui/manual_filter_map.rs:60:35 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_filter_map.rs:45:35 + --> tests/ui/manual_filter_map.rs:62:35 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_filter_map.rs:45:45 + --> tests/ui/manual_filter_map.rs:62:45 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:93:10 + --> tests/ui/manual_filter_map.rs:111:10 | LL | .filter(|f| f.option_field.is_some()) | __________^ +LL | | LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:98:10 + --> tests/ui/manual_filter_map.rs:117:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ +LL | | LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:103:10 + --> tests/ui/manual_filter_map.rs:123:10 | LL | .filter(|f| f.ref_field.is_some()) | __________^ +LL | | LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:108:10 + --> tests/ui/manual_filter_map.rs:129:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:113:10 + --> tests/ui/manual_filter_map.rs:135:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:118:10 + --> tests/ui/manual_filter_map.rs:141:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:123:10 + --> tests/ui/manual_filter_map.rs:147:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:128:10 + --> tests/ui/manual_filter_map.rs:153:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:133:10 + --> tests/ui/manual_filter_map.rs:159:10 | LL | .filter(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.to_owned().unwrap()); | |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:146:27 + --> tests/ui/manual_filter_map.rs:173:27 | LL | let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x { | ___________________________^ +LL | | LL | | Enum::A(s) => s, LL | | _ => unreachable!(), LL | | }); | |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })` error: `filter(..).map(..)` can be simplified as `filter_map(..)` - --> tests/ui/manual_filter_map.rs:156:10 + --> tests/ui/manual_filter_map.rs:184:10 | LL | .filter(|x| matches!(x, Enum::A(_))) | __________^ +LL | | LL | | .map(|x| if let Enum::A(s) = x { s } else { unreachable!() }); | |_____________________________________________________________________^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })` diff --git a/src/tools/clippy/tests/ui/manual_find.rs b/src/tools/clippy/tests/ui/manual_find.rs index 0a105b0359e50..20b557f21d141 100644 --- a/src/tools/clippy/tests/ui/manual_find.rs +++ b/src/tools/clippy/tests/ui/manual_find.rs @@ -3,8 +3,8 @@ //@no-rustfix fn vec_string(strings: Vec) -> Option { for s in strings { - //~^ ERROR: manual implementation of `Iterator::find` - //~| NOTE: you may need to dereference some variables + //~^ manual_find + if s == String::new() { return Some(s); } @@ -14,8 +14,8 @@ fn vec_string(strings: Vec) -> Option { fn tuple(arr: Vec<(String, i32)>) -> Option { for (s, _) in arr { - //~^ ERROR: manual implementation of `Iterator::find` - //~| NOTE: you may need to dereference some variables + //~^ manual_find + if s == String::new() { return Some(s); } diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.rs b/src/tools/clippy/tests/ui/manual_find_fixable.rs index 56c3f2629c7a2..08a7dd2c6eeef 100644 --- a/src/tools/clippy/tests/ui/manual_find_fixable.rs +++ b/src/tools/clippy/tests/ui/manual_find_fixable.rs @@ -8,6 +8,7 @@ const ARRAY: &[u32; 5] = &[2, 7, 1, 9, 3]; fn lookup(n: u32) -> Option { for &v in ARRAY { + //~^ manual_find if v == n { return Some(v); } @@ -17,6 +18,7 @@ fn lookup(n: u32) -> Option { fn with_pat(arr: Vec<(u32, u32)>) -> Option { for (a, _) in arr { + //~^ manual_find if a % 2 == 0 { return Some(a); } @@ -30,6 +32,7 @@ struct Data { } fn with_struct(arr: Vec) -> Option { for el in arr { + //~^ manual_find if el.name.len() == 10 { return Some(el); } @@ -40,6 +43,7 @@ fn with_struct(arr: Vec) -> Option { struct Tuple(usize, usize); fn with_tuple_struct(arr: Vec) -> Option { for Tuple(a, _) in arr { + //~^ manual_find if a >= 3 { return Some(a); } @@ -55,6 +59,7 @@ impl A { } fn with_method_call(arr: Vec) -> Option { for el in arr { + //~^ manual_find if el.should_keep() { return Some(el); } @@ -65,6 +70,7 @@ fn with_method_call(arr: Vec) -> Option { fn with_closure(arr: Vec) -> Option { let f = |el: u32| -> u32 { el + 10 }; for el in arr { + //~^ manual_find if f(el) == 20 { return Some(el); } @@ -75,6 +81,7 @@ fn with_closure(arr: Vec) -> Option { fn with_closure2(arr: HashMap) -> Option { let f = |el: i32| -> bool { el == 10 }; for &el in arr.values() { + //~^ manual_find if f(el) { return Some(el); } @@ -84,6 +91,7 @@ fn with_closure2(arr: HashMap) -> Option { fn with_bool(arr: Vec) -> Option { for el in arr { + //~^ manual_find if el.is_true { return Some(el); } @@ -114,6 +122,7 @@ fn with_else(arr: Vec) -> Option { fn tuple_with_ref(v: [(u8, &u8); 3]) -> Option { for (_, &x) in v { + //~^ manual_find if x > 10 { return Some(x); } @@ -123,6 +132,7 @@ fn tuple_with_ref(v: [(u8, &u8); 3]) -> Option { fn ref_to_tuple_with_ref(v: &[(u8, &u8)]) -> Option { for &(_, &x) in v { + //~^ manual_find if x > 10 { return Some(x); } @@ -132,6 +142,7 @@ fn ref_to_tuple_with_ref(v: &[(u8, &u8)]) -> Option { fn explicit_ret(arr: Vec) -> Option { for x in arr { + //~^ manual_find if x >= 5 { return Some(x); } @@ -187,6 +198,7 @@ fn as_closure() { #[rustfmt::skip] let f = |arr: Vec| -> Option { for x in arr { + //~^ manual_find if x < 1 { return Some(x); } diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.stderr b/src/tools/clippy/tests/ui/manual_find_fixable.stderr index 5ed8be1b3eeda..afa453c5a876a 100644 --- a/src/tools/clippy/tests/ui/manual_find_fixable.stderr +++ b/src/tools/clippy/tests/ui/manual_find_fixable.stderr @@ -2,6 +2,7 @@ error: manual implementation of `Iterator::find` --> tests/ui/manual_find_fixable.rs:10:5 | LL | / for &v in ARRAY { +LL | | LL | | if v == n { LL | | return Some(v); ... | @@ -12,9 +13,10 @@ LL | | None = help: to override `-D warnings` add `#[allow(clippy::manual_find)]` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:19:5 + --> tests/ui/manual_find_fixable.rs:20:5 | LL | / for (a, _) in arr { +LL | | LL | | if a % 2 == 0 { LL | | return Some(a); ... | @@ -22,9 +24,10 @@ LL | | None | |________^ help: replace with an iterator: `arr.into_iter().map(|(a, _)| a).find(|&a| a % 2 == 0)` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:32:5 + --> tests/ui/manual_find_fixable.rs:34:5 | LL | / for el in arr { +LL | | LL | | if el.name.len() == 10 { LL | | return Some(el); ... | @@ -34,9 +37,10 @@ LL | | None = note: you may need to dereference some variables error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:42:5 + --> tests/ui/manual_find_fixable.rs:45:5 | LL | / for Tuple(a, _) in arr { +LL | | LL | | if a >= 3 { LL | | return Some(a); ... | @@ -44,9 +48,10 @@ LL | | None | |________^ help: replace with an iterator: `arr.into_iter().map(|Tuple(a, _)| a).find(|&a| a >= 3)` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:57:5 + --> tests/ui/manual_find_fixable.rs:61:5 | LL | / for el in arr { +LL | | LL | | if el.should_keep() { LL | | return Some(el); ... | @@ -56,9 +61,10 @@ LL | | None = note: you may need to dereference some variables error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:67:5 + --> tests/ui/manual_find_fixable.rs:72:5 | LL | / for el in arr { +LL | | LL | | if f(el) == 20 { LL | | return Some(el); ... | @@ -66,9 +72,10 @@ LL | | None | |________^ help: replace with an iterator: `arr.into_iter().find(|&el| f(el) == 20)` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:77:5 + --> tests/ui/manual_find_fixable.rs:83:5 | LL | / for &el in arr.values() { +LL | | LL | | if f(el) { LL | | return Some(el); ... | @@ -76,9 +83,10 @@ LL | | None | |________^ help: replace with an iterator: `arr.values().find(|&&el| f(el)).copied()` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:86:5 + --> tests/ui/manual_find_fixable.rs:93:5 | LL | / for el in arr { +LL | | LL | | if el.is_true { LL | | return Some(el); ... | @@ -88,9 +96,10 @@ LL | | None = note: you may need to dereference some variables error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:116:5 + --> tests/ui/manual_find_fixable.rs:124:5 | LL | / for (_, &x) in v { +LL | | LL | | if x > 10 { LL | | return Some(x); ... | @@ -98,9 +107,10 @@ LL | | None | |________^ help: replace with an iterator: `v.into_iter().map(|(_, &x)| x).find(|&x| x > 10)` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:125:5 + --> tests/ui/manual_find_fixable.rs:134:5 | LL | / for &(_, &x) in v { +LL | | LL | | if x > 10 { LL | | return Some(x); ... | @@ -108,9 +118,10 @@ LL | | None | |________^ help: replace with an iterator: `v.iter().map(|&(_, &x)| x).find(|&x| x > 10)` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:134:5 + --> tests/ui/manual_find_fixable.rs:144:5 | LL | / for x in arr { +LL | | LL | | if x >= 5 { LL | | return Some(x); ... | @@ -118,9 +129,10 @@ LL | | return None; | |________________^ help: replace with an iterator: `arr.into_iter().find(|&x| x >= 5)` error: manual implementation of `Iterator::find` - --> tests/ui/manual_find_fixable.rs:189:9 + --> tests/ui/manual_find_fixable.rs:200:9 | LL | / for x in arr { +LL | | LL | | if x < 1 { LL | | return Some(x); ... | diff --git a/src/tools/clippy/tests/ui/manual_find_map.fixed b/src/tools/clippy/tests/ui/manual_find_map.fixed index 2d9a356b9bcda..1a452d50261f9 100644 --- a/src/tools/clippy/tests/ui/manual_find_map.fixed +++ b/src/tools/clippy/tests/ui/manual_find_map.fixed @@ -7,12 +7,15 @@ fn main() { // is_some(), unwrap() let _ = (0..).find_map(|a| to_opt(a)); + //~^ manual_find_map // ref pattern, expect() let _ = (0..).find_map(|a| to_opt(a)); + //~^ manual_find_map // is_ok(), unwrap_or() let _ = (0..).find_map(|a| to_res(a).ok()); + //~^ manual_find_map let _ = (1..5) .find_map(|y| *to_ref(to_opt(y))); @@ -28,20 +31,34 @@ fn main() { #[rustfmt::skip] fn simple_equal() { iter::>().find_map(|x| x); + //~^ manual_find_map iter::<&Option>().find_map(|x| *x); + //~^ manual_find_map iter::<&&Option>().find_map(|x| **x); + //~^ manual_find_map iter::>().find_map(|x| x.cloned()); + //~^ manual_find_map iter::<&Option<&u8>>().find_map(|x| x.cloned()); + //~^ manual_find_map iter::<&Option>().find_map(|x| x.as_deref()); + //~^ manual_find_map iter::>().find_map(|y| to_ref(y).cloned()); + //~^ manual_find_map iter::>().find_map(|x| x.ok()); + //~^ manual_find_map iter::<&Result>().find_map(|x| x.ok()); + //~^ manual_find_map iter::<&&Result>().find_map(|x| x.ok()); + //~^ manual_find_map iter::>().find_map(|x| x.cloned().ok()); + //~^ manual_find_map iter::<&Result<&u8, ()>>().find_map(|x| x.cloned().ok()); + //~^ manual_find_map iter::<&Result>().find_map(|x| x.as_deref().ok()); + //~^ manual_find_map iter::>().find_map(|y| to_ref(y).cloned().ok()); + //~^ manual_find_map } fn no_lint() { diff --git a/src/tools/clippy/tests/ui/manual_find_map.rs b/src/tools/clippy/tests/ui/manual_find_map.rs index 7c5cc136695a7..9415a2d2b5724 100644 --- a/src/tools/clippy/tests/ui/manual_find_map.rs +++ b/src/tools/clippy/tests/ui/manual_find_map.rs @@ -7,45 +7,66 @@ fn main() { // is_some(), unwrap() let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()); + //~^ manual_find_map // ref pattern, expect() let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); + //~^ manual_find_map // is_ok(), unwrap_or() let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); + //~^ manual_find_map let _ = (1..5) .find(|&x| to_ref(to_opt(x)).is_some()) + //~^ manual_find_map .map(|y| to_ref(to_opt(y)).unwrap()); let _ = (1..5) .find(|x| to_ref(to_opt(*x)).is_some()) + //~^ manual_find_map .map(|y| to_ref(to_opt(y)).unwrap()); let _ = (1..5) .find(|&x| to_ref(to_res(x)).is_ok()) + //~^ manual_find_map .map(|y| to_ref(to_res(y)).unwrap()); let _ = (1..5) .find(|x| to_ref(to_res(*x)).is_ok()) + //~^ manual_find_map .map(|y| to_ref(to_res(y)).unwrap()); } #[rustfmt::skip] fn simple_equal() { iter::>().find(|x| x.is_some()).map(|x| x.unwrap()); + //~^ manual_find_map iter::<&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); + //~^ manual_find_map iter::<&&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); + //~^ manual_find_map iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); + //~^ manual_find_map iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); + //~^ manual_find_map iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); + //~^ manual_find_map iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + //~^ manual_find_map iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); + //~^ manual_find_map iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); + //~^ manual_find_map iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); + //~^ manual_find_map iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); + //~^ manual_find_map } fn no_lint() { @@ -94,45 +115,54 @@ fn issue_8920() { let _ = vec .iter() .find(|f| f.option_field.is_some()) + //~^ manual_find_map .map(|f| f.option_field.clone().unwrap()); let _ = vec .iter() .find(|f| f.ref_field.is_some()) + //~^ manual_find_map .map(|f| f.ref_field.cloned().unwrap()); let _ = vec .iter() .find(|f| f.ref_field.is_some()) + //~^ manual_find_map .map(|f| f.ref_field.copied().unwrap()); let _ = vec .iter() .find(|f| f.result_field.is_ok()) + //~^ manual_find_map .map(|f| f.result_field.clone().unwrap()); let _ = vec .iter() .find(|f| f.result_field.is_ok()) + //~^ manual_find_map .map(|f| f.result_field.as_ref().unwrap()); let _ = vec .iter() .find(|f| f.result_field.is_ok()) + //~^ manual_find_map .map(|f| f.result_field.as_deref().unwrap()); let _ = vec .iter_mut() .find(|f| f.result_field.is_ok()) + //~^ manual_find_map .map(|f| f.result_field.as_mut().unwrap()); let _ = vec .iter_mut() .find(|f| f.result_field.is_ok()) + //~^ manual_find_map .map(|f| f.result_field.as_deref_mut().unwrap()); let _ = vec .iter() .find(|f| f.result_field.is_ok()) + //~^ manual_find_map .map(|f| f.result_field.to_owned().unwrap()); } diff --git a/src/tools/clippy/tests/ui/manual_find_map.stderr b/src/tools/clippy/tests/ui/manual_find_map.stderr index 2722d59f52a90..8fa6c090e6d2a 100644 --- a/src/tools/clippy/tests/ui/manual_find_map.stderr +++ b/src/tools/clippy/tests/ui/manual_find_map.stderr @@ -13,250 +13,263 @@ LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap() = help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:12:19 + --> tests/ui/manual_find_map.rs:13:19 | LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:12:29 + --> tests/ui/manual_find_map.rs:13:29 | LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi")); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:15:19 + --> tests/ui/manual_find_map.rs:17:19 | LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:15:29 + --> tests/ui/manual_find_map.rs:17:29 | LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1)); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:18:10 + --> tests/ui/manual_find_map.rs:21:10 | LL | .find(|&x| to_ref(to_opt(x)).is_some()) | __________^ +LL | | LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:18:20 + --> tests/ui/manual_find_map.rs:21:20 | LL | .find(|&x| to_ref(to_opt(x)).is_some()) | ^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:21:10 + --> tests/ui/manual_find_map.rs:25:10 | LL | .find(|x| to_ref(to_opt(*x)).is_some()) | __________^ +LL | | LL | | .map(|y| to_ref(to_opt(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:21:19 + --> tests/ui/manual_find_map.rs:25:19 | LL | .find(|x| to_ref(to_opt(*x)).is_some()) | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:25:10 + --> tests/ui/manual_find_map.rs:30:10 | LL | .find(|&x| to_ref(to_res(x)).is_ok()) | __________^ +LL | | LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:25:20 + --> tests/ui/manual_find_map.rs:30:20 | LL | .find(|&x| to_ref(to_res(x)).is_ok()) | ^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:28:10 + --> tests/ui/manual_find_map.rs:34:10 | LL | .find(|x| to_ref(to_res(*x)).is_ok()) | __________^ +LL | | LL | | .map(|y| to_ref(to_res(y)).unwrap()); | |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:28:19 + --> tests/ui/manual_find_map.rs:34:19 | LL | .find(|x| to_ref(to_res(*x)).is_ok()) | ^^^^^^^^^^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:34:26 + --> tests/ui/manual_find_map.rs:41:26 | LL | iter::>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:35:27 + --> tests/ui/manual_find_map.rs:43:27 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| *x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:36:28 + --> tests/ui/manual_find_map.rs:45:28 | LL | iter::<&&Option>().find(|x| x.is_some()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| **x)` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:37:27 + --> tests/ui/manual_find_map.rs:47:27 | LL | iter::>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:38:28 + --> tests/ui/manual_find_map.rs:49:28 | LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:39:31 + --> tests/ui/manual_find_map.rs:51:31 | LL | iter::<&Option>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:40:31 + --> tests/ui/manual_find_map.rs:53:31 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:40:41 + --> tests/ui/manual_find_map.rs:53:41 | LL | iter::>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:42:30 + --> tests/ui/manual_find_map.rs:56:30 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:43:31 + --> tests/ui/manual_find_map.rs:58:31 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:44:32 + --> tests/ui/manual_find_map.rs:60:32 | LL | iter::<&&Result>().find(|x| x.is_ok()).map(|x| x.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:45:31 + --> tests/ui/manual_find_map.rs:62:31 | LL | iter::>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:46:32 + --> tests/ui/manual_find_map.rs:64:32 | LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:47:35 + --> tests/ui/manual_find_map.rs:66:35 | LL | iter::<&Result>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:48:35 + --> tests/ui/manual_find_map.rs:68:35 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())` | note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once - --> tests/ui/manual_find_map.rs:48:45 + --> tests/ui/manual_find_map.rs:68:45 | LL | iter::>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap()); | ^^^^^^^^^ error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:96:10 + --> tests/ui/manual_find_map.rs:117:10 | LL | .find(|f| f.option_field.is_some()) | __________^ +LL | | LL | | .map(|f| f.option_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:101:10 + --> tests/ui/manual_find_map.rs:123:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ +LL | | LL | | .map(|f| f.ref_field.cloned().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:106:10 + --> tests/ui/manual_find_map.rs:129:10 | LL | .find(|f| f.ref_field.is_some()) | __________^ +LL | | LL | | .map(|f| f.ref_field.copied().unwrap()); | |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:111:10 + --> tests/ui/manual_find_map.rs:135:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.clone().unwrap()); | |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:116:10 + --> tests/ui/manual_find_map.rs:141:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_ref().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:121:10 + --> tests/ui/manual_find_map.rs:147:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_deref().unwrap()); | |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:126:10 + --> tests/ui/manual_find_map.rs:153:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_mut().unwrap()); | |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:131:10 + --> tests/ui/manual_find_map.rs:159:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.as_deref_mut().unwrap()); | |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())` error: `find(..).map(..)` can be simplified as `find_map(..)` - --> tests/ui/manual_find_map.rs:136:10 + --> tests/ui/manual_find_map.rs:165:10 | LL | .find(|f| f.result_field.is_ok()) | __________^ +LL | | LL | | .map(|f| f.result_field.to_owned().unwrap()); | |____________________________________________________^ help: try: `find_map(|f| f.result_field.to_owned().ok())` diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs index d57333ace040d..97f35c36e24cc 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.rs +++ b/src/tools/clippy/tests/ui/manual_flatten.rs @@ -5,7 +5,8 @@ fn main() { // Test for loop over implicitly adjusted `Iterator` with `if let` expression let x = vec![Some(1), Some(2), Some(3)]; for n in x { - //~^ ERROR: unnecessary `if let` since only the `Some` variant of the iterator element + //~^ manual_flatten + if let Some(y) = n { println!("{}", y); } @@ -14,7 +15,8 @@ fn main() { // Test for loop over implicitly adjusted `Iterator` with `if let` statement let y: Vec> = vec![]; for n in y.clone() { - //~^ ERROR: unnecessary `if let` since only the `Ok` variant of the iterator element i + //~^ manual_flatten + if let Ok(n) = n { println!("{}", n); }; @@ -22,7 +24,8 @@ fn main() { // Test for loop over by reference for n in &y { - //~^ ERROR: unnecessary `if let` since only the `Ok` variant of the iterator element i + //~^ manual_flatten + if let Ok(n) = n { println!("{}", n); } @@ -31,7 +34,8 @@ fn main() { // Test for loop over an implicit reference let z = &y; for n in z { - //~^ ERROR: unnecessary `if let` since only the `Ok` variant of the iterator element i + //~^ manual_flatten + if let Ok(n) = n { println!("{}", n); } @@ -41,7 +45,8 @@ fn main() { let z = vec![Some(1), Some(2), Some(3)]; let z = z.iter(); for n in z { - //~^ ERROR: unnecessary `if let` since only the `Some` variant of the iterator element + //~^ manual_flatten + if let Some(m) = n { println!("{}", m); } @@ -75,7 +80,8 @@ fn main() { let vec_of_ref = vec![&Some(1)]; for n in &vec_of_ref { - //~^ ERROR: unnecessary `if let` since only the `Some` variant of the iterator element + //~^ manual_flatten + if let Some(n) = n { println!("{:?}", n); } @@ -83,7 +89,8 @@ fn main() { let vec_of_ref = &vec_of_ref; for n in vec_of_ref { - //~^ ERROR: unnecessary `if let` since only the `Some` variant of the iterator element + //~^ manual_flatten + if let Some(n) = n { println!("{:?}", n); } @@ -91,7 +98,8 @@ fn main() { let slice_of_ref = &[&Some(1)]; for n in slice_of_ref { - //~^ ERROR: unnecessary `if let` since only the `Some` variant of the iterator element + //~^ manual_flatten + if let Some(n) = n { println!("{:?}", n); } @@ -122,7 +130,8 @@ fn main() { fn run_unformatted_tests() { // Skip rustfmt here on purpose so the suggestion does not fit in one line for n in vec![ - //~^ ERROR: unnecessary `if let` since only the `Some` variant of the iterator element + //~^ manual_flatten + Some(1), Some(2), Some(3) diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr index 93f7f11b5e64c..5ab25658017eb 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.stderr +++ b/src/tools/clippy/tests/ui/manual_flatten.stderr @@ -6,14 +6,14 @@ LL | for n in x { | _____| | | LL | | +LL | | LL | | if let Some(y) = n { -LL | | println!("{}", y); -LL | | } +... | LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:9:9 + --> tests/ui/manual_flatten.rs:10:9 | LL | / if let Some(y) = n { LL | | println!("{}", y); @@ -23,13 +23,14 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_flatten)]` error: unnecessary `if let` since only the `Ok` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:16:5 + --> tests/ui/manual_flatten.rs:17:5 | LL | for n in y.clone() { | ^ --------- help: try: `y.clone().into_iter().flatten()` | _____| | | LL | | +LL | | LL | | if let Ok(n) = n { LL | | println!("{}", n); LL | | }; @@ -37,7 +38,7 @@ LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:18:9 + --> tests/ui/manual_flatten.rs:20:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); @@ -45,21 +46,21 @@ LL | | }; | |_________^ error: unnecessary `if let` since only the `Ok` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:24:5 + --> tests/ui/manual_flatten.rs:26:5 | LL | for n in &y { | ^ -- help: try: `y.iter().flatten()` | _____| | | LL | | +LL | | LL | | if let Ok(n) = n { -LL | | println!("{}", n); -LL | | } +... | LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:26:9 + --> tests/ui/manual_flatten.rs:29:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); @@ -67,21 +68,21 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Ok` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:33:5 + --> tests/ui/manual_flatten.rs:36:5 | LL | for n in z { | ^ - help: try: `z.iter().flatten()` | _____| | | LL | | +LL | | LL | | if let Ok(n) = n { -LL | | println!("{}", n); -LL | | } +... | LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:35:9 + --> tests/ui/manual_flatten.rs:39:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); @@ -89,21 +90,21 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:43:5 + --> tests/ui/manual_flatten.rs:47:5 | LL | for n in z { | ^ - help: try: `z.flatten()` | _____| | | LL | | +LL | | LL | | if let Some(m) = n { -LL | | println!("{}", m); -LL | | } +... | LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:45:9 + --> tests/ui/manual_flatten.rs:50:9 | LL | / if let Some(m) = n { LL | | println!("{}", m); @@ -111,21 +112,21 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:77:5 + --> tests/ui/manual_flatten.rs:82:5 | LL | for n in &vec_of_ref { | ^ ----------- help: try: `vec_of_ref.iter().copied().flatten()` | _____| | | LL | | +LL | | LL | | if let Some(n) = n { -LL | | println!("{:?}", n); -LL | | } +... | LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:79:9 + --> tests/ui/manual_flatten.rs:85:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); @@ -133,21 +134,21 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:85:5 + --> tests/ui/manual_flatten.rs:91:5 | LL | for n in vec_of_ref { | ^ ---------- help: try: `vec_of_ref.iter().copied().flatten()` | _____| | | LL | | +LL | | LL | | if let Some(n) = n { -LL | | println!("{:?}", n); -LL | | } +... | LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:87:9 + --> tests/ui/manual_flatten.rs:94:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); @@ -155,21 +156,21 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:93:5 + --> tests/ui/manual_flatten.rs:100:5 | LL | for n in slice_of_ref { | ^ ------------ help: try: `slice_of_ref.iter().copied().flatten()` | _____| | | LL | | +LL | | LL | | if let Some(n) = n { -LL | | println!("{:?}", n); -LL | | } +... | LL | | } | |_____^ | help: ...and remove the `if let` statement in the for loop - --> tests/ui/manual_flatten.rs:95:9 + --> tests/ui/manual_flatten.rs:103:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); @@ -177,18 +178,18 @@ LL | | } | |_________^ error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:124:5 + --> tests/ui/manual_flatten.rs:132:5 | LL | / for n in vec![ LL | | +LL | | LL | | Some(1), -LL | | Some(2), ... | LL | | } | |_____^ | help: remove the `if let` statement in the for loop and then... - --> tests/ui/manual_flatten.rs:130:9 + --> tests/ui/manual_flatten.rs:139:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); diff --git a/src/tools/clippy/tests/ui/manual_float_methods.rs b/src/tools/clippy/tests/ui/manual_float_methods.rs index 66545d180ef9e..62cdc1c141d0c 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.rs +++ b/src/tools/clippy/tests/ui/manual_float_methods.rs @@ -22,12 +22,18 @@ fn fn_test_not_inf() -> f64 { fn main() { let x = 1.0f32; if x == f32::INFINITY || x == f32::NEG_INFINITY {} + //~^ manual_is_infinite if x != f32::INFINITY && x != f32::NEG_INFINITY {} + //~^ manual_is_finite if x == INFINITE || x == NEG_INFINITE {} + //~^ manual_is_infinite if x != INFINITE && x != NEG_INFINITE {} + //~^ manual_is_finite let x = 1.0f64; if x == f64::INFINITY || x == f64::NEG_INFINITY {} + //~^ manual_is_infinite if x != f64::INFINITY && x != f64::NEG_INFINITY {} + //~^ manual_is_finite // Don't lint if x.is_infinite() {} if x.is_finite() {} @@ -42,6 +48,7 @@ fn main() { const { let x = 1.0f64; if x == f64::INFINITY || x == f64::NEG_INFINITY {} + //~^ manual_is_infinite } const X: f64 = 1.0f64; if const { X == f64::INFINITY || X == f64::NEG_INFINITY } {} diff --git a/src/tools/clippy/tests/ui/manual_float_methods.stderr b/src/tools/clippy/tests/ui/manual_float_methods.stderr index 1352c5e73cab8..352c879c87d73 100644 --- a/src/tools/clippy/tests/ui/manual_float_methods.stderr +++ b/src/tools/clippy/tests/ui/manual_float_methods.stderr @@ -8,7 +8,7 @@ LL | if x == f32::INFINITY || x == f32::NEG_INFINITY {} = help: to override `-D warnings` add `#[allow(clippy::manual_is_infinite)]` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:25:8 + --> tests/ui/manual_float_methods.rs:26:8 | LL | if x != f32::INFINITY && x != f32::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,13 +32,13 @@ LL + if !x.is_infinite() {} | error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:26:8 + --> tests/ui/manual_float_methods.rs:28:8 | LL | if x == INFINITE || x == NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:27:8 + --> tests/ui/manual_float_methods.rs:30:8 | LL | if x != INFINITE && x != NEG_INFINITE {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,13 +60,13 @@ LL + if !x.is_infinite() {} | error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:29:8 + --> tests/ui/manual_float_methods.rs:33:8 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` error: manually checking if a float is finite - --> tests/ui/manual_float_methods.rs:30:8 + --> tests/ui/manual_float_methods.rs:35:8 | LL | if x != f64::INFINITY && x != f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL + if !x.is_infinite() {} | error: manually checking if a float is infinite - --> tests/ui/manual_float_methods.rs:44:12 + --> tests/ui/manual_float_methods.rs:50:12 | LL | if x == f64::INFINITY || x == f64::NEG_INFINITY {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the dedicated method instead: `x.is_infinite()` diff --git a/src/tools/clippy/tests/ui/manual_hash_one.fixed b/src/tools/clippy/tests/ui/manual_hash_one.fixed index edfd9c4a47bba..e45e4bbc3ce73 100644 --- a/src/tools/clippy/tests/ui/manual_hash_one.fixed +++ b/src/tools/clippy/tests/ui/manual_hash_one.fixed @@ -7,18 +7,21 @@ fn returned(b: impl BuildHasher) -> u64 { b.hash_one(&true) + //~^ manual_hash_one } fn unsized_receiver(b: impl BuildHasher, s: &str) { let _ = b.hash_one(&s[4..10]); + //~^ manual_hash_one } fn owned_value(b: impl BuildHasher, v: Vec) -> Vec { let _ = b.hash_one(&v); + //~^ manual_hash_one v } @@ -86,4 +89,5 @@ fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { let _ = b.hash_one(&v); + //~^ manual_hash_one } diff --git a/src/tools/clippy/tests/ui/manual_hash_one.rs b/src/tools/clippy/tests/ui/manual_hash_one.rs index ee61522853f0f..c93e26c8f6bf5 100644 --- a/src/tools/clippy/tests/ui/manual_hash_one.rs +++ b/src/tools/clippy/tests/ui/manual_hash_one.rs @@ -7,18 +7,21 @@ fn returned(b: impl BuildHasher) -> u64 { let mut hasher = b.build_hasher(); true.hash(&mut hasher); hasher.finish() + //~^ manual_hash_one } fn unsized_receiver(b: impl BuildHasher, s: &str) { let mut hasher = b.build_hasher(); s[4..10].hash(&mut hasher); let _ = hasher.finish(); + //~^ manual_hash_one } fn owned_value(b: impl BuildHasher, v: Vec) -> Vec { let mut hasher = b.build_hasher(); v.hash(&mut hasher); let _ = hasher.finish(); + //~^ manual_hash_one v } @@ -86,4 +89,5 @@ fn msrv_1_71(b: impl BuildHasher, v: impl Hash) { let mut hasher = b.build_hasher(); v.hash(&mut hasher); let _ = hasher.finish(); + //~^ manual_hash_one } diff --git a/src/tools/clippy/tests/ui/manual_hash_one.stderr b/src/tools/clippy/tests/ui/manual_hash_one.stderr index bcff36d9bafc1..b0691e2d396c0 100644 --- a/src/tools/clippy/tests/ui/manual_hash_one.stderr +++ b/src/tools/clippy/tests/ui/manual_hash_one.stderr @@ -14,7 +14,7 @@ LL ~ b.hash_one(&true) | error: manual implementation of `BuildHasher::hash_one` - --> tests/ui/manual_hash_one.rs:15:13 + --> tests/ui/manual_hash_one.rs:16:13 | LL | let _ = hasher.finish(); | ^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL ~ let _ = b.hash_one(&s[4..10]); | error: manual implementation of `BuildHasher::hash_one` - --> tests/ui/manual_hash_one.rs:21:13 + --> tests/ui/manual_hash_one.rs:23:13 | LL | let _ = hasher.finish(); | ^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL ~ let _ = b.hash_one(&v); | error: manual implementation of `BuildHasher::hash_one` - --> tests/ui/manual_hash_one.rs:88:13 + --> tests/ui/manual_hash_one.rs:91:13 | LL | let _ = hasher.finish(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed index 53a124f59c8dc..c1c929585cfd3 100644 --- a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed +++ b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed @@ -7,24 +7,34 @@ fn main() {} fn variants(a: &str, b: &str) { if a.eq_ignore_ascii_case(b) { + //~^ manual_ignore_case_cmp return; } if a.eq_ignore_ascii_case(b) { + //~^ manual_ignore_case_cmp return; } let r = a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp let r = r || a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp r && a.eq_ignore_ascii_case(&b.to_uppercase()); + //~^ manual_ignore_case_cmp // != if !a.eq_ignore_ascii_case(b) { + //~^ manual_ignore_case_cmp return; } if !a.eq_ignore_ascii_case(b) { + //~^ manual_ignore_case_cmp return; } let r = !a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp let r = r || !a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp r && !a.eq_ignore_ascii_case(&b.to_uppercase()); + //~^ manual_ignore_case_cmp } fn unsupported(a: char, b: char) { @@ -36,72 +46,111 @@ fn unsupported(a: char, b: char) { fn char(a: char, b: char) { a.eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == *&b.to_ascii_lowercase(); *&a.to_ascii_lowercase() == b.to_ascii_lowercase(); a.eq_ignore_ascii_case(&'a'); + //~^ manual_ignore_case_cmp 'a'.eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp } fn u8(a: u8, b: u8) { a.eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp a.eq_ignore_ascii_case(&b'a'); + //~^ manual_ignore_case_cmp b'a'.eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp } fn ref_str(a: &str, b: &str) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp a.to_uppercase().eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp a.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp } fn ref_ref_str(a: &&str, b: &&str) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp a.to_uppercase().eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp a.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp } fn string(a: String, b: String) { a.eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp a.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp &a.to_ascii_lowercase() == &b.to_ascii_lowercase(); &&a.to_ascii_lowercase() == &&b.to_ascii_lowercase(); a.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp } fn ref_string(a: String, b: &String) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp a.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp b.eq_ignore_ascii_case(&a); + //~^ manual_ignore_case_cmp b.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(&a); + //~^ manual_ignore_case_cmp } fn string_ref_str(a: String, b: &str) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp a.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp b.eq_ignore_ascii_case(&a); + //~^ manual_ignore_case_cmp b.eq_ignore_ascii_case("a"); + //~^ manual_ignore_case_cmp "a".eq_ignore_ascii_case(&a); + //~^ manual_ignore_case_cmp } fn ref_u8slice(a: &[u8], b: &[u8]) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp } fn u8vec(a: Vec, b: Vec) { a.eq_ignore_ascii_case(&b); + //~^ manual_ignore_case_cmp } fn ref_u8vec(a: Vec, b: &Vec) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp b.eq_ignore_ascii_case(&a); + //~^ manual_ignore_case_cmp } fn ref_osstr(a: &OsStr, b: &OsStr) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp } fn osstring(a: OsString, b: OsString) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp } fn ref_osstring(a: OsString, b: &OsString) { a.eq_ignore_ascii_case(b); + //~^ manual_ignore_case_cmp b.eq_ignore_ascii_case(a); + //~^ manual_ignore_case_cmp } diff --git a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs index 2a4d84b30acec..ca401e595fe97 100644 --- a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs +++ b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs @@ -7,24 +7,34 @@ fn main() {} fn variants(a: &str, b: &str) { if a.to_ascii_lowercase() == b.to_ascii_lowercase() { + //~^ manual_ignore_case_cmp return; } if a.to_ascii_uppercase() == b.to_ascii_uppercase() { + //~^ manual_ignore_case_cmp return; } let r = a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase(); + //~^ manual_ignore_case_cmp r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase(); + //~^ manual_ignore_case_cmp // != if a.to_ascii_lowercase() != b.to_ascii_lowercase() { + //~^ manual_ignore_case_cmp return; } if a.to_ascii_uppercase() != b.to_ascii_uppercase() { + //~^ manual_ignore_case_cmp return; } let r = a.to_ascii_lowercase() != b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase(); + //~^ manual_ignore_case_cmp r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn unsupported(a: char, b: char) { @@ -36,72 +46,111 @@ fn unsupported(a: char, b: char) { fn char(a: char, b: char) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == *&b.to_ascii_lowercase(); *&a.to_ascii_lowercase() == b.to_ascii_lowercase(); a.to_ascii_lowercase() == 'a'; + //~^ manual_ignore_case_cmp 'a' == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn u8(a: u8, b: u8) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == b'a'; + //~^ manual_ignore_case_cmp b'a' == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn ref_str(a: &str, b: &str) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn ref_ref_str(a: &&str, b: &&str) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn string(a: String, b: String) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp &a.to_ascii_lowercase() == &b.to_ascii_lowercase(); &&a.to_ascii_lowercase() == &&b.to_ascii_lowercase(); a.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn ref_string(a: String, b: &String) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp b.to_ascii_lowercase() == a.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp b.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == a.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn string_ref_str(a: String, b: &str) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp a.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp b.to_ascii_lowercase() == a.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp b.to_ascii_lowercase() == "a"; + //~^ manual_ignore_case_cmp "a" == a.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn ref_u8slice(a: &[u8], b: &[u8]) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn u8vec(a: Vec, b: Vec) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn ref_u8vec(a: Vec, b: &Vec) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp b.to_ascii_lowercase() == a.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn ref_osstr(a: &OsStr, b: &OsStr) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn osstring(a: OsString, b: OsString) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } fn ref_osstring(a: OsString, b: &OsString) { a.to_ascii_lowercase() == b.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp b.to_ascii_lowercase() == a.to_ascii_lowercase(); + //~^ manual_ignore_case_cmp } diff --git a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr index bc6393b66d5c2..47378a65799fc 100644 --- a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr +++ b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr @@ -16,7 +16,7 @@ LL + if a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:12:8 + --> tests/ui/manual_ignore_case_cmp.rs:13:8 | LL | if a.to_ascii_uppercase() == b.to_ascii_uppercase() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL + if a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:15:13 + --> tests/ui/manual_ignore_case_cmp.rs:17:13 | LL | let r = a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL + let r = a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:16:18 + --> tests/ui/manual_ignore_case_cmp.rs:19:18 | LL | let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + let r = r || a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:17:10 + --> tests/ui/manual_ignore_case_cmp.rs:21:10 | LL | r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL + r && a.eq_ignore_ascii_case(&b.to_uppercase()); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:19:8 + --> tests/ui/manual_ignore_case_cmp.rs:24:8 | LL | if a.to_ascii_lowercase() != b.to_ascii_lowercase() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -76,7 +76,7 @@ LL + if !a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:22:8 + --> tests/ui/manual_ignore_case_cmp.rs:28:8 | LL | if a.to_ascii_uppercase() != b.to_ascii_uppercase() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL + if !a.eq_ignore_ascii_case(b) { | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:25:13 + --> tests/ui/manual_ignore_case_cmp.rs:32:13 | LL | let r = a.to_ascii_lowercase() != b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL + let r = !a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:26:18 + --> tests/ui/manual_ignore_case_cmp.rs:34:18 | LL | let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -112,7 +112,7 @@ LL + let r = r || !a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:27:10 + --> tests/ui/manual_ignore_case_cmp.rs:36:10 | LL | r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -124,7 +124,7 @@ LL + r && !a.eq_ignore_ascii_case(&b.to_uppercase()); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:38:5 + --> tests/ui/manual_ignore_case_cmp.rs:48:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL + a.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:41:5 + --> tests/ui/manual_ignore_case_cmp.rs:52:5 | LL | a.to_ascii_lowercase() == 'a'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -148,7 +148,7 @@ LL + a.eq_ignore_ascii_case(&'a'); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:42:5 + --> tests/ui/manual_ignore_case_cmp.rs:54:5 | LL | 'a' == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL + 'a'.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:45:5 + --> tests/ui/manual_ignore_case_cmp.rs:58:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL + a.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:46:5 + --> tests/ui/manual_ignore_case_cmp.rs:60:5 | LL | a.to_ascii_lowercase() == b'a'; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +184,7 @@ LL + a.eq_ignore_ascii_case(&b'a'); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:47:5 + --> tests/ui/manual_ignore_case_cmp.rs:62:5 | LL | b'a' == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +196,7 @@ LL + b'a'.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:50:5 + --> tests/ui/manual_ignore_case_cmp.rs:66:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -208,7 +208,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:51:5 + --> tests/ui/manual_ignore_case_cmp.rs:68:5 | LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +220,7 @@ LL + a.to_uppercase().eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:52:5 + --> tests/ui/manual_ignore_case_cmp.rs:70:5 | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -232,7 +232,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:53:5 + --> tests/ui/manual_ignore_case_cmp.rs:72:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,7 +244,7 @@ LL + "a".eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:56:5 + --> tests/ui/manual_ignore_case_cmp.rs:76:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -256,7 +256,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:57:5 + --> tests/ui/manual_ignore_case_cmp.rs:78:5 | LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -268,7 +268,7 @@ LL + a.to_uppercase().eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:58:5 + --> tests/ui/manual_ignore_case_cmp.rs:80:5 | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -280,7 +280,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:59:5 + --> tests/ui/manual_ignore_case_cmp.rs:82:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -292,7 +292,7 @@ LL + "a".eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:62:5 + --> tests/ui/manual_ignore_case_cmp.rs:86:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -304,7 +304,7 @@ LL + a.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:63:5 + --> tests/ui/manual_ignore_case_cmp.rs:88:5 | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -316,7 +316,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:64:5 + --> tests/ui/manual_ignore_case_cmp.rs:90:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL + "a".eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:67:5 + --> tests/ui/manual_ignore_case_cmp.rs:94:5 | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -340,7 +340,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:68:5 + --> tests/ui/manual_ignore_case_cmp.rs:96:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -352,7 +352,7 @@ LL + "a".eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:71:5 + --> tests/ui/manual_ignore_case_cmp.rs:100:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:72:5 + --> tests/ui/manual_ignore_case_cmp.rs:102:5 | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:73:5 + --> tests/ui/manual_ignore_case_cmp.rs:104:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -388,7 +388,7 @@ LL + "a".eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:75:5 + --> tests/ui/manual_ignore_case_cmp.rs:107:5 | LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -400,7 +400,7 @@ LL + b.eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:76:5 + --> tests/ui/manual_ignore_case_cmp.rs:109:5 | LL | b.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -412,7 +412,7 @@ LL + b.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:77:5 + --> tests/ui/manual_ignore_case_cmp.rs:111:5 | LL | "a" == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -424,7 +424,7 @@ LL + "a".eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:80:5 + --> tests/ui/manual_ignore_case_cmp.rs:115:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -436,7 +436,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:81:5 + --> tests/ui/manual_ignore_case_cmp.rs:117:5 | LL | a.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -448,7 +448,7 @@ LL + a.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:82:5 + --> tests/ui/manual_ignore_case_cmp.rs:119:5 | LL | "a" == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -460,7 +460,7 @@ LL + "a".eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:84:5 + --> tests/ui/manual_ignore_case_cmp.rs:122:5 | LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -472,7 +472,7 @@ LL + b.eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:85:5 + --> tests/ui/manual_ignore_case_cmp.rs:124:5 | LL | b.to_ascii_lowercase() == "a"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -484,7 +484,7 @@ LL + b.eq_ignore_ascii_case("a"); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:86:5 + --> tests/ui/manual_ignore_case_cmp.rs:126:5 | LL | "a" == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -496,7 +496,7 @@ LL + "a".eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:89:5 + --> tests/ui/manual_ignore_case_cmp.rs:130:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -508,7 +508,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:92:5 + --> tests/ui/manual_ignore_case_cmp.rs:134:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -520,7 +520,7 @@ LL + a.eq_ignore_ascii_case(&b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:95:5 + --> tests/ui/manual_ignore_case_cmp.rs:138:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -532,7 +532,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:96:5 + --> tests/ui/manual_ignore_case_cmp.rs:140:5 | LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -544,7 +544,7 @@ LL + b.eq_ignore_ascii_case(&a); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:99:5 + --> tests/ui/manual_ignore_case_cmp.rs:144:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -556,7 +556,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:102:5 + --> tests/ui/manual_ignore_case_cmp.rs:148:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -568,7 +568,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:105:5 + --> tests/ui/manual_ignore_case_cmp.rs:152:5 | LL | a.to_ascii_lowercase() == b.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ LL + a.eq_ignore_ascii_case(b); | error: manual case-insensitive ASCII comparison - --> tests/ui/manual_ignore_case_cmp.rs:106:5 + --> tests/ui/manual_ignore_case_cmp.rs:154:5 | LL | b.to_ascii_lowercase() == a.to_ascii_lowercase(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed index 0e1b8fe3edb54..44f15d61f8563 100644 --- a/src/tools/clippy/tests/ui/manual_inspect.fixed +++ b/src/tools/clippy/tests/ui/manual_inspect.fixed @@ -3,24 +3,29 @@ fn main() { let _ = Some(0).inspect(|&x| { + //~^ manual_inspect println!("{}", x); }); let _ = Some(0).inspect(|&x| { + //~^ manual_inspect println!("{x}"); }); let _ = Some(0).inspect(|&x| { + //~^ manual_inspect println!("{}", x * 5 + 1); }); let _ = Some(0).inspect(|&x| { + //~^ manual_inspect if x == 0 { panic!(); } }); let _ = Some(0).inspect(|&x| { + //~^ manual_inspect if &x == &0 { let _y = x; panic!(); @@ -71,6 +76,7 @@ fn main() { } let _ = Some((String::new(), 0u32)).inspect(|x| { + //~^ manual_inspect if x.1 == 0 { let _x = x.1; panic!(); @@ -96,6 +102,7 @@ fn main() { }); let _ = Some(String::new()).inspect(|x| { + //~^ manual_inspect if x.is_empty() { let _ = || { let _x = x; @@ -106,6 +113,7 @@ fn main() { }); let _ = Some(0).inspect(|&x| { + //~^ manual_inspect if x == 0 { let _ = || { let _x = x; @@ -120,6 +128,7 @@ fn main() { struct Cell2(core::cell::Cell); let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { + //~^ manual_inspect x.0.set(1); }); @@ -135,16 +144,20 @@ fn main() { } let _: Result<_, ()> = Ok(0).inspect(|&x| { + //~^ manual_inspect println!("{}", x); }); let _: Result<(), _> = Err(0).inspect_err(|&x| { + //~^ manual_inspect println!("{}", x); }); let _ = [0] + //~^ suspicious_map .into_iter() .inspect(|&x| { + //~^ manual_inspect println!("{}", x); }) .count(); diff --git a/src/tools/clippy/tests/ui/manual_inspect.rs b/src/tools/clippy/tests/ui/manual_inspect.rs index 94cdfe3914006..d34f2abce6ae1 100644 --- a/src/tools/clippy/tests/ui/manual_inspect.rs +++ b/src/tools/clippy/tests/ui/manual_inspect.rs @@ -3,21 +3,25 @@ fn main() { let _ = Some(0).map(|x| { + //~^ manual_inspect println!("{}", x); x }); let _ = Some(0).map(|x| { + //~^ manual_inspect println!("{x}"); x }); let _ = Some(0).map(|x| { + //~^ manual_inspect println!("{}", x * 5 + 1); x }); let _ = Some(0).map(|x| { + //~^ manual_inspect if x == 0 { panic!(); } @@ -25,6 +29,7 @@ fn main() { }); let _ = Some(0).map(|x| { + //~^ manual_inspect if &x == &0 { let _y = x; panic!(); @@ -76,6 +81,7 @@ fn main() { } let _ = Some((String::new(), 0u32)).map(|x| { + //~^ manual_inspect if x.1 == 0 { let _x = x.1; panic!(); @@ -102,6 +108,7 @@ fn main() { }); let _ = Some(String::new()).map(|x| { + //~^ manual_inspect if x.is_empty() { let _ = || { let _x = &x; @@ -113,6 +120,7 @@ fn main() { }); let _ = Some(0).map(|x| { + //~^ manual_inspect if x == 0 { let _ = || { let _x = x; @@ -128,6 +136,7 @@ fn main() { struct Cell2(core::cell::Cell); let _ = Some(Cell2(Cell::new(0u32))).map(|x| { + //~^ manual_inspect x.0.set(1); x }); @@ -144,18 +153,22 @@ fn main() { } let _: Result<_, ()> = Ok(0).map(|x| { + //~^ manual_inspect println!("{}", x); x }); let _: Result<(), _> = Err(0).map_err(|x| { + //~^ manual_inspect println!("{}", x); x }); let _ = [0] + //~^ suspicious_map .into_iter() .map(|x| { + //~^ manual_inspect println!("{}", x); x }) diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr index 0559b3bd6611d..510325d2baaa9 100644 --- a/src/tools/clippy/tests/ui/manual_inspect.stderr +++ b/src/tools/clippy/tests/ui/manual_inspect.stderr @@ -9,11 +9,12 @@ LL | let _ = Some(0).map(|x| { help: try | LL ~ let _ = Some(0).inspect(|&x| { +LL | LL ~ println!("{}", x); | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:10:21 + --> tests/ui/manual_inspect.rs:11:21 | LL | let _ = Some(0).map(|x| { | ^^^ @@ -21,11 +22,12 @@ LL | let _ = Some(0).map(|x| { help: try | LL ~ let _ = Some(0).inspect(|&x| { +LL | LL ~ println!("{x}"); | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:15:21 + --> tests/ui/manual_inspect.rs:17:21 | LL | let _ = Some(0).map(|x| { | ^^^ @@ -33,11 +35,12 @@ LL | let _ = Some(0).map(|x| { help: try | LL ~ let _ = Some(0).inspect(|&x| { +LL | LL ~ println!("{}", x * 5 + 1); | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:20:21 + --> tests/ui/manual_inspect.rs:23:21 | LL | let _ = Some(0).map(|x| { | ^^^ @@ -45,13 +48,14 @@ LL | let _ = Some(0).map(|x| { help: try | LL ~ let _ = Some(0).inspect(|&x| { +LL | LL | if x == 0 { LL | panic!(); LL ~ } | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:27:21 + --> tests/ui/manual_inspect.rs:31:21 | LL | let _ = Some(0).map(|x| { | ^^^ @@ -59,14 +63,14 @@ LL | let _ = Some(0).map(|x| { help: try | LL ~ let _ = Some(0).inspect(|&x| { -LL | if &x == &0 { -LL | let _y = x; +LL | +... LL | panic!(); LL ~ } | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:78:41 + --> tests/ui/manual_inspect.rs:83:41 | LL | let _ = Some((String::new(), 0u32)).map(|x| { | ^^^ @@ -74,14 +78,14 @@ LL | let _ = Some((String::new(), 0u32)).map(|x| { help: try | LL ~ let _ = Some((String::new(), 0u32)).inspect(|x| { -LL | if x.1 == 0 { -LL | let _x = x.1; +LL | +... LL | panic!(); LL ~ } | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:104:33 + --> tests/ui/manual_inspect.rs:110:33 | LL | let _ = Some(String::new()).map(|x| { | ^^^ @@ -89,6 +93,7 @@ LL | let _ = Some(String::new()).map(|x| { help: try | LL ~ let _ = Some(String::new()).inspect(|x| { +LL | LL | if x.is_empty() { LL | let _ = || { LL ~ let _x = x; @@ -99,7 +104,7 @@ LL ~ println!("test"); | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:115:21 + --> tests/ui/manual_inspect.rs:122:21 | LL | let _ = Some(0).map(|x| { | ^^^ @@ -107,14 +112,14 @@ LL | let _ = Some(0).map(|x| { help: try | LL ~ let _ = Some(0).inspect(|&x| { -LL | if x == 0 { +LL | ... LL | panic!(); LL ~ } | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:130:46 + --> tests/ui/manual_inspect.rs:138:46 | LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { | ^^^ @@ -122,11 +127,12 @@ LL | let _ = Some(Cell2(Cell::new(0u32))).map(|x| { help: try | LL ~ let _ = Some(Cell2(Cell::new(0u32))).inspect(|x| { +LL | LL ~ x.0.set(1); | error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:146:34 + --> tests/ui/manual_inspect.rs:155:34 | LL | let _: Result<_, ()> = Ok(0).map(|x| { | ^^^ @@ -134,11 +140,12 @@ LL | let _: Result<_, ()> = Ok(0).map(|x| { help: try | LL ~ let _: Result<_, ()> = Ok(0).inspect(|&x| { +LL | LL ~ println!("{}", x); | error: using `map_err` over `inspect_err` - --> tests/ui/manual_inspect.rs:151:35 + --> tests/ui/manual_inspect.rs:161:35 | LL | let _: Result<(), _> = Err(0).map_err(|x| { | ^^^^^^^ @@ -146,18 +153,19 @@ LL | let _: Result<(), _> = Err(0).map_err(|x| { help: try | LL ~ let _: Result<(), _> = Err(0).inspect_err(|&x| { +LL | LL ~ println!("{}", x); | error: this call to `map()` won't have an effect on the call to `count()` - --> tests/ui/manual_inspect.rs:156:13 + --> tests/ui/manual_inspect.rs:167:13 | LL | let _ = [0] | _____________^ +LL | | LL | | .into_iter() LL | | .map(|x| { -LL | | println!("{}", x); -LL | | x +... | LL | | }) LL | | .count(); | |________________^ @@ -167,7 +175,7 @@ LL | | .count(); = help: to override `-D warnings` add `#[allow(clippy::suspicious_map)]` error: using `map` over `inspect` - --> tests/ui/manual_inspect.rs:158:10 + --> tests/ui/manual_inspect.rs:170:10 | LL | .map(|x| { | ^^^ @@ -175,6 +183,7 @@ LL | .map(|x| { help: try | LL ~ .inspect(|&x| { +LL | LL ~ println!("{}", x); | diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed index 1811337652dd5..187802bb76c9e 100644 --- a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed @@ -15,6 +15,7 @@ fn main() { } let duration = prev_instant.elapsed(); + //~^ manual_instant_elapsed // don't catch let duration = prev_instant.elapsed(); @@ -24,4 +25,6 @@ fn main() { let ref_to_instant = &Instant::now(); (*ref_to_instant).elapsed(); // to ensure parens are added correctly + // + //~^^ manual_instant_elapsed } diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs index fedca38b158aa..61e14e5a3d9d3 100644 --- a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs @@ -15,6 +15,7 @@ fn main() { } let duration = Instant::now() - prev_instant; + //~^ manual_instant_elapsed // don't catch let duration = prev_instant.elapsed(); @@ -24,4 +25,6 @@ fn main() { let ref_to_instant = &Instant::now(); Instant::now() - *ref_to_instant; // to ensure parens are added correctly + // + //~^^ manual_instant_elapsed } diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr index e8ffeb5f8ca3e..e84f3126f7070 100644 --- a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr @@ -8,7 +8,7 @@ LL | let duration = Instant::now() - prev_instant; = help: to override `-D warnings` add `#[allow(clippy::manual_instant_elapsed)]` error: manual implementation of `Instant::elapsed` - --> tests/ui/manual_instant_elapsed.rs:26:5 + --> tests/ui/manual_instant_elapsed.rs:27:5 | LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()` diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed index 179149f697db6..7b0d190683469 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed @@ -3,29 +3,45 @@ fn main() { assert!('x'.is_ascii_lowercase()); + //~^ manual_is_ascii_check assert!('X'.is_ascii_uppercase()); + //~^ manual_is_ascii_check assert!(b'x'.is_ascii_lowercase()); + //~^ manual_is_ascii_check assert!(b'X'.is_ascii_uppercase()); + //~^ manual_is_ascii_check let num = '2'; assert!(num.is_ascii_digit()); + //~^ manual_is_ascii_check assert!(b'1'.is_ascii_digit()); + //~^ manual_is_ascii_check assert!('x'.is_ascii_alphabetic()); + //~^ manual_is_ascii_check assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_')); b'0'.is_ascii_digit(); + //~^ manual_is_ascii_check b'a'.is_ascii_lowercase(); + //~^ manual_is_ascii_check b'A'.is_ascii_uppercase(); + //~^ manual_is_ascii_check '0'.is_ascii_digit(); + //~^ manual_is_ascii_check 'a'.is_ascii_lowercase(); + //~^ manual_is_ascii_check 'A'.is_ascii_uppercase(); + //~^ manual_is_ascii_check let cool_letter = &'g'; cool_letter.is_ascii_digit(); + //~^ manual_is_ascii_check cool_letter.is_ascii_lowercase(); + //~^ manual_is_ascii_check cool_letter.is_ascii_uppercase(); + //~^ manual_is_ascii_check } #[clippy::msrv = "1.23"] @@ -39,9 +55,13 @@ fn msrv_1_23() { #[clippy::msrv = "1.24"] fn msrv_1_24() { assert!(b'1'.is_ascii_digit()); + //~^ manual_is_ascii_check assert!('X'.is_ascii_uppercase()); + //~^ manual_is_ascii_check assert!('x'.is_ascii_alphabetic()); + //~^ manual_is_ascii_check assert!('x'.is_ascii_hexdigit()); + //~^ manual_is_ascii_check } #[clippy::msrv = "1.46"] @@ -53,14 +73,18 @@ fn msrv_1_46() { #[clippy::msrv = "1.47"] fn msrv_1_47() { const FOO: bool = 'x'.is_ascii_digit(); + //~^ manual_is_ascii_check const BAR: bool = 'x'.is_ascii_hexdigit(); + //~^ manual_is_ascii_check } #[allow(clippy::deref_addrof, clippy::needless_borrow)] fn with_refs() { let cool_letter = &&'g'; cool_letter.is_ascii_digit(); + //~^ manual_is_ascii_check cool_letter.is_ascii_lowercase(); + //~^ manual_is_ascii_check } fn generics() { @@ -79,11 +103,16 @@ fn generics() { { } take_while(|c: char| c.is_ascii_uppercase()); + //~^ manual_is_ascii_check take_while(|c: u8| c.is_ascii_uppercase()); + //~^ manual_is_ascii_check take_while(|c: char| c.is_ascii_uppercase()); + //~^ manual_is_ascii_check } fn adds_type_reference() { let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ascii_digit()).collect(); + //~^ manual_is_ascii_check let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c: &&mut char| c.is_ascii_digit()).collect(); + //~^ manual_is_ascii_check } diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs index 74f35ce94e84b..e4f7fe9f5838a 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs @@ -3,29 +3,45 @@ fn main() { assert!(matches!('x', 'a'..='z')); + //~^ manual_is_ascii_check assert!(matches!('X', 'A'..='Z')); + //~^ manual_is_ascii_check assert!(matches!(b'x', b'a'..=b'z')); + //~^ manual_is_ascii_check assert!(matches!(b'X', b'A'..=b'Z')); + //~^ manual_is_ascii_check let num = '2'; assert!(matches!(num, '0'..='9')); + //~^ manual_is_ascii_check assert!(matches!(b'1', b'0'..=b'9')); + //~^ manual_is_ascii_check assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + //~^ manual_is_ascii_check assert!(matches!('x', 'A'..='Z' | 'a'..='z' | '_')); (b'0'..=b'9').contains(&b'0'); + //~^ manual_is_ascii_check (b'a'..=b'z').contains(&b'a'); + //~^ manual_is_ascii_check (b'A'..=b'Z').contains(&b'A'); + //~^ manual_is_ascii_check ('0'..='9').contains(&'0'); + //~^ manual_is_ascii_check ('a'..='z').contains(&'a'); + //~^ manual_is_ascii_check ('A'..='Z').contains(&'A'); + //~^ manual_is_ascii_check let cool_letter = &'g'; ('0'..='9').contains(cool_letter); + //~^ manual_is_ascii_check ('a'..='z').contains(cool_letter); + //~^ manual_is_ascii_check ('A'..='Z').contains(cool_letter); + //~^ manual_is_ascii_check } #[clippy::msrv = "1.23"] @@ -39,9 +55,13 @@ fn msrv_1_23() { #[clippy::msrv = "1.24"] fn msrv_1_24() { assert!(matches!(b'1', b'0'..=b'9')); + //~^ manual_is_ascii_check assert!(matches!('X', 'A'..='Z')); + //~^ manual_is_ascii_check assert!(matches!('x', 'A'..='Z' | 'a'..='z')); + //~^ manual_is_ascii_check assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F')); + //~^ manual_is_ascii_check } #[clippy::msrv = "1.46"] @@ -53,14 +73,18 @@ fn msrv_1_46() { #[clippy::msrv = "1.47"] fn msrv_1_47() { const FOO: bool = matches!('x', '0'..='9'); + //~^ manual_is_ascii_check const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); + //~^ manual_is_ascii_check } #[allow(clippy::deref_addrof, clippy::needless_borrow)] fn with_refs() { let cool_letter = &&'g'; ('0'..='9').contains(&&cool_letter); + //~^ manual_is_ascii_check ('a'..='z').contains(*cool_letter); + //~^ manual_is_ascii_check } fn generics() { @@ -79,11 +103,16 @@ fn generics() { { } take_while(|c| ('A'..='Z').contains(&c)); + //~^ manual_is_ascii_check take_while(|c| (b'A'..=b'Z').contains(&c)); + //~^ manual_is_ascii_check take_while(|c: char| ('A'..='Z').contains(&c)); + //~^ manual_is_ascii_check } fn adds_type_reference() { let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect(); + //~^ manual_is_ascii_check let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect(); + //~^ manual_is_ascii_check } diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr index 7b3f0c938b0d2..9fd7f457b4201 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr @@ -8,145 +8,145 @@ LL | assert!(matches!('x', 'a'..='z')); = help: to override `-D warnings` add `#[allow(clippy::manual_is_ascii_check)]` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:6:13 + --> tests/ui/manual_is_ascii_check.rs:7:13 | LL | assert!(matches!('X', 'A'..='Z')); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:7:13 + --> tests/ui/manual_is_ascii_check.rs:9:13 | LL | assert!(matches!(b'x', b'a'..=b'z')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'x'.is_ascii_lowercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:8:13 + --> tests/ui/manual_is_ascii_check.rs:11:13 | LL | assert!(matches!(b'X', b'A'..=b'Z')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'X'.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:11:13 + --> tests/ui/manual_is_ascii_check.rs:15:13 | LL | assert!(matches!(num, '0'..='9')); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:12:13 + --> tests/ui/manual_is_ascii_check.rs:17:13 | LL | assert!(matches!(b'1', b'0'..=b'9')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:13:13 + --> tests/ui/manual_is_ascii_check.rs:19:13 | LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:17:5 + --> tests/ui/manual_is_ascii_check.rs:24:5 | LL | (b'0'..=b'9').contains(&b'0'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'0'.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:18:5 + --> tests/ui/manual_is_ascii_check.rs:26:5 | LL | (b'a'..=b'z').contains(&b'a'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'a'.is_ascii_lowercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:19:5 + --> tests/ui/manual_is_ascii_check.rs:28:5 | LL | (b'A'..=b'Z').contains(&b'A'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'A'.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:21:5 + --> tests/ui/manual_is_ascii_check.rs:31:5 | LL | ('0'..='9').contains(&'0'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'0'.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:22:5 + --> tests/ui/manual_is_ascii_check.rs:33:5 | LL | ('a'..='z').contains(&'a'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'a'.is_ascii_lowercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:23:5 + --> tests/ui/manual_is_ascii_check.rs:35:5 | LL | ('A'..='Z').contains(&'A'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'A'.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:26:5 + --> tests/ui/manual_is_ascii_check.rs:39:5 | LL | ('0'..='9').contains(cool_letter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:27:5 + --> tests/ui/manual_is_ascii_check.rs:41:5 | LL | ('a'..='z').contains(cool_letter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:28:5 + --> tests/ui/manual_is_ascii_check.rs:43:5 | LL | ('A'..='Z').contains(cool_letter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:41:13 + --> tests/ui/manual_is_ascii_check.rs:57:13 | LL | assert!(matches!(b'1', b'0'..=b'9')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:42:13 + --> tests/ui/manual_is_ascii_check.rs:59:13 | LL | assert!(matches!('X', 'A'..='Z')); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:43:13 + --> tests/ui/manual_is_ascii_check.rs:61:13 | LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:44:13 + --> tests/ui/manual_is_ascii_check.rs:63:13 | LL | assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:55:23 + --> tests/ui/manual_is_ascii_check.rs:75:23 | LL | const FOO: bool = matches!('x', '0'..='9'); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:56:23 + --> tests/ui/manual_is_ascii_check.rs:77:23 | LL | const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:62:5 + --> tests/ui/manual_is_ascii_check.rs:84:5 | LL | ('0'..='9').contains(&&cool_letter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_digit()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:63:5 + --> tests/ui/manual_is_ascii_check.rs:86:5 | LL | ('a'..='z').contains(*cool_letter); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_lowercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:81:20 + --> tests/ui/manual_is_ascii_check.rs:105:20 | LL | take_while(|c| ('A'..='Z').contains(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,7 +158,7 @@ LL + take_while(|c: char| c.is_ascii_uppercase()); | error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:82:20 + --> tests/ui/manual_is_ascii_check.rs:107:20 | LL | take_while(|c| (b'A'..=b'Z').contains(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,13 +170,13 @@ LL + take_while(|c: u8| c.is_ascii_uppercase()); | error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:83:26 + --> tests/ui/manual_is_ascii_check.rs:109:26 | LL | take_while(|c: char| ('A'..='Z').contains(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `c.is_ascii_uppercase()` error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:87:63 + --> tests/ui/manual_is_ascii_check.rs:114:63 | LL | let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c| ('0'..='9').contains(c)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -188,7 +188,7 @@ LL + let digits: Vec<&char> = ['1', 'A'].iter().take_while(|c: &&char| c.is_ | error: manual check for common ascii range - --> tests/ui/manual_is_ascii_check.rs:88:71 + --> tests/ui/manual_is_ascii_check.rs:116:71 | LL | let digits: Vec<&mut char> = ['1', 'A'].iter_mut().take_while(|c| ('0'..='9').contains(c)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed b/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed index dda5fe0ec3e77..6f29d76bd2109 100644 --- a/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed +++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed @@ -4,13 +4,19 @@ fn main() { let a = 16_u64; let _ = a.is_power_of_two(); + //~^ manual_is_power_of_two let _ = a.is_power_of_two(); + //~^ manual_is_power_of_two // Test different orders of expression let _ = a.is_power_of_two(); + //~^ manual_is_power_of_two let _ = a.is_power_of_two(); + //~^ manual_is_power_of_two let _ = a.is_power_of_two(); + //~^ manual_is_power_of_two let _ = a.is_power_of_two(); + //~^ manual_is_power_of_two let b = 4_i64; diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.rs b/src/tools/clippy/tests/ui/manual_is_power_of_two.rs index a1d3a95c4102b..0c44d7a660b43 100644 --- a/src/tools/clippy/tests/ui/manual_is_power_of_two.rs +++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.rs @@ -4,13 +4,19 @@ fn main() { let a = 16_u64; let _ = a.count_ones() == 1; + //~^ manual_is_power_of_two let _ = a & (a - 1) == 0; + //~^ manual_is_power_of_two // Test different orders of expression let _ = 1 == a.count_ones(); + //~^ manual_is_power_of_two let _ = (a - 1) & a == 0; + //~^ manual_is_power_of_two let _ = 0 == a & (a - 1); + //~^ manual_is_power_of_two let _ = 0 == (a - 1) & a; + //~^ manual_is_power_of_two let b = 4_i64; diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr b/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr index 3cfc6297abf27..ad12ee10565f6 100644 --- a/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr +++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr @@ -8,31 +8,31 @@ LL | let _ = a.count_ones() == 1; = help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:7:13 + --> tests/ui/manual_is_power_of_two.rs:8:13 | LL | let _ = a & (a - 1) == 0; | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:10:13 + --> tests/ui/manual_is_power_of_two.rs:12:13 | LL | let _ = 1 == a.count_ones(); | ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:11:13 + --> tests/ui/manual_is_power_of_two.rs:14:13 | LL | let _ = (a - 1) & a == 0; | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:12:13 + --> tests/ui/manual_is_power_of_two.rs:16:13 | LL | let _ = 0 == a & (a - 1); | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` error: manually reimplementing `is_power_of_two` - --> tests/ui/manual_is_power_of_two.rs:13:13 + --> tests/ui/manual_is_power_of_two.rs:18:13 | LL | let _ = 0 == (a - 1) & a; | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()` diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed index 8c34b51103c13..c9c184561dd69 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.fixed +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.fixed @@ -13,9 +13,11 @@ fn option_methods() { let _ = opt.is_some_and(|x| x > 1); // Multi-line cases. let _ = opt.is_some_and(|x| { + //~^ manual_is_variant_and x > 1 }); let _ = opt.is_some_and(|x| x > 1); + //~^ manual_is_variant_and let _ = opt .is_some_and(|x| x > 1); @@ -24,6 +26,7 @@ fn option_methods() { let opt2 = Some('a'); let _ = opt2.is_some_and(char::is_alphanumeric); // should lint + //~^ manual_is_variant_and let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint } @@ -33,6 +36,7 @@ fn result_methods() { // multi line cases let _ = res.is_ok_and(|x| { + //~^ manual_is_variant_and x > 1 }); let _ = res.is_ok_and(|x| x > 1); @@ -42,6 +46,7 @@ fn result_methods() { let res2: Result = Ok('a'); let _ = res2.is_ok_and(char::is_alphanumeric); // should lint + //~^ manual_is_variant_and let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint } diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.rs b/src/tools/clippy/tests/ui/manual_is_variant_and.rs index 25b2489d94211..52c7b56804ce2 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.rs +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.rs @@ -11,16 +11,20 @@ fn option_methods() { // Check for `option.map(_).unwrap_or_default()` use. // Single line case. let _ = opt.map(|x| x > 1) + //~^ manual_is_variant_and // Should lint even though this call is on a separate line. .unwrap_or_default(); // Multi-line cases. let _ = opt.map(|x| { + //~^ manual_is_variant_and x > 1 } ).unwrap_or_default(); let _ = opt.map(|x| x > 1).unwrap_or_default(); + //~^ manual_is_variant_and let _ = opt .map(|x| x > 1) + //~^ manual_is_variant_and .unwrap_or_default(); // won't fix because the return type of the closure is not `bool` @@ -28,6 +32,7 @@ fn option_methods() { let opt2 = Some('a'); let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint + //~^ manual_is_variant_and let _ = opt_map!(opt2, |x| x == 'a').unwrap_or_default(); // should not lint } @@ -37,10 +42,12 @@ fn result_methods() { // multi line cases let _ = res.map(|x| { + //~^ manual_is_variant_and x > 1 } ).unwrap_or_default(); let _ = res.map(|x| x > 1) + //~^ manual_is_variant_and .unwrap_or_default(); // won't fix because the return type of the closure is not `bool` @@ -48,6 +55,7 @@ fn result_methods() { let res2: Result = Ok('a'); let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint + //~^ manual_is_variant_and let _ = opt_map!(res2, |x| x == 'a').unwrap_or_default(); // should not lint } diff --git a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr index d3ff7cf8b316a..a4fa500580d0a 100644 --- a/src/tools/clippy/tests/ui/manual_is_variant_and.stderr +++ b/src/tools/clippy/tests/ui/manual_is_variant_and.stderr @@ -3,7 +3,7 @@ error: called `map().unwrap_or_default()` on an `Option` value | LL | let _ = opt.map(|x| x > 1) | _________________^ -LL | | // Should lint even though this call is on a separate line. +... | LL | | .unwrap_or_default(); | |____________________________^ help: use: `is_some_and(|x| x > 1)` | @@ -11,10 +11,11 @@ LL | | .unwrap_or_default(); = help: to override `-D warnings` add `#[allow(clippy::manual_is_variant_and)]` error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:17:17 + --> tests/ui/manual_is_variant_and.rs:18:17 | LL | let _ = opt.map(|x| { | _________________^ +LL | | LL | | x > 1 LL | | } LL | | ).unwrap_or_default(); @@ -23,35 +24,38 @@ LL | | ).unwrap_or_default(); help: use | LL ~ let _ = opt.is_some_and(|x| { +LL + LL + x > 1 LL ~ }); | error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:21:17 + --> tests/ui/manual_is_variant_and.rs:23:17 | LL | let _ = opt.map(|x| x > 1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(|x| x > 1)` error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:23:10 + --> tests/ui/manual_is_variant_and.rs:26:10 | LL | .map(|x| x > 1) | __________^ +LL | | LL | | .unwrap_or_default(); | |____________________________^ help: use: `is_some_and(|x| x > 1)` error: called `map().unwrap_or_default()` on an `Option` value - --> tests/ui/manual_is_variant_and.rs:30:18 + --> tests/ui/manual_is_variant_and.rs:34:18 | LL | let _ = opt2.map(char::is_alphanumeric).unwrap_or_default(); // should lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_some_and(char::is_alphanumeric)` error: called `map().unwrap_or_default()` on a `Result` value - --> tests/ui/manual_is_variant_and.rs:39:17 + --> tests/ui/manual_is_variant_and.rs:44:17 | LL | let _ = res.map(|x| { | _________________^ +LL | | LL | | x > 1 LL | | } LL | | ).unwrap_or_default(); @@ -60,20 +64,22 @@ LL | | ).unwrap_or_default(); help: use | LL ~ let _ = res.is_ok_and(|x| { +LL + LL + x > 1 LL ~ }); | error: called `map().unwrap_or_default()` on a `Result` value - --> tests/ui/manual_is_variant_and.rs:43:17 + --> tests/ui/manual_is_variant_and.rs:49:17 | LL | let _ = res.map(|x| x > 1) | _________________^ +LL | | LL | | .unwrap_or_default(); | |____________________________^ help: use: `is_ok_and(|x| x > 1)` error: called `map().unwrap_or_default()` on a `Result` value - --> tests/ui/manual_is_variant_and.rs:50:18 + --> tests/ui/manual_is_variant_and.rs:57:18 | LL | let _ = res2.map(char::is_alphanumeric).unwrap_or_default(); // should lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `is_ok_and(char::is_alphanumeric)` diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs index 2b36c3f3c2fb6..d2350d97ed003 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.rs +++ b/src/tools/clippy/tests/ui/manual_let_else.rs @@ -27,17 +27,19 @@ fn main() {} fn fire() { let v = if let Some(v_some) = g() { v_some } else { return }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { return; }; let v = if let Some(v) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + // Blocks around the identity should have no impact { { v } } } else { @@ -49,18 +51,20 @@ fn fire() { // continue and break diverge loop { let v = if let Some(v_some) = g() { v_some } else { continue }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + let v = if let Some(v_some) = g() { v_some } else { break }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else } // panic also diverges let v = if let Some(v_some) = g() { v_some } else { panic!() }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else // abort also diverges let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { std::process::abort() @@ -68,7 +72,8 @@ fn fire() { // If whose two branches diverge also diverges let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { if true { return } else { panic!() } @@ -76,7 +81,8 @@ fn fire() { // Diverging after an if still makes the block diverge: let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { if true {} @@ -85,7 +91,8 @@ fn fire() { // The final expression will need to be turned into a statement. let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { panic!(); @@ -94,7 +101,8 @@ fn fire() { // Even if the result is buried multiple expressions deep. let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { panic!(); @@ -110,7 +118,8 @@ fn fire() { // Or if a break gives the value. let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { loop { @@ -121,7 +130,8 @@ fn fire() { // Even if the break is in a weird position. let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { 'a: loop { @@ -137,7 +147,8 @@ fn fire() { // A match diverges if all branches diverge: let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { match 0 { @@ -148,7 +159,8 @@ fn fire() { // An if's expression can cause divergence: let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { if panic!() {}; @@ -156,7 +168,8 @@ fn fire() { // An expression of a match can cause divergence: let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { match panic!() { @@ -166,7 +179,8 @@ fn fire() { // Top level else if let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else if true { return; @@ -176,7 +190,8 @@ fn fire() { // All match arms diverge let v = if let Some(v_some) = g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { match (g(), g()) { @@ -194,7 +209,8 @@ fn fire() { // Tuples supported for the declared variables let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + v_some } else { return; @@ -202,7 +218,8 @@ fn fire() { // Tuples supported with multiple bindings let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + (w_some, v_some) } else { return; @@ -212,6 +229,7 @@ fn fire() { macro_rules! create_binding_if_some { ($n:ident, $e:expr) => { let $n = if let Some(v) = $e { v } else { return }; + //~^ manual_let_else }; } create_binding_if_some!(w, g()); @@ -221,31 +239,33 @@ fn fire() { } let v = if let Variant::A(a, 0) = e() { a } else { return }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else // `mut v` is inserted into the pattern let mut v = if let Variant::B(b) = e() { b } else { return }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else // Nesting works let nested = Ok(Some(e())); let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + b } else { return; }; // dot dot works let v = if let Variant::A(.., a) = e() { a } else { return }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else // () is preserved: a bit of an edge case but make sure it stays around let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else // Tuple structs work let w = if let Some(S { v: x }) = Some(S { v: 0 }) { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + x } else { return; @@ -253,7 +273,8 @@ fn fire() { // Field init shorthand is suggested let v = if let Some(S { v: x }) = Some(S { v: 0 }) { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + x } else { return; @@ -261,7 +282,8 @@ fn fire() { // Multi-field structs also work let (x, S { v }, w) = if let Some(U { v, w, x }) = None::>> { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else + (x, v, w) } else { return; @@ -378,7 +400,7 @@ fn not_fire() { let ff = Some(1); let _ = match ff { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Some(value) => value, _ => macro_call!(), }; @@ -455,5 +477,6 @@ fn issue12337() { // we still emit a lint for manual_let_else let _: Option<()> = try { let v = if let Some(v_some) = g() { v_some } else { return }; + //~^ manual_let_else }; } diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr index dcd5d4561113b..8f5cba64d545c 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else.stderr @@ -12,6 +12,7 @@ error: this could be rewritten as `let...else` | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some LL | | } else { LL | | return; @@ -26,12 +27,9 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:39:5 + --> tests/ui/manual_let_else.rs:40:5 | LL | / let v = if let Some(v) = g() { -LL | | -LL | | // Blocks around the identity should have no impact -LL | | { { v } } ... | LL | | return; LL | | }; @@ -47,28 +45,29 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:51:9 + --> tests/ui/manual_let_else.rs:53:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:53:9 + --> tests/ui/manual_let_else.rs:56:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:58:5 + --> tests/ui/manual_let_else.rs:61:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:62:5 + --> tests/ui/manual_let_else.rs:65:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some LL | | } else { LL | | std::process::abort() @@ -83,10 +82,11 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:70:5 + --> tests/ui/manual_let_else.rs:74:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some LL | | } else { LL | | if true { return } else { panic!() } @@ -101,13 +101,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:78:5 + --> tests/ui/manual_let_else.rs:83:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { -LL | | if true {} +... | LL | | panic!(); LL | | }; | |______^ @@ -121,13 +121,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:87:5 + --> tests/ui/manual_let_else.rs:93:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { -LL | | panic!(); +... | LL | | () LL | | }; | |______^ @@ -141,12 +141,12 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:96:5 + --> tests/ui/manual_let_else.rs:103:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { ... | LL | | }; | |______^ @@ -167,12 +167,12 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:112:5 + --> tests/ui/manual_let_else.rs:120:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { ... | LL | | }; | |______^ @@ -188,12 +188,12 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:123:5 + --> tests/ui/manual_let_else.rs:132:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { ... | LL | | }; | |______^ @@ -214,12 +214,12 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:139:5 + --> tests/ui/manual_let_else.rs:149:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { ... | LL | | }; LL | | }; @@ -236,10 +236,11 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:150:5 + --> tests/ui/manual_let_else.rs:161:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some LL | | } else { LL | | if panic!() {}; @@ -254,12 +255,12 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:158:5 + --> tests/ui/manual_let_else.rs:170:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { ... | LL | | }; LL | | }; @@ -275,12 +276,12 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:168:5 + --> tests/ui/manual_let_else.rs:181:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else if true { ... | LL | | panic!("diverge"); LL | | }; @@ -296,12 +297,12 @@ LL + } }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:178:5 + --> tests/ui/manual_let_else.rs:192:5 | LL | / let v = if let Some(v_some) = g() { LL | | +LL | | LL | | v_some -LL | | } else { ... | LL | | }; | |______^ @@ -324,10 +325,11 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:196:5 + --> tests/ui/manual_let_else.rs:211:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | +LL | | LL | | v_some LL | | } else { LL | | return; @@ -342,10 +344,11 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:204:5 + --> tests/ui/manual_let_else.rs:220:5 | LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) { LL | | +LL | | LL | | (w_some, v_some) LL | | } else { LL | | return; @@ -360,7 +363,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:214:13 + --> tests/ui/manual_let_else.rs:231:13 | LL | let $n = if let Some(v) = $e { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` @@ -371,22 +374,23 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:223:5 + --> tests/ui/manual_let_else.rs:241:5 | LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:227:5 + --> tests/ui/manual_let_else.rs:245:5 | LL | let mut v = if let Variant::B(b) = e() { b } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:232:5 + --> tests/ui/manual_let_else.rs:250:5 | LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested { LL | | +LL | | LL | | b LL | | } else { LL | | return; @@ -401,22 +405,23 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:239:5 + --> tests/ui/manual_let_else.rs:258:5 | LL | let v = if let Variant::A(.., a) = e() { a } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:243:5 + --> tests/ui/manual_let_else.rs:262:5 | LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:247:5 + --> tests/ui/manual_let_else.rs:266:5 | LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | +LL | | LL | | x LL | | } else { LL | | return; @@ -431,10 +436,11 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:255:5 + --> tests/ui/manual_let_else.rs:275:5 | LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) { LL | | +LL | | LL | | x LL | | } else { LL | | return; @@ -449,10 +455,11 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:263:5 + --> tests/ui/manual_let_else.rs:284:5 | LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::>> { LL | | +LL | | LL | | (x, v, w) LL | | } else { LL | | return; @@ -467,7 +474,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:380:5 + --> tests/ui/manual_let_else.rs:402:5 | LL | / let _ = match ff { LL | | @@ -477,7 +484,7 @@ LL | | }; | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else.rs:457:9 + --> tests/ui/manual_let_else.rs:479:9 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.rs b/src/tools/clippy/tests/ui/manual_let_else_match.rs index c37b5613ff7d5..6416753bac107 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.rs +++ b/src/tools/clippy/tests/ui/manual_let_else_match.rs @@ -34,14 +34,13 @@ fn main() {} fn fire() { let v = match g() { - //~^ ERROR: this could be rewritten as `let...else` - //~| NOTE: `-D clippy::manual-let-else` implied by `-D warnings` + //~^ manual_let_else Some(v_some) => v_some, None => return, }; let v = match g() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Some(v_some) => v_some, _ => return, }; @@ -49,13 +48,13 @@ fn fire() { loop { // More complex pattern for the identity arm and diverging arm let v = match h() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else (Some(v), None) | (None, Some(v)) => v, (Some(_), Some(_)) | (None, None) => continue, }; // Custom enums are supported as long as the "else" arm is a simple _ let v = match build_enum() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Variant::Bar(v) | Variant::Baz(v) => v, _ => continue, }; @@ -64,14 +63,14 @@ fn fire() { // There is a _ in the diverging arm // TODO also support unused bindings aka _v let v = match f() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Ok(v) => v, Err(_) => return, }; // Err(()) is an allowed pattern let v = match f().map_err(|_| ()) { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Ok(v) => v, Err(()) => return, }; @@ -79,20 +78,20 @@ fn fire() { let f = Variant::Bar(1); let _value = match f { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Variant::Bar(v) | Variant::Baz(v) => v, _ => return, }; let _value = match Some(build_enum()) { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Some(Variant::Bar(v) | Variant::Baz(v)) => v, _ => return, }; let data = [1_u8, 2, 3, 4, 0, 0, 0, 0]; let data = match data.as_slice() { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else [data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0] => data, _ => return, }; @@ -173,7 +172,7 @@ fn not_fire() { fn issue11579() { let msg = match Some("hi") { - //~^ ERROR: this could be rewritten as `let...else` + //~^ manual_let_else Some(m) => m, _ => unreachable!("can't happen"), }; diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr index 3c0065f64033f..393562c629bac 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr @@ -3,7 +3,6 @@ error: this could be rewritten as `let...else` | LL | / let v = match g() { LL | | -LL | | LL | | Some(v_some) => v_some, LL | | None => return, LL | | }; @@ -13,7 +12,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::manual_let_else)]` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:43:5 + --> tests/ui/manual_let_else_match.rs:42:5 | LL | / let v = match g() { LL | | @@ -23,7 +22,7 @@ LL | | }; | |______^ help: consider writing: `let Some(v) = g() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:51:9 + --> tests/ui/manual_let_else_match.rs:50:9 | LL | / let v = match h() { LL | | @@ -33,7 +32,7 @@ LL | | }; | |__________^ help: consider writing: `let ((Some(v), None) | (None, Some(v))) = h() else { continue };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:57:9 + --> tests/ui/manual_let_else_match.rs:56:9 | LL | / let v = match build_enum() { LL | | @@ -43,7 +42,7 @@ LL | | }; | |__________^ help: consider writing: `let (Variant::Bar(v) | Variant::Baz(v)) = build_enum() else { continue };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:66:5 + --> tests/ui/manual_let_else_match.rs:65:5 | LL | / let v = match f() { LL | | @@ -53,7 +52,7 @@ LL | | }; | |______^ help: consider writing: `let Ok(v) = f() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:73:5 + --> tests/ui/manual_let_else_match.rs:72:5 | LL | / let v = match f().map_err(|_| ()) { LL | | @@ -63,7 +62,7 @@ LL | | }; | |______^ help: consider writing: `let Ok(v) = f().map_err(|_| ()) else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:81:5 + --> tests/ui/manual_let_else_match.rs:80:5 | LL | / let _value = match f { LL | | @@ -73,7 +72,7 @@ LL | | }; | |______^ help: consider writing: `let (Variant::Bar(_value) | Variant::Baz(_value)) = f else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:87:5 + --> tests/ui/manual_let_else_match.rs:86:5 | LL | / let _value = match Some(build_enum()) { LL | | @@ -83,7 +82,7 @@ LL | | }; | |______^ help: consider writing: `let Some(Variant::Bar(_value) | Variant::Baz(_value)) = Some(build_enum()) else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:94:5 + --> tests/ui/manual_let_else_match.rs:93:5 | LL | / let data = match data.as_slice() { LL | | @@ -93,7 +92,7 @@ LL | | }; | |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_match.rs:175:5 + --> tests/ui/manual_let_else_match.rs:174:5 | LL | / let msg = match Some("hi") { LL | | diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed b/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed index 6b29ce7598573..aca32a49c13b6 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed +++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.fixed @@ -27,15 +27,18 @@ fn main() {} fn foo() -> Option<()> { // Fire here, normal case let v = g()?; + //~^ question_mark // Don't fire here, the pattern is refutable let Variant::A(v, w) = e() else { return None }; // Fire here, the pattern is irrefutable let (v, w) = g()?; + //~^ question_mark // Don't fire manual_let_else in this instance: question mark can be used instead. let v = g()?; + //~^ question_mark // Do fire manual_let_else in this instance: question mark cannot be used here due to the return // body. @@ -56,6 +59,7 @@ fn foo() -> Option<()> { #[allow(clippy::question_mark)] { let Some(v) = g() else { return None }; + //~^ manual_let_else } Some(()) @@ -64,6 +68,7 @@ fn foo() -> Option<()> { // lint not just `return None`, but also `return None;` (note the semicolon) fn issue11993(y: Option) -> Option { let x = y?; + //~^^^ question_mark // don't lint: more than one statement in the else body let Some(x) = y else { diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs b/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs index e92c4c1375e52..8b43d59816f9c 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs +++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.rs @@ -27,19 +27,23 @@ fn main() {} fn foo() -> Option<()> { // Fire here, normal case let Some(v) = g() else { return None }; + //~^ question_mark // Don't fire here, the pattern is refutable let Variant::A(v, w) = e() else { return None }; // Fire here, the pattern is irrefutable let Some((v, w)) = g() else { return None }; + //~^ question_mark // Don't fire manual_let_else in this instance: question mark can be used instead. let v = if let Some(v_some) = g() { v_some } else { return None }; + //~^ question_mark // Do fire manual_let_else in this instance: question mark cannot be used here due to the return // body. let v = if let Some(v_some) = g() { + //~^ manual_let_else v_some } else { return Some(()); @@ -51,6 +55,7 @@ fn foo() -> Option<()> { #[allow(clippy::question_mark)] { let v = match g() { + //~^ manual_let_else Some(v_some) => v_some, _ => return None, }; @@ -61,6 +66,7 @@ fn foo() -> Option<()> { #[allow(clippy::question_mark)] { let v = if let Some(v_some) = g() { v_some } else { return None }; + //~^ manual_let_else } Some(()) @@ -71,6 +77,7 @@ fn issue11993(y: Option) -> Option { let Some(x) = y else { return None; }; + //~^^^ question_mark // don't lint: more than one statement in the else body let Some(x) = y else { diff --git a/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr index 434872ca26777..4fdd64d98491b 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_question_mark.stderr @@ -8,21 +8,22 @@ LL | let Some(v) = g() else { return None }; = help: to override `-D warnings` add `#[allow(clippy::question_mark)]` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/manual_let_else_question_mark.rs:35:5 + --> tests/ui/manual_let_else_question_mark.rs:36:5 | LL | let Some((v, w)) = g() else { return None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `let (v, w) = g()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/manual_let_else_question_mark.rs:38:13 + --> tests/ui/manual_let_else_question_mark.rs:40:13 | LL | let v = if let Some(v_some) = g() { v_some } else { return None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `g()?` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_question_mark.rs:42:5 + --> tests/ui/manual_let_else_question_mark.rs:45:5 | LL | / let v = if let Some(v_some) = g() { +LL | | LL | | v_some LL | | } else { LL | | return Some(()); @@ -39,22 +40,23 @@ LL + }; | error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_question_mark.rs:53:9 + --> tests/ui/manual_let_else_question_mark.rs:57:9 | LL | / let v = match g() { +LL | | LL | | Some(v_some) => v_some, LL | | _ => return None, LL | | }; | |__________^ help: consider writing: `let Some(v) = g() else { return None };` error: this could be rewritten as `let...else` - --> tests/ui/manual_let_else_question_mark.rs:63:9 + --> tests/ui/manual_let_else_question_mark.rs:68:9 | LL | let v = if let Some(v_some) = g() { v_some } else { return None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return None };` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/manual_let_else_question_mark.rs:71:5 + --> tests/ui/manual_let_else_question_mark.rs:77:5 | LL | / let Some(x) = y else { LL | | return None; diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.fixed b/src/tools/clippy/tests/ui/manual_main_separator_str.fixed index 6441d6edef8cf..6e5478ad009eb 100644 --- a/src/tools/clippy/tests/ui/manual_main_separator_str.fixed +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.fixed @@ -19,12 +19,16 @@ struct V { fn main() { // Should lint let _: &str = std::path::MAIN_SEPARATOR_STR; + //~^ manual_main_separator_str let _ = len(std::path::MAIN_SEPARATOR_STR); + //~^ manual_main_separator_str let _: Vec = std::path::MAIN_SEPARATOR_STR.encode_utf16().collect(); + //~^ manual_main_separator_str // Should lint for field `f` only let _ = U { f: std::path::MAIN_SEPARATOR_STR, + //~^ manual_main_separator_str g: &MAIN_SEPARATOR.to_string(), }; diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.rs b/src/tools/clippy/tests/ui/manual_main_separator_str.rs index 339dfd8bb473b..170af2da143fd 100644 --- a/src/tools/clippy/tests/ui/manual_main_separator_str.rs +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.rs @@ -19,12 +19,16 @@ struct V { fn main() { // Should lint let _: &str = &MAIN_SEPARATOR.to_string(); + //~^ manual_main_separator_str let _ = len(&MAIN_SEPARATOR.to_string()); + //~^ manual_main_separator_str let _: Vec = MAIN_SEPARATOR.to_string().encode_utf16().collect(); + //~^ manual_main_separator_str // Should lint for field `f` only let _ = U { f: &MAIN_SEPARATOR.to_string(), + //~^ manual_main_separator_str g: &MAIN_SEPARATOR.to_string(), }; diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.stderr b/src/tools/clippy/tests/ui/manual_main_separator_str.stderr index 78395eb7d6648..1c58b8261d4f5 100644 --- a/src/tools/clippy/tests/ui/manual_main_separator_str.stderr +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.stderr @@ -8,19 +8,19 @@ LL | let _: &str = &MAIN_SEPARATOR.to_string(); = help: to override `-D warnings` add `#[allow(clippy::manual_main_separator_str)]` error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` - --> tests/ui/manual_main_separator_str.rs:22:17 + --> tests/ui/manual_main_separator_str.rs:23:17 | LL | let _ = len(&MAIN_SEPARATOR.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` - --> tests/ui/manual_main_separator_str.rs:23:23 + --> tests/ui/manual_main_separator_str.rs:25:23 | LL | let _: Vec = MAIN_SEPARATOR.to_string().encode_utf16().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` error: taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String` - --> tests/ui/manual_main_separator_str.rs:27:12 + --> tests/ui/manual_main_separator_str.rs:30:12 | LL | f: &MAIN_SEPARATOR.to_string(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `std::path::MAIN_SEPARATOR_STR` diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed index 16cee3fd38236..3586979ab358b 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.fixed +++ b/src/tools/clippy/tests/ui/manual_map_option.fixed @@ -113,7 +113,16 @@ fn main() { } // #6811 - Some(0).map(|x| vec![x]); + match Some(0) { + Some(x) => Some(vec![x]), + None => None, + }; + + // Don't lint, coercion + let x: Option> = match Some(()) { + Some(_) => Some(vec![b"1234"]), + None => None, + }; option_env!("").map(String::from); diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs index 4655acf1406c7..9477d0d795d2d 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.rs +++ b/src/tools/clippy/tests/ui/manual_map_option.rs @@ -12,21 +12,25 @@ fn main() { match Some(0) { + //~^ manual_map Some(_) => Some(2), None:: => None, }; match Some(0) { + //~^ manual_map Some(x) => Some(x + 1), _ => None, }; match Some("") { + //~^ manual_map Some(x) => Some(x.is_empty()), None => None, }; if let Some(x) = Some(0) { + //~^ manual_map Some(!x) } else { None @@ -34,11 +38,13 @@ fn main() { #[rustfmt::skip] match Some(0) { + //~^ manual_map Some(x) => { Some(std::convert::identity(x)) } None => { None } }; match Some(&String::new()) { + //~^ manual_map Some(x) => Some(str::len(x)), None => None, }; @@ -49,26 +55,31 @@ fn main() { }; match &Some([0, 1]) { + //~^ manual_map Some(x) => Some(x[0]), &None => None, }; match &Some(0) { + //~^ manual_map &Some(x) => Some(x * 2), None => None, }; match Some(String::new()) { + //~^ manual_map Some(ref x) => Some(x.is_empty()), _ => None, }; match &&Some(String::new()) { + //~^ manual_map Some(x) => Some(x.len()), _ => None, }; match &&Some(0) { + //~^ manual_map &&Some(x) => Some(x + x), &&_ => None, }; @@ -82,32 +93,38 @@ fn main() { #[allow(clippy::option_map_unit_fn)] { match &mut Some(String::new()) { + //~^ manual_map Some(x) => Some(x.push_str("")), None => None, }; } match &mut Some(String::new()) { + //~^ manual_map Some(ref x) => Some(x.len()), None => None, }; match &mut &Some(String::new()) { + //~^ manual_map Some(x) => Some(x.is_empty()), &mut _ => None, }; match Some((0, 1, 2)) { + //~^ manual_map Some((x, y, z)) => Some(x + y + z), None => None, }; match Some([1, 2, 3]) { + //~^ manual_map Some([first, ..]) => Some(first), None => None, }; match &Some((String::new(), "test")) { + //~^ manual_map Some((x, y)) => Some((y, x)), None => None, }; @@ -170,7 +187,14 @@ fn main() { None => None, }; + // Don't lint, coercion + let x: Option> = match Some(()) { + Some(_) => Some(vec![b"1234"]), + None => None, + }; + match option_env!("") { + //~^ manual_map Some(x) => Some(String::from(x)), None => None, }; @@ -191,6 +215,7 @@ fn main() { if let Some(_) = Some(0) { Some(0) } else if let Some(x) = Some(0) { + //~^ manual_map Some(x + 1) } else { None @@ -199,6 +224,7 @@ fn main() { if true { Some(0) } else if let Some(x) = Some(0) { + //~^ manual_map Some(x + 1) } else { None diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr index 47cc18303ba57..8f9bce4c265c9 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.stderr +++ b/src/tools/clippy/tests/ui/manual_map_option.stderr @@ -2,6 +2,7 @@ error: manual implementation of `Option::map` --> tests/ui/manual_map_option.rs:14:5 | LL | / match Some(0) { +LL | | LL | | Some(_) => Some(2), LL | | None:: => None, LL | | }; @@ -11,27 +12,30 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::manual_map)]` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:19:5 + --> tests/ui/manual_map_option.rs:20:5 | LL | / match Some(0) { +LL | | LL | | Some(x) => Some(x + 1), LL | | _ => None, LL | | }; | |_____^ help: try: `Some(0).map(|x| x + 1)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:24:5 + --> tests/ui/manual_map_option.rs:26:5 | LL | / match Some("") { +LL | | LL | | Some(x) => Some(x.is_empty()), LL | | None => None, LL | | }; | |_____^ help: try: `Some("").map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:29:5 + --> tests/ui/manual_map_option.rs:32:5 | LL | / if let Some(x) = Some(0) { +LL | | LL | | Some(!x) LL | | } else { LL | | None @@ -39,145 +43,151 @@ LL | | }; | |_____^ help: try: `Some(0).map(|x| !x)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:36:5 + --> tests/ui/manual_map_option.rs:40:5 | LL | / match Some(0) { +LL | | LL | | Some(x) => { Some(std::convert::identity(x)) } LL | | None => { None } LL | | }; | |_____^ help: try: `Some(0).map(std::convert::identity)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:41:5 + --> tests/ui/manual_map_option.rs:46:5 | LL | / match Some(&String::new()) { +LL | | LL | | Some(x) => Some(str::len(x)), LL | | None => None, LL | | }; | |_____^ help: try: `Some(&String::new()).map(|x| str::len(x))` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:51:5 + --> tests/ui/manual_map_option.rs:57:5 | LL | / match &Some([0, 1]) { +LL | | LL | | Some(x) => Some(x[0]), LL | | &None => None, LL | | }; | |_____^ help: try: `Some([0, 1]).as_ref().map(|x| x[0])` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:56:5 + --> tests/ui/manual_map_option.rs:63:5 | LL | / match &Some(0) { +LL | | LL | | &Some(x) => Some(x * 2), LL | | None => None, LL | | }; | |_____^ help: try: `Some(0).map(|x| x * 2)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:61:5 + --> tests/ui/manual_map_option.rs:69:5 | LL | / match Some(String::new()) { +LL | | LL | | Some(ref x) => Some(x.is_empty()), LL | | _ => None, LL | | }; | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:66:5 + --> tests/ui/manual_map_option.rs:75:5 | LL | / match &&Some(String::new()) { +LL | | LL | | Some(x) => Some(x.len()), LL | | _ => None, LL | | }; | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:71:5 + --> tests/ui/manual_map_option.rs:81:5 | LL | / match &&Some(0) { +LL | | LL | | &&Some(x) => Some(x + x), LL | | &&_ => None, LL | | }; | |_____^ help: try: `Some(0).map(|x| x + x)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:84:9 + --> tests/ui/manual_map_option.rs:95:9 | LL | / match &mut Some(String::new()) { +LL | | LL | | Some(x) => Some(x.push_str("")), LL | | None => None, LL | | }; | |_________^ help: try: `Some(String::new()).as_mut().map(|x| x.push_str(""))` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:90:5 + --> tests/ui/manual_map_option.rs:102:5 | LL | / match &mut Some(String::new()) { +LL | | LL | | Some(ref x) => Some(x.len()), LL | | None => None, LL | | }; | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:95:5 + --> tests/ui/manual_map_option.rs:108:5 | LL | / match &mut &Some(String::new()) { +LL | | LL | | Some(x) => Some(x.is_empty()), LL | | &mut _ => None, LL | | }; | |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.is_empty())` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:100:5 + --> tests/ui/manual_map_option.rs:114:5 | LL | / match Some((0, 1, 2)) { +LL | | LL | | Some((x, y, z)) => Some(x + y + z), LL | | None => None, LL | | }; | |_____^ help: try: `Some((0, 1, 2)).map(|(x, y, z)| x + y + z)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:105:5 + --> tests/ui/manual_map_option.rs:120:5 | LL | / match Some([1, 2, 3]) { +LL | | LL | | Some([first, ..]) => Some(first), LL | | None => None, LL | | }; | |_____^ help: try: `Some([1, 2, 3]).map(|[first, ..]| first)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:110:5 + --> tests/ui/manual_map_option.rs:126:5 | LL | / match &Some((String::new(), "test")) { +LL | | LL | | Some((x, y)) => Some((y, x)), LL | | None => None, LL | | }; | |_____^ help: try: `Some((String::new(), "test")).as_ref().map(|(x, y)| (y, x))` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:168:5 - | -LL | / match Some(0) { -LL | | Some(x) => Some(vec![x]), -LL | | None => None, -LL | | }; - | |_____^ help: try: `Some(0).map(|x| vec![x])` - -error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:173:5 + --> tests/ui/manual_map_option.rs:196:5 | LL | / match option_env!("") { +LL | | LL | | Some(x) => Some(String::from(x)), LL | | None => None, LL | | }; | |_____^ help: try: `option_env!("").map(String::from)` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:193:12 + --> tests/ui/manual_map_option.rs:217:12 | LL | } else if let Some(x) = Some(0) { | ____________^ +LL | | LL | | Some(x + 1) LL | | } else { LL | | None @@ -185,15 +195,16 @@ LL | | }; | |_____^ help: try: `{ Some(0).map(|x| x + 1) }` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option.rs:201:12 + --> tests/ui/manual_map_option.rs:226:12 | LL | } else if let Some(x) = Some(0) { | ____________^ +LL | | LL | | Some(x + 1) LL | | } else { LL | | None LL | | }; | |_____^ help: try: `{ Some(0).map(|x| x + 1) }` -error: aborting due to 21 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.fixed b/src/tools/clippy/tests/ui/manual_map_option_2.fixed index f5bb4e0af1ba8..d698cc74ea65a 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.fixed +++ b/src/tools/clippy/tests/ui/manual_map_option_2.fixed @@ -40,9 +40,14 @@ fn main() { None => None, }; - // Lint. `s` is captured by reference, so no lifetime issues. let s = Some(String::new()); + // Lint. `s` is captured by reference, so no lifetime issues. let _ = s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }); + // Don't lint this, type of `s` is coercioned from `&String` to `&str` + let x: Option<(String, &str)> = match &s { + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + }; // Issue #7820 unsafe fn f(x: u32) -> u32 { @@ -54,3 +59,87 @@ fn main() { let _ = Some(0).map(|x| unsafe { f(x) }); let _ = Some(0).map(|x| unsafe { f(x) }); } + +// issue #12659 +mod with_type_coercion { + trait DummyTrait {} + + fn foo Result>(f: F) { + // Don't lint + let _: Option, ()>> = match Some(0) { + Some(_) => Some(match f() { + Ok(res) => Ok(Box::new(res)), + _ => Err(()), + }), + None => None, + }; + + let _: Option> = match Some(()) { + Some(_) => Some(Box::new(b"1234")), + None => None, + }; + + let x = String::new(); + let _: Option> = match Some(()) { + Some(_) => Some(Box::new(&x)), + None => None, + }; + + let _: Option<&str> = match Some(()) { + Some(_) => Some(&x), + None => None, + }; + + let _ = Some(0).map(|_| match f() { + Ok(res) => Ok(Box::new(res)), + _ => Err(()), + }); + } + + #[allow(clippy::redundant_allocation)] + fn bar() { + fn f(_: Option>) {} + fn g(b: &[u8]) -> Box<&[u8]> { + Box::new(b) + } + + let x: &[u8; 4] = b"1234"; + f(match Some(()) { + Some(_) => Some(Box::new(x)), + None => None, + }); + + let _: Option> = Some(0).map(|_| g(x)); + } + + fn with_fn_ret(s: &Option) -> Option<(String, &str)> { + // Don't lint, `map` doesn't work as the return type is adjusted. + match s { + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + } + } + + fn with_fn_ret_2(s: &Option) -> Option<(String, &str)> { + if true { + // Don't lint, `map` doesn't work as the return type is adjusted. + return match s { + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + }; + } + None + } + + #[allow(clippy::needless_late_init)] + fn with_fn_ret_3<'a>(s: &'a Option) -> Option<(String, &'a str)> { + let x: Option<(String, &'a str)>; + x = { + match s { + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + } + }; + x + } +} diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.rs b/src/tools/clippy/tests/ui/manual_map_option_2.rs index cbc2356e0a2d3..069c2381f6db1 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.rs +++ b/src/tools/clippy/tests/ui/manual_map_option_2.rs @@ -4,6 +4,7 @@ fn main() { // Lint. `y` is declared within the arm, so it isn't captured by the map closure let _ = match Some(0) { + //~^ manual_map Some(x) => Some({ let y = (String::new(), String::new()); (x, y.0) @@ -43,9 +44,15 @@ fn main() { None => None, }; - // Lint. `s` is captured by reference, so no lifetime issues. let s = Some(String::new()); + // Lint. `s` is captured by reference, so no lifetime issues. let _ = match &s { + //~^ manual_map + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + }; + // Don't lint this, type of `s` is coercioned from `&String` to `&str` + let x: Option<(String, &str)> = match &s { Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), None => None, }; @@ -56,16 +63,111 @@ fn main() { } unsafe { let _ = match Some(0) { + //~^ manual_map Some(x) => Some(f(x)), None => None, }; } let _ = match Some(0) { + //~^ manual_map Some(x) => unsafe { Some(f(x)) }, None => None, }; let _ = match Some(0) { + //~^ manual_map Some(x) => Some(unsafe { f(x) }), None => None, }; } + +// issue #12659 +mod with_type_coercion { + trait DummyTrait {} + + fn foo Result>(f: F) { + // Don't lint + let _: Option, ()>> = match Some(0) { + Some(_) => Some(match f() { + Ok(res) => Ok(Box::new(res)), + _ => Err(()), + }), + None => None, + }; + + let _: Option> = match Some(()) { + Some(_) => Some(Box::new(b"1234")), + None => None, + }; + + let x = String::new(); + let _: Option> = match Some(()) { + Some(_) => Some(Box::new(&x)), + None => None, + }; + + let _: Option<&str> = match Some(()) { + Some(_) => Some(&x), + None => None, + }; + + let _ = match Some(0) { + //~^ manual_map + Some(_) => Some(match f() { + Ok(res) => Ok(Box::new(res)), + _ => Err(()), + }), + None => None, + }; + } + + #[allow(clippy::redundant_allocation)] + fn bar() { + fn f(_: Option>) {} + fn g(b: &[u8]) -> Box<&[u8]> { + Box::new(b) + } + + let x: &[u8; 4] = b"1234"; + f(match Some(()) { + Some(_) => Some(Box::new(x)), + None => None, + }); + + let _: Option> = match Some(0) { + //~^ manual_map + Some(_) => Some(g(x)), + None => None, + }; + } + + fn with_fn_ret(s: &Option) -> Option<(String, &str)> { + // Don't lint, `map` doesn't work as the return type is adjusted. + match s { + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + } + } + + fn with_fn_ret_2(s: &Option) -> Option<(String, &str)> { + if true { + // Don't lint, `map` doesn't work as the return type is adjusted. + return match s { + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + }; + } + None + } + + #[allow(clippy::needless_late_init)] + fn with_fn_ret_3<'a>(s: &'a Option) -> Option<(String, &'a str)> { + let x: Option<(String, &'a str)>; + x = { + match s { + Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), + None => None, + } + }; + x + } +} diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.stderr b/src/tools/clippy/tests/ui/manual_map_option_2.stderr index 78e4677544bc8..c9e040ce1d0ec 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.stderr +++ b/src/tools/clippy/tests/ui/manual_map_option_2.stderr @@ -3,10 +3,10 @@ error: manual implementation of `Option::map` | LL | let _ = match Some(0) { | _____________^ +LL | | LL | | Some(x) => Some({ LL | | let y = (String::new(), String::new()); -LL | | (x, y.0) -LL | | }), +... | LL | | None => None, LL | | }; | |_____^ @@ -22,44 +22,80 @@ LL ~ }); | error: manual implementation of `Option::map` - --> tests/ui/manual_map_option_2.rs:48:13 + --> tests/ui/manual_map_option_2.rs:49:13 | LL | let _ = match &s { | _____________^ +LL | | LL | | Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }), LL | | None => None, LL | | }; | |_____^ help: try: `s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } })` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option_2.rs:58:17 + --> tests/ui/manual_map_option_2.rs:65:17 | LL | let _ = match Some(0) { | _________________^ +LL | | LL | | Some(x) => Some(f(x)), LL | | None => None, LL | | }; | |_________^ help: try: `Some(0).map(|x| f(x))` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option_2.rs:63:13 + --> tests/ui/manual_map_option_2.rs:71:13 | LL | let _ = match Some(0) { | _____________^ +LL | | LL | | Some(x) => unsafe { Some(f(x)) }, LL | | None => None, LL | | }; | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })` error: manual implementation of `Option::map` - --> tests/ui/manual_map_option_2.rs:67:13 + --> tests/ui/manual_map_option_2.rs:76:13 | LL | let _ = match Some(0) { | _____________^ +LL | | LL | | Some(x) => Some(unsafe { f(x) }), LL | | None => None, LL | | }; | |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })` -error: aborting due to 5 previous errors +error: manual implementation of `Option::map` + --> tests/ui/manual_map_option_2.rs:113:17 + | +LL | let _ = match Some(0) { + | _________________^ +LL | | +LL | | Some(_) => Some(match f() { +LL | | Ok(res) => Ok(Box::new(res)), +... | +LL | | None => None, +LL | | }; + | |_________^ + | +help: try + | +LL ~ let _ = Some(0).map(|_| match f() { +LL + Ok(res) => Ok(Box::new(res)), +LL + _ => Err(()), +LL ~ }); + | + +error: manual implementation of `Option::map` + --> tests/ui/manual_map_option_2.rs:136:37 + | +LL | let _: Option> = match Some(0) { + | _____________________________________^ +LL | | +LL | | Some(_) => Some(g(x)), +LL | | None => None, +LL | | }; + | |_________^ help: try: `Some(0).map(|_| g(x))` + +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs index 786d7e6e24454..c83a26cab21ab 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs +++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.rs @@ -3,57 +3,64 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { let mut count = 0; for i in 3..src.len() { - //~^ ERROR: it looks like you're manually copying between slices - //~| NOTE: `-D clippy::manual-memcpy` implied by `-D warnings` + //~^ manual_memcpy + dst[i] = src[count]; count += 1; } let mut count = 0; for i in 3..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[count] = src[i]; count += 1; } let mut count = 3; for i in 0..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[count] = src[i]; count += 1; } let mut count = 3; for i in 0..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[count]; count += 1; } let mut count = 0; for i in 3..(3 + src.len()) { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[count]; count += 1; } let mut count = 3; for i in 5..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[count - 2]; count += 1; } let mut count = 2; for i in 0..dst.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[count]; count += 1; } let mut count = 5; for i in 3..10 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[count]; count += 1; } @@ -61,7 +68,8 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) let mut count = 3; let mut count2 = 30; for i in 0..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[count] = src[i]; dst2[count2] = src[i]; count += 1; @@ -72,7 +80,8 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) // arithmetic ones let mut count = 0 << 1; for i in 0..1 << 1 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[count] = src[i + 2]; count += 1; } @@ -80,7 +89,8 @@ pub fn manual_copy_with_counters(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) // make sure incrementing expressions without semicolons at the end of loops are handled correctly. let mut count = 0; for i in 3..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[count]; count += 1 } diff --git a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr index 41a991e9688f5..70da8309f3987 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr +++ b/src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr @@ -17,79 +17,86 @@ error: it looks like you're manually copying between slices | LL | / for i in 3..src.len() { LL | | +LL | | LL | | dst[count] = src[i]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].copy_from_slice(&src[3..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:20:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:21:5 | LL | / for i in 0..src.len() { LL | | +LL | | LL | | dst[count] = src[i]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].copy_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:27:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:29:5 | LL | / for i in 0..src.len() { LL | | +LL | | LL | | dst[i] = src[count]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[3..(src.len() + 3)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:34:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:37:5 | LL | / for i in 3..(3 + src.len()) { LL | | +LL | | LL | | dst[i] = src[count]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].copy_from_slice(&src[..(3 + src.len() - 3)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:41:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:45:5 | LL | / for i in 5..src.len() { LL | | +LL | | LL | | dst[i] = src[count - 2]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[5..src.len()].copy_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:48:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:53:5 | LL | / for i in 0..dst.len() { LL | | +LL | | LL | | dst[i] = src[count]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[2..(dst.len() + 2)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:55:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:61:5 | LL | / for i in 3..10 { LL | | +LL | | LL | | dst[i] = src[count]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[3..10].copy_from_slice(&src[5..(10 + 5 - 3)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:63:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:70:5 | LL | / for i in 0..src.len() { LL | | +LL | | LL | | dst[count] = src[i]; -LL | | dst2[count2] = src[i]; -LL | | count += 1; +... | LL | | count2 += 1; LL | | } | |_____^ @@ -101,20 +108,22 @@ LL + dst2[30..(src.len() + 30)].copy_from_slice(&src[..]); | error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:74:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:82:5 | LL | / for i in 0..1 << 1 { LL | | +LL | | LL | | dst[count] = src[i + 2]; LL | | count += 1; LL | | } | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].copy_from_slice(&src[2..((1 << 1) + 2)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/with_loop_counters.rs:82:5 + --> tests/ui/manual_memcpy/with_loop_counters.rs:91:5 | LL | / for i in 3..src.len() { LL | | +LL | | LL | | dst[i] = src[count]; LL | | count += 1 LL | | } diff --git a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs index 2f8640cd3f50f..a3b8763812d72 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs +++ b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs @@ -12,32 +12,36 @@ const LOOP_OFFSET: usize = 5000; pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { // plain manual memcpy for i in 0..src.len() { - //~^ ERROR: it looks like you're manually copying between slices - //~| NOTE: `-D clippy::manual-memcpy` implied by `-D warnings` + //~^ manual_memcpy + dst[i] = src[i]; } // dst offset memcpy for i in 0..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i + 10] = src[i]; } // src offset memcpy for i in 0..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i + 10]; } // src offset memcpy for i in 11..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i - 10]; } // overwrite entire dst for i in 0..dst.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i]; } @@ -51,7 +55,8 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { // multiple copies - suggest two memcpy statements for i in 10..256 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i - 5]; dst2[i + 500] = src[i] } @@ -64,7 +69,8 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { let some_var = 5; // Offset in variable for i in 10..LOOP_OFFSET { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i + LOOP_OFFSET] = src[i - some_var]; } @@ -78,7 +84,8 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { // make sure vectors are supported for i in 0..src_vec.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst_vec[i] = src_vec[i]; } @@ -108,24 +115,28 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { let from = 1; for i in from..from + src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i - from]; } for i in from..from + 3 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i - from]; } #[allow(clippy::identity_op)] for i in 0..5 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i - 0] = src[i]; } #[allow(clippy::reversed_empty_ranges)] for i in 0..0 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i]; } @@ -149,19 +160,22 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { let src = [0, 1, 2, 3, 4]; let mut dst = [0; 4]; for i in 0..4 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i]; } let mut dst = [0; 6]; for i in 0..5 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i]; } let mut dst = [0; 5]; for i in 0..5 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i]; } @@ -208,13 +222,15 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { let src = [[0; 5]; 5]; let mut dst = [0; 5]; for i in 0..5 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[0][i]; } let src = [[[0; 5]; 5]; 5]; for i in 0..5 { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[0][1][i]; } } @@ -222,7 +238,8 @@ pub fn manual_copy(src: &[i32], dst: &mut [i32], dst2: &mut [i32]) { #[warn(clippy::needless_range_loop, clippy::manual_memcpy)] pub fn manual_clone(src: &[String], dst: &mut [String]) { for i in 0..src.len() { - //~^ ERROR: it looks like you're manually copying between slices + //~^ manual_memcpy + dst[i] = src[i].clone(); } } diff --git a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr index c881e3fac769f..0e656dcbc63a4 100644 --- a/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr +++ b/src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr @@ -16,42 +16,47 @@ error: it looks like you're manually copying between slices | LL | / for i in 0..src.len() { LL | | +LL | | LL | | dst[i + 10] = src[i]; LL | | } | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].copy_from_slice(&src[..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:27:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:28:5 | LL | / for i in 0..src.len() { LL | | +LL | | LL | | dst[i] = src[i + 10]; LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[10..(src.len() + 10)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:33:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:35:5 | LL | / for i in 11..src.len() { LL | | +LL | | LL | | dst[i] = src[i - 10]; LL | | } | |_____^ help: try replacing the loop by: `dst[11..src.len()].copy_from_slice(&src[(11 - 10)..(src.len() - 10)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:39:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:42:5 | LL | / for i in 0..dst.len() { LL | | +LL | | LL | | dst[i] = src[i]; LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..dst.len()]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:53:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:57:5 | LL | / for i in 10..256 { LL | | +LL | | LL | | dst[i] = src[i - 5]; LL | | dst2[i + 500] = src[i] LL | | } @@ -64,109 +69,121 @@ LL + dst2[(10 + 500)..(256 + 500)].copy_from_slice(&src[10..256]); | error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:66:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:71:5 | LL | / for i in 10..LOOP_OFFSET { LL | | +LL | | LL | | dst[i + LOOP_OFFSET] = src[i - some_var]; LL | | } | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].copy_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:80:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:86:5 | LL | / for i in 0..src_vec.len() { LL | | +LL | | LL | | dst_vec[i] = src_vec[i]; LL | | } | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].copy_from_slice(&src_vec[..]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:110:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:117:5 | LL | / for i in from..from + src.len() { LL | | +LL | | LL | | dst[i] = src[i - from]; LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].copy_from_slice(&src[..(from + src.len() - from)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:115:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:123:5 | LL | / for i in from..from + 3 { LL | | +LL | | LL | | dst[i] = src[i - from]; LL | | } | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].copy_from_slice(&src[..(from + 3 - from)]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:121:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:130:5 | LL | / for i in 0..5 { LL | | +LL | | LL | | dst[i - 0] = src[i]; LL | | } | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:127:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:137:5 | LL | / for i in 0..0 { LL | | +LL | | LL | | dst[i] = src[i]; LL | | } | |_____^ help: try replacing the loop by: `dst[..0].copy_from_slice(&src[..0]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:151:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:162:5 | LL | / for i in 0..4 { LL | | +LL | | LL | | dst[i] = src[i]; LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..4]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:157:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:169:5 | LL | / for i in 0..5 { LL | | +LL | | LL | | dst[i] = src[i]; LL | | } | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:163:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:176:5 | LL | / for i in 0..5 { LL | | +LL | | LL | | dst[i] = src[i]; LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:210:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:224:5 | LL | / for i in 0..5 { LL | | +LL | | LL | | dst[i] = src[0][i]; LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:216:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:231:5 | LL | / for i in 0..5 { LL | | +LL | | LL | | dst[i] = src[0][1][i]; LL | | } | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[0][1]);` error: it looks like you're manually copying between slices - --> tests/ui/manual_memcpy/without_loop_counters.rs:224:5 + --> tests/ui/manual_memcpy/without_loop_counters.rs:240:5 | LL | / for i in 0..src.len() { LL | | +LL | | LL | | dst[i] = src[i].clone(); LL | | } | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..]);` diff --git a/src/tools/clippy/tests/ui/manual_midpoint.fixed b/src/tools/clippy/tests/ui/manual_midpoint.fixed new file mode 100644 index 0000000000000..63116ced84384 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_midpoint.fixed @@ -0,0 +1,74 @@ +#![warn(clippy::manual_midpoint)] + +macro_rules! mac { + ($a: expr, $b: expr) => { + ($a + $b) / 2 + }; +} + +macro_rules! add { + ($a: expr, $b: expr) => { + ($a + $b) + }; +} + +macro_rules! two { + () => { + 2 + }; +} + +#[clippy::msrv = "1.84"] +fn older_msrv() { + let a: u32 = 10; + let _ = (a + 5) / 2; +} + +#[clippy::msrv = "1.85"] +fn main() { + let a: u32 = 10; + let _ = u32::midpoint(a, 5); //~ ERROR: manual implementation of `midpoint` + + let f: f32 = 10.0; + let _ = f32::midpoint(f, 5.0); //~ ERROR: manual implementation of `midpoint` + + let _: u32 = 5 + u32::midpoint(8, 8) + 2; //~ ERROR: manual implementation of `midpoint` + let _: u32 = const { u32::midpoint(8, 8) }; //~ ERROR: manual implementation of `midpoint` + let _: f64 = const { f64::midpoint(8.0f64, 8.) }; //~ ERROR: manual implementation of `midpoint` + let _: u32 = u32::midpoint(u32::default(), u32::default()); //~ ERROR: manual implementation of `midpoint` + let _: u32 = u32::midpoint(two!(), two!()); //~ ERROR: manual implementation of `midpoint` + + // Do not lint in presence of an addition with more than 2 operands + let _: u32 = (10 + 20 + 30) / 2; + + // Do not lint if whole or part is coming from a macro + let _ = mac!(10, 20); + let _: u32 = add!(10u32, 20u32) / 2; + let _: u32 = (10 + 20) / two!(); + + // Do not lint if a literal is not present + let _ = (f + 5.0) / (1.0 + 1.0); + + // Do not lint on signed integer types + let i: i32 = 10; + let _ = (i + 5) / 2; + + // Do not lint on (x+1)/2 or (1+x)/2 as this looks more like a `div_ceil()` operation + let _ = (i + 1) / 2; + let _ = (1 + i) / 2; + + // But if we see (x+1.0)/2.0 or (x+1.0)/2.0, it is probably a midpoint operation + let _ = f32::midpoint(f, 1.0); //~ ERROR: manual implementation of `midpoint` + let _ = f32::midpoint(1.0, f); //~ ERROR: manual implementation of `midpoint` +} + +#[clippy::msrv = "1.86"] +fn older_signed_midpoint(i: i32) { + // Do not lint + let _ = (i + 10) / 2; +} + +#[clippy::msrv = "1.87"] +fn signed_midpoint(i: i32) { + let _ = i32::midpoint(i, 10); //~ ERROR: manual implementation of `midpoint` +} diff --git a/src/tools/clippy/tests/ui/manual_midpoint.rs b/src/tools/clippy/tests/ui/manual_midpoint.rs new file mode 100644 index 0000000000000..47f1b88c78cd8 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_midpoint.rs @@ -0,0 +1,74 @@ +#![warn(clippy::manual_midpoint)] + +macro_rules! mac { + ($a: expr, $b: expr) => { + ($a + $b) / 2 + }; +} + +macro_rules! add { + ($a: expr, $b: expr) => { + ($a + $b) + }; +} + +macro_rules! two { + () => { + 2 + }; +} + +#[clippy::msrv = "1.84"] +fn older_msrv() { + let a: u32 = 10; + let _ = (a + 5) / 2; +} + +#[clippy::msrv = "1.85"] +fn main() { + let a: u32 = 10; + let _ = (a + 5) / 2; //~ ERROR: manual implementation of `midpoint` + + let f: f32 = 10.0; + let _ = (f + 5.0) / 2.0; //~ ERROR: manual implementation of `midpoint` + + let _: u32 = 5 + (8 + 8) / 2 + 2; //~ ERROR: manual implementation of `midpoint` + let _: u32 = const { (8 + 8) / 2 }; //~ ERROR: manual implementation of `midpoint` + let _: f64 = const { (8.0f64 + 8.) / 2. }; //~ ERROR: manual implementation of `midpoint` + let _: u32 = (u32::default() + u32::default()) / 2; //~ ERROR: manual implementation of `midpoint` + let _: u32 = (two!() + two!()) / 2; //~ ERROR: manual implementation of `midpoint` + + // Do not lint in presence of an addition with more than 2 operands + let _: u32 = (10 + 20 + 30) / 2; + + // Do not lint if whole or part is coming from a macro + let _ = mac!(10, 20); + let _: u32 = add!(10u32, 20u32) / 2; + let _: u32 = (10 + 20) / two!(); + + // Do not lint if a literal is not present + let _ = (f + 5.0) / (1.0 + 1.0); + + // Do not lint on signed integer types + let i: i32 = 10; + let _ = (i + 5) / 2; + + // Do not lint on (x+1)/2 or (1+x)/2 as this looks more like a `div_ceil()` operation + let _ = (i + 1) / 2; + let _ = (1 + i) / 2; + + // But if we see (x+1.0)/2.0 or (x+1.0)/2.0, it is probably a midpoint operation + let _ = (f + 1.0) / 2.0; //~ ERROR: manual implementation of `midpoint` + let _ = (1.0 + f) / 2.0; //~ ERROR: manual implementation of `midpoint` +} + +#[clippy::msrv = "1.86"] +fn older_signed_midpoint(i: i32) { + // Do not lint + let _ = (i + 10) / 2; +} + +#[clippy::msrv = "1.87"] +fn signed_midpoint(i: i32) { + let _ = (i + 10) / 2; //~ ERROR: manual implementation of `midpoint` +} diff --git a/src/tools/clippy/tests/ui/manual_midpoint.stderr b/src/tools/clippy/tests/ui/manual_midpoint.stderr new file mode 100644 index 0000000000000..3d588e2114df3 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_midpoint.stderr @@ -0,0 +1,65 @@ +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:30:13 + | +LL | let _ = (a + 5) / 2; + | ^^^^^^^^^^^ help: use `u32::midpoint` instead: `u32::midpoint(a, 5)` + | + = note: `-D clippy::manual-midpoint` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_midpoint)]` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:33:13 + | +LL | let _ = (f + 5.0) / 2.0; + | ^^^^^^^^^^^^^^^ help: use `f32::midpoint` instead: `f32::midpoint(f, 5.0)` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:35:22 + | +LL | let _: u32 = 5 + (8 + 8) / 2 + 2; + | ^^^^^^^^^^^ help: use `u32::midpoint` instead: `u32::midpoint(8, 8)` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:36:26 + | +LL | let _: u32 = const { (8 + 8) / 2 }; + | ^^^^^^^^^^^ help: use `u32::midpoint` instead: `u32::midpoint(8, 8)` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:37:26 + | +LL | let _: f64 = const { (8.0f64 + 8.) / 2. }; + | ^^^^^^^^^^^^^^^^^^ help: use `f64::midpoint` instead: `f64::midpoint(8.0f64, 8.)` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:38:18 + | +LL | let _: u32 = (u32::default() + u32::default()) / 2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `u32::midpoint` instead: `u32::midpoint(u32::default(), u32::default())` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:39:18 + | +LL | let _: u32 = (two!() + two!()) / 2; + | ^^^^^^^^^^^^^^^^^^^^^ help: use `u32::midpoint` instead: `u32::midpoint(two!(), two!())` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:61:13 + | +LL | let _ = (f + 1.0) / 2.0; + | ^^^^^^^^^^^^^^^ help: use `f32::midpoint` instead: `f32::midpoint(f, 1.0)` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:62:13 + | +LL | let _ = (1.0 + f) / 2.0; + | ^^^^^^^^^^^^^^^ help: use `f32::midpoint` instead: `f32::midpoint(1.0, f)` + +error: manual implementation of `midpoint` which can overflow + --> tests/ui/manual_midpoint.rs:73:13 + | +LL | let _ = (i + 10) / 2; + | ^^^^^^^^^^^^ help: use `i32::midpoint` instead: `i32::midpoint(i, 10)` + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_next_back.fixed b/src/tools/clippy/tests/ui/manual_next_back.fixed index 75828f355d900..153fbc6fd071b 100644 --- a/src/tools/clippy/tests/ui/manual_next_back.fixed +++ b/src/tools/clippy/tests/ui/manual_next_back.fixed @@ -30,5 +30,7 @@ fn main() { // should lint let _ = (0..10).next_back().unwrap(); + //~^ manual_next_back let _ = "something".bytes().next_back(); + //~^ manual_next_back } diff --git a/src/tools/clippy/tests/ui/manual_next_back.rs b/src/tools/clippy/tests/ui/manual_next_back.rs index b980e90e11447..ca71d6a247736 100644 --- a/src/tools/clippy/tests/ui/manual_next_back.rs +++ b/src/tools/clippy/tests/ui/manual_next_back.rs @@ -30,5 +30,7 @@ fn main() { // should lint let _ = (0..10).rev().next().unwrap(); + //~^ manual_next_back let _ = "something".bytes().rev().next(); + //~^ manual_next_back } diff --git a/src/tools/clippy/tests/ui/manual_next_back.stderr b/src/tools/clippy/tests/ui/manual_next_back.stderr index c7e1ceca437cc..4ac7b0d212444 100644 --- a/src/tools/clippy/tests/ui/manual_next_back.stderr +++ b/src/tools/clippy/tests/ui/manual_next_back.stderr @@ -8,7 +8,7 @@ LL | let _ = (0..10).rev().next().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::manual_next_back)]` error: manual backwards iteration - --> tests/ui/manual_next_back.rs:33:32 + --> tests/ui/manual_next_back.rs:34:32 | LL | let _ = "something".bytes().rev().next(); | ^^^^^^^^^^^^^ help: use: `.next_back()` diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs index ffe2bb9246737..bb22165d478f5 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs @@ -27,6 +27,7 @@ pub enum NoDocHidden { // name of variant with doc hidden does not start with underscore pub enum NoUnderscore { + //~^ manual_non_exhaustive A, B, #[doc(hidden)] diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr index 0a9ac157f8502..0f91f24b4a34d 100644 --- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr +++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr @@ -27,6 +27,7 @@ error: this seems like a manual implementation of the non-exhaustive pattern --> tests/ui/manual_non_exhaustive_enum.rs:29:1 | LL | / pub enum NoUnderscore { +LL | | LL | | A, LL | | B, LL | | #[doc(hidden)] @@ -35,7 +36,7 @@ LL | | } | |_^ | help: remove this variant - --> tests/ui/manual_non_exhaustive_enum.rs:33:5 + --> tests/ui/manual_non_exhaustive_enum.rs:34:5 | LL | C, | ^ diff --git a/src/tools/clippy/tests/ui/manual_ok_err.fixed b/src/tools/clippy/tests/ui/manual_ok_err.fixed index e7e0464c47877..bc169b64be9fd 100644 --- a/src/tools/clippy/tests/ui/manual_ok_err.fixed +++ b/src/tools/clippy/tests/ui/manual_ok_err.fixed @@ -89,3 +89,12 @@ const fn cf(x: Result) -> Option { Err(_) => None, } } + +fn issue14239() { + let _ = if false { + None + } else { + "1".parse::().ok() + }; + //~^^^^^ manual_ok_err +} diff --git a/src/tools/clippy/tests/ui/manual_ok_err.rs b/src/tools/clippy/tests/ui/manual_ok_err.rs index 03ad773f47cf1..03c730d4b4e46 100644 --- a/src/tools/clippy/tests/ui/manual_ok_err.rs +++ b/src/tools/clippy/tests/ui/manual_ok_err.rs @@ -31,6 +31,7 @@ fn main() { let _ = if let Ok(v) = funcall() { //~^ manual_ok_err + Some(v) } else { None @@ -38,6 +39,7 @@ fn main() { let _ = if let Err(v) = funcall() { //~^ manual_ok_err + Some(v) } else { None @@ -123,3 +125,14 @@ const fn cf(x: Result) -> Option { Err(_) => None, } } + +fn issue14239() { + let _ = if false { + None + } else if let Ok(n) = "1".parse::() { + Some(n) + } else { + None + }; + //~^^^^^ manual_ok_err +} diff --git a/src/tools/clippy/tests/ui/manual_ok_err.stderr b/src/tools/clippy/tests/ui/manual_ok_err.stderr index d0d5e2c81e96e..13fceacda1074 100644 --- a/src/tools/clippy/tests/ui/manual_ok_err.stderr +++ b/src/tools/clippy/tests/ui/manual_ok_err.stderr @@ -51,6 +51,7 @@ error: manual implementation of `ok` LL | let _ = if let Ok(v) = funcall() { | _____________^ LL | | +LL | | LL | | Some(v) LL | | } else { LL | | None @@ -58,11 +59,12 @@ LL | | }; | |_____^ help: replace with: `funcall().ok()` error: manual implementation of `err` - --> tests/ui/manual_ok_err.rs:39:13 + --> tests/ui/manual_ok_err.rs:40:13 | LL | let _ = if let Err(v) = funcall() { | _____________^ LL | | +LL | | LL | | Some(v) LL | | } else { LL | | None @@ -70,7 +72,7 @@ LL | | }; | |_____^ help: replace with: `funcall().err()` error: manual implementation of `ok` - --> tests/ui/manual_ok_err.rs:47:13 + --> tests/ui/manual_ok_err.rs:49:13 | LL | let _ = match funcall() { | _____________^ @@ -81,7 +83,7 @@ LL | | }; | |_____^ help: replace with: `funcall().ok()` error: manual implementation of `ok` - --> tests/ui/manual_ok_err.rs:64:13 + --> tests/ui/manual_ok_err.rs:66:13 | LL | let _ = match -S { | _____________^ @@ -91,5 +93,23 @@ LL | | _ => None, LL | | }; | |_____^ help: replace with: `(-S).ok()` -error: aborting due to 8 previous errors +error: manual implementation of `ok` + --> tests/ui/manual_ok_err.rs:132:12 + | +LL | } else if let Ok(n) = "1".parse::() { + | ____________^ +LL | | Some(n) +LL | | } else { +LL | | None +LL | | }; + | |_____^ + | +help: replace with + | +LL ~ } else { +LL + "1".parse::().ok() +LL ~ }; + | + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/manual_ok_or.fixed b/src/tools/clippy/tests/ui/manual_ok_or.fixed index cc53cb416a22f..f326822149cd3 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.fixed +++ b/src/tools/clippy/tests/ui/manual_ok_or.fixed @@ -9,12 +9,15 @@ fn main() { // basic case let foo: Option = None; foo.ok_or("error"); + //~^ manual_ok_or // eta expansion case foo.ok_or("error"); + //~^ manual_ok_or // turbo fish syntax None::.ok_or("error"); + //~^ manual_ok_or // multiline case #[rustfmt::skip] diff --git a/src/tools/clippy/tests/ui/manual_ok_or.rs b/src/tools/clippy/tests/ui/manual_ok_or.rs index 39c61a1e490f2..7d065eda0ea1e 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.rs +++ b/src/tools/clippy/tests/ui/manual_ok_or.rs @@ -9,16 +9,20 @@ fn main() { // basic case let foo: Option = None; foo.map_or(Err("error"), |v| Ok(v)); + //~^ manual_ok_or // eta expansion case foo.map_or(Err("error"), Ok); + //~^ manual_ok_or // turbo fish syntax None::.map_or(Err("error"), |v| Ok(v)); + //~^ manual_ok_or // multiline case #[rustfmt::skip] foo.map_or(Err::( + //~^ manual_ok_or &format!( "{}{}{}{}{}{}{}", "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer") diff --git a/src/tools/clippy/tests/ui/manual_ok_or.stderr b/src/tools/clippy/tests/ui/manual_ok_or.stderr index 2441a75b5c46e..e8176f4c31fa6 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.stderr +++ b/src/tools/clippy/tests/ui/manual_ok_or.stderr @@ -8,34 +8,25 @@ LL | foo.map_or(Err("error"), |v| Ok(v)); = help: to override `-D warnings` add `#[allow(clippy::manual_ok_or)]` error: this pattern reimplements `Option::ok_or` - --> tests/ui/manual_ok_or.rs:14:5 + --> tests/ui/manual_ok_or.rs:15:5 | LL | foo.map_or(Err("error"), Ok); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `foo.ok_or("error")` -error: called `map_or(Err(_), Ok)` on an `Option` value - --> tests/ui/manual_ok_or.rs:14:5 - | -LL | foo.map_or(Err("error"), Ok); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok_or`: `foo.ok_or("error")` - | - = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` - error: this pattern reimplements `Option::ok_or` - --> tests/ui/manual_ok_or.rs:17:5 + --> tests/ui/manual_ok_or.rs:19:5 | LL | None::.map_or(Err("error"), |v| Ok(v)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `None::.ok_or("error")` error: this pattern reimplements `Option::ok_or` - --> tests/ui/manual_ok_or.rs:21:5 + --> tests/ui/manual_ok_or.rs:24:5 | LL | / foo.map_or(Err::( +LL | | LL | | &format!( LL | | "{}{}{}{}{}{}{}", -LL | | "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer") -LL | | ), +... | LL | | |v| Ok(v), LL | | ); | |_____^ @@ -47,5 +38,5 @@ LL + "{}{}{}{}{}{}{}", LL ~ "Alice", "Bob", "Sarah", "Marc", "Sandra", "Eric", "Jenifer")); | -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/manual_option_as_slice.rs b/src/tools/clippy/tests/ui/manual_option_as_slice.rs index 561a8b534014b..e1a97a6b27115 100644 --- a/src/tools/clippy/tests/ui/manual_option_as_slice.rs +++ b/src/tools/clippy/tests/ui/manual_option_as_slice.rs @@ -10,6 +10,7 @@ fn check(x: Option) { _ = if let Some(f) = x.as_ref() { //~^ manual_option_as_slice + std::slice::from_ref(f) } else { &[] diff --git a/src/tools/clippy/tests/ui/manual_option_as_slice.stderr b/src/tools/clippy/tests/ui/manual_option_as_slice.stderr index 569269d3e2b79..e240ae8eb7d90 100644 --- a/src/tools/clippy/tests/ui/manual_option_as_slice.stderr +++ b/src/tools/clippy/tests/ui/manual_option_as_slice.stderr @@ -18,6 +18,7 @@ error: use `Option::as_slice` LL | _ = if let Some(f) = x.as_ref() { | _________^ LL | | +LL | | LL | | std::slice::from_ref(f) LL | | } else { LL | | &[] @@ -25,31 +26,31 @@ LL | | }; | |_____^ help: use: `x.as_slice()` error: use `Option::as_slice` - --> tests/ui/manual_option_as_slice.rs:18:9 + --> tests/ui/manual_option_as_slice.rs:19:9 | LL | _ = x.as_ref().map_or(&[][..], std::slice::from_ref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()` error: use `Option::as_slice` - --> tests/ui/manual_option_as_slice.rs:21:9 + --> tests/ui/manual_option_as_slice.rs:22:9 | LL | _ = x.as_ref().map_or_else(Default::default, std::slice::from_ref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()` error: use `Option::as_slice` - --> tests/ui/manual_option_as_slice.rs:24:9 + --> tests/ui/manual_option_as_slice.rs:25:9 | LL | _ = x.as_ref().map(std::slice::from_ref).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()` error: use `Option::as_slice` - --> tests/ui/manual_option_as_slice.rs:27:9 + --> tests/ui/manual_option_as_slice.rs:28:9 | LL | _ = x.as_ref().map_or_else(|| &[42][..0], std::slice::from_ref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()` error: use `Option::as_slice` - --> tests/ui/manual_option_as_slice.rs:32:13 + --> tests/ui/manual_option_as_slice.rs:33:13 | LL | _ = x.as_ref().map_or_else(<&[_]>::default, from_ref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `x.as_slice()` diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed index 03e621d95ba16..b03e83e6b99d8 100644 --- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.fixed @@ -9,16 +9,25 @@ impl NotStr { fn main() { let sentence = "Hello, world!"; sentence.trim_end_matches(['.', ',', '!', '?']); + //~^ manual_pattern_char_comparison sentence.split(['\n', 'X']); + //~^ manual_pattern_char_comparison sentence.split(['\n', 'X']); + //~^ manual_pattern_char_comparison sentence.splitn(3, 'X'); + //~^ manual_pattern_char_comparison sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); let char_compare = 'X'; sentence.splitn(3, char_compare); + //~^ manual_pattern_char_comparison sentence.split(['\n', 'X', 'Y']); + //~^ manual_pattern_char_comparison sentence.splitn(3, 'X'); + //~^ manual_pattern_char_comparison sentence.splitn(3, ['X', 'W']); + //~^ manual_pattern_char_comparison sentence.find('🎈'); + //~^ manual_pattern_char_comparison let not_str = NotStr; not_str.find(|c: char| c == 'X'); @@ -58,4 +67,5 @@ fn msrv_1_57() { fn msrv_1_58() { let sentence = "Hello, world!"; sentence.trim_end_matches(['.', ',', '!', '?']); + //~^ manual_pattern_char_comparison } diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs index 43e883cd325a2..451480df42250 100644 --- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.rs @@ -9,16 +9,25 @@ impl NotStr { fn main() { let sentence = "Hello, world!"; sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + //~^ manual_pattern_char_comparison sentence.split(|c: char| c == '\n' || c == 'X'); + //~^ manual_pattern_char_comparison sentence.split(|c| c == '\n' || c == 'X'); + //~^ manual_pattern_char_comparison sentence.splitn(3, |c: char| c == 'X'); + //~^ manual_pattern_char_comparison sentence.splitn(3, |c: char| c.is_whitespace() || c == 'X'); let char_compare = 'X'; sentence.splitn(3, |c: char| c == char_compare); + //~^ manual_pattern_char_comparison sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); + //~^ manual_pattern_char_comparison sentence.splitn(3, |c: char| matches!(c, 'X')); + //~^ manual_pattern_char_comparison sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); + //~^ manual_pattern_char_comparison sentence.find(|c| c == '🎈'); + //~^ manual_pattern_char_comparison let not_str = NotStr; not_str.find(|c: char| c == 'X'); @@ -58,4 +67,5 @@ fn msrv_1_57() { fn msrv_1_58() { let sentence = "Hello, world!"; sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); + //~^ manual_pattern_char_comparison } diff --git a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr index f185d7c8f6767..d4fc3faa066f0 100644 --- a/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr +++ b/src/tools/clippy/tests/ui/manual_pattern_char_comparison.stderr @@ -8,55 +8,55 @@ LL | sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || = help: to override `-D warnings` add `#[allow(clippy::manual_pattern_char_comparison)]` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:12:20 + --> tests/ui/manual_pattern_char_comparison.rs:13:20 | LL | sentence.split(|c: char| c == '\n' || c == 'X'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:13:20 + --> tests/ui/manual_pattern_char_comparison.rs:15:20 | LL | sentence.split(|c| c == '\n' || c == 'X'); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X']` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:14:24 + --> tests/ui/manual_pattern_char_comparison.rs:17:24 | LL | sentence.splitn(3, |c: char| c == 'X'); | ^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:17:24 + --> tests/ui/manual_pattern_char_comparison.rs:21:24 | LL | sentence.splitn(3, |c: char| c == char_compare); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `char_compare` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:18:20 + --> tests/ui/manual_pattern_char_comparison.rs:23:20 | LL | sentence.split(|c: char| matches!(c, '\n' | 'X' | 'Y')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['\n', 'X', 'Y']` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:19:24 + --> tests/ui/manual_pattern_char_comparison.rs:25:24 | LL | sentence.splitn(3, |c: char| matches!(c, 'X')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a `char`: `'X'` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:20:24 + --> tests/ui/manual_pattern_char_comparison.rs:27:24 | LL | sentence.splitn(3, |c: char| matches!(c, 'X' | 'W')); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['X', 'W']` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:21:19 + --> tests/ui/manual_pattern_char_comparison.rs:29:19 | LL | sentence.find(|c| c == '🎈'); | ^^^^^^^^^^^^^ help: consider using a `char`: `'🎈'` error: this manual char comparison can be written more succinctly - --> tests/ui/manual_pattern_char_comparison.rs:60:31 + --> tests/ui/manual_pattern_char_comparison.rs:69:31 | LL | sentence.trim_end_matches(|c: char| c == '.' || c == ',' || c == '!' || c == '?'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using an array of `char`: `['.', ',', '!', '?']` diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.fixed b/src/tools/clippy/tests/ui/manual_range_patterns.fixed index 60467bf9e8848..c05e1fb27b03a 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.fixed +++ b/src/tools/clippy/tests/ui/manual_range_patterns.fixed @@ -6,7 +6,9 @@ fn main() { let f = 6; let _ = matches!(f, 1..=10); + //~^ manual_range_patterns let _ = matches!(f, 1..=10); + //~^ manual_range_patterns let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 8 | 10); // 7 is missing let _ = matches!(f, | 4); let _ = matches!(f, 4 | 5); @@ -14,34 +16,51 @@ fn main() { let _ = matches!(f, 0 | 2147483647); let _ = matches!(f, -2147483647 | 2147483647); let _ = matches!(f, 1..=4); + //~^ manual_range_patterns let _ = matches!(f, 1..4); + //~^ manual_range_patterns let _ = matches!(f, 1..=48324729); + //~^ manual_range_patterns let _ = matches!(f, 0..=48324730); + //~^ manual_range_patterns let _ = matches!(f, 0..=3); + //~^ manual_range_patterns #[allow(clippy::match_like_matches_macro)] let _ = match f { 1..=10 => true, + //~^ manual_range_patterns _ => false, }; let _ = matches!(f, -5..=3); + //~^ manual_range_patterns let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing let _ = matches!(f, -1_000_001..=1_000_001); + //~^ manual_range_patterns let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002); matches!(f, 0x00..=0x03); + //~^ manual_range_patterns matches!(f, 0x00..=0x07); + //~^ manual_range_patterns matches!(f, -0x09..=0x00); + //~^ manual_range_patterns matches!(f, 0..=5); + //~^ manual_range_patterns matches!(f, 0..5); + //~^ manual_range_patterns matches!(f, 0..10); + //~^ manual_range_patterns matches!(f, 0..=10); + //~^ manual_range_patterns matches!(f, 0..=10); + //~^ manual_range_patterns macro_rules! mac { ($e:expr) => { matches!($e, 1..=10) + //~^ manual_range_patterns }; } mac!(f); diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.rs b/src/tools/clippy/tests/ui/manual_range_patterns.rs index 9cd803334499d..e5c403dc5f2e8 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.rs +++ b/src/tools/clippy/tests/ui/manual_range_patterns.rs @@ -6,7 +6,9 @@ fn main() { let f = 6; let _ = matches!(f, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); + //~^ manual_range_patterns let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 7 | 8 | 10); + //~^ manual_range_patterns let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 8 | 10); // 7 is missing let _ = matches!(f, | 4); let _ = matches!(f, 4 | 5); @@ -14,34 +16,51 @@ fn main() { let _ = matches!(f, 0 | 2147483647); let _ = matches!(f, -2147483647 | 2147483647); let _ = matches!(f, 1 | (2..=4)); + //~^ manual_range_patterns let _ = matches!(f, 1 | (2..4)); + //~^ manual_range_patterns let _ = matches!(f, (1..=10) | (2..=13) | (14..=48324728) | 48324729); + //~^ manual_range_patterns let _ = matches!(f, 0 | (1..=10) | 48324730 | (2..=13) | (14..=48324728) | 48324729); + //~^ manual_range_patterns let _ = matches!(f, 0..=1 | 0..=2 | 0..=3); + //~^ manual_range_patterns #[allow(clippy::match_like_matches_macro)] let _ = match f { 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true, + //~^ manual_range_patterns _ => false, }; let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2); + //~^ manual_range_patterns let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1); // 2 is missing let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001); + //~^ manual_range_patterns let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_002); matches!(f, 0x00 | 0x01 | 0x02 | 0x03); + //~^ manual_range_patterns matches!(f, 0x00..=0x05 | 0x06 | 0x07); + //~^ manual_range_patterns matches!(f, -0x09 | -0x08 | -0x07..=0x00); + //~^ manual_range_patterns matches!(f, 0..5 | 5); + //~^ manual_range_patterns matches!(f, 0 | 1..5); + //~^ manual_range_patterns matches!(f, 0..=5 | 6..10); + //~^ manual_range_patterns matches!(f, 0..5 | 5..=10); + //~^ manual_range_patterns matches!(f, 5..=10 | 0..5); + //~^ manual_range_patterns macro_rules! mac { ($e:expr) => { matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10) + //~^ manual_range_patterns }; } mac!(f); diff --git a/src/tools/clippy/tests/ui/manual_range_patterns.stderr b/src/tools/clippy/tests/ui/manual_range_patterns.stderr index 7c19fdd475f19..e494e7234d686 100644 --- a/src/tools/clippy/tests/ui/manual_range_patterns.stderr +++ b/src/tools/clippy/tests/ui/manual_range_patterns.stderr @@ -8,109 +8,109 @@ LL | let _ = matches!(f, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10); = help: to override `-D warnings` add `#[allow(clippy::manual_range_patterns)]` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:9:25 + --> tests/ui/manual_range_patterns.rs:10:25 | LL | let _ = matches!(f, 4 | 2 | 3 | 1 | 5 | 6 | 9 | 7 | 8 | 10); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:16:25 + --> tests/ui/manual_range_patterns.rs:18:25 | LL | let _ = matches!(f, 1 | (2..=4)); | ^^^^^^^^^^^ help: try: `1..=4` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:17:25 + --> tests/ui/manual_range_patterns.rs:20:25 | LL | let _ = matches!(f, 1 | (2..4)); | ^^^^^^^^^^ help: try: `1..4` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:18:25 + --> tests/ui/manual_range_patterns.rs:22:25 | LL | let _ = matches!(f, (1..=10) | (2..=13) | (14..=48324728) | 48324729); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=48324729` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:19:25 + --> tests/ui/manual_range_patterns.rs:24:25 | LL | let _ = matches!(f, 0 | (1..=10) | 48324730 | (2..=13) | (14..=48324728) | 48324729); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0..=48324730` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:20:25 + --> tests/ui/manual_range_patterns.rs:26:25 | LL | let _ = matches!(f, 0..=1 | 0..=2 | 0..=3); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `0..=3` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:23:9 + --> tests/ui/manual_range_patterns.rs:30:9 | LL | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 => true, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:26:25 + --> tests/ui/manual_range_patterns.rs:34:25 | LL | let _ = matches!(f, -1 | -5 | 3 | -2 | -4 | -3 | 0 | 1 | 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-5..=3` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:28:25 + --> tests/ui/manual_range_patterns.rs:37:25 | LL | let _ = matches!(f, -1_000_000..=1_000_000 | -1_000_001 | 1_000_001); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-1_000_001..=1_000_001` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:31:17 + --> tests/ui/manual_range_patterns.rs:41:17 | LL | matches!(f, 0x00 | 0x01 | 0x02 | 0x03); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0x00..=0x03` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:32:17 + --> tests/ui/manual_range_patterns.rs:43:17 | LL | matches!(f, 0x00..=0x05 | 0x06 | 0x07); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `0x00..=0x07` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:33:17 + --> tests/ui/manual_range_patterns.rs:45:17 | LL | matches!(f, -0x09 | -0x08 | -0x07..=0x00); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `-0x09..=0x00` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:35:17 + --> tests/ui/manual_range_patterns.rs:48:17 | LL | matches!(f, 0..5 | 5); | ^^^^^^^^ help: try: `0..=5` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:36:17 + --> tests/ui/manual_range_patterns.rs:50:17 | LL | matches!(f, 0 | 1..5); | ^^^^^^^^ help: try: `0..5` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:38:17 + --> tests/ui/manual_range_patterns.rs:53:17 | LL | matches!(f, 0..=5 | 6..10); | ^^^^^^^^^^^^^ help: try: `0..10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:39:17 + --> tests/ui/manual_range_patterns.rs:55:17 | LL | matches!(f, 0..5 | 5..=10); | ^^^^^^^^^^^^^ help: try: `0..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:40:17 + --> tests/ui/manual_range_patterns.rs:57:17 | LL | matches!(f, 5..=10 | 0..5); | ^^^^^^^^^^^^^ help: try: `0..=10` error: this OR pattern can be rewritten using a range - --> tests/ui/manual_range_patterns.rs:44:26 + --> tests/ui/manual_range_patterns.rs:62:26 | LL | matches!($e, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `1..=10` diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed index 2d50865586d1f..e64654bb68664 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed @@ -11,10 +11,15 @@ fn main() { let value: i32 = 5; let _: i32 = value.rem_euclid(4); + //~^ manual_rem_euclid let _: i32 = value.rem_euclid(4); + //~^ manual_rem_euclid let _: i32 = value.rem_euclid(4); + //~^ manual_rem_euclid let _: i32 = value.rem_euclid(4); + //~^ manual_rem_euclid let _: i32 = 1 + value.rem_euclid(4); + //~^ manual_rem_euclid let _: i32 = (3 + value % 4) % 4; let _: i32 = (-4 + value % -4) % -4; @@ -35,6 +40,7 @@ fn main() { inline!( let value: i32 = 5; let _: i32 = value.rem_euclid(4); + //~^ manual_rem_euclid ); // Do not lint in external macros @@ -47,11 +53,13 @@ fn main() { // Should lint for params too pub fn rem_euclid_4(num: i32) -> i32 { num.rem_euclid(4) + //~^ manual_rem_euclid } // Constant version came later, should still lint pub const fn const_rem_euclid_4(num: i32) -> i32 { num.rem_euclid(4) + //~^ manual_rem_euclid } #[clippy::msrv = "1.37"] @@ -64,6 +72,7 @@ pub fn msrv_1_37() { pub fn msrv_1_38() { let x: i32 = 10; let _: i32 = x.rem_euclid(4); + //~^ manual_rem_euclid } // For const fns: @@ -77,4 +86,5 @@ pub const fn msrv_1_51() { pub const fn msrv_1_52() { let x: i32 = 10; let _: i32 = x.rem_euclid(4); + //~^ manual_rem_euclid } diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.rs b/src/tools/clippy/tests/ui/manual_rem_euclid.rs index e405a2db47651..4561a7ee9ea4e 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.rs +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.rs @@ -11,10 +11,15 @@ fn main() { let value: i32 = 5; let _: i32 = ((value % 4) + 4) % 4; + //~^ manual_rem_euclid let _: i32 = (4 + (value % 4)) % 4; + //~^ manual_rem_euclid let _: i32 = (value % 4 + 4) % 4; + //~^ manual_rem_euclid let _: i32 = (4 + value % 4) % 4; + //~^ manual_rem_euclid let _: i32 = 1 + (4 + value % 4) % 4; + //~^ manual_rem_euclid let _: i32 = (3 + value % 4) % 4; let _: i32 = (-4 + value % -4) % -4; @@ -35,6 +40,7 @@ fn main() { inline!( let value: i32 = 5; let _: i32 = ((value % 4) + 4) % 4; + //~^ manual_rem_euclid ); // Do not lint in external macros @@ -47,11 +53,13 @@ fn main() { // Should lint for params too pub fn rem_euclid_4(num: i32) -> i32 { ((num % 4) + 4) % 4 + //~^ manual_rem_euclid } // Constant version came later, should still lint pub const fn const_rem_euclid_4(num: i32) -> i32 { ((num % 4) + 4) % 4 + //~^ manual_rem_euclid } #[clippy::msrv = "1.37"] @@ -64,6 +72,7 @@ pub fn msrv_1_37() { pub fn msrv_1_38() { let x: i32 = 10; let _: i32 = ((x % 4) + 4) % 4; + //~^ manual_rem_euclid } // For const fns: @@ -77,4 +86,5 @@ pub const fn msrv_1_51() { pub const fn msrv_1_52() { let x: i32 = 10; let _: i32 = ((x % 4) + 4) % 4; + //~^ manual_rem_euclid } diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr index a19fdadb1c9bd..386815b23b680 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.stderr +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.stderr @@ -8,31 +8,31 @@ LL | let _: i32 = ((value % 4) + 4) % 4; = help: to override `-D warnings` add `#[allow(clippy::manual_rem_euclid)]` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:14:18 + --> tests/ui/manual_rem_euclid.rs:15:18 | LL | let _: i32 = (4 + (value % 4)) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:15:18 + --> tests/ui/manual_rem_euclid.rs:17:18 | LL | let _: i32 = (value % 4 + 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:16:18 + --> tests/ui/manual_rem_euclid.rs:19:18 | LL | let _: i32 = (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:17:22 + --> tests/ui/manual_rem_euclid.rs:21:22 | LL | let _: i32 = 1 + (4 + value % 4) % 4; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:37:22 + --> tests/ui/manual_rem_euclid.rs:42:22 | LL | let _: i32 = ((value % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `value.rem_euclid(4)` @@ -40,25 +40,25 @@ LL | let _: i32 = ((value % 4) + 4) % 4; = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:49:5 + --> tests/ui/manual_rem_euclid.rs:55:5 | LL | ((num % 4) + 4) % 4 | ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:54:5 + --> tests/ui/manual_rem_euclid.rs:61:5 | LL | ((num % 4) + 4) % 4 | ^^^^^^^^^^^^^^^^^^^ help: consider using: `num.rem_euclid(4)` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:66:18 + --> tests/ui/manual_rem_euclid.rs:74:18 | LL | let _: i32 = ((x % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)` error: manual `rem_euclid` implementation - --> tests/ui/manual_rem_euclid.rs:79:18 + --> tests/ui/manual_rem_euclid.rs:88:18 | LL | let _: i32 = ((x % 4) + 4) % 4; | ^^^^^^^^^^^^^^^^^ help: consider using: `x.rem_euclid(4)` diff --git a/src/tools/clippy/tests/ui/manual_repeat_n.fixed b/src/tools/clippy/tests/ui/manual_repeat_n.fixed index 4235b02a89e39..44ad3c02d3b85 100644 --- a/src/tools/clippy/tests/ui/manual_repeat_n.fixed +++ b/src/tools/clippy/tests/ui/manual_repeat_n.fixed @@ -4,14 +4,19 @@ use std::iter::repeat; fn main() { let _ = std::iter::repeat_n(10, 3); + //~^ manual_repeat_n let _ = std::iter::repeat_n(String::from("foo"), 4); + //~^ manual_repeat_n for value in std::iter::repeat_n(5, 3) {} + //~^ manual_repeat_n let _: Vec<_> = std::iter::repeat_n(String::from("bar"), 10).collect(); + //~^ manual_repeat_n let _ = std::iter::repeat_n(vec![1, 2], 2); + //~^ manual_repeat_n } mod foo_lib { diff --git a/src/tools/clippy/tests/ui/manual_repeat_n.rs b/src/tools/clippy/tests/ui/manual_repeat_n.rs index dbf9ac6a14afb..ef6d6827d573d 100644 --- a/src/tools/clippy/tests/ui/manual_repeat_n.rs +++ b/src/tools/clippy/tests/ui/manual_repeat_n.rs @@ -4,14 +4,19 @@ use std::iter::repeat; fn main() { let _ = repeat(10).take(3); + //~^ manual_repeat_n let _ = repeat(String::from("foo")).take(4); + //~^ manual_repeat_n for value in std::iter::repeat(5).take(3) {} + //~^ manual_repeat_n let _: Vec<_> = std::iter::repeat(String::from("bar")).take(10).collect(); + //~^ manual_repeat_n let _ = repeat(vec![1, 2]).take(2); + //~^ manual_repeat_n } mod foo_lib { diff --git a/src/tools/clippy/tests/ui/manual_repeat_n.stderr b/src/tools/clippy/tests/ui/manual_repeat_n.stderr index 87395b3f8bf1b..de968b3ff7919 100644 --- a/src/tools/clippy/tests/ui/manual_repeat_n.stderr +++ b/src/tools/clippy/tests/ui/manual_repeat_n.stderr @@ -8,25 +8,25 @@ LL | let _ = repeat(10).take(3); = help: to override `-D warnings` add `#[allow(clippy::manual_repeat_n)]` error: this `repeat().take()` can be written more concisely - --> tests/ui/manual_repeat_n.rs:8:13 + --> tests/ui/manual_repeat_n.rs:9:13 | LL | let _ = repeat(String::from("foo")).take(4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(String::from("foo"), 4)` error: this `repeat().take()` can be written more concisely - --> tests/ui/manual_repeat_n.rs:10:18 + --> tests/ui/manual_repeat_n.rs:12:18 | LL | for value in std::iter::repeat(5).take(3) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(5, 3)` error: this `repeat().take()` can be written more concisely - --> tests/ui/manual_repeat_n.rs:12:21 + --> tests/ui/manual_repeat_n.rs:15:21 | LL | let _: Vec<_> = std::iter::repeat(String::from("bar")).take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(String::from("bar"), 10)` error: this `repeat().take()` can be written more concisely - --> tests/ui/manual_repeat_n.rs:14:13 + --> tests/ui/manual_repeat_n.rs:18:13 | LL | let _ = repeat(vec![1, 2]).take(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(vec![1, 2], 2)` diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed index 5540029bf6b1f..ca8491131c06c 100644 --- a/src/tools/clippy/tests/ui/manual_retain.fixed +++ b/src/tools/clippy/tests/ui/manual_retain.fixed @@ -23,13 +23,18 @@ fn binary_heap_retain() { let mut binary_heap = BinaryHeap::from([1, 2, 3]); // Do lint. binary_heap.retain(|x| x % 2 == 0); + //~^ manual_retain binary_heap.retain(|x| x % 2 == 0); + //~^ manual_retain binary_heap.retain(|x| x % 2 == 0); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]); tuples.retain(|(ref x, ref y)| *x == 0); + //~^ manual_retain tuples.retain(|(x, y)| *x == 0); + //~^ manual_retain // Do not lint, because type conversion is performed binary_heap = binary_heap @@ -60,7 +65,9 @@ fn btree_map_retain() { let mut btree_map: BTreeMap = (0..8).map(|x| (x, x * 10)).collect(); // Do lint. btree_map.retain(|k, _| k % 2 == 0); + //~^ manual_retain btree_map.retain(|_, &mut v| v % 2 == 0); + //~^ manual_retain btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0)); // Do not lint, because the parameters are not matched in tuple pattern @@ -84,13 +91,18 @@ fn btree_set_retain() { // Do lint. btree_set.retain(|x| x % 2 == 0); + //~^ manual_retain btree_set.retain(|x| x % 2 == 0); + //~^ manual_retain btree_set.retain(|x| x % 2 == 0); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]); tuples.retain(|(ref x, ref y)| *x == 0); + //~^ manual_retain tuples.retain(|(x, y)| *x == 0); + //~^ manual_retain // Do not lint, because type conversion is performed btree_set = btree_set @@ -121,7 +133,9 @@ fn hash_map_retain() { let mut hash_map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); // Do lint. hash_map.retain(|k, _| k % 2 == 0); + //~^ manual_retain hash_map.retain(|_, &mut v| v % 2 == 0); + //~^ manual_retain hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0)); // Do not lint, because the parameters are not matched in tuple pattern @@ -144,13 +158,18 @@ fn hash_set_retain() { let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); // Do lint. hash_set.retain(|x| x % 2 == 0); + //~^ manual_retain hash_set.retain(|x| x % 2 == 0); + //~^ manual_retain hash_set.retain(|x| x % 2 == 0); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]); tuples.retain(|(ref x, ref y)| *x == 0); + //~^ manual_retain tuples.retain(|(x, y)| *x == 0); + //~^ manual_retain // Do not lint, because type conversion is performed hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::>(); @@ -180,6 +199,7 @@ fn string_retain() { let mut s = String::from("foobar"); // Do lint. s.retain(|c| c != 'o'); + //~^ manual_retain // Do not lint, because this expression is not assign. let mut bar: String = s.chars().filter(|&c| c != 'o').to_owned().collect(); @@ -192,13 +212,18 @@ fn vec_retain() { let mut vec = vec![0, 1, 2]; // Do lint. vec.retain(|x| x % 2 == 0); + //~^ manual_retain vec.retain(|x| x % 2 == 0); + //~^ manual_retain vec.retain(|x| x % 2 == 0); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = vec![(0, 1), (1, 2), (2, 3)]; tuples.retain(|(ref x, ref y)| *x == 0); + //~^ manual_retain tuples.retain(|(x, y)| *x == 0); + //~^ manual_retain // Do not lint, because type conversion is performed vec = vec.into_iter().filter(|x| x % 2 == 0).collect::>(); @@ -221,8 +246,11 @@ fn vec_deque_retain() { // Do lint. vec_deque.retain(|x| x % 2 == 0); + //~^ manual_retain vec_deque.retain(|x| x % 2 == 0); + //~^ manual_retain vec_deque.retain(|x| x % 2 == 0); + //~^ manual_retain // Do not lint, because type conversion is performed vec_deque = vec_deque @@ -280,10 +308,12 @@ fn issue_10393() { // Do lint let mut vec = vec![(0, 1), (1, 2), (2, 3)]; vec.retain(|(x, y)| *x == 0); + //~^ manual_retain // Do lint let mut tuples = vec![(true, -2), (false, 3)]; tuples.retain(|(_, n)| *n > 0); + //~^ manual_retain } fn issue_11457() { @@ -301,11 +331,17 @@ fn issue_12081() { // Do lint vec.retain(|&x| x == 0); + //~^ manual_retain vec.retain(|&x| x == 0); + //~^ manual_retain vec.retain(|&x| x == 0); + //~^ manual_retain // Do lint vec.retain(|x| *x == 0); + //~^ manual_retain vec.retain(|x| *x == 0); + //~^ manual_retain vec.retain(|x| *x == 0); + //~^ manual_retain } diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs index cee641d9d65f9..cd05a41f3f25a 100644 --- a/src/tools/clippy/tests/ui/manual_retain.rs +++ b/src/tools/clippy/tests/ui/manual_retain.rs @@ -23,13 +23,18 @@ fn binary_heap_retain() { let mut binary_heap = BinaryHeap::from([1, 2, 3]); // Do lint. binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); + //~^ manual_retain binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect(); + //~^ manual_retain binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect(); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]); tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); + //~^ manual_retain // Do not lint, because type conversion is performed binary_heap = binary_heap @@ -60,8 +65,11 @@ fn btree_map_retain() { let mut btree_map: BTreeMap = (0..8).map(|x| (x, x * 10)).collect(); // Do lint. btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + //~^ manual_retain btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); + //~^ manual_retain btree_map = btree_map + //~^ manual_retain .into_iter() .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) .collect(); @@ -87,13 +95,18 @@ fn btree_set_retain() { // Do lint. btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + //~^ manual_retain btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); + //~^ manual_retain btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]); tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); + //~^ manual_retain // Do not lint, because type conversion is performed btree_set = btree_set @@ -124,8 +137,11 @@ fn hash_map_retain() { let mut hash_map: HashMap = (0..8).map(|x| (x, x * 10)).collect(); // Do lint. hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); + //~^ manual_retain hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); + //~^ manual_retain hash_map = hash_map + //~^ manual_retain .into_iter() .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) .collect(); @@ -150,13 +166,18 @@ fn hash_set_retain() { let mut hash_set = HashSet::from([1, 2, 3, 4, 5, 6]); // Do lint. hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); + //~^ manual_retain hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); + //~^ manual_retain hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]); tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); + //~^ manual_retain // Do not lint, because type conversion is performed hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect::>(); @@ -186,6 +207,7 @@ fn string_retain() { let mut s = String::from("foobar"); // Do lint. s = s.chars().filter(|&c| c != 'o').to_owned().collect(); + //~^ manual_retain // Do not lint, because this expression is not assign. let mut bar: String = s.chars().filter(|&c| c != 'o').to_owned().collect(); @@ -198,13 +220,18 @@ fn vec_retain() { let mut vec = vec![0, 1, 2]; // Do lint. vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); + //~^ manual_retain vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); + //~^ manual_retain vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); + //~^ manual_retain // Do lint, because we use pattern matching let mut tuples = vec![(0, 1), (1, 2), (2, 3)]; tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); + //~^ manual_retain tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); + //~^ manual_retain // Do not lint, because type conversion is performed vec = vec.into_iter().filter(|x| x % 2 == 0).collect::>(); @@ -227,8 +254,11 @@ fn vec_deque_retain() { // Do lint. vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); + //~^ manual_retain vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); + //~^ manual_retain vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); + //~^ manual_retain // Do not lint, because type conversion is performed vec_deque = vec_deque @@ -286,10 +316,12 @@ fn issue_10393() { // Do lint let mut vec = vec![(0, 1), (1, 2), (2, 3)]; vec = vec.into_iter().filter(|(x, y)| *x == 0).collect(); + //~^ manual_retain // Do lint let mut tuples = vec![(true, -2), (false, 3)]; tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect(); + //~^ manual_retain } fn issue_11457() { @@ -307,11 +339,17 @@ fn issue_12081() { // Do lint vec = vec.iter().filter(|&&x| x == 0).copied().collect(); + //~^ manual_retain vec = vec.iter().filter(|&&x| x == 0).cloned().collect(); + //~^ manual_retain vec = vec.into_iter().filter(|&x| x == 0).collect(); + //~^ manual_retain // Do lint vec = vec.iter().filter(|&x| *x == 0).copied().collect(); + //~^ manual_retain vec = vec.iter().filter(|&x| *x == 0).cloned().collect(); + //~^ manual_retain vec = vec.into_iter().filter(|x| *x == 0).collect(); + //~^ manual_retain } diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr index c25c804df7581..2f81647dd8b7b 100644 --- a/src/tools/clippy/tests/ui/manual_retain.stderr +++ b/src/tools/clippy/tests/ui/manual_retain.stderr @@ -8,229 +8,231 @@ LL | binary_heap = binary_heap.into_iter().filter(|x| x % 2 == 0).collect(); = help: to override `-D warnings` add `#[allow(clippy::manual_retain)]` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:26:5 + --> tests/ui/manual_retain.rs:27:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:27:5 + --> tests/ui/manual_retain.rs:29:5 | LL | binary_heap = binary_heap.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `binary_heap.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:31:5 + --> tests/ui/manual_retain.rs:34:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:32:5 + --> tests/ui/manual_retain.rs:36:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:62:5 + --> tests/ui/manual_retain.rs:67:5 | LL | btree_map = btree_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:63:5 + --> tests/ui/manual_retain.rs:69:5 | LL | btree_map = btree_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:64:5 + --> tests/ui/manual_retain.rs:71:5 | LL | / btree_map = btree_map +LL | | LL | | .into_iter() LL | | .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `btree_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:89:5 + --> tests/ui/manual_retain.rs:97:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:90:5 + --> tests/ui/manual_retain.rs:99:5 | LL | btree_set = btree_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:91:5 + --> tests/ui/manual_retain.rs:101:5 | LL | btree_set = btree_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `btree_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:95:5 + --> tests/ui/manual_retain.rs:106:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:96:5 + --> tests/ui/manual_retain.rs:108:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:126:5 + --> tests/ui/manual_retain.rs:139:5 | LL | hash_map = hash_map.into_iter().filter(|(k, _)| k % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|k, _| k % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:127:5 + --> tests/ui/manual_retain.rs:141:5 | LL | hash_map = hash_map.into_iter().filter(|(_, v)| v % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_map.retain(|_, &mut v| v % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:128:5 + --> tests/ui/manual_retain.rs:143:5 | LL | / hash_map = hash_map +LL | | LL | | .into_iter() LL | | .filter(|(k, v)| (k % 2 == 0) && (v % 2 == 0)) LL | | .collect(); | |__________________^ help: consider calling `.retain()` instead: `hash_map.retain(|k, &mut v| (k % 2 == 0) && (v % 2 == 0))` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:152:5 + --> tests/ui/manual_retain.rs:168:5 | LL | hash_set = hash_set.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:153:5 + --> tests/ui/manual_retain.rs:170:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:154:5 + --> tests/ui/manual_retain.rs:172:5 | LL | hash_set = hash_set.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `hash_set.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:158:5 + --> tests/ui/manual_retain.rs:177:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:159:5 + --> tests/ui/manual_retain.rs:179:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:188:5 + --> tests/ui/manual_retain.rs:209:5 | LL | s = s.chars().filter(|&c| c != 'o').to_owned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `s.retain(|c| c != 'o')` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:200:5 + --> tests/ui/manual_retain.rs:222:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:201:5 + --> tests/ui/manual_retain.rs:224:5 | LL | vec = vec.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:202:5 + --> tests/ui/manual_retain.rs:226:5 | LL | vec = vec.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:206:5 + --> tests/ui/manual_retain.rs:231:5 | LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:207:5 + --> tests/ui/manual_retain.rs:233:5 | LL | tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:229:5 + --> tests/ui/manual_retain.rs:256:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:230:5 + --> tests/ui/manual_retain.rs:258:5 | LL | vec_deque = vec_deque.iter().filter(|&x| x % 2 == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:231:5 + --> tests/ui/manual_retain.rs:260:5 | LL | vec_deque = vec_deque.into_iter().filter(|x| x % 2 == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec_deque.retain(|x| x % 2 == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:288:5 + --> tests/ui/manual_retain.rs:318:5 | LL | vec = vec.into_iter().filter(|(x, y)| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|(x, y)| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:292:5 + --> tests/ui/manual_retain.rs:323:5 | LL | tuples = tuples.into_iter().filter(|(_, n)| *n > 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(_, n)| *n > 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:309:5 + --> tests/ui/manual_retain.rs:341:5 | LL | vec = vec.iter().filter(|&&x| x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:310:5 + --> tests/ui/manual_retain.rs:343:5 | LL | vec = vec.iter().filter(|&&x| x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:311:5 + --> tests/ui/manual_retain.rs:345:5 | LL | vec = vec.into_iter().filter(|&x| x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|&x| x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:314:5 + --> tests/ui/manual_retain.rs:349:5 | LL | vec = vec.iter().filter(|&x| *x == 0).copied().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:315:5 + --> tests/ui/manual_retain.rs:351:5 | LL | vec = vec.iter().filter(|&x| *x == 0).cloned().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` error: this expression can be written more simply using `.retain()` - --> tests/ui/manual_retain.rs:316:5 + --> tests/ui/manual_retain.rs:353:5 | LL | vec = vec.into_iter().filter(|x| *x == 0).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `vec.retain(|x| *x == 0)` diff --git a/src/tools/clippy/tests/ui/manual_rotate.fixed b/src/tools/clippy/tests/ui/manual_rotate.fixed index 5d33838a31877..49db8661369e9 100644 --- a/src/tools/clippy/tests/ui/manual_rotate.fixed +++ b/src/tools/clippy/tests/ui/manual_rotate.fixed @@ -6,18 +6,29 @@ fn main() { let a_u32 = 1u32; // True positives let y_u8 = x_u8.rotate_right(3); + //~^ manual_rotate let y_u16 = x_u16.rotate_right(7); + //~^ manual_rotate let y_u32 = x_u32.rotate_right(8); + //~^ manual_rotate let y_u64 = x_u64.rotate_right(9); + //~^ manual_rotate let y_i8 = x_i8.rotate_right(3); + //~^ manual_rotate let y_i16 = x_i16.rotate_right(7); + //~^ manual_rotate let y_i32 = x_i32.rotate_right(8); + //~^ manual_rotate let y_i64 = x_i64.rotate_right(9); + //~^ manual_rotate // Plus also works instead of | let y_u32_plus = x_u32.rotate_right(8); + //~^ manual_rotate // Complex expression let y_u32_complex = (x_u32 | 3256).rotate_right(8); + //~^ manual_rotate let y_u64_as = (x_u32 as u64).rotate_right(8); + //~^ manual_rotate // False positives - can't be replaced with a rotation let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); diff --git a/src/tools/clippy/tests/ui/manual_rotate.rs b/src/tools/clippy/tests/ui/manual_rotate.rs index 5377491fb1a38..6445e60aa25da 100644 --- a/src/tools/clippy/tests/ui/manual_rotate.rs +++ b/src/tools/clippy/tests/ui/manual_rotate.rs @@ -6,18 +6,29 @@ fn main() { let a_u32 = 1u32; // True positives let y_u8 = (x_u8 >> 3) | (x_u8 << 5); + //~^ manual_rotate let y_u16 = (x_u16 >> 7) | (x_u16 << 9); + //~^ manual_rotate let y_u32 = (x_u32 >> 8) | (x_u32 << 24); + //~^ manual_rotate let y_u64 = (x_u64 >> 9) | (x_u64 << 55); + //~^ manual_rotate let y_i8 = (x_i8 >> 3) | (x_i8 << 5); + //~^ manual_rotate let y_i16 = (x_i16 >> 7) | (x_i16 << 9); + //~^ manual_rotate let y_i32 = (x_i32 >> 8) | (x_i32 << 24); + //~^ manual_rotate let y_i64 = (x_i64 >> 9) | (x_i64 << 55); + //~^ manual_rotate // Plus also works instead of | let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); + //~^ manual_rotate // Complex expression let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); + //~^ manual_rotate let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); + //~^ manual_rotate // False positives - can't be replaced with a rotation let y_u8_false = (x_u8 >> 6) | (x_u8 << 3); diff --git a/src/tools/clippy/tests/ui/manual_rotate.stderr b/src/tools/clippy/tests/ui/manual_rotate.stderr index 52da0861f7003..a28721fbb94c8 100644 --- a/src/tools/clippy/tests/ui/manual_rotate.stderr +++ b/src/tools/clippy/tests/ui/manual_rotate.stderr @@ -8,61 +8,61 @@ LL | let y_u8 = (x_u8 >> 3) | (x_u8 << 5); = help: to override `-D warnings` add `#[allow(clippy::manual_rotate)]` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:9:17 + --> tests/ui/manual_rotate.rs:10:17 | LL | let y_u16 = (x_u16 >> 7) | (x_u16 << 9); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u16.rotate_right(7)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:10:17 + --> tests/ui/manual_rotate.rs:12:17 | LL | let y_u32 = (x_u32 >> 8) | (x_u32 << 24); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:11:17 + --> tests/ui/manual_rotate.rs:14:17 | LL | let y_u64 = (x_u64 >> 9) | (x_u64 << 55); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u64.rotate_right(9)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:12:16 + --> tests/ui/manual_rotate.rs:16:16 | LL | let y_i8 = (x_i8 >> 3) | (x_i8 << 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i8.rotate_right(3)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:13:17 + --> tests/ui/manual_rotate.rs:18:17 | LL | let y_i16 = (x_i16 >> 7) | (x_i16 << 9); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i16.rotate_right(7)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:14:17 + --> tests/ui/manual_rotate.rs:20:17 | LL | let y_i32 = (x_i32 >> 8) | (x_i32 << 24); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i32.rotate_right(8)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:15:17 + --> tests/ui/manual_rotate.rs:22:17 | LL | let y_i64 = (x_i64 >> 9) | (x_i64 << 55); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_i64.rotate_right(9)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:17:22 + --> tests/ui/manual_rotate.rs:25:22 | LL | let y_u32_plus = (x_u32 >> 8) + (x_u32 << 24); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `x_u32.rotate_right(8)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:19:25 + --> tests/ui/manual_rotate.rs:28:25 | LL | let y_u32_complex = ((x_u32 | 3256) >> 8) | ((x_u32 | 3256) << 24); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 | 3256).rotate_right(8)` error: there is no need to manually implement bit rotation - --> tests/ui/manual_rotate.rs:20:20 + --> tests/ui/manual_rotate.rs:30:20 | LL | let y_u64_as = (x_u32 as u64 >> 8) | ((x_u32 as u64) << 56); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this expression can be rewritten as: `(x_u32 as u64).rotate_right(8)` diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed index 528a65790c4c8..3f73d6e5a1a67 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed @@ -4,38 +4,57 @@ use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.saturating_add(1); + //~^ manual_saturating_arithmetic let _ = 1u32.saturating_add(1); + //~^ manual_saturating_arithmetic let _ = 1u8.saturating_add(1); + //~^ manual_saturating_arithmetic let _ = 1u128.saturating_add(1); let _ = 1u32.checked_add(1).unwrap_or(1234); // ok let _ = 1u8.checked_add(1).unwrap_or(0); // ok let _ = 1u32.saturating_mul(1); + //~^ manual_saturating_arithmetic let _ = 1u32.saturating_sub(1); + //~^ manual_saturating_arithmetic let _ = 1u32.saturating_sub(1); + //~^ manual_saturating_arithmetic let _ = 1u8.saturating_sub(1); + //~^ manual_saturating_arithmetic let _ = 1u32.checked_sub(1).unwrap_or(1234); // ok let _ = 1u8.checked_sub(1).unwrap_or(255); // ok let _ = 1i32.saturating_add(1); + //~^ manual_saturating_arithmetic let _ = 1i32.saturating_add(1); + //~^ manual_saturating_arithmetic let _ = 1i8.saturating_add(1); + //~^ manual_saturating_arithmetic let _ = 1i128.saturating_add(1); let _ = 1i32.saturating_add(-1); + //~^ manual_saturating_arithmetic let _ = 1i32.saturating_add(-1); + //~^ manual_saturating_arithmetic let _ = 1i8.saturating_add(-1); + //~^ manual_saturating_arithmetic let _ = 1i128.saturating_add(-1); let _ = 1i32.checked_add(1).unwrap_or(1234); // ok let _ = 1i8.checked_add(1).unwrap_or(-128); // ok let _ = 1i8.checked_add(-1).unwrap_or(127); // ok let _ = 1i32.saturating_sub(1); + //~^ manual_saturating_arithmetic let _ = 1i32.saturating_sub(1); + //~^ manual_saturating_arithmetic let _ = 1i8.saturating_sub(1); + //~^ manual_saturating_arithmetic let _ = 1i128.saturating_sub(1); let _ = 1i32.saturating_sub(-1); + //~^ manual_saturating_arithmetic let _ = 1i32.saturating_sub(-1); + //~^ manual_saturating_arithmetic let _ = 1i8.saturating_sub(-1); + //~^ manual_saturating_arithmetic let _ = 1i128.saturating_sub(-1); let _ = 1i32.checked_sub(1).unwrap_or(1234); // ok let _ = 1i8.checked_sub(1).unwrap_or(127); // ok diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs index 55f3720dfcc06..98246a5cd96ca 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs @@ -4,31 +4,47 @@ use std::{i32, i128, u32, u128}; fn main() { let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); + //~^ manual_saturating_arithmetic let _ = 1u32.checked_add(1).unwrap_or(u32::MAX); + //~^ manual_saturating_arithmetic let _ = 1u8.checked_add(1).unwrap_or(255); + //~^ manual_saturating_arithmetic let _ = 1u128 + //~^ manual_saturating_arithmetic .checked_add(1) .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455); let _ = 1u32.checked_add(1).unwrap_or(1234); // ok let _ = 1u8.checked_add(1).unwrap_or(0); // ok let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX); + //~^ manual_saturating_arithmetic let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value()); + //~^ manual_saturating_arithmetic let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN); + //~^ manual_saturating_arithmetic let _ = 1u8.checked_sub(1).unwrap_or(0); + //~^ manual_saturating_arithmetic let _ = 1u32.checked_sub(1).unwrap_or(1234); // ok let _ = 1u8.checked_sub(1).unwrap_or(255); // ok let _ = 1i32.checked_add(1).unwrap_or(i32::max_value()); + //~^ manual_saturating_arithmetic let _ = 1i32.checked_add(1).unwrap_or(i32::MAX); + //~^ manual_saturating_arithmetic let _ = 1i8.checked_add(1).unwrap_or(127); + //~^ manual_saturating_arithmetic let _ = 1i128 + //~^ manual_saturating_arithmetic .checked_add(1) .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value()); + //~^ manual_saturating_arithmetic let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN); + //~^ manual_saturating_arithmetic let _ = 1i8.checked_add(-1).unwrap_or(-128); + //~^ manual_saturating_arithmetic let _ = 1i128 + //~^ manual_saturating_arithmetic .checked_add(-1) .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); let _ = 1i32.checked_add(1).unwrap_or(1234); // ok @@ -36,15 +52,23 @@ fn main() { let _ = 1i8.checked_add(-1).unwrap_or(127); // ok let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value()); + //~^ manual_saturating_arithmetic let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN); + //~^ manual_saturating_arithmetic let _ = 1i8.checked_sub(1).unwrap_or(-128); + //~^ manual_saturating_arithmetic let _ = 1i128 + //~^ manual_saturating_arithmetic .checked_sub(1) .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value()); + //~^ manual_saturating_arithmetic let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX); + //~^ manual_saturating_arithmetic let _ = 1i8.checked_sub(-1).unwrap_or(127); + //~^ manual_saturating_arithmetic let _ = 1i128 + //~^ manual_saturating_arithmetic .checked_sub(-1) .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); let _ = 1i32.checked_sub(1).unwrap_or(1234); // ok diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr index b6a8df0f84e13..9d133d8a073b4 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.stderr @@ -8,154 +8,159 @@ LL | let _ = 1u32.checked_add(1).unwrap_or(u32::max_value()); = help: to override `-D warnings` add `#[allow(clippy::manual_saturating_arithmetic)]` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:7:13 + --> tests/ui/manual_saturating_arithmetic.rs:8:13 | LL | let _ = 1u32.checked_add(1).unwrap_or(u32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u32.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:8:13 + --> tests/ui/manual_saturating_arithmetic.rs:10:13 | LL | let _ = 1u8.checked_add(1).unwrap_or(255); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1u8.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:9:13 + --> tests/ui/manual_saturating_arithmetic.rs:12:13 | LL | let _ = 1u128 | _____________^ +LL | | LL | | .checked_add(1) LL | | .unwrap_or(340_282_366_920_938_463_463_374_607_431_768_211_455); | |_______________________________________________________________________^ help: consider using `saturating_add`: `1u128.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:14:13 + --> tests/ui/manual_saturating_arithmetic.rs:18:13 | LL | let _ = 1u32.checked_mul(1).unwrap_or(u32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_mul`: `1u32.saturating_mul(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:16:13 + --> tests/ui/manual_saturating_arithmetic.rs:21:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:17:13 + --> tests/ui/manual_saturating_arithmetic.rs:23:13 | LL | let _ = 1u32.checked_sub(1).unwrap_or(u32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:18:13 + --> tests/ui/manual_saturating_arithmetic.rs:25:13 | LL | let _ = 1u8.checked_sub(1).unwrap_or(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1u8.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:22:13 + --> tests/ui/manual_saturating_arithmetic.rs:30:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::max_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:23:13 + --> tests/ui/manual_saturating_arithmetic.rs:32:13 | LL | let _ = 1i32.checked_add(1).unwrap_or(i32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:24:13 + --> tests/ui/manual_saturating_arithmetic.rs:34:13 | LL | let _ = 1i8.checked_add(1).unwrap_or(127); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:25:13 + --> tests/ui/manual_saturating_arithmetic.rs:36:13 | LL | let _ = 1i128 | _____________^ +LL | | LL | | .checked_add(1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); | |_______________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:28:13 + --> tests/ui/manual_saturating_arithmetic.rs:40:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:29:13 + --> tests/ui/manual_saturating_arithmetic.rs:42:13 | LL | let _ = 1i32.checked_add(-1).unwrap_or(i32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i32.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:30:13 + --> tests/ui/manual_saturating_arithmetic.rs:44:13 | LL | let _ = 1i8.checked_add(-1).unwrap_or(-128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_add`: `1i8.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:31:13 + --> tests/ui/manual_saturating_arithmetic.rs:46:13 | LL | let _ = 1i128 | _____________^ +LL | | LL | | .checked_add(-1) LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); | |________________________________________________________________________^ help: consider using `saturating_add`: `1i128.saturating_add(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:38:13 + --> tests/ui/manual_saturating_arithmetic.rs:54:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::min_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:39:13 + --> tests/ui/manual_saturating_arithmetic.rs:56:13 | LL | let _ = 1i32.checked_sub(1).unwrap_or(i32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:40:13 + --> tests/ui/manual_saturating_arithmetic.rs:58:13 | LL | let _ = 1i8.checked_sub(1).unwrap_or(-128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:41:13 + --> tests/ui/manual_saturating_arithmetic.rs:60:13 | LL | let _ = 1i128 | _____________^ +LL | | LL | | .checked_sub(1) LL | | .unwrap_or(-170_141_183_460_469_231_731_687_303_715_884_105_728); | |________________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:44:13 + --> tests/ui/manual_saturating_arithmetic.rs:64:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::max_value()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:45:13 + --> tests/ui/manual_saturating_arithmetic.rs:66:13 | LL | let _ = 1i32.checked_sub(-1).unwrap_or(i32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i32.saturating_sub(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:46:13 + --> tests/ui/manual_saturating_arithmetic.rs:68:13 | LL | let _ = 1i8.checked_sub(-1).unwrap_or(127); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `saturating_sub`: `1i8.saturating_sub(-1)` error: manual saturating arithmetic - --> tests/ui/manual_saturating_arithmetic.rs:47:13 + --> tests/ui/manual_saturating_arithmetic.rs:70:13 | LL | let _ = 1i128 | _____________^ +LL | | LL | | .checked_sub(-1) LL | | .unwrap_or(170_141_183_460_469_231_731_687_303_715_884_105_727); | |_______________________________________________________________________^ help: consider using `saturating_sub`: `1i128.saturating_sub(-1)` diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.fixed b/src/tools/clippy/tests/ui/manual_slice_fill.fixed index 397a156a2dc77..bba863247f5d3 100644 --- a/src/tools/clippy/tests/ui/manual_slice_fill.fixed +++ b/src/tools/clippy/tests/ui/manual_slice_fill.fixed @@ -1,5 +1,5 @@ #![warn(clippy::manual_slice_fill)] -#![allow(clippy::needless_range_loop)] +#![allow(clippy::needless_range_loop, clippy::useless_vec)] macro_rules! assign_element { ($slice:ident, $index:expr) => { @@ -99,3 +99,27 @@ fn should_not_lint() { *i = None; } } + +fn issue_14192() { + let mut tmp = vec![0; 3]; + + for i in 0..tmp.len() { + tmp[i] = i; + } + + for i in 0..tmp.len() { + tmp[i] = 2 + i; + } + + for i in 0..tmp.len() { + tmp[0] = i; + } +} + +fn issue14189() { + // Should not lint because `!*b` is not constant + let mut tmp = vec![1, 2, 3]; + for b in &mut tmp { + *b = !*b; + } +} diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.rs b/src/tools/clippy/tests/ui/manual_slice_fill.rs index c25127ca613ab..44c60dc40f074 100644 --- a/src/tools/clippy/tests/ui/manual_slice_fill.rs +++ b/src/tools/clippy/tests/ui/manual_slice_fill.rs @@ -1,5 +1,5 @@ #![warn(clippy::manual_slice_fill)] -#![allow(clippy::needless_range_loop)] +#![allow(clippy::needless_range_loop, clippy::useless_vec)] macro_rules! assign_element { ($slice:ident, $index:expr) => { @@ -23,21 +23,25 @@ fn should_lint() { let mut some_slice = [1, 2, 3, 4, 5]; for i in 0..some_slice.len() { + //~^ manual_slice_fill some_slice[i] = 0; } let x = 5; for i in 0..some_slice.len() { + //~^ manual_slice_fill some_slice[i] = x; } for i in &mut some_slice { + //~^ manual_slice_fill *i = 0; } // This should trigger `manual_slice_fill`, but the applicability is `MaybeIncorrect` since comments // within the loop might be purely informational. for i in 0..some_slice.len() { + //~^ manual_slice_fill some_slice[i] = 0; // foo } @@ -108,3 +112,27 @@ fn should_not_lint() { *i = None; } } + +fn issue_14192() { + let mut tmp = vec![0; 3]; + + for i in 0..tmp.len() { + tmp[i] = i; + } + + for i in 0..tmp.len() { + tmp[i] = 2 + i; + } + + for i in 0..tmp.len() { + tmp[0] = i; + } +} + +fn issue14189() { + // Should not lint because `!*b` is not constant + let mut tmp = vec![1, 2, 3]; + for b in &mut tmp { + *b = !*b; + } +} diff --git a/src/tools/clippy/tests/ui/manual_slice_fill.stderr b/src/tools/clippy/tests/ui/manual_slice_fill.stderr index 3aa980f691916..38e43d5b4e06e 100644 --- a/src/tools/clippy/tests/ui/manual_slice_fill.stderr +++ b/src/tools/clippy/tests/ui/manual_slice_fill.stderr @@ -2,6 +2,7 @@ error: manually filling a slice --> tests/ui/manual_slice_fill.rs:25:5 | LL | / for i in 0..some_slice.len() { +LL | | LL | | some_slice[i] = 0; LL | | } | |_____^ help: try: `some_slice.fill(0);` @@ -10,25 +11,28 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::manual_slice_fill)]` error: manually filling a slice - --> tests/ui/manual_slice_fill.rs:30:5 + --> tests/ui/manual_slice_fill.rs:31:5 | LL | / for i in 0..some_slice.len() { +LL | | LL | | some_slice[i] = x; LL | | } | |_____^ help: try: `some_slice.fill(x);` error: manually filling a slice - --> tests/ui/manual_slice_fill.rs:34:5 + --> tests/ui/manual_slice_fill.rs:36:5 | LL | / for i in &mut some_slice { +LL | | LL | | *i = 0; LL | | } | |_____^ help: try: `some_slice.fill(0);` error: manually filling a slice - --> tests/ui/manual_slice_fill.rs:40:5 + --> tests/ui/manual_slice_fill.rs:43:5 | LL | / for i in 0..some_slice.len() { +LL | | LL | | some_slice[i] = 0; LL | | // foo LL | | } diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed index 0603b30e34653..294d1e1506dec 100644 --- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed +++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed @@ -15,18 +15,35 @@ fn main() { // True positives: let _ = std::mem::size_of_val(s_i32); // WARNING + // + //~^^ manual_slice_size_calculation let _ = std::mem::size_of_val(s_i32); // WARNING + // + //~^^ manual_slice_size_calculation let _ = std::mem::size_of_val(s_i32) * 5; // WARNING + // + //~^^ manual_slice_size_calculation let _ = std::mem::size_of_val(*s_i32_ref); // WARNING + // + //~^^ manual_slice_size_calculation let _ = std::mem::size_of_val(**s_i32_ref_ref); // WARNING + // + //~^^ manual_slice_size_calculation let len = s_i32.len(); let size = size_of::(); let _ = std::mem::size_of_val(s_i32); // WARNING + // + //~^^ manual_slice_size_calculation let _ = std::mem::size_of_val(s_i32); // WARNING + // + //~^^ manual_slice_size_calculation let _ = std::mem::size_of_val(s_i32); // WARNING + // + //~^^ manual_slice_size_calculation let _ = std::mem::size_of_val(external!(&[1u64][..])); + //~^ manual_slice_size_calculation // True negatives: let _ = size_of::() + s_i32.len(); // Ok, not a multiplication diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs index 14093e653c09d..ae5225663139b 100644 --- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs +++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs @@ -15,18 +15,35 @@ fn main() { // True positives: let _ = s_i32.len() * size_of::(); // WARNING + // + //~^^ manual_slice_size_calculation let _ = size_of::() * s_i32.len(); // WARNING + // + //~^^ manual_slice_size_calculation let _ = size_of::() * s_i32.len() * 5; // WARNING + // + //~^^ manual_slice_size_calculation let _ = size_of::() * s_i32_ref.len(); // WARNING + // + //~^^ manual_slice_size_calculation let _ = size_of::() * s_i32_ref_ref.len(); // WARNING + // + //~^^ manual_slice_size_calculation let len = s_i32.len(); let size = size_of::(); let _ = len * size_of::(); // WARNING + // + //~^^ manual_slice_size_calculation let _ = s_i32.len() * size; // WARNING + // + //~^^ manual_slice_size_calculation let _ = len * size; // WARNING + // + //~^^ manual_slice_size_calculation let _ = external!(&[1u64][..]).len() * size_of::(); + //~^ manual_slice_size_calculation // True negatives: let _ = size_of::() + s_i32.len(); // Ok, not a multiplication diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr index 0397f3a4969a8..f07e97a1c8638 100644 --- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr +++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr @@ -8,49 +8,49 @@ LL | let _ = s_i32.len() * size_of::(); // WARNING = help: to override `-D warnings` add `#[allow(clippy::manual_slice_size_calculation)]` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:18:13 + --> tests/ui/manual_slice_size_calculation.rs:20:13 | LL | let _ = size_of::() * s_i32.len(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:19:13 + --> tests/ui/manual_slice_size_calculation.rs:23:13 | LL | let _ = size_of::() * s_i32.len() * 5; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:20:13 + --> tests/ui/manual_slice_size_calculation.rs:26:13 | LL | let _ = size_of::() * s_i32_ref.len(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(*s_i32_ref)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:21:13 + --> tests/ui/manual_slice_size_calculation.rs:29:13 | LL | let _ = size_of::() * s_i32_ref_ref.len(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(**s_i32_ref_ref)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:25:13 + --> tests/ui/manual_slice_size_calculation.rs:35:13 | LL | let _ = len * size_of::(); // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:26:13 + --> tests/ui/manual_slice_size_calculation.rs:38:13 | LL | let _ = s_i32.len() * size; // WARNING | ^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:27:13 + --> tests/ui/manual_slice_size_calculation.rs:41:13 | LL | let _ = len * size; // WARNING | ^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> tests/ui/manual_slice_size_calculation.rs:29:13 + --> tests/ui/manual_slice_size_calculation.rs:45:13 | LL | let _ = external!(&[1u64][..]).len() * size_of::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` diff --git a/src/tools/clippy/tests/ui/manual_split_once.fixed b/src/tools/clippy/tests/ui/manual_split_once.fixed index aaac6a048e1d0..76dfb99b787d2 100644 --- a/src/tools/clippy/tests/ui/manual_split_once.fixed +++ b/src/tools/clippy/tests/ui/manual_split_once.fixed @@ -9,23 +9,33 @@ use itertools::Itertools; fn main() { let _ = "key=value".splitn(2, '=').nth(2); let _ = "key=value".split_once('=').unwrap().1; + //~^ manual_split_once let _ = "key=value".split_once('=').unwrap().1; + //~^ manual_split_once let (_, _) = "key=value".split_once('=').unwrap(); + //~^ manual_split_once let s = String::from("key=value"); let _ = s.split_once('=').unwrap().1; + //~^ manual_split_once let s = Box::::from("key=value"); let _ = s.split_once('=').unwrap().1; + //~^ manual_split_once let s = &"key=value"; let _ = s.split_once('=').unwrap().1; + //~^ manual_split_once fn _f(s: &str) -> Option<&str> { let _ = s.split_once('=')?.1; + //~^ manual_split_once let _ = s.split_once('=')?.1; + //~^ manual_split_once let _ = s.rsplit_once('=')?.0; + //~^ manual_split_once let _ = s.rsplit_once('=')?.0; + //~^ manual_split_once None } @@ -34,24 +44,31 @@ fn main() { // `rsplitn` gives the results in the reverse order of `rsplit_once` let _ = "key=value".rsplit_once('=').unwrap().0; + //~^ manual_split_once let (_, _) = "key=value".rsplit_once('=').map(|(x, y)| (y, x)).unwrap(); + //~^ manual_split_once let _ = s.rsplit_once('=').map(|x| x.0); + //~^ manual_split_once } fn indirect() -> Option<()> { let (l, r) = "a.b.c".split_once('.').unwrap(); + //~^ manual_split_once let (l, r) = "a.b.c".split_once('.')?; + //~^ manual_split_once let (l, r) = "a.b.c".rsplit_once('.').unwrap(); + //~^ manual_split_once let (l, r) = "a.b.c".rsplit_once('.')?; + //~^ manual_split_once @@ -137,8 +154,10 @@ fn _msrv_1_51() { #[clippy::msrv = "1.52"] fn _msrv_1_52() { let _ = "key=value".split_once('=').unwrap().1; + //~^ manual_split_once let (a, b) = "a.b.c".split_once('.').unwrap(); + //~^ manual_split_once } diff --git a/src/tools/clippy/tests/ui/manual_split_once.rs b/src/tools/clippy/tests/ui/manual_split_once.rs index 113e1737c97da..73602fae3d82f 100644 --- a/src/tools/clippy/tests/ui/manual_split_once.rs +++ b/src/tools/clippy/tests/ui/manual_split_once.rs @@ -9,23 +9,33 @@ use itertools::Itertools; fn main() { let _ = "key=value".splitn(2, '=').nth(2); let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + //~^ manual_split_once let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); + //~^ manual_split_once let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); + //~^ manual_split_once let s = String::from("key=value"); let _ = s.splitn(2, '=').nth(1).unwrap(); + //~^ manual_split_once let s = Box::::from("key=value"); let _ = s.splitn(2, '=').nth(1).unwrap(); + //~^ manual_split_once let s = &"key=value"; let _ = s.splitn(2, '=').skip(1).next().unwrap(); + //~^ manual_split_once fn _f(s: &str) -> Option<&str> { let _ = s.splitn(2, '=').nth(1)?; + //~^ manual_split_once let _ = s.splitn(2, '=').skip(1).next()?; + //~^ manual_split_once let _ = s.rsplitn(2, '=').nth(1)?; + //~^ manual_split_once let _ = s.rsplitn(2, '=').skip(1).next()?; + //~^ manual_split_once None } @@ -34,24 +44,31 @@ fn main() { // `rsplitn` gives the results in the reverse order of `rsplit_once` let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); + //~^ manual_split_once let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); + //~^ manual_split_once let _ = s.rsplitn(2, '=').nth(1); + //~^ manual_split_once } fn indirect() -> Option<()> { let mut iter = "a.b.c".splitn(2, '.'); + //~^ manual_split_once let l = iter.next().unwrap(); let r = iter.next().unwrap(); let mut iter = "a.b.c".splitn(2, '.'); + //~^ manual_split_once let l = iter.next()?; let r = iter.next()?; let mut iter = "a.b.c".rsplitn(2, '.'); + //~^ manual_split_once let r = iter.next().unwrap(); let l = iter.next().unwrap(); let mut iter = "a.b.c".rsplitn(2, '.'); + //~^ manual_split_once let r = iter.next()?; let l = iter.next()?; @@ -137,8 +154,10 @@ fn _msrv_1_51() { #[clippy::msrv = "1.52"] fn _msrv_1_52() { let _ = "key=value".splitn(2, '=').nth(1).unwrap(); + //~^ manual_split_once let mut iter = "a.b.c".splitn(2, '.'); + //~^ manual_split_once let a = iter.next().unwrap(); let b = iter.next().unwrap(); } diff --git a/src/tools/clippy/tests/ui/manual_split_once.stderr b/src/tools/clippy/tests/ui/manual_split_once.stderr index 366d860f25efd..2a44f6e7438c3 100644 --- a/src/tools/clippy/tests/ui/manual_split_once.stderr +++ b/src/tools/clippy/tests/ui/manual_split_once.stderr @@ -8,82 +8,83 @@ LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::manual_split_once)]` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:12:13 + --> tests/ui/manual_split_once.rs:13:13 | LL | let _ = "key=value".splitn(2, '=').skip(1).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:13:18 + --> tests/ui/manual_split_once.rs:15:18 | LL | let (_, _) = "key=value".splitn(2, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=')` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:16:13 + --> tests/ui/manual_split_once.rs:19:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:19:13 + --> tests/ui/manual_split_once.rs:23:13 | LL | let _ = s.splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:22:13 + --> tests/ui/manual_split_once.rs:27:13 | LL | let _ = s.splitn(2, '=').skip(1).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:25:17 + --> tests/ui/manual_split_once.rs:31:17 | LL | let _ = s.splitn(2, '=').nth(1)?; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:26:17 + --> tests/ui/manual_split_once.rs:33:17 | LL | let _ = s.splitn(2, '=').skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.split_once('=')?.1` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:27:17 + --> tests/ui/manual_split_once.rs:35:17 | LL | let _ = s.rsplitn(2, '=').nth(1)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:28:17 + --> tests/ui/manual_split_once.rs:37:17 | LL | let _ = s.rsplitn(2, '=').skip(1).next()?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=')?.0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:36:13 + --> tests/ui/manual_split_once.rs:46:13 | LL | let _ = "key=value".rsplitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').unwrap().0` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:37:18 + --> tests/ui/manual_split_once.rs:48:18 | LL | let (_, _) = "key=value".rsplitn(2, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".rsplit_once('=').map(|(x, y)| (y, x))` error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:38:13 + --> tests/ui/manual_split_once.rs:50:13 | LL | let _ = s.rsplitn(2, '=').nth(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.rsplit_once('=').map(|x| x.0)` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:42:5 + --> tests/ui/manual_split_once.rs:55:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | let l = iter.next().unwrap(); | ----------------------------- first usage here LL | let r = iter.next().unwrap(); @@ -92,15 +93,17 @@ LL | let r = iter.next().unwrap(); help: replace with `split_once` | LL ~ let (l, r) = "a.b.c".split_once('.').unwrap(); +LL | LL ~ LL ~ | error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:46:5 + --> tests/ui/manual_split_once.rs:60:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | let l = iter.next()?; | --------------------- first usage here LL | let r = iter.next()?; @@ -109,15 +112,17 @@ LL | let r = iter.next()?; help: replace with `split_once` | LL ~ let (l, r) = "a.b.c".split_once('.')?; +LL | LL ~ LL ~ | error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:50:5 + --> tests/ui/manual_split_once.rs:65:5 | LL | let mut iter = "a.b.c".rsplitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | let r = iter.next().unwrap(); | ----------------------------- first usage here LL | let l = iter.next().unwrap(); @@ -126,15 +131,17 @@ LL | let l = iter.next().unwrap(); help: replace with `rsplit_once` | LL ~ let (l, r) = "a.b.c".rsplit_once('.').unwrap(); +LL | LL ~ LL ~ | error: manual implementation of `rsplit_once` - --> tests/ui/manual_split_once.rs:54:5 + --> tests/ui/manual_split_once.rs:70:5 | LL | let mut iter = "a.b.c".rsplitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | let r = iter.next()?; | --------------------- first usage here LL | let l = iter.next()?; @@ -143,21 +150,23 @@ LL | let l = iter.next()?; help: replace with `rsplit_once` | LL ~ let (l, r) = "a.b.c".rsplit_once('.')?; +LL | LL ~ LL ~ | error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:139:13 + --> tests/ui/manual_split_once.rs:156:13 | LL | let _ = "key=value".splitn(2, '=').nth(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split_once('=').unwrap().1` error: manual implementation of `split_once` - --> tests/ui/manual_split_once.rs:141:5 + --> tests/ui/manual_split_once.rs:159:5 | LL | let mut iter = "a.b.c".splitn(2, '.'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | let a = iter.next().unwrap(); | ----------------------------- first usage here LL | let b = iter.next().unwrap(); @@ -166,6 +175,7 @@ LL | let b = iter.next().unwrap(); help: replace with `split_once` | LL ~ let (a, b) = "a.b.c".split_once('.').unwrap(); +LL | LL ~ LL ~ | diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed index da6f36f53b0d4..bbe4260f6bc81 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.fixed +++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed @@ -6,13 +6,18 @@ use std::iter::repeat; fn main() { let _: String = "test".repeat(10); + //~^ manual_str_repeat let _: String = "x".repeat(10); + //~^ manual_str_repeat let _: String = "'".repeat(10); + //~^ manual_str_repeat let _: String = "\"".repeat(10); + //~^ manual_str_repeat let x = "test"; let count = 10; let _ = x.repeat(count + 2); + //~^ manual_str_repeat macro_rules! m { ($e:expr) => {{ $e }}; @@ -22,6 +27,7 @@ fn main() { let x = &x; let _: String = (*x).repeat(count); + //~^ manual_str_repeat macro_rules! repeat_m { ($e:expr) => {{ repeat($e) }}; @@ -31,6 +37,7 @@ fn main() { let x: Box = Box::from("test"); let _: String = x.repeat(count); + //~^ manual_str_repeat #[derive(Clone)] struct S; @@ -43,9 +50,11 @@ fn main() { let _: String = repeat(Box::new(S)).take(count).collect(); let _: String = Cow::Borrowed("test").repeat(count); + //~^ manual_str_repeat let x = "x".to_owned(); let _: String = x.repeat(count); + //~^ manual_str_repeat let x = 'x'; // Don't lint, not char literal @@ -61,4 +70,5 @@ fn _msrv_1_15() { #[clippy::msrv = "1.16"] fn _msrv_1_16() { let _: String = "test".repeat(10); + //~^ manual_str_repeat } diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs index 686ed4fee7d1c..38d2eb4fcad8a 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.rs +++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs @@ -6,13 +6,18 @@ use std::iter::repeat; fn main() { let _: String = std::iter::repeat("test").take(10).collect(); + //~^ manual_str_repeat let _: String = std::iter::repeat('x').take(10).collect(); + //~^ manual_str_repeat let _: String = std::iter::repeat('\'').take(10).collect(); + //~^ manual_str_repeat let _: String = std::iter::repeat('"').take(10).collect(); + //~^ manual_str_repeat let x = "test"; let count = 10; let _ = repeat(x).take(count + 2).collect::(); + //~^ manual_str_repeat macro_rules! m { ($e:expr) => {{ $e }}; @@ -22,6 +27,7 @@ fn main() { let x = &x; let _: String = repeat(*x).take(count).collect(); + //~^ manual_str_repeat macro_rules! repeat_m { ($e:expr) => {{ repeat($e) }}; @@ -31,6 +37,7 @@ fn main() { let x: Box = Box::from("test"); let _: String = repeat(x).take(count).collect(); + //~^ manual_str_repeat #[derive(Clone)] struct S; @@ -43,9 +50,11 @@ fn main() { let _: String = repeat(Box::new(S)).take(count).collect(); let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); + //~^ manual_str_repeat let x = "x".to_owned(); let _: String = repeat(x).take(count).collect(); + //~^ manual_str_repeat let x = 'x'; // Don't lint, not char literal @@ -61,4 +70,5 @@ fn _msrv_1_15() { #[clippy::msrv = "1.16"] fn _msrv_1_16() { let _: String = std::iter::repeat("test").take(10).collect(); + //~^ manual_str_repeat } diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr index d4f8786fb5f10..7998c3f6d97c4 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.stderr +++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr @@ -8,55 +8,55 @@ LL | let _: String = std::iter::repeat("test").take(10).collect(); = help: to override `-D warnings` add `#[allow(clippy::manual_str_repeat)]` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:9:21 + --> tests/ui/manual_str_repeat.rs:10:21 | LL | let _: String = std::iter::repeat('x').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"x".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:10:21 + --> tests/ui/manual_str_repeat.rs:12:21 | LL | let _: String = std::iter::repeat('\'').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"'".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:11:21 + --> tests/ui/manual_str_repeat.rs:14:21 | LL | let _: String = std::iter::repeat('"').take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"\"".repeat(10)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:15:13 + --> tests/ui/manual_str_repeat.rs:19:13 | LL | let _ = repeat(x).take(count + 2).collect::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count + 2)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:24:21 + --> tests/ui/manual_str_repeat.rs:29:21 | LL | let _: String = repeat(*x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*x).repeat(count)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:33:21 + --> tests/ui/manual_str_repeat.rs:39:21 | LL | let _: String = repeat(x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:45:21 + --> tests/ui/manual_str_repeat.rs:52:21 | LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Cow::Borrowed("test").repeat(count)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:48:21 + --> tests/ui/manual_str_repeat.rs:56:21 | LL | let _: String = repeat(x).take(count).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `x.repeat(count)` error: manual implementation of `str::repeat` using iterators - --> tests/ui/manual_str_repeat.rs:63:21 + --> tests/ui/manual_str_repeat.rs:72:21 | LL | let _: String = std::iter::repeat("test").take(10).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"test".repeat(10)` diff --git a/src/tools/clippy/tests/ui/manual_string_new.fixed b/src/tools/clippy/tests/ui/manual_string_new.fixed index 2d4c5a0291532..02eeb603891a7 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.fixed +++ b/src/tools/clippy/tests/ui/manual_string_new.fixed @@ -12,12 +12,15 @@ macro_rules! create_strings_from_macro { fn main() { // Method calls let _ = String::new(); + //~^ manual_string_new let _ = "no warning".to_string(); let _ = String::new(); + //~^ manual_string_new let _ = "no warning".to_owned(); let _: String = String::new(); + //~^ manual_string_new let _: String = "no warning".into(); let _: SomeOtherStruct = "no warning".into(); @@ -25,26 +28,32 @@ fn main() { // Calls let _ = String::new(); + //~^ manual_string_new let _ = String::new(); + //~^ manual_string_new let _ = String::from("no warning"); let _ = SomeOtherStruct::from("no warning"); let _ = SomeOtherStruct::from(""); // Again: no warning. let _ = String::new(); + //~^ manual_string_new let _ = String::try_from("no warning").unwrap(); let _ = String::try_from("no warning").expect("this should not warn"); let _ = SomeOtherStruct::try_from("no warning").unwrap(); let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning. let _: String = String::new(); + //~^ manual_string_new let _: String = From::from("no warning"); let _: SomeOtherStruct = From::from("no warning"); let _: SomeOtherStruct = From::from(""); // Again: no warning. let _: String = String::new(); + //~^ manual_string_new let _: String = TryFrom::try_from("no warning").unwrap(); let _: String = TryFrom::try_from("no warning").expect("this should not warn"); let _: String = String::new(); + //~^ manual_string_new let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap(); let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning. diff --git a/src/tools/clippy/tests/ui/manual_string_new.rs b/src/tools/clippy/tests/ui/manual_string_new.rs index 20f0be6aaf97f..fb4f58abad263 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.rs +++ b/src/tools/clippy/tests/ui/manual_string_new.rs @@ -12,12 +12,15 @@ macro_rules! create_strings_from_macro { fn main() { // Method calls let _ = "".to_string(); + //~^ manual_string_new let _ = "no warning".to_string(); let _ = "".to_owned(); + //~^ manual_string_new let _ = "no warning".to_owned(); let _: String = "".into(); + //~^ manual_string_new let _: String = "no warning".into(); let _: SomeOtherStruct = "no warning".into(); @@ -25,26 +28,32 @@ fn main() { // Calls let _ = String::from(""); + //~^ manual_string_new let _ = ::from(""); + //~^ manual_string_new let _ = String::from("no warning"); let _ = SomeOtherStruct::from("no warning"); let _ = SomeOtherStruct::from(""); // Again: no warning. let _ = String::try_from("").unwrap(); + //~^ manual_string_new let _ = String::try_from("no warning").unwrap(); let _ = String::try_from("no warning").expect("this should not warn"); let _ = SomeOtherStruct::try_from("no warning").unwrap(); let _ = SomeOtherStruct::try_from("").unwrap(); // Again: no warning. let _: String = From::from(""); + //~^ manual_string_new let _: String = From::from("no warning"); let _: SomeOtherStruct = From::from("no warning"); let _: SomeOtherStruct = From::from(""); // Again: no warning. let _: String = TryFrom::try_from("").unwrap(); + //~^ manual_string_new let _: String = TryFrom::try_from("no warning").unwrap(); let _: String = TryFrom::try_from("no warning").expect("this should not warn"); let _: String = TryFrom::try_from("").expect("this should warn"); + //~^ manual_string_new let _: SomeOtherStruct = TryFrom::try_from("no_warning").unwrap(); let _: SomeOtherStruct = TryFrom::try_from("").unwrap(); // Again: no warning. diff --git a/src/tools/clippy/tests/ui/manual_string_new.stderr b/src/tools/clippy/tests/ui/manual_string_new.stderr index 6b434f405d31c..2d98501f62d47 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.stderr +++ b/src/tools/clippy/tests/ui/manual_string_new.stderr @@ -8,49 +8,49 @@ LL | let _ = "".to_string(); = help: to override `-D warnings` add `#[allow(clippy::manual_string_new)]` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:17:13 + --> tests/ui/manual_string_new.rs:18:13 | LL | let _ = "".to_owned(); | ^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:20:21 + --> tests/ui/manual_string_new.rs:22:21 | LL | let _: String = "".into(); | ^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:27:13 + --> tests/ui/manual_string_new.rs:30:13 | LL | let _ = String::from(""); | ^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:28:13 + --> tests/ui/manual_string_new.rs:32:13 | LL | let _ = ::from(""); | ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:33:13 + --> tests/ui/manual_string_new.rs:38:13 | LL | let _ = String::try_from("").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:39:21 + --> tests/ui/manual_string_new.rs:45:21 | LL | let _: String = From::from(""); | ^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:44:21 + --> tests/ui/manual_string_new.rs:51:21 | LL | let _: String = TryFrom::try_from("").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` error: empty String is being created manually - --> tests/ui/manual_string_new.rs:47:21 + --> tests/ui/manual_string_new.rs:55:21 | LL | let _: String = TryFrom::try_from("").expect("this should warn"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()` diff --git a/src/tools/clippy/tests/ui/manual_strip.rs b/src/tools/clippy/tests/ui/manual_strip.rs index 8bd0300e6bcce..086b75a398753 100644 --- a/src/tools/clippy/tests/ui/manual_strip.rs +++ b/src/tools/clippy/tests/ui/manual_strip.rs @@ -5,7 +5,8 @@ fn main() { if s.starts_with("ab") { str::to_string(&s["ab".len()..]); - //~^ ERROR: stripping a prefix manually + //~^ manual_strip + s["ab".len()..].to_string(); str::to_string(&s[2..]); @@ -14,7 +15,8 @@ fn main() { if s.ends_with("bc") { str::to_string(&s[..s.len() - "bc".len()]); - //~^ ERROR: stripping a suffix manually + //~^ manual_strip + s[..s.len() - "bc".len()].to_string(); str::to_string(&s[..s.len() - 2]); @@ -24,7 +26,8 @@ fn main() { // Character patterns if s.starts_with('a') { str::to_string(&s[1..]); - //~^ ERROR: stripping a prefix manually + //~^ manual_strip + s[1..].to_string(); } @@ -32,14 +35,15 @@ fn main() { let prefix = "ab"; if s.starts_with(prefix) { str::to_string(&s[prefix.len()..]); - //~^ ERROR: stripping a prefix manually + //~^ manual_strip } // Constant prefix const PREFIX: &str = "ab"; if s.starts_with(PREFIX) { str::to_string(&s[PREFIX.len()..]); - //~^ ERROR: stripping a prefix manually + //~^ manual_strip + str::to_string(&s[2..]); } @@ -47,14 +51,14 @@ fn main() { const TARGET: &str = "abc"; if TARGET.starts_with(prefix) { str::to_string(&TARGET[prefix.len()..]); - //~^ ERROR: stripping a prefix manually + //~^ manual_strip } // String target - not mutated. let s1: String = "abc".into(); if s1.starts_with("ab") { s1[2..].to_uppercase(); - //~^ ERROR: stripping a prefix manually + //~^ manual_strip } // String target - mutated. (Don't lint.) @@ -70,6 +74,23 @@ fn main() { if s3.starts_with("ab") { s4[2..].to_string(); } + + // Don't propose to reuse the `stripped` identifier as it is overriden + if s.starts_with("ab") { + let stripped = &s["ab".len()..]; + //~^ ERROR: stripping a prefix manually + let stripped = format!("{stripped}-"); + println!("{stripped}{}", &s["ab".len()..]); + } + + // Don't propose to reuse the `stripped` identifier as it is mutable + if s.starts_with("ab") { + let mut stripped = &s["ab".len()..]; + //~^ ERROR: stripping a prefix manually + stripped = ""; + let stripped = format!("{stripped}-"); + println!("{stripped}{}", &s["ab".len()..]); + } } #[clippy::msrv = "1.44"] @@ -85,6 +106,6 @@ fn msrv_1_45() { let s = "abc"; if s.starts_with('a') { s[1..].to_string(); - //~^ ERROR: stripping a prefix manually + //~^ manual_strip } } diff --git a/src/tools/clippy/tests/ui/manual_strip.stderr b/src/tools/clippy/tests/ui/manual_strip.stderr index a70c988a0549e..a323ef700e767 100644 --- a/src/tools/clippy/tests/ui/manual_strip.stderr +++ b/src/tools/clippy/tests/ui/manual_strip.stderr @@ -16,6 +16,7 @@ help: try using the `strip_prefix` method LL ~ if let Some() = s.strip_prefix("ab") { LL ~ str::to_string(); LL | +LL | LL ~ .to_string(); LL | LL ~ str::to_string(); @@ -23,13 +24,13 @@ LL ~ .to_string(); | error: stripping a suffix manually - --> tests/ui/manual_strip.rs:16:24 + --> tests/ui/manual_strip.rs:17:24 | LL | str::to_string(&s[..s.len() - "bc".len()]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: the suffix was tested here - --> tests/ui/manual_strip.rs:15:5 + --> tests/ui/manual_strip.rs:16:5 | LL | if s.ends_with("bc") { | ^^^^^^^^^^^^^^^^^^^^^ @@ -38,6 +39,7 @@ help: try using the `strip_suffix` method LL ~ if let Some() = s.strip_suffix("bc") { LL ~ str::to_string(); LL | +LL | LL ~ .to_string(); LL | LL ~ str::to_string(); @@ -45,13 +47,13 @@ LL ~ .to_string(); | error: stripping a prefix manually - --> tests/ui/manual_strip.rs:26:24 + --> tests/ui/manual_strip.rs:28:24 | LL | str::to_string(&s[1..]); | ^^^^^^^ | note: the prefix was tested here - --> tests/ui/manual_strip.rs:25:5 + --> tests/ui/manual_strip.rs:27:5 | LL | if s.starts_with('a') { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -60,17 +62,18 @@ help: try using the `strip_prefix` method LL ~ if let Some() = s.strip_prefix('a') { LL ~ str::to_string(); LL | +LL | LL ~ .to_string(); | error: stripping a prefix manually - --> tests/ui/manual_strip.rs:34:24 + --> tests/ui/manual_strip.rs:37:24 | LL | str::to_string(&s[prefix.len()..]); | ^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> tests/ui/manual_strip.rs:33:5 + --> tests/ui/manual_strip.rs:36:5 | LL | if s.starts_with(prefix) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,13 +84,13 @@ LL ~ str::to_string(); | error: stripping a prefix manually - --> tests/ui/manual_strip.rs:41:24 + --> tests/ui/manual_strip.rs:44:24 | LL | str::to_string(&s[PREFIX.len()..]); | ^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> tests/ui/manual_strip.rs:40:5 + --> tests/ui/manual_strip.rs:43:5 | LL | if s.starts_with(PREFIX) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,17 +99,18 @@ help: try using the `strip_prefix` method LL ~ if let Some() = s.strip_prefix(PREFIX) { LL ~ str::to_string(); LL | +LL | LL ~ str::to_string(); | error: stripping a prefix manually - --> tests/ui/manual_strip.rs:49:24 + --> tests/ui/manual_strip.rs:53:24 | LL | str::to_string(&TARGET[prefix.len()..]); | ^^^^^^^^^^^^^^^^^^^^^^^ | note: the prefix was tested here - --> tests/ui/manual_strip.rs:48:5 + --> tests/ui/manual_strip.rs:52:5 | LL | if TARGET.starts_with(prefix) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -117,13 +121,13 @@ LL ~ str::to_string(); | error: stripping a prefix manually - --> tests/ui/manual_strip.rs:56:9 + --> tests/ui/manual_strip.rs:60:9 | LL | s1[2..].to_uppercase(); | ^^^^^^^ | note: the prefix was tested here - --> tests/ui/manual_strip.rs:55:5 + --> tests/ui/manual_strip.rs:59:5 | LL | if s1.starts_with("ab") { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -134,13 +138,54 @@ LL ~ .to_uppercase(); | error: stripping a prefix manually - --> tests/ui/manual_strip.rs:87:9 + --> tests/ui/manual_strip.rs:80:24 + | +LL | let stripped = &s["ab".len()..]; + | ^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> tests/ui/manual_strip.rs:79:5 + | +LL | if s.starts_with("ab") { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL ~ if let Some() = s.strip_prefix("ab") { +LL ~ let stripped = ; +LL | +LL | let stripped = format!("{stripped}-"); +LL ~ println!("{stripped}{}", ); + | + +error: stripping a prefix manually + --> tests/ui/manual_strip.rs:88:28 + | +LL | let mut stripped = &s["ab".len()..]; + | ^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> tests/ui/manual_strip.rs:87:5 + | +LL | if s.starts_with("ab") { + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_prefix` method + | +LL ~ if let Some() = s.strip_prefix("ab") { +LL ~ let mut stripped = ; +LL | +LL | stripped = ""; +LL | let stripped = format!("{stripped}-"); +LL ~ println!("{stripped}{}", ); + | + +error: stripping a prefix manually + --> tests/ui/manual_strip.rs:108:9 | LL | s[1..].to_string(); | ^^^^^^ | note: the prefix was tested here - --> tests/ui/manual_strip.rs:86:5 + --> tests/ui/manual_strip.rs:107:5 | LL | if s.starts_with('a') { | ^^^^^^^^^^^^^^^^^^^^^^ @@ -150,5 +195,5 @@ LL ~ if let Some() = s.strip_prefix('a') { LL ~ .to_string(); | -error: aborting due to 8 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/manual_strip_fixable.fixed b/src/tools/clippy/tests/ui/manual_strip_fixable.fixed new file mode 100644 index 0000000000000..75a3f1645de33 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_strip_fixable.fixed @@ -0,0 +1,15 @@ +#![warn(clippy::manual_strip)] + +fn main() { + let s = "abc"; + + if let Some(stripped) = s.strip_prefix("ab") { + //~^ ERROR: stripping a prefix manually + println!("{stripped}{}", stripped); + } + + if let Some(stripped) = s.strip_suffix("bc") { + //~^ ERROR: stripping a suffix manually + println!("{stripped}{}", stripped); + } +} diff --git a/src/tools/clippy/tests/ui/manual_strip_fixable.rs b/src/tools/clippy/tests/ui/manual_strip_fixable.rs new file mode 100644 index 0000000000000..5080068449e20 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_strip_fixable.rs @@ -0,0 +1,17 @@ +#![warn(clippy::manual_strip)] + +fn main() { + let s = "abc"; + + if s.starts_with("ab") { + let stripped = &s["ab".len()..]; + //~^ ERROR: stripping a prefix manually + println!("{stripped}{}", &s["ab".len()..]); + } + + if s.ends_with("bc") { + let stripped = &s[..s.len() - "bc".len()]; + //~^ ERROR: stripping a suffix manually + println!("{stripped}{}", &s[..s.len() - "bc".len()]); + } +} diff --git a/src/tools/clippy/tests/ui/manual_strip_fixable.stderr b/src/tools/clippy/tests/ui/manual_strip_fixable.stderr new file mode 100644 index 0000000000000..1c276e5d8fdfe --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_strip_fixable.stderr @@ -0,0 +1,40 @@ +error: stripping a prefix manually + --> tests/ui/manual_strip_fixable.rs:7:24 + | +LL | let stripped = &s["ab".len()..]; + | ^^^^^^^^^^^^^^^^ + | +note: the prefix was tested here + --> tests/ui/manual_strip_fixable.rs:6:5 + | +LL | if s.starts_with("ab") { + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `-D clippy::manual-strip` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::manual_strip)]` +help: try using the `strip_prefix` method + | +LL ~ if let Some(stripped) = s.strip_prefix("ab") { +LL ~ +LL ~ println!("{stripped}{}", stripped); + | + +error: stripping a suffix manually + --> tests/ui/manual_strip_fixable.rs:13:24 + | +LL | let stripped = &s[..s.len() - "bc".len()]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: the suffix was tested here + --> tests/ui/manual_strip_fixable.rs:12:5 + | +LL | if s.ends_with("bc") { + | ^^^^^^^^^^^^^^^^^^^^^ +help: try using the `strip_suffix` method + | +LL ~ if let Some(stripped) = s.strip_suffix("bc") { +LL ~ +LL ~ println!("{stripped}{}", stripped); + | + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs index 702a9e67d3d59..c9880e651cd7c 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs @@ -4,7 +4,8 @@ fn swap1() { let mut v = [3, 2, 1, 0]; let index = v[0]; - //~^ ERROR: this looks like you are swapping elements of `v` manually + //~^ manual_swap + v[0] = v[index]; v[index] = index; } @@ -12,6 +13,7 @@ fn swap1() { fn swap2() { let mut v = [3, 2, 1, 0]; let tmp = v[0]; + //~^ manual_swap v[0] = v[1]; v[1] = tmp; // check not found in this scope. @@ -23,6 +25,7 @@ fn swap3() { let i1 = 0; let i2 = 1; let temp = v[i1]; + //~^ manual_swap v[i1] = v[i2]; v[i2] = temp; } @@ -32,6 +35,7 @@ fn swap4() { let i1 = 0; let i2 = 1; let temp = v[i1]; + //~^ manual_swap v[i1] = v[i2 + 1]; v[i2 + 1] = temp; } @@ -41,6 +45,7 @@ fn swap5() { let i1 = 0; let i2 = 1; let temp = v[i1]; + //~^ manual_swap v[i1] = v[i2 + 1]; v[i2 + 1] = temp; } @@ -48,7 +53,8 @@ fn swap5() { fn swap6() { let mut v = [0, 1, 2, 3]; let index = v[0]; - //~^ ERROR: this looks like you are swapping elements of `v` manually + //~^ manual_swap + v[0] = v[index + 1]; v[index + 1] = index; } @@ -58,6 +64,7 @@ fn swap7() { let i1 = 0; let i2 = 6; let tmp = v[i1 * 3]; + //~^ manual_swap v[i1 * 3] = v[i2 / 2]; v[i2 / 2] = tmp; } @@ -67,6 +74,7 @@ fn swap8() { let i1 = 1; let i2 = 1; let tmp = v[i1 + i2]; + //~^ manual_swap 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 index eecfcd3977beb..7ab898fcc7267 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr @@ -3,6 +3,7 @@ error: this looks like you are swapping elements of `v` manually | LL | / let index = v[0]; LL | | +LL | | LL | | v[0] = v[index]; LL | | v[index] = index; | |_____________________^ @@ -16,9 +17,10 @@ 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 + --> tests/ui/manual_swap_auto_fix.rs:15:5 | LL | / let tmp = v[0]; +LL | | LL | | v[0] = v[1]; LL | | v[1] = tmp; | |_______________^ @@ -30,34 +32,38 @@ 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 + --> tests/ui/manual_swap_auto_fix.rs:27:5 | LL | / let temp = v[i1]; +LL | | 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 + --> tests/ui/manual_swap_auto_fix.rs:37:5 | LL | / let temp = v[i1]; +LL | | 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 + --> tests/ui/manual_swap_auto_fix.rs:47:5 | LL | / let temp = v[i1]; +LL | | 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 + --> tests/ui/manual_swap_auto_fix.rs:55:5 | LL | / let index = v[0]; LL | | +LL | | LL | | v[0] = v[index + 1]; LL | | v[index + 1] = index; | |_________________________^ @@ -69,17 +75,19 @@ 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 + --> tests/ui/manual_swap_auto_fix.rs:66:5 | LL | / let tmp = v[i1 * 3]; +LL | | 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 + --> tests/ui/manual_swap_auto_fix.rs:76:5 | LL | / let tmp = v[i1 + i2]; +LL | | LL | | v[i1 + i2] = v[i2]; LL | | v[i2] = tmp; | |________________^ help: try: `v.swap(i1 + i2, i2);` diff --git a/src/tools/clippy/tests/ui/manual_try_fold.rs b/src/tools/clippy/tests/ui/manual_try_fold.rs index 7299d7cf98629..c91ea41bb84c5 100644 --- a/src/tools/clippy/tests/ui/manual_try_fold.rs +++ b/src/tools/clippy/tests/ui/manual_try_fold.rs @@ -57,13 +57,16 @@ fn main() { [1, 2, 3] .iter() .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + //~^ manual_try_fold .unwrap(); [1, 2, 3] .iter() .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); + //~^ manual_try_fold [1, 2, 3] .iter() .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); + //~^ manual_try_fold // Do not lint [1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i)).unwrap(); [1, 2, 3].iter().fold(0i32, |sum, i| sum + i); @@ -94,6 +97,7 @@ fn msrv_juust_right() { [1, 2, 3] .iter() .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) + //~^ manual_try_fold .unwrap(); } diff --git a/src/tools/clippy/tests/ui/manual_try_fold.stderr b/src/tools/clippy/tests/ui/manual_try_fold.stderr index bc075e87d71f5..f2740187878fe 100644 --- a/src/tools/clippy/tests/ui/manual_try_fold.stderr +++ b/src/tools/clippy/tests/ui/manual_try_fold.stderr @@ -8,19 +8,19 @@ LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) = help: to override `-D warnings` add `#[allow(clippy::manual_try_fold)]` error: usage of `Iterator::fold` on a type that implements `Try` - --> tests/ui/manual_try_fold.rs:63:10 + --> tests/ui/manual_try_fold.rs:64:10 | LL | .fold(NotOption(0i32, 0i32), |sum, i| NotOption(0i32, 0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(..., |sum, i| ...)` error: usage of `Iterator::fold` on a type that implements `Try` - --> tests/ui/manual_try_fold.rs:66:10 + --> tests/ui/manual_try_fold.rs:68:10 | LL | .fold(NotOptionButWorse(0i32), |sum, i| NotOptionButWorse(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` error: usage of `Iterator::fold` on a type that implements `Try` - --> tests/ui/manual_try_fold.rs:96:10 + --> tests/ui/manual_try_fold.rs:99:10 | LL | .fold(Some(0i32), |sum, i| sum?.checked_add(*i)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `try_fold` instead: `try_fold(0i32, |sum, i| ...)` diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs index cdbe51a41212c..c88b6f95da68e 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs @@ -9,18 +9,21 @@ fn option_unwrap_or() { // int case match Some(1) { + //~^ manual_unwrap_or Some(i) => i, None => 42, }; // int case reversed match Some(1) { + //~^ manual_unwrap_or None => 42, Some(i) => i, }; // richer none expr match Some(1) { + //~^ manual_unwrap_or Some(i) => i, None => 1 + 42, }; @@ -28,6 +31,7 @@ fn option_unwrap_or() { // multiline case #[rustfmt::skip] match Some(1) { + //~^ manual_unwrap_or Some(i) => i, None => { 42 + 42 @@ -38,6 +42,7 @@ fn option_unwrap_or() { // string case match Some("Bob") { + //~^ manual_unwrap_or Some(i) => i, None => "Alice", }; @@ -85,6 +90,7 @@ fn option_unwrap_or() { }; if let Some(x) = Some(1) { + //~^ manual_unwrap_or x } else { 42 @@ -118,6 +124,7 @@ fn option_unwrap_or() { fn result_unwrap_or() { // int case match Ok::(1) { + //~^ manual_unwrap_or Ok(i) => i, Err(_) => 42, }; @@ -125,12 +132,14 @@ fn result_unwrap_or() { // int case, scrutinee is a binding let a = Ok::(1); match a { + //~^ manual_unwrap_or Ok(i) => i, Err(_) => 42, }; // int case, suggestion must surround Result expr with parentheses match Ok(1) as Result { + //~^ manual_unwrap_or Ok(i) => i, Err(_) => 42, }; @@ -144,18 +153,21 @@ fn result_unwrap_or() { } let s = S {}; match s.method() { + //~^ manual_unwrap_or Some(i) => i, None => 42, }; // int case reversed match Ok::(1) { + //~^ manual_unwrap_or Err(_) => 42, Ok(i) => i, }; // richer none expr match Ok::(1) { + //~^ manual_unwrap_or Ok(i) => i, Err(_) => 1 + 42, }; @@ -163,6 +175,7 @@ fn result_unwrap_or() { // multiline case #[rustfmt::skip] match Ok::(1) { + //~^ manual_unwrap_or Ok(i) => i, Err(_) => { 42 + 42 @@ -173,6 +186,7 @@ fn result_unwrap_or() { // string case match Ok::<&str, &str>("Bob") { + //~^ manual_unwrap_or Ok(i) => i, Err(_) => "Alice", }; @@ -209,6 +223,7 @@ fn result_unwrap_or() { }; if let Ok(x) = Ok::(1) { + //~^ manual_unwrap_or x } else { 42 @@ -263,6 +278,7 @@ mod issue6965 { fn test() { let _ = match some_macro!() { + //~^ manual_unwrap_or Some(val) => val, None => 0, }; diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr index a5a64ecb9a3e0..a5deb55786e96 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr @@ -2,6 +2,7 @@ error: this pattern reimplements `Option::unwrap_or` --> tests/ui/manual_unwrap_or.rs:11:5 | LL | / match Some(1) { +LL | | LL | | Some(i) => i, LL | | None => 42, LL | | }; @@ -11,30 +12,32 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or)]` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:17:5 + --> tests/ui/manual_unwrap_or.rs:18:5 | LL | / match Some(1) { +LL | | LL | | None => 42, LL | | Some(i) => i, LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:23:5 + --> tests/ui/manual_unwrap_or.rs:25:5 | LL | / match Some(1) { +LL | | LL | | Some(i) => i, LL | | None => 1 + 42, LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(1 + 42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:30:5 + --> tests/ui/manual_unwrap_or.rs:33:5 | LL | / match Some(1) { +LL | | LL | | Some(i) => i, LL | | None => { -LL | | 42 + 42 ... | LL | | }; | |_____^ @@ -49,18 +52,20 @@ LL ~ }); | error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:40:5 + --> tests/ui/manual_unwrap_or.rs:44:5 | LL | / match Some("Bob") { +LL | | LL | | Some(i) => i, LL | | None => "Alice", LL | | }; | |_____^ help: replace with: `Some("Bob").unwrap_or("Alice")` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:87:5 + --> tests/ui/manual_unwrap_or.rs:92:5 | LL | / if let Some(x) = Some(1) { +LL | | LL | | x LL | | } else { LL | | 42 @@ -68,66 +73,72 @@ LL | | }; | |_____^ help: replace with: `Some(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:120:5 + --> tests/ui/manual_unwrap_or.rs:126:5 | LL | / match Ok::(1) { +LL | | LL | | Ok(i) => i, LL | | Err(_) => 42, LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:127:5 + --> tests/ui/manual_unwrap_or.rs:134:5 | LL | / match a { +LL | | LL | | Ok(i) => i, LL | | Err(_) => 42, LL | | }; | |_____^ help: replace with: `a.unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:133:5 + --> tests/ui/manual_unwrap_or.rs:141:5 | LL | / match Ok(1) as Result { +LL | | LL | | Ok(i) => i, LL | | Err(_) => 42, LL | | }; | |_____^ help: replace with: `(Ok(1) as Result).unwrap_or(42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:146:5 + --> tests/ui/manual_unwrap_or.rs:155:5 | LL | / match s.method() { +LL | | LL | | Some(i) => i, LL | | None => 42, LL | | }; | |_____^ help: replace with: `s.method().unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:152:5 + --> tests/ui/manual_unwrap_or.rs:162:5 | LL | / match Ok::(1) { +LL | | LL | | Err(_) => 42, LL | | Ok(i) => i, LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:158:5 + --> tests/ui/manual_unwrap_or.rs:169:5 | LL | / match Ok::(1) { +LL | | LL | | Ok(i) => i, LL | | Err(_) => 1 + 42, LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(1 + 42)` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:165:5 + --> tests/ui/manual_unwrap_or.rs:177:5 | LL | / match Ok::(1) { +LL | | LL | | Ok(i) => i, LL | | Err(_) => { -LL | | 42 + 42 ... | LL | | }; | |_____^ @@ -142,18 +153,20 @@ LL ~ }); | error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:175:5 + --> tests/ui/manual_unwrap_or.rs:188:5 | LL | / match Ok::<&str, &str>("Bob") { +LL | | LL | | Ok(i) => i, LL | | Err(_) => "Alice", LL | | }; | |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")` error: this pattern reimplements `Result::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:211:5 + --> tests/ui/manual_unwrap_or.rs:225:5 | LL | / if let Ok(x) = Ok::(1) { +LL | | LL | | x LL | | } else { LL | | 42 @@ -161,10 +174,11 @@ LL | | }; | |_____^ help: replace with: `Ok::(1).unwrap_or(42)` error: this pattern reimplements `Option::unwrap_or` - --> tests/ui/manual_unwrap_or.rs:265:17 + --> tests/ui/manual_unwrap_or.rs:280:17 | LL | let _ = match some_macro!() { | _________________^ +LL | | LL | | Some(val) => val, LL | | None => 0, LL | | }; 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 649f65c89fb0a..bedb3f0af0f3e 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs @@ -4,35 +4,36 @@ fn main() { let x: Option> = None; match x { - //~^ ERROR: match can be simplified with `.unwrap_or_default()` + //~^ manual_unwrap_or_default Some(v) => v, None => Vec::default(), }; let x: Option> = None; match x { - //~^ ERROR: match can be simplified with `.unwrap_or_default()` + //~^ manual_unwrap_or_default Some(v) => v, _ => Vec::default(), }; let x: Option = None; match x { - //~^ ERROR: match can be simplified with `.unwrap_or_default()` + //~^ manual_unwrap_or_default Some(v) => v, None => String::new(), }; let x: Option> = None; match x { - //~^ ERROR: match can be simplified with `.unwrap_or_default()` + //~^ manual_unwrap_or_default None => Vec::default(), Some(v) => v, }; let x: Option> = None; if let Some(v) = x { - //~^ ERROR: if let can be simplified with `.unwrap_or_default()` + //~^ manual_unwrap_or_default + v } else { Vec::default() @@ -50,14 +51,15 @@ fn main() { let x: Result = Ok(String::new()); match x { - //~^ ERROR: match can be simplified with `.unwrap_or_default()` + //~^ manual_unwrap_or_default Ok(v) => v, Err(_) => String::new(), }; let x: Result = Ok(String::new()); if let Ok(v) = x { - //~^ ERROR: if let can be simplified with `.unwrap_or_default()` + //~^ manual_unwrap_or_default + v } else { String::new() @@ -69,6 +71,7 @@ unsafe fn no_deref_ptr(a: Option, b: *const Option) -> i32 { match a { // `*b` being correct depends on `a == Some(_)` Some(_) => match *b { + //~^ manual_unwrap_or_default Some(v) => v, _ => 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 9e3b1be5cb9be..ca9aa159152e3 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr @@ -46,6 +46,7 @@ error: if let can be simplified with `.unwrap_or_default()` | LL | / if let Some(v) = x { LL | | +LL | | LL | | v LL | | } else { LL | | Vec::default() @@ -53,7 +54,7 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:52:5 + --> tests/ui/manual_unwrap_or_default.rs:53:5 | LL | / match x { LL | | @@ -63,10 +64,11 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: if let can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:59:5 + --> tests/ui/manual_unwrap_or_default.rs:60:5 | LL | / if let Ok(v) = x { LL | | +LL | | LL | | v LL | | } else { LL | | String::new() @@ -74,10 +76,11 @@ LL | | }; | |_____^ help: replace it with: `x.unwrap_or_default()` error: match can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default.rs:71:20 + --> tests/ui/manual_unwrap_or_default.rs:73:20 | LL | Some(_) => match *b { | ____________________^ +LL | | LL | | Some(v) => v, LL | | _ => 0, LL | | }, diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs index acc54b52816cc..c48a4d5ee5152 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.rs @@ -3,13 +3,17 @@ fn issue_12670() { // no auto: type not found #[allow(clippy::match_result_ok)] let _ = if let Some(x) = "1".parse().ok() { + //~^ manual_unwrap_or_default x } else { i32::default() }; let _ = if let Some(x) = None { x } else { i32::default() }; + //~^ manual_unwrap_or_default // auto fix with unwrap_or_default let a: Option = None; let _ = if let Some(x) = a { x } else { i32::default() }; + //~^ manual_unwrap_or_default let _ = if let Some(x) = Some(99) { x } else { i32::default() }; + //~^ manual_unwrap_or_default } diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr index 3849d33cf254b..94a7c2f5d2c35 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr +++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default_unfixable.stderr @@ -3,6 +3,7 @@ error: if let can be simplified with `.unwrap_or_default()` | LL | let _ = if let Some(x) = "1".parse().ok() { | _____________^ +LL | | LL | | x LL | | } else { LL | | i32::default() @@ -13,19 +14,19 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::manual_unwrap_or_default)]` error: if let can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default_unfixable.rs:10:13 + --> tests/ui/manual_unwrap_or_default_unfixable.rs:11:13 | LL | let _ = if let Some(x) = None { x } else { i32::default() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `None::.unwrap_or_default()` error: if let can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default_unfixable.rs:13:13 + --> tests/ui/manual_unwrap_or_default_unfixable.rs:15:13 | LL | let _ = if let Some(x) = a { x } else { i32::default() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `a.unwrap_or_default()` error: if let can be simplified with `.unwrap_or_default()` - --> tests/ui/manual_unwrap_or_default_unfixable.rs:14:13 + --> tests/ui/manual_unwrap_or_default_unfixable.rs:17:13 | LL | let _ = if let Some(x) = Some(99) { x } else { i32::default() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(99).unwrap_or_default()` diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.fixed b/src/tools/clippy/tests/ui/manual_while_let_some.fixed index c70d258dfe6e1..c0f6522d5fb87 100644 --- a/src/tools/clippy/tests/ui/manual_while_let_some.fixed +++ b/src/tools/clippy/tests/ui/manual_while_let_some.fixed @@ -19,6 +19,7 @@ fn main() { let mut numbers = vec![1, 2, 3, 4, 5]; while let Some(number) = numbers.pop() { + //~^ manual_while_let_some } let mut val = VecInStruct { @@ -27,14 +28,17 @@ fn main() { }; while let Some(number) = val.numbers.pop() { + //~^ manual_while_let_some } while let Some(element) = numbers.pop() { accept_i32(element); + //~^ manual_while_let_some } while let Some(element) = numbers.pop() { accept_i32(element); + //~^ manual_while_let_some } // This should not warn. It "conditionally" pops elements. @@ -78,14 +82,17 @@ fn main() { let mut numbers = vec![(0, 0), (1, 1), (2, 2)]; while let Some((a, b)) = numbers.pop() { + //~^ manual_while_let_some } while let Some(element) = numbers.pop() { accept_i32_tuple(element); + //~^ manual_while_let_some } let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }]; while let Some(Foo { a, b }) = results.pop() { + //~^ manual_while_let_some } } diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.rs b/src/tools/clippy/tests/ui/manual_while_let_some.rs index 415bb57986673..f69eb66af1d74 100644 --- a/src/tools/clippy/tests/ui/manual_while_let_some.rs +++ b/src/tools/clippy/tests/ui/manual_while_let_some.rs @@ -19,6 +19,7 @@ fn main() { let mut numbers = vec![1, 2, 3, 4, 5]; while !numbers.is_empty() { let number = numbers.pop().unwrap(); + //~^ manual_while_let_some } let mut val = VecInStruct { @@ -27,14 +28,17 @@ fn main() { }; while !val.numbers.is_empty() { let number = val.numbers.pop().unwrap(); + //~^ manual_while_let_some } while !numbers.is_empty() { accept_i32(numbers.pop().unwrap()); + //~^ manual_while_let_some } while !numbers.is_empty() { accept_i32(numbers.pop().expect("")); + //~^ manual_while_let_some } // This should not warn. It "conditionally" pops elements. @@ -78,14 +82,17 @@ fn main() { let mut numbers = vec![(0, 0), (1, 1), (2, 2)]; while !numbers.is_empty() { let (a, b) = numbers.pop().unwrap(); + //~^ manual_while_let_some } while !numbers.is_empty() { accept_i32_tuple(numbers.pop().unwrap()); + //~^ manual_while_let_some } let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }]; while !results.is_empty() { let Foo { a, b } = results.pop().unwrap(); + //~^ manual_while_let_some } } diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.stderr b/src/tools/clippy/tests/ui/manual_while_let_some.stderr index 8d444b80aaffa..5f2fecb7a0b97 100644 --- a/src/tools/clippy/tests/ui/manual_while_let_some.stderr +++ b/src/tools/clippy/tests/ui/manual_while_let_some.stderr @@ -13,7 +13,7 @@ LL ~ | error: you seem to be trying to pop elements from a `Vec` in a loop - --> tests/ui/manual_while_let_some.rs:29:9 + --> tests/ui/manual_while_let_some.rs:30:9 | LL | let number = val.numbers.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL ~ | error: you seem to be trying to pop elements from a `Vec` in a loop - --> tests/ui/manual_while_let_some.rs:33:20 + --> tests/ui/manual_while_let_some.rs:35:20 | LL | accept_i32(numbers.pop().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL ~ accept_i32(element); | error: you seem to be trying to pop elements from a `Vec` in a loop - --> tests/ui/manual_while_let_some.rs:37:20 + --> tests/ui/manual_while_let_some.rs:40:20 | LL | accept_i32(numbers.pop().expect("")); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL ~ accept_i32(element); | error: you seem to be trying to pop elements from a `Vec` in a loop - --> tests/ui/manual_while_let_some.rs:80:9 + --> tests/ui/manual_while_let_some.rs:84:9 | LL | let (a, b) = numbers.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL ~ | error: you seem to be trying to pop elements from a `Vec` in a loop - --> tests/ui/manual_while_let_some.rs:84:26 + --> tests/ui/manual_while_let_some.rs:89:26 | LL | accept_i32_tuple(numbers.pop().unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL ~ accept_i32_tuple(element); | error: you seem to be trying to pop elements from a `Vec` in a loop - --> tests/ui/manual_while_let_some.rs:89:9 + --> tests/ui/manual_while_let_some.rs:95:9 | LL | let Foo { a, b } = results.pop().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/many_single_char_names.rs b/src/tools/clippy/tests/ui/many_single_char_names.rs index 68578340d90e1..b601092248554 100644 --- a/src/tools/clippy/tests/ui/many_single_char_names.rs +++ b/src/tools/clippy/tests/ui/many_single_char_names.rs @@ -3,10 +3,10 @@ fn bla() { let a: i32; - //~^ ERROR: 5 bindings with single-character names in scope - //~| NOTE: `-D clippy::many-single-char-names` implied by `-D warnings` - //~| ERROR: 6 bindings with single-character names in scope - //~| ERROR: 5 bindings with single-character names in scope + //~^ many_single_char_names + //~| many_single_char_names + //~| many_single_char_names + let (b, c, d): (i32, i64, i16); { { @@ -32,11 +32,11 @@ fn bla() { } fn bindings(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {} -//~^ ERROR: 8 bindings with single-character names in scope +//~^ many_single_char_names fn bindings2() { let (a, b, c, d, e, f, g, h): (bool, bool, bool, bool, bool, bool, bool, bool) = unimplemented!(); - //~^ ERROR: 8 bindings with single-character names in scope + //~^ many_single_char_names } fn shadowing() { diff --git a/src/tools/clippy/tests/ui/map_all_any_identity.fixed b/src/tools/clippy/tests/ui/map_all_any_identity.fixed index c92462ab9c278..35543d239752f 100644 --- a/src/tools/clippy/tests/ui/map_all_any_identity.fixed +++ b/src/tools/clippy/tests/ui/map_all_any_identity.fixed @@ -3,6 +3,7 @@ fn main() { let _ = ["foo"].into_iter().any(|s| s == "foo"); //~^ map_all_any_identity + let _ = ["foo"].into_iter().all(|s| s == "foo"); //~^ map_all_any_identity diff --git a/src/tools/clippy/tests/ui/map_all_any_identity.rs b/src/tools/clippy/tests/ui/map_all_any_identity.rs index 0e4a564ca0467..704eb821aaaa1 100644 --- a/src/tools/clippy/tests/ui/map_all_any_identity.rs +++ b/src/tools/clippy/tests/ui/map_all_any_identity.rs @@ -3,6 +3,7 @@ fn main() { let _ = ["foo"].into_iter().map(|s| s == "foo").any(|a| a); //~^ map_all_any_identity + let _ = ["foo"].into_iter().map(|s| s == "foo").all(std::convert::identity); //~^ map_all_any_identity diff --git a/src/tools/clippy/tests/ui/map_all_any_identity.stderr b/src/tools/clippy/tests/ui/map_all_any_identity.stderr index 39df2a3d9616b..24df97d883acc 100644 --- a/src/tools/clippy/tests/ui/map_all_any_identity.stderr +++ b/src/tools/clippy/tests/ui/map_all_any_identity.stderr @@ -13,7 +13,7 @@ LL + let _ = ["foo"].into_iter().any(|s| s == "foo"); | error: usage of `.map(...).all(identity)` - --> tests/ui/map_all_any_identity.rs:6:33 + --> tests/ui/map_all_any_identity.rs:7:33 | LL | let _ = ["foo"].into_iter().map(|s| s == "foo").all(std::convert::identity); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed index f9f8dc1a51232..8db4b21be684b 100644 --- a/src/tools/clippy/tests/ui/map_clone.fixed +++ b/src/tools/clippy/tests/ui/map_clone.fixed @@ -12,11 +12,16 @@ fn main() { let _: Vec = vec![5_i8; 6].iter().copied().collect(); + //~^ map_clone let _: Vec = vec![String::new()].iter().cloned().collect(); + //~^ map_clone let _: Vec = vec![42, 43].iter().copied().collect(); + //~^ map_clone let _: Option = Some(Box::new(16)).map(|b| *b); let _: Option = Some(&16).copied(); + //~^ map_clone let _: Option = Some(&1).copied(); + //~^ map_clone // Don't lint these let v = vec![5_i8; 6]; @@ -28,6 +33,7 @@ fn main() { // Issue #498 let _ = std::env::args(); + //~^ map_clone // Issue #4824 item types that aren't references { @@ -67,22 +73,21 @@ fn main() { let x = Some(String::new()); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.cloned(); - //~^ ERROR: you are explicitly cloning with `.map()` + //~^ map_clone + let y = x.cloned(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone + let y = x.cloned(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone let x: Option = Some(0); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.copied(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone + let y = x.copied(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone // Should not suggest `copied` or `cloned` here since `T` is not a reference. let x: Option = Some(0); @@ -93,20 +98,18 @@ fn main() { let x: Result = Ok(String::new()); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.cloned(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone + let y = x.cloned(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone let x: Result = Ok(0); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.copied(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone + let y = x.copied(); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone // Should not suggest `copied` or `cloned` here since `T` is not a reference. let x: Result = Ok(0); diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs index a5c19ce063191..a726e35616345 100644 --- a/src/tools/clippy/tests/ui/map_clone.rs +++ b/src/tools/clippy/tests/ui/map_clone.rs @@ -12,11 +12,16 @@ fn main() { let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); + //~^ map_clone let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); + //~^ map_clone let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); + //~^ map_clone let _: Option = Some(Box::new(16)).map(|b| *b); let _: Option = Some(&16).map(|b| *b); + //~^ map_clone let _: Option = Some(&1).map(|x| x.clone()); + //~^ map_clone // Don't lint these let v = vec![5_i8; 6]; @@ -28,6 +33,7 @@ fn main() { // Issue #498 let _ = std::env::args().map(|v| v.clone()); + //~^ map_clone // Issue #4824 item types that aren't references { @@ -67,22 +73,21 @@ fn main() { let x = Some(String::new()); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.map(|x| String::clone(x)); - //~^ ERROR: you are explicitly cloning with `.map()` + //~^ map_clone + let y = x.map(Clone::clone); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone + let y = x.map(String::clone); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone let x: Option = Some(0); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.map(|x| u32::clone(x)); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone + let y = x.map(|x| Clone::clone(x)); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone // Should not suggest `copied` or `cloned` here since `T` is not a reference. let x: Option = Some(0); @@ -93,20 +98,18 @@ fn main() { let x: Result = Ok(String::new()); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.map(|x| String::clone(x)); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone + let y = x.map(|x| Clone::clone(x)); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `cloned` method + //~^ map_clone let x: Result = Ok(0); let x = x.as_ref(); // We do this to prevent triggering the `useless_asref` lint. let y = x.map(|x| u32::clone(x)); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone + let y = x.map(|x| Clone::clone(x)); - //~^ ERROR: you are explicitly cloning with `.map()` - //~| HELP: consider calling the dedicated `copied` method + //~^ map_clone // Should not suggest `copied` or `cloned` here since `T` is not a reference. let x: Result = Ok(0); diff --git a/src/tools/clippy/tests/ui/map_clone.stderr b/src/tools/clippy/tests/ui/map_clone.stderr index d9e025de4abe9..8bf54e4e8aee1 100644 --- a/src/tools/clippy/tests/ui/map_clone.stderr +++ b/src/tools/clippy/tests/ui/map_clone.stderr @@ -8,85 +8,85 @@ LL | let _: Vec = vec![5_i8; 6].iter().map(|x| *x).collect(); = help: to override `-D warnings` add `#[allow(clippy::map_clone)]` error: you are using an explicit closure for cloning elements - --> tests/ui/map_clone.rs:15:26 + --> tests/ui/map_clone.rs:16:26 | LL | let _: Vec = vec![String::new()].iter().map(|x| x.clone()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `vec![String::new()].iter().cloned()` error: you are using an explicit closure for copying elements - --> tests/ui/map_clone.rs:16:23 + --> tests/ui/map_clone.rs:18:23 | LL | let _: Vec = vec![42, 43].iter().map(|&x| x).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `vec![42, 43].iter().copied()` error: you are using an explicit closure for copying elements - --> tests/ui/map_clone.rs:18:26 + --> tests/ui/map_clone.rs:21:26 | LL | let _: Option = Some(&16).map(|b| *b); | ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&16).copied()` error: you are using an explicit closure for copying elements - --> tests/ui/map_clone.rs:19:25 + --> tests/ui/map_clone.rs:23:25 | LL | let _: Option = Some(&1).map(|x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `Some(&1).copied()` error: you are needlessly cloning iterator elements - --> tests/ui/map_clone.rs:30:29 + --> tests/ui/map_clone.rs:35:29 | LL | let _ = std::env::args().map(|v| v.clone()); | ^^^^^^^^^^^^^^^^^^^ help: remove the `map` call error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:69:13 + --> tests/ui/map_clone.rs:75:13 | LL | let y = x.map(|x| String::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:71:13 + --> tests/ui/map_clone.rs:78:13 | LL | let y = x.map(Clone::clone); | ^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:74:13 + --> tests/ui/map_clone.rs:81:13 | LL | let y = x.map(String::clone); | ^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:80:13 + --> tests/ui/map_clone.rs:86:13 | LL | let y = x.map(|x| u32::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:83:13 + --> tests/ui/map_clone.rs:89:13 | LL | let y = x.map(|x| Clone::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:95:13 + --> tests/ui/map_clone.rs:100:13 | LL | let y = x.map(|x| String::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:98:13 + --> tests/ui/map_clone.rs:103:13 | LL | let y = x.map(|x| Clone::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `x.cloned()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:104:13 + --> tests/ui/map_clone.rs:108:13 | LL | let y = x.map(|x| u32::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` error: you are explicitly cloning with `.map()` - --> tests/ui/map_clone.rs:107:13 + --> tests/ui/map_clone.rs:111:13 | LL | let y = x.map(|x| Clone::clone(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `copied` method: `x.copied()` diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.fixed b/src/tools/clippy/tests/ui/map_collect_result_unit.fixed index 374af105f889d..26957e59f14ae 100644 --- a/src/tools/clippy/tests/ui/map_collect_result_unit.fixed +++ b/src/tools/clippy/tests/ui/map_collect_result_unit.fixed @@ -3,7 +3,9 @@ fn main() { { let _ = (0..3).try_for_each(|t| Err(t + 1)); + //~^ map_collect_result_unit let _: Result<(), _> = (0..3).try_for_each(|t| Err(t + 1)); + //~^ map_collect_result_unit let _ = (0..3).try_for_each(|t| Err(t + 1)); } diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.rs b/src/tools/clippy/tests/ui/map_collect_result_unit.rs index 5c6fb23e2372b..cdd73bfe65446 100644 --- a/src/tools/clippy/tests/ui/map_collect_result_unit.rs +++ b/src/tools/clippy/tests/ui/map_collect_result_unit.rs @@ -3,7 +3,9 @@ fn main() { { let _ = (0..3).map(|t| Err(t + 1)).collect::>(); + //~^ map_collect_result_unit let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); + //~^ map_collect_result_unit let _ = (0..3).try_for_each(|t| Err(t + 1)); } diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.stderr b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr index 8d147340e16aa..93293be855bb0 100644 --- a/src/tools/clippy/tests/ui/map_collect_result_unit.stderr +++ b/src/tools/clippy/tests/ui/map_collect_result_unit.stderr @@ -8,7 +8,7 @@ LL | let _ = (0..3).map(|t| Err(t + 1)).collect::>(); = help: to override `-D warnings` add `#[allow(clippy::map_collect_result_unit)]` error: `.map().collect()` can be replaced with `.try_for_each()` - --> tests/ui/map_collect_result_unit.rs:6:32 + --> tests/ui/map_collect_result_unit.rs:7:32 | LL | let _: Result<(), _> = (0..3).map(|t| Err(t + 1)).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(0..3).try_for_each(|t| Err(t + 1))` diff --git a/src/tools/clippy/tests/ui/map_err.rs b/src/tools/clippy/tests/ui/map_err.rs index 07c51784407a6..0f0c8f6c71cf8 100644 --- a/src/tools/clippy/tests/ui/map_err.rs +++ b/src/tools/clippy/tests/ui/map_err.rs @@ -20,7 +20,7 @@ fn main() -> Result<(), Errors> { let x = u32::try_from(-123_i32); println!("{:?}", x.map_err(|_| Errors::Ignored)); - //~^ ERROR: `map_err(|_|...` wildcard pattern discards the original error + //~^ map_err_ignore // Should not warn you because you explicitly ignore the parameter // using a named wildcard value diff --git a/src/tools/clippy/tests/ui/map_flatten.rs b/src/tools/clippy/tests/ui/map_flatten.rs index eafc8b6e81cab..d7e9c9d9900d9 100644 --- a/src/tools/clippy/tests/ui/map_flatten.rs +++ b/src/tools/clippy/tests/ui/map_flatten.rs @@ -6,8 +6,9 @@ fn long_span() { let _: Option = Some(1) .map(|x| { - //~^ ERROR: called `map(..).flatten()` on `Option` - //~| NOTE: `-D clippy::map-flatten` implied by `-D warnings` + //~^ map_flatten + + if x <= 5 { Some(x) } else { @@ -18,7 +19,8 @@ fn long_span() { let _: Result = Ok(1) .map(|x| { - //~^ ERROR: called `map(..).flatten()` on `Result` + //~^ map_flatten + if x == 1 { Ok(x) } else { @@ -31,7 +33,8 @@ fn long_span() { fn do_something() { } let _: Result = result .map(|res| { - //~^ ERROR: called `map(..).flatten()` on `Result` + //~^ map_flatten + if res > 0 { do_something(); Ok(res) @@ -44,7 +47,8 @@ fn long_span() { let _: Vec<_> = vec![5_i8; 6] .into_iter() .map(|some_value| { - //~^ ERROR: called `map(..).flatten()` on `Iterator` + //~^ map_flatten + if some_value > 3 { Some(some_value) } else { @@ -62,7 +66,7 @@ fn no_suggestion_if_comments_present() { .iter() // a lovely comment explaining the code in very detail .map(|x| x.iter()) - //~^ ERROR: called `map(..).flatten()` on `Iterator` + //~^ map_flatten // the answer to life, the universe and everything could be here .flatten(); } diff --git a/src/tools/clippy/tests/ui/map_flatten.stderr b/src/tools/clippy/tests/ui/map_flatten.stderr index 34bd174d7dde9..704267fea3cf5 100644 --- a/src/tools/clippy/tests/ui/map_flatten.stderr +++ b/src/tools/clippy/tests/ui/map_flatten.stderr @@ -3,9 +3,6 @@ error: called `map(..).flatten()` on `Option` | LL | .map(|x| { | __________^ -LL | | -LL | | -LL | | if x <= 5 { ... | LL | | }) LL | | .flatten(); @@ -17,7 +14,8 @@ help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|x| { LL + -LL + +LL + +LL + LL + if x <= 5 { LL + Some(x) LL + } else { @@ -27,13 +25,13 @@ LL ~ }); | error: called `map(..).flatten()` on `Result` - --> tests/ui/map_flatten.rs:20:10 + --> tests/ui/map_flatten.rs:21:10 | LL | .map(|x| { | __________^ LL | | +LL | | LL | | if x == 1 { -LL | | Ok(x) ... | LL | | }) LL | | .flatten(); @@ -43,6 +41,7 @@ help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|x| { LL + +LL + LL + if x == 1 { LL + Ok(x) LL + } else { @@ -52,13 +51,13 @@ LL ~ }); | error: called `map(..).flatten()` on `Result` - --> tests/ui/map_flatten.rs:33:10 + --> tests/ui/map_flatten.rs:35:10 | LL | .map(|res| { | __________^ LL | | +LL | | LL | | if res > 0 { -LL | | do_something(); ... | LL | | }) LL | | .flatten(); @@ -68,6 +67,7 @@ help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|res| { LL + +LL + LL + if res > 0 { LL + do_something(); LL + Ok(res) @@ -78,13 +78,13 @@ LL ~ }); | error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten.rs:46:10 + --> tests/ui/map_flatten.rs:49:10 | LL | .map(|some_value| { | __________^ LL | | +LL | | LL | | if some_value > 3 { -LL | | Some(some_value) ... | LL | | }) LL | | .flatten() @@ -94,6 +94,7 @@ help: try replacing `map` with `filter_map` and remove the `.flatten()` | LL ~ .filter_map(|some_value| { LL + +LL + LL + if some_value > 3 { LL + Some(some_value) LL + } else { @@ -103,7 +104,7 @@ LL + }) | error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten.rs:64:10 + --> tests/ui/map_flatten.rs:68:10 | LL | .map(|x| x.iter()) | __________^ diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed index 1932f412d2ca0..948fec970d869 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed @@ -14,18 +14,25 @@ fn main() { let option_id_ref: fn(i8) -> Option = option_id; let option_id_closure = |x| Some(x); let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id).collect(); + //~^ map_flatten let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_ref).collect(); + //~^ map_flatten let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(option_id_closure).collect(); + //~^ map_flatten let _: Vec<_> = vec![5_i8; 6].into_iter().filter_map(|x| x.checked_add(1)).collect(); + //~^ map_flatten // mapping to Iterator on Iterator let _: Vec<_> = vec![5_i8; 6].into_iter().flat_map(|x| 0..x).collect(); + //~^ map_flatten // mapping to Option on Option let _: Option<_> = (Some(Some(1))).and_then(|x| x); + //~^ map_flatten // mapping to Result on Result let _: Result<_, &str> = (Ok(Ok(1))).and_then(|x| x); + //~^ map_flatten issue8734(); issue8878(); @@ -35,6 +42,7 @@ fn issue8734() { let _ = [0u8, 1, 2, 3] .into_iter() .flat_map(|n| match n { + //~^ map_flatten 1 => [n .saturating_add(1) .saturating_add(1) @@ -54,6 +62,7 @@ fn issue8878() { std::collections::HashMap::::new() .get(&0) .and_then(|_| { + //~^ map_flatten // we need some newlines // so that the span is big enough // for a split output of the diagnostic diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs index 093fd9b6cae29..67a91ab94147e 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs @@ -14,18 +14,25 @@ fn main() { let option_id_ref: fn(i8) -> Option = option_id; let option_id_closure = |x| Some(x); let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect(); + //~^ map_flatten let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); + //~^ map_flatten let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); + //~^ map_flatten let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); + //~^ map_flatten // mapping to Iterator on Iterator let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); + //~^ map_flatten // mapping to Option on Option let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); + //~^ map_flatten // mapping to Result on Result let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); + //~^ map_flatten issue8734(); issue8878(); @@ -35,6 +42,7 @@ fn issue8734() { let _ = [0u8, 1, 2, 3] .into_iter() .map(|n| match n { + //~^ map_flatten 1 => [n .saturating_add(1) .saturating_add(1) @@ -55,6 +63,7 @@ fn issue8878() { std::collections::HashMap::::new() .get(&0) .map(|_| { + //~^ map_flatten // we need some newlines // so that the span is big enough // for a split output of the diagnostic diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr index 095bee52d6d71..05d4d9a6ad85c 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr @@ -8,49 +8,49 @@ LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().coll = help: to override `-D warnings` add `#[allow(clippy::map_flatten)]` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:17:47 + --> tests/ui/map_flatten_fixable.rs:18:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:18:47 + --> tests/ui/map_flatten_fixable.rs:20:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:19:47 + --> tests/ui/map_flatten_fixable.rs:22:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:22:47 + --> tests/ui/map_flatten_fixable.rs:26:47 | LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)` error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:25:40 + --> tests/ui/map_flatten_fixable.rs:30:40 | LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Result` - --> tests/ui/map_flatten_fixable.rs:28:42 + --> tests/ui/map_flatten_fixable.rs:34:42 | LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten(); | ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)` error: called `map(..).flatten()` on `Iterator` - --> tests/ui/map_flatten_fixable.rs:37:10 + --> tests/ui/map_flatten_fixable.rs:44:10 | LL | .map(|n| match n { | __________^ +LL | | LL | | 1 => [n LL | | .saturating_add(1) -LL | | .saturating_add(1) ... | LL | | }) LL | | .flatten(); @@ -59,6 +59,7 @@ LL | | .flatten(); help: try replacing `map` with `flat_map` and remove the `.flatten()` | LL ~ .flat_map(|n| match n { +LL + LL + 1 => [n LL + .saturating_add(1) LL + .saturating_add(1) @@ -73,7 +74,7 @@ LL ~ }); | error: called `map(..).flatten()` on `Option` - --> tests/ui/map_flatten_fixable.rs:57:10 + --> tests/ui/map_flatten_fixable.rs:65:10 | LL | .map(|_| { | __________^ @@ -85,6 +86,7 @@ LL | | .flatten(); help: try replacing `map` with `and_then` and remove the `.flatten()` | LL ~ .and_then(|_| { +LL + LL + // we need some newlines LL + // so that the span is big enough LL + // for a split output of the diagnostic diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed index 3257ddc6f72b3..83b2dac5fc517 100644 --- a/src/tools/clippy/tests/ui/map_identity.fixed +++ b/src/tools/clippy/tests/ui/map_identity.fixed @@ -5,8 +5,12 @@ fn main() { let x: [u16; 3] = [1, 2, 3]; // should lint let _: Vec<_> = x.iter().map(not_identity).collect(); + //~^ map_identity let _: Vec<_> = x.iter().collect(); + //~^ map_identity + //~| map_identity let _: Option = Some(3); + //~^ map_identity let _: Result = Ok(-3); // should not lint let _: Vec<_> = x.iter().map(|x| 2 * x).collect(); @@ -16,6 +20,7 @@ fn main() { return x + 3; }); let _: Result = Ok(1); + //~^ map_identity let _: Result = Ok(1).map_err(|a: u32| a * 42); // : u32 guides type inference let _ = Ok(1).map_err(|a: u32| a); @@ -26,11 +31,14 @@ fn issue7189() { // should lint let x = [(1, 2), (3, 4)].iter().copied(); let _ = x.clone(); + //~^ map_identity let _ = x.clone(); let _ = x.clone(); + //~^ map_identity let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied(); let _ = y.clone(); + //~^ map_identity // should not lint let _ = x.clone().map(|(x, y)| (x, y, y)); @@ -60,6 +68,7 @@ fn issue11764() { // no match ergonomics for `(i32, i32)` let _ = x.iter().copied(); + //~^ map_identity } fn issue13904() { @@ -71,8 +80,10 @@ fn issue13904() { #[allow(unused_mut)] let mut it = [1, 2, 3].into_iter(); let _ = it.next(); + //~^ map_identity // lint let it = [1, 2, 3].into_iter(); let _ = { it }.next(); + //~^ map_identity } diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs index be3bb9a4f1068..e839c551364be 100644 --- a/src/tools/clippy/tests/ui/map_identity.rs +++ b/src/tools/clippy/tests/ui/map_identity.rs @@ -5,9 +5,14 @@ fn main() { let x: [u16; 3] = [1, 2, 3]; // should lint let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); + //~^ map_identity let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); + //~^ map_identity + //~| map_identity let _: Option = Some(3).map(|x| x); + //~^ map_identity let _: Result = Ok(-3).map(|x| { + //~^ map_identity return x; }); // should not lint @@ -18,6 +23,7 @@ fn main() { return x + 3; }); let _: Result = Ok(1).map_err(|a| a); + //~^ map_identity let _: Result = Ok(1).map_err(|a: u32| a * 42); // : u32 guides type inference let _ = Ok(1).map_err(|a: u32| a); @@ -28,13 +34,17 @@ fn issue7189() { // should lint let x = [(1, 2), (3, 4)].iter().copied(); let _ = x.clone().map(|(x, y)| (x, y)); + //~^ map_identity let _ = x.clone().map(|(x, y)| { + //~^ map_identity return (x, y); }); let _ = x.clone().map(|(x, y)| return (x, y)); + //~^ map_identity let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))].iter().copied(); let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,)))); + //~^ map_identity // should not lint let _ = x.clone().map(|(x, y)| (x, y, y)); @@ -64,6 +74,7 @@ fn issue11764() { // no match ergonomics for `(i32, i32)` let _ = x.iter().copied().map(|(x, y)| (x, y)); + //~^ map_identity } fn issue13904() { @@ -75,8 +86,10 @@ fn issue13904() { #[allow(unused_mut)] let mut it = [1, 2, 3].into_iter(); let _ = it.map(|x| x).next(); + //~^ map_identity // lint let it = [1, 2, 3].into_iter(); let _ = { it }.map(|x| x).next(); + //~^ map_identity } diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr index aa3fc4ae0b5c4..9836f3b4cc5f8 100644 --- a/src/tools/clippy/tests/ui/map_identity.stderr +++ b/src/tools/clippy/tests/ui/map_identity.stderr @@ -8,79 +8,81 @@ LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect(); = help: to override `-D warnings` add `#[allow(clippy::map_identity)]` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:8:57 + --> tests/ui/map_identity.rs:9:57 | LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); | ^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:8:29 + --> tests/ui/map_identity.rs:9:29 | LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:9:32 + --> tests/ui/map_identity.rs:12:32 | LL | let _: Option = Some(3).map(|x| x); | ^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:10:36 + --> tests/ui/map_identity.rs:14:36 | LL | let _: Result = Ok(-3).map(|x| { | ____________________________________^ +LL | | LL | | return x; LL | | }); | |______^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:20:36 + --> tests/ui/map_identity.rs:25:36 | LL | let _: Result = Ok(1).map_err(|a| a); | ^^^^^^^^^^^^^^^ help: remove the call to `map_err` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:30:22 + --> tests/ui/map_identity.rs:36:22 | LL | let _ = x.clone().map(|(x, y)| (x, y)); | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:31:22 + --> tests/ui/map_identity.rs:38:22 | LL | let _ = x.clone().map(|(x, y)| { | ______________________^ +LL | | LL | | return (x, y); LL | | }); | |______^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:34:22 + --> tests/ui/map_identity.rs:42:22 | LL | let _ = x.clone().map(|(x, y)| return (x, y)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:37:22 + --> tests/ui/map_identity.rs:46:22 | LL | let _ = y.clone().map(|(x, y, (z, (w,)))| (x, y, (z, (w,)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:66:30 + --> tests/ui/map_identity.rs:76:30 | LL | let _ = x.iter().copied().map(|(x, y)| (x, y)); | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:77:15 + --> tests/ui/map_identity.rs:88:15 | LL | let _ = it.map(|x| x).next(); | ^^^^^^^^^^^ help: remove the call to `map` error: unnecessary map of the identity function - --> tests/ui/map_identity.rs:81:19 + --> tests/ui/map_identity.rs:93:19 | LL | let _ = { it }.map(|x| x).next(); | ^^^^^^^^^^^ help: remove the call to `map` diff --git a/src/tools/clippy/tests/ui/map_unit_fn.rs b/src/tools/clippy/tests/ui/map_unit_fn.rs index e7f07b50f3ab1..3a810196a44db 100644 --- a/src/tools/clippy/tests/ui/map_unit_fn.rs +++ b/src/tools/clippy/tests/ui/map_unit_fn.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![allow(unused)] struct Mappable; diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.rs b/src/tools/clippy/tests/ui/map_unwrap_or.rs index dfaa8f24f987f..fba81cb493cde 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/map_unwrap_or.rs @@ -15,25 +15,31 @@ fn option_methods() { // Check for `option.map(_).unwrap_or(_)` use. // Single line case. let _ = opt.map(|x| x + 1) + //~^ map_unwrap_or // Should lint even though this call is on a separate line. .unwrap_or(0); // Multi-line cases. let _ = opt.map(|x| { + //~^ map_unwrap_or x + 1 } ).unwrap_or(0); let _ = opt.map(|x| x + 1) + //~^ map_unwrap_or .unwrap_or({ 0 }); // Single line `map(f).unwrap_or(None)` case. let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); + //~^ map_unwrap_or // Multi-line `map(f).unwrap_or(None)` cases. let _ = opt.map(|x| { + //~^ map_unwrap_or Some(x + 1) } ).unwrap_or(None); let _ = opt + //~^ map_unwrap_or .map(|x| Some(x + 1)) .unwrap_or(None); // macro case @@ -45,20 +51,24 @@ fn option_methods() { // ...but DO lint if the `unwrap_or` argument is not used in the `map` let id: String = "identifier".to_string(); let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); + //~^ map_unwrap_or // Check for `option.map(_).unwrap_or_else(_)` use. // Multi-line cases. let _ = opt.map(|x| { + //~^ map_unwrap_or x + 1 } ).unwrap_or_else(|| 0); let _ = opt.map(|x| x + 1) + //~^ map_unwrap_or .unwrap_or_else(|| 0 ); // Check for `map(f).unwrap_or(false)` use. let _ = opt.map(|x| x > 5).unwrap_or(false); + //~^ map_unwrap_or } @@ -69,10 +79,12 @@ fn result_methods() { // Check for `result.map(_).unwrap_or_else(_)` use. // multi line cases let _ = res.map(|x| { + //~^ map_unwrap_or x + 1 } ).unwrap_or_else(|_e| 0); let _ = res.map(|x| x + 1) + //~^ map_unwrap_or .unwrap_or_else(|_e| { 0 }); @@ -97,6 +109,7 @@ fn msrv_1_41() { let res: Result = Ok(1); let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); + //~^ map_unwrap_or } #[clippy::msrv = "1.69"] @@ -104,6 +117,7 @@ fn msrv_1_69() { let opt: Option = Some(1); let _ = opt.map(|x| x > 5).unwrap_or(false); + //~^ map_unwrap_or } #[clippy::msrv = "1.70"] @@ -111,6 +125,7 @@ fn msrv_1_70() { let opt: Option = Some(1); let _ = opt.map(|x| x > 5).unwrap_or(false); + //~^ map_unwrap_or } mod issue_10579 { diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.stderr b/src/tools/clippy/tests/ui/map_unwrap_or.stderr index d6ddd09c188c6..0b6c9b7fcf192 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or.stderr @@ -3,7 +3,7 @@ error: called `map().unwrap_or()` on an `Option` value | LL | let _ = opt.map(|x| x + 1) | _____________^ -LL | | // Should lint even though this call is on a separate line. +... | LL | | .unwrap_or(0); | |_____________________^ | @@ -16,10 +16,11 @@ LL + let _ = opt.map_or(0, |x| x + 1); | error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:21:13 + --> tests/ui/map_unwrap_or.rs:22:13 | LL | let _ = opt.map(|x| { | _____________^ +LL | | LL | | x + 1 LL | | } LL | | ).unwrap_or(0); @@ -28,16 +29,18 @@ LL | | ).unwrap_or(0); help: use `map_or(, )` instead | LL ~ let _ = opt.map_or(0, |x| { +LL | LL | x + 1 LL | } LL ~ ); | error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:25:13 + --> tests/ui/map_unwrap_or.rs:27:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ +LL | | LL | | .unwrap_or({ LL | | 0 LL | | }); @@ -51,7 +54,7 @@ LL ~ }, |x| x + 1); | error: called `map().unwrap_or(None)` on an `Option` value - --> tests/ui/map_unwrap_or.rs:30:13 + --> tests/ui/map_unwrap_or.rs:33:13 | LL | let _ = opt.map(|x| Some(x + 1)).unwrap_or(None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -63,10 +66,11 @@ LL + let _ = opt.and_then(|x| Some(x + 1)); | error: called `map().unwrap_or(None)` on an `Option` value - --> tests/ui/map_unwrap_or.rs:32:13 + --> tests/ui/map_unwrap_or.rs:36:13 | LL | let _ = opt.map(|x| { | _____________^ +LL | | LL | | Some(x + 1) LL | | } LL | | ).unwrap_or(None); @@ -75,16 +79,18 @@ LL | | ).unwrap_or(None); help: use `and_then()` instead | LL ~ let _ = opt.and_then(|x| { +LL | LL | Some(x + 1) LL | } LL ~ ); | error: called `map().unwrap_or(None)` on an `Option` value - --> tests/ui/map_unwrap_or.rs:36:13 + --> tests/ui/map_unwrap_or.rs:41:13 | LL | let _ = opt | _____________^ +LL | | LL | | .map(|x| Some(x + 1)) LL | | .unwrap_or(None); | |________________________^ @@ -96,7 +102,7 @@ LL + .and_then(|x| Some(x + 1)); | error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:47:13 + --> tests/ui/map_unwrap_or.rs:53:13 | LL | let _ = Some("prefix").map(|p| format!("{}.", p)).unwrap_or(id); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,27 +114,29 @@ LL + let _ = Some("prefix").map_or(id, |p| format!("{}.", p)); | error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:51:13 + --> tests/ui/map_unwrap_or.rs:58:13 | LL | let _ = opt.map(|x| { | _____________^ +LL | | LL | | x + 1 LL | | } LL | | ).unwrap_or_else(|| 0); | |__________________________^ error: called `map().unwrap_or_else()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:55:13 + --> tests/ui/map_unwrap_or.rs:63:13 | LL | let _ = opt.map(|x| x + 1) | _____________^ +LL | | LL | | .unwrap_or_else(|| LL | | 0 LL | | ); | |_________^ error: called `map().unwrap_or(false)` on an `Option` value - --> tests/ui/map_unwrap_or.rs:61:13 + --> tests/ui/map_unwrap_or.rs:70:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,33 +148,35 @@ LL + let _ = opt.is_some_and(|x| x > 5); | error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or.rs:71:13 + --> tests/ui/map_unwrap_or.rs:81:13 | LL | let _ = res.map(|x| { | _____________^ +LL | | LL | | x + 1 LL | | } LL | | ).unwrap_or_else(|_e| 0); | |____________________________^ error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or.rs:75:13 + --> tests/ui/map_unwrap_or.rs:86:13 | LL | let _ = res.map(|x| x + 1) | _____________^ +LL | | LL | | .unwrap_or_else(|_e| { LL | | 0 LL | | }); | |__________^ error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or.rs:99:13 + --> tests/ui/map_unwrap_or.rs:111:13 | LL | let _ = res.map(|x| x + 1).unwrap_or_else(|_e| 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` error: called `map().unwrap_or()` on an `Option` value - --> tests/ui/map_unwrap_or.rs:106:13 + --> tests/ui/map_unwrap_or.rs:119:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -178,7 +188,7 @@ LL + let _ = opt.map_or(false, |x| x > 5); | error: called `map().unwrap_or(false)` on an `Option` value - --> tests/ui/map_unwrap_or.rs:113:13 + --> tests/ui/map_unwrap_or.rs:127:13 | LL | let _ = opt.map(|x| x > 5).unwrap_or(false); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs index d3d0ae0154c15..1078c7a3cf344 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs @@ -14,6 +14,7 @@ fn option_methods() { // Check for `option.map(_).unwrap_or_else(_)` use. // single line case let _ = opt.map(|x| x + 1) + //~^ map_unwrap_or // Should lint even though this call is on a separate line. .unwrap_or_else(|| 0); @@ -44,6 +45,7 @@ fn result_methods() { // Check for `result.map(_).unwrap_or_else(_)` use. // single line case let _ = res.map(|x| x + 1) + //~^ map_unwrap_or // should lint even though this call is on a separate line .unwrap_or_else(|_e| 0); diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr index 89a7c979f6e92..99e660f8dbd10 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.stderr @@ -3,7 +3,7 @@ error: called `map().unwrap_or_else()` on an `Option` value | LL | let _ = opt.map(|x| x + 1) | _____________^ -LL | | // Should lint even though this call is on a separate line. +... | LL | | .unwrap_or_else(|| 0); | |_____________________________^ help: try: `opt.map_or_else(|| 0, |x| x + 1)` | @@ -11,11 +11,11 @@ LL | | .unwrap_or_else(|| 0); = help: to override `-D warnings` add `#[allow(clippy::map_unwrap_or)]` error: called `map().unwrap_or_else()` on a `Result` value - --> tests/ui/map_unwrap_or_fixable.rs:46:13 + --> tests/ui/map_unwrap_or_fixable.rs:47:13 | LL | let _ = res.map(|x| x + 1) | _____________^ -LL | | // should lint even though this call is on a separate line +... | LL | | .unwrap_or_else(|_e| 0); | |_______________________________^ help: try: `res.map_or_else(|_e| 0, |x| x + 1)` diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed index 18716e93d1e9c..254c46ecae389 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.fixed @@ -23,27 +23,43 @@ macro_rules! r#gen { fn main() { // These should be raised std::iter::repeat_with(|| do_something()).take(10); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(10); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(11); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(7); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(8); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_n(3, 10); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| { + //~^ map_with_unused_argument_over_ranges let x = 3; x + 2 }).take(10); std::iter::repeat_with(|| do_something()).take(10).collect::>(); + //~^ map_with_unused_argument_over_ranges let upper = 4; std::iter::repeat_with(|| do_something()).take(upper); + //~^ map_with_unused_argument_over_ranges let upper_fn = || 4; std::iter::repeat_with(|| do_something()).take(upper_fn()); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(upper_fn() + 1); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(upper_fn() - 2); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(upper_fn() - 1); + //~^ map_with_unused_argument_over_ranges (-3..9).map(|_| do_something()); std::iter::repeat_with(|| do_something()).take(0); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take(1); + //~^ map_with_unused_argument_over_ranges std::iter::repeat_with(|| do_something()).take((1 << 4) - 0); + //~^ map_with_unused_argument_over_ranges // These should not be raised r#gen!(); let lower = 2; @@ -65,9 +81,11 @@ fn msrv_1_27() { #[clippy::msrv = "1.28"] fn msrv_1_28() { std::iter::repeat_with(|| do_something()).take(10); + //~^ map_with_unused_argument_over_ranges } #[clippy::msrv = "1.81"] fn msrv_1_82() { std::iter::repeat(3).take(10); + //~^ map_with_unused_argument_over_ranges } diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs index 596afd51e61f3..05c8d64f8012b 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.rs @@ -23,27 +23,43 @@ macro_rules! r#gen { fn main() { // These should be raised (0..10).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (0..10).map(|_foo| do_something()); + //~^ map_with_unused_argument_over_ranges (0..=10).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (3..10).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (3..=10).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (0..10).map(|_| 3); + //~^ map_with_unused_argument_over_ranges (0..10).map(|_| { + //~^ map_with_unused_argument_over_ranges let x = 3; x + 2 }); (0..10).map(|_| do_something()).collect::>(); + //~^ map_with_unused_argument_over_ranges let upper = 4; (0..upper).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges let upper_fn = || 4; (0..upper_fn()).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (0..=upper_fn()).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (2..upper_fn()).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (2..=upper_fn()).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (-3..9).map(|_| do_something()); (9..3).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (9..=9).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges (1..=1 << 4).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges // These should not be raised r#gen!(); let lower = 2; @@ -65,9 +81,11 @@ fn msrv_1_27() { #[clippy::msrv = "1.28"] fn msrv_1_28() { (0..10).map(|_| do_something()); + //~^ map_with_unused_argument_over_ranges } #[clippy::msrv = "1.81"] fn msrv_1_82() { (0..10).map(|_| 3); + //~^ map_with_unused_argument_over_ranges } diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr index 840515f95df48..e5c93ceac02aa 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges.stderr @@ -13,7 +13,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:26:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:27:5 | LL | (0..10).map(|_foo| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:27:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:29:5 | LL | (0..=10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + std::iter::repeat_with(|| do_something()).take(11); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:28:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:31:5 | LL | (3..10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + std::iter::repeat_with(|| do_something()).take(7); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:29:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:33:5 | LL | (3..=10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + std::iter::repeat_with(|| do_something()).take(8); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:30:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:35:5 | LL | (0..10).map(|_| 3); | ^^^^^^^^^^^^^^^^^^ @@ -73,9 +73,10 @@ LL + std::iter::repeat_n(3, 10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:31:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:37:5 | LL | / (0..10).map(|_| { +LL | | LL | | let x = 3; LL | | x + 2 LL | | }); @@ -84,13 +85,14 @@ LL | | }); help: remove the explicit range and use `repeat_with` and `take` | LL ~ std::iter::repeat_with(|| { +LL | LL | let x = 3; LL | x + 2 LL ~ }).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:35:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:42:5 | LL | (0..10).map(|_| do_something()).collect::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -102,7 +104,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10).collect::>(); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:37:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:45:5 | LL | (0..upper).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -114,7 +116,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:39:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:48:5 | LL | (0..upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -126,7 +128,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn()); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:40:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:50:5 | LL | (0..=upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -138,7 +140,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn() + 1); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:41:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:52:5 | LL | (2..upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -150,7 +152,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn() - 2); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:42:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:54:5 | LL | (2..=upper_fn()).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +164,7 @@ LL + std::iter::repeat_with(|| do_something()).take(upper_fn() - 1); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:44:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:57:5 | LL | (9..3).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -174,7 +176,7 @@ LL + std::iter::repeat_with(|| do_something()).take(0); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:45:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:59:5 | LL | (9..=9).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -186,7 +188,7 @@ LL + std::iter::repeat_with(|| do_something()).take(1); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:46:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:61:5 | LL | (1..=1 << 4).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +200,7 @@ LL + std::iter::repeat_with(|| do_something()).take((1 << 4) - 0); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:67:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:83:5 | LL | (0..10).map(|_| do_something()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -210,7 +212,7 @@ LL + std::iter::repeat_with(|| do_something()).take(10); | error: map of a closure that does not depend on its parameter over a range - --> tests/ui/map_with_unused_argument_over_ranges.rs:72:5 + --> tests/ui/map_with_unused_argument_over_ranges.rs:89:5 | LL | (0..10).map(|_| 3); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.fixed b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.fixed index 65e59774905c4..15a2780da4400 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.fixed +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.fixed @@ -5,4 +5,5 @@ use alloc::vec::Vec; fn nostd(v: &mut [i32]) { let _: Vec<_> = core::iter::repeat_n(3 + 1, 10).collect(); + //~^ map_with_unused_argument_over_ranges } diff --git a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.rs b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.rs index dda7a69b33f96..58de71facebb0 100644 --- a/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.rs +++ b/src/tools/clippy/tests/ui/map_with_unused_argument_over_ranges_nostd.rs @@ -5,4 +5,5 @@ use alloc::vec::Vec; fn nostd(v: &mut [i32]) { let _: Vec<_> = (0..10).map(|_| 3 + 1).collect(); + //~^ map_with_unused_argument_over_ranges } diff --git a/src/tools/clippy/tests/ui/match_as_ref.rs b/src/tools/clippy/tests/ui/match_as_ref.rs index 655e166236975..3a5b1227331e7 100644 --- a/src/tools/clippy/tests/ui/match_as_ref.rs +++ b/src/tools/clippy/tests/ui/match_as_ref.rs @@ -4,12 +4,14 @@ fn match_as_ref() { let owned: Option<()> = None; let borrowed: Option<&()> = match owned { + //~^ match_as_ref None => None, Some(ref v) => Some(v), }; let mut mut_owned: Option<()> = None; let borrow_mut: Option<&mut ()> = match mut_owned { + //~^ match_as_ref None => None, Some(ref mut v) => Some(v), }; @@ -28,6 +30,7 @@ mod issue4437 { impl Error for E { fn source(&self) -> Option<&(dyn Error + 'static)> { match self.source { + //~^ match_as_ref Some(ref s) => Some(s), None => None, } diff --git a/src/tools/clippy/tests/ui/match_as_ref.stderr b/src/tools/clippy/tests/ui/match_as_ref.stderr index 97b121424d932..7b40cb80dc6ed 100644 --- a/src/tools/clippy/tests/ui/match_as_ref.stderr +++ b/src/tools/clippy/tests/ui/match_as_ref.stderr @@ -3,6 +3,7 @@ error: use `as_ref()` instead | LL | let borrowed: Option<&()> = match owned { | _________________________________^ +LL | | LL | | None => None, LL | | Some(ref v) => Some(v), LL | | }; @@ -12,19 +13,21 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::match_as_ref)]` error: use `as_mut()` instead - --> tests/ui/match_as_ref.rs:12:39 + --> tests/ui/match_as_ref.rs:13:39 | LL | let borrow_mut: Option<&mut ()> = match mut_owned { | _______________________________________^ +LL | | LL | | None => None, LL | | Some(ref mut v) => Some(v), LL | | }; | |_____^ help: try: `mut_owned.as_mut()` error: use `as_ref()` instead - --> tests/ui/match_as_ref.rs:30:13 + --> tests/ui/match_as_ref.rs:32:13 | LL | / match self.source { +LL | | LL | | Some(ref s) => Some(s), LL | | None => None, LL | | } diff --git a/src/tools/clippy/tests/ui/match_bool.fixed b/src/tools/clippy/tests/ui/match_bool.fixed index 61a8e54fa10ce..1dfb82db12061 100644 --- a/src/tools/clippy/tests/ui/match_bool.fixed +++ b/src/tools/clippy/tests/ui/match_bool.fixed @@ -55,4 +55,10 @@ fn match_bool() { if !(!test && option == 5) { println!("Hello") }; } +fn issue14099() { + if true { 'a: { + break 'a; + } } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_bool.rs b/src/tools/clippy/tests/ui/match_bool.rs index 9c81d2917869b..719b4e51eb6d9 100644 --- a/src/tools/clippy/tests/ui/match_bool.rs +++ b/src/tools/clippy/tests/ui/match_bool.rs @@ -5,20 +5,20 @@ fn match_bool() { let test: bool = true; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool true => 0, false => 42, }; let option = 1; match option == 1 { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool true => 1, false => 0, }; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool true => (), false => { println!("Noooo!"); @@ -26,7 +26,7 @@ fn match_bool() { }; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool false => { println!("Noooo!"); }, @@ -34,7 +34,7 @@ fn match_bool() { }; match test && test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool false => { println!("Noooo!"); }, @@ -42,7 +42,7 @@ fn match_bool() { }; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool false => { println!("Noooo!"); }, @@ -67,40 +67,50 @@ fn match_bool() { }; let _ = match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool true if option == 5 => 10, _ => 1, }; let _ = match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool false if option == 5 => 10, _ => 1, }; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool true if option == 5 => println!("Hello"), _ => (), }; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool true if option == 5 => (), _ => println!("Hello"), }; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool false if option == 5 => println!("Hello"), _ => (), }; match test { - //~^ ERROR: `match` on a boolean expression + //~^ match_bool false if option == 5 => (), _ => println!("Hello"), }; } +fn issue14099() { + match true { + //~^ match_bool + true => 'a: { + break 'a; + }, + _ => (), + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_bool.stderr b/src/tools/clippy/tests/ui/match_bool.stderr index a4e504a0a82e4..c05742e56339a 100644 --- a/src/tools/clippy/tests/ui/match_bool.stderr +++ b/src/tools/clippy/tests/ui/match_bool.stderr @@ -164,5 +164,24 @@ LL | | _ => println!("Hello"), LL | | }; | |_____^ help: consider using an `if`/`else` expression: `if !(!test && option == 5) { println!("Hello") }` -error: aborting due to 12 previous errors +error: `match` on a boolean expression + --> tests/ui/match_bool.rs:107:5 + | +LL | / match true { +LL | | +LL | | true => 'a: { +LL | | break 'a; +LL | | }, +LL | | _ => (), +LL | | } + | |_____^ + | +help: consider using an `if`/`else` expression + | +LL ~ if true { 'a: { +LL + break 'a; +LL + } } + | + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed index 05edc024ba9f7..8530ab16bfd7d 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed @@ -12,18 +12,23 @@ fn main() { // Lint let _y = matches!(x, Some(0)); + //~^^^^ match_like_matches_macro // Lint let _w = x.is_some(); + //~^^^^ redundant_pattern_matching // Turn into is_none let _z = x.is_none(); + //~^^^^ redundant_pattern_matching // Lint let _zz = !matches!(x, Some(r) if r == 0); + //~^^^^ match_like_matches_macro // Lint let _zzz = matches!(x, Some(5)); + //~^ match_like_matches_macro // No lint let _a = match x { @@ -48,16 +53,19 @@ fn main() { { // lint let _ans = matches!(x, E::A(_) | E::B(_)); + //~^^^^^ match_like_matches_macro } { // lint // skip rustfmt to prevent removing block for first pattern #[rustfmt::skip] let _ans = matches!(x, E::A(_) | E::B(_)); + //~^^^^^^^ match_like_matches_macro } { // lint let _ans = !matches!(x, E::B(_) | E::C); + //~^^^^^ match_like_matches_macro } { // no lint @@ -114,12 +122,14 @@ fn main() { // should print "z" in suggestion (#6503) let z = &Some(3); let _z = matches!(z, Some(3)); + //~^^^^ match_like_matches_macro } { // this could also print "z" in suggestion..? let z = Some(3); let _z = matches!(&z, Some(3)); + //~^^^^ match_like_matches_macro } { @@ -134,6 +144,7 @@ fn main() { let z = AnEnum::X; // we can't remove the reference here! let _ = matches!(&z, AnEnum::X); + //~^^^^ match_like_matches_macro foo(z); } } @@ -145,6 +156,7 @@ fn main() { let val = Some(S(42)); // we need the reference here because later val is consumed by fun() let _res = matches!(&val, &Some(ref _a)); + //~^^^^ match_like_matches_macro fun(val); } @@ -154,6 +166,7 @@ fn main() { fn fun(_val: Option) {} let val = Some(S(42)); let _res = matches!(&val, &Some(ref _a)); + //~^^^^ match_like_matches_macro fun(val); } @@ -209,4 +222,5 @@ fn msrv_1_41() { #[clippy::msrv = "1.42"] fn msrv_1_42() { let _y = matches!(Some(5), Some(0)); + //~^^^^ match_like_matches_macro } diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs index d6a0313cde432..81017936889e4 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs @@ -15,27 +15,32 @@ fn main() { Some(0) => true, _ => false, }; + //~^^^^ match_like_matches_macro // Lint let _w = match x { Some(_) => true, _ => false, }; + //~^^^^ redundant_pattern_matching // Turn into is_none let _z = match x { Some(_) => false, None => true, }; + //~^^^^ redundant_pattern_matching // Lint let _zz = match x { Some(r) if r == 0 => false, _ => true, }; + //~^^^^ match_like_matches_macro // Lint let _zzz = if let Some(5) = x { true } else { false }; + //~^ match_like_matches_macro // No lint let _a = match x { @@ -64,6 +69,7 @@ fn main() { E::B(_) => true, _ => false, }; + //~^^^^^ match_like_matches_macro } { // lint @@ -76,6 +82,7 @@ fn main() { E::B(_) => true, _ => false, }; + //~^^^^^^^ match_like_matches_macro } { // lint @@ -84,6 +91,7 @@ fn main() { E::C => false, _ => true, }; + //~^^^^^ match_like_matches_macro } { // no lint @@ -143,6 +151,7 @@ fn main() { Some(3) => true, _ => false, }; + //~^^^^ match_like_matches_macro } { @@ -152,6 +161,7 @@ fn main() { Some(3) => true, _ => false, }; + //~^^^^ match_like_matches_macro } { @@ -169,6 +179,7 @@ fn main() { AnEnum::X => true, _ => false, }; + //~^^^^ match_like_matches_macro foo(z); } } @@ -183,6 +194,7 @@ fn main() { &Some(ref _a) => true, _ => false, }; + //~^^^^ match_like_matches_macro fun(val); } @@ -195,6 +207,7 @@ fn main() { &Some(ref _a) => true, _ => false, }; + //~^^^^ match_like_matches_macro fun(val); } @@ -253,4 +266,5 @@ fn msrv_1_42() { Some(0) => true, _ => false, }; + //~^^^^ match_like_matches_macro } diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr index ffe5772ece90b..8fceb05bc6e87 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr @@ -12,7 +12,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/match_expr_like_matches_macro.rs:20:14 + --> tests/ui/match_expr_like_matches_macro.rs:21:14 | LL | let _w = match x { | ______________^ @@ -25,7 +25,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_expr_like_matches_macro.rs:26:14 + --> tests/ui/match_expr_like_matches_macro.rs:28:14 | LL | let _z = match x { | ______________^ @@ -35,7 +35,7 @@ LL | | }; | |_____^ help: try: `x.is_none()` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:32:15 + --> tests/ui/match_expr_like_matches_macro.rs:35:15 | LL | let _zz = match x { | _______________^ @@ -45,13 +45,13 @@ LL | | }; | |_____^ help: try: `!matches!(x, Some(r) if r == 0)` error: if let .. else expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:38:16 + --> tests/ui/match_expr_like_matches_macro.rs:42:16 | LL | let _zzz = if let Some(5) = x { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(x, Some(5))` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:62:20 + --> tests/ui/match_expr_like_matches_macro.rs:67:20 | LL | let _ans = match x { | ____________________^ @@ -62,7 +62,7 @@ LL | | }; | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:72:20 + --> tests/ui/match_expr_like_matches_macro.rs:78:20 | LL | let _ans = match x { | ____________________^ @@ -74,7 +74,7 @@ LL | | }; | |_________^ help: try: `matches!(x, E::A(_) | E::B(_))` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:82:20 + --> tests/ui/match_expr_like_matches_macro.rs:89:20 | LL | let _ans = match x { | ____________________^ @@ -85,7 +85,7 @@ LL | | }; | |_________^ help: try: `!matches!(x, E::B(_) | E::C)` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:142:18 + --> tests/ui/match_expr_like_matches_macro.rs:150:18 | LL | let _z = match &z { | __________________^ @@ -95,7 +95,7 @@ LL | | }; | |_________^ help: try: `matches!(z, Some(3))` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:151:18 + --> tests/ui/match_expr_like_matches_macro.rs:160:18 | LL | let _z = match &z { | __________________^ @@ -105,7 +105,7 @@ LL | | }; | |_________^ help: try: `matches!(&z, Some(3))` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:168:21 + --> tests/ui/match_expr_like_matches_macro.rs:178:21 | LL | let _ = match &z { | _____________________^ @@ -115,7 +115,7 @@ LL | | }; | |_____________^ help: try: `matches!(&z, AnEnum::X)` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:182:20 + --> tests/ui/match_expr_like_matches_macro.rs:193:20 | LL | let _res = match &val { | ____________________^ @@ -125,7 +125,7 @@ LL | | }; | |_________^ help: try: `matches!(&val, &Some(ref _a))` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:194:20 + --> tests/ui/match_expr_like_matches_macro.rs:206:20 | LL | let _res = match &val { | ____________________^ @@ -135,7 +135,7 @@ LL | | }; | |_________^ help: try: `matches!(&val, &Some(ref _a))` error: match expression looks like `matches!` macro - --> tests/ui/match_expr_like_matches_macro.rs:252:14 + --> tests/ui/match_expr_like_matches_macro.rs:265:14 | LL | let _y = match Some(5) { | ______________^ diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.rs b/src/tools/clippy/tests/ui/match_on_vec_items.rs index f7b8500faa4a0..f3174ec9734df 100644 --- a/src/tools/clippy/tests/ui/match_on_vec_items.rs +++ b/src/tools/clippy/tests/ui/match_on_vec_items.rs @@ -8,8 +8,7 @@ fn match_with_wildcard() { // Lint, may panic match arr[idx] { - //~^ ERROR: indexing into a vector may panic - //~| NOTE: `-D clippy::match-on-vec-items` implied by `-D warnings` + //~^ match_on_vec_items 0 => println!("0"), 1 => println!("1"), _ => {}, @@ -17,7 +16,7 @@ fn match_with_wildcard() { // Lint, may panic match arr[range] { - //~^ ERROR: indexing into a vector may panic + //~^ match_on_vec_items [0, 1] => println!("0 1"), [1, 2] => println!("1 2"), _ => {}, @@ -31,7 +30,7 @@ fn match_without_wildcard() { // Lint, may panic match arr[idx] { - //~^ ERROR: indexing into a vector may panic + //~^ match_on_vec_items 0 => println!("0"), 1 => println!("1"), num => {}, @@ -39,7 +38,7 @@ fn match_without_wildcard() { // Lint, may panic match arr[range] { - //~^ ERROR: indexing into a vector may panic + //~^ match_on_vec_items [0, 1] => println!("0 1"), [1, 2] => println!("1 2"), [ref sub @ ..] => {}, @@ -53,7 +52,7 @@ fn match_wildcard_and_action() { // Lint, may panic match arr[idx] { - //~^ ERROR: indexing into a vector may panic + //~^ match_on_vec_items 0 => println!("0"), 1 => println!("1"), _ => println!("Hello, World!"), @@ -61,7 +60,7 @@ fn match_wildcard_and_action() { // Lint, may panic match arr[range] { - //~^ ERROR: indexing into a vector may panic + //~^ match_on_vec_items [0, 1] => println!("0 1"), [1, 2] => println!("1 2"), _ => println!("Hello, World!"), @@ -75,7 +74,7 @@ fn match_vec_ref() { // Lint, may panic match arr[idx] { - //~^ ERROR: indexing into a vector may panic + //~^ match_on_vec_items 0 => println!("0"), 1 => println!("1"), _ => {}, @@ -83,7 +82,7 @@ fn match_vec_ref() { // Lint, may panic match arr[range] { - //~^ ERROR: indexing into a vector may panic + //~^ match_on_vec_items [0, 1] => println!("0 1"), [1, 2] => println!("1 2"), _ => {}, diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.stderr b/src/tools/clippy/tests/ui/match_on_vec_items.stderr index e31db37841379..ae79e1305f7fd 100644 --- a/src/tools/clippy/tests/ui/match_on_vec_items.stderr +++ b/src/tools/clippy/tests/ui/match_on_vec_items.stderr @@ -8,43 +8,43 @@ LL | match arr[idx] { = help: to override `-D warnings` add `#[allow(clippy::match_on_vec_items)]` error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:19:11 + --> tests/ui/match_on_vec_items.rs:18:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:33:11 + --> tests/ui/match_on_vec_items.rs:32:11 | LL | match arr[idx] { | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:41:11 + --> tests/ui/match_on_vec_items.rs:40:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:55:11 + --> tests/ui/match_on_vec_items.rs:54:11 | LL | match arr[idx] { | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:63:11 + --> tests/ui/match_on_vec_items.rs:62:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try: `arr.get(range)` error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:77:11 + --> tests/ui/match_on_vec_items.rs:76:11 | LL | match arr[idx] { | ^^^^^^^^ help: try: `arr.get(idx)` error: indexing into a vector may panic - --> tests/ui/match_on_vec_items.rs:85:11 + --> tests/ui/match_on_vec_items.rs:84:11 | LL | match arr[range] { | ^^^^^^^^^^ help: try: `arr.get(range)` diff --git a/src/tools/clippy/tests/ui/match_overlapping_arm.rs b/src/tools/clippy/tests/ui/match_overlapping_arm.rs index a056fdeaa5d0c..176287e3d2e0c 100644 --- a/src/tools/clippy/tests/ui/match_overlapping_arm.rs +++ b/src/tools/clippy/tests/ui/match_overlapping_arm.rs @@ -7,14 +7,14 @@ fn overlapping() { match 42 { 0..=10 => println!("0..=10"), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm 0..=11 => println!("0..=11"), _ => (), } match 42 { 0..=5 => println!("0..=5"), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm 6..=7 => println!("6..=7"), FOO..=11 => println!("FOO..=11"), _ => (), @@ -52,7 +52,7 @@ fn overlapping() { match 42 { 0..11 => println!("0..11"), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm 0..=11 => println!("0..=11"), _ => (), } @@ -78,13 +78,13 @@ fn overlapping() { match 42 { 5..14 => println!("5..14"), 0..=10 => println!("0..=10"), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm _ => (), } match 42 { 0..7 => println!("0..7"), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm 0..=10 => println!("0..=10"), _ => (), } @@ -97,7 +97,7 @@ fn overlapping() { match 42 { ..=23 => println!("..=23"), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm ..26 => println!("..26"), _ => (), } @@ -107,7 +107,7 @@ fn overlapping() { 5..=10 => (), 0..=20 => (), 21..=30 => (), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm 21..=40 => (), _ => (), } @@ -122,7 +122,7 @@ fn overlapping() { // Only warn about the first if there are multiple overlaps match 42u128 { 0..=0x0000_0000_0000_00ff => (), - //~^ ERROR: some ranges overlap + //~^ match_overlapping_arm 0..=0x0000_0000_0000_ffff => (), 0..=0x0000_0000_ffff_ffff => (), 0..=0xffff_ffff_ffff_ffff => (), diff --git a/src/tools/clippy/tests/ui/match_ref_pats.fixed b/src/tools/clippy/tests/ui/match_ref_pats.fixed index f8d47b0fdc7da..8add3da0c99f0 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.fixed +++ b/src/tools/clippy/tests/ui/match_ref_pats.fixed @@ -6,6 +6,7 @@ fn ref_pats() { { let v = &Some(0); match *v { + //~^ match_ref_pats Some(v) => println!("{:?}", v), None => println!("none"), } @@ -23,6 +24,7 @@ fn ref_pats() { // Special case: using `&` both in expr and pats. let w = Some(0); match w { + //~^ match_ref_pats Some(v) => println!("{:?}", v), None => println!("none"), } @@ -35,11 +37,13 @@ fn ref_pats() { let a = &Some(0); if a.is_none() { + //~^ redundant_pattern_matching println!("none"); } let b = Some(0); if b.is_none() { + //~^ redundant_pattern_matching println!("none"); } } @@ -100,6 +104,7 @@ mod issue_7740 { fn issue_7740() { // Issue #7740 match *foobar_variant!(0) { + //~^ match_ref_pats FooBar::Foo => println!("Foo"), FooBar::Bar => println!("Bar"), FooBar::FooBar => println!("FooBar"), diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs index bcd7bf7ab51b9..07889b0dfc243 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.rs +++ b/src/tools/clippy/tests/ui/match_ref_pats.rs @@ -6,6 +6,7 @@ fn ref_pats() { { let v = &Some(0); match v { + //~^ match_ref_pats &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -23,6 +24,7 @@ fn ref_pats() { // Special case: using `&` both in expr and pats. let w = Some(0); match &w { + //~^ match_ref_pats &Some(v) => println!("{:?}", v), &None => println!("none"), } @@ -35,11 +37,13 @@ fn ref_pats() { let a = &Some(0); if let &None = a { + //~^ redundant_pattern_matching println!("none"); } let b = Some(0); if let &None = &b { + //~^ redundant_pattern_matching println!("none"); } } @@ -100,6 +104,7 @@ mod issue_7740 { fn issue_7740() { // Issue #7740 match foobar_variant!(0) { + //~^ match_ref_pats &FooBar::Foo => println!("Foo"), &FooBar::Bar => println!("Bar"), &FooBar::FooBar => println!("FooBar"), diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr index fc01ab0a919a1..f81b290b32cb8 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.stderr +++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr @@ -2,6 +2,7 @@ error: you don't need to add `&` to all patterns --> tests/ui/match_ref_pats.rs:8:9 | LL | / match v { +LL | | LL | | &Some(v) => println!("{:?}", v), LL | | &None => println!("none"), LL | | } @@ -12,14 +13,16 @@ LL | | } help: instead of prefixing all patterns with `&`, you can dereference the expression | LL ~ match *v { +LL | LL ~ Some(v) => println!("{:?}", v), LL ~ None => println!("none"), | error: you don't need to add `&` to both the expression and the patterns - --> tests/ui/match_ref_pats.rs:25:5 + --> tests/ui/match_ref_pats.rs:26:5 | LL | / match &w { +LL | | LL | | &Some(v) => println!("{:?}", v), LL | | &None => println!("none"), LL | | } @@ -28,12 +31,13 @@ LL | | } help: try | LL ~ match w { +LL | LL ~ Some(v) => println!("{:?}", v), LL ~ None => println!("none"), | error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:37:12 + --> tests/ui/match_ref_pats.rs:39:12 | LL | if let &None = a { | -------^^^^^---- help: try: `if a.is_none()` @@ -42,15 +46,16 @@ LL | if let &None = a { = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:42:12 + --> tests/ui/match_ref_pats.rs:45:12 | LL | if let &None = &b { | -------^^^^^----- help: try: `if b.is_none()` error: you don't need to add `&` to all patterns - --> tests/ui/match_ref_pats.rs:102:9 + --> tests/ui/match_ref_pats.rs:106:9 | LL | / match foobar_variant!(0) { +LL | | LL | | &FooBar::Foo => println!("Foo"), LL | | &FooBar::Bar => println!("Bar"), LL | | &FooBar::FooBar => println!("FooBar"), @@ -61,6 +66,7 @@ LL | | } help: instead of prefixing all patterns with `&`, you can dereference the expression | LL ~ match *foobar_variant!(0) { +LL | LL ~ FooBar::Foo => println!("Foo"), LL ~ FooBar::Bar => println!("Bar"), LL ~ FooBar::FooBar => println!("FooBar"), diff --git a/src/tools/clippy/tests/ui/match_result_ok.fixed b/src/tools/clippy/tests/ui/match_result_ok.fixed index 117e0bc68ccc0..0e630e6a29045 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.fixed +++ b/src/tools/clippy/tests/ui/match_result_ok.fixed @@ -11,6 +11,7 @@ fn str_to_int(x: &str) -> i32 { if let Ok(y) = x.parse() { y } else { 0 } + //~^ match_result_ok } fn str_to_int_ok(x: &str) -> i32 { @@ -21,6 +22,7 @@ fn str_to_int_ok(x: &str) -> i32 { fn strange_some_no_else(x: &str) -> i32 { { if let Ok(y) = x . parse() { + //~^ match_result_ok return y; }; 0 @@ -47,6 +49,7 @@ impl Wat { fn base_1(x: i32) { let mut wat = Wat { counter: x }; while let Ok(a) = wat.next() { + //~^ match_result_ok println!("{}", a); } } diff --git a/src/tools/clippy/tests/ui/match_result_ok.rs b/src/tools/clippy/tests/ui/match_result_ok.rs index f8a5269024da5..63bf6e8ab5087 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.rs +++ b/src/tools/clippy/tests/ui/match_result_ok.rs @@ -11,6 +11,7 @@ fn str_to_int(x: &str) -> i32 { if let Some(y) = x.parse().ok() { y } else { 0 } + //~^ match_result_ok } fn str_to_int_ok(x: &str) -> i32 { @@ -21,6 +22,7 @@ fn str_to_int_ok(x: &str) -> i32 { fn strange_some_no_else(x: &str) -> i32 { { if let Some(y) = x . parse() . ok () { + //~^ match_result_ok return y; }; 0 @@ -47,6 +49,7 @@ impl Wat { fn base_1(x: i32) { let mut wat = Wat { counter: x }; while let Some(a) = wat.next().ok() { + //~^ match_result_ok println!("{}", a); } } diff --git a/src/tools/clippy/tests/ui/match_result_ok.stderr b/src/tools/clippy/tests/ui/match_result_ok.stderr index 18b23bd784540..822cc4de77f3d 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.stderr +++ b/src/tools/clippy/tests/ui/match_result_ok.stderr @@ -13,7 +13,7 @@ LL + if let Ok(y) = x.parse() { y } else { 0 } | error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:23:9 + --> tests/ui/match_result_ok.rs:24:9 | LL | if let Some(y) = x . parse() . ok () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + if let Ok(y) = x . parse() { | error: matching on `Some` with `ok()` is redundant - --> tests/ui/match_result_ok.rs:49:5 + --> tests/ui/match_result_ok.rs:51:5 | LL | while let Some(a) = wat.next().ok() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs index 2f4652dcf32b6..55441948e91b6 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.rs +++ b/src/tools/clippy/tests/ui/match_same_arms.rs @@ -9,30 +9,36 @@ pub enum Abc { fn match_same_arms() { let _ = match Abc::A { - Abc::A => 0, //~ ERROR: this match arm has an identical body to the `_` wildcard arm + Abc::A => 0, + //~^ match_same_arms Abc::B => 1, _ => 0, }; match (1, 2, 3) { - (1, .., 3) => 42, //~ ERROR: this match arm has an identical body to another arm + (1, .., 3) => 42, + //~^ match_same_arms (.., 3) => 42, _ => 0, }; let _ = match 42 { 42 => 1, - 51 => 1, //~ ERROR: this match arm has an identical body to another arm - 41 => 2, //~ ERROR: this match arm has an identical body to another arm + 51 => 1, + //~^ match_same_arms + 41 => 2, + //~^ match_same_arms 52 => 2, _ => 0, }; let _ = match 42 { 1 => 2, - 2 => 2, //~ ERROR: this match arm has an identical body to another arm - //~^ ERROR: this match arm has an identical body to another arm - 3 => 2, //~ ERROR: this match arm has an identical body to another arm + 2 => 2, + //~^ match_same_arms + //~| match_same_arms + 3 => 2, + //~^ match_same_arms 4 => 3, _ => 0, }; @@ -50,7 +56,7 @@ mod issue4244 { match self { CommandInfo::BuiltIn { name, .. } => name.to_string(), CommandInfo::External { name, .. } => name.to_string(), - //~^ ERROR: this match arm has an identical body to another arm + //~^ match_same_arms } } } diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr index 4a4772da143a2..3744b83d89cc8 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms.stderr @@ -1,12 +1,13 @@ error: this match arm has an identical body to the `_` wildcard arm --> tests/ui/match_same_arms.rs:12:9 | -LL | Abc::A => 0, - | ^^^^^^^^^^^^^ help: try removing the arm +LL | / Abc::A => 0, +LL | | + | |________^ help: try removing the arm | = help: or try changing either arm body note: `_` wildcard arm here - --> tests/ui/match_same_arms.rs:14:9 + --> tests/ui/match_same_arms.rs:15:9 | LL | _ => 0, | ^^^^^^ @@ -14,7 +15,7 @@ LL | _ => 0, = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]` error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:18:9 + --> tests/ui/match_same_arms.rs:19:9 | LL | (1, .., 3) => 42, | ^^^^^^^^^^^^^^^^ @@ -23,11 +24,12 @@ LL | (1, .., 3) => 42, help: or try merging the arm patterns and removing the obsolete arm | LL ~ (1, .., 3) | (.., 3) => 42, +LL | LL ~ _ => 0, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:25:9 + --> tests/ui/match_same_arms.rs:27:9 | LL | 51 => 1, | ^^^^^^^ @@ -41,7 +43,7 @@ LL + 51 | 42 => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:26:9 + --> tests/ui/match_same_arms.rs:29:9 | LL | 41 => 2, | ^^^^^^^ @@ -50,11 +52,12 @@ LL | 41 => 2, help: or try merging the arm patterns and removing the obsolete arm | LL ~ 41 | 52 => 2, +LL | LL ~ _ => 0, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:33:9 + --> tests/ui/match_same_arms.rs:37:9 | LL | 2 => 2, | ^^^^^^ @@ -68,7 +71,7 @@ LL + 2 | 1 => 2, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:35:9 + --> tests/ui/match_same_arms.rs:40:9 | LL | 3 => 2, | ^^^^^^ @@ -78,11 +81,12 @@ help: or try merging the arm patterns and removing the obsolete arm | LL ~ 2 => 2, LL | +LL | LL ~ 3 | 1 => 2, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:33:9 + --> tests/ui/match_same_arms.rs:37:9 | LL | 2 => 2, | ^^^^^^ @@ -92,11 +96,12 @@ help: or try merging the arm patterns and removing the obsolete arm | LL ~ 2 | 3 => 2, LL | +LL | LL ~ | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms.rs:52:17 + --> tests/ui/match_same_arms.rs:58:17 | LL | CommandInfo::External { name, .. } => name.to_string(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/match_same_arms2.fixed b/src/tools/clippy/tests/ui/match_same_arms2.fixed index b7d377f1ebffc..0d93e2c728d75 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.fixed +++ b/src/tools/clippy/tests/ui/match_same_arms2.fixed @@ -14,6 +14,7 @@ fn foo() -> bool { fn match_same_arms() { let _ = match 42 { + //~^^^^^^^^^ match_same_arms _ => { foo(); let mut a = 42 + [23].len() as i32; @@ -24,15 +25,16 @@ fn match_same_arms() { a }, }; - //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm let _ = match 42 { - 51 | 42 => foo(), //~ ERROR: this match arm has an identical body to another arm + 51 | 42 => foo(), + //~^ match_same_arms _ => true, }; let _ = match Some(42) { - None | Some(_) => 24, //~ ERROR: this match arm has an identical body to another arm + None | Some(_) => 24, + //~^ match_same_arms }; let _ = match Some(42) { @@ -53,7 +55,8 @@ fn match_same_arms() { }; match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) => bar(a), //~ ERROR: this match arm has an identical body to another arm + (None, Some(a)) | (Some(a), None) => bar(a), + //~^ match_same_arms _ => (), } @@ -66,12 +69,14 @@ fn match_same_arms() { }; let _ = match (Some(42), Some(42)) { - (None, Some(a)) | (Some(a), None) if a == 42 => a, //~ ERROR: this match arm has an identical body to another arm + (None, Some(a)) | (Some(a), None) if a == 42 => a, + //~^ match_same_arms _ => 0, }; match (Some(42), Some(42)) { - (Some(a), ..) | (.., Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm + (Some(a), ..) | (.., Some(a)) => bar(a), + //~^ match_same_arms _ => (), } @@ -104,7 +109,8 @@ fn match_same_arms() { } match (x, Some(1i32)) { - (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm + (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), + //~^ match_same_arms _ => println!("err"), } @@ -118,7 +124,8 @@ fn match_same_arms() { // False negative #2251. match x { Ok(_tmp) => println!("ok"), - Ok(_) | Ok(3) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm + Ok(_) | Ok(3) => println!("ok"), + //~^ match_same_arms Err(_) => { unreachable!(); }, @@ -145,11 +152,11 @@ fn match_same_arms() { 1 | 0 => { empty!(0); }, + //~^^^ match_same_arms x => { empty!(x); }, } - //~^^^^^^^ ERROR: this match arm has an identical body to another arm match_expr_like_matches_macro_priority(); } @@ -193,7 +200,8 @@ fn main() { // Suggest moving `Foo::Z(_)` up. let _ = match Foo::X(0) { - Foo::X(0) | Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm + Foo::X(0) | Foo::Z(_) => 1, + //~^ match_same_arms Foo::X(_) | Foo::Y(_) => 2, _ => 0, }; @@ -201,7 +209,8 @@ fn main() { // Suggest moving `Foo::X(0)` down. let _ = match Foo::X(0) { Foo::Y(_) | Foo::Z(0) => 2, - Foo::Z(_) | Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm + Foo::Z(_) | Foo::X(0) => 1, + //~^ match_same_arms _ => 0, }; @@ -223,7 +232,8 @@ fn main() { let _ = match None { Some(Bar { y: 10, z: 0, .. }) => 2, None => 50, - Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm + Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, + //~^ match_same_arms _ => 200, }; @@ -237,6 +247,7 @@ fn main() { let _ = match 0 { 1 | 0 => cfg!(not_enable), + //~^ match_same_arms _ => false, }; } @@ -252,7 +263,7 @@ mod with_lifetime { fn get(&self) -> &'a str { match *self { MaybeStaticStr::Borrowed(s) | MaybeStaticStr::Static(s) => s, - //~^ ERROR: this match arm has an identical body to another arm + //~^ match_same_arms } } } diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index dfd15d10c3d34..b0ebc4784f331 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -23,6 +23,7 @@ fn match_same_arms() { a = -31 - a; a }, + //~^^^^^^^^^ match_same_arms _ => { foo(); let mut a = 42 + [23].len() as i32; @@ -33,17 +34,18 @@ fn match_same_arms() { a }, }; - //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm let _ = match 42 { 42 => foo(), - 51 => foo(), //~ ERROR: this match arm has an identical body to another arm + 51 => foo(), + //~^ match_same_arms _ => true, }; let _ = match Some(42) { Some(_) => 24, - None => 24, //~ ERROR: this match arm has an identical body to another arm + None => 24, + //~^ match_same_arms }; let _ = match Some(42) { @@ -65,7 +67,8 @@ fn match_same_arms() { match (Some(42), Some(42)) { (Some(a), None) => bar(a), - (None, Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm + (None, Some(a)) => bar(a), + //~^ match_same_arms _ => (), } @@ -79,12 +82,14 @@ fn match_same_arms() { let _ = match (Some(42), Some(42)) { (Some(a), None) if a == 42 => a, - (None, Some(a)) if a == 42 => a, //~ ERROR: this match arm has an identical body to another arm + (None, Some(a)) if a == 42 => a, + //~^ match_same_arms _ => 0, }; match (Some(42), Some(42)) { - (Some(a), ..) => bar(a), //~ ERROR: this match arm has an identical body to another arm + (Some(a), ..) => bar(a), + //~^ match_same_arms (.., Some(a)) => bar(a), _ => (), } @@ -118,7 +123,8 @@ fn match_same_arms() { } match (x, Some(1i32)) { - (Ok(x), Some(_)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm + (Ok(x), Some(_)) => println!("ok {}", x), + //~^ match_same_arms (Ok(_), Some(x)) => println!("ok {}", x), _ => println!("err"), } @@ -134,7 +140,8 @@ fn match_same_arms() { match x { Ok(_tmp) => println!("ok"), Ok(3) => println!("ok"), - Ok(_) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm + Ok(_) => println!("ok"), + //~^ match_same_arms Err(_) => { unreachable!(); }, @@ -164,11 +171,11 @@ fn match_same_arms() { 1 => { empty!(0); }, + //~^^^ match_same_arms x => { empty!(x); }, } - //~^^^^^^^ ERROR: this match arm has an identical body to another arm match_expr_like_matches_macro_priority(); } @@ -212,7 +219,8 @@ fn main() { // Suggest moving `Foo::Z(_)` up. let _ = match Foo::X(0) { - Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm + Foo::X(0) => 1, + //~^ match_same_arms Foo::X(_) | Foo::Y(_) => 2, Foo::Z(_) => 1, _ => 0, @@ -222,7 +230,8 @@ fn main() { let _ = match Foo::X(0) { Foo::X(0) => 1, Foo::Y(_) | Foo::Z(0) => 2, - Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm + Foo::Z(_) => 1, + //~^ match_same_arms _ => 0, }; @@ -245,7 +254,8 @@ fn main() { Some(Bar { x: 0, y: 5, .. }) => 1, Some(Bar { y: 10, z: 0, .. }) => 2, None => 50, - Some(Bar { y: 0, x: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm + Some(Bar { y: 0, x: 5, .. }) => 1, + //~^ match_same_arms _ => 200, }; @@ -260,6 +270,7 @@ fn main() { let _ = match 0 { 0 => cfg!(not_enable), 1 => cfg!(not_enable), + //~^ match_same_arms _ => false, }; } @@ -276,7 +287,7 @@ mod with_lifetime { match *self { MaybeStaticStr::Static(s) => s, MaybeStaticStr::Borrowed(s) => s, - //~^ ERROR: this match arm has an identical body to another arm + //~^ match_same_arms } } } diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index 525a25e9287be..21a8743cc3242 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -7,12 +7,12 @@ LL | | let mut a = 42 + [23].len() as i32; LL | | if true { ... | LL | | }, -LL | | _ => { +LL | | | |________^ help: try removing the arm | = help: or try changing either arm body note: `_` wildcard arm here - --> tests/ui/match_same_arms2.rs:26:9 + --> tests/ui/match_same_arms2.rs:27:9 | LL | / _ => { LL | | foo(); @@ -40,7 +40,7 @@ LL + 51 | 42 => foo(), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:46:9 + --> tests/ui/match_same_arms2.rs:47:9 | LL | None => 24, | ^^^^^^^^^^ @@ -54,7 +54,7 @@ LL + None | Some(_) => 24, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:68:9 + --> tests/ui/match_same_arms2.rs:70:9 | LL | (None, Some(a)) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + (None, Some(a)) | (Some(a), None) => bar(a), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:82:9 + --> tests/ui/match_same_arms2.rs:85:9 | LL | (None, Some(a)) if a == 42 => a, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL + (None, Some(a)) | (Some(a), None) if a == 42 => a, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:87:9 + --> tests/ui/match_same_arms2.rs:91:9 | LL | (Some(a), ..) => bar(a), | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,11 +91,12 @@ LL | (Some(a), ..) => bar(a), help: or try merging the arm patterns and removing the obsolete arm | LL ~ (Some(a), ..) | (.., Some(a)) => bar(a), +LL | LL ~ _ => (), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:121:9 + --> tests/ui/match_same_arms2.rs:126:9 | LL | (Ok(x), Some(_)) => println!("ok {}", x), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,11 +105,12 @@ LL | (Ok(x), Some(_)) => println!("ok {}", x), help: or try merging the arm patterns and removing the obsolete arm | LL ~ (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), +LL | LL ~ _ => println!("err"), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:137:9 + --> tests/ui/match_same_arms2.rs:143:9 | LL | Ok(_) => println!("ok"), | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +124,7 @@ LL + Ok(_) | Ok(3) => println!("ok"), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:164:9 + --> tests/ui/match_same_arms2.rs:171:9 | LL | / 1 => { LL | | empty!(0); @@ -140,7 +142,7 @@ LL + 1 | 0 => { | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:215:9 + --> tests/ui/match_same_arms2.rs:222:9 | LL | Foo::X(0) => 1, | ^^^^^^^^^^^^^^ @@ -149,12 +151,13 @@ LL | Foo::X(0) => 1, help: or try merging the arm patterns and removing the obsolete arm | LL ~ Foo::X(0) | Foo::Z(_) => 1, +LL | LL | Foo::X(_) | Foo::Y(_) => 2, LL ~ _ => 0, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:225:9 + --> tests/ui/match_same_arms2.rs:233:9 | LL | Foo::Z(_) => 1, | ^^^^^^^^^^^^^^ @@ -167,7 +170,7 @@ LL ~ Foo::Z(_) | Foo::X(0) => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:248:9 + --> tests/ui/match_same_arms2.rs:257:9 | LL | Some(Bar { y: 0, x: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +184,7 @@ LL ~ Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:262:9 + --> tests/ui/match_same_arms2.rs:272:9 | LL | 1 => cfg!(not_enable), | ^^^^^^^^^^^^^^^^^^^^^ @@ -195,7 +198,7 @@ LL + 1 | 0 => cfg!(not_enable), | error: this match arm has an identical body to another arm - --> tests/ui/match_same_arms2.rs:278:17 + --> tests/ui/match_same_arms2.rs:289:17 | LL | MaybeStaticStr::Borrowed(s) => s, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed index 804c0a869a9ff..0c9398933b80e 100644 --- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed +++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed @@ -41,7 +41,7 @@ pub fn g(x: Ordering) { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm + //~^ match_same_arms _ => repeat(), } } @@ -54,7 +54,7 @@ mod g { Ordering::Relaxed => println!("relaxed"), Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm + //~^ match_same_arms _ => repeat(), } } diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs index e50663932a1a6..304a9e5c28e76 100644 --- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs +++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs @@ -42,7 +42,7 @@ pub fn g(x: Ordering) { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm + //~^ match_same_arms _ => repeat(), } } @@ -56,7 +56,7 @@ mod g { Ordering::Release => println!("release"), Ordering::Acquire => println!("acquire"), Ordering::AcqRel | Ordering::SeqCst => repeat(), - //~^ ERROR: this match arm has an identical body to the `_` wildcard arm + //~^ match_same_arms _ => repeat(), } } diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs index ff2f842ac39ee..ada51254c6cdf 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.rs +++ b/src/tools/clippy/tests/ui/match_single_binding.rs @@ -31,12 +31,14 @@ fn main() { let c = 3; // Lint match (a, b, c) { + //~^ match_single_binding (x, y, z) => { println!("{} {} {}", x, y, z); }, } // Lint match (a, b, c) { + //~^ match_single_binding (x, y, z) => println!("{} {} {}", x, y, z), } // Ok @@ -54,10 +56,12 @@ fn main() { } // Lint match a { + //~^ match_single_binding _ => println!("whatever"), } // Lint match a { + //~^ match_single_binding _ => { let x = 29; println!("x has a value of {}", x); @@ -65,6 +69,7 @@ fn main() { } // Lint match a { + //~^ match_single_binding _ => { let e = 5 * a; if e >= 5 { @@ -75,24 +80,29 @@ fn main() { // Lint let p = Point { x: 0, y: 7 }; match p { + //~^ match_single_binding Point { x, y } => println!("Coords: ({}, {})", x, y), } // Lint match p { + //~^ match_single_binding Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1), } // Lint let x = 5; match x { + //~^ match_single_binding ref r => println!("Got a reference to {}", r), } // Lint let mut x = 5; match x { + //~^ match_single_binding ref mut mr => println!("Got a mutable reference to {}", mr), } // Lint let product = match coords() { + //~^ match_single_binding Point { x, y } => x * y, }; // Lint @@ -101,6 +111,7 @@ fn main() { let _ = v .iter() .map(|i| match i.unwrap() { + //~^ match_single_binding unwrapped => unwrapped, }) .collect::>(); @@ -127,6 +138,7 @@ fn main() { // Lint let x = 1; match x { + //~^ match_single_binding // => _ => println!("Not an array index start"), } @@ -136,6 +148,7 @@ fn issue_8723() { let (mut val, idx) = ("a b", 1); val = match val.split_at(idx) { + //~^ match_single_binding (pre, suf) => { println!("{}", pre); suf @@ -149,12 +162,14 @@ fn side_effects() {} fn issue_9575() { let _ = || match side_effects() { + //~^ match_single_binding _ => println!("Needs curlies"), }; } fn issue_9725(r: Option) { match r { + //~^ match_single_binding x => match x { Some(_) => { println!("Some"); @@ -168,37 +183,46 @@ fn issue_9725(r: Option) { fn issue_10447() -> usize { match 1 { + //~^ match_single_binding _ => (), } let a = match 1 { + //~^ match_single_binding _ => (), }; match 1 { + //~^ match_single_binding _ => side_effects(), } let b = match 1 { + //~^ match_single_binding _ => side_effects(), }; match 1 { + //~^ match_single_binding _ => println!("1"), } let c = match 1 { + //~^ match_single_binding _ => println!("1"), }; let in_expr = [ match 1 { + //~^ match_single_binding _ => (), }, match 1 { + //~^ match_single_binding _ => side_effects(), }, match 1 { + //~^ match_single_binding _ => println!("1"), }, ]; diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr index 19ab85180ad28..7e1ec32dac2ff 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding.stderr @@ -2,6 +2,7 @@ error: this match could be written as a `let` statement --> tests/ui/match_single_binding.rs:33:5 | LL | / match (a, b, c) { +LL | | LL | | (x, y, z) => { LL | | println!("{} {} {}", x, y, z); LL | | }, @@ -19,9 +20,10 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:39:5 + --> tests/ui/match_single_binding.rs:40:5 | LL | / match (a, b, c) { +LL | | LL | | (x, y, z) => println!("{} {} {}", x, y, z), LL | | } | |_____^ @@ -33,17 +35,19 @@ LL + println!("{} {} {}", x, y, z); | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:56:5 + --> tests/ui/match_single_binding.rs:58:5 | LL | / match a { +LL | | LL | | _ => println!("whatever"), LL | | } | |_____^ help: consider using the match body instead: `println!("whatever");` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:60:5 + --> tests/ui/match_single_binding.rs:63:5 | LL | / match a { +LL | | LL | | _ => { LL | | let x = 29; LL | | println!("x has a value of {}", x); @@ -60,12 +64,12 @@ LL + } | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:67:5 + --> tests/ui/match_single_binding.rs:71:5 | LL | / match a { +LL | | LL | | _ => { LL | | let e = 5 * a; -LL | | if e >= 5 { ... | LL | | }, LL | | } @@ -82,9 +86,10 @@ LL + } | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:77:5 + --> tests/ui/match_single_binding.rs:82:5 | LL | / match p { +LL | | LL | | Point { x, y } => println!("Coords: ({}, {})", x, y), LL | | } | |_____^ @@ -96,9 +101,10 @@ LL + println!("Coords: ({}, {})", x, y); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:81:5 + --> tests/ui/match_single_binding.rs:87:5 | LL | / match p { +LL | | LL | | Point { x: x1, y: y1 } => println!("Coords: ({}, {})", x1, y1), LL | | } | |_____^ @@ -110,9 +116,10 @@ LL + println!("Coords: ({}, {})", x1, y1); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:86:5 + --> tests/ui/match_single_binding.rs:93:5 | LL | / match x { +LL | | LL | | ref r => println!("Got a reference to {}", r), LL | | } | |_____^ @@ -124,9 +131,10 @@ LL + println!("Got a reference to {}", r); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:91:5 + --> tests/ui/match_single_binding.rs:99:5 | LL | / match x { +LL | | LL | | ref mut mr => println!("Got a mutable reference to {}", mr), LL | | } | |_____^ @@ -138,9 +146,10 @@ LL + println!("Got a mutable reference to {}", mr); | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:95:5 + --> tests/ui/match_single_binding.rs:104:5 | LL | / let product = match coords() { +LL | | LL | | Point { x, y } => x * y, LL | | }; | |______^ @@ -152,10 +161,11 @@ LL + let product = x * y; | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:103:18 + --> tests/ui/match_single_binding.rs:113:18 | LL | .map(|i| match i.unwrap() { | __________________^ +LL | | LL | | unwrapped => unwrapped, LL | | }) | |_________^ @@ -169,18 +179,20 @@ LL ~ }) | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:129:5 + --> tests/ui/match_single_binding.rs:140:5 | LL | / match x { +LL | | LL | | // => LL | | _ => println!("Not an array index start"), LL | | } | |_____^ help: consider using the match body instead: `println!("Not an array index start")` error: this assignment could be simplified - --> tests/ui/match_single_binding.rs:138:5 + --> tests/ui/match_single_binding.rs:150:5 | LL | / val = match val.split_at(idx) { +LL | | LL | | (pre, suf) => { LL | | println!("{}", pre); LL | | suf @@ -198,10 +210,11 @@ LL ~ }; | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding.rs:151:16 + --> tests/ui/match_single_binding.rs:164:16 | LL | let _ = || match side_effects() { | ________________^ +LL | | LL | | _ => println!("Needs curlies"), LL | | }; | |_____^ @@ -215,12 +228,12 @@ LL ~ }; | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding.rs:157:5 + --> tests/ui/match_single_binding.rs:171:5 | LL | / match r { +LL | | LL | | x => match x { LL | | Some(_) => { -LL | | println!("Some"); ... | LL | | }, LL | | }; @@ -240,76 +253,85 @@ LL ~ }; | error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:170:5 + --> tests/ui/match_single_binding.rs:185:5 | LL | / match 1 { +LL | | LL | | _ => (), LL | | } | |_____^ help: consider using the match body instead: `();` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:174:13 + --> tests/ui/match_single_binding.rs:190:13 | LL | let a = match 1 { | _____________^ +LL | | LL | | _ => (), LL | | }; | |_____^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:178:5 + --> tests/ui/match_single_binding.rs:195:5 | LL | / match 1 { +LL | | LL | | _ => side_effects(), LL | | } | |_____^ help: consider using the match body instead: `side_effects();` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:182:13 + --> tests/ui/match_single_binding.rs:200:13 | LL | let b = match 1 { | _____________^ +LL | | LL | | _ => side_effects(), LL | | }; | |_____^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:186:5 + --> tests/ui/match_single_binding.rs:205:5 | LL | / match 1 { +LL | | LL | | _ => println!("1"), LL | | } | |_____^ help: consider using the match body instead: `println!("1");` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:190:13 + --> tests/ui/match_single_binding.rs:210:13 | LL | let c = match 1 { | _____________^ +LL | | LL | | _ => println!("1"), LL | | }; | |_____^ help: consider using the match body instead: `println!("1")` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:195:9 + --> tests/ui/match_single_binding.rs:216:9 | LL | / match 1 { +LL | | LL | | _ => (), LL | | }, | |_________^ help: consider using the match body instead: `()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:198:9 + --> tests/ui/match_single_binding.rs:220:9 | LL | / match 1 { +LL | | LL | | _ => side_effects(), LL | | }, | |_________^ help: consider using the match body instead: `side_effects()` error: this match could be replaced by its body itself - --> tests/ui/match_single_binding.rs:201:9 + --> tests/ui/match_single_binding.rs:224:9 | LL | / match 1 { +LL | | LL | | _ => println!("1"), LL | | }, | |_________^ help: consider using the match body instead: `println!("1")` diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed index 5673aa78c76ae..988121f50d0fa 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed @@ -45,6 +45,7 @@ fn main() { // issue #7094 let x = 1; match x { + //~^ match_single_binding 0 => 1, _ => 2, }; diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs index 575e7f5816b8b..a4fb2bd6f3817 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.rs +++ b/src/tools/clippy/tests/ui/match_single_binding2.rs @@ -15,6 +15,7 @@ fn main() { fn size_hint(iter: &AppendIter) -> (usize, Option) { match &iter.inner { Some((iter, _item)) => match iter.size_hint() { + //~^ match_single_binding (min, max) => (min.saturating_add(1), max.and_then(|max| max.checked_add(1))), }, None => (0, Some(0)), @@ -28,6 +29,7 @@ fn main() { #[rustfmt::skip] Some((first, _second)) => { match get_tup() { + //~^ match_single_binding (a, b) => println!("a {:?} and b {:?}", a, b), } }, @@ -39,6 +41,7 @@ fn main() { // Lint (scrutinee has side effects) // issue #7094 match side_effects() { + //~^ match_single_binding _ => println!("Side effects"), } @@ -46,6 +49,7 @@ fn main() { // issue #7094 let x = 1; match match x { + //~^ match_single_binding 0 => 1, _ => 2, } { diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr index 38659596af1ff..a24cbe3eed766 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr @@ -3,6 +3,7 @@ error: this match could be written as a `let` statement | LL | Some((iter, _item)) => match iter.size_hint() { | ____________________________________^ +LL | | LL | | (min, max) => (min.saturating_add(1), max.and_then(|max| max.checked_add(1))), LL | | }, | |_____________^ @@ -18,9 +19,10 @@ LL ~ }, | error: this match could be written as a `let` statement - --> tests/ui/match_single_binding2.rs:30:13 + --> tests/ui/match_single_binding2.rs:31:13 | LL | / match get_tup() { +LL | | LL | | (a, b) => println!("a {:?} and b {:?}", a, b), LL | | } | |_____________^ @@ -32,9 +34,10 @@ LL + println!("a {:?} and b {:?}", a, b) | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding2.rs:41:5 + --> tests/ui/match_single_binding2.rs:43:5 | LL | / match side_effects() { +LL | | LL | | _ => println!("Side effects"), LL | | } | |_____^ @@ -46,9 +49,10 @@ LL + println!("Side effects"); | error: this match could be replaced by its scrutinee and body - --> tests/ui/match_single_binding2.rs:48:5 + --> tests/ui/match_single_binding2.rs:51:5 | LL | / match match x { +LL | | LL | | 0 => 1, LL | | _ => 2, LL | | } { @@ -59,6 +63,7 @@ LL | | } help: consider using the scrutinee and body instead | LL ~ match x { +LL + LL + 0 => 1, LL + _ => 2, LL + }; diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed b/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed index a608ab0c0cb05..5f41f29f8a466 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed @@ -110,6 +110,7 @@ fn as_str_match_mismatch() { match var.to_ascii_lowercase().as_str() { "foo" => {}, "bar" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -120,6 +121,7 @@ fn non_alphabetic_mismatch() { match var.to_ascii_lowercase().as_str() { "1234567890" => {}, "~!@#$%^&*()-_=+foo" => {}, + //~^ match_str_case_mismatch "\n\r\t\x7F" => {}, _ => {}, } @@ -132,6 +134,7 @@ fn unicode_cased_mismatch() { "水" => {}, "νερό" => {}, "воды" => {}, + //~^ match_str_case_mismatch "물" => {}, _ => {}, } @@ -143,6 +146,7 @@ fn titlecase_mismatch() { match var.to_lowercase().as_str() { "foolj" => {}, "bardz" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -153,6 +157,7 @@ fn no_case_equivalent_mismatch() { match var.to_uppercase().as_str() { "FOOɕ" => {}, "BARʁ" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -163,6 +168,7 @@ fn addrof_unary_match_mismatch() { match &*var.to_ascii_lowercase() { "foo" => {}, "bar" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -178,6 +184,7 @@ fn alternating_chain_mismatch() { { "FOO" => {}, "BAR" => {}, + //~^ match_str_case_mismatch _ => {}, } } diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.rs b/src/tools/clippy/tests/ui/match_str_case_mismatch.rs index 1e4269d1db5de..fa5d5a8ebc317 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.rs +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.rs @@ -110,6 +110,7 @@ fn as_str_match_mismatch() { match var.to_ascii_lowercase().as_str() { "foo" => {}, "Bar" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -120,6 +121,7 @@ fn non_alphabetic_mismatch() { match var.to_ascii_lowercase().as_str() { "1234567890" => {}, "~!@#$%^&*()-_=+Foo" => {}, + //~^ match_str_case_mismatch "\n\r\t\x7F" => {}, _ => {}, } @@ -132,6 +134,7 @@ fn unicode_cased_mismatch() { "水" => {}, "νερό" => {}, "Воды" => {}, + //~^ match_str_case_mismatch "물" => {}, _ => {}, } @@ -143,6 +146,7 @@ fn titlecase_mismatch() { match var.to_lowercase().as_str() { "foolj" => {}, "barDz" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -153,6 +157,7 @@ fn no_case_equivalent_mismatch() { match var.to_uppercase().as_str() { "FOOɕ" => {}, "bARʁ" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -163,6 +168,7 @@ fn addrof_unary_match_mismatch() { match &*var.to_ascii_lowercase() { "foo" => {}, "Bar" => {}, + //~^ match_str_case_mismatch _ => {}, } } @@ -178,6 +184,7 @@ fn alternating_chain_mismatch() { { "FOO" => {}, "bAR" => {}, + //~^ match_str_case_mismatch _ => {}, } } diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr index 5b14fd13a53b1..8068edfff947f 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.stderr @@ -13,7 +13,7 @@ LL + "bar" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:122:9 + --> tests/ui/match_str_case_mismatch.rs:123:9 | LL | "~!@#$%^&*()-_=+Foo" => {}, | ^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + "~!@#$%^&*()-_=+foo" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:134:9 + --> tests/ui/match_str_case_mismatch.rs:136:9 | LL | "Воды" => {}, | ^^^^^^ @@ -37,7 +37,7 @@ LL + "воды" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:145:9 + --> tests/ui/match_str_case_mismatch.rs:148:9 | LL | "barDz" => {}, | ^^^^^^ @@ -49,7 +49,7 @@ LL + "bardz" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:155:9 + --> tests/ui/match_str_case_mismatch.rs:159:9 | LL | "bARʁ" => {}, | ^^^^^^ @@ -61,7 +61,7 @@ LL + "BARʁ" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:165:9 + --> tests/ui/match_str_case_mismatch.rs:170:9 | LL | "Bar" => {}, | ^^^^^ @@ -73,7 +73,7 @@ LL + "bar" => {}, | error: this `match` arm has a differing case than its expression - --> tests/ui/match_str_case_mismatch.rs:180:9 + --> tests/ui/match_str_case_mismatch.rs:186:9 | LL | "bAR" => {}, | ^^^^^ diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.rs b/src/tools/clippy/tests/ui/match_wild_err_arm.rs index 8e670ce5bda2c..d18d4047e2a64 100644 --- a/src/tools/clippy/tests/ui/match_wild_err_arm.rs +++ b/src/tools/clippy/tests/ui/match_wild_err_arm.rs @@ -21,24 +21,22 @@ fn match_wild_err_arm() { Ok(3) => println!("ok"), Ok(_) => println!("ok"), Err(_) => panic!("err"), - //~^ ERROR: `Err(_)` matches all errors - //~| NOTE: match each error separately or use the error output, or use `.expect(ms + //~^ match_wild_err_arm } match x { Ok(3) => println!("ok"), Ok(_) => println!("ok"), Err(_) => panic!(), - //~^ ERROR: `Err(_)` matches all errors - //~| NOTE: match each error separately or use the error output, or use `.expect(ms + //~^ match_wild_err_arm } match x { Ok(3) => println!("ok"), Ok(_) => println!("ok"), Err(_) => { - //~^ ERROR: `Err(_)` matches all errors - //~| NOTE: match each error separately or use the error output, or use `.expect(ms + //~^ match_wild_err_arm + panic!(); }, } @@ -47,8 +45,7 @@ fn match_wild_err_arm() { Ok(3) => println!("ok"), Ok(_) => println!("ok"), Err(_e) => panic!(), - //~^ ERROR: `Err(_e)` matches all errors - //~| NOTE: match each error separately or use the error output, or use `.expect(ms + //~^ match_wild_err_arm } // Allowed when used in `panic!`. diff --git a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr index f98065d9a591f..fc65924f0873c 100644 --- a/src/tools/clippy/tests/ui/match_wild_err_arm.stderr +++ b/src/tools/clippy/tests/ui/match_wild_err_arm.stderr @@ -9,7 +9,7 @@ LL | Err(_) => panic!("err"), = help: to override `-D warnings` add `#[allow(clippy::match_wild_err_arm)]` error: `Err(_)` matches all errors - --> tests/ui/match_wild_err_arm.rs:31:9 + --> tests/ui/match_wild_err_arm.rs:30:9 | LL | Err(_) => panic!(), | ^^^^^^ @@ -17,7 +17,7 @@ LL | Err(_) => panic!(), = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_)` matches all errors - --> tests/ui/match_wild_err_arm.rs:39:9 + --> tests/ui/match_wild_err_arm.rs:37:9 | LL | Err(_) => { | ^^^^^^ @@ -25,7 +25,7 @@ LL | Err(_) => { = note: match each error separately or use the error output, or use `.expect(msg)` if the error case is unreachable error: `Err(_e)` matches all errors - --> tests/ui/match_wild_err_arm.rs:49:9 + --> tests/ui/match_wild_err_arm.rs:47:9 | LL | Err(_e) => panic!(), | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed index e5ea2fdde82fd..c34f49df6549f 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed @@ -20,6 +20,7 @@ impl Color { Self::Green => (), Self::Blue => (), Self::Rgb(..) => (), + //~^ match_wildcard_for_single_variants }; } } @@ -30,6 +31,7 @@ fn main() { Foo::A => {}, Foo::B => {}, Foo::C => {}, + //~^ match_wildcard_for_single_variants } let color = Color::Red; @@ -40,6 +42,7 @@ fn main() { Color::Green => {}, Color::Rgb(_r, _g, _b) => {}, Color::Blue => {}, + //~^ match_wildcard_for_single_variants } // check exhaustive wild @@ -48,12 +51,14 @@ fn main() { Color::Green => {}, Color::Rgb(..) => {}, Color::Blue => {}, + //~^ match_wildcard_for_single_variants } match color { Color::Red => {}, Color::Green => {}, Color::Rgb(_, _, _) => {}, Color::Blue => {}, + //~^ match_wildcard_for_single_variants } // shouldn't lint as there is one missing variant @@ -71,6 +76,7 @@ fn main() { Color::Green => (), &Color::Rgb(..) => (), Color::Blue => (), + //~^ match_wildcard_for_single_variants } use self::Color as C; @@ -80,6 +86,7 @@ fn main() { C::Green => (), C::Rgb(..) => (), C::Blue => (), + //~^ match_wildcard_for_single_variants } match color { @@ -87,6 +94,7 @@ fn main() { Color::Green => (), Color::Rgb(..) => (), Color::Blue => (), + //~^ match_wildcard_for_single_variants } match Some(0) { @@ -122,6 +130,7 @@ fn main() { Enum::B => (), Enum::C => (), Enum::__Private => (), + //~^ match_wildcard_for_single_variants } match Enum::A { Enum::A => (), @@ -149,6 +158,7 @@ mod issue9993 { _ if false => 0, Foo::A(_) => 1, Foo::B => 2, + //~^ match_wildcard_for_single_variants }; } } diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs index dbd7fbe160f02..ecdb7d2fa3af2 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs @@ -20,6 +20,7 @@ impl Color { Self::Green => (), Self::Blue => (), _ => (), + //~^ match_wildcard_for_single_variants }; } } @@ -30,6 +31,7 @@ fn main() { Foo::A => {}, Foo::B => {}, _ => {}, + //~^ match_wildcard_for_single_variants } let color = Color::Red; @@ -40,6 +42,7 @@ fn main() { Color::Green => {}, Color::Rgb(_r, _g, _b) => {}, _ => {}, + //~^ match_wildcard_for_single_variants } // check exhaustive wild @@ -48,12 +51,14 @@ fn main() { Color::Green => {}, Color::Rgb(..) => {}, _ => {}, + //~^ match_wildcard_for_single_variants } match color { Color::Red => {}, Color::Green => {}, Color::Rgb(_, _, _) => {}, _ => {}, + //~^ match_wildcard_for_single_variants } // shouldn't lint as there is one missing variant @@ -71,6 +76,7 @@ fn main() { Color::Green => (), &Color::Rgb(..) => (), &_ => (), + //~^ match_wildcard_for_single_variants } use self::Color as C; @@ -80,6 +86,7 @@ fn main() { C::Green => (), C::Rgb(..) => (), _ => (), + //~^ match_wildcard_for_single_variants } match color { @@ -87,6 +94,7 @@ fn main() { Color::Green => (), Color::Rgb(..) => (), _ => (), + //~^ match_wildcard_for_single_variants } match Some(0) { @@ -122,6 +130,7 @@ fn main() { Enum::B => (), Enum::C => (), _ => (), + //~^ match_wildcard_for_single_variants } match Enum::A { Enum::A => (), @@ -149,6 +158,7 @@ mod issue9993 { _ if false => 0, Foo::A(_) => 1, _ => 2, + //~^ match_wildcard_for_single_variants }; } } diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr index 5cc50c823b2ca..3c0cc53b1bf27 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr @@ -8,55 +8,55 @@ LL | _ => (), = help: to override `-D warnings` add `#[allow(clippy::match_wildcard_for_single_variants)]` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:32:9 + --> tests/ui/match_wildcard_for_single_variants.rs:33:9 | LL | _ => {}, | ^ help: try: `Foo::C` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:42:9 + --> tests/ui/match_wildcard_for_single_variants.rs:44:9 | LL | _ => {}, | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:50:9 + --> tests/ui/match_wildcard_for_single_variants.rs:53:9 | LL | _ => {}, | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:56:9 + --> tests/ui/match_wildcard_for_single_variants.rs:60:9 | LL | _ => {}, | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:73:9 + --> tests/ui/match_wildcard_for_single_variants.rs:78:9 | LL | &_ => (), | ^^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:82:9 + --> tests/ui/match_wildcard_for_single_variants.rs:88:9 | LL | _ => (), | ^ help: try: `C::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:89:9 + --> tests/ui/match_wildcard_for_single_variants.rs:96:9 | LL | _ => (), | ^ help: try: `Color::Blue` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:124:13 + --> tests/ui/match_wildcard_for_single_variants.rs:132:13 | LL | _ => (), | ^ help: try: `Enum::__Private` error: wildcard matches only a single variant and will also match any future added variants - --> tests/ui/match_wildcard_for_single_variants.rs:151:13 + --> tests/ui/match_wildcard_for_single_variants.rs:160:13 | LL | _ => 2, | ^ help: try: `Foo::B` diff --git a/src/tools/clippy/tests/ui/mem_forget.rs b/src/tools/clippy/tests/ui/mem_forget.rs index 1f508b3bca289..b510af8ac6f16 100644 --- a/src/tools/clippy/tests/ui/mem_forget.rs +++ b/src/tools/clippy/tests/ui/mem_forget.rs @@ -12,23 +12,19 @@ fn main() { let six: Arc = Arc::new(6); memstuff::forget(six); - //~^ ERROR: usage of `mem::forget` on `Drop` type - //~| NOTE: argument has type `std::sync::Arc` + //~^ mem_forget let seven: Rc = Rc::new(7); std::mem::forget(seven); - //~^ ERROR: usage of `mem::forget` on `Drop` type - //~| NOTE: argument has type `std::rc::Rc` + //~^ mem_forget let eight: Vec = vec![8]; forgetSomething(eight); - //~^ ERROR: usage of `mem::forget` on `Drop` type - //~| NOTE: argument has type `std::vec::Vec` + //~^ mem_forget let string = String::new(); std::mem::forget(string); - //~^ ERROR: usage of `mem::forget` on type with `Drop` fields - //~| NOTE: argument has type `std::string::String` + //~^ mem_forget std::mem::forget(7); } diff --git a/src/tools/clippy/tests/ui/mem_forget.stderr b/src/tools/clippy/tests/ui/mem_forget.stderr index 3b0e839e0871a..049db54a04b0e 100644 --- a/src/tools/clippy/tests/ui/mem_forget.stderr +++ b/src/tools/clippy/tests/ui/mem_forget.stderr @@ -9,7 +9,7 @@ LL | memstuff::forget(six); = help: to override `-D warnings` add `#[allow(clippy::mem_forget)]` error: usage of `mem::forget` on `Drop` type - --> tests/ui/mem_forget.rs:19:5 + --> tests/ui/mem_forget.rs:18:5 | LL | std::mem::forget(seven); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | std::mem::forget(seven); = note: argument has type `std::rc::Rc` error: usage of `mem::forget` on `Drop` type - --> tests/ui/mem_forget.rs:24:5 + --> tests/ui/mem_forget.rs:22:5 | LL | forgetSomething(eight); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | forgetSomething(eight); = note: argument has type `std::vec::Vec` error: usage of `mem::forget` on type with `Drop` fields - --> tests/ui/mem_forget.rs:29:5 + --> tests/ui/mem_forget.rs:26:5 | LL | std::mem::forget(string); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed index 4210dbbe82d37..870ef23113a2f 100644 --- a/src/tools/clippy/tests/ui/mem_replace.fixed +++ b/src/tools/clippy/tests/ui/mem_replace.fixed @@ -11,53 +11,76 @@ use std::mem; fn replace_option_with_none() { let mut an_option = Some(1); let _ = an_option.take(); + //~^ mem_replace_option_with_none let an_option = &mut Some(1); let _ = an_option.take(); + //~^ mem_replace_option_with_none } fn replace_with_default() { let mut s = String::from("foo"); let _ = std::mem::take(&mut s); + //~^ mem_replace_with_default + let _ = std::mem::take(&mut s); + //~^ mem_replace_with_default let s = &mut String::from("foo"); let _ = std::mem::take(s); + //~^ mem_replace_with_default + let _ = std::mem::take(s); + //~^ mem_replace_with_default let _ = std::mem::take(s); + //~^ mem_replace_with_default let mut v = vec![123]; let _ = std::mem::take(&mut v); + //~^ mem_replace_with_default let _ = std::mem::take(&mut v); + //~^ mem_replace_with_default let _ = std::mem::take(&mut v); + //~^ mem_replace_with_default let _ = std::mem::take(&mut v); + //~^ mem_replace_with_default let mut hash_map: HashMap = HashMap::new(); let _ = std::mem::take(&mut hash_map); + //~^ mem_replace_with_default let mut btree_map: BTreeMap = BTreeMap::new(); let _ = std::mem::take(&mut btree_map); + //~^ mem_replace_with_default let mut vd: VecDeque = VecDeque::new(); let _ = std::mem::take(&mut vd); + //~^ mem_replace_with_default let mut hash_set: HashSet<&str> = HashSet::new(); let _ = std::mem::take(&mut hash_set); + //~^ mem_replace_with_default let mut btree_set: BTreeSet<&str> = BTreeSet::new(); let _ = std::mem::take(&mut btree_set); + //~^ mem_replace_with_default let mut list: LinkedList = LinkedList::new(); let _ = std::mem::take(&mut list); + //~^ mem_replace_with_default let mut binary_heap: BinaryHeap = BinaryHeap::new(); let _ = std::mem::take(&mut binary_heap); + //~^ mem_replace_with_default let mut tuple = (vec![1, 2], BinaryHeap::::new()); let _ = std::mem::take(&mut tuple); + //~^ mem_replace_with_default let mut refstr = "hello"; let _ = std::mem::take(&mut refstr); + //~^ mem_replace_with_default let mut slice: &[i32] = &[1, 2, 3]; let _ = std::mem::take(&mut slice); + //~^ mem_replace_with_default } // lint is disabled for primitives because in this case `take` @@ -94,6 +117,7 @@ fn msrv_1_39() { fn msrv_1_40() { let mut s = String::from("foo"); let _ = std::mem::take(&mut s); + //~^ mem_replace_with_default } fn issue9824() { @@ -124,8 +148,34 @@ fn issue9824() { // replace option with none let _ = f.0.take(); + //~^ mem_replace_option_with_none let _ = (*f).take(); + //~^ mem_replace_option_with_none let _ = b.opt.take(); + //~^ mem_replace_option_with_none // replace with default let _ = std::mem::take(&mut b.val); + //~^ mem_replace_with_default +} + +#[clippy::msrv = "1.31"] +fn mem_replace_option_with_some() { + let mut an_option = Some(0); + let replaced = an_option.replace(1); + //~^ ERROR: replacing an `Option` with `Some(..)` + + let mut an_option = &mut Some(0); + let replaced = an_option.replace(1); + //~^ ERROR: replacing an `Option` with `Some(..)` + + let (mut opt1, mut opt2) = (Some(0), Some(0)); + let b = true; + let replaced = (if b { &mut opt1 } else { &mut opt2 }).replace(1); + //~^ ERROR: replacing an `Option` with `Some(..)` +} + +#[clippy::msrv = "1.30"] +fn mem_replace_option_with_some_bad_msrv() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); } diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs index bd7ad78b2af26..b4ed5eafea953 100644 --- a/src/tools/clippy/tests/ui/mem_replace.rs +++ b/src/tools/clippy/tests/ui/mem_replace.rs @@ -11,53 +11,76 @@ use std::mem; fn replace_option_with_none() { let mut an_option = Some(1); let _ = mem::replace(&mut an_option, None); + //~^ mem_replace_option_with_none let an_option = &mut Some(1); let _ = mem::replace(an_option, None); + //~^ mem_replace_option_with_none } fn replace_with_default() { let mut s = String::from("foo"); let _ = std::mem::replace(&mut s, String::default()); + //~^ mem_replace_with_default + let _ = std::mem::replace(&mut s, String::new()); + //~^ mem_replace_with_default let s = &mut String::from("foo"); let _ = std::mem::replace(s, String::default()); + //~^ mem_replace_with_default + let _ = std::mem::replace(s, String::new()); + //~^ mem_replace_with_default let _ = std::mem::replace(s, Default::default()); + //~^ mem_replace_with_default let mut v = vec![123]; let _ = std::mem::replace(&mut v, Vec::default()); + //~^ mem_replace_with_default let _ = std::mem::replace(&mut v, Default::default()); + //~^ mem_replace_with_default let _ = std::mem::replace(&mut v, Vec::new()); + //~^ mem_replace_with_default let _ = std::mem::replace(&mut v, vec![]); + //~^ mem_replace_with_default let mut hash_map: HashMap = HashMap::new(); let _ = std::mem::replace(&mut hash_map, HashMap::new()); + //~^ mem_replace_with_default let mut btree_map: BTreeMap = BTreeMap::new(); let _ = std::mem::replace(&mut btree_map, BTreeMap::new()); + //~^ mem_replace_with_default let mut vd: VecDeque = VecDeque::new(); let _ = std::mem::replace(&mut vd, VecDeque::new()); + //~^ mem_replace_with_default let mut hash_set: HashSet<&str> = HashSet::new(); let _ = std::mem::replace(&mut hash_set, HashSet::new()); + //~^ mem_replace_with_default let mut btree_set: BTreeSet<&str> = BTreeSet::new(); let _ = std::mem::replace(&mut btree_set, BTreeSet::new()); + //~^ mem_replace_with_default let mut list: LinkedList = LinkedList::new(); let _ = std::mem::replace(&mut list, LinkedList::new()); + //~^ mem_replace_with_default let mut binary_heap: BinaryHeap = BinaryHeap::new(); let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); + //~^ mem_replace_with_default let mut tuple = (vec![1, 2], BinaryHeap::::new()); let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new())); + //~^ mem_replace_with_default let mut refstr = "hello"; let _ = std::mem::replace(&mut refstr, ""); + //~^ mem_replace_with_default let mut slice: &[i32] = &[1, 2, 3]; let _ = std::mem::replace(&mut slice, &[]); + //~^ mem_replace_with_default } // lint is disabled for primitives because in this case `take` @@ -94,6 +117,7 @@ fn msrv_1_39() { fn msrv_1_40() { let mut s = String::from("foo"); let _ = std::mem::replace(&mut s, String::default()); + //~^ mem_replace_with_default } fn issue9824() { @@ -124,8 +148,34 @@ fn issue9824() { // replace option with none let _ = std::mem::replace(&mut f.0, None); + //~^ mem_replace_option_with_none let _ = std::mem::replace(&mut *f, None); + //~^ mem_replace_option_with_none let _ = std::mem::replace(&mut b.opt, None); + //~^ mem_replace_option_with_none // replace with default let _ = std::mem::replace(&mut b.val, String::default()); + //~^ mem_replace_with_default +} + +#[clippy::msrv = "1.31"] +fn mem_replace_option_with_some() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); + //~^ ERROR: replacing an `Option` with `Some(..)` + + let mut an_option = &mut Some(0); + let replaced = mem::replace(an_option, Some(1)); + //~^ ERROR: replacing an `Option` with `Some(..)` + + let (mut opt1, mut opt2) = (Some(0), Some(0)); + let b = true; + let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); + //~^ ERROR: replacing an `Option` with `Some(..)` +} + +#[clippy::msrv = "1.30"] +fn mem_replace_option_with_some_bad_msrv() { + let mut an_option = Some(0); + let replaced = mem::replace(&mut an_option, Some(1)); } diff --git a/src/tools/clippy/tests/ui/mem_replace.stderr b/src/tools/clippy/tests/ui/mem_replace.stderr index c33f80b01b852..fb4a367266d30 100644 --- a/src/tools/clippy/tests/ui/mem_replace.stderr +++ b/src/tools/clippy/tests/ui/mem_replace.stderr @@ -8,13 +8,13 @@ LL | let _ = mem::replace(&mut an_option, None); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:15:13 + --> tests/ui/mem_replace.rs:16:13 | LL | let _ = mem::replace(an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:20:13 + --> tests/ui/mem_replace.rs:22:13 | LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` @@ -23,130 +23,163 @@ LL | let _ = std::mem::replace(&mut s, String::default()); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:23:13 + --> tests/ui/mem_replace.rs:24:13 + | +LL | let _ = std::mem::replace(&mut s, String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> tests/ui/mem_replace.rs:28:13 | LL | let _ = std::mem::replace(s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:24:13 + --> tests/ui/mem_replace.rs:30:13 + | +LL | let _ = std::mem::replace(s, String::new()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` + +error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` + --> tests/ui/mem_replace.rs:32:13 | LL | let _ = std::mem::replace(s, Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(s)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:27:13 + --> tests/ui/mem_replace.rs:36:13 | LL | let _ = std::mem::replace(&mut v, Vec::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:28:13 + --> tests/ui/mem_replace.rs:38:13 | LL | let _ = std::mem::replace(&mut v, Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:29:13 + --> tests/ui/mem_replace.rs:40:13 | LL | let _ = std::mem::replace(&mut v, Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:30:13 + --> tests/ui/mem_replace.rs:42:13 | LL | let _ = std::mem::replace(&mut v, vec![]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut v)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:33:13 + --> tests/ui/mem_replace.rs:46:13 | LL | let _ = std::mem::replace(&mut hash_map, HashMap::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_map)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:36:13 + --> tests/ui/mem_replace.rs:50:13 | LL | let _ = std::mem::replace(&mut btree_map, BTreeMap::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_map)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:39:13 + --> tests/ui/mem_replace.rs:54:13 | LL | let _ = std::mem::replace(&mut vd, VecDeque::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut vd)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:42:13 + --> tests/ui/mem_replace.rs:58:13 | LL | let _ = std::mem::replace(&mut hash_set, HashSet::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut hash_set)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:45:13 + --> tests/ui/mem_replace.rs:62:13 | LL | let _ = std::mem::replace(&mut btree_set, BTreeSet::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut btree_set)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:48:13 + --> tests/ui/mem_replace.rs:66:13 | LL | let _ = std::mem::replace(&mut list, LinkedList::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut list)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:51:13 + --> tests/ui/mem_replace.rs:70:13 | LL | let _ = std::mem::replace(&mut binary_heap, BinaryHeap::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut binary_heap)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:54:13 + --> tests/ui/mem_replace.rs:74:13 | LL | let _ = std::mem::replace(&mut tuple, (vec![], BinaryHeap::new())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut tuple)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:57:13 + --> tests/ui/mem_replace.rs:78:13 | LL | let _ = std::mem::replace(&mut refstr, ""); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut refstr)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:60:13 + --> tests/ui/mem_replace.rs:82:13 | LL | let _ = std::mem::replace(&mut slice, &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut slice)` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:96:13 + --> tests/ui/mem_replace.rs:119:13 | LL | let _ = std::mem::replace(&mut s, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut s)` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:126:13 + --> tests/ui/mem_replace.rs:150:13 | LL | let _ = std::mem::replace(&mut f.0, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:127:13 + --> tests/ui/mem_replace.rs:152:13 | LL | let _ = std::mem::replace(&mut *f, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace.rs:128:13 + --> tests/ui/mem_replace.rs:154:13 | LL | let _ = std::mem::replace(&mut b.opt, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` - --> tests/ui/mem_replace.rs:130:13 + --> tests/ui/mem_replace.rs:157:13 | LL | let _ = std::mem::replace(&mut b.val, String::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut b.val)` -error: aborting due to 24 previous errors +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace.rs:164:20 + | +LL | let replaced = mem::replace(&mut an_option, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)` + | + = note: `-D clippy::mem-replace-option-with-some` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_some)]` + +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace.rs:168:20 + | +LL | let replaced = mem::replace(an_option, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `an_option.replace(1)` + +error: replacing an `Option` with `Some(..)` + --> tests/ui/mem_replace.rs:173:20 + | +LL | let replaced = mem::replace(if b { &mut opt1 } else { &mut opt2 }, Some(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::replace()` instead: `(if b { &mut opt1 } else { &mut opt2 }).replace(1)` + +error: aborting due to 29 previous errors diff --git a/src/tools/clippy/tests/ui/mem_replace_macro.rs b/src/tools/clippy/tests/ui/mem_replace_macro.rs index c14ea2942f3ed..9458dade3a9c7 100644 --- a/src/tools/clippy/tests/ui/mem_replace_macro.rs +++ b/src/tools/clippy/tests/ui/mem_replace_macro.rs @@ -8,5 +8,6 @@ use proc_macros::{external, inline_macros}; fn main() { let s = &mut String::from("foo"); let _ = inline!(std::mem::replace($s, Default::default())); + //~^ mem_replace_with_default let _ = external!(std::mem::replace($s, Default::default())); } diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed index 60f523c8ef1ec..669450e59d8b0 100644 --- a/src/tools/clippy/tests/ui/mem_replace_no_std.fixed +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.fixed @@ -21,16 +21,20 @@ fn panic(info: &PanicInfo) -> ! { fn replace_option_with_none() { let mut an_option = Some(1); let _ = an_option.take(); + //~^ mem_replace_option_with_none let an_option = &mut Some(1); let _ = an_option.take(); + //~^ mem_replace_option_with_none } fn replace_with_default() { let mut refstr = "hello"; let _ = core::mem::take(&mut refstr); + //~^ mem_replace_with_default let mut slice: &[i32] = &[1, 2, 3]; let _ = core::mem::take(&mut slice); + //~^ mem_replace_with_default } // lint is disabled for primitives because in this case `take` @@ -74,8 +78,11 @@ fn issue9824() { // replace option with none let _ = f.0.take(); + //~^ mem_replace_option_with_none let _ = (*f).take(); + //~^ mem_replace_option_with_none let _ = b.opt.take(); + //~^ mem_replace_option_with_none // replace with default let _ = mem::replace(&mut b.val, u8::default()); } diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.rs b/src/tools/clippy/tests/ui/mem_replace_no_std.rs index d1cb9a5817bad..2cdf1df5196ac 100644 --- a/src/tools/clippy/tests/ui/mem_replace_no_std.rs +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.rs @@ -21,16 +21,20 @@ fn panic(info: &PanicInfo) -> ! { fn replace_option_with_none() { let mut an_option = Some(1); let _ = mem::replace(&mut an_option, None); + //~^ mem_replace_option_with_none let an_option = &mut Some(1); let _ = mem::replace(an_option, None); + //~^ mem_replace_option_with_none } fn replace_with_default() { let mut refstr = "hello"; let _ = mem::replace(&mut refstr, ""); + //~^ mem_replace_with_default let mut slice: &[i32] = &[1, 2, 3]; let _ = mem::replace(&mut slice, &[]); + //~^ mem_replace_with_default } // lint is disabled for primitives because in this case `take` @@ -74,8 +78,11 @@ fn issue9824() { // replace option with none let _ = mem::replace(&mut f.0, None); + //~^ mem_replace_option_with_none let _ = mem::replace(&mut *f, None); + //~^ mem_replace_option_with_none let _ = mem::replace(&mut b.opt, None); + //~^ mem_replace_option_with_none // replace with default let _ = mem::replace(&mut b.val, u8::default()); } diff --git a/src/tools/clippy/tests/ui/mem_replace_no_std.stderr b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr index 6ba6d2162a745..926a8288fd31b 100644 --- a/src/tools/clippy/tests/ui/mem_replace_no_std.stderr +++ b/src/tools/clippy/tests/ui/mem_replace_no_std.stderr @@ -8,13 +8,13 @@ LL | let _ = mem::replace(&mut an_option, None); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_option_with_none)]` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:25:13 + --> tests/ui/mem_replace_no_std.rs:26:13 | LL | let _ = mem::replace(an_option, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `an_option.take()` error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` - --> tests/ui/mem_replace_no_std.rs:30:13 + --> tests/ui/mem_replace_no_std.rs:32:13 | LL | let _ = mem::replace(&mut refstr, ""); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut refstr)` @@ -23,25 +23,25 @@ LL | let _ = mem::replace(&mut refstr, ""); = help: to override `-D warnings` add `#[allow(clippy::mem_replace_with_default)]` error: replacing a value of type `T` with `T::default()` is better expressed using `core::mem::take` - --> tests/ui/mem_replace_no_std.rs:33:13 + --> tests/ui/mem_replace_no_std.rs:36:13 | LL | let _ = mem::replace(&mut slice, &[]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `core::mem::take(&mut slice)` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:76:13 + --> tests/ui/mem_replace_no_std.rs:80:13 | LL | let _ = mem::replace(&mut f.0, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `f.0.take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:77:13 + --> tests/ui/mem_replace_no_std.rs:82:13 | LL | let _ = mem::replace(&mut *f, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `(*f).take()` error: replacing an `Option` with `None` - --> tests/ui/mem_replace_no_std.rs:78:13 + --> tests/ui/mem_replace_no_std.rs:84:13 | LL | let _ = mem::replace(&mut b.opt, None); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Option::take()` instead: `b.opt.take()` diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index cb1f695c651cb..76b0d131dd41d 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -11,6 +11,7 @@ clippy::new_without_default, clippy::needless_pass_by_value, clippy::needless_lifetimes, + clippy::elidable_lifetime_names, clippy::print_stdout, clippy::must_use_candidate, clippy::use_self, @@ -101,6 +102,7 @@ struct BadNew; impl BadNew { fn new() -> i32 { + //~^ new_ret_no_self 0 } } @@ -122,6 +124,7 @@ fn filter_next() { // Multi-line case. let _ = v.iter().filter(|&x| { + //~^ filter_next *x < 0 } ).next(); diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr index 2e2bd3d874f51..353b999d7da0f 100644 --- a/src/tools/clippy/tests/ui/methods.stderr +++ b/src/tools/clippy/tests/ui/methods.stderr @@ -1,7 +1,8 @@ error: methods called `new` usually return `Self` - --> tests/ui/methods.rs:103:5 + --> tests/ui/methods.rs:104:5 | LL | / fn new() -> i32 { +LL | | LL | | 0 LL | | } | |_____^ @@ -10,10 +11,11 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]` error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead - --> tests/ui/methods.rs:124:13 + --> tests/ui/methods.rs:126:13 | LL | let _ = v.iter().filter(|&x| { | _____________^ +LL | | LL | | *x < 0 LL | | } LL | | ).next(); diff --git a/src/tools/clippy/tests/ui/methods_fixable.fixed b/src/tools/clippy/tests/ui/methods_fixable.fixed index bb06b5a480ff1..49730d8115584 100644 --- a/src/tools/clippy/tests/ui/methods_fixable.fixed +++ b/src/tools/clippy/tests/ui/methods_fixable.fixed @@ -7,4 +7,5 @@ fn main() { // Single-line case. let _ = v.iter().find(|&x| *x < 0); + //~^ filter_next } diff --git a/src/tools/clippy/tests/ui/methods_fixable.rs b/src/tools/clippy/tests/ui/methods_fixable.rs index 11de924593ed2..a499b63b6f5bd 100644 --- a/src/tools/clippy/tests/ui/methods_fixable.rs +++ b/src/tools/clippy/tests/ui/methods_fixable.rs @@ -7,4 +7,5 @@ fn main() { // Single-line case. let _ = v.iter().filter(|&x| *x < 0).next(); + //~^ filter_next } diff --git a/src/tools/clippy/tests/ui/methods_unfixable.rs b/src/tools/clippy/tests/ui/methods_unfixable.rs index ee59983a7573e..c19a769f79745 100644 --- a/src/tools/clippy/tests/ui/methods_unfixable.rs +++ b/src/tools/clippy/tests/ui/methods_unfixable.rs @@ -7,5 +7,5 @@ fn main() { pub fn issue10029() { let iter = (0..10); let _ = iter.filter(|_| true).next(); - //~^ ERROR: called `filter(..).next()` on an `Iterator`. This is more succinctly expre + //~^ filter_next } diff --git a/src/tools/clippy/tests/ui/min_ident_chars.rs b/src/tools/clippy/tests/ui/min_ident_chars.rs index 1d89f26b6ee4d..f473ac848a8ee 100644 --- a/src/tools/clippy/tests/ui/min_ident_chars.rs +++ b/src/tools/clippy/tests/ui/min_ident_chars.rs @@ -7,24 +7,35 @@ extern crate proc_macros; use proc_macros::{external, with_span}; struct A { + //~^ min_ident_chars a: u32, + //~^ min_ident_chars i: u32, A: u32, + //~^ min_ident_chars I: u32, + //~^ min_ident_chars } struct B(u32); +//~^ min_ident_chars struct O { + //~^ min_ident_chars o: u32, + //~^ min_ident_chars } struct i; enum C { + //~^ min_ident_chars D, + //~^ min_ident_chars E, + //~^ min_ident_chars F, + //~^ min_ident_chars j, } @@ -39,8 +50,11 @@ struct AA(T, E); trait Trait { const A: u32 = 0; + //~^ min_ident_chars type A; + //~^ min_ident_chars fn a() {} + //~^ min_ident_chars } fn main() { @@ -55,22 +69,37 @@ fn main() { let z = 1; // Implicitly disallowed idents let h = 1; + //~^ min_ident_chars let e = 2; + //~^ min_ident_chars let l = 3; + //~^ min_ident_chars let l = 4; + //~^ min_ident_chars let o = 6; + //~^ min_ident_chars // 2 len does not lint let hi = 0; // Lint let (h, o, w) = (1, 2, 3); + //~^ min_ident_chars + //~| min_ident_chars for (a, (r, e)) in (0..1000).enumerate().enumerate() {} + //~^ min_ident_chars + //~| min_ident_chars + //~| min_ident_chars let you = Vec4 { x: 1, y: 2, z: 3, w: 4 }; while let (d, o, _i, n, g) = (true, true, false, false, true) {} + //~^ min_ident_chars + //~| min_ident_chars + //~| min_ident_chars let today = true; // Ideally this wouldn't lint, but this would (likely) require global analysis, outta scope // of this lint regardless let o = 1; + //~^ min_ident_chars let o = O { o }; + //~^ min_ident_chars for j in 0..1000 {} for _ in 0..10 {} @@ -85,7 +114,10 @@ fn main() { } fn b() {} +//~^ min_ident_chars fn wrong_pythagoras(a: f32, b: f32) -> f32 { + //~^ min_ident_chars + //~| min_ident_chars a * a + a * b } diff --git a/src/tools/clippy/tests/ui/min_ident_chars.stderr b/src/tools/clippy/tests/ui/min_ident_chars.stderr index 3dd5c9561fd02..bd6c45cf648e4 100644 --- a/src/tools/clippy/tests/ui/min_ident_chars.stderr +++ b/src/tools/clippy/tests/ui/min_ident_chars.stderr @@ -8,187 +8,187 @@ LL | struct A { = help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]` error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:10:5 + --> tests/ui/min_ident_chars.rs:11:5 | LL | a: u32, | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:12:5 + --> tests/ui/min_ident_chars.rs:14:5 | LL | A: u32, | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:13:5 + --> tests/ui/min_ident_chars.rs:16:5 | LL | I: u32, | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:16:8 + --> tests/ui/min_ident_chars.rs:20:8 | LL | struct B(u32); | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:18:8 + --> tests/ui/min_ident_chars.rs:23:8 | LL | struct O { | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:19:5 + --> tests/ui/min_ident_chars.rs:25:5 | LL | o: u32, | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:24:6 + --> tests/ui/min_ident_chars.rs:31:6 | LL | enum C { | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:25:5 + --> tests/ui/min_ident_chars.rs:33:5 | LL | D, | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:26:5 + --> tests/ui/min_ident_chars.rs:35:5 | LL | E, | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:27:5 + --> tests/ui/min_ident_chars.rs:37:5 | LL | F, | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:41:11 + --> tests/ui/min_ident_chars.rs:52:11 | LL | const A: u32 = 0; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:42:10 + --> tests/ui/min_ident_chars.rs:54:10 | LL | type A; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:43:8 + --> tests/ui/min_ident_chars.rs:56:8 | LL | fn a() {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:57:9 + --> tests/ui/min_ident_chars.rs:71:9 | LL | let h = 1; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:58:9 + --> tests/ui/min_ident_chars.rs:73:9 | LL | let e = 2; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:59:9 + --> tests/ui/min_ident_chars.rs:75:9 | LL | let l = 3; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:60:9 + --> tests/ui/min_ident_chars.rs:77:9 | LL | let l = 4; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:61:9 + --> tests/ui/min_ident_chars.rs:79:9 | LL | let o = 6; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:65:10 + --> tests/ui/min_ident_chars.rs:84:10 | LL | let (h, o, w) = (1, 2, 3); | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:65:13 + --> tests/ui/min_ident_chars.rs:84:13 | LL | let (h, o, w) = (1, 2, 3); | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:66:10 + --> tests/ui/min_ident_chars.rs:87:10 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:66:14 + --> tests/ui/min_ident_chars.rs:87:14 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:66:17 + --> tests/ui/min_ident_chars.rs:87:17 | LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:68:16 + --> tests/ui/min_ident_chars.rs:92:16 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:68:19 + --> tests/ui/min_ident_chars.rs:92:19 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:68:29 + --> tests/ui/min_ident_chars.rs:92:29 | LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:72:9 + --> tests/ui/min_ident_chars.rs:99:9 | LL | let o = 1; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:73:9 + --> tests/ui/min_ident_chars.rs:101:9 | LL | let o = O { o }; | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:87:4 + --> tests/ui/min_ident_chars.rs:116:4 | LL | fn b() {} | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:88:21 + --> tests/ui/min_ident_chars.rs:118:21 | LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { | ^ error: this ident consists of a single char - --> tests/ui/min_ident_chars.rs:88:29 + --> tests/ui/min_ident_chars.rs:118:29 | LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 { | ^ diff --git a/src/tools/clippy/tests/ui/min_max.rs b/src/tools/clippy/tests/ui/min_max.rs index cf64f85f9bb5f..f3eeb85f20ed6 100644 --- a/src/tools/clippy/tests/ui/min_max.rs +++ b/src/tools/clippy/tests/ui/min_max.rs @@ -20,17 +20,19 @@ impl NotOrd { fn main() { let x = 2usize; min(1, max(3, x)); - //~^ ERROR: this `min`/`max` combination leads to constant result - //~| NOTE: `-D clippy::min-max` implied by `-D warnings` + //~^ min_max + min(max(3, x), 1); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max + max(min(x, 1), 3); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max + max(3, min(x, 1)); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max my_max(3, my_min(x, 1)); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max min(3, max(1, x)); // ok, could be 1, 2 or 3 depending on x @@ -41,32 +43,37 @@ fn main() { let s = "Hello"; min("Apple", max("Zoo", s)); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max + max(min(s, "Apple"), "Zoo"); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max max("Apple", min(s, "Zoo")); // ok let f = 3f32; x.min(1).max(3); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max + x.max(3).min(1); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max + f.max(3f32).min(1f32); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max x.max(1).min(3); // ok x.min(3).max(1); // ok f.min(3f32).max(1f32); // ok max(x.min(1), 3); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max + min(x.max(1), 3); // ok s.max("Zoo").min("Apple"); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max + s.min("Apple").max("Zoo"); - //~^ ERROR: this `min`/`max` combination leads to constant result + //~^ min_max s.min("Zoo").max("Apple"); // ok diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr index bb1a82e320d97..84b4d37545529 100644 --- a/src/tools/clippy/tests/ui/min_max.stderr +++ b/src/tools/clippy/tests/ui/min_max.stderr @@ -14,67 +14,67 @@ LL | min(max(3, x), 1); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:27:5 + --> tests/ui/min_max.rs:28:5 | LL | max(min(x, 1), 3); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:29:5 + --> tests/ui/min_max.rs:31:5 | LL | max(3, min(x, 1)); | ^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:32:5 + --> tests/ui/min_max.rs:34:5 | LL | my_max(3, my_min(x, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:43:5 + --> tests/ui/min_max.rs:45:5 | LL | min("Apple", max("Zoo", s)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:45:5 + --> tests/ui/min_max.rs:48:5 | LL | max(min(s, "Apple"), "Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:51:5 + --> tests/ui/min_max.rs:54:5 | LL | x.min(1).max(3); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:53:5 + --> tests/ui/min_max.rs:57:5 | LL | x.max(3).min(1); | ^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:55:5 + --> tests/ui/min_max.rs:60:5 | LL | f.max(3f32).min(1f32); | ^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:62:5 + --> tests/ui/min_max.rs:67:5 | LL | max(x.min(1), 3); | ^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:66:5 + --> tests/ui/min_max.rs:72:5 | LL | s.max("Zoo").min("Apple"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `min`/`max` combination leads to constant result - --> tests/ui/min_max.rs:68:5 + --> tests/ui/min_max.rs:75:5 | LL | s.min("Apple").max("Zoo"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/min_rust_version_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_attr.rs index 5fe3306d6fc83..4627bef28a29b 100644 --- a/src/tools/clippy/tests/ui/min_rust_version_attr.rs +++ b/src/tools/clippy/tests/ui/min_rust_version_attr.rs @@ -11,13 +11,13 @@ fn just_under_msrv() { #[clippy::msrv = "1.43.0"] fn meets_msrv() { let log2_10 = 3.321928094887362; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found + //~^ approx_constant } #[clippy::msrv = "1.44.0"] fn just_above_msrv() { let log2_10 = 3.321928094887362; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found + //~^ approx_constant } #[clippy::msrv = "1.42"] @@ -28,7 +28,7 @@ fn no_patch_under() { #[clippy::msrv = "1.43"] fn no_patch_meets() { let log2_10 = 3.321928094887362; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found + //~^ approx_constant } fn inner_attr_under() { @@ -39,7 +39,7 @@ fn inner_attr_under() { fn inner_attr_meets() { #![clippy::msrv = "1.43"] let log2_10 = 3.321928094887362; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found + //~^ approx_constant } // https://github.com/rust-lang/rust-clippy/issues/6920 @@ -50,7 +50,7 @@ fn scoping() { // Should warn let log2_10 = 3.321928094887362; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found + //~^ approx_constant mod a { #![clippy::msrv = "1.42.0"] @@ -58,7 +58,7 @@ fn scoping() { fn should_warn() { #![clippy::msrv = "1.43.0"] let log2_10 = 3.321928094887362; - //~^ ERROR: approximate value of `f{32, 64}::consts::LOG2_10` found + //~^ approx_constant } fn should_not_warn() { diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs index a4560f9e9a99b..11ff865b583bf 100644 --- a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs +++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs @@ -9,12 +9,12 @@ fn main() { // lint on both params impl Foo {} - //~^ ERROR: `Foo` has a similarly named generic type parameter `B` in its declaration, - //~| ERROR: `Foo` has a similarly named generic type parameter `A` in its declaration, + //~^ mismatching_type_param_order + //~| mismatching_type_param_order // lint on the 2nd param impl Foo {} - //~^ ERROR: `Foo` has a similarly named generic type parameter `A` in its declaration, + //~^ mismatching_type_param_order // should not lint impl Foo {} @@ -26,8 +26,8 @@ fn main() { // should not lint on lifetimes impl<'m, 'l, B, A> FooLifetime<'m, 'l, B, A> {} - //~^ ERROR: `FooLifetime` has a similarly named generic type parameter `B` in its decl - //~| ERROR: `FooLifetime` has a similarly named generic type parameter `A` in its decl + //~^ mismatching_type_param_order + //~| mismatching_type_param_order struct Bar { x: i32, @@ -44,9 +44,9 @@ fn main() { } impl FooEnum {} - //~^ ERROR: `FooEnum` has a similarly named generic type parameter `C` in its declarat - //~| ERROR: `FooEnum` has a similarly named generic type parameter `A` in its declarat - //~| ERROR: `FooEnum` has a similarly named generic type parameter `B` in its declarat + //~^ mismatching_type_param_order + //~| mismatching_type_param_order + //~| mismatching_type_param_order // also works for unions union FooUnion @@ -58,8 +58,8 @@ fn main() { } impl FooUnion where A: Copy {} - //~^ ERROR: `FooUnion` has a similarly named generic type parameter `B` in its declara - //~| ERROR: `FooUnion` has a similarly named generic type parameter `A` in its declara + //~^ mismatching_type_param_order + //~| mismatching_type_param_order impl FooUnion where diff --git a/src/tools/clippy/tests/ui/misnamed_getters.fixed b/src/tools/clippy/tests/ui/misnamed_getters.fixed index 70af604b21448..cada5307b1c8e 100644 --- a/src/tools/clippy/tests/ui/misnamed_getters.fixed +++ b/src/tools/clippy/tests/ui/misnamed_getters.fixed @@ -10,32 +10,37 @@ struct A { impl A { fn a(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field - //~| NOTE: `-D clippy::misnamed-getters` implied by `-D warnings` + //~^ misnamed_getters + &self.a } fn a_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } fn b(self) -> u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + self.b } fn b_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } fn c(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.c } fn c_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.c } } @@ -47,21 +52,25 @@ union B { impl B { unsafe fn a(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.a } unsafe fn a_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } unsafe fn b(self) -> u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + self.b } unsafe fn b_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } @@ -74,21 +83,25 @@ impl B { } unsafe fn a_unchecked(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.a } unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } unsafe fn b_unchecked(self) -> u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + self.b } unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } @@ -121,20 +134,24 @@ impl core::ops::DerefMut for D { impl D { fn a(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.a } fn a_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } fn d(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.d } fn d_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.d } } diff --git a/src/tools/clippy/tests/ui/misnamed_getters.rs b/src/tools/clippy/tests/ui/misnamed_getters.rs index 23c3e7bc5cf7e..f529c56b4717b 100644 --- a/src/tools/clippy/tests/ui/misnamed_getters.rs +++ b/src/tools/clippy/tests/ui/misnamed_getters.rs @@ -10,32 +10,37 @@ struct A { impl A { fn a(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field - //~| NOTE: `-D clippy::misnamed-getters` implied by `-D warnings` + //~^ misnamed_getters + &self.b } fn a_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } fn b(self) -> u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + self.a } fn b_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } fn c(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.b } fn c_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } } @@ -47,21 +52,25 @@ union B { impl B { unsafe fn a(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.b } unsafe fn a_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } unsafe fn b(self) -> u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + self.a } unsafe fn b_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } @@ -74,21 +83,25 @@ impl B { } unsafe fn a_unchecked(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.b } unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } unsafe fn b_unchecked(self) -> u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + self.a } unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.a } @@ -121,20 +134,24 @@ impl core::ops::DerefMut for D { impl D { fn a(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.b } fn a_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } fn d(&self) -> &u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &self.b } fn d_mut(&mut self) -> &mut u8 { - //~^ ERROR: getter function appears to return the wrong field + //~^ misnamed_getters + &mut self.b } } diff --git a/src/tools/clippy/tests/ui/misnamed_getters.stderr b/src/tools/clippy/tests/ui/misnamed_getters.stderr index 056fa2be92151..5dd1d75bcf6f1 100644 --- a/src/tools/clippy/tests/ui/misnamed_getters.stderr +++ b/src/tools/clippy/tests/ui/misnamed_getters.stderr @@ -17,166 +17,183 @@ error: getter function appears to return the wrong field | LL | / fn a_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.b | | ----------- help: consider using: `&mut self.a` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:22:5 + --> tests/ui/misnamed_getters.rs:23:5 | LL | / fn b(self) -> u8 { LL | | +LL | | LL | | self.a | | ------ help: consider using: `self.b` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:27:5 + --> tests/ui/misnamed_getters.rs:29:5 | LL | / fn b_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.a | | ----------- help: consider using: `&mut self.b` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:32:5 + --> tests/ui/misnamed_getters.rs:35:5 | LL | / fn c(&self) -> &u8 { LL | | +LL | | LL | | &self.b | | ------- help: consider using: `&self.c` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:37:5 + --> tests/ui/misnamed_getters.rs:41:5 | LL | / fn c_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.a | | ----------- help: consider using: `&mut self.c` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:49:5 + --> tests/ui/misnamed_getters.rs:54:5 | LL | / unsafe fn a(&self) -> &u8 { LL | | +LL | | LL | | &self.b | | ------- help: consider using: `&self.a` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:53:5 + --> tests/ui/misnamed_getters.rs:59:5 | LL | / unsafe fn a_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.b | | ----------- help: consider using: `&mut self.a` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:58:5 + --> tests/ui/misnamed_getters.rs:65:5 | LL | / unsafe fn b(self) -> u8 { LL | | +LL | | LL | | self.a | | ------ help: consider using: `self.b` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:63:5 + --> tests/ui/misnamed_getters.rs:71:5 | LL | / unsafe fn b_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.a | | ----------- help: consider using: `&mut self.b` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:76:5 + --> tests/ui/misnamed_getters.rs:85:5 | LL | / unsafe fn a_unchecked(&self) -> &u8 { LL | | +LL | | LL | | &self.b | | ------- help: consider using: `&self.a` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:80:5 + --> tests/ui/misnamed_getters.rs:90:5 | LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.b | | ----------- help: consider using: `&mut self.a` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:85:5 + --> tests/ui/misnamed_getters.rs:96:5 | LL | / unsafe fn b_unchecked(self) -> u8 { LL | | +LL | | LL | | self.a | | ------ help: consider using: `self.b` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:90:5 + --> tests/ui/misnamed_getters.rs:102:5 | LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.a | | ----------- help: consider using: `&mut self.b` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:123:5 + --> tests/ui/misnamed_getters.rs:136:5 | LL | / fn a(&self) -> &u8 { LL | | +LL | | LL | | &self.b | | ------- help: consider using: `&self.a` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:127:5 + --> tests/ui/misnamed_getters.rs:141:5 | LL | / fn a_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.b | | ----------- help: consider using: `&mut self.a` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:132:5 + --> tests/ui/misnamed_getters.rs:147:5 | LL | / fn d(&self) -> &u8 { LL | | +LL | | LL | | &self.b | | ------- help: consider using: `&self.d` LL | | } | |_____^ error: getter function appears to return the wrong field - --> tests/ui/misnamed_getters.rs:136:5 + --> tests/ui/misnamed_getters.rs:152:5 | LL | / fn d_mut(&mut self) -> &mut u8 { LL | | +LL | | LL | | &mut self.b | | ----------- help: consider using: `&mut self.d` LL | | } diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed index ac44a6f3fdb22..3bbafe0bba3fe 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed @@ -28,25 +28,25 @@ fn sum_with_assert_ge_other_way(v: &[u8]) -> u8 { fn sum_with_assert_lt(v: &[u8]) -> u8 { assert!(v.len() > 4); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn sum_with_assert_le(v: &[u8]) -> u8 { assert!(v.len() > 4); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn sum_with_incorrect_assert_len(v: &[u8]) -> u8 { assert!(v.len() > 4); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn sum_with_incorrect_assert_len2(v: &[u8]) -> u8 { assert!(v.len() > 4); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } // ok, don't lint for single array access @@ -64,7 +64,8 @@ fn subslice_ok(v: &[u8]) { fn subslice_bad(v: &[u8]) { assert!(v.len() > 3); let _ = v[0]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v[1..4]; } @@ -78,7 +79,8 @@ fn subslice_inclusive_ok(v: &[u8]) { fn subslice_inclusive_bad(v: &[u8]) { assert!(v.len() > 4); let _ = v[0]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v[1..=4]; } @@ -93,15 +95,17 @@ fn index_different_slices_wrong_len(v1: &[u8], v2: &[u8]) { assert!(v1.len() > 12); assert!(v2.len() > 15); let _ = v1[0] + v1[12]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v2[5] + v2[15]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn index_different_slices_one_wrong_len(v1: &[u8], v2: &[u8]) { assert!(v1.len() > 12); assert!(v2.len() > 15); let _ = v1[0] + v1[12]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v2[5] + v2[15]; } @@ -125,11 +129,13 @@ fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { assert!(4 == v4.len()); let _ = v1[0] + v1[1] + v1[2]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v2[0] + v2[1] + v2[2]; let _ = v3[0] + v3[1] + v3[2]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v4[0] + v4[1] + v4[2]; } diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs index f05d5fea57dc2..f8ea0173c13fc 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs @@ -28,25 +28,25 @@ fn sum_with_assert_ge_other_way(v: &[u8]) -> u8 { fn sum_with_assert_lt(v: &[u8]) -> u8 { assert!(v.len() < 5); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn sum_with_assert_le(v: &[u8]) -> u8 { assert!(v.len() <= 5); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn sum_with_incorrect_assert_len(v: &[u8]) -> u8 { assert!(v.len() > 3); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn sum_with_incorrect_assert_len2(v: &[u8]) -> u8 { assert!(v.len() >= 4); v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } // ok, don't lint for single array access @@ -64,7 +64,8 @@ fn subslice_ok(v: &[u8]) { fn subslice_bad(v: &[u8]) { assert!(v.len() >= 3); let _ = v[0]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v[1..4]; } @@ -78,7 +79,8 @@ fn subslice_inclusive_ok(v: &[u8]) { fn subslice_inclusive_bad(v: &[u8]) { assert!(v.len() >= 4); let _ = v[0]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v[1..=4]; } @@ -93,15 +95,17 @@ fn index_different_slices_wrong_len(v1: &[u8], v2: &[u8]) { assert!(v1.len() >= 12); assert!(v2.len() >= 15); let _ = v1[0] + v1[12]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v2[5] + v2[15]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing } fn index_different_slices_one_wrong_len(v1: &[u8], v2: &[u8]) { assert!(v1.len() >= 12); assert!(v2.len() > 15); let _ = v1[0] + v1[12]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v2[5] + v2[15]; } @@ -125,11 +129,13 @@ fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) { assert!(4 == v4.len()); let _ = v1[0] + v1[1] + v1[2]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v2[0] + v2[1] + v2[2]; let _ = v3[0] + v3[1] + v3[2]; - //~^ ERROR: indexing into a slice multiple times with an `assert` that does not cover the + //~^ missing_asserts_for_indexing + let _ = v4[0] + v4[1] + v4[2]; } diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr index 2e63cd4a0e503..5d30920ccf521 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr @@ -147,7 +147,7 @@ LL | assert!(v.len() >= 3); | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 3)` LL | let _ = v[0]; | _____________^ -LL | | +... | LL | | let _ = v[1..4]; | |___________________^ | @@ -157,37 +157,37 @@ note: slice indexed here LL | let _ = v[0]; | ^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:68:13 + --> tests/ui/missing_asserts_for_indexing.rs:69:13 | LL | let _ = v[1..4]; | ^^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:80:13 + --> tests/ui/missing_asserts_for_indexing.rs:81:13 | LL | assert!(v.len() >= 4); | --------------------- help: provide the highest index that is indexed with: `assert!(v.len() > 4)` LL | let _ = v[0]; | _____________^ -LL | | +... | LL | | let _ = v[1..=4]; | |____________________^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:80:13 + --> tests/ui/missing_asserts_for_indexing.rs:81:13 | LL | let _ = v[0]; | ^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:82:13 + --> tests/ui/missing_asserts_for_indexing.rs:84:13 | LL | let _ = v[1..=4]; | ^^^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:95:13 + --> tests/ui/missing_asserts_for_indexing.rs:97:13 | LL | assert!(v1.len() >= 12); | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` @@ -196,19 +196,19 @@ LL | let _ = v1[0] + v1[12]; | ^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:95:13 + --> tests/ui/missing_asserts_for_indexing.rs:97:13 | LL | let _ = v1[0] + v1[12]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:95:21 + --> tests/ui/missing_asserts_for_indexing.rs:97:21 | LL | let _ = v1[0] + v1[12]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:97:13 + --> tests/ui/missing_asserts_for_indexing.rs:100:13 | LL | assert!(v2.len() >= 15); | ----------------------- help: provide the highest index that is indexed with: `assert!(v2.len() > 15)` @@ -217,19 +217,19 @@ LL | let _ = v2[5] + v2[15]; | ^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:97:13 + --> tests/ui/missing_asserts_for_indexing.rs:100:13 | LL | let _ = v2[5] + v2[15]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:97:21 + --> tests/ui/missing_asserts_for_indexing.rs:100:21 | LL | let _ = v2[5] + v2[15]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:103:13 + --> tests/ui/missing_asserts_for_indexing.rs:106:13 | LL | assert!(v1.len() >= 12); | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() > 12)` @@ -238,19 +238,19 @@ LL | let _ = v1[0] + v1[12]; | ^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:103:13 + --> tests/ui/missing_asserts_for_indexing.rs:106:13 | LL | let _ = v1[0] + v1[12]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:103:21 + --> tests/ui/missing_asserts_for_indexing.rs:106:21 | LL | let _ = v1[0] + v1[12]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:127:13 + --> tests/ui/missing_asserts_for_indexing.rs:131:13 | LL | assert!(v1.len() == 2); | ---------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)` @@ -259,24 +259,24 @@ LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^^^^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:127:13 + --> tests/ui/missing_asserts_for_indexing.rs:131:13 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:127:21 + --> tests/ui/missing_asserts_for_indexing.rs:131:21 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:127:29 + --> tests/ui/missing_asserts_for_indexing.rs:131:29 | LL | let _ = v1[0] + v1[1] + v1[2]; | ^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times with an `assert` that does not cover the highest index - --> tests/ui/missing_asserts_for_indexing.rs:131:13 + --> tests/ui/missing_asserts_for_indexing.rs:136:13 | LL | assert!(2 == v3.len()); | ---------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)` @@ -285,17 +285,17 @@ LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^^^^^^^^^^^^^^^^^ | note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:13 + --> tests/ui/missing_asserts_for_indexing.rs:136:13 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:21 + --> tests/ui/missing_asserts_for_indexing.rs:136:21 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing.rs:131:29 + --> tests/ui/missing_asserts_for_indexing.rs:136:29 | LL | let _ = v3[0] + v3[1] + v3[2]; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs index de53079a47608..a520151a2dd94 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs @@ -3,18 +3,20 @@ fn sum(v: &[u8]) -> u8 { v[0] + v[1] + v[2] + v[3] + v[4] - //~^ ERROR: indexing into a slice multiple times without an `assert` + //~^ missing_asserts_for_indexing } fn subslice(v: &[u8]) { let _ = v[0]; - //~^ ERROR: indexing into a slice multiple times without an `assert` + //~^ missing_asserts_for_indexing + let _ = v[1..4]; } fn variables(v: &[u8]) -> u8 { let a = v[0]; - //~^ ERROR: indexing into a slice multiple times without an `assert` + //~^ missing_asserts_for_indexing + let b = v[1]; let c = v[2]; a + b + c @@ -22,13 +24,16 @@ fn variables(v: &[u8]) -> u8 { fn index_different_slices(v1: &[u8], v2: &[u8]) { let _ = v1[0] + v1[12]; + //~^ missing_asserts_for_indexing let _ = v2[5] + v2[15]; + //~^ missing_asserts_for_indexing } fn index_different_slices2(v1: &[u8], v2: &[u8]) { assert!(v1.len() > 12); let _ = v1[0] + v1[12]; let _ = v2[5] + v2[15]; + //~^ missing_asserts_for_indexing } struct Foo<'a> { @@ -38,7 +43,7 @@ struct Foo<'a> { fn index_struct_field(f: &Foo<'_>) { let _ = f.v[0] + f.v[1]; - //~^ ERROR: indexing into a slice multiple times without an `assert` + //~^ missing_asserts_for_indexing } fn index_struct_different_fields(f: &Foo<'_>) { @@ -52,7 +57,7 @@ fn shadowing() { let x: &[i32] = &[1]; let _ = x[0] + x[1]; - //~^ ERROR: indexing into a slice multiple times without an `assert` + //~^ missing_asserts_for_indexing } pub fn issue11856(values: &[i32]) -> usize { diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr index b575e09966ce1..24109b052a8af 100644 --- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr +++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr @@ -39,7 +39,7 @@ error: indexing into a slice multiple times without an `assert` | LL | let _ = v[0]; | _____________^ -LL | | +... | LL | | let _ = v[1..4]; | |___________________^ | @@ -50,130 +50,131 @@ note: slice indexed here LL | let _ = v[0]; | ^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:12:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:13:13 | LL | let _ = v[1..4]; | ^^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:16:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 | LL | let a = v[0]; | _____________^ LL | | +LL | | LL | | let b = v[1]; LL | | let c = v[2]; | |________________^ | = help: consider asserting the length before indexing: `assert!(v.len() > 2);` note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:16:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:17:13 | LL | let a = v[0]; | ^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:18:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:20:13 | LL | let b = v[1]; | ^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:19:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:21:13 | LL | let c = v[2]; | ^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:24:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 | LL | let _ = v1[0] + v1[12]; | ^^^^^^^^^^^^^^ | = help: consider asserting the length before indexing: `assert!(v1.len() > 12);` note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:24:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:13 | LL | let _ = v1[0] + v1[12]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:24:21 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:26:21 | LL | let _ = v1[0] + v1[12]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:25:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 | LL | let _ = v2[5] + v2[15]; | ^^^^^^^^^^^^^^ | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:25:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:13 | LL | let _ = v2[5] + v2[15]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:25:21 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:28:21 | LL | let _ = v2[5] + v2[15]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:31:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 | LL | let _ = v2[5] + v2[15]; | ^^^^^^^^^^^^^^ | = help: consider asserting the length before indexing: `assert!(v2.len() > 15);` note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:31:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:13 | LL | let _ = v2[5] + v2[15]; | ^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:31:21 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:35:21 | LL | let _ = v2[5] + v2[15]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:40:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 | LL | let _ = f.v[0] + f.v[1]; | ^^^^^^^^^^^^^^^ | = help: consider asserting the length before indexing: `assert!(f.v.len() > 1);` note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:40:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:13 | LL | let _ = f.v[0] + f.v[1]; | ^^^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:40:22 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:45:22 | LL | let _ = f.v[0] + f.v[1]; | ^^^^^^ = note: asserting the length before indexing will elide bounds checks error: indexing into a slice multiple times without an `assert` - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:54:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 | LL | let _ = x[0] + x[1]; | ^^^^^^^^^^^ | = help: consider asserting the length before indexing: `assert!(x.len() > 1);` note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:54:13 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:13 | LL | let _ = x[0] + x[1]; | ^^^^ note: slice indexed here - --> tests/ui/missing_asserts_for_indexing_unfixable.rs:54:20 + --> tests/ui/missing_asserts_for_indexing_unfixable.rs:59:20 | LL | let _ = x[0] + x[1]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index cdfdcd5007a82..bd6339b78700e 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -1,3 +1,4 @@ +//@ check-pass //! False-positive tests to ensure we don't suggest `const` for things where it would cause a //! compilation error. //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. @@ -206,6 +207,7 @@ mod msrv { mod with_ty_alias { type Foo = impl std::fmt::Debug; + #[define_opaque(Foo)] fn foo(_: Foo) { let _: Foo = 1; } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed index 689060468c574..10df44e73b85f 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed @@ -11,45 +11,44 @@ struct Game { impl Game { // Could be const pub const fn new() -> Self { - //~^ ERROR: this could be a `const fn` - //~| NOTE: `-D clippy::missing-const-for-fn` implied by `-D warnings` + //~^ missing_const_for_fn Self { guess: 42 } } const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn b } } // Could be const const fn one() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn 1 } // Could also be const const fn two() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn let abc = 2; abc } // Could be const (since Rust 1.39) const fn string() -> String { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn String::new() } // Could be const const unsafe fn four() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn 4 } // Could also be const const fn generic(t: T) -> T { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn t } @@ -58,7 +57,7 @@ fn sub(x: u32) -> usize { } const fn generic_arr(t: [T; 1]) -> T { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn t[0] } @@ -72,7 +71,7 @@ mod with_drop { impl B { // This can be const, because `a` is passed by reference pub const fn b(self, a: &A) -> B { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn B } } @@ -82,7 +81,7 @@ mod with_drop { mod const_fn_stabilized_before_msrv { // This could be const because `u8::is_ascii_digit` is a stable const function in 1.47. const fn const_fn_stabilized_before_msrv(byte: u8) { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn byte.is_ascii_digit(); } } @@ -94,7 +93,7 @@ fn msrv_1_45() -> i32 { #[clippy::msrv = "1.46"] const fn msrv_1_46() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn 46 } @@ -114,7 +113,7 @@ impl const Drop for D { // Lint this, since it can be dropped in const contexts // FIXME(const_trait_impl) const fn d(this: D) {} -//~^ ERROR: this could be a `const fn` +//~^ missing_const_for_fn mod msrv { struct Foo(*const u8, &'static u8); @@ -122,12 +121,12 @@ mod msrv { impl Foo { #[clippy::msrv = "1.58"] const fn deref_ptr_can_be_const(self) -> usize { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn unsafe { *self.0 as usize } } const fn deref_copied_val(self) -> usize { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn *self.1 as usize } } @@ -138,7 +137,7 @@ mod msrv { #[clippy::msrv = "1.56"] const fn union_access_can_be_const() { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } @@ -146,12 +145,12 @@ mod msrv { #[clippy::msrv = "1.62"] mod with_extern { const extern "C" fn c() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn #[rustfmt::skip] #[allow(missing_abi)] const extern fn implicit_c() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn // any item functions in extern block won't trigger this lint extern "C" { @@ -168,11 +167,13 @@ mod issue12677 { impl Wrapper { #[must_use] pub const fn new(strings: Vec) -> Self { + //~^ missing_const_for_fn Self { strings } } #[must_use] pub const fn empty() -> Self { + //~^ missing_const_for_fn Self { strings: Vec::new() } } } @@ -184,6 +185,7 @@ mod issue12677 { impl Other { pub const fn new(text: String) -> Self { + //~^ missing_const_for_fn let vec = Vec::new(); Self { text, vec } } @@ -203,18 +205,19 @@ mod with_ty_alias { // is. Because the associate ty could have no default, therefore would cause ICE, as demonstrated // in this test. const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + //~^ missing_const_for_fn } mod extern_fn { const extern "C-unwind" fn c_unwind() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn const extern "system" fn system() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn const extern "system-unwind" fn system_unwind() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn } const fn mut_add(x: &mut i32) { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn *x += 1; } 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 492c47d7e49b5..bc44b34daef7e 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 @@ -11,45 +11,44 @@ struct Game { impl Game { // Could be const pub fn new() -> Self { - //~^ ERROR: this could be a `const fn` - //~| NOTE: `-D clippy::missing-const-for-fn` implied by `-D warnings` + //~^ missing_const_for_fn Self { guess: 42 } } fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn b } } // Could be const fn one() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn 1 } // Could also be const fn two() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn let abc = 2; abc } // Could be const (since Rust 1.39) fn string() -> String { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn String::new() } // Could be const unsafe fn four() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn 4 } // Could also be const fn generic(t: T) -> T { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn t } @@ -58,7 +57,7 @@ fn sub(x: u32) -> usize { } fn generic_arr(t: [T; 1]) -> T { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn t[0] } @@ -72,7 +71,7 @@ mod with_drop { impl B { // This can be const, because `a` is passed by reference pub fn b(self, a: &A) -> B { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn B } } @@ -82,7 +81,7 @@ mod with_drop { mod const_fn_stabilized_before_msrv { // This could be const because `u8::is_ascii_digit` is a stable const function in 1.47. fn const_fn_stabilized_before_msrv(byte: u8) { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn byte.is_ascii_digit(); } } @@ -94,7 +93,7 @@ fn msrv_1_45() -> i32 { #[clippy::msrv = "1.46"] fn msrv_1_46() -> i32 { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn 46 } @@ -114,7 +113,7 @@ impl const Drop for D { // Lint this, since it can be dropped in const contexts // FIXME(const_trait_impl) fn d(this: D) {} -//~^ ERROR: this could be a `const fn` +//~^ missing_const_for_fn mod msrv { struct Foo(*const u8, &'static u8); @@ -122,12 +121,12 @@ mod msrv { impl Foo { #[clippy::msrv = "1.58"] fn deref_ptr_can_be_const(self) -> usize { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn unsafe { *self.0 as usize } } fn deref_copied_val(self) -> usize { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn *self.1 as usize } } @@ -138,7 +137,7 @@ mod msrv { #[clippy::msrv = "1.56"] fn union_access_can_be_const() { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn let bar = Bar { val: 1 }; let _ = unsafe { bar.val }; } @@ -146,12 +145,12 @@ mod msrv { #[clippy::msrv = "1.62"] mod with_extern { extern "C" fn c() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn #[rustfmt::skip] #[allow(missing_abi)] extern fn implicit_c() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn // any item functions in extern block won't trigger this lint extern "C" { @@ -168,11 +167,13 @@ mod issue12677 { impl Wrapper { #[must_use] pub fn new(strings: Vec) -> Self { + //~^ missing_const_for_fn Self { strings } } #[must_use] pub fn empty() -> Self { + //~^ missing_const_for_fn Self { strings: Vec::new() } } } @@ -184,6 +185,7 @@ mod issue12677 { impl Other { pub fn new(text: String) -> Self { + //~^ missing_const_for_fn let vec = Vec::new(); Self { text, vec } } @@ -203,18 +205,19 @@ mod with_ty_alias { // is. Because the associate ty could have no default, therefore would cause ICE, as demonstrated // in this test. fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} + //~^ missing_const_for_fn } mod extern_fn { extern "C-unwind" fn c_unwind() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn extern "system" fn system() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn extern "system-unwind" fn system_unwind() {} - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn } fn mut_add(x: &mut i32) { - //~^ ERROR: this could be a `const fn` + //~^ missing_const_for_fn *x += 1; } diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr index a06703e2ebf23..5df5a54ff5216 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr @@ -3,7 +3,6 @@ error: this could be a `const fn` | LL | / pub fn new() -> Self { LL | | -LL | | LL | | Self { guess: 42 } LL | | } | |_____^ @@ -16,7 +15,7 @@ LL | pub const fn new() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:19:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:18:5 | LL | / fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; N]) -> &'a [T; N] { LL | | @@ -30,7 +29,7 @@ LL | const fn const_generic_params<'a, T, const N: usize>(&self, b: &'a [T; | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:26:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:25:1 | LL | / fn one() -> i32 { LL | | @@ -44,7 +43,7 @@ LL | const fn one() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:32:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:31:1 | LL | / fn two() -> i32 { LL | | @@ -59,7 +58,7 @@ LL | const fn two() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:39:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:38:1 | LL | / fn string() -> String { LL | | @@ -73,7 +72,7 @@ LL | const fn string() -> String { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:45:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:44:1 | LL | / unsafe fn four() -> i32 { LL | | @@ -87,7 +86,7 @@ LL | const unsafe fn four() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:51:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:50:1 | LL | / fn generic(t: T) -> T { LL | | @@ -101,7 +100,7 @@ LL | const fn generic(t: T) -> T { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:60:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:59:1 | LL | / fn generic_arr(t: [T; 1]) -> T { LL | | @@ -115,7 +114,7 @@ LL | const fn generic_arr(t: [T; 1]) -> T { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:74:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:73:9 | LL | / pub fn b(self, a: &A) -> B { LL | | @@ -129,7 +128,7 @@ LL | pub const fn b(self, a: &A) -> B { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:84:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:83:5 | LL | / fn const_fn_stabilized_before_msrv(byte: u8) { LL | | @@ -143,7 +142,7 @@ LL | const fn const_fn_stabilized_before_msrv(byte: u8) { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:96:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:95:1 | LL | / fn msrv_1_46() -> i32 { LL | | @@ -157,7 +156,7 @@ LL | const fn msrv_1_46() -> i32 { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:116:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:115:1 | LL | fn d(this: D) {} | ^^^^^^^^^^^^^^^^ @@ -168,7 +167,7 @@ LL | const fn d(this: D) {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:124:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:123:9 | LL | / fn deref_ptr_can_be_const(self) -> usize { LL | | @@ -182,7 +181,7 @@ LL | const fn deref_ptr_can_be_const(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:129:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:128:9 | LL | / fn deref_copied_val(self) -> usize { LL | | @@ -196,7 +195,7 @@ LL | const fn deref_copied_val(self) -> usize { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:140:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:139:5 | LL | / fn union_access_can_be_const() { LL | | @@ -211,7 +210,7 @@ LL | const fn union_access_can_be_const() { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:148:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:147:9 | LL | extern "C" fn c() {} | ^^^^^^^^^^^^^^^^^^^^ @@ -222,7 +221,7 @@ LL | const extern "C" fn c() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:153:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:152:9 | LL | extern fn implicit_c() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -233,9 +232,10 @@ LL | const extern fn implicit_c() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:170:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:169:9 | LL | / pub fn new(strings: Vec) -> Self { +LL | | LL | | Self { strings } LL | | } | |_________^ @@ -249,6 +249,7 @@ error: this could be a `const fn` --> tests/ui/missing_const_for_fn/could_be_const.rs:175:9 | LL | / pub fn empty() -> Self { +LL | | LL | | Self { strings: Vec::new() } LL | | } | |_________^ @@ -259,9 +260,10 @@ LL | pub const fn empty() -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:186:9 + --> tests/ui/missing_const_for_fn/could_be_const.rs:187:9 | LL | / pub fn new(text: String) -> Self { +LL | | LL | | let vec = Vec::new(); LL | | Self { text, vec } LL | | } @@ -273,7 +275,7 @@ LL | pub const fn new(text: String) -> Self { | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:205:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:207:5 | LL | fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -284,7 +286,7 @@ LL | const fn alias_ty_is_projection(bar: <() as FooTrait>::Foo) {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:209:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:212:5 | LL | extern "C-unwind" fn c_unwind() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -295,7 +297,7 @@ LL | const extern "C-unwind" fn c_unwind() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:211:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:214:5 | LL | extern "system" fn system() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -306,7 +308,7 @@ LL | const extern "system" fn system() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:213:5 + --> tests/ui/missing_const_for_fn/could_be_const.rs:216:5 | LL | extern "system-unwind" fn system_unwind() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -317,7 +319,7 @@ LL | const extern "system-unwind" fn system_unwind() {} | +++++ error: this could be a `const fn` - --> tests/ui/missing_const_for_fn/could_be_const.rs:217:1 + --> tests/ui/missing_const_for_fn/could_be_const.rs:220:1 | LL | / fn mut_add(x: &mut i32) { LL | | diff --git a/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed index 90b31b9b5d219..2efe10c153da3 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed +++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.fixed @@ -6,8 +6,8 @@ fn main() { // lint and suggest const thread_local! { static BUF_1: RefCell = const { RefCell::new(String::new()) }; + //~^ missing_const_for_thread_local } - //~^^ ERROR: initializer for `thread_local` value can be made `const` // don't lint thread_local! { @@ -16,23 +16,25 @@ fn main() { thread_local! { static SIMPLE:i32 = const { 1 }; + //~^ missing_const_for_thread_local } - //~^^ ERROR: initializer for `thread_local` value can be made `const` // lint and suggest const for all non const items thread_local! { static BUF_3_CAN_BE_MADE_CONST: RefCell = const { RefCell::new(String::new()) }; + //~^ missing_const_for_thread_local static CONST_MIXED_WITH:i32 = const { 1 }; static BUF_4_CAN_BE_MADE_CONST: RefCell = const { RefCell::new(String::new()) }; + //~^ missing_const_for_thread_local } - //~^^^^ ERROR: initializer for `thread_local` value can be made `const` - //~^^^ ERROR: initializer for `thread_local` value can be made `const` thread_local! { static PEEL_ME: i32 = const { 1 }; - //~^ ERROR: initializer for `thread_local` value can be made `const` + //~^ missing_const_for_thread_local + static PEEL_ME_MANY: i32 = const { { let x = 1; x * x } }; - //~^ ERROR: initializer for `thread_local` value can be made `const` + //~^ missing_const_for_thread_local + } } diff --git a/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs index f97e4848fd7a6..119cc5a99fa05 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.rs @@ -6,8 +6,8 @@ fn main() { // lint and suggest const thread_local! { static BUF_1: RefCell = RefCell::new(String::new()); + //~^ missing_const_for_thread_local } - //~^^ ERROR: initializer for `thread_local` value can be made `const` // don't lint thread_local! { @@ -16,23 +16,25 @@ fn main() { thread_local! { static SIMPLE:i32 = 1; + //~^ missing_const_for_thread_local } - //~^^ ERROR: initializer for `thread_local` value can be made `const` // lint and suggest const for all non const items thread_local! { static BUF_3_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); + //~^ missing_const_for_thread_local static CONST_MIXED_WITH:i32 = const { 1 }; static BUF_4_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); + //~^ missing_const_for_thread_local } - //~^^^^ ERROR: initializer for `thread_local` value can be made `const` - //~^^^ ERROR: initializer for `thread_local` value can be made `const` thread_local! { static PEEL_ME: i32 = { 1 }; - //~^ ERROR: initializer for `thread_local` value can be made `const` + //~^ missing_const_for_thread_local + static PEEL_ME_MANY: i32 = { let x = 1; x * x }; - //~^ ERROR: initializer for `thread_local` value can be made `const` + //~^ missing_const_for_thread_local + } } diff --git a/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr index c143a37454f5b..4e90c10c92f8f 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr +++ b/src/tools/clippy/tests/ui/missing_const_for_thread_local.stderr @@ -20,7 +20,7 @@ LL | static BUF_3_CAN_BE_MADE_CONST: RefCell = RefCell::new(Stri | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/missing_const_for_thread_local.rs:26:59 + --> tests/ui/missing_const_for_thread_local.rs:27:59 | LL | static BUF_4_CAN_BE_MADE_CONST: RefCell = RefCell::new(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { RefCell::new(String::new()) }` @@ -32,7 +32,7 @@ LL | static PEEL_ME: i32 = { 1 }; | ^^^^^ help: replace with: `const { 1 }` error: initializer for `thread_local` value can be made `const` - --> tests/ui/missing_const_for_thread_local.rs:34:36 + --> tests/ui/missing_const_for_thread_local.rs:35:36 | LL | static PEEL_ME_MANY: i32 = { let x = 1; x * x }; | ^^^^^^^^^^^^^^^^^^^^ help: replace with: `const { { let x = 1; x * x } }` diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs index 31bc4309582ea..705de959cb7da 100644 --- a/src/tools/clippy/tests/ui/missing_doc.rs +++ b/src/tools/clippy/tests/ui/missing_doc.rs @@ -17,15 +17,18 @@ use proc_macros::with_span; use std::arch::global_asm; type Typedef = String; +//~^ missing_docs_in_private_items pub type PubTypedef = String; mod module_no_dox {} +//~^ missing_docs_in_private_items pub mod pub_module_no_dox {} /// dox pub fn foo() {} pub fn foo2() {} fn foo3() {} +//~^ missing_docs_in_private_items #[allow(clippy::missing_docs_in_private_items)] pub fn foo4() {} @@ -40,8 +43,13 @@ mod a { } enum Baz { + //~^ missing_docs_in_private_items BazA { a: isize, b: isize }, + //~^ missing_docs_in_private_items + //~| missing_docs_in_private_items + //~| missing_docs_in_private_items BarB, + //~^ missing_docs_in_private_items } pub enum PubBaz { @@ -66,6 +74,7 @@ pub enum PubBaz3 { pub fn baz() {} const FOO: u32 = 0; +//~^ missing_docs_in_private_items /// dox pub const FOO1: u32 = 0; #[allow(clippy::missing_docs_in_private_items)] @@ -75,6 +84,7 @@ pub const FOO3: u32 = 0; pub const FOO4: u32 = 0; static BAR: u32 = 0; +//~^ missing_docs_in_private_items /// dox pub static BAR1: u32 = 0; #[allow(clippy::missing_docs_in_private_items)] @@ -84,17 +94,20 @@ pub static BAR3: u32 = 0; pub static BAR4: u32 = 0; mod internal_impl { + //~^ missing_docs_in_private_items /// dox pub fn documented() {} pub fn undocumented1() {} pub fn undocumented2() {} fn undocumented3() {} + //~^ missing_docs_in_private_items /// dox pub mod globbed { /// dox pub fn also_documented() {} pub fn also_undocumented1() {} fn also_undocumented2() {} + //~^ missing_docs_in_private_items } } /// dox @@ -120,6 +133,7 @@ with_span!(span pub const FOO2_PM: u32 = 0;); const _: () = (); fn issue13298() { + //~^ missing_docs_in_private_items // Rustdoc doesn't generate documentation for items within other items like fns or consts const MSG: &str = "Hello, world!"; } diff --git a/src/tools/clippy/tests/ui/missing_doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr index 6554eed161062..63e440b82d147 100644 --- a/src/tools/clippy/tests/ui/missing_doc.stderr +++ b/src/tools/clippy/tests/ui/missing_doc.stderr @@ -8,89 +8,91 @@ LL | type Typedef = String; = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a module - --> tests/ui/missing_doc.rs:22:1 + --> tests/ui/missing_doc.rs:23:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> tests/ui/missing_doc.rs:28:1 + --> tests/ui/missing_doc.rs:30:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> tests/ui/missing_doc.rs:42:1 + --> tests/ui/missing_doc.rs:45:1 | LL | / enum Baz { +LL | | LL | | BazA { a: isize, b: isize }, -LL | | BarB, +... | LL | | } | |_^ error: missing documentation for a variant - --> tests/ui/missing_doc.rs:43:5 + --> tests/ui/missing_doc.rs:47:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:43:12 + --> tests/ui/missing_doc.rs:47:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> tests/ui/missing_doc.rs:43:22 + --> tests/ui/missing_doc.rs:47:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> tests/ui/missing_doc.rs:44:5 + --> tests/ui/missing_doc.rs:51:5 | LL | BarB, | ^^^^ error: missing documentation for a constant - --> tests/ui/missing_doc.rs:68:1 + --> tests/ui/missing_doc.rs:76:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> tests/ui/missing_doc.rs:77:1 + --> tests/ui/missing_doc.rs:86:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> tests/ui/missing_doc.rs:86:1 + --> tests/ui/missing_doc.rs:96:1 | LL | / mod internal_impl { +LL | | LL | | /// dox LL | | pub fn documented() {} -LL | | pub fn undocumented1() {} ... | LL | | } | |_^ error: missing documentation for a function - --> tests/ui/missing_doc.rs:91:5 + --> tests/ui/missing_doc.rs:102:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> tests/ui/missing_doc.rs:97:9 + --> tests/ui/missing_doc.rs:109:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> tests/ui/missing_doc.rs:122:1 + --> tests/ui/missing_doc.rs:135:1 | LL | / fn issue13298() { +LL | | LL | | // Rustdoc doesn't generate documentation for items within other items like fns or consts LL | | const MSG: &str = "Hello, world!"; LL | | } diff --git a/src/tools/clippy/tests/ui/missing_doc_crate.rs b/src/tools/clippy/tests/ui/missing_doc_crate.rs index fdb23af279df5..e6e783a2bb405 100644 --- a/src/tools/clippy/tests/ui/missing_doc_crate.rs +++ b/src/tools/clippy/tests/ui/missing_doc_crate.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::missing_docs_in_private_items)] #![allow(clippy::doc_include_without_cfg)] #![doc = include_str!("../../README.md")] diff --git a/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs index 73584ac8c67d3..f55d8b67cb847 100644 --- a/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs +++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs @@ -1,5 +1,4 @@ #![warn(clippy::missing_docs_in_private_items)] -//~^ ERROR: missing documentation for the crate -//~| NOTE: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` +//~^ missing_docs_in_private_items fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs index 520ddbe16b829..034ce31dfe768 100644 --- a/src/tools/clippy/tests/ui/missing_doc_impl.rs +++ b/src/tools/clippy/tests/ui/missing_doc_impl.rs @@ -11,13 +11,17 @@ extern crate proc_macros; use proc_macros::with_span; struct Foo { + //~^ missing_docs_in_private_items a: isize, + //~^ missing_docs_in_private_items b: isize, + //~^ missing_docs_in_private_items } pub struct PubFoo { pub a: isize, b: isize, + //~^ missing_docs_in_private_items } #[allow(clippy::missing_docs_in_private_items)] @@ -65,9 +69,11 @@ pub trait E: Sized { impl Foo { pub fn new() -> Self { + //~^ missing_docs_in_private_items Foo { a: 0, b: 0 } } fn bar() {} + //~^ missing_docs_in_private_items } impl PubFoo { @@ -76,6 +82,7 @@ impl PubFoo { pub fn foo1() {} #[must_use = "yep"] fn foo2() -> u32 { + //~^ missing_docs_in_private_items 1 } #[allow(clippy::missing_docs_in_private_items)] diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr index e2052c346df8f..999ff06f593e9 100644 --- a/src/tools/clippy/tests/ui/missing_doc_impl.stderr +++ b/src/tools/clippy/tests/ui/missing_doc_impl.stderr @@ -2,8 +2,9 @@ error: missing documentation for a struct --> tests/ui/missing_doc_impl.rs:13:1 | LL | / struct Foo { +LL | | LL | | a: isize, -LL | | b: isize, +... | LL | | } | |_^ | @@ -11,41 +12,43 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]` error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:14:5 + --> tests/ui/missing_doc_impl.rs:15:5 | LL | a: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:15:5 + --> tests/ui/missing_doc_impl.rs:17:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> tests/ui/missing_doc_impl.rs:20:5 + --> tests/ui/missing_doc_impl.rs:23:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:67:5 + --> tests/ui/missing_doc_impl.rs:71:5 | LL | / pub fn new() -> Self { +LL | | LL | | Foo { a: 0, b: 0 } LL | | } | |_____^ error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:70:5 + --> tests/ui/missing_doc_impl.rs:75:5 | LL | fn bar() {} | ^^^^^^^^^^^ error: missing documentation for an associated function - --> tests/ui/missing_doc_impl.rs:78:5 + --> tests/ui/missing_doc_impl.rs:84:5 | LL | / fn foo2() -> u32 { +LL | | LL | | 1 LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/missing_fields_in_debug.rs b/src/tools/clippy/tests/ui/missing_fields_in_debug.rs index 68867ec819d14..14803b5485a11 100644 --- a/src/tools/clippy/tests/ui/missing_fields_in_debug.rs +++ b/src/tools/clippy/tests/ui/missing_fields_in_debug.rs @@ -12,7 +12,8 @@ struct NamedStruct1Ignored { } impl fmt::Debug for NamedStruct1Ignored { - //~^ ERROR: manual `Debug` impl does not include all fields + //~^ missing_fields_in_debug + // unused field: hidden fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter @@ -31,7 +32,8 @@ struct NamedStructMultipleIgnored { } impl fmt::Debug for NamedStructMultipleIgnored { - //~^ ERROR: manual `Debug` impl does not include all fields + //~^ missing_fields_in_debug + // unused fields: hidden, hidden2, hidden4 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter @@ -93,7 +95,8 @@ struct MultiExprDebugImpl { // ok impl fmt::Debug for MultiExprDebugImpl { - //~^ ERROR: manual `Debug` impl does not include all fields + //~^ missing_fields_in_debug + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let mut f = formatter.debug_struct("MultiExprDebugImpl"); f.field("a", &self.a); diff --git a/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr index 5e51194c4b372..75b551e1f5c7e 100644 --- a/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr +++ b/src/tools/clippy/tests/ui/missing_fields_in_debug.stderr @@ -2,9 +2,6 @@ error: manual `Debug` impl does not include all fields --> tests/ui/missing_fields_in_debug.rs:14:1 | LL | / impl fmt::Debug for NamedStruct1Ignored { -LL | | -LL | | // unused field: hidden -LL | | fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { ... | LL | | } | |_^ @@ -20,28 +17,25 @@ LL | hidden: u32, = help: to override `-D warnings` add `#[allow(clippy::missing_fields_in_debug)]` error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:33:1 + --> tests/ui/missing_fields_in_debug.rs:34:1 | LL | / impl fmt::Debug for NamedStructMultipleIgnored { -LL | | -LL | | // unused fields: hidden, hidden2, hidden4 -LL | | fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { ... | LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:27:5 + --> tests/ui/missing_fields_in_debug.rs:28:5 | LL | hidden: u32, | ^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:28:5 + --> tests/ui/missing_fields_in_debug.rs:29:5 | LL | hidden2: String, | ^^^^^^^^^^^^^^^ note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:30:5 + --> tests/ui/missing_fields_in_debug.rs:31:5 | LL | hidden4: ((((u8), u16), u32), u64), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,18 +43,18 @@ LL | hidden4: ((((u8), u16), u32), u64), = help: consider calling `.finish_non_exhaustive()` if you intend to ignore fields error: manual `Debug` impl does not include all fields - --> tests/ui/missing_fields_in_debug.rs:95:1 + --> tests/ui/missing_fields_in_debug.rs:97:1 | LL | / impl fmt::Debug for MultiExprDebugImpl { LL | | +LL | | LL | | fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { -LL | | let mut f = formatter.debug_struct("MultiExprDebugImpl"); ... | LL | | } | |_^ | note: this field is unused - --> tests/ui/missing_fields_in_debug.rs:91:5 + --> tests/ui/missing_fields_in_debug.rs:93:5 | LL | b: String, | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_inline.rs b/src/tools/clippy/tests/ui/missing_inline.rs index dca85b94d5ee5..c1801005b777a 100644 --- a/src/tools/clippy/tests/ui/missing_inline.rs +++ b/src/tools/clippy/tests/ui/missing_inline.rs @@ -18,8 +18,8 @@ pub mod pub_module {} // ok fn foo() {} // missing #[inline] pub fn pub_foo() {} -//~^ ERROR: missing `#[inline]` for a function -//~| NOTE: `-D clippy::missing-inline-in-public-items` implied by `-D warnings` +//~^ missing_inline_in_public_items + #[inline] pub fn pub_foo_inline() {} // ok #[inline(always)] @@ -37,7 +37,8 @@ pub trait PubBar { fn PubBar_a(); // ok // missing #[inline] fn PubBar_b() {} - //~^ ERROR: missing `#[inline]` for a default trait method + //~^ missing_inline_in_public_items + #[inline] fn PubBar_c() {} // ok } @@ -53,13 +54,15 @@ impl PubBar for Foo { impl PubBar for PubFoo { // missing #[inline] fn PubBar_a() {} - //~^ ERROR: missing `#[inline]` for a method + //~^ missing_inline_in_public_items + // missing #[inline] fn PubBar_b() {} - //~^ ERROR: missing `#[inline]` for a method + //~^ missing_inline_in_public_items + // missing #[inline] fn PubBar_c() {} - //~^ ERROR: missing `#[inline]` for a method + //~^ missing_inline_in_public_items } // do not need inline because Foo is not exported @@ -71,7 +74,7 @@ impl Foo { impl PubFoo { // missing #[inline] pub fn PubFooImpl() {} - //~^ ERROR: missing `#[inline]` for a method + //~^ missing_inline_in_public_items } // do not lint this since users cannot control the external code diff --git a/src/tools/clippy/tests/ui/missing_inline.stderr b/src/tools/clippy/tests/ui/missing_inline.stderr index c2bb37141a025..99ee828e805ca 100644 --- a/src/tools/clippy/tests/ui/missing_inline.stderr +++ b/src/tools/clippy/tests/ui/missing_inline.stderr @@ -14,25 +14,25 @@ LL | fn PubBar_b() {} | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> tests/ui/missing_inline.rs:55:5 + --> tests/ui/missing_inline.rs:56:5 | LL | fn PubBar_a() {} | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> tests/ui/missing_inline.rs:58:5 + --> tests/ui/missing_inline.rs:60:5 | LL | fn PubBar_b() {} | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> tests/ui/missing_inline.rs:61:5 + --> tests/ui/missing_inline.rs:64:5 | LL | fn PubBar_c() {} | ^^^^^^^^^^^^^^^^ error: missing `#[inline]` for a method - --> tests/ui/missing_inline.rs:73:5 + --> tests/ui/missing_inline.rs:76:5 | LL | pub fn PubFooImpl() {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_inline_executable.rs b/src/tools/clippy/tests/ui/missing_inline_executable.rs index 6e0400ac935bb..444a7f1c964f0 100644 --- a/src/tools/clippy/tests/ui/missing_inline_executable.rs +++ b/src/tools/clippy/tests/ui/missing_inline_executable.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::missing_inline_in_public_items)] pub fn foo() {} diff --git a/src/tools/clippy/tests/ui/missing_inline_proc_macro.rs b/src/tools/clippy/tests/ui/missing_inline_proc_macro.rs index e47a198c6aeaf..ce368304f725a 100644 --- a/src/tools/clippy/tests/ui/missing_inline_proc_macro.rs +++ b/src/tools/clippy/tests/ui/missing_inline_proc_macro.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::missing_inline_in_public_items)] extern crate proc_macro; diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs index b0fa8e9885988..95e361c5d5556 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.rs +++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs @@ -11,17 +11,20 @@ fn main() {} /// This needs to be documented pub fn unwrap() { + //~^ missing_panics_doc let result = Err("Hi"); result.unwrap() } /// This needs to be documented pub fn panic() { + //~^ missing_panics_doc panic!("This function panics") } /// This needs to be documented pub fn inner_body(opt: Option) { + //~^ missing_panics_doc opt.map(|x| { if x == 10 { panic!() @@ -31,17 +34,20 @@ pub fn inner_body(opt: Option) { /// This needs to be documented pub fn unreachable_and_panic() { + //~^ missing_panics_doc if true { unreachable!() } else { panic!() } } /// This needs to be documented pub fn assert_eq() { + //~^ missing_panics_doc let x = 0; assert_eq!(x, 0); } /// This needs to be documented pub fn assert_ne() { + //~^ missing_panics_doc let x = 0; assert_ne!(x, 0); } @@ -149,30 +155,36 @@ pub fn debug_assertions() { // `pub` is required, because the lint does not consider unreachable items pub mod issue10240 { pub fn option_unwrap(v: &[T]) -> &T { + //~^ missing_panics_doc let o: Option<&T> = v.last(); o.unwrap() } pub fn option_expect(v: &[T]) -> &T { + //~^ missing_panics_doc let o: Option<&T> = v.last(); o.expect("passed an empty thing") } pub fn result_unwrap(v: &[T]) -> &T { + //~^ missing_panics_doc let res: Result<&T, &str> = v.last().ok_or("oh noes"); res.unwrap() } pub fn result_expect(v: &[T]) -> &T { + //~^ missing_panics_doc let res: Result<&T, &str> = v.last().ok_or("oh noes"); res.expect("passed an empty thing") } pub fn last_unwrap(v: &[u32]) -> u32 { + //~^ missing_panics_doc *v.last().unwrap() } pub fn last_expect(v: &[u32]) -> u32 { + //~^ missing_panics_doc *v.last().expect("passed an empty thing") } } diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.stderr b/src/tools/clippy/tests/ui/missing_panics_doc.stderr index c6a939d86f7c7..a83e2fa367dd3 100644 --- a/src/tools/clippy/tests/ui/missing_panics_doc.stderr +++ b/src/tools/clippy/tests/ui/missing_panics_doc.stderr @@ -5,7 +5,7 @@ LL | pub fn unwrap() { | ^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:15:5 + --> tests/ui/missing_panics_doc.rs:16:5 | LL | result.unwrap() | ^^^^^^^^^^^^^^^ @@ -13,133 +13,133 @@ LL | result.unwrap() = help: to override `-D warnings` add `#[allow(clippy::missing_panics_doc)]` error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:19:1 + --> tests/ui/missing_panics_doc.rs:20:1 | LL | pub fn panic() { | ^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:20:5 + --> tests/ui/missing_panics_doc.rs:22:5 | LL | panic!("This function panics") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:24:1 + --> tests/ui/missing_panics_doc.rs:26:1 | LL | pub fn inner_body(opt: Option) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:27:13 + --> tests/ui/missing_panics_doc.rs:30:13 | LL | panic!() | ^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:33:1 + --> tests/ui/missing_panics_doc.rs:36:1 | LL | pub fn unreachable_and_panic() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:34:39 + --> tests/ui/missing_panics_doc.rs:38:39 | LL | if true { unreachable!() } else { panic!() } | ^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:38:1 + --> tests/ui/missing_panics_doc.rs:42:1 | LL | pub fn assert_eq() { | ^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:40:5 + --> tests/ui/missing_panics_doc.rs:45:5 | LL | assert_eq!(x, 0); | ^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:44:1 + --> tests/ui/missing_panics_doc.rs:49:1 | LL | pub fn assert_ne() { | ^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:46:5 + --> tests/ui/missing_panics_doc.rs:52:5 | LL | assert_ne!(x, 0); | ^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:151:5 + --> tests/ui/missing_panics_doc.rs:157:5 | LL | pub fn option_unwrap(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:153:9 + --> tests/ui/missing_panics_doc.rs:160:9 | LL | o.unwrap() | ^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:156:5 + --> tests/ui/missing_panics_doc.rs:163:5 | LL | pub fn option_expect(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:158:9 + --> tests/ui/missing_panics_doc.rs:166:9 | LL | o.expect("passed an empty thing") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:161:5 + --> tests/ui/missing_panics_doc.rs:169:5 | LL | pub fn result_unwrap(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:163:9 + --> tests/ui/missing_panics_doc.rs:172:9 | LL | res.unwrap() | ^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:166:5 + --> tests/ui/missing_panics_doc.rs:175:5 | LL | pub fn result_expect(v: &[T]) -> &T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:168:9 + --> tests/ui/missing_panics_doc.rs:178:9 | LL | res.expect("passed an empty thing") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:171:5 + --> tests/ui/missing_panics_doc.rs:181:5 | LL | pub fn last_unwrap(v: &[u32]) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:172:10 + --> tests/ui/missing_panics_doc.rs:183:10 | LL | *v.last().unwrap() | ^^^^^^^^^^^^^^^^^ error: docs for function which may panic missing `# Panics` section - --> tests/ui/missing_panics_doc.rs:175:5 + --> tests/ui/missing_panics_doc.rs:186:5 | LL | pub fn last_expect(v: &[u32]) -> u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: first possible panic found here - --> tests/ui/missing_panics_doc.rs:176:10 + --> tests/ui/missing_panics_doc.rs:188:10 | LL | *v.last().expect("passed an empty thing") | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing_spin_loop.fixed b/src/tools/clippy/tests/ui/missing_spin_loop.fixed index b6520d478be8b..03fbf8ccc8a37 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop.fixed +++ b/src/tools/clippy/tests/ui/missing_spin_loop.fixed @@ -8,16 +8,22 @@ fn main() { let b = AtomicBool::new(true); // Those should lint while b.load(Ordering::Acquire) { std::hint::spin_loop() } + //~^ missing_spin_loop while !b.load(Ordering::SeqCst) { std::hint::spin_loop() } + //~^ missing_spin_loop while b.load(Ordering::Acquire) == false { std::hint::spin_loop() } + //~^ missing_spin_loop while { true == b.load(Ordering::Acquire) } { std::hint::spin_loop() } + //~^ missing_spin_loop while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) { std::hint::spin_loop() } + //~^ missing_spin_loop while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) { std::hint::spin_loop() } + //~^ missing_spin_loop // This is OK, as the body is not empty while b.load(Ordering::Acquire) { diff --git a/src/tools/clippy/tests/ui/missing_spin_loop.rs b/src/tools/clippy/tests/ui/missing_spin_loop.rs index 7b115c66ade6e..bf18590b9408e 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop.rs +++ b/src/tools/clippy/tests/ui/missing_spin_loop.rs @@ -8,16 +8,22 @@ fn main() { let b = AtomicBool::new(true); // Those should lint while b.load(Ordering::Acquire) {} + //~^ missing_spin_loop while !b.load(Ordering::SeqCst) {} + //~^ missing_spin_loop while b.load(Ordering::Acquire) == false {} + //~^ missing_spin_loop while { true == b.load(Ordering::Acquire) } {} + //~^ missing_spin_loop while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {} + //~^ missing_spin_loop while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {} + //~^ missing_spin_loop // This is OK, as the body is not empty while b.load(Ordering::Acquire) { diff --git a/src/tools/clippy/tests/ui/missing_spin_loop.stderr b/src/tools/clippy/tests/ui/missing_spin_loop.stderr index 12f4b53a3d187..98c32d0423469 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop.stderr +++ b/src/tools/clippy/tests/ui/missing_spin_loop.stderr @@ -8,31 +8,31 @@ LL | while b.load(Ordering::Acquire) {} = help: to override `-D warnings` add `#[allow(clippy::missing_spin_loop)]` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:12:37 + --> tests/ui/missing_spin_loop.rs:13:37 | LL | while !b.load(Ordering::SeqCst) {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:14:46 + --> tests/ui/missing_spin_loop.rs:16:46 | LL | while b.load(Ordering::Acquire) == false {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:16:49 + --> tests/ui/missing_spin_loop.rs:19:49 | LL | while { true == b.load(Ordering::Acquire) } {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:18:93 + --> tests/ui/missing_spin_loop.rs:22:93 | LL | while b.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) != Ok(true) {} | ^^ help: try: `{ std::hint::spin_loop() }` error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop.rs:20:94 + --> tests/ui/missing_spin_loop.rs:25:94 | LL | while Ok(false) != b.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) {} | ^^ help: try: `{ std::hint::spin_loop() }` diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed index 771ab1ab21a82..a525d414670ee 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed @@ -9,5 +9,6 @@ pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let b = AtomicBool::new(true); // This should lint with `core::hint::spin_loop()` while b.load(Ordering::Acquire) { core::hint::spin_loop() } + //~^ missing_spin_loop 0 } diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs index bf890fc4066b5..3b421f32c34f5 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs @@ -9,5 +9,6 @@ pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let b = AtomicBool::new(true); // This should lint with `core::hint::spin_loop()` while b.load(Ordering::Acquire) {} + //~^ missing_spin_loop 0 } diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.rs b/src/tools/clippy/tests/ui/missing_trait_methods.rs index 55b904bde59af..7af186ba33220 100644 --- a/src/tools/clippy/tests/ui/missing_trait_methods.rs +++ b/src/tools/clippy/tests/ui/missing_trait_methods.rs @@ -20,10 +20,11 @@ trait B { struct Partial; impl A for Partial {} -//~^ ERROR: missing trait method provided by default: `provided` +//~^ missing_trait_methods impl B for Partial { - //~^ ERROR: missing trait method provided by default: `b` + //~^ missing_trait_methods + fn required() {} fn a(_: usize) -> usize { @@ -56,5 +57,8 @@ trait MissingMultiple { } impl MissingMultiple for Partial {} +//~^ missing_trait_methods +//~| missing_trait_methods +//~| missing_trait_methods fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_trait_methods.stderr b/src/tools/clippy/tests/ui/missing_trait_methods.stderr index 9c4968b022d7e..d9fb8951ab3db 100644 --- a/src/tools/clippy/tests/ui/missing_trait_methods.stderr +++ b/src/tools/clippy/tests/ui/missing_trait_methods.stderr @@ -25,37 +25,37 @@ LL | fn b<'a, T: AsRef<[u8]>>(a: &'a T) -> &'a [u8] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing trait method provided by default: `one` - --> tests/ui/missing_trait_methods.rs:58:1 + --> tests/ui/missing_trait_methods.rs:59:1 | LL | impl MissingMultiple for Partial {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: implement the method - --> tests/ui/missing_trait_methods.rs:53:5 + --> tests/ui/missing_trait_methods.rs:54:5 | LL | fn one() {} | ^^^^^^^^ error: missing trait method provided by default: `two` - --> tests/ui/missing_trait_methods.rs:58:1 + --> tests/ui/missing_trait_methods.rs:59:1 | LL | impl MissingMultiple for Partial {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: implement the method - --> tests/ui/missing_trait_methods.rs:54:5 + --> tests/ui/missing_trait_methods.rs:55:5 | LL | fn two() {} | ^^^^^^^^ error: missing trait method provided by default: `three` - --> tests/ui/missing_trait_methods.rs:58:1 + --> tests/ui/missing_trait_methods.rs:59:1 | LL | impl MissingMultiple for Partial {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: implement the method - --> tests/ui/missing_trait_methods.rs:55:5 + --> tests/ui/missing_trait_methods.rs:56:5 | LL | fn three() {} | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed index b84b3dc349ec3..a0190acc5d4b3 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed @@ -14,35 +14,58 @@ use proc_macros::with_span; fn main() { let fail14 = 2_i32; + //~^ mistyped_literal_suffixes let fail15 = 4_i64; + //~^ mistyped_literal_suffixes let fail16 = 7_i8; // + // + //~^^ mistyped_literal_suffixes let fail17 = 23_i16; // + // + //~^^ mistyped_literal_suffixes let ok18 = 23_128; let fail20 = 2_i8; // + // + //~^^ mistyped_literal_suffixes let fail21 = 4_i16; // + // + //~^^ mistyped_literal_suffixes let ok24 = 12.34_64; let fail25 = 1E2_f32; + //~^ mistyped_literal_suffixes let fail26 = 43E7_f64; + //~^ mistyped_literal_suffixes let fail27 = 243E17_f32; + //~^ mistyped_literal_suffixes let fail28 = 241_251_235E723_f64; + //~^ mistyped_literal_suffixes let ok29 = 42279.911_32; // testing that the suggestion actually fits in its type let fail30 = 127_i8; // should be i8 + // + //~^^ mistyped_literal_suffixes let fail31 = 240_u8; // should be u8 + // + //~^^ mistyped_literal_suffixes let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_i16; + //~^ mistyped_literal_suffixes let fail34 = 0xABCD_u16; + //~^ mistyped_literal_suffixes let ok35 = 0x12345_16; let fail36 = 0xFFFF_FFFF_FFFF_FFFF_u64; // u64 + // + //~^^ mistyped_literal_suffixes // issue #6129 let ok37 = 123_32.123; let ok38 = 124_64.0; let _ = 1.123_45E1_f32; + //~^ mistyped_literal_suffixes let _ = with_span!(1 2_u32); } diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs index a47a736067a85..12a26204e7557 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs @@ -14,35 +14,58 @@ use proc_macros::with_span; fn main() { let fail14 = 2_32; + //~^ mistyped_literal_suffixes let fail15 = 4_64; + //~^ mistyped_literal_suffixes let fail16 = 7_8; // + // + //~^^ mistyped_literal_suffixes let fail17 = 23_16; // + // + //~^^ mistyped_literal_suffixes let ok18 = 23_128; let fail20 = 2__8; // + // + //~^^ mistyped_literal_suffixes let fail21 = 4___16; // + // + //~^^ mistyped_literal_suffixes let ok24 = 12.34_64; let fail25 = 1E2_32; + //~^ mistyped_literal_suffixes let fail26 = 43E7_64; + //~^ mistyped_literal_suffixes let fail27 = 243E17_32; + //~^ mistyped_literal_suffixes let fail28 = 241251235E723_64; + //~^ mistyped_literal_suffixes let ok29 = 42279.911_32; // testing that the suggestion actually fits in its type let fail30 = 127_8; // should be i8 + // + //~^^ mistyped_literal_suffixes let fail31 = 240_8; // should be u8 + // + //~^^ mistyped_literal_suffixes let ok32 = 360_8; // doesn't fit in either, should be ignored let fail33 = 0x1234_16; + //~^ mistyped_literal_suffixes let fail34 = 0xABCD_16; + //~^ mistyped_literal_suffixes let ok35 = 0x12345_16; let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64 + // + //~^^ mistyped_literal_suffixes // issue #6129 let ok37 = 123_32.123; let ok38 = 124_64.0; let _ = 1.12345E1_32; + //~^ mistyped_literal_suffixes let _ = with_span!(1 2_u32); } diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr index 56bfb06d8e669..9c6b2fab21c31 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr @@ -7,91 +7,91 @@ LL | let fail14 = 2_32; = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:17:18 + --> tests/ui/mistyped_literal_suffix.rs:18:18 | LL | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:18:18 + --> tests/ui/mistyped_literal_suffix.rs:20:18 | LL | let fail16 = 7_8; // | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:19:18 + --> tests/ui/mistyped_literal_suffix.rs:23:18 | LL | let fail17 = 23_16; // | ^^^^^ help: did you mean to write: `23_i16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:22:18 + --> tests/ui/mistyped_literal_suffix.rs:28:18 | LL | let fail20 = 2__8; // | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:23:18 + --> tests/ui/mistyped_literal_suffix.rs:31:18 | LL | let fail21 = 4___16; // | ^^^^^^ help: did you mean to write: `4_i16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:26:18 + --> tests/ui/mistyped_literal_suffix.rs:36:18 | LL | let fail25 = 1E2_32; | ^^^^^^ help: did you mean to write: `1E2_f32` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:27:18 + --> tests/ui/mistyped_literal_suffix.rs:38:18 | LL | let fail26 = 43E7_64; | ^^^^^^^ help: did you mean to write: `43E7_f64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:28:18 + --> tests/ui/mistyped_literal_suffix.rs:40:18 | LL | let fail27 = 243E17_32; | ^^^^^^^^^ help: did you mean to write: `243E17_f32` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:29:18 + --> tests/ui/mistyped_literal_suffix.rs:42:18 | LL | let fail28 = 241251235E723_64; | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:33:18 + --> tests/ui/mistyped_literal_suffix.rs:47:18 | LL | let fail30 = 127_8; // should be i8 | ^^^^^ help: did you mean to write: `127_i8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:34:18 + --> tests/ui/mistyped_literal_suffix.rs:50:18 | LL | let fail31 = 240_8; // should be u8 | ^^^^^ help: did you mean to write: `240_u8` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:36:18 + --> tests/ui/mistyped_literal_suffix.rs:54:18 | LL | let fail33 = 0x1234_16; | ^^^^^^^^^ help: did you mean to write: `0x1234_i16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:37:18 + --> tests/ui/mistyped_literal_suffix.rs:56:18 | LL | let fail34 = 0xABCD_16; | ^^^^^^^^^ help: did you mean to write: `0xABCD_u16` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:39:18 + --> tests/ui/mistyped_literal_suffix.rs:59:18 | LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64` error: mistyped literal suffix - --> tests/ui/mistyped_literal_suffix.rs:45:13 + --> tests/ui/mistyped_literal_suffix.rs:67:13 | LL | let _ = 1.12345E1_32; | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32` 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 index df44b07a69414..43d22940415f0 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/auxiliary/submodule.rs @@ -3,7 +3,6 @@ #![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 index 153262e65570d..19a45e720a608 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/global_allow.rs @@ -1,4 +1,5 @@ -// issue 12436 +// https://github.com/rust-lang/rust-clippy/issues/12436 +//@check-pass #![allow(clippy::mixed_attributes_style)] #[path = "auxiliary/submodule.rs"] 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 index b0f1f0bda9e60..8cef6a80048a5 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.rs @@ -1,3 +1,5 @@ +//@error-in-other-file: item has both inner and outer attributes +//@no-rustfix #[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 index 968c537c7e44f..1239742a05b7e 100644 --- a/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr +++ b/src/tools/clippy/tests/ui/mixed_attributes_style/mod_declaration.stderr @@ -2,7 +2,6 @@ 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)] | |________________________^ diff --git a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs index 241536abdfbd7..2ead166bf8011 100644 --- a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs @@ -12,11 +12,12 @@ fn main() { x = 1; 1 } + x; - //~^ ERROR: unsequenced read of `x` + //~^ mixed_read_write_in_expression // Example from iss#277 x += { - //~^ ERROR: unsequenced read of `x` + //~^ mixed_read_write_in_expression + x = 20; 2 }; @@ -30,7 +31,7 @@ fn main() { let base = Foo { a: 4, b: 5 }; let foo = Foo { a: x, - //~^ ERROR: unsequenced read of `x` + //~^ mixed_read_write_in_expression ..{ x = 6; base @@ -40,7 +41,8 @@ fn main() { let closure = || { let mut x = 0; x += { - //~^ ERROR: unsequenced read of `x` + //~^ mixed_read_write_in_expression + x = 20; 2 }; diff --git a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr index 796d4ccd26b72..e34dce2bb132c 100644 --- a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr +++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.stderr @@ -19,31 +19,31 @@ LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> tests/ui/mixed_read_write_in_expression.rs:20:9 + --> tests/ui/mixed_read_write_in_expression.rs:21:9 | LL | x = 20; | ^^^^^^ error: unsequenced read of `x` - --> tests/ui/mixed_read_write_in_expression.rs:32:12 + --> tests/ui/mixed_read_write_in_expression.rs:33:12 | LL | a: x, | ^ | note: whether read occurs before this write depends on evaluation order - --> tests/ui/mixed_read_write_in_expression.rs:35:13 + --> tests/ui/mixed_read_write_in_expression.rs:36:13 | LL | x = 6; | ^^^^^ error: unsequenced read of `x` - --> tests/ui/mixed_read_write_in_expression.rs:42:9 + --> tests/ui/mixed_read_write_in_expression.rs:43:9 | LL | x += { | ^ | note: whether read occurs before this write depends on evaluation order - --> tests/ui/mixed_read_write_in_expression.rs:44:13 + --> tests/ui/mixed_read_write_in_expression.rs:46:13 | LL | x = 20; | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/module_inception.rs b/src/tools/clippy/tests/ui/module_inception.rs index ad46e0c29aee3..15b7fb8777700 100644 --- a/src/tools/clippy/tests/ui/module_inception.rs +++ b/src/tools/clippy/tests/ui/module_inception.rs @@ -3,14 +3,15 @@ pub mod foo2 { pub mod bar2 { pub mod bar2 { - //~^ ERROR: module has the same name as its containing module - //~| NOTE: `-D clippy::module-inception` implied by `-D warnings` + //~^ module_inception + pub mod foo2 {} } pub mod foo2 {} } pub mod foo2 { - //~^ ERROR: module has the same name as its containing module + //~^ module_inception + pub mod bar2 {} } } @@ -18,13 +19,15 @@ pub mod foo2 { mod foo { mod bar { mod bar { - //~^ ERROR: module has the same name as its containing module + //~^ module_inception + mod foo {} } mod foo {} } mod foo { - //~^ ERROR: module has the same name as its containing module + //~^ module_inception + mod bar {} } } diff --git a/src/tools/clippy/tests/ui/module_inception.stderr b/src/tools/clippy/tests/ui/module_inception.stderr index 455f5372747a4..8e7d555cebc67 100644 --- a/src/tools/clippy/tests/ui/module_inception.stderr +++ b/src/tools/clippy/tests/ui/module_inception.stderr @@ -16,24 +16,27 @@ error: module has the same name as its containing module | LL | / pub mod foo2 { LL | | +LL | | LL | | pub mod bar2 {} LL | | } | |_____^ error: module has the same name as its containing module - --> tests/ui/module_inception.rs:20:9 + --> tests/ui/module_inception.rs:21:9 | LL | / mod bar { LL | | +LL | | LL | | mod foo {} LL | | } | |_________^ error: module has the same name as its containing module - --> tests/ui/module_inception.rs:26:5 + --> tests/ui/module_inception.rs:28:5 | LL | / mod foo { LL | | +LL | | LL | | mod bar {} LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs index 71d8ac7a1f0e0..2fde98d7927c2 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.rs +++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs @@ -6,16 +6,19 @@ pub mod foo { pub fn foo() {} pub fn foo_bar() {} - //~^ ERROR: item name starts with its containing module's name - //~| NOTE: `-D clippy::module-name-repetitions` implied by `-D warnings` + //~^ module_name_repetitions + pub fn bar_foo() {} - //~^ ERROR: item name ends with its containing module's name + //~^ module_name_repetitions + pub struct FooCake; - //~^ ERROR: item name starts with its containing module's name + //~^ module_name_repetitions + pub enum CakeFoo {} - //~^ ERROR: item name ends with its containing module's name + //~^ module_name_repetitions + pub struct Foo7Bar; - //~^ ERROR: item name starts with its containing module's name + //~^ module_name_repetitions // Should not warn pub struct Foobar; @@ -28,7 +31,7 @@ pub mod foo { pub use error::Error; // ... but should still warn when the item is reexported to create a *public* path with repetition. pub use error::FooError; - //~^ ERROR: item name starts with its containing module's name + //~^ module_name_repetitions // FIXME: This should also warn because it creates the public path `foo::FooIter`. mod iter { diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.stderr b/src/tools/clippy/tests/ui/module_name_repetitions.stderr index 8fd8b39487537..9000c44a3902e 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.stderr +++ b/src/tools/clippy/tests/ui/module_name_repetitions.stderr @@ -14,25 +14,25 @@ LL | pub fn bar_foo() {} | ^^^^^^^ error: item name starts with its containing module's name - --> tests/ui/module_name_repetitions.rs:13:16 + --> tests/ui/module_name_repetitions.rs:14:16 | LL | pub struct FooCake; | ^^^^^^^ error: item name ends with its containing module's name - --> tests/ui/module_name_repetitions.rs:15:14 + --> tests/ui/module_name_repetitions.rs:17:14 | LL | pub enum CakeFoo {} | ^^^^^^^ error: item name starts with its containing module's name - --> tests/ui/module_name_repetitions.rs:17:16 + --> tests/ui/module_name_repetitions.rs:20:16 | LL | pub struct Foo7Bar; | ^^^^^^^ error: item name starts with its containing module's name - --> tests/ui/module_name_repetitions.rs:30:20 + --> tests/ui/module_name_repetitions.rs:33:20 | LL | pub use error::FooError; | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs index a5b63bed531b0..0e08174f686eb 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.rs @@ -6,67 +6,62 @@ fn main() { // Lint when both sides are const and of the opposite sign -1.6 % 2.1; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1.600 % - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1.6 % -2.1; - //~^ ERROR: you are using modulo operator on constants with different signs: `1.600 % - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + (1.1 - 2.3) % (1.1 + 2.3); - //~^ ERROR: you are using modulo operator on constants with different signs: `-1.200 % - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + (1.1 + 2.3) % (1.1 - 2.3); - //~^ ERROR: you are using modulo operator on constants with different signs: `3.400 % - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic // Lint on floating point numbers let a_f16: f16 = -1.6; let mut b_f16: f16 = 2.1; a_f16 % b_f16; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f16 % a_f16; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f16 %= a_f16; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic // Lint on floating point numbers let a_f32: f32 = -1.6; let mut b_f32: f32 = 2.1; a_f32 % b_f32; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f32 % a_f32; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f32 %= a_f32; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_f64: f64 = -1.6; let mut b_f64: f64 = 2.1; a_f64 % b_f64; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f64 % a_f64; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f64 %= a_f64; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_f128: f128 = -1.6; let mut b_f128: f128 = 2.1; a_f128 % b_f128; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f128 % a_f128; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_f128 %= a_f128; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic // No lint when both sides are const and of the same sign 1.6 % 2.1; diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr index 2b4937552bdab..91b5c80ce9f4e 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_float.stderr @@ -33,7 +33,7 @@ LL | (1.1 + 2.3) % (1.1 - 2.3); = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:24:5 + --> tests/ui/modulo_arithmetic_float.rs:23:5 | LL | a_f16 % b_f16; | ^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | a_f16 % b_f16; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:27:5 + --> tests/ui/modulo_arithmetic_float.rs:26:5 | LL | b_f16 % a_f16; | ^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | b_f16 % a_f16; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:30:5 + --> tests/ui/modulo_arithmetic_float.rs:29:5 | LL | b_f16 %= a_f16; | ^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | b_f16 %= a_f16; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:37:5 + --> tests/ui/modulo_arithmetic_float.rs:35:5 | LL | a_f32 % b_f32; | ^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | a_f32 % b_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:40:5 + --> tests/ui/modulo_arithmetic_float.rs:38:5 | LL | b_f32 % a_f32; | ^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | b_f32 % a_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:43:5 + --> tests/ui/modulo_arithmetic_float.rs:41:5 | LL | b_f32 %= a_f32; | ^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | b_f32 %= a_f32; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:49:5 + --> tests/ui/modulo_arithmetic_float.rs:46:5 | LL | a_f64 % b_f64; | ^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | a_f64 % b_f64; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:52:5 + --> tests/ui/modulo_arithmetic_float.rs:49:5 | LL | b_f64 % a_f64; | ^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | b_f64 % a_f64; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:55:5 + --> tests/ui/modulo_arithmetic_float.rs:52:5 | LL | b_f64 %= a_f64; | ^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | b_f64 %= a_f64; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:61:5 + --> tests/ui/modulo_arithmetic_float.rs:57:5 | LL | a_f128 % b_f128; | ^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | a_f128 % b_f128; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:64:5 + --> tests/ui/modulo_arithmetic_float.rs:60:5 | LL | b_f128 % a_f128; | ^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | b_f128 % a_f128; = note: double check for expected result especially when interoperating with different languages error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_float.rs:67:5 + --> tests/ui/modulo_arithmetic_float.rs:63:5 | LL | b_f128 %= a_f128; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs index c427b8580e17a..d7cd910e43cb7 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.rs @@ -6,77 +6,69 @@ fn main() { let a = -1; let mut b = 2; a % b; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b % a; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b %= a; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_i8: i8 = 1; let mut b_i8: i8 = 2; a_i8 % b_i8; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_i8 %= a_i8; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_i16: i16 = 1; let mut b_i16: i16 = 2; a_i16 % b_i16; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_i16 %= a_i16; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_i32: i32 = 1; let mut b_i32: i32 = 2; a_i32 % b_i32; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_i32 %= a_i32; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_i64: i64 = 1; let mut b_i64: i64 = 2; a_i64 % b_i64; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_i64 %= a_i64; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_i128: i128 = 1; let mut b_i128: i128 = 2; a_i128 % b_i128; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_i128 %= a_i128; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a_isize: isize = 1; let mut b_isize: isize = 2; a_isize % b_isize; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b_isize %= a_isize; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic let a = 1; let mut b = 2; a % b; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + b %= a; - //~^ ERROR: you are using modulo operator on types that might have different signs - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic // No lint on unsigned integral value let a_u8: u8 = 17; diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr index f1cfe791a03b0..d1b71cdab5e42 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral.stderr @@ -28,7 +28,7 @@ LL | b %= a; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:20:5 + --> tests/ui/modulo_arithmetic_integral.rs:19:5 | LL | a_i8 % b_i8; | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | a_i8 % b_i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:23:5 + --> tests/ui/modulo_arithmetic_integral.rs:22:5 | LL | b_i8 %= a_i8; | ^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | b_i8 %= a_i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:29:5 + --> tests/ui/modulo_arithmetic_integral.rs:27:5 | LL | a_i16 % b_i16; | ^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | a_i16 % b_i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:32:5 + --> tests/ui/modulo_arithmetic_integral.rs:30:5 | LL | b_i16 %= a_i16; | ^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | b_i16 %= a_i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:38:5 + --> tests/ui/modulo_arithmetic_integral.rs:35:5 | LL | a_i32 % b_i32; | ^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | a_i32 % b_i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:41:5 + --> tests/ui/modulo_arithmetic_integral.rs:38:5 | LL | b_i32 %= a_i32; | ^^^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | b_i32 %= a_i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:47:5 + --> tests/ui/modulo_arithmetic_integral.rs:43:5 | LL | a_i64 % b_i64; | ^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | a_i64 % b_i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:50:5 + --> tests/ui/modulo_arithmetic_integral.rs:46:5 | LL | b_i64 %= a_i64; | ^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | b_i64 %= a_i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:56:5 + --> tests/ui/modulo_arithmetic_integral.rs:51:5 | LL | a_i128 % b_i128; | ^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | a_i128 % b_i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:59:5 + --> tests/ui/modulo_arithmetic_integral.rs:54:5 | LL | b_i128 %= a_i128; | ^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | b_i128 %= a_i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:65:5 + --> tests/ui/modulo_arithmetic_integral.rs:59:5 | LL | a_isize % b_isize; | ^^^^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | a_isize % b_isize; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:68:5 + --> tests/ui/modulo_arithmetic_integral.rs:62:5 | LL | b_isize %= a_isize; | ^^^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | b_isize %= a_isize; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:74:5 + --> tests/ui/modulo_arithmetic_integral.rs:67:5 | LL | a % b; | ^^^^^ @@ -145,7 +145,7 @@ LL | a % b; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on types that might have different signs - --> tests/ui/modulo_arithmetic_integral.rs:77:5 + --> tests/ui/modulo_arithmetic_integral.rs:70:5 | LL | b %= a; | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs index dbc679a69825c..9f5fb697df0ea 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.rs @@ -9,57 +9,55 @@ fn main() { // Lint when both sides are const and of the opposite sign -1 % 2; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1 % -2; - //~^ ERROR: you are using modulo operator on constants with different signs: `1 % -2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + (1 - 2) % (1 + 2); - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 3` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + (1 + 2) % (1 - 2); - //~^ ERROR: you are using modulo operator on constants with different signs: `3 % -1` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 35 * (7 - 4 * 2) % (-500 * -600); - //~^ ERROR: you are using modulo operator on constants with different signs: `-35 % 30 - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic -1i8 % 2i8; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1i8 % -2i8; - //~^ ERROR: you are using modulo operator on constants with different signs: `1 % -2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + -1i16 % 2i16; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1i16 % -2i16; - //~^ ERROR: you are using modulo operator on constants with different signs: `1 % -2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + -1i32 % 2i32; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1i32 % -2i32; - //~^ ERROR: you are using modulo operator on constants with different signs: `1 % -2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + -1i64 % 2i64; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1i64 % -2i64; - //~^ ERROR: you are using modulo operator on constants with different signs: `1 % -2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + -1i128 % 2i128; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1i128 % -2i128; - //~^ ERROR: you are using modulo operator on constants with different signs: `1 % -2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + -1isize % 2isize; - //~^ ERROR: you are using modulo operator on constants with different signs: `-1 % 2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic + 1isize % -2isize; - //~^ ERROR: you are using modulo operator on constants with different signs: `1 % -2` - //~| NOTE: double check for expected result especially when interoperating with differ + //~^ modulo_arithmetic // No lint when both sides are const and of the same sign 1 % 2; diff --git a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr index 722d9b83660ee..12edee8cf4255 100644 --- a/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr +++ b/src/tools/clippy/tests/ui/modulo_arithmetic_integral_const.stderr @@ -46,7 +46,7 @@ LL | 35 * (7 - 4 * 2) % (-500 * -600); = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:27:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:26:5 | LL | -1i8 % 2i8; | ^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | -1i8 % 2i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:30:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:29:5 | LL | 1i8 % -2i8; | ^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | 1i8 % -2i8; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:33:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:32:5 | LL | -1i16 % 2i16; | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | -1i16 % 2i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:36:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:35:5 | LL | 1i16 % -2i16; | ^^^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | 1i16 % -2i16; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:39:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:38:5 | LL | -1i32 % 2i32; | ^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | -1i32 % 2i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:42:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:41:5 | LL | 1i32 % -2i32; | ^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | 1i32 % -2i32; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:45:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:44:5 | LL | -1i64 % 2i64; | ^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | -1i64 % 2i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:48:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:47:5 | LL | 1i64 % -2i64; | ^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | 1i64 % -2i64; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:51:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:50:5 | LL | -1i128 % 2i128; | ^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | -1i128 % 2i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:54:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:53:5 | LL | 1i128 % -2i128; | ^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | 1i128 % -2i128; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `-1 % 2` - --> tests/ui/modulo_arithmetic_integral_const.rs:57:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:56:5 | LL | -1isize % 2isize; | ^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | -1isize % 2isize; = note: or consider using `rem_euclid` or similar function error: you are using modulo operator on constants with different signs: `1 % -2` - --> tests/ui/modulo_arithmetic_integral_const.rs:60:5 + --> tests/ui/modulo_arithmetic_integral_const.rs:59:5 | LL | 1isize % -2isize; | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/modulo_one.rs b/src/tools/clippy/tests/ui/modulo_one.rs index c332a15f15778..63ae61059cb86 100644 --- a/src/tools/clippy/tests/ui/modulo_one.rs +++ b/src/tools/clippy/tests/ui/modulo_one.rs @@ -1,4 +1,5 @@ #![warn(clippy::modulo_one)] +#![allow(unconditional_panic)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::identity_op)] static STATIC_ONE: usize = 2 - 1; @@ -6,33 +7,34 @@ static STATIC_NEG_ONE: i64 = 1 - 2; fn main() { 10 % 1; - //~^ ERROR: any number modulo 1 will be 0 - //~| NOTE: `-D clippy::modulo-one` implied by `-D warnings` + //~^ modulo_one + 10 % -1; - //~^ ERROR: any number modulo -1 will panic/overflow or result in 0 + //~^ modulo_one + 10 % 2; // also caught by rustc i32::MIN % (-1); - //~^ ERROR: this operation will panic at runtime - //~| NOTE: `#[deny(unconditional_panic)]` on by default - //~| ERROR: any number modulo -1 will panic/overflow or result in 0 + //~^ modulo_one const ONE: u32 = 1 * 1; const NEG_ONE: i64 = 1 - 2; const INT_MIN: i64 = i64::MIN; 2 % ONE; - //~^ ERROR: any number modulo 1 will be 0 + //~^ modulo_one + // NOT caught by lint 5 % STATIC_ONE; 2 % NEG_ONE; - //~^ ERROR: any number modulo -1 will panic/overflow or result in 0 + //~^ modulo_one + // NOT caught by lint 5 % STATIC_NEG_ONE; // also caught by rustc INT_MIN % NEG_ONE; - //~^ ERROR: this operation will panic at runtime - //~| ERROR: any number modulo -1 will panic/overflow or result in 0 + //~^ modulo_one + // Not caught by lint, we don't look into static items, even if entirely immutable. INT_MIN % STATIC_NEG_ONE; } diff --git a/src/tools/clippy/tests/ui/modulo_one.stderr b/src/tools/clippy/tests/ui/modulo_one.stderr index aedcf24eae71e..1c9c79d1c6214 100644 --- a/src/tools/clippy/tests/ui/modulo_one.stderr +++ b/src/tools/clippy/tests/ui/modulo_one.stderr @@ -1,19 +1,5 @@ -error: this operation will panic at runtime - --> tests/ui/modulo_one.rs:15:5 - | -LL | i32::MIN % (-1); - | ^^^^^^^^^^^^^^^ attempt to compute `i32::MIN % -1_i32`, which would overflow - | - = note: `#[deny(unconditional_panic)]` on by default - -error: this operation will panic at runtime - --> tests/ui/modulo_one.rs:33:5 - | -LL | INT_MIN % NEG_ONE; - | ^^^^^^^^^^^^^^^^^ attempt to compute `i64::MIN % -1_i64`, which would overflow - error: any number modulo 1 will be 0 - --> tests/ui/modulo_one.rs:8:5 + --> tests/ui/modulo_one.rs:9:5 | LL | 10 % 1; | ^^^^^^ @@ -22,13 +8,13 @@ LL | 10 % 1; = help: to override `-D warnings` add `#[allow(clippy::modulo_one)]` error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:11:5 + --> tests/ui/modulo_one.rs:12:5 | LL | 10 % -1; | ^^^^^^^ error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:15:5 + --> tests/ui/modulo_one.rs:17:5 | LL | i32::MIN % (-1); | ^^^^^^^^^^^^^^^ @@ -40,16 +26,16 @@ LL | 2 % ONE; | ^^^^^^^ error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:28:5 + --> tests/ui/modulo_one.rs:29:5 | LL | 2 % NEG_ONE; | ^^^^^^^^^^^ error: any number modulo -1 will panic/overflow or result in 0 - --> tests/ui/modulo_one.rs:33:5 + --> tests/ui/modulo_one.rs:35:5 | LL | INT_MIN % NEG_ONE; | ^^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/msrv_attributes_without_early_lints.rs b/src/tools/clippy/tests/ui/msrv_attributes_without_early_lints.rs new file mode 100644 index 0000000000000..dcef1a485fceb --- /dev/null +++ b/src/tools/clippy/tests/ui/msrv_attributes_without_early_lints.rs @@ -0,0 +1,14 @@ +//@check-pass + +#![allow(clippy::all, clippy::pedantic, clippy::restriction, clippy::nursery)] +#![forbid(clippy::ptr_as_ptr)] + +/// MSRV checking in late passes skips checking the parent nodes if no early pass sees a +/// `#[clippy::msrv]` attribute +/// +/// Here we ensure that even if all early passes are allowed (above) the attribute is still detected +/// in late lints such as `clippy::ptr_as_ptr` +#[clippy::msrv = "1.37"] +fn f(p: *const i32) { + let _ = p as *const i64; +} diff --git a/src/tools/clippy/tests/ui/multi_assignments.rs b/src/tools/clippy/tests/ui/multi_assignments.rs index cdbf13b68889e..5a0d9a7aa37cb 100644 --- a/src/tools/clippy/tests/ui/multi_assignments.rs +++ b/src/tools/clippy/tests/ui/multi_assignments.rs @@ -2,15 +2,18 @@ fn main() { let (mut a, mut b, mut c, mut d) = ((), (), (), ()); a = b = c; - //~^ ERROR: assignments don't nest intuitively - //~| NOTE: `-D clippy::multi-assignments` implied by `-D warnings` + //~^ multi_assignments + a = b = c = d; - //~^ ERROR: assignments don't nest intuitively - //~| ERROR: assignments don't nest intuitively + //~^ multi_assignments + //~| multi_assignments + a = b = { c }; - //~^ ERROR: assignments don't nest intuitively + //~^ multi_assignments + a = { b = c }; - //~^ ERROR: assignments don't nest intuitively + //~^ multi_assignments + a = (b = c); - //~^ ERROR: assignments don't nest intuitively + //~^ multi_assignments } diff --git a/src/tools/clippy/tests/ui/multi_assignments.stderr b/src/tools/clippy/tests/ui/multi_assignments.stderr index 53c22fcdb4c07..f56489c0b4b72 100644 --- a/src/tools/clippy/tests/ui/multi_assignments.stderr +++ b/src/tools/clippy/tests/ui/multi_assignments.stderr @@ -20,19 +20,19 @@ LL | a = b = c = d; | ^^^^^^^^^ error: assignments don't nest intuitively - --> tests/ui/multi_assignments.rs:10:5 + --> tests/ui/multi_assignments.rs:11:5 | LL | a = b = { c }; | ^^^^^^^^^^^^^ error: assignments don't nest intuitively - --> tests/ui/multi_assignments.rs:12:5 + --> tests/ui/multi_assignments.rs:14:5 | LL | a = { b = c }; | ^^^^^^^^^^^^^ error: assignments don't nest intuitively - --> tests/ui/multi_assignments.rs:14:5 + --> tests/ui/multi_assignments.rs:17:5 | LL | a = (b = c); | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/multiple_bound_locations.rs b/src/tools/clippy/tests/ui/multiple_bound_locations.rs index de9d994782ece..95b269d8935df 100644 --- a/src/tools/clippy/tests/ui/multiple_bound_locations.rs +++ b/src/tools/clippy/tests/ui/multiple_bound_locations.rs @@ -1,21 +1,21 @@ #![warn(clippy::multiple_bound_locations)] fn ty(a: F) -//~^ ERROR: bound is defined in more than one place +//~^ multiple_bound_locations where F: Sized, { } fn lifetime<'a, 'b: 'a, 'c>(a: &'b str, b: &'a str, c: &'c str) -//~^ ERROR: bound is defined in more than one place +//~^ multiple_bound_locations where 'b: 'c, { } fn ty_pred() -//~^ ERROR: bound is defined in more than one place +//~^ multiple_bound_locations where for<'a> F: Send + 'a, { @@ -25,21 +25,21 @@ struct B; impl B { fn ty(a: F) - //~^ ERROR: bound is defined in more than one place + //~^ multiple_bound_locations where F: Sized, { } fn lifetime<'a, 'b: 'a, 'c>(a: &'b str, b: &'a str, c: &'c str) - //~^ ERROR: bound is defined in more than one place + //~^ multiple_bound_locations where 'b: 'c, { } fn ty_pred() - //~^ ERROR: bound is defined in more than one place + //~^ multiple_bound_locations where for<'a> F: Send + 'a, { diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs index 87d3517cd5f22..016fd89a7b7ac 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs @@ -36,6 +36,7 @@ static mut STATIC: i32 = 0; fn test1() { unsafe { + //~^ multiple_unsafe_ops_per_block STATIC += 1; not_very_safe(); } @@ -45,6 +46,7 @@ fn test2() { let u = U { i: 0 }; unsafe { + //~^ multiple_unsafe_ops_per_block drop(u.u); *raw_ptr(); } @@ -52,6 +54,7 @@ fn test2() { fn test3() { unsafe { + //~^ multiple_unsafe_ops_per_block asm!("nop"); sample.not_very_safe(); STATIC = 0; @@ -61,6 +64,7 @@ fn test3() { fn test_all() { let u = U { i: 0 }; unsafe { + //~^ multiple_unsafe_ops_per_block drop(u.u); drop(STATIC); sample.not_very_safe(); @@ -105,6 +109,7 @@ fn correct3() { unsafe fn read_char_bad(ptr: *const u8) -> char { unsafe { char::from_u32_unchecked(*ptr.cast::()) } + //~^ multiple_unsafe_ops_per_block } // no lint @@ -123,6 +128,7 @@ fn issue10259() { fn _fn_ptr(x: unsafe fn()) { unsafe { + //~^ multiple_unsafe_ops_per_block x(); x(); } @@ -134,6 +140,7 @@ fn _assoc_const() { } fn _f() { unsafe { + //~^ multiple_unsafe_ops_per_block T::X(); T::X(); } @@ -144,6 +151,7 @@ fn _field_fn_ptr(x: unsafe fn()) { struct X(unsafe fn()); let x = X(x); unsafe { + //~^ multiple_unsafe_ops_per_block x.0(); x.0(); } diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr index a9417a9ef91c7..3130cecc25250 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr @@ -2,18 +2,19 @@ error: this `unsafe` block contains 2 unsafe operations, expected only one --> tests/ui/multiple_unsafe_ops_per_block.rs:38:5 | LL | / unsafe { +LL | | LL | | STATIC += 1; LL | | not_very_safe(); LL | | } | |_____^ | note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:39:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:40:9 | LL | STATIC += 1; | ^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:40:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:41:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ @@ -21,29 +22,31 @@ LL | not_very_safe(); = help: to override `-D warnings` add `#[allow(clippy::multiple_unsafe_ops_per_block)]` error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:47:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:48:5 | LL | / unsafe { +LL | | LL | | drop(u.u); LL | | *raw_ptr(); LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:48:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:50:14 | LL | drop(u.u); | ^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:49:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:51:9 | LL | *raw_ptr(); | ^^^^^^^^^^ error: this `unsafe` block contains 3 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:54:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:56:5 | LL | / unsafe { +LL | | LL | | asm!("nop"); LL | | sample.not_very_safe(); LL | | STATIC = 0; @@ -51,137 +54,140 @@ LL | | } | |_____^ | note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:55:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:58:9 | LL | asm!("nop"); | ^^^^^^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:56:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:59:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: modification of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:57:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:60:9 | LL | STATIC = 0; | ^^^^^^^^^^ error: this `unsafe` block contains 6 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:63:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:66:5 | LL | / unsafe { +LL | | LL | | drop(u.u); LL | | drop(STATIC); -LL | | sample.not_very_safe(); ... | LL | | asm!("nop"); LL | | } | |_____^ | note: union field access occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:64:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:68:14 | LL | drop(u.u); | ^^^ note: access of a mutable static occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:65:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:69:14 | LL | drop(STATIC); | ^^^^^^ note: unsafe method call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:66:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:70:9 | LL | sample.not_very_safe(); | ^^^^^^^^^^^^^^^^^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:67:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:71:9 | LL | not_very_safe(); | ^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:68:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:72:9 | LL | *raw_ptr(); | ^^^^^^^^^^ note: inline assembly used here - --> tests/ui/multiple_unsafe_ops_per_block.rs:69:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:73:9 | LL | asm!("nop"); | ^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:107:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:5 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:107:14 + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:14 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: raw pointer dereference occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:107:39 + --> tests/ui/multiple_unsafe_ops_per_block.rs:111:39 | LL | unsafe { char::from_u32_unchecked(*ptr.cast::()) } | ^^^^^^^^^^^^^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:125:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:130:5 | LL | / unsafe { +LL | | LL | | x(); LL | | x(); LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:126:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:132:9 | LL | x(); | ^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:127:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:133:9 | LL | x(); | ^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:136:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:142:9 | LL | / unsafe { +LL | | LL | | T::X(); LL | | T::X(); LL | | } | |_________^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:137:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:144:13 | LL | T::X(); | ^^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:138:13 + --> tests/ui/multiple_unsafe_ops_per_block.rs:145:13 | LL | T::X(); | ^^^^^^ error: this `unsafe` block contains 2 unsafe operations, expected only one - --> tests/ui/multiple_unsafe_ops_per_block.rs:146:5 + --> tests/ui/multiple_unsafe_ops_per_block.rs:153:5 | LL | / unsafe { +LL | | LL | | x.0(); LL | | x.0(); LL | | } | |_____^ | note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:147:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:155:9 | LL | x.0(); | ^^^^^ note: unsafe function call occurs here - --> tests/ui/multiple_unsafe_ops_per_block.rs:148:9 + --> tests/ui/multiple_unsafe_ops_per_block.rs:156:9 | LL | x.0(); | ^^^^^ diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed index 2459af6068845..b5d356a502170 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.fixed +++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed @@ -14,11 +14,13 @@ pub struct MyAtomic(AtomicBool); pub struct MyPure; #[must_use] pub fn pure(i: u8) -> u8 { + //~^ must_use_candidate i } impl MyPure { #[must_use] pub fn inherent_pure(&self) -> u8 { + //~^ must_use_candidate 0 } } @@ -50,6 +52,7 @@ pub fn with_callback bool>(f: &F) -> bool { } #[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { + //~^ must_use_candidate true } @@ -62,6 +65,7 @@ pub fn atomics(b: &AtomicBool) -> bool { } #[must_use] pub fn rcd(_x: Rc) -> bool { + //~^ must_use_candidate true } @@ -70,6 +74,7 @@ pub fn rcmut(_x: Rc<&mut u32>) -> bool { } #[must_use] pub fn arcd(_x: Arc) -> bool { + //~^ must_use_candidate false } diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs index 5f9b2449552a9..14ea16662fdb4 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.rs +++ b/src/tools/clippy/tests/ui/must_use_candidates.rs @@ -14,11 +14,13 @@ pub struct MyAtomic(AtomicBool); pub struct MyPure; pub fn pure(i: u8) -> u8 { + //~^ must_use_candidate i } impl MyPure { pub fn inherent_pure(&self) -> u8 { + //~^ must_use_candidate 0 } } @@ -50,6 +52,7 @@ pub fn with_callback bool>(f: &F) -> bool { } pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { + //~^ must_use_candidate true } @@ -62,6 +65,7 @@ pub fn atomics(b: &AtomicBool) -> bool { } pub fn rcd(_x: Rc) -> bool { + //~^ must_use_candidate true } @@ -70,6 +74,7 @@ pub fn rcmut(_x: Rc<&mut u32>) -> bool { } pub fn arcd(_x: Arc) -> bool { + //~^ must_use_candidate false } diff --git a/src/tools/clippy/tests/ui/must_use_candidates.stderr b/src/tools/clippy/tests/ui/must_use_candidates.stderr index 2117e37866e2d..590253d95f9e3 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.stderr +++ b/src/tools/clippy/tests/ui/must_use_candidates.stderr @@ -8,25 +8,25 @@ LL | pub fn pure(i: u8) -> u8 { = help: to override `-D warnings` add `#[allow(clippy::must_use_candidate)]` error: this method could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:21:5 + --> tests/ui/must_use_candidates.rs:22:5 | LL | pub fn inherent_pure(&self) -> u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn inherent_pure(&self) -> u8` error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:52:1 + --> tests/ui/must_use_candidates.rs:54:1 | LL | pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn with_marker(_d: std::marker::PhantomData<&mut u32>) -> bool` error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:64:1 + --> tests/ui/must_use_candidates.rs:67:1 | LL | pub fn rcd(_x: Rc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn rcd(_x: Rc) -> bool` error: this function could have a `#[must_use]` attribute - --> tests/ui/must_use_candidates.rs:72:1 + --> tests/ui/must_use_candidates.rs:76:1 | LL | pub fn arcd(_x: Arc) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add the attribute: `#[must_use] pub fn arcd(_x: Arc) -> bool` diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed index b92d9379c904b..683754a98c828 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.fixed +++ b/src/tools/clippy/tests/ui/must_use_unit.fixed @@ -7,10 +7,13 @@ extern crate proc_macros; use proc_macros::external; pub fn must_use_default() {} +//~^ must_use_unit pub fn must_use_unit() -> () {} +//~^ must_use_unit pub fn must_use_with_note() {} +//~^ must_use_unit fn main() { must_use_default(); @@ -23,9 +26,3 @@ fn main() { fn foo() {} ); } - -#[cfg_attr(all(), deprecated)] -fn issue_12320() {} - -#[cfg_attr(all(), deprecated, doc = "foo")] -fn issue_12320_2() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit.rs b/src/tools/clippy/tests/ui/must_use_unit.rs index c77e728275048..519b8fa368219 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.rs +++ b/src/tools/clippy/tests/ui/must_use_unit.rs @@ -8,12 +8,15 @@ use proc_macros::external; #[must_use] pub fn must_use_default() {} +//~^ must_use_unit #[must_use] pub fn must_use_unit() -> () {} +//~^ must_use_unit #[must_use = "With note"] pub fn must_use_with_note() {} +//~^ must_use_unit fn main() { must_use_default(); @@ -26,9 +29,3 @@ fn main() { fn foo() {} ); } - -#[cfg_attr(all(), must_use, deprecated)] -fn issue_12320() {} - -#[cfg_attr(all(), deprecated, doc = "foo", must_use)] -fn issue_12320_2() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit.stderr b/src/tools/clippy/tests/ui/must_use_unit.stderr index b435568deeab8..8f2af0cbd2915 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.stderr +++ b/src/tools/clippy/tests/ui/must_use_unit.stderr @@ -10,7 +10,7 @@ LL | pub fn must_use_default() {} = help: to override `-D warnings` add `#[allow(clippy::must_use_unit)]` error: this unit-returning function has a `#[must_use]` attribute - --> tests/ui/must_use_unit.rs:13:1 + --> tests/ui/must_use_unit.rs:14:1 | LL | #[must_use] | ----------- help: remove the attribute @@ -18,28 +18,12 @@ LL | pub fn must_use_unit() -> () {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this unit-returning function has a `#[must_use]` attribute - --> tests/ui/must_use_unit.rs:16:1 + --> tests/ui/must_use_unit.rs:18:1 | LL | #[must_use = "With note"] | ------------------------- help: remove the attribute LL | pub fn must_use_with_note() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this unit-returning function has a `#[must_use]` attribute - --> tests/ui/must_use_unit.rs:31:1 - | -LL | #[cfg_attr(all(), must_use, deprecated)] - | -------------------- help: change these attributes to: `deprecated` -LL | fn issue_12320() {} - | ^^^^^^^^^^^^^^^^ - -error: this unit-returning function has a `#[must_use]` attribute - --> tests/ui/must_use_unit.rs:34:1 - | -LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)] - | --------------------------------- help: change these attributes to: `deprecated, doc = "foo"` -LL | fn issue_12320_2() {} - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/must_use_unit_unfixable.rs b/src/tools/clippy/tests/ui/must_use_unit_unfixable.rs new file mode 100644 index 0000000000000..0dba7996bac33 --- /dev/null +++ b/src/tools/clippy/tests/ui/must_use_unit_unfixable.rs @@ -0,0 +1,11 @@ +//@no-rustfix + +#[cfg_attr(all(), must_use, deprecated)] +fn issue_12320() {} +//~^ must_use_unit + +#[cfg_attr(all(), deprecated, doc = "foo", must_use)] +fn issue_12320_2() {} +//~^ must_use_unit + +fn main() {} diff --git a/src/tools/clippy/tests/ui/must_use_unit_unfixable.stderr b/src/tools/clippy/tests/ui/must_use_unit_unfixable.stderr new file mode 100644 index 0000000000000..087682199afb9 --- /dev/null +++ b/src/tools/clippy/tests/ui/must_use_unit_unfixable.stderr @@ -0,0 +1,28 @@ +error: this unit-returning function has a `#[must_use]` attribute + --> tests/ui/must_use_unit_unfixable.rs:4:1 + | +LL | fn issue_12320() {} + | ^^^^^^^^^^^^^^^^ + | +help: remove `must_use` + --> tests/ui/must_use_unit_unfixable.rs:3:19 + | +LL | #[cfg_attr(all(), must_use, deprecated)] + | ^^^^^^^^ + = note: `-D clippy::must-use-unit` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::must_use_unit)]` + +error: this unit-returning function has a `#[must_use]` attribute + --> tests/ui/must_use_unit_unfixable.rs:8:1 + | +LL | fn issue_12320_2() {} + | ^^^^^^^^^^^^^^^^^^ + | +help: remove `must_use` + --> tests/ui/must_use_unit_unfixable.rs:7:44 + | +LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)] + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/mut_from_ref.rs b/src/tools/clippy/tests/ui/mut_from_ref.rs index 0ab6d77de1e1d..b8c10f3eeb8f9 100644 --- a/src/tools/clippy/tests/ui/mut_from_ref.rs +++ b/src/tools/clippy/tests/ui/mut_from_ref.rs @@ -5,14 +5,15 @@ struct Foo; impl Foo { fn this_wont_hurt_a_bit(&self) -> &mut Foo { - //~^ ERROR: mutable borrow from immutable input(s) + //~^ mut_from_ref + unsafe { unimplemented!() } } } trait Ouch { fn ouch(x: &Foo) -> &mut Foo; - //~^ ERROR: mutable borrow from immutable input(s) + //~^ mut_from_ref } impl Ouch for Foo { @@ -22,17 +23,20 @@ impl Ouch for Foo { } fn fail(x: &u32) -> &mut u16 { - //~^ ERROR: mutable borrow from immutable input(s) + //~^ mut_from_ref + unsafe { unimplemented!() } } fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { - //~^ ERROR: mutable borrow from immutable input(s) + //~^ mut_from_ref + unsafe { unimplemented!() } } fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { - //~^ ERROR: mutable borrow from immutable input(s) + //~^ mut_from_ref + unsafe { unimplemented!() } } @@ -47,7 +51,8 @@ fn also_works<'a>(x: &'a u32, y: &'a mut u32) -> &'a mut u32 { } unsafe fn also_broken(x: &u32) -> &mut u32 { - //~^ ERROR: mutable borrow from immutable input(s) + //~^ mut_from_ref + unimplemented!() } diff --git a/src/tools/clippy/tests/ui/mut_from_ref.stderr b/src/tools/clippy/tests/ui/mut_from_ref.stderr index 34fe91b5b3acb..8c3c8e0c3d851 100644 --- a/src/tools/clippy/tests/ui/mut_from_ref.stderr +++ b/src/tools/clippy/tests/ui/mut_from_ref.stderr @@ -13,61 +13,61 @@ LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo { = help: to override `-D warnings` add `#[allow(clippy::mut_from_ref)]` error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:14:25 + --> tests/ui/mut_from_ref.rs:15:25 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:14:16 + --> tests/ui/mut_from_ref.rs:15:16 | LL | fn ouch(x: &Foo) -> &mut Foo; | ^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:24:21 + --> tests/ui/mut_from_ref.rs:25:21 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:24:12 + --> tests/ui/mut_from_ref.rs:25:12 | LL | fn fail(x: &u32) -> &mut u16 { | ^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:29:50 + --> tests/ui/mut_from_ref.rs:31:50 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:29:25 + --> tests/ui/mut_from_ref.rs:31:25 | LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 { | ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:34:67 + --> tests/ui/mut_from_ref.rs:37:67 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:34:27 + --> tests/ui/mut_from_ref.rs:37:27 | LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 { | ^^^^^^^ ^^^^^^^ error: mutable borrow from immutable input(s) - --> tests/ui/mut_from_ref.rs:49:35 + --> tests/ui/mut_from_ref.rs:53:35 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { | ^^^^^^^^ | note: immutable borrow here - --> tests/ui/mut_from_ref.rs:49:26 + --> tests/ui/mut_from_ref.rs:53:26 | LL | unsafe fn also_broken(x: &u32) -> &mut u32 { | ^^^^ diff --git a/src/tools/clippy/tests/ui/mut_key.rs b/src/tools/clippy/tests/ui/mut_key.rs index 43ff705c47750..29dc2d020132f 100644 --- a/src/tools/clippy/tests/ui/mut_key.rs +++ b/src/tools/clippy/tests/ui/mut_key.rs @@ -29,11 +29,12 @@ impl Hash for Key { } fn should_not_take_this_arg(m: &mut HashMap, _n: usize) -> HashSet { - //~^ ERROR: mutable key type - //~| NOTE: `-D clippy::mutable-key-type` implied by `-D warnings` - //~| ERROR: mutable key type + //~^ mutable_key_type + //~| mutable_key_type + let _other: HashMap = HashMap::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + m.keys().cloned().collect() } @@ -61,7 +62,7 @@ fn generics_are_ok_too(_m: &mut HashSet) { fn tuples(_m: &mut HashMap<((), U), ()>) {} fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} -//~^ ERROR: mutable key type +//~^ mutable_key_type fn main() { let _ = should_not_take_this_arg(&mut HashMap::new(), 1); @@ -74,29 +75,39 @@ fn main() { raw_mut_ptr_is_ok(&mut HashMap::new()); let _map = HashMap::, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::<&mut Cell, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + // Collection types from `std` who's impl of `Hash` or `Ord` delegate their type parameters let _map = HashMap::>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::, ()>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::>>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + // Smart pointers from `std` who's impl of `Hash` or `Ord` delegate their type parameters let _map = HashMap::>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type + let _map = HashMap::>, usize>::new(); - //~^ ERROR: mutable key type + //~^ mutable_key_type // Not interior mutability let _map = HashMap::<&mut usize, usize>::new(); diff --git a/src/tools/clippy/tests/ui/mut_key.stderr b/src/tools/clippy/tests/ui/mut_key.stderr index 8698ed4fd678b..0d504584fbae8 100644 --- a/src/tools/clippy/tests/ui/mut_key.stderr +++ b/src/tools/clippy/tests/ui/mut_key.stderr @@ -31,7 +31,7 @@ LL | let _other: HashMap = HashMap::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:63:22 + --> tests/ui/mut_key.rs:64:22 | LL | fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL | fn tuples_bad(_m: &mut HashMap<(Key, U), bool>) {} = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:76:5 + --> tests/ui/mut_key.rs:77:5 | LL | let _map = HashMap::, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL | let _map = HashMap::, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:78:5 + --> tests/ui/mut_key.rs:80:5 | LL | let _map = HashMap::<&mut Cell, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | let _map = HashMap::<&mut Cell, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:81:5 + --> tests/ui/mut_key.rs:84:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +71,7 @@ LL | let _map = HashMap::>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:83:5 + --> tests/ui/mut_key.rs:87:5 | LL | let _map = HashMap::, ()>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | let _map = HashMap::, ()>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:85:5 + --> tests/ui/mut_key.rs:90:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | let _map = HashMap::>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:87:5 + --> tests/ui/mut_key.rs:93:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -101,7 +101,7 @@ LL | let _map = HashMap::>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:89:5 + --> tests/ui/mut_key.rs:96:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,7 +111,7 @@ LL | let _map = HashMap::>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:91:5 + --> tests/ui/mut_key.rs:99:5 | LL | let _map = HashMap::>>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | let _map = HashMap::>>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:94:5 + --> tests/ui/mut_key.rs:103:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +132,7 @@ LL | let _map = HashMap::>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:96:5 + --> tests/ui/mut_key.rs:106:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -142,7 +142,7 @@ LL | let _map = HashMap::>, usize>::new(); = note: ... because it contains `UnsafeCell`, which has interior mutability error: mutable key type - --> tests/ui/mut_key.rs:98:5 + --> tests/ui/mut_key.rs:109:5 | LL | let _map = HashMap::>, usize>::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/mut_mut.rs b/src/tools/clippy/tests/ui/mut_mut.rs index 4c45bc9802654..bbcdbc89b6a4b 100644 --- a/src/tools/clippy/tests/ui/mut_mut.rs +++ b/src/tools/clippy/tests/ui/mut_mut.rs @@ -13,6 +13,7 @@ extern crate proc_macros; use proc_macros::{external, inline_macros}; fn fun(x: &mut &mut u32) -> bool { + //~^ mut_mut **x > 0 } @@ -30,21 +31,29 @@ macro_rules! mut_ptr { #[inline_macros] fn main() { let mut x = &mut &mut 1u32; + //~^ mut_mut { let mut y = &mut x; + //~^ mut_mut } if fun(x) { let y: &mut &mut u32 = &mut &mut 2; + //~^ mut_mut + //~| mut_mut **y + **x; } if fun(x) { let y: &mut &mut &mut u32 = &mut &mut &mut 2; + //~^ mut_mut + //~| mut_mut + //~| mut_mut ***y + **x; } let mut z = inline!(&mut $(&mut 3u32)); + //~^ mut_mut } fn issue939() { diff --git a/src/tools/clippy/tests/ui/mut_mut.stderr b/src/tools/clippy/tests/ui/mut_mut.stderr index 42853fdc008c1..74b0c9ba145a9 100644 --- a/src/tools/clippy/tests/ui/mut_mut.stderr +++ b/src/tools/clippy/tests/ui/mut_mut.stderr @@ -8,13 +8,13 @@ LL | fn fun(x: &mut &mut u32) -> bool { = help: to override `-D warnings` add `#[allow(clippy::mut_mut)]` error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:32:17 + --> tests/ui/mut_mut.rs:33:17 | LL | let mut x = &mut &mut 1u32; | ^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:47:25 + --> tests/ui/mut_mut.rs:55:25 | LL | let mut z = inline!(&mut $(&mut 3u32)); | ^ @@ -22,37 +22,37 @@ LL | let mut z = inline!(&mut $(&mut 3u32)); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this expression mutably borrows a mutable reference. Consider reborrowing - --> tests/ui/mut_mut.rs:34:21 + --> tests/ui/mut_mut.rs:36:21 | LL | let mut y = &mut x; | ^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:38:32 + --> tests/ui/mut_mut.rs:41:32 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:38:16 + --> tests/ui/mut_mut.rs:41:16 | LL | let y: &mut &mut u32 = &mut &mut 2; | ^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:43:37 + --> tests/ui/mut_mut.rs:48:37 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:43:16 + --> tests/ui/mut_mut.rs:48:16 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^^^^^^ error: generally you want to avoid `&mut &mut _` if possible - --> tests/ui/mut_mut.rs:43:21 + --> tests/ui/mut_mut.rs:48:21 | LL | let y: &mut &mut &mut u32 = &mut &mut &mut 2; | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed index 29c5a27cb6247..5790ee8c1b022 100644 --- a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed +++ b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed @@ -8,11 +8,13 @@ fn mut_mutex_lock() { let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); let mut value = value_mutex.get_mut().unwrap(); + //~^ mut_mutex_lock *value += 1; let mut value_mutex = Mutex::new(42_u8); let mut_ref_mut_ref_mutex = &mut &mut value_mutex; let mut value = mut_ref_mut_ref_mutex.get_mut().unwrap(); + //~^ mut_mutex_lock *value += 1; } diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.rs b/src/tools/clippy/tests/ui/mut_mutex_lock.rs index fcdb3ff97dbc5..7286afac823b7 100644 --- a/src/tools/clippy/tests/ui/mut_mutex_lock.rs +++ b/src/tools/clippy/tests/ui/mut_mutex_lock.rs @@ -8,11 +8,13 @@ fn mut_mutex_lock() { let value_mutex = Arc::get_mut(&mut value_rc).unwrap(); let mut value = value_mutex.lock().unwrap(); + //~^ mut_mutex_lock *value += 1; let mut value_mutex = Mutex::new(42_u8); let mut_ref_mut_ref_mutex = &mut &mut value_mutex; let mut value = mut_ref_mut_ref_mutex.lock().unwrap(); + //~^ mut_mutex_lock *value += 1; } diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.stderr b/src/tools/clippy/tests/ui/mut_mutex_lock.stderr index 92601c4c61215..67543c73c6eef 100644 --- a/src/tools/clippy/tests/ui/mut_mutex_lock.stderr +++ b/src/tools/clippy/tests/ui/mut_mutex_lock.stderr @@ -8,7 +8,7 @@ LL | let mut value = value_mutex.lock().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::mut_mutex_lock)]` error: calling `&mut Mutex::lock` unnecessarily locks an exclusive (mutable) reference - --> tests/ui/mut_mutex_lock.rs:15:43 + --> tests/ui/mut_mutex_lock.rs:16:43 | LL | let mut value = mut_ref_mut_ref_mutex.lock().unwrap(); | ^^^^ help: change this to: `get_mut` diff --git a/src/tools/clippy/tests/ui/mut_range_bound.rs b/src/tools/clippy/tests/ui/mut_range_bound.rs index 7aebbf4981ee8..107a6229b86d8 100644 --- a/src/tools/clippy/tests/ui/mut_range_bound.rs +++ b/src/tools/clippy/tests/ui/mut_range_bound.rs @@ -6,8 +6,7 @@ fn mut_range_bound_upper() { let mut m = 4; for i in 0..m { m = 5; - //~^ ERROR: attempt to mutate range bound within loop - //~| NOTE: the range of the loop is unchanged + //~^ mut_range_bound } } @@ -15,8 +14,7 @@ fn mut_range_bound_lower() { let mut m = 4; for i in m..10 { m *= 2; - //~^ ERROR: attempt to mutate range bound within loop - //~| NOTE: the range of the loop is unchanged + //~^ mut_range_bound } } @@ -25,11 +23,10 @@ fn mut_range_bound_both() { let mut n = 6; for i in m..n { m = 5; - //~^ ERROR: attempt to mutate range bound within loop - //~| NOTE: the range of the loop is unchanged + //~^ mut_range_bound + n = 7; - //~^ ERROR: attempt to mutate range bound within loop - //~| NOTE: the range of the loop is unchanged + //~^ mut_range_bound } } @@ -44,8 +41,8 @@ fn mut_borrow_range_bound() { let mut m = 4; for i in 0..m { let n = &mut m; - //~^ ERROR: attempt to mutate range bound within loop - //~| NOTE: the range of the loop is unchanged + //~^ mut_range_bound + *n += 1; } } @@ -79,8 +76,8 @@ fn mut_range_bound_no_immediate_break() { for i in 0..m { // warning because it is not immediately followed by break m = 2; - //~^ ERROR: attempt to mutate range bound within loop - //~| NOTE: the range of the loop is unchanged + //~^ mut_range_bound + if m == 4 { break; } @@ -91,8 +88,8 @@ fn mut_range_bound_no_immediate_break() { if n == 4 { // FIXME: warning because it is not immediately followed by break n = 1; - //~^ ERROR: attempt to mutate range bound within loop - //~| NOTE: the range of the loop is unchanged + //~^ mut_range_bound + let _ = 2; break; } diff --git a/src/tools/clippy/tests/ui/mut_range_bound.stderr b/src/tools/clippy/tests/ui/mut_range_bound.stderr index 6f93b0ebe6fcc..3aae6e2dca6d0 100644 --- a/src/tools/clippy/tests/ui/mut_range_bound.stderr +++ b/src/tools/clippy/tests/ui/mut_range_bound.stderr @@ -9,7 +9,7 @@ LL | m = 5; = help: to override `-D warnings` add `#[allow(clippy::mut_range_bound)]` error: attempt to mutate range bound within loop - --> tests/ui/mut_range_bound.rs:17:9 + --> tests/ui/mut_range_bound.rs:16:9 | LL | m *= 2; | ^ @@ -17,7 +17,7 @@ LL | m *= 2; = note: the range of the loop is unchanged error: attempt to mutate range bound within loop - --> tests/ui/mut_range_bound.rs:27:9 + --> tests/ui/mut_range_bound.rs:25:9 | LL | m = 5; | ^ @@ -25,7 +25,7 @@ LL | m = 5; = note: the range of the loop is unchanged error: attempt to mutate range bound within loop - --> tests/ui/mut_range_bound.rs:30:9 + --> tests/ui/mut_range_bound.rs:28:9 | LL | n = 7; | ^ @@ -33,7 +33,7 @@ LL | n = 7; = note: the range of the loop is unchanged error: attempt to mutate range bound within loop - --> tests/ui/mut_range_bound.rs:46:22 + --> tests/ui/mut_range_bound.rs:43:22 | LL | let n = &mut m; | ^ @@ -41,7 +41,7 @@ LL | let n = &mut m; = note: the range of the loop is unchanged error: attempt to mutate range bound within loop - --> tests/ui/mut_range_bound.rs:81:9 + --> tests/ui/mut_range_bound.rs:78:9 | LL | m = 2; | ^ @@ -49,7 +49,7 @@ LL | m = 2; = note: the range of the loop is unchanged error: attempt to mutate range bound within loop - --> tests/ui/mut_range_bound.rs:93:13 + --> tests/ui/mut_range_bound.rs:90:13 | LL | n = 1; | ^ diff --git a/src/tools/clippy/tests/ui/mut_reference.rs b/src/tools/clippy/tests/ui/mut_reference.rs index 1d7faaa5e75e4..f664c373cdc3a 100644 --- a/src/tools/clippy/tests/ui/mut_reference.rs +++ b/src/tools/clippy/tests/ui/mut_reference.rs @@ -28,16 +28,16 @@ impl MyStruct { fn main() { // Functions takes_an_immutable_reference(&mut 42); - //~^ ERROR: the function `takes_an_immutable_reference` doesn't need a mutable referen - //~| NOTE: `-D clippy::unnecessary-mut-passed` implied by `-D warnings` + //~^ unnecessary_mut_passed + let as_ptr: fn(&i32) = takes_an_immutable_reference; as_ptr(&mut 42); - //~^ ERROR: the function `as_ptr` doesn't need a mutable reference + //~^ unnecessary_mut_passed // Methods let my_struct = MyStruct; my_struct.takes_an_immutable_reference(&mut 42); - //~^ ERROR: the method `takes_an_immutable_reference` doesn't need a mutable reference + //~^ unnecessary_mut_passed // No error diff --git a/src/tools/clippy/tests/ui/mutex_atomic.rs b/src/tools/clippy/tests/ui/mutex_atomic.rs index 3a51538b74240..80a712a9286a4 100644 --- a/src/tools/clippy/tests/ui/mutex_atomic.rs +++ b/src/tools/clippy/tests/ui/mutex_atomic.rs @@ -6,32 +6,40 @@ fn main() { use std::sync::Mutex; Mutex::new(true); - //~^ ERROR: consider using an `AtomicBool` instead of a `Mutex` here; if you just want - //~| NOTE: `-D clippy::mutex-atomic` implied by `-D warnings` + //~^ mutex_atomic + Mutex::new(5usize); - //~^ ERROR: consider using an `AtomicUsize` instead of a `Mutex` here; if you just wan + //~^ mutex_atomic + Mutex::new(9isize); - //~^ ERROR: consider using an `AtomicIsize` instead of a `Mutex` here; if you just wan + //~^ mutex_atomic + let mut x = 4u32; Mutex::new(&x as *const u32); - //~^ ERROR: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want + //~^ mutex_atomic + Mutex::new(&mut x as *mut u32); - //~^ ERROR: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want + //~^ mutex_atomic + Mutex::new(0u32); - //~^ ERROR: consider using an `AtomicU32` instead of a `Mutex` here; if you just wan - //~| NOTE: `-D clippy::mutex-integer` implied by `-D warnings` + //~^ mutex_integer + Mutex::new(0i32); - //~^ ERROR: consider using an `AtomicI32` instead of a `Mutex` here; if you just wan + //~^ mutex_integer + Mutex::new(0f32); // there are no float atomics, so this should not lint Mutex::new(0u8); - //~^ ERROR: consider using an `AtomicU8` instead of a `Mutex` here; if you just wan + //~^ mutex_integer + Mutex::new(0i16); - //~^ ERROR: consider using an `AtomicI16` instead of a `Mutex` here; if you just wan + //~^ mutex_integer + let _x: Mutex = Mutex::new(0); - //~^ ERROR: consider using an `AtomicI8` instead of a `Mutex` here; if you just wan + //~^ mutex_integer + const X: i64 = 0; Mutex::new(X); - //~^ ERROR: consider using an `AtomicI64` instead of a `Mutex` here; if you just wan + //~^ mutex_integer // there are no 128 atomics, so these two should not lint { diff --git a/src/tools/clippy/tests/ui/mutex_atomic.stderr b/src/tools/clippy/tests/ui/mutex_atomic.stderr index 683a7b939db3a..838fc1d7c36ee 100644 --- a/src/tools/clippy/tests/ui/mutex_atomic.stderr +++ b/src/tools/clippy/tests/ui/mutex_atomic.stderr @@ -14,25 +14,25 @@ LL | Mutex::new(5usize); | ^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:13:5 + --> tests/ui/mutex_atomic.rs:14:5 | LL | Mutex::new(9isize); | ^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:16:5 + --> tests/ui/mutex_atomic.rs:18:5 | LL | Mutex::new(&x as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:18:5 + --> tests/ui/mutex_atomic.rs:21:5 | LL | Mutex::new(&mut x as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: consider using an `AtomicU32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:20:5 + --> tests/ui/mutex_atomic.rs:24:5 | LL | Mutex::new(0u32); | ^^^^^^^^^^^^^^^^ @@ -41,31 +41,31 @@ LL | Mutex::new(0u32); = help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]` error: consider using an `AtomicI32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:23:5 + --> tests/ui/mutex_atomic.rs:27:5 | LL | Mutex::new(0i32); | ^^^^^^^^^^^^^^^^ error: consider using an `AtomicU8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:26:5 + --> tests/ui/mutex_atomic.rs:31:5 | LL | Mutex::new(0u8); | ^^^^^^^^^^^^^^^ error: consider using an `AtomicI16` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:28:5 + --> tests/ui/mutex_atomic.rs:34:5 | LL | Mutex::new(0i16); | ^^^^^^^^^^^^^^^^ error: consider using an `AtomicI8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:30:25 + --> tests/ui/mutex_atomic.rs:37:25 | LL | let _x: Mutex = Mutex::new(0); | ^^^^^^^^^^^^^ error: consider using an `AtomicI64` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>` - --> tests/ui/mutex_atomic.rs:33:5 + --> tests/ui/mutex_atomic.rs:41:5 | LL | Mutex::new(X); | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed index 530eb77d83d28..adb9096c9f242 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed @@ -8,6 +8,7 @@ pub enum ValType { impl ValType { pub fn bad(self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -16,6 +17,7 @@ impl ValType { } pub fn mut_bad(mut self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -24,6 +26,7 @@ impl ValType { } pub fn ref_bad(&self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -32,6 +35,7 @@ impl ValType { } pub fn ref_bad_with_lifetime<'a>(&'a self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -40,6 +44,7 @@ impl ValType { } pub fn mut_ref_bad(&mut self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -48,6 +53,7 @@ impl ValType { } pub fn mut_ref_bad_with_lifetime<'a>(&'a mut self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -66,7 +72,9 @@ impl ValType { trait Foo<'r#struct> { fn f1(&'r#struct self) {} + //~^ needless_arbitrary_self_type fn f2(&'r#struct mut self) {} + //~^ needless_arbitrary_self_type } fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs index 5a1ff96a11cc2..550546ed24fd7 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs @@ -8,6 +8,7 @@ pub enum ValType { impl ValType { pub fn bad(self: Self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -16,6 +17,7 @@ impl ValType { } pub fn mut_bad(mut self: Self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -24,6 +26,7 @@ impl ValType { } pub fn ref_bad(self: &Self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -32,6 +35,7 @@ impl ValType { } pub fn ref_bad_with_lifetime<'a>(self: &'a Self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -40,6 +44,7 @@ impl ValType { } pub fn mut_ref_bad(self: &mut Self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -48,6 +53,7 @@ impl ValType { } pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) { + //~^ needless_arbitrary_self_type unimplemented!(); } @@ -66,7 +72,9 @@ impl ValType { trait Foo<'r#struct> { fn f1(self: &'r#struct Self) {} + //~^ needless_arbitrary_self_type fn f2(self: &'r#struct mut Self) {} + //~^ needless_arbitrary_self_type } fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr index 7ebbbaa122f51..b5c0aae8310f3 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.stderr @@ -8,43 +8,43 @@ LL | pub fn bad(self: Self) { = help: to override `-D warnings` add `#[allow(clippy::needless_arbitrary_self_type)]` error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:18:20 + --> tests/ui/needless_arbitrary_self_type.rs:19:20 | LL | pub fn mut_bad(mut self: Self) { | ^^^^^^^^^^^^^^ help: consider to change this parameter to: `mut self` error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:26:20 + --> tests/ui/needless_arbitrary_self_type.rs:28:20 | LL | pub fn ref_bad(self: &Self) { | ^^^^^^^^^^^ help: consider to change this parameter to: `&self` error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:34:38 + --> tests/ui/needless_arbitrary_self_type.rs:37:38 | LL | pub fn ref_bad_with_lifetime<'a>(self: &'a Self) { | ^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a self` error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:42:24 + --> tests/ui/needless_arbitrary_self_type.rs:46:24 | LL | pub fn mut_ref_bad(self: &mut Self) { | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&mut self` error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:50:42 + --> tests/ui/needless_arbitrary_self_type.rs:55:42 | LL | pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) { | ^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a mut self` error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:68:11 + --> tests/ui/needless_arbitrary_self_type.rs:74:11 | LL | fn f1(self: &'r#struct Self) {} | ^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct self` error: the type of the `self` parameter does not need to be arbitrary - --> tests/ui/needless_arbitrary_self_type.rs:69:11 + --> tests/ui/needless_arbitrary_self_type.rs:76:11 | LL | fn f2(self: &'r#struct mut Self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct mut self` diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.fixed b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.fixed index 62a6e5932435d..f4ee0a8bd0724 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.fixed +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.fixed @@ -40,6 +40,7 @@ mod issue_6089 { impl T2 for S2 { #[allow(clippy::needless_lifetimes)] fn call_with_mut_self(&mut self) {} + //~^ needless_arbitrary_self_type } } diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs index 00871f9f450ca..3f29025c1362f 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs @@ -40,6 +40,7 @@ mod issue_6089 { impl T2 for S2 { #[allow(clippy::needless_lifetimes)] fn call_with_mut_self(self: &mut Self) {} + //~^ needless_arbitrary_self_type } } diff --git a/src/tools/clippy/tests/ui/needless_as_bytes.fixed b/src/tools/clippy/tests/ui/needless_as_bytes.fixed index 74b4ba5be7989..9cbc7b9c26519 100644 --- a/src/tools/clippy/tests/ui/needless_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/needless_as_bytes.fixed @@ -16,11 +16,13 @@ impl S { fn main() { if "some string".is_empty() { //~^ needless_as_bytes + println!("len = {}", "some string".len()); //~^ needless_as_bytes } if "some string".is_empty() { //~^ needless_as_bytes + println!("len = {}", "some string".len()); //~^ needless_as_bytes } @@ -28,11 +30,13 @@ fn main() { let s = String::from("yet another string"); if s.is_empty() { //~^ needless_as_bytes + println!("len = {}", s.len()); //~^ needless_as_bytes } if s.is_empty() { //~^ needless_as_bytes + println!("len = {}", s.len()); //~^ needless_as_bytes } diff --git a/src/tools/clippy/tests/ui/needless_as_bytes.rs b/src/tools/clippy/tests/ui/needless_as_bytes.rs index ffcce60bbbef2..7de699647e85f 100644 --- a/src/tools/clippy/tests/ui/needless_as_bytes.rs +++ b/src/tools/clippy/tests/ui/needless_as_bytes.rs @@ -16,11 +16,13 @@ impl S { fn main() { if "some string".as_bytes().is_empty() { //~^ needless_as_bytes + println!("len = {}", "some string".as_bytes().len()); //~^ needless_as_bytes } if "some string".bytes().is_empty() { //~^ needless_as_bytes + println!("len = {}", "some string".bytes().len()); //~^ needless_as_bytes } @@ -28,11 +30,13 @@ fn main() { let s = String::from("yet another string"); if s.as_bytes().is_empty() { //~^ needless_as_bytes + println!("len = {}", s.as_bytes().len()); //~^ needless_as_bytes } if s.bytes().is_empty() { //~^ needless_as_bytes + println!("len = {}", s.bytes().len()); //~^ needless_as_bytes } diff --git a/src/tools/clippy/tests/ui/needless_as_bytes.stderr b/src/tools/clippy/tests/ui/needless_as_bytes.stderr index 138c6630ae7d9..0eead9815f8ab 100644 --- a/src/tools/clippy/tests/ui/needless_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/needless_as_bytes.stderr @@ -8,43 +8,43 @@ LL | if "some string".as_bytes().is_empty() { = help: to override `-D warnings` add `#[allow(clippy::needless_as_bytes)]` error: needless call to `as_bytes` - --> tests/ui/needless_as_bytes.rs:19:30 + --> tests/ui/needless_as_bytes.rs:20:30 | LL | println!("len = {}", "some string".as_bytes().len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `"some string".len()` error: needless call to `bytes` - --> tests/ui/needless_as_bytes.rs:22:8 + --> tests/ui/needless_as_bytes.rs:23:8 | LL | if "some string".bytes().is_empty() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `"some string".is_empty()` error: needless call to `bytes` - --> tests/ui/needless_as_bytes.rs:24:30 + --> tests/ui/needless_as_bytes.rs:26:30 | LL | println!("len = {}", "some string".bytes().len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `"some string".len()` error: needless call to `as_bytes` - --> tests/ui/needless_as_bytes.rs:29:8 + --> tests/ui/needless_as_bytes.rs:31:8 | LL | if s.as_bytes().is_empty() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `s.is_empty()` error: needless call to `as_bytes` - --> tests/ui/needless_as_bytes.rs:31:30 + --> tests/ui/needless_as_bytes.rs:34:30 | LL | println!("len = {}", s.as_bytes().len()); | ^^^^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `s.len()` error: needless call to `bytes` - --> tests/ui/needless_as_bytes.rs:34:8 + --> tests/ui/needless_as_bytes.rs:37:8 | LL | if s.bytes().is_empty() { | ^^^^^^^^^^^^^^^^^^^^ help: `is_empty()` can be called directly on strings: `s.is_empty()` error: needless call to `bytes` - --> tests/ui/needless_as_bytes.rs:36:30 + --> tests/ui/needless_as_bytes.rs:40:30 | LL | println!("len = {}", s.bytes().len()); | ^^^^^^^^^^^^^^^ help: `len()` can be called directly on strings: `s.len()` diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed index a8176618c1f23..89a3c1474f25d 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed @@ -21,6 +21,7 @@ fn main() { println!("true") } if y && !x { + //~^ needless_bitwise_bool println!("true") } diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs index f190eb2b76e76..f5aa7a9f3d9e3 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs @@ -21,6 +21,7 @@ fn main() { println!("true") } if y & !x { + //~^ needless_bitwise_bool println!("true") } diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed index ec63c4fd6a268..0664abf0944dc 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed @@ -39,17 +39,26 @@ fn main() { let x = true; let y = false; x; + //~^^^^^ needless_bool !x; + //~^^^^^ needless_bool !(x && y); + //~^^^^^ needless_bool let a = 0; let b = 1; a != b; + //~^^^^^ needless_bool a == b; + //~^^^^^ needless_bool a >= b; + //~^^^^^ needless_bool a > b; + //~^^^^^ needless_bool a <= b; + //~^^^^^ needless_bool a < b; + //~^^^^^ needless_bool if x { x } else { @@ -74,26 +83,32 @@ fn main() { fn bool_ret3(x: bool) -> bool { return x; + //~^^^^^ needless_bool } fn bool_ret4(x: bool) -> bool { return !x; + //~^^^^^ needless_bool } fn bool_ret5(x: bool, y: bool) -> bool { return x && y; + //~^^^^^ needless_bool } fn bool_ret6(x: bool, y: bool) -> bool { return !(x && y); + //~^^^^^ needless_bool } fn needless_bool(x: bool) { if x {}; + //~^ bool_comparison } fn needless_bool2(x: bool) { if !x {}; + //~^ bool_comparison } fn needless_bool3(x: bool) { @@ -104,7 +119,9 @@ fn needless_bool3(x: bool) { } if x {}; + //~^ bool_comparison if !x {}; + //~^ bool_comparison } fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() { @@ -114,6 +131,7 @@ fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_b let x = if b { true } else { !returns_bool() }; + //~^^^^^ needless_bool } unsafe fn no(v: u8) -> u8 { @@ -123,10 +141,13 @@ unsafe fn no(v: u8) -> u8 { #[allow(clippy::unnecessary_operation)] fn needless_bool_condition() -> bool { (unsafe { no(4) } & 1 != 0); + //~^^^^^ needless_bool let _brackets_unneeded = unsafe { no(4) } & 1 != 0; + //~^ needless_bool fn foo() -> bool { // parentheses are needed here (unsafe { no(4) } & 1 != 0) + //~^ needless_bool } foo() @@ -138,8 +159,11 @@ fn issue12846() { // parentheses are needed here let _x = (a && b).then(|| todo!()); + //~^ needless_bool let _x = (a && b) as u8; + //~^ needless_bool // parentheses are not needed here let _x = a.then(|| todo!()); + //~^ needless_bool } diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs index 8694aa7159080..7507a6af408bb 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs @@ -43,16 +43,19 @@ fn main() { } else { false }; + //~^^^^^ needless_bool if x { false } else { true }; + //~^^^^^ needless_bool if x && y { false } else { true }; + //~^^^^^ needless_bool let a = 0; let b = 1; @@ -61,31 +64,37 @@ fn main() { } else { true }; + //~^^^^^ needless_bool if a != b { false } else { true }; + //~^^^^^ needless_bool if a < b { false } else { true }; + //~^^^^^ needless_bool if a <= b { false } else { true }; + //~^^^^^ needless_bool if a > b { false } else { true }; + //~^^^^^ needless_bool if a >= b { false } else { true }; + //~^^^^^ needless_bool if x { x } else { @@ -114,6 +123,7 @@ fn bool_ret3(x: bool) -> bool { } else { return false; }; + //~^^^^^ needless_bool } fn bool_ret4(x: bool) -> bool { @@ -122,6 +132,7 @@ fn bool_ret4(x: bool) -> bool { } else { return true; }; + //~^^^^^ needless_bool } fn bool_ret5(x: bool, y: bool) -> bool { @@ -130,6 +141,7 @@ fn bool_ret5(x: bool, y: bool) -> bool { } else { return false; }; + //~^^^^^ needless_bool } fn bool_ret6(x: bool, y: bool) -> bool { @@ -138,14 +150,17 @@ fn bool_ret6(x: bool, y: bool) -> bool { } else { return true; }; + //~^^^^^ needless_bool } fn needless_bool(x: bool) { if x == true {}; + //~^ bool_comparison } fn needless_bool2(x: bool) { if x == false {}; + //~^ bool_comparison } fn needless_bool3(x: bool) { @@ -156,7 +171,9 @@ fn needless_bool3(x: bool) { } if x == true {}; + //~^ bool_comparison if x == false {}; + //~^ bool_comparison } fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_brackets() { @@ -170,6 +187,7 @@ fn needless_bool_in_the_suggestion_wraps_the_predicate_of_if_else_statement_in_b } else { true }; + //~^^^^^ needless_bool } unsafe fn no(v: u8) -> u8 { @@ -183,10 +201,13 @@ fn needless_bool_condition() -> bool { } else { false }; + //~^^^^^ needless_bool let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; + //~^ needless_bool fn foo() -> bool { // parentheses are needed here if unsafe { no(4) } & 1 != 0 { true } else { false } + //~^ needless_bool } foo() @@ -198,8 +219,11 @@ fn issue12846() { // parentheses are needed here let _x = if a && b { true } else { false }.then(|| todo!()); + //~^ needless_bool let _x = if a && b { true } else { false } as u8; + //~^ needless_bool // parentheses are not needed here let _x = if a { true } else { false }.then(|| todo!()); + //~^ needless_bool } diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index 99b5b99834486..3f117ee5a5021 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -12,7 +12,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:46:5 + --> tests/ui/needless_bool/fixable.rs:47:5 | LL | / if x { LL | | false @@ -22,7 +22,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:51:5 + --> tests/ui/needless_bool/fixable.rs:53:5 | LL | / if x && y { LL | | false @@ -32,7 +32,7 @@ LL | | }; | |_____^ help: you can reduce it to: `!(x && y)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:59:5 + --> tests/ui/needless_bool/fixable.rs:62:5 | LL | / if a == b { LL | | false @@ -42,7 +42,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a != b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:64:5 + --> tests/ui/needless_bool/fixable.rs:68:5 | LL | / if a != b { LL | | false @@ -52,7 +52,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a == b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:69:5 + --> tests/ui/needless_bool/fixable.rs:74:5 | LL | / if a < b { LL | | false @@ -62,7 +62,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a >= b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:74:5 + --> tests/ui/needless_bool/fixable.rs:80:5 | LL | / if a <= b { LL | | false @@ -72,7 +72,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a > b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:79:5 + --> tests/ui/needless_bool/fixable.rs:86:5 | LL | / if a > b { LL | | false @@ -82,7 +82,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a <= b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:84:5 + --> tests/ui/needless_bool/fixable.rs:92:5 | LL | / if a >= b { LL | | false @@ -92,7 +92,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a < b` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:112:5 + --> tests/ui/needless_bool/fixable.rs:121:5 | LL | / if x { LL | | return true; @@ -102,7 +102,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:120:5 + --> tests/ui/needless_bool/fixable.rs:130:5 | LL | / if x { LL | | return false; @@ -112,7 +112,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:128:5 + --> tests/ui/needless_bool/fixable.rs:139:5 | LL | / if x && y { LL | | return true; @@ -122,7 +122,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:136:5 + --> tests/ui/needless_bool/fixable.rs:148:5 | LL | / if x && y { LL | | return false; @@ -132,7 +132,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> tests/ui/needless_bool/fixable.rs:144:8 + --> tests/ui/needless_bool/fixable.rs:157:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -141,25 +141,25 @@ LL | if x == true {}; = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against false can be replaced by a negation - --> tests/ui/needless_bool/fixable.rs:148:8 + --> tests/ui/needless_bool/fixable.rs:162:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> tests/ui/needless_bool/fixable.rs:158:8 + --> tests/ui/needless_bool/fixable.rs:173:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> tests/ui/needless_bool/fixable.rs:159:8 + --> tests/ui/needless_bool/fixable.rs:175:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:168:12 + --> tests/ui/needless_bool/fixable.rs:185:12 | LL | } else if returns_bool() { | ____________^ @@ -170,7 +170,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:181:5 + --> tests/ui/needless_bool/fixable.rs:199:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -180,31 +180,31 @@ LL | | }; | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:186:30 + --> tests/ui/needless_bool/fixable.rs:205:30 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:189:9 + --> tests/ui/needless_bool/fixable.rs:209:9 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:200:14 + --> tests/ui/needless_bool/fixable.rs:221:14 | LL | let _x = if a && b { true } else { false }.then(|| todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:201:14 + --> tests/ui/needless_bool/fixable.rs:223:14 | LL | let _x = if a && b { true } else { false } as u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(a && b)` error: this if-then-else expression returns a bool literal - --> tests/ui/needless_bool/fixable.rs:204:14 + --> tests/ui/needless_bool/fixable.rs:227:14 | LL | let _x = if a { true } else { false }.then(|| todo!()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `a` diff --git a/src/tools/clippy/tests/ui/needless_bool/simple.rs b/src/tools/clippy/tests/ui/needless_bool/simple.rs index 588bb88f44613..40ffeae6c56fa 100644 --- a/src/tools/clippy/tests/ui/needless_bool/simple.rs +++ b/src/tools/clippy/tests/ui/needless_bool/simple.rs @@ -16,11 +16,13 @@ fn main() { } else { true }; + //~^^^^^ needless_bool if x { false } else { false }; + //~^^^^^ needless_bool if x { x } else { @@ -36,6 +38,7 @@ fn bool_ret(x: bool) -> bool { } else { return true; }; + //~^^^^^ needless_bool } fn bool_ret2(x: bool) -> bool { @@ -44,4 +47,5 @@ fn bool_ret2(x: bool) -> bool { } else { return false; }; + //~^^^^^ needless_bool } diff --git a/src/tools/clippy/tests/ui/needless_bool/simple.stderr b/src/tools/clippy/tests/ui/needless_bool/simple.stderr index bf30a56f43e7b..077e9b5df47cf 100644 --- a/src/tools/clippy/tests/ui/needless_bool/simple.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/simple.stderr @@ -12,7 +12,7 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::needless_bool)]` error: this if-then-else expression will always return false - --> tests/ui/needless_bool/simple.rs:19:5 + --> tests/ui/needless_bool/simple.rs:20:5 | LL | / if x { LL | | false @@ -22,7 +22,7 @@ LL | | }; | |_____^ error: this if-then-else expression will always return true - --> tests/ui/needless_bool/simple.rs:34:5 + --> tests/ui/needless_bool/simple.rs:36:5 | LL | / if x { LL | | return true; @@ -32,7 +32,7 @@ LL | | }; | |_____^ error: this if-then-else expression will always return false - --> tests/ui/needless_bool/simple.rs:42:5 + --> tests/ui/needless_bool/simple.rs:45:5 | LL | / if x { LL | | return false; diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.fixed b/src/tools/clippy/tests/ui/needless_bool_assign.fixed index 7b10fe78c6813..e0c717ecda21b 100644 --- a/src/tools/clippy/tests/ui/needless_bool_assign.fixed +++ b/src/tools/clippy/tests/ui/needless_bool_assign.fixed @@ -11,7 +11,9 @@ fn main() { }; let mut a = Data { field: false }; a.field = random() && random(); + //~^^^^^ needless_bool_assign a.field = !(random() && random()); + //~^^^^^ needless_bool_assign // Do not lint… if random() { a.field = false; @@ -22,6 +24,8 @@ fn main() { // This one also triggers lint `clippy::if_same_then_else` // which does not suggest a rewrite. random(); a.field = true; + //~^^^^^ if_same_then_else + //~| needless_bool_assign let mut b = false; if random() { a.field = false; diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.rs b/src/tools/clippy/tests/ui/needless_bool_assign.rs index 85c0a5777feea..3e4fecefa7852 100644 --- a/src/tools/clippy/tests/ui/needless_bool_assign.rs +++ b/src/tools/clippy/tests/ui/needless_bool_assign.rs @@ -15,11 +15,13 @@ fn main() { } else { a.field = false } + //~^^^^^ needless_bool_assign if random() && random() { a.field = false; } else { a.field = true } + //~^^^^^ needless_bool_assign // Do not lint… if random() { a.field = false; @@ -34,6 +36,8 @@ fn main() { } else { a.field = true; } + //~^^^^^ if_same_then_else + //~| needless_bool_assign let mut b = false; if random() { a.field = false; diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.stderr b/src/tools/clippy/tests/ui/needless_bool_assign.stderr index 2d80dded39c31..f33a4bc0c592c 100644 --- a/src/tools/clippy/tests/ui/needless_bool_assign.stderr +++ b/src/tools/clippy/tests/ui/needless_bool_assign.stderr @@ -12,7 +12,7 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::needless_bool_assign)]` error: this if-then-else expression assigns a bool literal - --> tests/ui/needless_bool_assign.rs:18:5 + --> tests/ui/needless_bool_assign.rs:19:5 | LL | / if random() && random() { LL | | a.field = false; @@ -22,7 +22,7 @@ LL | | } | |_____^ help: you can reduce it to: `a.field = !(random() && random());` error: this if-then-else expression assigns a bool literal - --> tests/ui/needless_bool_assign.rs:32:5 + --> tests/ui/needless_bool_assign.rs:34:5 | LL | / if random() { LL | | a.field = true; @@ -32,7 +32,7 @@ LL | | } | |_____^ help: you can reduce it to: `random(); a.field = true;` error: this `if` has identical blocks - --> tests/ui/needless_bool_assign.rs:32:17 + --> tests/ui/needless_bool_assign.rs:34:17 | LL | if random() { | _________________^ @@ -41,7 +41,7 @@ LL | | } else { | |_____^ | note: same as this - --> tests/ui/needless_bool_assign.rs:34:12 + --> tests/ui/needless_bool_assign.rs:36:12 | LL | } else { | ____________^ diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 2763830e09c9f..d7d344452c5d8 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -14,10 +14,14 @@ fn main() { let ref_a = &a; let _ = x(&a); // no warning let _ = x(&a); // warn + // + //~^^ needless_borrow let mut b = 5; mut_ref(&mut b); // no warning mut_ref(&mut b); // warn + // + //~^^ needless_borrow let s = &String::from("hi"); let s_ident = f(&s); // should not error, because `&String` implements Copy, but `String` does not @@ -30,14 +34,17 @@ fn main() { 45 => { println!("foo"); &a + //~^ needless_borrow }, 46 => &a, + //~^ needless_borrow 47 => { println!("foo"); loop { println!("{}", a); if a == 25 { break ref_a; + //~^ needless_borrow } } }, @@ -45,12 +52,17 @@ fn main() { }; let _ = x(&a); + //~^ needless_borrow let _ = x(&a); + //~^ needless_borrow let _ = x(&mut b); + //~^ needless_borrow let _ = x(ref_a); + //~^ needless_borrow { let b = &mut b; x(b); + //~^ needless_borrow } // Issue #8191 @@ -58,9 +70,13 @@ fn main() { let mut x = &mut x; mut_ref(x); + //~^ needless_borrow mut_ref(x); + //~^ needless_borrow let y: &mut i32 = x; + //~^ needless_borrow let y: &mut i32 = x; + //~^ needless_borrow let y = match 0 { // Don't lint. Removing the borrow would move 'x' @@ -70,12 +86,14 @@ fn main() { let y: &mut i32 = match 0 { // Lint here. The type given above triggers auto-borrow. 0 => x, + //~^ needless_borrow _ => &mut *x, }; fn ref_mut_i32(_: &mut i32) {} ref_mut_i32(match 0 { // Lint here. The type given above triggers auto-borrow. 0 => x, + //~^ needless_borrow _ => &mut *x, }); // use 'x' after to make sure it's still usable in the fixed code. @@ -88,8 +106,10 @@ fn main() { let x = (1, 2); let _ = x.0; + //~^ needless_borrow let x = &x as *const (i32, i32); let _ = unsafe { (*x).0 }; + //~^ needless_borrow // Issue #8367 trait Foo { @@ -100,6 +120,7 @@ fn main() { } (&()).foo(); // Don't lint. `()` doesn't implement `Foo` (&()).foo(); + //~^ needless_borrow impl Foo for i32 { fn foo(self) {} @@ -109,6 +130,7 @@ fn main() { } (&5).foo(); // Don't lint. `5` will call `::foo` (&5).foo(); + //~^ needless_borrow trait FooRef { fn foo_ref(&self); @@ -135,6 +157,7 @@ fn main() { // issue #11786 let x: (&str,) = ("",); + //~^ needless_borrow } #[allow(clippy::needless_borrowed_reference)] @@ -177,6 +200,7 @@ mod issue9160 { { fn calls_field(&self) -> T { (self.f)() + //~^ needless_borrow } } @@ -186,6 +210,7 @@ mod issue9160 { { fn calls_mut_field(&mut self) -> T { (self.f)() + //~^ needless_borrow } } } @@ -223,6 +248,7 @@ fn issue9383() { }; let _ = &mut (&mut x.u).x; let _ = &mut { x.u }.x; + //~^ needless_borrow let _ = &mut ({ &mut x.u }).x; let mut x = U { @@ -230,11 +256,14 @@ fn issue9383() { }; let _ = &mut (&mut x.u).x; let _ = &mut { x.u }.x; + //~^ needless_borrow let _ = &mut ({ &mut x.u }).x; let mut x = U { u: Wrap(Foo { x: 0 }) }; let _ = &mut x.u.x; + //~^ needless_borrow let _ = &mut { x.u }.x; + //~^ needless_borrow let _ = &mut ({ &mut x.u }).x; } } @@ -256,6 +285,7 @@ fn issue_12268() { let option = Some((&1,)); let x = (&1,); option.unwrap_or((x.0,)); - //~^ ERROR: this expression creates a reference which is immediately dereferenced by the + //~^ needless_borrow + // compiler } diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index b46f82b18c641..1f05b90b47285 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -14,10 +14,14 @@ fn main() { let ref_a = &a; let _ = x(&a); // no warning let _ = x(&&a); // warn + // + //~^^ needless_borrow let mut b = 5; mut_ref(&mut b); // no warning mut_ref(&mut &mut b); // warn + // + //~^^ needless_borrow let s = &String::from("hi"); let s_ident = f(&s); // should not error, because `&String` implements Copy, but `String` does not @@ -30,14 +34,17 @@ fn main() { 45 => { println!("foo"); &&a + //~^ needless_borrow }, 46 => &&a, + //~^ needless_borrow 47 => { println!("foo"); loop { println!("{}", a); if a == 25 { break &ref_a; + //~^ needless_borrow } } }, @@ -45,12 +52,17 @@ fn main() { }; let _ = x(&&&a); + //~^ needless_borrow let _ = x(&mut &&a); + //~^ needless_borrow let _ = x(&&&mut b); + //~^ needless_borrow let _ = x(&&ref_a); + //~^ needless_borrow { let b = &mut b; x(&b); + //~^ needless_borrow } // Issue #8191 @@ -58,9 +70,13 @@ fn main() { let mut x = &mut x; mut_ref(&mut x); + //~^ needless_borrow mut_ref(&mut &mut x); + //~^ needless_borrow let y: &mut i32 = &mut x; + //~^ needless_borrow let y: &mut i32 = &mut &mut x; + //~^ needless_borrow let y = match 0 { // Don't lint. Removing the borrow would move 'x' @@ -70,12 +86,14 @@ fn main() { let y: &mut i32 = match 0 { // Lint here. The type given above triggers auto-borrow. 0 => &mut x, + //~^ needless_borrow _ => &mut *x, }; fn ref_mut_i32(_: &mut i32) {} ref_mut_i32(match 0 { // Lint here. The type given above triggers auto-borrow. 0 => &mut x, + //~^ needless_borrow _ => &mut *x, }); // use 'x' after to make sure it's still usable in the fixed code. @@ -88,8 +106,10 @@ fn main() { let x = (1, 2); let _ = (&x).0; + //~^ needless_borrow let x = &x as *const (i32, i32); let _ = unsafe { (&*x).0 }; + //~^ needless_borrow // Issue #8367 trait Foo { @@ -100,6 +120,7 @@ fn main() { } (&()).foo(); // Don't lint. `()` doesn't implement `Foo` (&&()).foo(); + //~^ needless_borrow impl Foo for i32 { fn foo(self) {} @@ -109,6 +130,7 @@ fn main() { } (&5).foo(); // Don't lint. `5` will call `::foo` (&&5).foo(); + //~^ needless_borrow trait FooRef { fn foo_ref(&self); @@ -135,6 +157,7 @@ fn main() { // issue #11786 let x: (&str,) = (&"",); + //~^ needless_borrow } #[allow(clippy::needless_borrowed_reference)] @@ -177,6 +200,7 @@ mod issue9160 { { fn calls_field(&self) -> T { (&self.f)() + //~^ needless_borrow } } @@ -186,6 +210,7 @@ mod issue9160 { { fn calls_mut_field(&mut self) -> T { (&mut self.f)() + //~^ needless_borrow } } } @@ -223,6 +248,7 @@ fn issue9383() { }; let _ = &mut (&mut x.u).x; let _ = &mut (&mut { x.u }).x; + //~^ needless_borrow let _ = &mut ({ &mut x.u }).x; let mut x = U { @@ -230,11 +256,14 @@ fn issue9383() { }; let _ = &mut (&mut x.u).x; let _ = &mut (&mut { x.u }).x; + //~^ needless_borrow let _ = &mut ({ &mut x.u }).x; let mut x = U { u: Wrap(Foo { x: 0 }) }; let _ = &mut (&mut x.u).x; + //~^ needless_borrow let _ = &mut (&mut { x.u }).x; + //~^ needless_borrow let _ = &mut ({ &mut x.u }).x; } } @@ -256,6 +285,7 @@ fn issue_12268() { let option = Some((&1,)); let x = (&1,); option.unwrap_or((&x.0,)); - //~^ ERROR: this expression creates a reference which is immediately dereferenced by the + //~^ needless_borrow + // compiler } diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index 4b2b17e7e570a..b036b1e47d187 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -8,163 +8,163 @@ LL | let _ = x(&&a); // warn = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:20:13 + --> tests/ui/needless_borrow.rs:22:13 | LL | mut_ref(&mut &mut b); // warn | ^^^^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:32:13 + --> tests/ui/needless_borrow.rs:36:13 | LL | &&a | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:34:15 + --> tests/ui/needless_borrow.rs:39:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:40:27 + --> tests/ui/needless_borrow.rs:46:27 | LL | break &ref_a; | ^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:47:15 + --> tests/ui/needless_borrow.rs:54:15 | LL | let _ = x(&&&a); | ^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:48:15 + --> tests/ui/needless_borrow.rs:56:15 | LL | let _ = x(&mut &&a); | ^^^^^^^^ help: change this to: `&a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:49:15 + --> tests/ui/needless_borrow.rs:58:15 | LL | let _ = x(&&&mut b); | ^^^^^^^^ help: change this to: `&mut b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:50:15 + --> tests/ui/needless_borrow.rs:60:15 | LL | let _ = x(&&ref_a); | ^^^^^^^ help: change this to: `ref_a` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:53:11 + --> tests/ui/needless_borrow.rs:64:11 | LL | x(&b); | ^^ help: change this to: `b` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:60:13 + --> tests/ui/needless_borrow.rs:72:13 | LL | mut_ref(&mut x); | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:61:13 + --> tests/ui/needless_borrow.rs:74:13 | LL | mut_ref(&mut &mut x); | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:62:23 + --> tests/ui/needless_borrow.rs:76:23 | LL | let y: &mut i32 = &mut x; | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:63:23 + --> tests/ui/needless_borrow.rs:78:23 | LL | let y: &mut i32 = &mut &mut x; | ^^^^^^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:72:14 + --> tests/ui/needless_borrow.rs:88:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:78:14 + --> tests/ui/needless_borrow.rs:95:14 | LL | 0 => &mut x, | ^^^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:90:13 + --> tests/ui/needless_borrow.rs:108:13 | LL | let _ = (&x).0; | ^^^^ help: change this to: `x` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:92:22 + --> tests/ui/needless_borrow.rs:111:22 | LL | let _ = unsafe { (&*x).0 }; | ^^^^^ help: change this to: `(*x)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:102:5 + --> tests/ui/needless_borrow.rs:122:5 | LL | (&&()).foo(); | ^^^^^^ help: change this to: `(&())` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:111:5 + --> tests/ui/needless_borrow.rs:132:5 | LL | (&&5).foo(); | ^^^^^ help: change this to: `(&5)` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:137:23 + --> tests/ui/needless_borrow.rs:159:23 | LL | let x: (&str,) = (&"",); | ^^^ help: change this to: `""` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:179:13 + --> tests/ui/needless_borrow.rs:202:13 | LL | (&self.f)() | ^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:188:13 + --> tests/ui/needless_borrow.rs:212:13 | LL | (&mut self.f)() | ^^^^^^^^^^^^^ help: change this to: `(self.f)` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:225:22 + --> tests/ui/needless_borrow.rs:250:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:232:22 + --> tests/ui/needless_borrow.rs:258:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:236:22 + --> tests/ui/needless_borrow.rs:263:22 | LL | let _ = &mut (&mut x.u).x; | ^^^^^^^^^^ help: change this to: `x.u` error: this expression borrows a value the compiler would automatically borrow - --> tests/ui/needless_borrow.rs:237:22 + --> tests/ui/needless_borrow.rs:265:22 | LL | let _ = &mut (&mut { x.u }).x; | ^^^^^^^^^^^^^^ help: change this to: `{ x.u }` error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_borrow.rs:258:23 + --> tests/ui/needless_borrow.rs:287:23 | LL | option.unwrap_or((&x.0,)); | ^^^^ help: change this to: `x.0` diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.fixed b/src/tools/clippy/tests/ui/needless_borrow_pat.fixed index 8f8887f08a270..fe966a716df71 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.fixed @@ -57,22 +57,22 @@ fn main() { // Err, reference to a &String let _: &String = match Some(&x) { Some(x) => x, - //~^ ERROR: this pattern creates a reference to a reference - //~| NOTE: `-D clippy::needless-borrow` implied by `-D warnings` + //~^ needless_borrow None => return, }; // Err, reference to a &String. let _: &String = match Some(&x) { Some(x) => x, - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow None => return, }; // Err, reference to a &String let _: &String = match Some(&x) { Some(x) => { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + f1(x); f1(x); x @@ -83,19 +83,21 @@ fn main() { // Err, reference to a &String match Some(&x) { Some(x) => m1!(x), - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow None => return, }; // Err, reference to a &String let _ = |&x: &&String| { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = x; }; // Err, reference to a &String let (y,) = (&x,); - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = y; let y = &&x; @@ -106,7 +108,7 @@ fn main() { // Err, reference to a &u32. Don't suggest adding a reference to the field access. let _: u32 = match Some(&x) { Some(x) => x.0, - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow None => return, }; @@ -117,14 +119,15 @@ fn main() { // Err, reference to &u32. let _: &u32 = match E::A(&0) { E::A(x) | E::B(x) => x, - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow }; // Err, reference to &String. if_chain! { if true; if let Some(x) = Some(&String::new()); - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + then { f1(x); } @@ -133,7 +136,8 @@ fn main() { // Err, reference to a &String fn f2<'a>(&x: &&'a String) -> &'a String { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = x; x } @@ -141,7 +145,8 @@ fn f2<'a>(&x: &&'a String) -> &'a String { trait T1 { // Err, reference to a &String fn f(&x: &&String) { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = x; } } @@ -150,7 +155,8 @@ struct S; impl T1 for S { // Err, reference to a &String fn f(&x: &&String) { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = x; } } diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs index 56dbd923f2560..a6b43855cad10 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.rs +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs @@ -57,22 +57,22 @@ fn main() { // Err, reference to a &String let _: &String = match Some(&x) { Some(ref x) => x, - //~^ ERROR: this pattern creates a reference to a reference - //~| NOTE: `-D clippy::needless-borrow` implied by `-D warnings` + //~^ needless_borrow None => return, }; // Err, reference to a &String. let _: &String = match Some(&x) { Some(ref x) => *x, - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow None => return, }; // Err, reference to a &String let _: &String = match Some(&x) { Some(ref x) => { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + f1(x); f1(*x); x @@ -83,19 +83,21 @@ fn main() { // Err, reference to a &String match Some(&x) { Some(ref x) => m1!(x), - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow None => return, }; // Err, reference to a &String let _ = |&ref x: &&String| { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = x; }; // Err, reference to a &String let (ref y,) = (&x,); - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = *y; let y = &&x; @@ -106,7 +108,7 @@ fn main() { // Err, reference to a &u32. Don't suggest adding a reference to the field access. let _: u32 = match Some(&x) { Some(ref x) => x.0, - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow None => return, }; @@ -117,14 +119,15 @@ fn main() { // Err, reference to &u32. let _: &u32 = match E::A(&0) { E::A(ref x) | E::B(ref x) => *x, - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow }; // Err, reference to &String. if_chain! { if true; if let Some(ref x) = Some(&String::new()); - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + then { f1(x); } @@ -133,7 +136,8 @@ fn main() { // Err, reference to a &String fn f2<'a>(&ref x: &&'a String) -> &'a String { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = x; *x } @@ -141,7 +145,8 @@ fn f2<'a>(&ref x: &&'a String) -> &'a String { trait T1 { // Err, reference to a &String fn f(&ref x: &&String) { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = x; } } @@ -150,7 +155,8 @@ struct S; impl T1 for S { // Err, reference to a &String fn f(&ref x: &&String) { - //~^ ERROR: this pattern creates a reference to a reference + //~^ needless_borrow + let _: &String = *x; } } diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr index 035376cabaf42..25c570eb7ff73 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr @@ -8,7 +8,7 @@ LL | Some(ref x) => x, = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:67:14 + --> tests/ui/needless_borrow_pat.rs:66:14 | LL | Some(ref x) => *x, | ^^^^^ @@ -20,7 +20,7 @@ LL + Some(x) => x, | error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:74:14 + --> tests/ui/needless_borrow_pat.rs:73:14 | LL | Some(ref x) => { | ^^^^^ @@ -29,6 +29,7 @@ help: try | LL ~ Some(x) => { LL | +LL | LL | f1(x); LL ~ f1(x); | @@ -46,7 +47,7 @@ LL | let _ = |&ref x: &&String| { | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:97:10 + --> tests/ui/needless_borrow_pat.rs:98:10 | LL | let (ref y,) = (&x,); | ^^^^^ @@ -55,17 +56,18 @@ help: try | LL ~ let (y,) = (&x,); LL | +LL | LL ~ let _: &String = y; | error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:108:14 + --> tests/ui/needless_borrow_pat.rs:110:14 | LL | Some(ref x) => x.0, | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:119:14 + --> tests/ui/needless_borrow_pat.rs:121:14 | LL | E::A(ref x) | E::B(ref x) => *x, | ^^^^^ ^^^^^ @@ -77,13 +79,13 @@ LL + E::A(x) | E::B(x) => x, | error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:126:21 + --> tests/ui/needless_borrow_pat.rs:128:21 | LL | if let Some(ref x) = Some(&String::new()); | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:135:12 + --> tests/ui/needless_borrow_pat.rs:138:12 | LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ @@ -92,18 +94,19 @@ help: try | LL ~ fn f2<'a>(&x: &&'a String) -> &'a String { LL | +LL | LL | let _: &String = x; LL ~ x | error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:143:11 + --> tests/ui/needless_borrow_pat.rs:147:11 | LL | fn f(&ref x: &&String) { | ^^^^^ help: try: `x` error: this pattern creates a reference to a reference - --> tests/ui/needless_borrow_pat.rs:152:11 + --> tests/ui/needless_borrow_pat.rs:157:11 | LL | fn f(&ref x: &&String) { | ^^^^^ @@ -112,6 +115,7 @@ help: try | LL ~ fn f(&x: &&String) { LL | +LL | LL ~ let _: &String = x; | diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed index 5d2fd0950ee41..e4504bc2784cc 100644 --- a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed +++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed @@ -28,32 +28,48 @@ fn should_lint( ) { let mut v = Vec::::new(); let _ = v.iter_mut().filter(|a| a.is_empty()); + //~^ needless_borrowed_reference let var = 3; let thingy = Some(&var); if let Some(v) = thingy {} + //~^ needless_borrowed_reference if let &[a, ref b] = slice_of_refs {} + //~^ needless_borrowed_reference let [a, ..] = &array; + //~^ needless_borrowed_reference let [a, b, ..] = &array; + //~^ needless_borrowed_reference if let [a, b] = slice {} + //~^ needless_borrowed_reference if let [a, b] = &vec[..] {} + //~^ needless_borrowed_reference if let [a, b, ..] = slice {} + //~^ needless_borrowed_reference if let [a, .., b] = slice {} + //~^ needless_borrowed_reference if let [.., a, b] = slice {} + //~^ needless_borrowed_reference if let [a, _] = slice {} + //~^ needless_borrowed_reference if let (a, b, c) = &tuple {} + //~^ needless_borrowed_reference if let (a, _, c) = &tuple {} + //~^ needless_borrowed_reference if let (a, ..) = &tuple {} + //~^ needless_borrowed_reference if let TupleStruct(a, ..) = &tuple_struct {} + //~^ needless_borrowed_reference if let Struct { + //~^ needless_borrowed_reference a, b: b, c: renamed, @@ -61,6 +77,7 @@ fn should_lint( {} if let Struct { a, b: _, .. } = &s {} + //~^ needless_borrowed_reference } fn should_not_lint( diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs index 556fd3a35427c..7edfda60b9790 100644 --- a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs +++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs @@ -28,32 +28,48 @@ fn should_lint( ) { let mut v = Vec::::new(); let _ = v.iter_mut().filter(|&ref a| a.is_empty()); + //~^ needless_borrowed_reference let var = 3; let thingy = Some(&var); if let Some(&ref v) = thingy {} + //~^ needless_borrowed_reference if let &[&ref a, ref b] = slice_of_refs {} + //~^ needless_borrowed_reference let &[ref a, ..] = &array; + //~^ needless_borrowed_reference let &[ref a, ref b, ..] = &array; + //~^ needless_borrowed_reference if let &[ref a, ref b] = slice {} + //~^ needless_borrowed_reference if let &[ref a, ref b] = &vec[..] {} + //~^ needless_borrowed_reference if let &[ref a, ref b, ..] = slice {} + //~^ needless_borrowed_reference if let &[ref a, .., ref b] = slice {} + //~^ needless_borrowed_reference if let &[.., ref a, ref b] = slice {} + //~^ needless_borrowed_reference if let &[ref a, _] = slice {} + //~^ needless_borrowed_reference if let &(ref a, ref b, ref c) = &tuple {} + //~^ needless_borrowed_reference if let &(ref a, _, ref c) = &tuple {} + //~^ needless_borrowed_reference if let &(ref a, ..) = &tuple {} + //~^ needless_borrowed_reference if let &TupleStruct(ref a, ..) = &tuple_struct {} + //~^ needless_borrowed_reference if let &Struct { + //~^ needless_borrowed_reference ref a, b: ref b, c: ref renamed, @@ -61,6 +77,7 @@ fn should_lint( {} if let &Struct { ref a, b: _, .. } = &s {} + //~^ needless_borrowed_reference } fn should_not_lint( diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr index b8181e2805c9c..bfa3cafdedeb1 100644 --- a/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr +++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.stderr @@ -13,7 +13,7 @@ LL + let _ = v.iter_mut().filter(|a| a.is_empty()); | error: this pattern takes a reference on something that is being dereferenced - --> tests/ui/needless_borrowed_ref.rs:34:17 + --> tests/ui/needless_borrowed_ref.rs:35:17 | LL | if let Some(&ref v) = thingy {} | ^^^^^^ @@ -25,7 +25,7 @@ LL + if let Some(v) = thingy {} | error: this pattern takes a reference on something that is being dereferenced - --> tests/ui/needless_borrowed_ref.rs:36:14 + --> tests/ui/needless_borrowed_ref.rs:38:14 | LL | if let &[&ref a, ref b] = slice_of_refs {} | ^^^^^^ @@ -37,7 +37,7 @@ LL + if let &[a, ref b] = slice_of_refs {} | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:38:9 + --> tests/ui/needless_borrowed_ref.rs:41:9 | LL | let &[ref a, ..] = &array; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + let [a, ..] = &array; | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:39:9 + --> tests/ui/needless_borrowed_ref.rs:43:9 | LL | let &[ref a, ref b, ..] = &array; | ^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let [a, b, ..] = &array; | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:41:12 + --> tests/ui/needless_borrowed_ref.rs:46:12 | LL | if let &[ref a, ref b] = slice {} | ^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + if let [a, b] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:42:12 + --> tests/ui/needless_borrowed_ref.rs:48:12 | LL | if let &[ref a, ref b] = &vec[..] {} | ^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + if let [a, b] = &vec[..] {} | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:44:12 + --> tests/ui/needless_borrowed_ref.rs:51:12 | LL | if let &[ref a, ref b, ..] = slice {} | ^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + if let [a, b, ..] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:45:12 + --> tests/ui/needless_borrowed_ref.rs:53:12 | LL | if let &[ref a, .., ref b] = slice {} | ^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + if let [a, .., b] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:46:12 + --> tests/ui/needless_borrowed_ref.rs:55:12 | LL | if let &[.., ref a, ref b] = slice {} | ^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + if let [.., a, b] = slice {} | error: dereferencing a slice pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:48:12 + --> tests/ui/needless_borrowed_ref.rs:58:12 | LL | if let &[ref a, _] = slice {} | ^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + if let [a, _] = slice {} | error: dereferencing a tuple pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:50:12 + --> tests/ui/needless_borrowed_ref.rs:61:12 | LL | if let &(ref a, ref b, ref c) = &tuple {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + if let (a, b, c) = &tuple {} | error: dereferencing a tuple pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:51:12 + --> tests/ui/needless_borrowed_ref.rs:63:12 | LL | if let &(ref a, _, ref c) = &tuple {} | ^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + if let (a, _, c) = &tuple {} | error: dereferencing a tuple pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:52:12 + --> tests/ui/needless_borrowed_ref.rs:65:12 | LL | if let &(ref a, ..) = &tuple {} | ^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + if let (a, ..) = &tuple {} | error: dereferencing a tuple pattern where every element takes a reference - --> tests/ui/needless_borrowed_ref.rs:54:12 + --> tests/ui/needless_borrowed_ref.rs:68:12 | LL | if let &TupleStruct(ref a, ..) = &tuple_struct {} | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,10 +181,11 @@ LL + if let TupleStruct(a, ..) = &tuple_struct {} | error: dereferencing a struct pattern where every field's pattern takes a reference - --> tests/ui/needless_borrowed_ref.rs:56:12 + --> tests/ui/needless_borrowed_ref.rs:71:12 | LL | if let &Struct { | ____________^ +LL | | LL | | ref a, LL | | b: ref b, LL | | c: ref renamed, @@ -194,13 +195,14 @@ LL | | } = &s help: try removing the `&` and `ref` parts | LL ~ if let Struct { +LL | LL ~ a, LL ~ b: b, LL ~ c: renamed, | error: dereferencing a struct pattern where every field's pattern takes a reference - --> tests/ui/needless_borrowed_ref.rs:63:12 + --> tests/ui/needless_borrowed_ref.rs:79:12 | LL | if let &Struct { ref a, b: _, .. } = &s {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed index c1dc8b5e8d09c..8dea0d259772e 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed @@ -14,11 +14,14 @@ use std::process::Command; fn main() { let _ = Command::new("ls").args(["-a", "-l"]).status().unwrap(); + //~^ needless_borrows_for_generic_args let _ = Path::new(".").join("."); + //~^ needless_borrows_for_generic_args let _ = Any::type_id(&""); // Don't lint. `Any` is only bound let _ = Box::new(&""); // Don't lint. Type parameter appears in return type let _ = Some("").unwrap_or(&""); let _ = std::fs::write("x", "".to_string()); + //~^ needless_borrows_for_generic_args { #[derive(Clone, Copy)] @@ -34,6 +37,7 @@ fn main() { fn deref_target_is_x>(_: T) {} deref_target_is_x(X); + //~^ needless_borrows_for_generic_args } { fn multiple_constraints(_: T) @@ -47,6 +51,7 @@ fn main() { } multiple_constraints([[""]]); + //~^ needless_borrows_for_generic_args } { #[derive(Clone, Copy)] @@ -67,6 +72,7 @@ fn main() { } multiple_constraints_normalizes_to_same(X, X); + //~^ needless_borrows_for_generic_args } { fn only_sized(_: T) {} @@ -125,6 +131,7 @@ fn main() { #[allow(unused_mut)] fn warn(mut x: &mut Iter) { takes_iter(x) + //~^ needless_borrows_for_generic_args } } #[clippy::msrv = "1.52.0"] @@ -134,6 +141,7 @@ fn main() { #[clippy::msrv = "1.53.0"] { let _ = Command::new("ls").args(["-a", "-l"]).status().unwrap(); + //~^ needless_borrows_for_generic_args }; { let env = "env".to_owned(); @@ -245,6 +253,7 @@ fn main() { // 8 foo::<&[u8; 100]>(&a); foo(a); + //~^ needless_borrows_for_generic_args } { struct S; @@ -329,9 +338,13 @@ fn main() { let x = String::new(); f(&x); // Don't lint, not a copy, makes it unavailable later f(String::new()); // Lint, makes no difference + // + //~^^ needless_borrows_for_generic_args let y = "".to_owned(); f(&y); // Don't lint f("".to_owned()); // Lint + // + //~^^ needless_borrows_for_generic_args } { fn takes_writer(_: T) {} diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs index c7f66824d5818..bc2db6774e963 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs @@ -14,11 +14,14 @@ use std::process::Command; fn main() { let _ = Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + //~^ needless_borrows_for_generic_args let _ = Path::new(".").join(&&"."); + //~^ needless_borrows_for_generic_args let _ = Any::type_id(&""); // Don't lint. `Any` is only bound let _ = Box::new(&""); // Don't lint. Type parameter appears in return type let _ = Some("").unwrap_or(&""); let _ = std::fs::write("x", &"".to_string()); + //~^ needless_borrows_for_generic_args { #[derive(Clone, Copy)] @@ -34,6 +37,7 @@ fn main() { fn deref_target_is_x>(_: T) {} deref_target_is_x(&X); + //~^ needless_borrows_for_generic_args } { fn multiple_constraints(_: T) @@ -47,6 +51,7 @@ fn main() { } multiple_constraints(&[[""]]); + //~^ needless_borrows_for_generic_args } { #[derive(Clone, Copy)] @@ -67,6 +72,7 @@ fn main() { } multiple_constraints_normalizes_to_same(&X, X); + //~^ needless_borrows_for_generic_args } { fn only_sized(_: T) {} @@ -125,6 +131,7 @@ fn main() { #[allow(unused_mut)] fn warn(mut x: &mut Iter) { takes_iter(&mut x) + //~^ needless_borrows_for_generic_args } } #[clippy::msrv = "1.52.0"] @@ -134,6 +141,7 @@ fn main() { #[clippy::msrv = "1.53.0"] { let _ = Command::new("ls").args(&["-a", "-l"]).status().unwrap(); + //~^ needless_borrows_for_generic_args }; { let env = "env".to_owned(); @@ -245,6 +253,7 @@ fn main() { // 8 foo::<&[u8; 100]>(&a); foo(&a); + //~^ needless_borrows_for_generic_args } { struct S; @@ -329,9 +338,13 @@ fn main() { let x = String::new(); f(&x); // Don't lint, not a copy, makes it unavailable later f(&String::new()); // Lint, makes no difference + // + //~^^ needless_borrows_for_generic_args let y = "".to_owned(); f(&y); // Don't lint f(&"".to_owned()); // Lint + // + //~^^ needless_borrows_for_generic_args } { fn takes_writer(_: T) {} diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr index fba0755d14b5f..8829854e30739 100644 --- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr +++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr @@ -8,61 +8,61 @@ LL | let _ = Command::new("ls").args(&["-a", "-l"]).status().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::needless_borrows_for_generic_args)]` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:17:33 + --> tests/ui/needless_borrows_for_generic_args.rs:18:33 | LL | let _ = Path::new(".").join(&&"."); | ^^^^^ help: change this to: `"."` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:21:33 + --> tests/ui/needless_borrows_for_generic_args.rs:23:33 | LL | let _ = std::fs::write("x", &"".to_string()); | ^^^^^^^^^^^^^^^ help: change this to: `"".to_string()` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:36:27 + --> tests/ui/needless_borrows_for_generic_args.rs:39:27 | LL | deref_target_is_x(&X); | ^^ help: change this to: `X` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:49:30 + --> tests/ui/needless_borrows_for_generic_args.rs:53:30 | LL | multiple_constraints(&[[""]]); | ^^^^^^^ help: change this to: `[[""]]` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:69:49 + --> tests/ui/needless_borrows_for_generic_args.rs:74:49 | LL | multiple_constraints_normalizes_to_same(&X, X); | ^^ help: change this to: `X` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:127:24 + --> tests/ui/needless_borrows_for_generic_args.rs:133:24 | LL | takes_iter(&mut x) | ^^^^^^ help: change this to: `x` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:136:41 + --> tests/ui/needless_borrows_for_generic_args.rs:143:41 | LL | let _ = Command::new("ls").args(&["-a", "-l"]).status().unwrap(); | ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:247:13 + --> tests/ui/needless_borrows_for_generic_args.rs:255:13 | LL | foo(&a); | ^^ help: change this to: `a` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:331:11 + --> tests/ui/needless_borrows_for_generic_args.rs:340:11 | LL | f(&String::new()); // Lint, makes no difference | ^^^^^^^^^^^^^^ help: change this to: `String::new()` error: the borrowed expression implements the required traits - --> tests/ui/needless_borrows_for_generic_args.rs:334:11 + --> tests/ui/needless_borrows_for_generic_args.rs:345:11 | LL | f(&"".to_owned()); // Lint | ^^^^^^^^^^^^^^ help: change this to: `"".to_owned()` diff --git a/src/tools/clippy/tests/ui/needless_character_iteration.fixed b/src/tools/clippy/tests/ui/needless_character_iteration.fixed index f0bf84a41d7ed..e25db9bb590f7 100644 --- a/src/tools/clippy/tests/ui/needless_character_iteration.fixed +++ b/src/tools/clippy/tests/ui/needless_character_iteration.fixed @@ -16,25 +16,29 @@ fn magic(_: char) {} fn main() { "foo".is_ascii(); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + !"foo".is_ascii(); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + "foo".is_ascii(); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + !"foo".is_ascii(); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration let s = String::new(); s.is_ascii(); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + !"foo".to_string().is_ascii(); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration "foo".is_ascii(); !"foo".is_ascii(); S::default().field().is_ascii(); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration // Should not lint! "foo".chars().all(|c| { diff --git a/src/tools/clippy/tests/ui/needless_character_iteration.rs b/src/tools/clippy/tests/ui/needless_character_iteration.rs index 2805d2438b4ab..9b184dab6bc82 100644 --- a/src/tools/clippy/tests/ui/needless_character_iteration.rs +++ b/src/tools/clippy/tests/ui/needless_character_iteration.rs @@ -16,33 +16,39 @@ fn magic(_: char) {} fn main() { "foo".chars().all(|c| c.is_ascii()); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + "foo".chars().any(|c| !c.is_ascii()); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + "foo".chars().all(|c| char::is_ascii(&c)); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + "foo".chars().any(|c| !char::is_ascii(&c)); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration let s = String::new(); s.chars().all(|c| c.is_ascii()); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + "foo".to_string().chars().any(|c| !c.is_ascii()); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration "foo".chars().all(|c| { - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + let x = c; x.is_ascii() }); "foo".chars().any(|c| { - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration + let x = c; !x.is_ascii() }); S::default().field().chars().all(|x| x.is_ascii()); - //~^ ERROR: checking if a string is ascii using iterators + //~^ needless_character_iteration // Should not lint! "foo".chars().all(|c| { diff --git a/src/tools/clippy/tests/ui/needless_character_iteration.stderr b/src/tools/clippy/tests/ui/needless_character_iteration.stderr index 7966033555f5b..9954049966444 100644 --- a/src/tools/clippy/tests/ui/needless_character_iteration.stderr +++ b/src/tools/clippy/tests/ui/needless_character_iteration.stderr @@ -8,57 +8,59 @@ LL | "foo".chars().all(|c| c.is_ascii()); = help: to override `-D warnings` add `#[allow(clippy::needless_character_iteration)]` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:20:5 + --> tests/ui/needless_character_iteration.rs:21:5 | LL | "foo".chars().any(|c| !c.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:22:5 + --> tests/ui/needless_character_iteration.rs:24:5 | LL | "foo".chars().all(|c| char::is_ascii(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"foo".is_ascii()` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:24:5 + --> tests/ui/needless_character_iteration.rs:27:5 | LL | "foo".chars().any(|c| !char::is_ascii(&c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".is_ascii()` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:28:5 + --> tests/ui/needless_character_iteration.rs:31:5 | LL | s.chars().all(|c| c.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.is_ascii()` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:30:5 + --> tests/ui/needless_character_iteration.rs:34:5 | LL | "foo".to_string().chars().any(|c| !c.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!"foo".to_string().is_ascii()` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:33:5 + --> tests/ui/needless_character_iteration.rs:37:5 | LL | / "foo".chars().all(|c| { LL | | +LL | | LL | | let x = c; LL | | x.is_ascii() LL | | }); | |______^ help: try: `"foo".is_ascii()` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:38:5 + --> tests/ui/needless_character_iteration.rs:43:5 | LL | / "foo".chars().any(|c| { LL | | +LL | | LL | | let x = c; LL | | !x.is_ascii() LL | | }); | |______^ help: try: `!"foo".is_ascii()` error: checking if a string is ascii using iterators - --> tests/ui/needless_character_iteration.rs:44:5 + --> tests/ui/needless_character_iteration.rs:50:5 | LL | S::default().field().chars().all(|x| x.is_ascii()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `S::default().field().is_ascii()` diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed index bd83581bdd975..bad8c307586cf 100644 --- a/src/tools/clippy/tests/ui/needless_collect.fixed +++ b/src/tools/clippy/tests/ui/needless_collect.fixed @@ -1,4 +1,10 @@ -#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)] +#![allow( + unused, + clippy::needless_if, + clippy::suspicious_map, + clippy::iter_count, + clippy::manual_contains +)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; @@ -7,16 +13,21 @@ use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedL fn main() { let sample = [1; 5]; let len = sample.iter().count(); + //~^ needless_collect if sample.iter().next().is_none() { + //~^ needless_collect // Empty } sample.iter().cloned().any(|x| x == 1); + //~^ needless_collect // #7164 HashMap's and BTreeMap's `len` usage should not be linted sample.iter().map(|x| (x, x)).collect::>().len(); sample.iter().map(|x| (x, x)).collect::>().len(); sample.iter().map(|x| (x, x)).next().is_none(); + //~^ needless_collect sample.iter().map(|x| (x, x)).next().is_none(); + //~^ needless_collect // Notice the `HashSet`--this should not be linted sample.iter().collect::>().len(); @@ -24,19 +35,27 @@ fn main() { sample.iter().collect::>().len(); sample.iter().count(); + //~^ needless_collect sample.iter().next().is_none(); + //~^ needless_collect sample.iter().cloned().any(|x| x == 1); + //~^ needless_collect sample.iter().any(|x| x == &1); + //~^ needless_collect // `BinaryHeap` doesn't have `contains` method sample.iter().count(); + //~^ needless_collect sample.iter().next().is_none(); + //~^ needless_collect // Don't lint string from str let _ = ["", ""].into_iter().collect::().is_empty(); let _ = sample.iter().next().is_none(); + //~^ needless_collect let _ = sample.iter().any(|x| x == &0); + //~^ needless_collect struct VecWrapper(Vec); impl core::ops::Deref for VecWrapper { @@ -59,14 +78,20 @@ fn main() { } let _ = sample.iter().next().is_none(); + //~^ needless_collect let _ = sample.iter().any(|x| x == &0); + //~^ needless_collect #[allow(clippy::double_parens)] { Vec::::new().extend((0..10)); + //~^ needless_collect foo((0..10)); + //~^ needless_collect bar((0..10).collect::>(), (0..10)); + //~^ needless_collect baz((0..10), (), ('a'..='z')) + //~^ needless_collect } let values = [1, 2, 3, 4]; diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs index 6a81a767bbb67..3dfb5194f4048 100644 --- a/src/tools/clippy/tests/ui/needless_collect.rs +++ b/src/tools/clippy/tests/ui/needless_collect.rs @@ -1,4 +1,10 @@ -#![allow(unused, clippy::needless_if, clippy::suspicious_map, clippy::iter_count)] +#![allow( + unused, + clippy::needless_if, + clippy::suspicious_map, + clippy::iter_count, + clippy::manual_contains +)] use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; @@ -7,16 +13,21 @@ use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedL fn main() { let sample = [1; 5]; let len = sample.iter().collect::>().len(); + //~^ needless_collect if sample.iter().collect::>().is_empty() { + //~^ needless_collect // Empty } sample.iter().cloned().collect::>().contains(&1); + //~^ needless_collect // #7164 HashMap's and BTreeMap's `len` usage should not be linted sample.iter().map(|x| (x, x)).collect::>().len(); sample.iter().map(|x| (x, x)).collect::>().len(); sample.iter().map(|x| (x, x)).collect::>().is_empty(); + //~^ needless_collect sample.iter().map(|x| (x, x)).collect::>().is_empty(); + //~^ needless_collect // Notice the `HashSet`--this should not be linted sample.iter().collect::>().len(); @@ -24,19 +35,27 @@ fn main() { sample.iter().collect::>().len(); sample.iter().collect::>().len(); + //~^ needless_collect sample.iter().collect::>().is_empty(); + //~^ needless_collect sample.iter().cloned().collect::>().contains(&1); + //~^ needless_collect sample.iter().collect::>().contains(&&1); + //~^ needless_collect // `BinaryHeap` doesn't have `contains` method sample.iter().collect::>().len(); + //~^ needless_collect sample.iter().collect::>().is_empty(); + //~^ needless_collect // Don't lint string from str let _ = ["", ""].into_iter().collect::().is_empty(); let _ = sample.iter().collect::>().is_empty(); + //~^ needless_collect let _ = sample.iter().collect::>().contains(&&0); + //~^ needless_collect struct VecWrapper(Vec); impl core::ops::Deref for VecWrapper { @@ -59,14 +78,20 @@ fn main() { } let _ = sample.iter().collect::>().is_empty(); + //~^ needless_collect let _ = sample.iter().collect::>().contains(&&0); + //~^ needless_collect #[allow(clippy::double_parens)] { Vec::::new().extend((0..10).collect::>()); + //~^ needless_collect foo((0..10).collect::>()); + //~^ needless_collect bar((0..10).collect::>(), (0..10).collect::>()); + //~^ needless_collect baz((0..10), (), ('a'..='z').collect::>()) + //~^ needless_collect } let values = [1, 2, 3, 4]; diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index ea317896d3684..00745eb2923c6 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -1,5 +1,5 @@ error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:9:29 + --> tests/ui/needless_collect.rs:15:29 | LL | let len = sample.iter().collect::>().len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` @@ -8,109 +8,109 @@ LL | let len = sample.iter().collect::>().len(); = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:10:22 + --> tests/ui/needless_collect.rs:17:22 | LL | if sample.iter().collect::>().is_empty() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:13:28 + --> tests/ui/needless_collect.rs:21:28 | LL | sample.iter().cloned().collect::>().contains(&1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:18:35 + --> tests/ui/needless_collect.rs:27:35 | LL | sample.iter().map(|x| (x, x)).collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:19:35 + --> tests/ui/needless_collect.rs:29:35 | LL | sample.iter().map(|x| (x, x)).collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:26:19 + --> tests/ui/needless_collect.rs:37:19 | LL | sample.iter().collect::>().len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:27:19 + --> tests/ui/needless_collect.rs:39:19 | LL | sample.iter().collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:28:28 + --> tests/ui/needless_collect.rs:41:28 | LL | sample.iter().cloned().collect::>().contains(&1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:29:19 + --> tests/ui/needless_collect.rs:43:19 | LL | sample.iter().collect::>().contains(&&1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &1)` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:32:19 + --> tests/ui/needless_collect.rs:47:19 | LL | sample.iter().collect::>().len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:33:19 + --> tests/ui/needless_collect.rs:49:19 | LL | sample.iter().collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:38:27 + --> tests/ui/needless_collect.rs:55:27 | LL | let _ = sample.iter().collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:39:27 + --> tests/ui/needless_collect.rs:57:27 | LL | let _ = sample.iter().collect::>().contains(&&0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:61:27 + --> tests/ui/needless_collect.rs:80:27 | LL | let _ = sample.iter().collect::>().is_empty(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:62:27 + --> tests/ui/needless_collect.rs:82:27 | LL | let _ = sample.iter().collect::>().contains(&&0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:66:40 + --> tests/ui/needless_collect.rs:87:40 | LL | Vec::::new().extend((0..10).collect::>()); | ^^^^^^^^^^^^^^^^^^^^ help: remove this call error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:67:20 + --> tests/ui/needless_collect.rs:89:20 | LL | foo((0..10).collect::>()); | ^^^^^^^^^^^^^^^^^^^^ help: remove this call error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:68:49 + --> tests/ui/needless_collect.rs:91:49 | LL | bar((0..10).collect::>(), (0..10).collect::>()); | ^^^^^^^^^^^^^^^^^^^^ help: remove this call error: avoid using `collect()` when not needed - --> tests/ui/needless_collect.rs:69:37 + --> tests/ui/needless_collect.rs:93:37 | LL | baz((0..10), (), ('a'..='z').collect::>()) | ^^^^^^^^^^^^^^^^^^^^ help: remove this call diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs index 9d66c5f255fe5..57d0f2b994808 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs @@ -7,17 +7,20 @@ use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; fn main() { let sample = [1; 5]; let indirect_iter = sample.iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed - //~| NOTE: `-D clippy::needless-collect` implied by `-D warnings` + //~^ needless_collect + indirect_iter.into_iter().map(|x| (x, x + 1)).collect::>(); let indirect_len = sample.iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + indirect_len.len(); let indirect_empty = sample.iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + indirect_empty.is_empty(); let indirect_contains = sample.iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + indirect_contains.contains(&&5); let indirect_negative = sample.iter().collect::>(); indirect_negative.len(); @@ -30,7 +33,8 @@ fn main() { let a = "a".to_string(); let sample = vec![a.clone(), "b".to_string(), "c".to_string()]; let non_copy_contains = sample.into_iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + non_copy_contains.contains(&a); // Fix #5991 @@ -60,25 +64,29 @@ mod issue7110 { fn lint_vec(string: &str) -> usize { let buffer: Vec<&str> = string.split('/').collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + buffer.len() } fn lint_vec_deque() -> usize { let sample = [1; 5]; let indirect_len: VecDeque<_> = sample.iter().collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + indirect_len.len() } fn lint_linked_list() -> usize { let sample = [1; 5]; let indirect_len: LinkedList<_> = sample.iter().collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + indirect_len.len() } fn lint_binary_heap() -> usize { let sample = [1; 5]; let indirect_len: BinaryHeap<_> = sample.iter().collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + indirect_len.len() } fn dont_lint(string: &str) -> usize { @@ -139,7 +147,8 @@ mod issue_8553 { for i in 0..2 { let y: Vec = vec.iter().map(|k| k * k).collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + let z: Vec = vec.iter().map(|k| k * k).collect(); // Do lint y.contains(&i); @@ -165,7 +174,8 @@ mod issue_8553 { while n > 2 { let y: Vec = vec.iter().map(|k| k * k).collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + let z: Vec = vec.iter().map(|k| k * k).collect(); // Do lint y.contains(&n); @@ -195,7 +205,8 @@ mod issue_8553 { loop { if n < 2 { let y: Vec = vec.iter().map(|k| k * k).collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + let z: Vec = vec.iter().map(|k| k * k).collect(); // Do lint y.contains(&n); @@ -232,7 +243,8 @@ mod issue_8553 { while let Some(value) = optional { let y: Vec = vec.iter().map(|k| k * k).collect(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + let z: Vec = vec.iter().map(|k| k * k).collect(); if n < 2 { // Do lint @@ -258,7 +270,8 @@ mod issue_8553 { let vec = vec![1, 2]; let v: Vec = vec.iter().map(|i| i * i).collect(); let w = v.iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + // Do lint for _ in 0..w.len() { todo!(); @@ -281,7 +294,8 @@ mod issue_8553 { let mut vec = vec![1, 2]; let mut v: Vec = vec.iter().map(|i| i * i).collect(); let mut w = v.iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + // Do lint while 1 == w.len() { todo!(); @@ -304,7 +318,8 @@ mod issue_8553 { let mut vec = vec![1, 2]; let mut v: Vec = vec.iter().map(|i| i * i).collect(); let mut w = v.iter().collect::>(); - //~^ ERROR: avoid using `collect()` when not needed + //~^ needless_collect + // Do lint while let Some(i) = Some(w.len()) { todo!(); diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr index f25c029375455..c7bf1b14df804 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.stderr @@ -22,7 +22,7 @@ error: avoid using `collect()` when not needed | LL | let indirect_len = sample.iter().collect::>(); | ^^^^^^^ -LL | +... LL | indirect_len.len(); | ------------------ the iterator could be used here instead | @@ -30,15 +30,16 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL ~ sample.iter().count(); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:16:40 + --> tests/ui/needless_collect_indirect.rs:17:40 | LL | let indirect_empty = sample.iter().collect::>(); | ^^^^^^^ -LL | +... LL | indirect_empty.is_empty(); | ------------------------- the iterator could be used here instead | @@ -46,15 +47,16 @@ help: check if the original Iterator has anything instead of collecting it and s | LL ~ LL | +LL | LL ~ sample.iter().next().is_none(); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:19:43 + --> tests/ui/needless_collect_indirect.rs:21:43 | LL | let indirect_contains = sample.iter().collect::>(); | ^^^^^^^ -LL | +... LL | indirect_contains.contains(&&5); | ------------------------------- the iterator could be used here instead | @@ -62,15 +64,16 @@ help: check if the original Iterator contains an element instead of collecting t | LL ~ LL | +LL | LL ~ sample.iter().any(|x| x == &5); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:32:48 + --> tests/ui/needless_collect_indirect.rs:35:48 | LL | let non_copy_contains = sample.into_iter().collect::>(); | ^^^^^^^ -LL | +... LL | non_copy_contains.contains(&a); | ------------------------------ the iterator could be used here instead | @@ -78,15 +81,16 @@ help: check if the original Iterator contains an element instead of collecting t | LL ~ LL | +LL | LL ~ sample.into_iter().any(|x| x == a); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:62:51 + --> tests/ui/needless_collect_indirect.rs:66:51 | LL | let buffer: Vec<&str> = string.split('/').collect(); | ^^^^^^^ -LL | +... LL | buffer.len() | ------------ the iterator could be used here instead | @@ -94,15 +98,16 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL ~ string.split('/').count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:68:55 + --> tests/ui/needless_collect_indirect.rs:73:55 | LL | let indirect_len: VecDeque<_> = sample.iter().collect(); | ^^^^^^^ -LL | +... LL | indirect_len.len() | ------------------ the iterator could be used here instead | @@ -110,15 +115,16 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:74:57 + --> tests/ui/needless_collect_indirect.rs:80:57 | LL | let indirect_len: LinkedList<_> = sample.iter().collect(); | ^^^^^^^ -LL | +... LL | indirect_len.len() | ------------------ the iterator could be used here instead | @@ -126,15 +132,16 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:80:57 + --> tests/ui/needless_collect_indirect.rs:87:57 | LL | let indirect_len: BinaryHeap<_> = sample.iter().collect(); | ^^^^^^^ -LL | +... LL | indirect_len.len() | ------------------ the iterator could be used here instead | @@ -142,11 +149,12 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL ~ sample.iter().count() | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:141:59 + --> tests/ui/needless_collect_indirect.rs:149:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -158,13 +166,13 @@ help: check if the original Iterator contains an element instead of collecting t | LL ~ LL | -LL | let z: Vec = vec.iter().map(|k| k * k).collect(); +... LL | // Do lint LL ~ vec.iter().map(|k| k * k).any(|x| x == i); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:167:59 + --> tests/ui/needless_collect_indirect.rs:176:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -176,13 +184,13 @@ help: check if the original Iterator contains an element instead of collecting t | LL ~ LL | -LL | let z: Vec = vec.iter().map(|k| k * k).collect(); +... LL | // Do lint LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:197:63 + --> tests/ui/needless_collect_indirect.rs:207:63 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -194,13 +202,13 @@ help: check if the original Iterator contains an element instead of collecting t | LL ~ LL | -LL | let z: Vec = vec.iter().map(|k| k * k).collect(); +... LL | // Do lint LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:234:59 + --> tests/ui/needless_collect_indirect.rs:245:59 | LL | let y: Vec = vec.iter().map(|k| k * k).collect(); | ^^^^^^^ @@ -218,7 +226,7 @@ LL ~ vec.iter().map(|k| k * k).any(|x| x == n); | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:260:26 + --> tests/ui/needless_collect_indirect.rs:272:26 | LL | let w = v.iter().collect::>(); | ^^^^^^^ @@ -230,12 +238,13 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL | // Do lint LL ~ for _ in 0..v.iter().count() { | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:283:30 + --> tests/ui/needless_collect_indirect.rs:296:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ @@ -247,12 +256,13 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL | // Do lint LL ~ while 1 == v.iter().count() { | error: avoid using `collect()` when not needed - --> tests/ui/needless_collect_indirect.rs:306:30 + --> tests/ui/needless_collect_indirect.rs:320:30 | LL | let mut w = v.iter().collect::>(); | ^^^^^^^ @@ -264,6 +274,7 @@ help: take the original Iterator's count instead of collecting it and finding th | LL ~ LL | +LL | LL | // Do lint LL ~ while let Some(i) = Some(v.iter().count()) { | diff --git a/src/tools/clippy/tests/ui/needless_continue.rs b/src/tools/clippy/tests/ui/needless_continue.rs index 334a2b32775f3..e873db6dee14e 100644 --- a/src/tools/clippy/tests/ui/needless_continue.rs +++ b/src/tools/clippy/tests/ui/needless_continue.rs @@ -28,7 +28,8 @@ fn main() { let i = 0; println!("bar {} ", i); } else { - //~^ ERROR: this `else` block is redundant + //~^ needless_continue + continue; } @@ -44,7 +45,8 @@ fn main() { } if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { - //~^ ERROR: there is no need for an explicit `else` block for this `if` expression + //~^ needless_continue + continue; } else { println!("Blabber"); @@ -58,7 +60,7 @@ fn main() { fn simple_loop() { loop { continue; - //~^ ERROR: this `continue` expression is redundant + //~^ needless_continue } } @@ -66,7 +68,7 @@ fn simple_loop2() { loop { println!("bleh"); continue; - //~^ ERROR: this `continue` expression is redundant + //~^ needless_continue } } @@ -74,7 +76,8 @@ fn simple_loop2() { fn simple_loop3() { loop { continue - //~^ ERROR: this `continue` expression is redundant + //~^ needless_continue + } } @@ -83,7 +86,8 @@ fn simple_loop4() { loop { println!("bleh"); continue - //~^ ERROR: this `continue` expression is redundant + //~^ needless_continue + } } @@ -91,7 +95,7 @@ fn simple_loop5() { loop { println!("bleh"); { continue } - //~^ ERROR: this `continue` expression is redundant + //~^ needless_continue } } @@ -142,14 +146,16 @@ mod issue_2329 { if condition() { println!("bar-3"); } else { - //~^ ERROR: this `else` block is redundant + //~^ needless_continue + continue 'inner; } println!("bar-4"); update_condition(); if condition() { - //~^ ERROR: there is no need for an explicit `else` block for this `if` ex + //~^ needless_continue + continue; } else { println!("bar-5"); @@ -172,7 +178,7 @@ fn issue_13641() { while std::hint::black_box(true) { 'b: loop { continue 'b; - //~^ ERROR: this `continue` expression is redundant + //~^ needless_continue } } } @@ -188,9 +194,11 @@ mod issue_4077 { } else if !some_expr() { println!("bar-8"); continue 'inner; + //~^ needless_continue } else { println!("bar-9"); continue 'inner; + //~^ needless_continue } } } @@ -201,6 +209,7 @@ mod issue_4077 { Err(_) => { println!("bar-10"); continue; + //~^ needless_continue }, } } @@ -208,6 +217,7 @@ mod issue_4077 { loop { if true { } else { + //~^ needless_continue // redundant `else` continue; // redundant `continue` } @@ -215,6 +225,7 @@ mod issue_4077 { loop { if some_expr() { + //~^ needless_continue continue; } else { do_something(); diff --git a/src/tools/clippy/tests/ui/needless_continue.stderr b/src/tools/clippy/tests/ui/needless_continue.stderr index ec39d62341957..878c1e731e32a 100644 --- a/src/tools/clippy/tests/ui/needless_continue.stderr +++ b/src/tools/clippy/tests/ui/needless_continue.stderr @@ -4,6 +4,7 @@ error: this `else` block is redundant LL | } else { | ________________^ LL | | +LL | | LL | | continue; LL | | } | |_________^ @@ -27,6 +28,7 @@ LL | | } } if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { + continue; } else { println!("Blabber"); @@ -38,13 +40,13 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::needless_continue)]` error: there is no need for an explicit `else` block for this `if` expression - --> tests/ui/needless_continue.rs:46:9 + --> tests/ui/needless_continue.rs:47:9 | LL | / if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { LL | | +LL | | LL | | continue; -LL | | } else { -LL | | println!("Blabber"); +... | LL | | println!("Jabber"); LL | | } | |_________^ @@ -52,6 +54,7 @@ LL | | } = help: consider dropping the `else` clause if (zero!(i % 2) || nonzero!(i % 5)) && i % 3 != 0 { + continue; } { @@ -60,7 +63,7 @@ LL | | } } error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:60:9 + --> tests/ui/needless_continue.rs:62:9 | LL | continue; | ^^^^^^^^ @@ -68,7 +71,7 @@ LL | continue; = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:68:9 + --> tests/ui/needless_continue.rs:70:9 | LL | continue; | ^^^^^^^^ @@ -76,7 +79,7 @@ LL | continue; = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:76:9 + --> tests/ui/needless_continue.rs:78:9 | LL | continue | ^^^^^^^^ @@ -84,7 +87,7 @@ LL | continue = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:85:9 + --> tests/ui/needless_continue.rs:88:9 | LL | continue | ^^^^^^^^ @@ -92,7 +95,7 @@ LL | continue = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:93:11 + --> tests/ui/needless_continue.rs:97:11 | LL | { continue } | ^^^^^^^^ @@ -100,11 +103,12 @@ LL | { continue } = help: consider dropping the `continue` expression error: this `else` block is redundant - --> tests/ui/needless_continue.rs:144:24 + --> tests/ui/needless_continue.rs:148:24 | LL | } else { | ________________________^ LL | | +LL | | LL | | continue 'inner; LL | | } | |_________________^ @@ -117,6 +121,7 @@ LL | | } update_condition(); if condition() { + continue; } else { println!("bar-5"); @@ -125,10 +130,11 @@ LL | | } } error: there is no need for an explicit `else` block for this `if` expression - --> tests/ui/needless_continue.rs:151:17 + --> tests/ui/needless_continue.rs:156:17 | LL | / if condition() { LL | | +LL | | LL | | continue; LL | | } else { LL | | println!("bar-5"); @@ -138,6 +144,7 @@ LL | | } = help: consider dropping the `else` clause if condition() { + continue; } { @@ -145,7 +152,7 @@ LL | | } } error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:174:13 + --> tests/ui/needless_continue.rs:180:13 | LL | continue 'b; | ^^^^^^^^^^^ @@ -153,7 +160,7 @@ LL | continue 'b; = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:190:21 + --> tests/ui/needless_continue.rs:196:21 | LL | continue 'inner; | ^^^^^^^^^^^^^^^ @@ -161,7 +168,7 @@ LL | continue 'inner; = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:193:21 + --> tests/ui/needless_continue.rs:200:21 | LL | continue 'inner; | ^^^^^^^^^^^^^^^ @@ -169,7 +176,7 @@ LL | continue 'inner; = help: consider dropping the `continue` expression error: this `continue` expression is redundant - --> tests/ui/needless_continue.rs:203:21 + --> tests/ui/needless_continue.rs:211:21 | LL | continue; | ^^^^^^^^ @@ -177,10 +184,11 @@ LL | continue; = help: consider dropping the `continue` expression error: this `else` block is redundant - --> tests/ui/needless_continue.rs:210:20 + --> tests/ui/needless_continue.rs:219:20 | LL | } else { | ____________________^ +LL | | LL | | // redundant `else` LL | | continue; // redundant `continue` LL | | } @@ -193,9 +201,10 @@ LL | | } } error: there is no need for an explicit `else` block for this `if` expression - --> tests/ui/needless_continue.rs:217:13 + --> tests/ui/needless_continue.rs:227:13 | LL | / if some_expr() { +LL | | LL | | continue; LL | | } else { LL | | do_something(); @@ -204,6 +213,7 @@ LL | | } | = help: consider dropping the `else` clause if some_expr() { + continue; } { diff --git a/src/tools/clippy/tests/ui/needless_doc_main.rs b/src/tools/clippy/tests/ui/needless_doc_main.rs index fee05926ce4fc..cf01cae2e8fd4 100644 --- a/src/tools/clippy/tests/ui/needless_doc_main.rs +++ b/src/tools/clippy/tests/ui/needless_doc_main.rs @@ -6,7 +6,6 @@ /// ``` /// fn main() { //~^ ERROR: needless `fn main` in doctest -//~| NOTE: `-D clippy::needless-doctest-main` implied by `-D warnings` /// unimplemented!(); /// } /// ``` diff --git a/src/tools/clippy/tests/ui/needless_doc_main.stderr b/src/tools/clippy/tests/ui/needless_doc_main.stderr index 7e362cf377ce4..9ba2ad306dac2 100644 --- a/src/tools/clippy/tests/ui/needless_doc_main.stderr +++ b/src/tools/clippy/tests/ui/needless_doc_main.stderr @@ -4,7 +4,6 @@ error: needless `fn main` in doctest LL | /// fn main() { | _____^ LL | | -LL | | LL | | /// unimplemented!(); LL | | /// } | |_____^ @@ -13,7 +12,7 @@ LL | | /// } = help: to override `-D warnings` add `#[allow(clippy::needless_doctest_main)]` error: needless `fn main` in doctest - --> tests/ui/needless_doc_main.rs:16:5 + --> tests/ui/needless_doc_main.rs:15:5 | LL | /// fn main() -> () { | _____^ @@ -23,7 +22,7 @@ LL | | /// } | |_____^ error: needless `fn main` in doctest - --> tests/ui/needless_doc_main.rs:24:5 + --> tests/ui/needless_doc_main.rs:23:5 | LL | /// fn main() { | _____^ @@ -33,7 +32,7 @@ LL | | /// } | |_____^ error: needless `fn main` in doctest - --> tests/ui/needless_doc_main.rs:32:5 + --> tests/ui/needless_doc_main.rs:31:5 | LL | /// // the fn is not always the first line | _____^ diff --git a/src/tools/clippy/tests/ui/needless_else.fixed b/src/tools/clippy/tests/ui/needless_else.fixed index 240b79bae13c2..0455910c3ee8c 100644 --- a/src/tools/clippy/tests/ui/needless_else.fixed +++ b/src/tools/clippy/tests/ui/needless_else.fixed @@ -21,6 +21,7 @@ fn main() { if b { println!("Foobar"); } + //~^^ needless_else if b { println!("Foobar"); diff --git a/src/tools/clippy/tests/ui/needless_else.rs b/src/tools/clippy/tests/ui/needless_else.rs index ad84da1705357..236ac631a49e5 100644 --- a/src/tools/clippy/tests/ui/needless_else.rs +++ b/src/tools/clippy/tests/ui/needless_else.rs @@ -22,6 +22,7 @@ fn main() { println!("Foobar"); } else { } + //~^^ needless_else if b { println!("Foobar"); diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed index 2362314290e61..fa23e18318f19 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed @@ -13,27 +13,34 @@ fn should_lint() { let v: Vec = Vec::new(); let mut acc = 0; for elem in v.iter() { + //~^ needless_for_each acc += elem; } for elem in v.into_iter() { + //~^ needless_for_each acc += elem; } for elem in [1, 2, 3].iter() { + //~^ needless_for_each acc += elem; } let mut hash_map: HashMap = HashMap::new(); for (k, v) in hash_map.iter() { + //~^ needless_for_each acc += k + v; } for (k, v) in hash_map.iter_mut() { + //~^ needless_for_each acc += *k + *v; } for k in hash_map.keys() { + //~^ needless_for_each acc += k; } for v in hash_map.values() { + //~^ needless_for_each acc += v; } @@ -41,6 +48,7 @@ fn should_lint() { Vec::new() } for elem in my_vec().iter() { + //~^ needless_for_each acc += elem; } } diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs index 5b1186daa229b..2c7e68a6f5128 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs @@ -13,27 +13,34 @@ fn should_lint() { let v: Vec = Vec::new(); let mut acc = 0; v.iter().for_each(|elem| { + //~^ needless_for_each acc += elem; }); v.into_iter().for_each(|elem| { + //~^ needless_for_each acc += elem; }); [1, 2, 3].iter().for_each(|elem| { + //~^ needless_for_each acc += elem; }); let mut hash_map: HashMap = HashMap::new(); hash_map.iter().for_each(|(k, v)| { + //~^ needless_for_each acc += k + v; }); hash_map.iter_mut().for_each(|(k, v)| { + //~^ needless_for_each acc += *k + *v; }); hash_map.keys().for_each(|k| { + //~^ needless_for_each acc += k; }); hash_map.values().for_each(|v| { + //~^ needless_for_each acc += v; }); @@ -41,6 +48,7 @@ fn should_lint() { Vec::new() } my_vec().iter().for_each(|elem| { + //~^ needless_for_each acc += elem; }); } diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr index 21342d0525618..013a3fa3e36d5 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.stderr @@ -2,6 +2,7 @@ error: needless use of `for_each` --> tests/ui/needless_for_each_fixable.rs:15:5 | LL | / v.iter().for_each(|elem| { +LL | | LL | | acc += elem; LL | | }); | |_______^ @@ -11,14 +12,16 @@ LL | | }); help: try | LL ~ for elem in v.iter() { +LL + LL + acc += elem; LL + } | error: needless use of `for_each` - --> tests/ui/needless_for_each_fixable.rs:18:5 + --> tests/ui/needless_for_each_fixable.rs:19:5 | LL | / v.into_iter().for_each(|elem| { +LL | | LL | | acc += elem; LL | | }); | |_______^ @@ -26,14 +29,16 @@ LL | | }); help: try | LL ~ for elem in v.into_iter() { +LL + LL + acc += elem; LL + } | error: needless use of `for_each` - --> tests/ui/needless_for_each_fixable.rs:22:5 + --> tests/ui/needless_for_each_fixable.rs:24:5 | LL | / [1, 2, 3].iter().for_each(|elem| { +LL | | LL | | acc += elem; LL | | }); | |_______^ @@ -41,14 +46,16 @@ LL | | }); help: try | LL ~ for elem in [1, 2, 3].iter() { +LL + LL + acc += elem; LL + } | error: needless use of `for_each` - --> tests/ui/needless_for_each_fixable.rs:27:5 + --> tests/ui/needless_for_each_fixable.rs:30:5 | LL | / hash_map.iter().for_each(|(k, v)| { +LL | | LL | | acc += k + v; LL | | }); | |_______^ @@ -56,14 +63,16 @@ LL | | }); help: try | LL ~ for (k, v) in hash_map.iter() { +LL + LL + acc += k + v; LL + } | error: needless use of `for_each` - --> tests/ui/needless_for_each_fixable.rs:30:5 + --> tests/ui/needless_for_each_fixable.rs:34:5 | LL | / hash_map.iter_mut().for_each(|(k, v)| { +LL | | LL | | acc += *k + *v; LL | | }); | |_______^ @@ -71,14 +80,16 @@ LL | | }); help: try | LL ~ for (k, v) in hash_map.iter_mut() { +LL + LL + acc += *k + *v; LL + } | error: needless use of `for_each` - --> tests/ui/needless_for_each_fixable.rs:33:5 + --> tests/ui/needless_for_each_fixable.rs:38:5 | LL | / hash_map.keys().for_each(|k| { +LL | | LL | | acc += k; LL | | }); | |_______^ @@ -86,14 +97,16 @@ LL | | }); help: try | LL ~ for k in hash_map.keys() { +LL + LL + acc += k; LL + } | error: needless use of `for_each` - --> tests/ui/needless_for_each_fixable.rs:36:5 + --> tests/ui/needless_for_each_fixable.rs:42:5 | LL | / hash_map.values().for_each(|v| { +LL | | LL | | acc += v; LL | | }); | |_______^ @@ -101,14 +114,16 @@ LL | | }); help: try | LL ~ for v in hash_map.values() { +LL + LL + acc += v; LL + } | error: needless use of `for_each` - --> tests/ui/needless_for_each_fixable.rs:43:5 + --> tests/ui/needless_for_each_fixable.rs:50:5 | LL | / my_vec().iter().for_each(|elem| { +LL | | LL | | acc += elem; LL | | }); | |_______^ @@ -116,6 +131,7 @@ LL | | }); help: try | LL ~ for elem in my_vec().iter() { +LL + LL + acc += elem; LL + } | diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs index 2220cf9e11eef..159cbe49828f6 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs +++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.rs @@ -6,8 +6,8 @@ fn main() { let v: Vec = Vec::new(); // This is unfixable because the closure includes `return`. v.iter().for_each(|v| { - //~^ ERROR: needless use of `for_each` - //~| NOTE: `-D clippy::needless-for-each` implied by `-D warnings` + //~^ needless_for_each + if *v == 10 { return; } else { diff --git a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr index 722016b121252..3a3a240c5a3ab 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr +++ b/src/tools/clippy/tests/ui/needless_for_each_unfixable.stderr @@ -15,7 +15,7 @@ help: try | LL ~ for v in v.iter() { LL + -LL + +LL + LL + if *v == 10 { LL + return; LL + } else { diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed index 79e33a7218b7e..6208ca19b82b4 100644 --- a/src/tools/clippy/tests/ui/needless_if.fixed +++ b/src/tools/clippy/tests/ui/needless_if.fixed @@ -25,13 +25,16 @@ fn maybe_side_effect() -> bool { fn main() { // Lint + //~^ needless_if // Do not remove the condition maybe_side_effect(); + //~^ needless_if // Do not lint if (true) { } else { } ({ + //~^ needless_if return; }); // Do not lint if `else if` is present @@ -48,6 +51,7 @@ fn main() { {} // Can lint nested `if let`s ({ + //~^ needless_if if let true = true && true { @@ -91,12 +95,15 @@ fn main() { // Must be placed into an expression context to not be interpreted as a block ({ maybe_side_effect() }); + //~^ needless_if // Would be a block followed by `&&true` - a double reference to `true` ({ maybe_side_effect() } && true); + //~^ needless_if // Don't leave trailing attributes #[allow(unused)] true; + //~^ needless_if let () = if maybe_side_effect() {}; } diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs index 2c135fb22bf87..b459ff877be61 100644 --- a/src/tools/clippy/tests/ui/needless_if.rs +++ b/src/tools/clippy/tests/ui/needless_if.rs @@ -25,13 +25,16 @@ fn maybe_side_effect() -> bool { fn main() { // Lint if (true) {} + //~^ needless_if // Do not remove the condition if maybe_side_effect() {} + //~^ needless_if // Do not lint if (true) { } else { } if { + //~^ needless_if return; } {} // Do not lint if `else if` is present @@ -48,6 +51,7 @@ fn main() { {} // Can lint nested `if let`s if { + //~^ needless_if if let true = true && true { @@ -92,12 +96,15 @@ fn main() { // Must be placed into an expression context to not be interpreted as a block if { maybe_side_effect() } {} + //~^ needless_if // Would be a block followed by `&&true` - a double reference to `true` if { maybe_side_effect() } && true {} + //~^ needless_if // Don't leave trailing attributes #[allow(unused)] if true {} + //~^ needless_if let () = if maybe_side_effect() {}; } diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr index cbfeb979d2f20..eeb8d044526d3 100644 --- a/src/tools/clippy/tests/ui/needless_if.stderr +++ b/src/tools/clippy/tests/ui/needless_if.stderr @@ -8,15 +8,16 @@ LL | if (true) {} = help: to override `-D warnings` add `#[allow(clippy::needless_if)]` error: this `if` branch is empty - --> tests/ui/needless_if.rs:29:5 + --> tests/ui/needless_if.rs:30:5 | LL | if maybe_side_effect() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `maybe_side_effect();` error: this `if` branch is empty - --> tests/ui/needless_if.rs:34:5 + --> tests/ui/needless_if.rs:36:5 | LL | / if { +LL | | LL | | return; LL | | } {} | |________^ @@ -24,14 +25,16 @@ LL | | } {} help: you can remove it | LL ~ ({ +LL + LL + return; LL + }); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:50:5 + --> tests/ui/needless_if.rs:53:5 | LL | / if { +LL | | LL | | if let true = true LL | | && true ... | @@ -42,6 +45,7 @@ LL | | {} help: you can remove it | LL ~ ({ +LL + LL + if let true = true LL + && true LL + { @@ -53,19 +57,19 @@ LL + } && true); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:94:5 + --> tests/ui/needless_if.rs:98:5 | LL | if { maybe_side_effect() } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` error: this `if` branch is empty - --> tests/ui/needless_if.rs:96:5 + --> tests/ui/needless_if.rs:101:5 | LL | if { maybe_side_effect() } && true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` error: this `if` branch is empty - --> tests/ui/needless_if.rs:100:5 + --> tests/ui/needless_if.rs:106:5 | LL | if true {} | ^^^^^^^^^^ help: you can remove it: `true;` diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index b4bd53ce7bf7f..eb67e6cc82821 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -25,22 +25,28 @@ impl std::ops::Drop for SignificantDrop { fn simple() { + //~^ needless_late_init let a = "zero"; + //~^ needless_late_init + //~^ needless_late_init let b = 1; let c = 2; + //~^ needless_late_init let d: usize = 1; + //~^ needless_late_init let e = format!("{}", d); } fn main() { + //~^ needless_late_init let n = 1; let a = match n { 1 => "one", @@ -50,6 +56,7 @@ fn main() { }; + //~^ needless_late_init let b = if n == 3 { "four" } else { @@ -57,6 +64,7 @@ fn main() { }; + //~^ needless_late_init let d = if true { let temp = 5; temp @@ -65,6 +73,7 @@ fn main() { }; + //~^ needless_late_init let e = if true { format!("{} {}", a, b) } else { @@ -72,12 +81,14 @@ fn main() { }; + //~^ needless_late_init let f = match 1 { 1 => "three", _ => return, }; // has semi + //~^ needless_late_init let g: usize = if true { 5 } else { @@ -86,14 +97,17 @@ fn main() { // Drop order only matters if both are significant + //~^ needless_late_init let y = SignificantDrop; let x = 1; + //~^ needless_late_init let y = 1; let x = SignificantDrop; + //~^ needless_late_init // types that should be considered insignificant let y = 1; let y = "2"; @@ -113,6 +127,7 @@ async fn in_async() -> &'static str { } + //~^ needless_late_init let n = 1; let a = match n { 1 => f().await, @@ -130,6 +145,7 @@ const fn in_const() -> &'static str { } + //~^ needless_late_init let n = 1; let a = match n { 1 => f(), diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index e25483625a68c..7de2202dc3234 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -25,22 +25,28 @@ impl std::ops::Drop for SignificantDrop { fn simple() { let a; + //~^ needless_late_init a = "zero"; let b; + //~^ needless_late_init let c; + //~^ needless_late_init b = 1; c = 2; let d: usize; + //~^ needless_late_init d = 1; let e; + //~^ needless_late_init e = format!("{}", d); } fn main() { let a; + //~^ needless_late_init let n = 1; match n { 1 => a = "one", @@ -50,6 +56,7 @@ fn main() { } let b; + //~^ needless_late_init if n == 3 { b = "four"; } else { @@ -57,6 +64,7 @@ fn main() { } let d; + //~^ needless_late_init if true { let temp = 5; d = temp; @@ -65,6 +73,7 @@ fn main() { } let e; + //~^ needless_late_init if true { e = format!("{} {}", a, b); } else { @@ -72,12 +81,14 @@ fn main() { } let f; + //~^ needless_late_init match 1 { 1 => f = "three", _ => return, }; // has semi let g: usize; + //~^ needless_late_init if true { g = 5; } else { @@ -86,14 +97,17 @@ fn main() { // Drop order only matters if both are significant let x; + //~^ needless_late_init let y = SignificantDrop; x = 1; let x; + //~^ needless_late_init let y = 1; x = SignificantDrop; let x; + //~^ needless_late_init // types that should be considered insignificant let y = 1; let y = "2"; @@ -113,6 +127,7 @@ async fn in_async() -> &'static str { } let a; + //~^ needless_late_init let n = 1; match n { 1 => a = f().await, @@ -130,6 +145,7 @@ const fn in_const() -> &'static str { } let a; + //~^ needless_late_init let n = 1; match n { 1 => a = f(), diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index de048091cfbe5..02fd2811da58b 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -3,6 +3,7 @@ error: unneeded late initialization | LL | let a; | ^^^^^^ created here +LL | LL | a = "zero"; | ^^^^^^^^^^ initialised here | @@ -11,71 +12,79 @@ LL | a = "zero"; help: move the declaration `a` here | LL ~ +LL | LL ~ let a = "zero"; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:30:5 + --> tests/ui/needless_late_init.rs:31:5 | LL | let b; | ^^^^^^ created here -LL | let c; +... LL | b = 1; | ^^^^^ initialised here | help: move the declaration `b` here | LL ~ +LL | LL | let c; +LL | LL ~ let b = 1; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:31:5 + --> tests/ui/needless_late_init.rs:33:5 | LL | let c; | ^^^^^^ created here -LL | b = 1; +... LL | c = 2; | ^^^^^ initialised here | help: move the declaration `c` here | LL ~ +LL | LL | b = 1; LL ~ let c = 2; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:35:5 + --> tests/ui/needless_late_init.rs:38:5 | LL | let d: usize; | ^^^^^^^^^^^^^ created here +LL | LL | d = 1; | ^^^^^ initialised here | help: move the declaration `d` here | LL ~ +LL | LL ~ let d: usize = 1; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:38:5 + --> tests/ui/needless_late_init.rs:42:5 | LL | let e; | ^^^^^^ created here +LL | LL | e = format!("{}", d); | ^^^^^^^^^^^^^^^^^^^^ initialised here | help: move the declaration `e` here | LL ~ +LL | LL ~ let e = format!("{}", d); | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:43:5 + --> tests/ui/needless_late_init.rs:48:5 | LL | let a; | ^^^^^^ @@ -83,6 +92,7 @@ LL | let a; help: move the declaration `a` here and remove the assignments from the `match` arms | LL ~ +LL | LL | let n = 1; LL ~ let a = match n { LL ~ 1 => "one", @@ -93,7 +103,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:52:5 + --> tests/ui/needless_late_init.rs:58:5 | LL | let b; | ^^^^^^ @@ -101,6 +111,7 @@ LL | let b; help: move the declaration `b` here and remove the assignments from the branches | LL ~ +LL | LL ~ let b = if n == 3 { LL ~ "four" LL | } else { @@ -109,7 +120,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:59:5 + --> tests/ui/needless_late_init.rs:66:5 | LL | let d; | ^^^^^^ @@ -117,6 +128,7 @@ LL | let d; help: move the declaration `d` here and remove the assignments from the branches | LL ~ +LL | LL ~ let d = if true { LL | let temp = 5; LL ~ temp @@ -126,7 +138,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:67:5 + --> tests/ui/needless_late_init.rs:75:5 | LL | let e; | ^^^^^^ @@ -134,6 +146,7 @@ LL | let e; help: move the declaration `e` here and remove the assignments from the branches | LL ~ +LL | LL ~ let e = if true { LL ~ format!("{} {}", a, b) LL | } else { @@ -142,7 +155,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:74:5 + --> tests/ui/needless_late_init.rs:83:5 | LL | let f; | ^^^^^^ @@ -150,12 +163,13 @@ LL | let f; help: move the declaration `f` here and remove the assignments from the `match` arms | LL ~ +LL | LL ~ let f = match 1 { LL ~ 1 => "three", | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:80:5 + --> tests/ui/needless_late_init.rs:90:5 | LL | let g: usize; | ^^^^^^^^^^^^^ @@ -163,6 +177,7 @@ LL | let g: usize; help: move the declaration `g` here and remove the assignments from the branches | LL ~ +LL | LL ~ let g: usize = if true { LL ~ 5 LL | } else { @@ -171,39 +186,41 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:88:5 + --> tests/ui/needless_late_init.rs:99:5 | LL | let x; | ^^^^^^ created here -LL | let y = SignificantDrop; +... LL | x = 1; | ^^^^^ initialised here | help: move the declaration `x` here | LL ~ +LL | LL | let y = SignificantDrop; LL ~ let x = 1; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:92:5 + --> tests/ui/needless_late_init.rs:104:5 | LL | let x; | ^^^^^^ created here -LL | let y = 1; +... LL | x = SignificantDrop; | ^^^^^^^^^^^^^^^^^^^ initialised here | help: move the declaration `x` here | LL ~ +LL | LL | let y = 1; LL ~ let x = SignificantDrop; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:96:5 + --> tests/ui/needless_late_init.rs:109:5 | LL | let x; | ^^^^^^ created here @@ -214,14 +231,14 @@ LL | x = SignificantDrop; help: move the declaration `x` here | LL ~ -LL | // types that should be considered insignificant +LL | ... LL | let y = Box::new(4); LL ~ let x = SignificantDrop; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:115:5 + --> tests/ui/needless_late_init.rs:129:5 | LL | let a; | ^^^^^^ @@ -229,6 +246,7 @@ LL | let a; help: move the declaration `a` here and remove the assignments from the `match` arms | LL ~ +LL | LL | let n = 1; LL ~ let a = match n { LL ~ 1 => f().await, @@ -239,7 +257,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:132:5 + --> tests/ui/needless_late_init.rs:147:5 | LL | let a; | ^^^^^^ @@ -247,6 +265,7 @@ LL | let a; help: move the declaration `a` here and remove the assignments from the `match` arms | LL ~ +LL | LL | let n = 1; LL ~ let a = match n { LL ~ 1 => f(), diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index 86cf9a9cdb635..d59393fb3f3c6 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs -#![warn(clippy::needless_lifetimes)] +#![warn(clippy::needless_lifetimes, clippy::elidable_lifetime_names)] #![allow( unused, clippy::boxed_local, @@ -9,15 +9,18 @@ clippy::redundant_allocation, clippy::unnecessary_wraps, dyn_drop, - clippy::get_first + clippy::get_first, + elided_named_lifetimes )] extern crate proc_macros; use proc_macros::inline_macros; fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} +//~^ needless_lifetimes fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {} +//~^ needless_lifetimes // No error; same lifetime on two params. fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {} @@ -28,6 +31,7 @@ fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {} fn mut_and_static_input(_x: &mut u8, _y: &'static str) {} fn in_and_out(x: &u8, _y: u8) -> &u8 { + //~^ needless_lifetimes x } @@ -40,6 +44,7 @@ fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { // fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 // ^^^ fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 { + //~^ needless_lifetimes x } @@ -47,6 +52,7 @@ fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 { // fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 // ^^^ fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 { + //~^ needless_lifetimes y } @@ -64,6 +70,7 @@ fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { // fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> // ^^^ fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> { + //~^ needless_lifetimes Ok(x) } @@ -71,6 +78,7 @@ fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> { // fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> // ^^^ fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> { + //~^ needless_lifetimes Ok(y) } @@ -80,53 +88,19 @@ fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { } fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> { + //~^ needless_lifetimes Ok(x) } // Where-clause, but without lifetimes. fn where_clause_without_lt(x: &u8, _y: u8) -> Result<&u8, ()> +//~^ needless_lifetimes where T: Copy, { Ok(x) } -type Ref<'r> = &'r u8; - -// No error; same lifetime on two params. -fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} - -fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} - -// No error; bounded lifetime. -fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} - -// No error; bounded lifetime. -fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) -where - 'b: 'a, -{ -} - -struct Lt<'a, I: 'static> { - x: &'a I, -} - -// No error; fn bound references `'a`. -fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> -where - F: Fn(Lt<'a, I>) -> Lt<'a, I>, -{ - unreachable!() -} - -fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> -where - for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>, -{ - unreachable!() -} - // No error; see below. fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) { f(x); @@ -151,6 +125,7 @@ struct X { impl X { fn self_and_out(&self) -> &u8 { + //~^ needless_lifetimes &self.x } @@ -158,6 +133,7 @@ impl X { // fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 // ^^^ fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 { + //~^ needless_lifetimes &self.x } @@ -165,10 +141,12 @@ impl X { // fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 // ^^^^^ fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 { + //~^ needless_lifetimes x } fn distinct_self_and_in(&self, _x: &u8) {} + //~^ needless_lifetimes // No error; same lifetimes on two params. fn self_and_same_in<'s>(&'s self, _x: &'s u8) {} @@ -187,33 +165,12 @@ fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 { unimplemented!() } -fn struct_with_lt(_foo: Foo<'_>) -> &str { - unimplemented!() -} - -// No warning; two input lifetimes (named on the reference, anonymous on `Foo`). -fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { - unimplemented!() -} - -// No warning; two input lifetimes (anonymous on the reference, named on `Foo`). -fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str { - unimplemented!() -} - -// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is -// valid: -// fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str -// ^^ -fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { - unimplemented!() -} - // Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is // valid: // fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str // ^^^^ fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str { + //~^ needless_lifetimes unimplemented!() } @@ -229,42 +186,23 @@ fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str { // Should warn because there is no lifetime on `Drop`, so this would be // unambiguous if we elided the lifetime. fn trait_obj_elided2(_arg: &dyn Drop) -> &str { + //~^ needless_lifetimes unimplemented!() } type FooAlias<'a> = Foo<'a>; -fn alias_with_lt(_foo: FooAlias<'_>) -> &str { - unimplemented!() -} - -// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`). -fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { - unimplemented!() -} - -// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`). -fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str { - unimplemented!() -} - -// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is -// valid: -// fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str -// ^^ -fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { - unimplemented!() -} - // Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is // valid: // fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str // ^^^^^^^^^ fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str { + //~^ needless_lifetimes unimplemented!() } fn named_input_elided_output(_arg: &str) -> &str { + //~^ needless_lifetimes unimplemented!() } @@ -273,6 +211,7 @@ fn elided_input_named_output<'a>(_arg: &str) -> &'a str { } fn trait_bound_ok>(_: &u8, _: T) { + //~^ needless_lifetimes unimplemented!() } fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) { @@ -304,37 +243,16 @@ fn test<'a>(x: &'a [u8]) -> u8 { *y } -// Issue #3284: give hint regarding lifetime in return type. -struct Cow<'a> { - x: &'a str, -} -fn out_return_type_lts(e: &str) -> Cow<'_> { - unimplemented!() -} - // Make sure we still warn on implementations mod issue4291 { trait BadTrait { fn needless_lt(x: &u8) {} + //~^ needless_lifetimes } impl BadTrait for () { fn needless_lt(_x: &u8) {} - } -} - -mod issue2944 { - trait Foo {} - struct Bar; - struct Baz<'a> { - bar: &'a Bar, - } - - impl Foo for Baz<'_> {} - impl Bar { - fn baz(&self) -> impl Foo + '_ { - Baz { bar: self } - } + //~^ needless_lifetimes } } @@ -365,6 +283,7 @@ mod nested_elision_sites { f(i) } fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 { + //~^ needless_lifetimes f(i) } @@ -374,6 +293,7 @@ mod nested_elision_sites { } // lint fn generics_elidable &i32>(i: &i32, f: T) -> &i32 { + //~^ needless_lifetimes f(i) } @@ -386,6 +306,7 @@ mod nested_elision_sites { } // lint fn where_clause_elidable(i: &i32, f: T) -> &i32 + //~^ needless_lifetimes where T: Fn(&i32) -> &i32, { @@ -401,6 +322,7 @@ mod nested_elision_sites { } // lint fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 { + //~^ needless_lifetimes f(i) } @@ -414,9 +336,11 @@ mod nested_elision_sites { // lint fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 { + //~^ needless_lifetimes |f| 42 } fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) { + //~^ needless_lifetimes |f| () } } @@ -439,17 +363,21 @@ mod issue7296 { struct Foo; impl Foo { fn implicit(&self) -> &() { + //~^ needless_lifetimes &() } fn implicit_mut(&mut self) -> &() { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.81"] fn explicit(self: &Arc) -> &() { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.81"] fn explicit_mut(self: &mut Rc) -> &() { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.80"] @@ -462,20 +390,25 @@ mod issue7296 { } fn lifetime_elsewhere(self: Box, here: &()) -> &() { + //~^ needless_lifetimes &() } } trait Bar { fn implicit(&self) -> &(); + //~^ needless_lifetimes fn implicit_provided(&self) -> &() { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.81"] fn explicit(self: &Arc) -> &(); + //~^ needless_lifetimes #[clippy::msrv = "1.81"] fn explicit_provided(self: &Arc) -> &() { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.80"] @@ -486,7 +419,9 @@ mod issue7296 { } fn lifetime_elsewhere(self: Box, here: &()) -> &(); + //~^ needless_lifetimes fn lifetime_elsewhere_provided(self: Box, here: &()) -> &() { + //~^ needless_lifetimes &() } } @@ -496,8 +431,10 @@ mod pr_9743_false_negative_fix { #![allow(unused)] fn foo(x: &u8, y: &'_ u8) {} + //~^ needless_lifetimes fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {} + //~^ needless_lifetimes } mod pr_9743_output_lifetime_checks { @@ -505,11 +442,13 @@ mod pr_9743_output_lifetime_checks { // lint: only one input fn one_input(x: &u8) -> &u8 { + //~^ needless_lifetimes unimplemented!() } // lint: multiple inputs, output would not be elided fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 { + //~^ needless_lifetimes unimplemented!() } @@ -526,6 +465,7 @@ mod in_macro { // lint local macro expands to function with needless lifetimes inline! { fn one_input(x: &u8) -> &u8 { + //~^ needless_lifetimes unimplemented!() } } @@ -594,85 +534,4 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } -mod issue13923 { - struct Py<'py> { - data: &'py str, - } - - enum Content<'t, 'py> { - Py(Py<'py>), - T1(&'t str), - T2(&'t str), - } - - enum ContentString<'t> { - T1(&'t str), - T2(&'t str), - } - - impl<'t, 'py> ContentString<'t> { - // `'py` cannot be elided - fn map_content1(self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(content) => Content::T2(f(content)), - } - } - } - - impl<'t> ContentString<'t> { - // `'py` can be elided because of `&self` - fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(content) => Content::T2(f(content)), - } - } - } - - impl<'t> ContentString<'t> { - // `'py` can be elided because of `&'_ self` - fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(content) => Content::T2(f(content)), - } - } - } - - impl<'t, 'py> ContentString<'t> { - // `'py` should not be elided as the default lifetime, even if working, could be named as `'t` - fn map_content4(self, f: impl FnOnce(&'t str) -> &'t str, o: &'t str) -> Content<'t, 'py> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(_) => Content::T2(o), - } - } - } - - impl<'t> ContentString<'t> { - // `'py` can be elided because of `&Self` - fn map_content5( - self: std::pin::Pin<&Self>, - f: impl FnOnce(&'t str) -> &'t str, - o: &'t str, - ) -> Content<'t, '_> { - match *self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(_) => Content::T2(o), - } - } - } - - struct Cx<'a, 'b> { - a: &'a u32, - b: &'b u32, - } - - // `'c` cannot be elided because we have several input lifetimes - fn one_explicit<'b>(x: Cx<'_, 'b>) -> &'b u32 { - x.b - } -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index 1ee0f4c6092ae..e24907ab5fcdf 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -1,6 +1,6 @@ //@aux-build:proc_macros.rs -#![warn(clippy::needless_lifetimes)] +#![warn(clippy::needless_lifetimes, clippy::elidable_lifetime_names)] #![allow( unused, clippy::boxed_local, @@ -9,15 +9,18 @@ clippy::redundant_allocation, clippy::unnecessary_wraps, dyn_drop, - clippy::get_first + clippy::get_first, + elided_named_lifetimes )] extern crate proc_macros; use proc_macros::inline_macros; fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} +//~^ needless_lifetimes fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} +//~^ needless_lifetimes // No error; same lifetime on two params. fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {} @@ -28,6 +31,7 @@ fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {} fn mut_and_static_input(_x: &mut u8, _y: &'static str) {} fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { + //~^ needless_lifetimes x } @@ -40,6 +44,7 @@ fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 { // fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 // ^^^ fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { + //~^ needless_lifetimes x } @@ -47,6 +52,7 @@ fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { // fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 // ^^^ fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 { + //~^ needless_lifetimes y } @@ -64,6 +70,7 @@ fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 { // fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> // ^^^ fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { + //~^ needless_lifetimes Ok(x) } @@ -71,6 +78,7 @@ fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { // fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> // ^^^ fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> { + //~^ needless_lifetimes Ok(y) } @@ -80,53 +88,19 @@ fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 { } fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { + //~^ needless_lifetimes Ok(x) } // Where-clause, but without lifetimes. fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> +//~^ needless_lifetimes where T: Copy, { Ok(x) } -type Ref<'r> = &'r u8; - -// No error; same lifetime on two params. -fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {} - -fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} - -// No error; bounded lifetime. -fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {} - -// No error; bounded lifetime. -fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8) -where - 'b: 'a, -{ -} - -struct Lt<'a, I: 'static> { - x: &'a I, -} - -// No error; fn bound references `'a`. -fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> -where - F: Fn(Lt<'a, I>) -> Lt<'a, I>, -{ - unreachable!() -} - -fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> -where - for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>, -{ - unreachable!() -} - // No error; see below. fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) { f(x); @@ -151,6 +125,7 @@ struct X { impl X { fn self_and_out<'s>(&'s self) -> &'s u8 { + //~^ needless_lifetimes &self.x } @@ -158,6 +133,7 @@ impl X { // fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 // ^^^ fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { + //~^ needless_lifetimes &self.x } @@ -165,10 +141,12 @@ impl X { // fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 // ^^^^^ fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 { + //~^ needless_lifetimes x } fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} + //~^ needless_lifetimes // No error; same lifetimes on two params. fn self_and_same_in<'s>(&'s self, _x: &'s u8) {} @@ -187,33 +165,12 @@ fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 { unimplemented!() } -fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { - unimplemented!() -} - -// No warning; two input lifetimes (named on the reference, anonymous on `Foo`). -fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str { - unimplemented!() -} - -// No warning; two input lifetimes (anonymous on the reference, named on `Foo`). -fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str { - unimplemented!() -} - -// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is -// valid: -// fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str -// ^^ -fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { - unimplemented!() -} - // Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is // valid: // fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str // ^^^^ fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str { + //~^ needless_lifetimes unimplemented!() } @@ -229,42 +186,23 @@ fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str { // Should warn because there is no lifetime on `Drop`, so this would be // unambiguous if we elided the lifetime. fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { + //~^ needless_lifetimes unimplemented!() } type FooAlias<'a> = Foo<'a>; -fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { - unimplemented!() -} - -// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`). -fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str { - unimplemented!() -} - -// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`). -fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str { - unimplemented!() -} - -// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is -// valid: -// fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str -// ^^ -fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { - unimplemented!() -} - // Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is // valid: // fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str // ^^^^^^^^^ fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str { + //~^ needless_lifetimes unimplemented!() } fn named_input_elided_output<'a>(_arg: &'a str) -> &str { + //~^ needless_lifetimes unimplemented!() } @@ -273,6 +211,7 @@ fn elided_input_named_output<'a>(_arg: &str) -> &'a str { } fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { + //~^ needless_lifetimes unimplemented!() } fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) { @@ -304,37 +243,16 @@ fn test<'a>(x: &'a [u8]) -> u8 { *y } -// Issue #3284: give hint regarding lifetime in return type. -struct Cow<'a> { - x: &'a str, -} -fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { - unimplemented!() -} - // Make sure we still warn on implementations mod issue4291 { trait BadTrait { fn needless_lt<'a>(x: &'a u8) {} + //~^ needless_lifetimes } impl BadTrait for () { fn needless_lt<'a>(_x: &'a u8) {} - } -} - -mod issue2944 { - trait Foo {} - struct Bar; - struct Baz<'a> { - bar: &'a Bar, - } - - impl<'a> Foo for Baz<'a> {} - impl Bar { - fn baz<'a>(&'a self) -> impl Foo + 'a { - Baz { bar: self } - } + //~^ needless_lifetimes } } @@ -365,6 +283,7 @@ mod nested_elision_sites { f(i) } fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { + //~^ needless_lifetimes f(i) } @@ -374,6 +293,7 @@ mod nested_elision_sites { } // lint fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { + //~^ needless_lifetimes f(i) } @@ -386,6 +306,7 @@ mod nested_elision_sites { } // lint fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32 + //~^ needless_lifetimes where T: Fn(&i32) -> &i32, { @@ -401,6 +322,7 @@ mod nested_elision_sites { } // lint fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { + //~^ needless_lifetimes f(i) } @@ -414,9 +336,11 @@ mod nested_elision_sites { // lint fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { + //~^ needless_lifetimes |f| 42 } fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { + //~^ needless_lifetimes |f| () } } @@ -439,17 +363,21 @@ mod issue7296 { struct Foo; impl Foo { fn implicit<'a>(&'a self) -> &'a () { + //~^ needless_lifetimes &() } fn implicit_mut<'a>(&'a mut self) -> &'a () { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.81"] fn explicit<'a>(self: &'a Arc) -> &'a () { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.81"] fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.80"] @@ -462,20 +390,25 @@ mod issue7296 { } fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { + //~^ needless_lifetimes &() } } trait Bar { fn implicit<'a>(&'a self) -> &'a (); + //~^ needless_lifetimes fn implicit_provided<'a>(&'a self) -> &'a () { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.81"] fn explicit<'a>(self: &'a Arc) -> &'a (); + //~^ needless_lifetimes #[clippy::msrv = "1.81"] fn explicit_provided<'a>(self: &'a Arc) -> &'a () { + //~^ needless_lifetimes &() } #[clippy::msrv = "1.80"] @@ -486,7 +419,9 @@ mod issue7296 { } fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); + //~^ needless_lifetimes fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { + //~^ needless_lifetimes &() } } @@ -496,8 +431,10 @@ mod pr_9743_false_negative_fix { #![allow(unused)] fn foo<'a>(x: &'a u8, y: &'_ u8) {} + //~^ needless_lifetimes fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} + //~^ needless_lifetimes } mod pr_9743_output_lifetime_checks { @@ -505,11 +442,13 @@ mod pr_9743_output_lifetime_checks { // lint: only one input fn one_input<'a>(x: &'a u8) -> &'a u8 { + //~^ needless_lifetimes unimplemented!() } // lint: multiple inputs, output would not be elided fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 { + //~^ needless_lifetimes unimplemented!() } @@ -526,6 +465,7 @@ mod in_macro { // lint local macro expands to function with needless lifetimes inline! { fn one_input<'a>(x: &'a u8) -> &'a u8 { + //~^ needless_lifetimes unimplemented!() } } @@ -594,85 +534,4 @@ mod issue13749bis { impl<'a, T: 'a> Generic {} } -mod issue13923 { - struct Py<'py> { - data: &'py str, - } - - enum Content<'t, 'py> { - Py(Py<'py>), - T1(&'t str), - T2(&'t str), - } - - enum ContentString<'t> { - T1(&'t str), - T2(&'t str), - } - - impl<'t, 'py> ContentString<'t> { - // `'py` cannot be elided - fn map_content1(self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(content) => Content::T2(f(content)), - } - } - } - - impl<'t, 'py> ContentString<'t> { - // `'py` can be elided because of `&self` - fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(content) => Content::T2(f(content)), - } - } - } - - impl<'t, 'py> ContentString<'t> { - // `'py` can be elided because of `&'_ self` - fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(content) => Content::T2(f(content)), - } - } - } - - impl<'t, 'py> ContentString<'t> { - // `'py` should not be elided as the default lifetime, even if working, could be named as `'t` - fn map_content4(self, f: impl FnOnce(&'t str) -> &'t str, o: &'t str) -> Content<'t, 'py> { - match self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(_) => Content::T2(o), - } - } - } - - impl<'t, 'py> ContentString<'t> { - // `'py` can be elided because of `&Self` - fn map_content5( - self: std::pin::Pin<&Self>, - f: impl FnOnce(&'t str) -> &'t str, - o: &'t str, - ) -> Content<'t, 'py> { - match *self { - Self::T1(content) => Content::T1(f(content)), - Self::T2(_) => Content::T2(o), - } - } - } - - struct Cx<'a, 'b> { - a: &'a u32, - b: &'b u32, - } - - // `'c` cannot be elided because we have several input lifetimes - fn one_explicit<'b>(x: Cx<'_, 'b>) -> &'b u32 { - &x.b - } -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index 465d529bf16c5..138d0498c43e4 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -1,16 +1,5 @@ -error: elided lifetime has a name - --> tests/ui/needless_lifetimes.rs:267:52 - | -LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { - | -- ^ this elided lifetime gets resolved as `'a` - | | - | lifetime `'a` declared here - | - = note: `-D elided-named-lifetimes` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(elided_named_lifetimes)]` - error: the following explicit lifetimes could be elided: 'a, 'b - --> tests/ui/needless_lifetimes.rs:18:23 + --> tests/ui/needless_lifetimes.rs:19:23 | LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {} | ^^ ^^ ^^ ^^ @@ -24,7 +13,7 @@ LL + fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {} | error: the following explicit lifetimes could be elided: 'a, 'b - --> tests/ui/needless_lifetimes.rs:20:24 + --> tests/ui/needless_lifetimes.rs:22:24 | LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {} | ^^ ^^ ^^ ^^ @@ -36,7 +25,7 @@ LL + fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:30:15 + --> tests/ui/needless_lifetimes.rs:33:15 | LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 { | ^^ ^^ ^^ @@ -48,7 +37,7 @@ LL + fn in_and_out(x: &u8, _y: u8) -> &u8 { | error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:42:31 + --> tests/ui/needless_lifetimes.rs:46:31 | LL | fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 { | ^^ ^^ @@ -60,7 +49,7 @@ LL + fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:49:27 + --> tests/ui/needless_lifetimes.rs:54:27 | LL | fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 { | ^^ ^^ @@ -72,7 +61,7 @@ LL + fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 { | error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:66:26 + --> tests/ui/needless_lifetimes.rs:72:26 | LL | fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> { | ^^ ^^ @@ -84,7 +73,7 @@ LL + fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:73:22 + --> tests/ui/needless_lifetimes.rs:80:22 | LL | fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> { | ^^ ^^ @@ -96,7 +85,7 @@ LL + fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:82:21 + --> tests/ui/needless_lifetimes.rs:90:21 | LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> { | ^^ ^^ ^^ @@ -108,7 +97,7 @@ LL + fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:87:28 + --> tests/ui/needless_lifetimes.rs:96:28 | LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> | ^^ ^^ ^^ @@ -119,32 +108,8 @@ LL - fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> LL + fn where_clause_without_lt(x: &u8, _y: u8) -> Result<&u8, ()> | -error: the following explicit lifetimes could be elided: 'a, 'b - --> tests/ui/needless_lifetimes.rs:99:21 - | -LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} - | ^^ ^^ ^^ ^^ - | -help: elide the lifetimes - | -LL - fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {} -LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {} - | - -error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:123:15 - | -LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> - | ^^ ^^ ^^ - | -help: elide the lifetimes - | -LL - fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I> -LL + fn fn_bound_2(_m: Lt<'_, I>, _f: F) -> Lt<'_, I> - | - error: the following explicit lifetimes could be elided: 's - --> tests/ui/needless_lifetimes.rs:153:21 + --> tests/ui/needless_lifetimes.rs:127:21 | LL | fn self_and_out<'s>(&'s self) -> &'s u8 { | ^^ ^^ ^^ @@ -156,7 +121,7 @@ LL + fn self_and_out(&self) -> &u8 { | error: the following explicit lifetimes could be elided: 't - --> tests/ui/needless_lifetimes.rs:160:30 + --> tests/ui/needless_lifetimes.rs:135:30 | LL | fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 { | ^^ ^^ @@ -168,7 +133,7 @@ LL + fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 { | error: the following explicit lifetimes could be elided: 's - --> tests/ui/needless_lifetimes.rs:167:26 + --> tests/ui/needless_lifetimes.rs:143:26 | LL | fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 { | ^^ ^^ @@ -180,7 +145,7 @@ LL + fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 { | error: the following explicit lifetimes could be elided: 's, 't - --> tests/ui/needless_lifetimes.rs:171:29 + --> tests/ui/needless_lifetimes.rs:148:29 | LL | fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {} | ^^ ^^ ^^ ^^ @@ -192,31 +157,7 @@ LL + fn distinct_self_and_in(&self, _x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:190:19 - | -LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { - | ^^ ^^ ^^ - | -help: elide the lifetimes - | -LL - fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str { -LL + fn struct_with_lt(_foo: Foo<'_>) -> &str { - | - -error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:208:25 - | -LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { - | ^^ ^^ - | -help: elide the lifetimes - | -LL - fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str { -LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str { - | - -error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:216:21 + --> tests/ui/needless_lifetimes.rs:172:21 | LL | fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str { | ^^ ^^ @@ -228,7 +169,7 @@ LL + fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:231:22 + --> tests/ui/needless_lifetimes.rs:188:22 | LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str { | ^^ ^^ ^^ @@ -240,31 +181,7 @@ LL + fn trait_obj_elided2(_arg: &dyn Drop) -> &str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:237:18 - | -LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { - | ^^ ^^ ^^ - | -help: elide the lifetimes - | -LL - fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str { -LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str { - | - -error: the following explicit lifetimes could be elided: 'b - --> tests/ui/needless_lifetimes.rs:255:24 - | -LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { - | ^^ ^^ - | -help: elide the lifetimes - | -LL - fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str { -LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str { - | - -error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:263:20 + --> tests/ui/needless_lifetimes.rs:199:20 | LL | fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str { | ^^ ^^ @@ -276,7 +193,7 @@ LL + fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:267:30 + --> tests/ui/needless_lifetimes.rs:204:30 | LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str { | ^^ ^^ ^ @@ -288,7 +205,7 @@ LL + fn named_input_elided_output(_arg: &str) -> &str { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:275:19 + --> tests/ui/needless_lifetimes.rs:213:19 | LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) { | ^^ ^^ @@ -300,19 +217,7 @@ LL + fn trait_bound_ok>(_: &u8, _: T) { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:311:24 - | -LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { - | ^^ ^^ ^^ - | -help: elide the lifetimes - | -LL - fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> { -LL + fn out_return_type_lts(e: &str) -> Cow<'_> { - | - -error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:318:24 + --> tests/ui/needless_lifetimes.rs:249:24 | LL | fn needless_lt<'a>(x: &'a u8) {} | ^^ ^^ @@ -324,7 +229,7 @@ LL + fn needless_lt(x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:322:24 + --> tests/ui/needless_lifetimes.rs:254:24 | LL | fn needless_lt<'a>(_x: &'a u8) {} | ^^ ^^ @@ -336,31 +241,7 @@ LL + fn needless_lt(_x: &u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:333:10 - | -LL | impl<'a> Foo for Baz<'a> {} - | ^^ ^^ - | -help: elide the lifetimes - | -LL - impl<'a> Foo for Baz<'a> {} -LL + impl Foo for Baz<'_> {} - | - -error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:335:16 - | -LL | fn baz<'a>(&'a self) -> impl Foo + 'a { - | ^^ ^^ ^^ - | -help: elide the lifetimes - | -LL - fn baz<'a>(&'a self) -> impl Foo + 'a { -LL + fn baz(&self) -> impl Foo + '_ { - | - -error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:367:55 + --> tests/ui/needless_lifetimes.rs:285:55 | LL | fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 { | ^^ ^^ ^^ @@ -372,7 +253,7 @@ LL + fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(& | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:376:26 + --> tests/ui/needless_lifetimes.rs:295:26 | LL | fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 { | ^^ ^^ ^^ @@ -384,7 +265,7 @@ LL + fn generics_elidable &i32>(i: &i32, f: T) -> &i32 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:388:30 + --> tests/ui/needless_lifetimes.rs:308:30 | LL | fn where_clause_elidable<'a, T>(i: &'a i32, f: T) -> &'a i32 | ^^ ^^ ^^ @@ -396,7 +277,7 @@ LL + fn where_clause_elidable(i: &i32, f: T) -> &i32 | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:403:28 + --> tests/ui/needless_lifetimes.rs:324:28 | LL | fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 { | ^^ ^^ ^^ @@ -408,7 +289,7 @@ LL + fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:416:28 + --> tests/ui/needless_lifetimes.rs:338:28 | LL | fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 { | ^^ ^^ @@ -420,7 +301,7 @@ LL + fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:419:28 + --> tests/ui/needless_lifetimes.rs:342:28 | LL | fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) { | ^^ ^^ @@ -432,7 +313,7 @@ LL + fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:441:21 + --> tests/ui/needless_lifetimes.rs:365:21 | LL | fn implicit<'a>(&'a self) -> &'a () { | ^^ ^^ ^^ @@ -444,7 +325,7 @@ LL + fn implicit(&self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:444:25 + --> tests/ui/needless_lifetimes.rs:369:25 | LL | fn implicit_mut<'a>(&'a mut self) -> &'a () { | ^^ ^^ ^^ @@ -456,7 +337,7 @@ LL + fn implicit_mut(&mut self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:448:21 + --> tests/ui/needless_lifetimes.rs:374:21 | LL | fn explicit<'a>(self: &'a Arc) -> &'a () { | ^^ ^^ ^^ @@ -468,7 +349,7 @@ LL + fn explicit(self: &Arc) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:452:25 + --> tests/ui/needless_lifetimes.rs:379:25 | LL | fn explicit_mut<'a>(self: &'a mut Rc) -> &'a () { | ^^ ^^ ^^ @@ -480,7 +361,7 @@ LL + fn explicit_mut(self: &mut Rc) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:464:31 + --> tests/ui/needless_lifetimes.rs:392:31 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a () { | ^^ ^^ ^^ @@ -492,7 +373,7 @@ LL + fn lifetime_elsewhere(self: Box, here: &()) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:470:21 + --> tests/ui/needless_lifetimes.rs:399:21 | LL | fn implicit<'a>(&'a self) -> &'a (); | ^^ ^^ ^^ @@ -504,7 +385,7 @@ LL + fn implicit(&self) -> &(); | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:471:30 + --> tests/ui/needless_lifetimes.rs:401:30 | LL | fn implicit_provided<'a>(&'a self) -> &'a () { | ^^ ^^ ^^ @@ -516,7 +397,7 @@ LL + fn implicit_provided(&self) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:476:21 + --> tests/ui/needless_lifetimes.rs:407:21 | LL | fn explicit<'a>(self: &'a Arc) -> &'a (); | ^^ ^^ ^^ @@ -528,7 +409,7 @@ LL + fn explicit(self: &Arc) -> &(); | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:478:30 + --> tests/ui/needless_lifetimes.rs:410:30 | LL | fn explicit_provided<'a>(self: &'a Arc) -> &'a () { | ^^ ^^ ^^ @@ -540,7 +421,7 @@ LL + fn explicit_provided(self: &Arc) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:488:31 + --> tests/ui/needless_lifetimes.rs:421:31 | LL | fn lifetime_elsewhere<'a>(self: Box, here: &'a ()) -> &'a (); | ^^ ^^ ^^ @@ -552,7 +433,7 @@ LL + fn lifetime_elsewhere(self: Box, here: &()) -> &(); | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:489:40 + --> tests/ui/needless_lifetimes.rs:423:40 | LL | fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { | ^^ ^^ ^^ @@ -564,7 +445,7 @@ LL + fn lifetime_elsewhere_provided(self: Box, here: &()) -> &() { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:498:12 + --> tests/ui/needless_lifetimes.rs:433:12 | LL | fn foo<'a>(x: &'a u8, y: &'_ u8) {} | ^^ ^^ @@ -576,7 +457,7 @@ LL + fn foo(x: &u8, y: &'_ u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:500:12 + --> tests/ui/needless_lifetimes.rs:436:12 | LL | fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {} | ^^ ^^ @@ -588,7 +469,7 @@ LL + fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {} | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:507:18 + --> tests/ui/needless_lifetimes.rs:444:18 | LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { | ^^ ^^ ^^ @@ -600,7 +481,7 @@ LL + fn one_input(x: &u8) -> &u8 { | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:512:42 + --> tests/ui/needless_lifetimes.rs:450:42 | LL | fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 { | ^^ ^^ @@ -612,7 +493,7 @@ LL + fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) | error: the following explicit lifetimes could be elided: 'a - --> tests/ui/needless_lifetimes.rs:528:22 + --> tests/ui/needless_lifetimes.rs:467:22 | LL | fn one_input<'a>(x: &'a u8) -> &'a u8 { | ^^ ^^ ^^ @@ -624,64 +505,5 @@ LL - fn one_input<'a>(x: &'a u8) -> &'a u8 { LL + fn one_input(x: &u8) -> &u8 { | -error: the following explicit lifetimes could be elided: 'py - --> tests/ui/needless_lifetimes.rs:623:14 - | -LL | impl<'t, 'py> ContentString<'t> { - | ^^^ -LL | // `'py` can be elided because of `&self` -LL | fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { - | ^^^ - | -help: elide the lifetimes - | -LL ~ impl<'t> ContentString<'t> { -LL | // `'py` can be elided because of `&self` -LL ~ fn map_content2(&self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { - | - -error: the following explicit lifetimes could be elided: 'py - --> tests/ui/needless_lifetimes.rs:633:14 - | -LL | impl<'t, 'py> ContentString<'t> { - | ^^^ -LL | // `'py` can be elided because of `&'_ self` -LL | fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, 'py> { - | ^^^ - | -help: elide the lifetimes - | -LL ~ impl<'t> ContentString<'t> { -LL | // `'py` can be elided because of `&'_ self` -LL ~ fn map_content3(&'_ self, f: impl FnOnce(&'t str) -> &'t str) -> Content<'t, '_> { - | - -error: the following explicit lifetimes could be elided: 'py - --> tests/ui/needless_lifetimes.rs:653:14 - | -LL | impl<'t, 'py> ContentString<'t> { - | ^^^ -... -LL | ) -> Content<'t, 'py> { - | ^^^ - | -help: elide the lifetimes - | -LL ~ impl<'t> ContentString<'t> { -LL | // `'py` can be elided because of `&Self` -... -LL | o: &'t str, -LL ~ ) -> Content<'t, '_> { - | - -error: this expression creates a reference which is immediately dereferenced by the compiler - --> tests/ui/needless_lifetimes.rs:674:9 - | -LL | &x.b - | ^^^^ help: change this to: `x.b` - | - = note: `-D clippy::needless-borrow` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]` - -error: aborting due to 56 previous errors +error: aborting due to 42 previous errors diff --git a/src/tools/clippy/tests/ui/needless_match.fixed b/src/tools/clippy/tests/ui/needless_match.fixed index 06c6169d0da0b..b2c2bbfaa3613 100644 --- a/src/tools/clippy/tests/ui/needless_match.fixed +++ b/src/tools/clippy/tests/ui/needless_match.fixed @@ -61,6 +61,7 @@ fn result_match() { fn if_let_option() { let _ = Some(1); + //~^ needless_match fn do_something() {} @@ -96,7 +97,9 @@ fn if_let_option_result() -> Result<(), ()> { fn if_let_result() { let x: Result = Ok(1); let _: Result = x; + //~^ needless_match let _: Result = x; + //~^ needless_match // Input type mismatch, don't trigger #[allow(clippy::question_mark)] let _: Result = if let Err(e) = Ok(1) { Err(e) } else { x }; diff --git a/src/tools/clippy/tests/ui/needless_match.rs b/src/tools/clippy/tests/ui/needless_match.rs index 6b71de68e1be7..1cb670edc60fb 100644 --- a/src/tools/clippy/tests/ui/needless_match.rs +++ b/src/tools/clippy/tests/ui/needless_match.rs @@ -13,6 +13,7 @@ enum Simple { fn useless_match() { let i = 10; let _: i32 = match i { + //~^ needless_match 0 => 0, 1 => 1, 2 => 2, @@ -20,6 +21,7 @@ fn useless_match() { }; let s = "test"; let _: &str = match s { + //~^ needless_match "a" => "a", "b" => "b", s => s, @@ -29,6 +31,7 @@ fn useless_match() { fn custom_type_match() { let se = Simple::A; let _: Simple = match se { + //~^ needless_match Simple::A => Simple::A, Simple::B => Simple::B, Simple::C => Simple::C, @@ -51,6 +54,7 @@ fn custom_type_match() { fn option_match(x: Option) { let _: Option = match x { + //~^ needless_match Some(a) => Some(a), None => None, }; @@ -67,10 +71,12 @@ fn func_ret_err(err: T) -> Result { fn result_match() { let _: Result = match Ok(1) { + //~^ needless_match Ok(a) => Ok(a), Err(err) => Err(err), }; let _: Result = match func_ret_err(0_i32) { + //~^ needless_match Err(err) => Err(err), Ok(a) => Ok(a), }; @@ -84,6 +90,7 @@ fn result_match() { fn if_let_option() { let _ = if let Some(a) = Some(1) { Some(a) } else { None }; + //~^ needless_match fn do_something() {} @@ -119,7 +126,9 @@ fn if_let_option_result() -> Result<(), ()> { fn if_let_result() { let x: Result = Ok(1); let _: Result = if let Err(e) = x { Err(e) } else { x }; + //~^ needless_match let _: Result = if let Ok(val) = x { Ok(val) } else { x }; + //~^ needless_match // Input type mismatch, don't trigger #[allow(clippy::question_mark)] let _: Result = if let Err(e) = Ok(1) { Err(e) } else { x }; @@ -127,6 +136,7 @@ fn if_let_result() { fn if_let_custom_enum(x: Simple) { let _: Simple = if let Simple::A = x { + //~^ needless_match Simple::A } else if let Simple::B = x { Simple::B @@ -166,6 +176,7 @@ mod issue8542 { let bb = false; let _: Complex = match ce { + //~^ needless_match Complex::A(a) => Complex::A(a), Complex::B(a, b) => Complex::B(a, b), Complex::C(a, b, c) => Complex::C(a, b, c), @@ -250,12 +261,14 @@ mod issue9084 { // should lint let _ = match e { + //~^ needless_match _ if some_bool => e, _ => e, }; // should lint let _ = match e { + //~^ needless_match Some(i) => Some(i), _ if some_bool => e, _ => e, @@ -337,6 +350,7 @@ pub fn issue13574() -> Option<()> { // Same const, should lint let _ = { if let Some(num) = A { + //~^ needless_match Some(num) } else if let Some(num) = A { Some(num) diff --git a/src/tools/clippy/tests/ui/needless_match.stderr b/src/tools/clippy/tests/ui/needless_match.stderr index 1410585cb2e3e..719b0ef884696 100644 --- a/src/tools/clippy/tests/ui/needless_match.stderr +++ b/src/tools/clippy/tests/ui/needless_match.stderr @@ -3,6 +3,7 @@ error: this match expression is unnecessary | LL | let _: i32 = match i { | __________________^ +LL | | LL | | 0 => 0, LL | | 1 => 1, LL | | 2 => 2, @@ -14,10 +15,11 @@ LL | | }; = help: to override `-D warnings` add `#[allow(clippy::needless_match)]` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:22:19 + --> tests/ui/needless_match.rs:23:19 | LL | let _: &str = match s { | ___________________^ +LL | | LL | | "a" => "a", LL | | "b" => "b", LL | | s => s, @@ -25,10 +27,11 @@ LL | | }; | |_____^ help: replace it with: `s` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:31:21 + --> tests/ui/needless_match.rs:33:21 | LL | let _: Simple = match se { | _____________________^ +LL | | LL | | Simple::A => Simple::A, LL | | Simple::B => Simple::B, LL | | Simple::C => Simple::C, @@ -37,94 +40,99 @@ LL | | }; | |_____^ help: replace it with: `se` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:53:26 + --> tests/ui/needless_match.rs:56:26 | LL | let _: Option = match x { | __________________________^ +LL | | LL | | Some(a) => Some(a), LL | | None => None, LL | | }; | |_____^ help: replace it with: `x` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:69:31 + --> tests/ui/needless_match.rs:73:31 | LL | let _: Result = match Ok(1) { | _______________________________^ +LL | | LL | | Ok(a) => Ok(a), LL | | Err(err) => Err(err), LL | | }; | |_____^ help: replace it with: `Ok(1)` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:73:31 + --> tests/ui/needless_match.rs:78:31 | LL | let _: Result = match func_ret_err(0_i32) { | _______________________________^ +LL | | LL | | Err(err) => Err(err), LL | | Ok(a) => Ok(a), LL | | }; | |_____^ help: replace it with: `func_ret_err(0_i32)` error: this if-let expression is unnecessary - --> tests/ui/needless_match.rs:86:13 + --> tests/ui/needless_match.rs:92:13 | LL | let _ = if let Some(a) = Some(1) { Some(a) } else { None }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `Some(1)` error: this if-let expression is unnecessary - --> tests/ui/needless_match.rs:121:31 + --> tests/ui/needless_match.rs:128:31 | LL | let _: Result = if let Err(e) = x { Err(e) } else { x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x` error: this if-let expression is unnecessary - --> tests/ui/needless_match.rs:122:31 + --> tests/ui/needless_match.rs:130:31 | LL | let _: Result = if let Ok(val) = x { Ok(val) } else { x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x` error: this if-let expression is unnecessary - --> tests/ui/needless_match.rs:129:21 + --> tests/ui/needless_match.rs:138:21 | LL | let _: Simple = if let Simple::A = x { | _____________________^ +LL | | LL | | Simple::A LL | | } else if let Simple::B = x { -LL | | Simple::B ... | LL | | x LL | | }; | |_____^ help: replace it with: `x` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:168:26 + --> tests/ui/needless_match.rs:178:26 | LL | let _: Complex = match ce { | __________________________^ +LL | | LL | | Complex::A(a) => Complex::A(a), LL | | Complex::B(a, b) => Complex::B(a, b), -LL | | Complex::C(a, b, c) => Complex::C(a, b, c), -LL | | Complex::D(E::VariantA(ea, eb), b) => Complex::D(E::VariantA(ea, eb), b), +... | LL | | Complex::D(E::VariantB(ea, eb), b) => Complex::D(E::VariantB(ea, eb), b), LL | | }; | |_________^ help: replace it with: `ce` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:252:17 + --> tests/ui/needless_match.rs:263:17 | LL | let _ = match e { | _________________^ +LL | | LL | | _ if some_bool => e, LL | | _ => e, LL | | }; | |_________^ help: replace it with: `e` error: this match expression is unnecessary - --> tests/ui/needless_match.rs:258:17 + --> tests/ui/needless_match.rs:270:17 | LL | let _ = match e { | _________________^ +LL | | LL | | Some(i) => Some(i), LL | | _ if some_bool => e, LL | | _ => e, @@ -132,12 +140,12 @@ LL | | }; | |_________^ help: replace it with: `e` error: this if-let expression is unnecessary - --> tests/ui/needless_match.rs:339:9 + --> tests/ui/needless_match.rs:352:9 | LL | / if let Some(num) = A { +LL | | LL | | Some(num) LL | | } else if let Some(num) = A { -LL | | Some(num) ... | LL | | None LL | | } diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.fixed b/src/tools/clippy/tests/ui/needless_maybe_sized.fixed index 4d24a7cee619b..f8b1643969903 100644 --- a/src/tools/clippy/tests/ui/needless_maybe_sized.fixed +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.fixed @@ -7,27 +7,34 @@ extern crate proc_macros; use proc_macros::external; fn directly(t: &T) {} +//~^ needless_maybe_sized trait A: Sized {} trait B: A {} fn depth_1(t: &T) {} +//~^ needless_maybe_sized fn depth_2(t: &T) {} +//~^ needless_maybe_sized // We only need to show one fn multiple_paths(t: &T) {} +//~^ needless_maybe_sized fn in_where(t: &T) where T: Sized, + //~^ needless_maybe_sized { } fn mixed_1(t: &T) + //~^ needless_maybe_sized { } fn mixed_2(t: &T) +//~^ needless_maybe_sized where T: Sized, { @@ -36,38 +43,50 @@ where fn mixed_3(t: &T) where T: Sized, + //~^ needless_maybe_sized { } struct Struct(T); +//~^ needless_maybe_sized impl Struct { + //~^ needless_maybe_sized fn method(&self) {} + //~^ needless_maybe_sized } enum Enum { + //~^ needless_maybe_sized Variant(&'static T), } union Union<'a, T: Sized> { + //~^ needless_maybe_sized a: &'a T, } trait Trait { + //~^ needless_maybe_sized fn trait_method() {} + //~^ needless_maybe_sized type GAT; + //~^ needless_maybe_sized type Assoc: Sized + ?Sized; // False negative } trait SecondInTrait: Send + Sized {} fn second_in_trait() {} +//~^ needless_maybe_sized fn impl_trait(_: &(impl Sized)) {} +//~^ needless_maybe_sized trait GenericTrait: Sized {} fn in_generic_trait, U>() {} +//~^ needless_maybe_sized mod larger_graph { // C1 C2 Sized @@ -83,6 +102,7 @@ mod larger_graph { trait A1: B1 + B2 {} fn larger_graph() {} + //~^ needless_maybe_sized } // Should not lint diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.rs b/src/tools/clippy/tests/ui/needless_maybe_sized.rs index ef66f9a4f2aec..e4312b40563f1 100644 --- a/src/tools/clippy/tests/ui/needless_maybe_sized.rs +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.rs @@ -7,29 +7,36 @@ extern crate proc_macros; use proc_macros::external; fn directly(t: &T) {} +//~^ needless_maybe_sized trait A: Sized {} trait B: A {} fn depth_1(t: &T) {} +//~^ needless_maybe_sized fn depth_2(t: &T) {} +//~^ needless_maybe_sized // We only need to show one fn multiple_paths(t: &T) {} +//~^ needless_maybe_sized fn in_where(t: &T) where T: Sized + ?Sized, + //~^ needless_maybe_sized { } fn mixed_1(t: &T) where T: ?Sized, + //~^ needless_maybe_sized { } fn mixed_2(t: &T) +//~^ needless_maybe_sized where T: Sized, { @@ -39,38 +46,50 @@ fn mixed_3(t: &T) where T: Sized, T: ?Sized, + //~^ needless_maybe_sized { } struct Struct(T); +//~^ needless_maybe_sized impl Struct { + //~^ needless_maybe_sized fn method(&self) {} + //~^ needless_maybe_sized } enum Enum { + //~^ needless_maybe_sized Variant(&'static T), } union Union<'a, T: Sized + ?Sized> { + //~^ needless_maybe_sized a: &'a T, } trait Trait { + //~^ needless_maybe_sized fn trait_method() {} + //~^ needless_maybe_sized type GAT; + //~^ needless_maybe_sized type Assoc: Sized + ?Sized; // False negative } trait SecondInTrait: Send + Sized {} fn second_in_trait() {} +//~^ needless_maybe_sized fn impl_trait(_: &(impl Sized + ?Sized)) {} +//~^ needless_maybe_sized trait GenericTrait: Sized {} fn in_generic_trait + ?Sized, U>() {} +//~^ needless_maybe_sized mod larger_graph { // C1 C2 Sized @@ -86,6 +105,7 @@ mod larger_graph { trait A1: B1 + B2 {} fn larger_graph() {} + //~^ needless_maybe_sized } // Should not lint diff --git a/src/tools/clippy/tests/ui/needless_maybe_sized.stderr b/src/tools/clippy/tests/ui/needless_maybe_sized.stderr index 3b1d2b49b0622..30dcaa48e4292 100644 --- a/src/tools/clippy/tests/ui/needless_maybe_sized.stderr +++ b/src/tools/clippy/tests/ui/needless_maybe_sized.stderr @@ -18,13 +18,13 @@ LL + fn directly(t: &T) {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:14:19 + --> tests/ui/needless_maybe_sized.rs:15:19 | LL | fn depth_1(t: &T) {} | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:14:15 + --> tests/ui/needless_maybe_sized.rs:15:15 | LL | fn depth_1(t: &T) {} | ^ @@ -36,13 +36,13 @@ LL + fn depth_1(t: &T) {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:15:19 + --> tests/ui/needless_maybe_sized.rs:17:19 | LL | fn depth_2(t: &T) {} | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:15:15 + --> tests/ui/needless_maybe_sized.rs:17:15 | LL | fn depth_2(t: &T) {} | ^ @@ -55,13 +55,13 @@ LL + fn depth_2(t: &T) {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:18:30 + --> tests/ui/needless_maybe_sized.rs:21:30 | LL | fn multiple_paths(t: &T) {} | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:18:22 + --> tests/ui/needless_maybe_sized.rs:21:22 | LL | fn multiple_paths(t: &T) {} | ^ @@ -73,13 +73,13 @@ LL + fn multiple_paths(t: &T) {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:22:16 + --> tests/ui/needless_maybe_sized.rs:26:16 | LL | T: Sized + ?Sized, | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:22:8 + --> tests/ui/needless_maybe_sized.rs:26:8 | LL | T: Sized + ?Sized, | ^^^^^ @@ -90,13 +90,13 @@ LL + T: Sized, | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:28:8 + --> tests/ui/needless_maybe_sized.rs:33:8 | LL | T: ?Sized, | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:26:15 + --> tests/ui/needless_maybe_sized.rs:31:15 | LL | fn mixed_1(t: &T) | ^^^^^ @@ -107,13 +107,13 @@ LL - T: ?Sized, | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:32:15 + --> tests/ui/needless_maybe_sized.rs:38:15 | LL | fn mixed_2(t: &T) | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:34:8 + --> tests/ui/needless_maybe_sized.rs:41:8 | LL | T: Sized, | ^^^^^ @@ -124,13 +124,13 @@ LL + fn mixed_2(t: &T) | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:41:8 + --> tests/ui/needless_maybe_sized.rs:48:8 | LL | T: ?Sized, | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:40:8 + --> tests/ui/needless_maybe_sized.rs:47:8 | LL | T: Sized, | ^^^^^ @@ -142,13 +142,13 @@ LL + T: Sized, | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:45:26 + --> tests/ui/needless_maybe_sized.rs:53:26 | LL | struct Struct(T); | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:45:18 + --> tests/ui/needless_maybe_sized.rs:53:18 | LL | struct Struct(T); | ^^^^^ @@ -159,13 +159,13 @@ LL + struct Struct(T); | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:47:17 + --> tests/ui/needless_maybe_sized.rs:56:17 | LL | impl Struct { | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:47:9 + --> tests/ui/needless_maybe_sized.rs:56:9 | LL | impl Struct { | ^^^^^ @@ -176,13 +176,13 @@ LL + impl Struct { | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:48:26 + --> tests/ui/needless_maybe_sized.rs:58:26 | LL | fn method(&self) {} | ^^^^^^ | note: `U` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:48:18 + --> tests/ui/needless_maybe_sized.rs:58:18 | LL | fn method(&self) {} | ^^^^^ @@ -193,13 +193,13 @@ LL + fn method(&self) {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:51:22 + --> tests/ui/needless_maybe_sized.rs:62:22 | LL | enum Enum { | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:51:14 + --> tests/ui/needless_maybe_sized.rs:62:14 | LL | enum Enum { | ^^^^^ @@ -210,13 +210,13 @@ LL + enum Enum { | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:55:28 + --> tests/ui/needless_maybe_sized.rs:67:28 | LL | union Union<'a, T: Sized + ?Sized> { | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:55:20 + --> tests/ui/needless_maybe_sized.rs:67:20 | LL | union Union<'a, T: Sized + ?Sized> { | ^^^^^ @@ -227,13 +227,13 @@ LL + union Union<'a, T: Sized> { | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:59:24 + --> tests/ui/needless_maybe_sized.rs:72:24 | LL | trait Trait { | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:59:16 + --> tests/ui/needless_maybe_sized.rs:72:16 | LL | trait Trait { | ^^^^^ @@ -244,13 +244,13 @@ LL + trait Trait { | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:60:32 + --> tests/ui/needless_maybe_sized.rs:74:32 | LL | fn trait_method() {} | ^^^^^^ | note: `U` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:60:24 + --> tests/ui/needless_maybe_sized.rs:74:24 | LL | fn trait_method() {} | ^^^^^ @@ -261,13 +261,13 @@ LL + fn trait_method() {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:62:25 + --> tests/ui/needless_maybe_sized.rs:77:25 | LL | type GAT; | ^^^^^^ | note: `U` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:62:17 + --> tests/ui/needless_maybe_sized.rs:77:17 | LL | type GAT; | ^^^^^ @@ -278,13 +278,13 @@ LL + type GAT; | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:68:23 + --> tests/ui/needless_maybe_sized.rs:84:23 | LL | fn second_in_trait() {} | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:68:32 + --> tests/ui/needless_maybe_sized.rs:84:32 | LL | fn second_in_trait() {} | ^^^^^^^^^^^^^ @@ -296,13 +296,13 @@ LL + fn second_in_trait() {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:70:33 + --> tests/ui/needless_maybe_sized.rs:87:33 | LL | fn impl_trait(_: &(impl Sized + ?Sized)) {} | ^^^^^^ | note: `impl Sized + ?Sized` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:70:25 + --> tests/ui/needless_maybe_sized.rs:87:25 | LL | fn impl_trait(_: &(impl Sized + ?Sized)) {} | ^^^^^ @@ -313,13 +313,13 @@ LL + fn impl_trait(_: &(impl Sized)) {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:73:42 + --> tests/ui/needless_maybe_sized.rs:91:42 | LL | fn in_generic_trait + ?Sized, U>() {} | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:73:24 + --> tests/ui/needless_maybe_sized.rs:91:24 | LL | fn in_generic_trait + ?Sized, U>() {} | ^^^^^^^^^^^^^^^ @@ -331,13 +331,13 @@ LL + fn in_generic_trait, U>() {} | error: `?Sized` bound is ignored because of a `Sized` requirement - --> tests/ui/needless_maybe_sized.rs:88:29 + --> tests/ui/needless_maybe_sized.rs:107:29 | LL | fn larger_graph() {} | ^^^^^^ | note: `T` cannot be unsized because of the bound - --> tests/ui/needless_maybe_sized.rs:88:24 + --> tests/ui/needless_maybe_sized.rs:107:24 | LL | fn larger_graph() {} | ^^ diff --git a/src/tools/clippy/tests/ui/needless_option_as_deref.fixed b/src/tools/clippy/tests/ui/needless_option_as_deref.fixed index 84eaf12fc1398..fd639f3b57fa7 100644 --- a/src/tools/clippy/tests/ui/needless_option_as_deref.fixed +++ b/src/tools/clippy/tests/ui/needless_option_as_deref.fixed @@ -5,11 +5,14 @@ fn main() { // should lint let _: Option<&usize> = Some(&1); + //~^ needless_option_as_deref let _: Option<&mut usize> = Some(&mut 1); + //~^ needless_option_as_deref let mut y = 0; let mut x = Some(&mut y); let _ = x; + //~^ needless_option_as_deref // should not lint let _ = Some(Box::new(1)).as_deref(); @@ -70,3 +73,16 @@ mod issue_non_copy_13077 { pub field: (), } } + +mod issue14148 { + pub trait SomeTrait { + fn something(&self, mut maybe_side_effect: Option<&mut String>) { + other(maybe_side_effect.as_deref_mut()); + other(maybe_side_effect); + } + } + + fn other(_maybe_side_effect: Option<&mut String>) { + unimplemented!() + } +} diff --git a/src/tools/clippy/tests/ui/needless_option_as_deref.rs b/src/tools/clippy/tests/ui/needless_option_as_deref.rs index fff1e45d846fb..cbf7935794b31 100644 --- a/src/tools/clippy/tests/ui/needless_option_as_deref.rs +++ b/src/tools/clippy/tests/ui/needless_option_as_deref.rs @@ -5,11 +5,14 @@ fn main() { // should lint let _: Option<&usize> = Some(&1).as_deref(); + //~^ needless_option_as_deref let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); + //~^ needless_option_as_deref let mut y = 0; let mut x = Some(&mut y); let _ = x.as_deref_mut(); + //~^ needless_option_as_deref // should not lint let _ = Some(Box::new(1)).as_deref(); @@ -70,3 +73,16 @@ mod issue_non_copy_13077 { pub field: (), } } + +mod issue14148 { + pub trait SomeTrait { + fn something(&self, mut maybe_side_effect: Option<&mut String>) { + other(maybe_side_effect.as_deref_mut()); + other(maybe_side_effect); + } + } + + fn other(_maybe_side_effect: Option<&mut String>) { + unimplemented!() + } +} diff --git a/src/tools/clippy/tests/ui/needless_option_as_deref.stderr b/src/tools/clippy/tests/ui/needless_option_as_deref.stderr index a05d0aa9276ac..bd19dc75eed60 100644 --- a/src/tools/clippy/tests/ui/needless_option_as_deref.stderr +++ b/src/tools/clippy/tests/ui/needless_option_as_deref.stderr @@ -8,13 +8,13 @@ LL | let _: Option<&usize> = Some(&1).as_deref(); = help: to override `-D warnings` add `#[allow(clippy::needless_option_as_deref)]` error: derefed type is same as origin - --> tests/ui/needless_option_as_deref.rs:8:33 + --> tests/ui/needless_option_as_deref.rs:9:33 | LL | let _: Option<&mut usize> = Some(&mut 1).as_deref_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(&mut 1)` error: derefed type is same as origin - --> tests/ui/needless_option_as_deref.rs:12:13 + --> tests/ui/needless_option_as_deref.rs:14:13 | LL | let _ = x.as_deref_mut(); | ^^^^^^^^^^^^^^^^ help: try: `x` diff --git a/src/tools/clippy/tests/ui/needless_option_take.fixed b/src/tools/clippy/tests/ui/needless_option_take.fixed index 6514b67ef7a71..a8bd50b79899b 100644 --- a/src/tools/clippy/tests/ui/needless_option_take.fixed +++ b/src/tools/clippy/tests/ui/needless_option_take.fixed @@ -21,7 +21,7 @@ fn main() { let x = Some(3); x.as_ref(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take println!("Testing non erroneous option_take_on_temporary"); let mut x = Some(3); @@ -29,30 +29,31 @@ fn main() { let mut x = Some(3); let y = x.as_mut(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take + let y = x.replace(289); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let y = Some(3).as_mut(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let y = Option::as_mut(&mut x); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let x = return_option(); let x = return_option(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let x = MyStruct::get_option(); let x = MyStruct::get_option(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let mut my_vec = vec![1, 2, 3]; my_vec.push(4); let y = my_vec.first(); let y = my_vec.first(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let y = my_vec.first(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take } diff --git a/src/tools/clippy/tests/ui/needless_option_take.rs b/src/tools/clippy/tests/ui/needless_option_take.rs index c6807718a758e..8141ee43db11f 100644 --- a/src/tools/clippy/tests/ui/needless_option_take.rs +++ b/src/tools/clippy/tests/ui/needless_option_take.rs @@ -21,7 +21,7 @@ fn main() { let x = Some(3); x.as_ref().take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take println!("Testing non erroneous option_take_on_temporary"); let mut x = Some(3); @@ -29,30 +29,31 @@ fn main() { let mut x = Some(3); let y = x.as_mut().take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take + let y = x.replace(289).take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let y = Some(3).as_mut().take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let y = Option::as_mut(&mut x).take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let x = return_option(); let x = return_option().take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let x = MyStruct::get_option(); let x = MyStruct::get_option().take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let mut my_vec = vec![1, 2, 3]; my_vec.push(4); let y = my_vec.first(); let y = my_vec.first().take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take let y = my_vec.first().take(); - //~^ ERROR: called `Option::take()` on a temporary value + //~^ needless_option_take } diff --git a/src/tools/clippy/tests/ui/needless_option_take.stderr b/src/tools/clippy/tests/ui/needless_option_take.stderr index 3fc339ed79e2a..9054463c07cd2 100644 --- a/src/tools/clippy/tests/ui/needless_option_take.stderr +++ b/src/tools/clippy/tests/ui/needless_option_take.stderr @@ -21,7 +21,7 @@ LL | let y = x.as_mut().take(); = note: `as_mut` creates a temporary value, so calling take() has no effect error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:33:13 + --> tests/ui/needless_option_take.rs:34:13 | LL | let y = x.replace(289).take(); | ^^^^^^^^^^^^^^------- @@ -31,7 +31,7 @@ LL | let y = x.replace(289).take(); = note: `replace` creates a temporary value, so calling take() has no effect error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:36:13 + --> tests/ui/needless_option_take.rs:37:13 | LL | let y = Some(3).as_mut().take(); | ^^^^^^^^^^^^^^^^------- @@ -41,7 +41,7 @@ LL | let y = Some(3).as_mut().take(); = note: `as_mut` creates a temporary value, so calling take() has no effect error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:39:13 + --> tests/ui/needless_option_take.rs:40:13 | LL | let y = Option::as_mut(&mut x).take(); | ^^^^^^^^^^^^^^^^^^^^^^------- @@ -51,7 +51,7 @@ LL | let y = Option::as_mut(&mut x).take(); = note: `as_mut` creates a temporary value, so calling take() has no effect error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:43:13 + --> tests/ui/needless_option_take.rs:44:13 | LL | let x = return_option().take(); | ^^^^^^^^^^^^^^^------- @@ -61,7 +61,7 @@ LL | let x = return_option().take(); = note: `return_option` creates a temporary value, so calling take() has no effect error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:47:13 + --> tests/ui/needless_option_take.rs:48:13 | LL | let x = MyStruct::get_option().take(); | ^^^^^^^^^^^^^^^^^^^^^^------- @@ -71,7 +71,7 @@ LL | let x = MyStruct::get_option().take(); = note: `get_option` creates a temporary value, so calling take() has no effect error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:53:13 + --> tests/ui/needless_option_take.rs:54:13 | LL | let y = my_vec.first().take(); | ^^^^^^^^^^^^^^------- @@ -81,7 +81,7 @@ LL | let y = my_vec.first().take(); = note: `first` creates a temporary value, so calling take() has no effect error: called `Option::take()` on a temporary value - --> tests/ui/needless_option_take.rs:56:13 + --> tests/ui/needless_option_take.rs:57:13 | LL | let y = my_vec.first().take(); | ^^^^^^^^^^^^^^------- diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed index b4d9e3297c491..7abcbc0c6e32c 100644 --- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed +++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed @@ -5,9 +5,15 @@ fn main() { let _ = 'a'..='z'; + //~^ needless_parens_on_range_literals + //~| needless_parens_on_range_literals let _ = 'a'..'z'; + //~^ needless_parens_on_range_literals let _ = (1.)..2.; let _ = (1.)..2.; + //~^ needless_parens_on_range_literals let _ = 'a'..; + //~^ needless_parens_on_range_literals let _ = ..'z'; + //~^ needless_parens_on_range_literals } diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs index 2f0e54f80d85a..2a6f9305883bd 100644 --- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs +++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs @@ -5,9 +5,15 @@ fn main() { let _ = ('a')..=('z'); + //~^ needless_parens_on_range_literals + //~| needless_parens_on_range_literals let _ = 'a'..('z'); + //~^ needless_parens_on_range_literals let _ = (1.)..2.; let _ = (1.)..(2.); + //~^ needless_parens_on_range_literals let _ = ('a')..; + //~^ needless_parens_on_range_literals let _ = ..('z'); + //~^ needless_parens_on_range_literals } diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr index d293ecce69fbd..082b2cd8cade4 100644 --- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr +++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.stderr @@ -14,25 +14,25 @@ LL | let _ = ('a')..=('z'); | ^^^^^ help: try: `'z'` error: needless parenthesis on range literals can be removed - --> tests/ui/needless_parens_on_range_literals.rs:8:18 + --> tests/ui/needless_parens_on_range_literals.rs:10:18 | LL | let _ = 'a'..('z'); | ^^^^^ help: try: `'z'` error: needless parenthesis on range literals can be removed - --> tests/ui/needless_parens_on_range_literals.rs:10:19 + --> tests/ui/needless_parens_on_range_literals.rs:13:19 | LL | let _ = (1.)..(2.); | ^^^^ help: try: `2.` error: needless parenthesis on range literals can be removed - --> tests/ui/needless_parens_on_range_literals.rs:11:13 + --> tests/ui/needless_parens_on_range_literals.rs:15:13 | LL | let _ = ('a')..; | ^^^^^ help: try: `'a'` error: needless parenthesis on range literals can be removed - --> tests/ui/needless_parens_on_range_literals.rs:12:15 + --> tests/ui/needless_parens_on_range_literals.rs:17:15 | LL | let _ = ..('z'); | ^^^^^ help: try: `'z'` diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs index 162ec82aeded2..f0c5a716ac991 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs @@ -9,7 +9,8 @@ use std::ptr::NonNull; fn foo(s: &mut Vec, b: &u32, x: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + *x += *b + s.len() as u32; } @@ -34,7 +35,8 @@ fn foo5(s: &mut Vec) { } fn foo6(s: &mut Vec) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + non_mut_ref(s); } @@ -44,10 +46,11 @@ struct Bar; impl Bar { fn bar(&mut self) {} - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut fn mushroom(&self, vec: &mut Vec) -> usize { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + vec.len() } } @@ -124,35 +127,44 @@ async fn f7(x: &mut i32, y: i32, z: &mut i32, a: i32) { } async fn a1(x: &mut i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + println!("{:?}", x); } async fn a2(x: &mut i32, y: String) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + println!("{:?}", x); } async fn a3(x: &mut i32, y: String, z: String) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + println!("{:?}", x); } async fn a4(x: &mut i32, y: i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + println!("{:?}", x); } async fn a5(x: i32, y: &mut i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + println!("{:?}", x); } async fn a6(x: i32, y: &mut i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + println!("{:?}", x); } async fn a7(x: i32, y: i32, z: &mut i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + println!("{:?}", z); } async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + //~| needless_pass_by_ref_mut + println!("{:?}", z); } @@ -186,14 +198,12 @@ fn lint_attr(s: &mut u32) {} #[cfg(not(feature = "a"))] fn cfg_warn(s: &mut u32) {} -//~^ ERROR: this argument is a mutable reference, but not used mutably -//~| NOTE: this is cfg-gated and may require further changes +//~^ needless_pass_by_ref_mut #[cfg(not(feature = "a"))] mod foo { fn cfg_warn(s: &mut u32) {} - //~^ ERROR: this argument is a mutable reference, but not used mutably - //~| NOTE: this is cfg-gated and may require further changes + //~^ needless_pass_by_ref_mut } // Should not warn. @@ -206,7 +216,8 @@ async fn inner_async(x: &mut i32, y: &mut u32) { } async fn inner_async2(x: &mut i32, y: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async { *x += 1; } @@ -214,7 +225,8 @@ async fn inner_async2(x: &mut i32, y: &mut u32) { } async fn inner_async3(x: &mut i32, y: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async { *y += 1; } @@ -233,6 +245,7 @@ async fn async_vec2(b: &mut Vec) { fn non_mut(n: &str) {} //Should warn async fn call_in_closure1(n: &mut str) { + //~^ needless_pass_by_ref_mut (|| non_mut(n))() } fn str_mut(str: &mut String) -> bool { @@ -252,7 +265,8 @@ async fn closure(n: &mut usize) -> impl '_ + FnMut() { // Should warn. fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + || *n + 1 } @@ -263,7 +277,8 @@ async fn closure3(n: &mut usize) { // Should warn. async fn closure4(n: &mut usize) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + (|| { let _x = *n + 1; })(); @@ -317,17 +332,20 @@ struct MutSelf { impl MutSelf { fn bar(&mut self) {} - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async fn foo(&mut self, u: &mut i32, v: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably - //~| ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + //~| needless_pass_by_ref_mut + async { *u += 1; } .await; } async fn foo2(&mut self, u: &mut i32, v: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async { self.a += 1; *u += 1; @@ -343,16 +361,26 @@ impl MutSelfTrait for MutSelf { // `is_from_proc_macro` stress tests fn _empty_tup(x: &mut (())) {} +//~^ needless_pass_by_ref_mut fn _single_tup(x: &mut ((i32,))) {} +//~^ needless_pass_by_ref_mut fn _multi_tup(x: &mut ((i32, u32))) {} +//~^ needless_pass_by_ref_mut fn _fn(x: &mut (fn())) {} +//~^ needless_pass_by_ref_mut #[rustfmt::skip] fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} +//~^ needless_pass_by_ref_mut fn _extern_c_fn(x: &mut extern "C" fn()) {} +//~^ needless_pass_by_ref_mut fn _unsafe_fn(x: &mut unsafe fn()) {} +//~^ needless_pass_by_ref_mut fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} +//~^ needless_pass_by_ref_mut fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} +//~^ needless_pass_by_ref_mut fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} +//~^ needless_pass_by_ref_mut fn main() { let mut u = 0; diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr index f462fa9099ed6..6637a255b5f51 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr @@ -8,79 +8,79 @@ LL | fn foo(s: &mut Vec, b: &u32, x: &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:36:12 + --> tests/ui/needless_pass_by_ref_mut.rs:37:12 | LL | fn foo6(s: &mut Vec) { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:46:12 + --> tests/ui/needless_pass_by_ref_mut.rs:48:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:49:29 + --> tests/ui/needless_pass_by_ref_mut.rs:51:29 | LL | fn mushroom(&self, vec: &mut Vec) -> usize { | ^^^^^^^^^^^^^ help: consider changing to: `&Vec` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:126:16 + --> tests/ui/needless_pass_by_ref_mut.rs:129:16 | LL | async fn a1(x: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:130:16 + --> tests/ui/needless_pass_by_ref_mut.rs:134:16 | LL | async fn a2(x: &mut i32, y: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:134:16 + --> tests/ui/needless_pass_by_ref_mut.rs:139:16 | LL | async fn a3(x: &mut i32, y: String, z: String) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:138:16 + --> tests/ui/needless_pass_by_ref_mut.rs:144:16 | LL | async fn a4(x: &mut i32, y: i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:142:24 + --> tests/ui/needless_pass_by_ref_mut.rs:149:24 | LL | async fn a5(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:146:24 + --> tests/ui/needless_pass_by_ref_mut.rs:154:24 | LL | async fn a6(x: i32, y: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:150:32 + --> tests/ui/needless_pass_by_ref_mut.rs:159:32 | LL | async fn a7(x: i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:154:24 + --> tests/ui/needless_pass_by_ref_mut.rs:164:24 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:154:45 + --> tests/ui/needless_pass_by_ref_mut.rs:164:45 | LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:188:16 + --> tests/ui/needless_pass_by_ref_mut.rs:200:16 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -88,7 +88,7 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:194:20 + --> tests/ui/needless_pass_by_ref_mut.rs:205:20 | LL | fn cfg_warn(s: &mut u32) {} | ^^^^^^^^ help: consider changing to: `&u32` @@ -96,115 +96,115 @@ LL | fn cfg_warn(s: &mut u32) {} = note: this is cfg-gated and may require further changes error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:208:39 + --> tests/ui/needless_pass_by_ref_mut.rs:218:39 | LL | async fn inner_async2(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:216:26 + --> tests/ui/needless_pass_by_ref_mut.rs:227:26 | LL | async fn inner_async3(x: &mut i32, y: &mut u32) { | ^^^^^^^^ help: consider changing to: `&i32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:235:30 + --> tests/ui/needless_pass_by_ref_mut.rs:247:30 | LL | async fn call_in_closure1(n: &mut str) { | ^^^^^^^^ help: consider changing to: `&str` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:254:16 + --> tests/ui/needless_pass_by_ref_mut.rs:267:16 | LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize { | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:265:22 + --> tests/ui/needless_pass_by_ref_mut.rs:279:22 | LL | async fn closure4(n: &mut usize) { | ^^^^^^^^^^ help: consider changing to: `&usize` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:319:12 + --> tests/ui/needless_pass_by_ref_mut.rs:334:12 | LL | fn bar(&mut self) {} | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:321:18 + --> tests/ui/needless_pass_by_ref_mut.rs:337:18 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^^ help: consider changing to: `&self` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:321:45 + --> tests/ui/needless_pass_by_ref_mut.rs:337:45 | LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:329:46 + --> tests/ui/needless_pass_by_ref_mut.rs:346:46 | LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:345:18 + --> tests/ui/needless_pass_by_ref_mut.rs:363:18 | LL | fn _empty_tup(x: &mut (())) {} | ^^^^^^^^^ help: consider changing to: `&()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:346:19 + --> tests/ui/needless_pass_by_ref_mut.rs:365:19 | LL | fn _single_tup(x: &mut ((i32,))) {} | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:347:18 + --> tests/ui/needless_pass_by_ref_mut.rs:367:18 | LL | fn _multi_tup(x: &mut ((i32, u32))) {} | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:348:11 + --> tests/ui/needless_pass_by_ref_mut.rs:369:11 | LL | fn _fn(x: &mut (fn())) {} | ^^^^^^^^^^^ help: consider changing to: `&fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:350:23 + --> tests/ui/needless_pass_by_ref_mut.rs:372:23 | LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:351:20 + --> tests/ui/needless_pass_by_ref_mut.rs:374:20 | LL | fn _extern_c_fn(x: &mut extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:352:18 + --> tests/ui/needless_pass_by_ref_mut.rs:376:18 | LL | fn _unsafe_fn(x: &mut unsafe fn()) {} | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:353:25 + --> tests/ui/needless_pass_by_ref_mut.rs:378:25 | LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:354:20 + --> tests/ui/needless_pass_by_ref_mut.rs:380:20 | LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut.rs:355:20 + --> tests/ui/needless_pass_by_ref_mut.rs:382:20 | LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)` diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed index f26b39ea6a16b..0e2ac02023641 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.fixed @@ -6,7 +6,8 @@ #![warn(clippy::needless_pass_by_ref_mut)] async fn inner_async3(x: &i32, y: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async { *y += 1; } @@ -14,7 +15,8 @@ async fn inner_async3(x: &i32, y: &mut u32) { } async fn inner_async4(u: &mut i32, v: &u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async { *u += 1; } diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs index 4220215b1fe9b..9201d9a272984 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.rs @@ -6,7 +6,8 @@ #![warn(clippy::needless_pass_by_ref_mut)] async fn inner_async3(x: &mut i32, y: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async { *y += 1; } @@ -14,7 +15,8 @@ async fn inner_async3(x: &mut i32, y: &mut u32) { } async fn inner_async4(u: &mut i32, v: &mut u32) { - //~^ ERROR: this argument is a mutable reference, but not used mutably + //~^ needless_pass_by_ref_mut + async { *u += 1; } diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr index 1c0136cf5d594..9876a6b507187 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut2.stderr @@ -8,7 +8,7 @@ LL | async fn inner_async3(x: &mut i32, y: &mut u32) { = help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]` error: this argument is a mutable reference, but not used mutably - --> tests/ui/needless_pass_by_ref_mut2.rs:16:39 + --> tests/ui/needless_pass_by_ref_mut2.rs:17:39 | LL | async fn inner_async4(u: &mut i32, v: &mut u32) { | ^^^^^^^^ help: consider changing to: `&u32` diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.rs b/src/tools/clippy/tests/ui/needless_pass_by_value.rs index a8d9db95dcc77..885fb409417b1 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_value.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_value.rs @@ -17,8 +17,8 @@ use std::mem::MaybeUninit; // `v` should be warned // `w`, `x` and `y` are allowed (moved or mutated) fn foo(v: Vec, w: Vec, mut x: Vec, y: Vec) -> Vec { - //~^ ERROR: this argument is passed by value, but not consumed in the function body - //~| NOTE: `-D clippy::needless-pass-by-value` implied by `-D warnings` + //~^ needless_pass_by_value + assert_eq!(v.len(), 42); consume(w); @@ -33,15 +33,17 @@ fn consume(_: T) {} struct Wrapper(String); fn bar(x: String, y: Wrapper) { - //~^ ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + //~| needless_pass_by_value + assert_eq!(x.len(), 42); assert_eq!(y.0.len(), 42); } // V implements `Borrow`, but should be warned correctly fn test_borrow_trait, U: AsRef, V>(t: T, u: U, v: V) { - //~^ ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + println!("{}", t.borrow()); println!("{}", u.as_ref()); consume(&v); @@ -54,7 +56,8 @@ fn test_fn i32>(f: F) { // x should be warned, but y is ok fn test_match(x: Option>, y: Option>) { - //~^ ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + match x { Some(Some(_)) => 1, // not moved _ => 0, @@ -68,8 +71,9 @@ fn test_match(x: Option>, y: Option>) { // x and y should be warned, but z is ok fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { - //~^ ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + //~| needless_pass_by_value + let Wrapper(s) = z; // moved let Wrapper(ref t) = y; // not moved let Wrapper(_) = y; // still not moved @@ -86,13 +90,14 @@ impl<'a, T> Serialize for &'a T where T: Serialize {} impl Serialize for i32 {} fn test_blanket_ref(vals: T, serializable: S) {} -//~^ ERROR: this argument is passed by value, but not consumed in the function body +//~^ needless_pass_by_value fn issue_2114(s: String, t: String, u: Vec, v: Vec) { - //~^ ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + //~| needless_pass_by_value + //~| needless_pass_by_value + //~| needless_pass_by_value + s.capacity(); let _ = t.clone(); u.capacity(); @@ -106,9 +111,9 @@ impl S { self, // taking `self` by value is always allowed s: String, - //~^ ERROR: this argument is passed by value, but not consumed in the function bod + //~^ needless_pass_by_value t: String, - //~^ ERROR: this argument is passed by value, but not consumed in the function bod + //~^ needless_pass_by_value ) -> usize { s.len() + t.capacity() } @@ -118,8 +123,8 @@ impl S { } fn baz(&self, uu: U, ss: Self) {} - //~^ ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + //~| needless_pass_by_value } trait FalsePositive { @@ -142,16 +147,18 @@ fn range>(range: T) { struct CopyWrapper(u32); fn bar_copy(x: u32, y: CopyWrapper) { - //~^ ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + assert_eq!(x, 42); assert_eq!(y.0, 42); } // x and y should be warned, but z is ok fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { - //~^ ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body - //~| ERROR: this argument is passed by value, but not consumed in the function body + //~^ needless_pass_by_value + //~| needless_pass_by_value + //~| needless_pass_by_value + let CopyWrapper(s) = z; // moved let CopyWrapper(ref t) = y; // not moved let CopyWrapper(_) = y; // still not moved @@ -164,13 +171,13 @@ fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { trait Bar<'a, A> {} impl<'b, T> Bar<'b, T> for T {} fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} -//~^ ERROR: this argument is passed by value, but not consumed in the function body +//~^ needless_pass_by_value // Also this should not cause an ICE. See #2831 trait Club<'a, A> {} impl Club<'static, T> for T {} fn more_fun(items: impl Club<'static, i32>) {} -//~^ ERROR: this argument is passed by value, but not consumed in the function body +//~^ needless_pass_by_value fn is_sync(_: T) where diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr index 2c90da51252a4..4ac4fdce972d2 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_value.stderr +++ b/src/tools/clippy/tests/ui/needless_pass_by_value.stderr @@ -20,43 +20,43 @@ LL | fn bar(x: String, y: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:43:71 + --> tests/ui/needless_pass_by_value.rs:44:71 | LL | fn test_borrow_trait, U: AsRef, V>(t: T, u: U, v: V) { | ^ help: consider taking a reference instead: `&V` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:56:18 + --> tests/ui/needless_pass_by_value.rs:58:18 | LL | fn test_match(x: Option>, y: Option>) { | ^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&Option>` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:70:24 + --> tests/ui/needless_pass_by_value.rs:73:24 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:70:36 + --> tests/ui/needless_pass_by_value.rs:73:36 | LL | fn test_destructure(x: Wrapper, y: Wrapper, z: Wrapper) { | ^^^^^^^ help: consider taking a reference instead: `&Wrapper` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:88:49 + --> tests/ui/needless_pass_by_value.rs:92:49 | LL | fn test_blanket_ref(vals: T, serializable: S) {} | ^ help: consider taking a reference instead: `&T` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:91:18 + --> tests/ui/needless_pass_by_value.rs:95:18 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:91:29 + --> tests/ui/needless_pass_by_value.rs:95:29 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^ @@ -73,13 +73,13 @@ LL + let _ = t.to_string(); | error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:91:40 + --> tests/ui/needless_pass_by_value.rs:95:40 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ help: consider taking a reference instead: `&Vec` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:91:53 + --> tests/ui/needless_pass_by_value.rs:95:53 | LL | fn issue_2114(s: String, t: String, u: Vec, v: Vec) { | ^^^^^^^^ @@ -96,85 +96,85 @@ LL + let _ = v.to_owned(); | error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:108:12 + --> tests/ui/needless_pass_by_value.rs:113:12 | LL | s: String, | ^^^^^^ help: consider changing the type to: `&str` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:110:12 + --> tests/ui/needless_pass_by_value.rs:115:12 | LL | t: String, | ^^^^^^ help: consider taking a reference instead: `&String` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:120:23 + --> tests/ui/needless_pass_by_value.rs:125:23 | LL | fn baz(&self, uu: U, ss: Self) {} | ^ help: consider taking a reference instead: `&U` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:120:30 + --> tests/ui/needless_pass_by_value.rs:125:30 | LL | fn baz(&self, uu: U, ss: Self) {} | ^^^^ help: consider taking a reference instead: `&Self` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:144:24 + --> tests/ui/needless_pass_by_value.rs:149:24 | LL | fn bar_copy(x: u32, y: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:142:1 + --> tests/ui/needless_pass_by_value.rs:147:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:151:29 + --> tests/ui/needless_pass_by_value.rs:157:29 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:142:1 + --> tests/ui/needless_pass_by_value.rs:147:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:151:45 + --> tests/ui/needless_pass_by_value.rs:157:45 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:142:1 + --> tests/ui/needless_pass_by_value.rs:147:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:151:61 + --> tests/ui/needless_pass_by_value.rs:157:61 | LL | fn test_destructure_copy(x: CopyWrapper, y: CopyWrapper, z: CopyWrapper) { | ^^^^^^^^^^^ help: consider taking a reference instead: `&CopyWrapper` | help: or consider marking this type as `Copy` - --> tests/ui/needless_pass_by_value.rs:142:1 + --> tests/ui/needless_pass_by_value.rs:147:1 | LL | struct CopyWrapper(u32); | ^^^^^^^^^^^^^^^^^^ error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:166:40 + --> tests/ui/needless_pass_by_value.rs:173:40 | LL | fn some_fun<'b, S: Bar<'b, ()>>(items: S) {} | ^ help: consider taking a reference instead: `&S` error: this argument is passed by value, but not consumed in the function body - --> tests/ui/needless_pass_by_value.rs:172:20 + --> tests/ui/needless_pass_by_value.rs:179:20 | LL | fn more_fun(items: impl Club<'static, i32>) {} | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider taking a reference instead: `&impl Club<'static, i32>` diff --git a/src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs b/src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs index c603163c145f2..67516a962e755 100644 --- a/src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs +++ b/src/tools/clippy/tests/ui/needless_pass_by_value_proc_macro.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::needless_pass_by_value)] extern crate proc_macro; diff --git a/src/tools/clippy/tests/ui/needless_pub_self.fixed b/src/tools/clippy/tests/ui/needless_pub_self.fixed index d9f7b92d09012..7b4601ba8a370 100644 --- a/src/tools/clippy/tests/ui/needless_pub_self.fixed +++ b/src/tools/clippy/tests/ui/needless_pub_self.fixed @@ -11,13 +11,16 @@ extern crate proc_macros; fn a() {} +//~^ needless_pub_self fn b() {} +//~^ needless_pub_self pub fn c() {} mod a { pub(in super) fn d() {} pub(super) fn e() {} fn f() {} + //~^ needless_pub_self } external! { diff --git a/src/tools/clippy/tests/ui/needless_pub_self.rs b/src/tools/clippy/tests/ui/needless_pub_self.rs index 9f0ec76477e6e..f64a56c37989d 100644 --- a/src/tools/clippy/tests/ui/needless_pub_self.rs +++ b/src/tools/clippy/tests/ui/needless_pub_self.rs @@ -11,13 +11,16 @@ extern crate proc_macros; pub(self) fn a() {} +//~^ needless_pub_self pub(in self) fn b() {} +//~^ needless_pub_self pub fn c() {} mod a { pub(in super) fn d() {} pub(super) fn e() {} pub(self) fn f() {} + //~^ needless_pub_self } external! { diff --git a/src/tools/clippy/tests/ui/needless_pub_self.stderr b/src/tools/clippy/tests/ui/needless_pub_self.stderr index 1fdd841656594..c362d11804ec1 100644 --- a/src/tools/clippy/tests/ui/needless_pub_self.stderr +++ b/src/tools/clippy/tests/ui/needless_pub_self.stderr @@ -9,7 +9,7 @@ LL | pub(self) fn a() {} = help: remove it error: unnecessary `pub(in self)` - --> tests/ui/needless_pub_self.rs:14:1 + --> tests/ui/needless_pub_self.rs:15:1 | LL | pub(in self) fn b() {} | ^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | pub(in self) fn b() {} = help: remove it error: unnecessary `pub(self)` - --> tests/ui/needless_pub_self.rs:20:5 + --> tests/ui/needless_pub_self.rs:22:5 | LL | pub(self) fn f() {} | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed index 92f01c217c1cb..375c38771eb6d 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed @@ -18,6 +18,7 @@ struct TR { fn simple_option_bad1(to: TO) -> Option { // return as a statement return to.magic; + //~^ needless_question_mark } // formatting will add a semi-colon, which would make @@ -26,16 +27,19 @@ fn simple_option_bad1(to: TO) -> Option { fn simple_option_bad2(to: TO) -> Option { // return as an expression return to.magic + //~^ needless_question_mark } fn simple_option_bad3(to: TO) -> Option { // block value "return" to.magic + //~^ needless_question_mark } fn simple_option_bad4(to: Option) -> Option { // single line closure to.and_then(|t| t.magic) + //~^ needless_question_mark } // formatting this will remove the block brackets, making @@ -45,11 +49,13 @@ fn simple_option_bad5(to: Option) -> Option { // closure with body to.and_then(|t| { t.magic + //~^ needless_question_mark }) } fn simple_result_bad1(tr: TR) -> Result { return tr.magic; + //~^ needless_question_mark } // formatting will add a semi-colon, which would make @@ -57,14 +63,17 @@ fn simple_result_bad1(tr: TR) -> Result { #[rustfmt::skip] fn simple_result_bad2(tr: TR) -> Result { return tr.magic + //~^ needless_question_mark } fn simple_result_bad3(tr: TR) -> Result { tr.magic + //~^ needless_question_mark } fn simple_result_bad4(tr: Result) -> Result { tr.and_then(|t| t.magic) + //~^ needless_question_mark } // formatting this will remove the block brackets, making @@ -73,6 +82,7 @@ fn simple_result_bad4(tr: Result) -> Result { fn simple_result_bad5(tr: Result) -> Result { tr.and_then(|t| { t.magic + //~^ needless_question_mark }) } @@ -80,6 +90,7 @@ fn also_bad(tr: Result) -> Result { if tr.is_ok() { let t = tr.unwrap(); return t.magic; + //~^ needless_question_mark } Err(false) } @@ -115,6 +126,7 @@ pub fn test1() { macro_rules! some_and_qmark_in_macro { ($expr:expr) => { || -> Option<_> { Some($expr) }() + //~^ needless_question_mark }; } @@ -126,6 +138,7 @@ pub fn test2() { async fn async_option_bad(to: TO) -> Option { let _ = Some(3); to.magic + //~^ needless_question_mark } async fn async_deref_ref(s: Option<&String>) -> Option<&str> { @@ -134,8 +147,10 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> { async fn async_result_bad(s: TR) -> Result { s.magic + //~^ needless_question_mark } async fn async_wrapped(a: Option) -> Option { { a } + //~^ needless_question_mark } diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs index 21c858c291ffa..5f6bd0c0f166e 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_question_mark.rs @@ -18,6 +18,7 @@ struct TR { fn simple_option_bad1(to: TO) -> Option { // return as a statement return Some(to.magic?); + //~^ needless_question_mark } // formatting will add a semi-colon, which would make @@ -26,16 +27,19 @@ fn simple_option_bad1(to: TO) -> Option { fn simple_option_bad2(to: TO) -> Option { // return as an expression return Some(to.magic?) + //~^ needless_question_mark } fn simple_option_bad3(to: TO) -> Option { // block value "return" Some(to.magic?) + //~^ needless_question_mark } fn simple_option_bad4(to: Option) -> Option { // single line closure to.and_then(|t| Some(t.magic?)) + //~^ needless_question_mark } // formatting this will remove the block brackets, making @@ -45,11 +49,13 @@ fn simple_option_bad5(to: Option) -> Option { // closure with body to.and_then(|t| { Some(t.magic?) + //~^ needless_question_mark }) } fn simple_result_bad1(tr: TR) -> Result { return Ok(tr.magic?); + //~^ needless_question_mark } // formatting will add a semi-colon, which would make @@ -57,14 +63,17 @@ fn simple_result_bad1(tr: TR) -> Result { #[rustfmt::skip] fn simple_result_bad2(tr: TR) -> Result { return Ok(tr.magic?) + //~^ needless_question_mark } fn simple_result_bad3(tr: TR) -> Result { Ok(tr.magic?) + //~^ needless_question_mark } fn simple_result_bad4(tr: Result) -> Result { tr.and_then(|t| Ok(t.magic?)) + //~^ needless_question_mark } // formatting this will remove the block brackets, making @@ -73,6 +82,7 @@ fn simple_result_bad4(tr: Result) -> Result { fn simple_result_bad5(tr: Result) -> Result { tr.and_then(|t| { Ok(t.magic?) + //~^ needless_question_mark }) } @@ -80,6 +90,7 @@ fn also_bad(tr: Result) -> Result { if tr.is_ok() { let t = tr.unwrap(); return Ok(t.magic?); + //~^ needless_question_mark } Err(false) } @@ -115,6 +126,7 @@ pub fn test1() { macro_rules! some_and_qmark_in_macro { ($expr:expr) => { || -> Option<_> { Some(Some($expr)?) }() + //~^ needless_question_mark }; } @@ -126,6 +138,7 @@ pub fn test2() { async fn async_option_bad(to: TO) -> Option { let _ = Some(3); Some(to.magic?) + //~^ needless_question_mark } async fn async_deref_ref(s: Option<&String>) -> Option<&str> { @@ -134,8 +147,10 @@ async fn async_deref_ref(s: Option<&String>) -> Option<&str> { async fn async_result_bad(s: TR) -> Result { Ok(s.magic?) + //~^ needless_question_mark } async fn async_wrapped(a: Option) -> Option { { Some(a?) } + //~^ needless_question_mark } diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index 0a1cb59797086..55da4f28976c1 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -8,67 +8,67 @@ LL | return Some(to.magic?); = help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:28:12 + --> tests/ui/needless_question_mark.rs:29:12 | LL | return Some(to.magic?) | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:33:5 + --> tests/ui/needless_question_mark.rs:35:5 | LL | Some(to.magic?) | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:38:21 + --> tests/ui/needless_question_mark.rs:41:21 | LL | to.and_then(|t| Some(t.magic?)) | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:47:9 + --> tests/ui/needless_question_mark.rs:51:9 | LL | Some(t.magic?) | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:52:12 + --> tests/ui/needless_question_mark.rs:57:12 | LL | return Ok(tr.magic?); | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:59:12 + --> tests/ui/needless_question_mark.rs:65:12 | LL | return Ok(tr.magic?) | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:63:5 + --> tests/ui/needless_question_mark.rs:70:5 | LL | Ok(tr.magic?) | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:67:21 + --> tests/ui/needless_question_mark.rs:75:21 | LL | tr.and_then(|t| Ok(t.magic?)) | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:75:9 + --> tests/ui/needless_question_mark.rs:84:9 | LL | Ok(t.magic?) | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:82:16 + --> tests/ui/needless_question_mark.rs:92:16 | LL | return Ok(t.magic?); | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:117:27 + --> tests/ui/needless_question_mark.rs:128:27 | LL | || -> Option<_> { Some(Some($expr)?) }() | ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)` @@ -79,19 +79,19 @@ LL | let _x = some_and_qmark_in_macro!(x?); = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:128:5 + --> tests/ui/needless_question_mark.rs:140:5 | LL | Some(to.magic?) | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:136:5 + --> tests/ui/needless_question_mark.rs:149:5 | LL | Ok(s.magic?) | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic` error: question mark operator is useless here - --> tests/ui/needless_question_mark.rs:140:7 + --> tests/ui/needless_question_mark.rs:154:7 | LL | { Some(a?) } | ^^^^^^^^ help: try removing question mark and `Some()`: `a` diff --git a/src/tools/clippy/tests/ui/needless_range_loop.rs b/src/tools/clippy/tests/ui/needless_range_loop.rs index 75f1896eded17..8a1c1be289cf8 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop.rs +++ b/src/tools/clippy/tests/ui/needless_range_loop.rs @@ -14,8 +14,8 @@ fn main() { let mut vec = vec![1, 2, 3, 4]; let vec2 = vec![1, 2, 3, 4]; for i in 0..vec.len() { - //~^ ERROR: the loop variable `i` is only used to index `vec` - //~| NOTE: `-D clippy::needless-range-loop` implied by `-D warnings` + //~^ needless_range_loop + println!("{}", vec[i]); } @@ -25,23 +25,27 @@ fn main() { } for i in 0..vec.len() { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + let _ = vec[i]; } // ICE #746 for j in 0..4 { - //~^ ERROR: the loop variable `j` is only used to index `STATIC` + //~^ needless_range_loop + println!("{:?}", STATIC[j]); } for j in 0..4 { - //~^ ERROR: the loop variable `j` is only used to index `CONST` + //~^ needless_range_loop + println!("{:?}", CONST[j]); } for i in 0..vec.len() { - //~^ ERROR: the loop variable `i` is used to index `vec` + //~^ needless_range_loop + println!("{} {}", vec[i], i); } for i in 0..vec.len() { @@ -50,48 +54,57 @@ fn main() { } for i in 0..vec.len() { - //~^ ERROR: the loop variable `i` is only used to index `vec2` + //~^ needless_range_loop + println!("{}", vec2[i]); } for i in 5..vec.len() { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + println!("{}", vec[i]); } for i in 0..MAX_LEN { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + println!("{}", vec[i]); } for i in 0..=MAX_LEN { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + println!("{}", vec[i]); } for i in 5..10 { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + println!("{}", vec[i]); } for i in 5..=10 { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + println!("{}", vec[i]); } for i in 5..vec.len() { - //~^ ERROR: the loop variable `i` is used to index `vec` + //~^ needless_range_loop + println!("{} {}", vec[i], i); } for i in 5..10 { - //~^ ERROR: the loop variable `i` is used to index `vec` + //~^ needless_range_loop + println!("{} {}", vec[i], i); } // #2542 for i in 0..vec.len() { - //~^ ERROR: the loop variable `i` is used to index `vec` + //~^ needless_range_loop + vec[i] = Some(1).unwrap_or_else(|| panic!("error on {}", i)); } diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr index 831b8511e434b..23c085f9d3b21 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop.stderr +++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr @@ -25,7 +25,7 @@ LL + for in &vec { | error: the loop variable `j` is only used to index `STATIC` - --> tests/ui/needless_range_loop.rs:33:14 + --> tests/ui/needless_range_loop.rs:34:14 | LL | for j in 0..4 { | ^^^^ @@ -37,7 +37,7 @@ LL + for in &STATIC { | error: the loop variable `j` is only used to index `CONST` - --> tests/ui/needless_range_loop.rs:38:14 + --> tests/ui/needless_range_loop.rs:40:14 | LL | for j in 0..4 { | ^^^^ @@ -49,7 +49,7 @@ LL + for in &CONST { | error: the loop variable `i` is used to index `vec` - --> tests/ui/needless_range_loop.rs:43:14 + --> tests/ui/needless_range_loop.rs:46:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + for (i, ) in vec.iter().enumerate() { | error: the loop variable `i` is only used to index `vec2` - --> tests/ui/needless_range_loop.rs:52:14 + --> tests/ui/needless_range_loop.rs:56:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + for in vec2.iter().take(vec.len()) { | error: the loop variable `i` is only used to index `vec` - --> tests/ui/needless_range_loop.rs:57:14 + --> tests/ui/needless_range_loop.rs:62:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + for in vec.iter().skip(5) { | error: the loop variable `i` is only used to index `vec` - --> tests/ui/needless_range_loop.rs:62:14 + --> tests/ui/needless_range_loop.rs:68:14 | LL | for i in 0..MAX_LEN { | ^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + for in vec.iter().take(MAX_LEN) { | error: the loop variable `i` is only used to index `vec` - --> tests/ui/needless_range_loop.rs:67:14 + --> tests/ui/needless_range_loop.rs:74:14 | LL | for i in 0..=MAX_LEN { | ^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + for in vec.iter().take(MAX_LEN + 1) { | error: the loop variable `i` is only used to index `vec` - --> tests/ui/needless_range_loop.rs:72:14 + --> tests/ui/needless_range_loop.rs:80:14 | LL | for i in 5..10 { | ^^^^^ @@ -121,7 +121,7 @@ LL + for in vec.iter().take(10).skip(5) { | error: the loop variable `i` is only used to index `vec` - --> tests/ui/needless_range_loop.rs:77:14 + --> tests/ui/needless_range_loop.rs:86:14 | LL | for i in 5..=10 { | ^^^^^^ @@ -133,7 +133,7 @@ LL + for in vec.iter().take(10 + 1).skip(5) { | error: the loop variable `i` is used to index `vec` - --> tests/ui/needless_range_loop.rs:82:14 + --> tests/ui/needless_range_loop.rs:92:14 | LL | for i in 5..vec.len() { | ^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + for (i, ) in vec.iter().enumerate().skip(5) { | error: the loop variable `i` is used to index `vec` - --> tests/ui/needless_range_loop.rs:87:14 + --> tests/ui/needless_range_loop.rs:98:14 | LL | for i in 5..10 { | ^^^^^ @@ -157,7 +157,7 @@ LL + for (i, ) in vec.iter().enumerate().take(10).skip(5) { | error: the loop variable `i` is used to index `vec` - --> tests/ui/needless_range_loop.rs:93:14 + --> tests/ui/needless_range_loop.rs:105:14 | LL | for i in 0..vec.len() { | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_range_loop2.rs b/src/tools/clippy/tests/ui/needless_range_loop2.rs index 787ff18f338d2..68784a8df19d3 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop2.rs +++ b/src/tools/clippy/tests/ui/needless_range_loop2.rs @@ -9,8 +9,8 @@ fn main() { let ns = vec![2, 3, 5, 7]; for i in 3..10 { - //~^ ERROR: the loop variable `i` is only used to index `ns` - //~| NOTE: `-D clippy::needless-range-loop` implied by `-D warnings` + //~^ needless_range_loop + println!("{}", ns[i]); } @@ -32,14 +32,16 @@ fn main() { let mut ms = vec![1, 2, 3, 4, 5, 6]; for i in 0..ms.len() { - //~^ ERROR: the loop variable `i` is only used to index `ms` + //~^ needless_range_loop + ms[i] *= 2; } assert_eq!(ms, vec![2, 4, 6, 8, 10, 12]); let mut ms = vec![1, 2, 3, 4, 5, 6]; for i in 0..ms.len() { - //~^ ERROR: the loop variable `i` is only used to index `ms` + //~^ needless_range_loop + let x = &mut ms[i]; *x *= 2; } @@ -64,7 +66,8 @@ fn main() { let mut vec = vec![0; 9]; for i in x..x + 4 { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + vec[i] += 1; } @@ -72,24 +75,28 @@ fn main() { let mut vec = vec![0; 10]; for i in x..=x + 4 { - //~^ ERROR: the loop variable `i` is only used to index `vec` + //~^ needless_range_loop + vec[i] += 1; } let arr = [1, 2, 3]; for i in 0..3 { - //~^ ERROR: the loop variable `i` is only used to index `arr` + //~^ needless_range_loop + println!("{}", arr[i]); } for i in 0..2 { - //~^ ERROR: the loop variable `i` is only used to index `arr` + //~^ needless_range_loop + println!("{}", arr[i]); } for i in 1..3 { - //~^ ERROR: the loop variable `i` is only used to index `arr` + //~^ needless_range_loop + println!("{}", arr[i]); } diff --git a/src/tools/clippy/tests/ui/needless_range_loop2.stderr b/src/tools/clippy/tests/ui/needless_range_loop2.stderr index f37e1f2872d04..cb979b3f3c243 100644 --- a/src/tools/clippy/tests/ui/needless_range_loop2.stderr +++ b/src/tools/clippy/tests/ui/needless_range_loop2.stderr @@ -25,7 +25,7 @@ LL + for in &mut ms { | error: the loop variable `i` is only used to index `ms` - --> tests/ui/needless_range_loop2.rs:41:14 + --> tests/ui/needless_range_loop2.rs:42:14 | LL | for i in 0..ms.len() { | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + for in &mut ms { | error: the loop variable `i` is only used to index `vec` - --> tests/ui/needless_range_loop2.rs:66:14 + --> tests/ui/needless_range_loop2.rs:68:14 | LL | for i in x..x + 4 { | ^^^^^^^^ @@ -49,7 +49,7 @@ LL + for in vec.iter_mut().skip(x).take(4) { | error: the loop variable `i` is only used to index `vec` - --> tests/ui/needless_range_loop2.rs:74:14 + --> tests/ui/needless_range_loop2.rs:77:14 | LL | for i in x..=x + 4 { | ^^^^^^^^^ @@ -61,7 +61,7 @@ LL + for in vec.iter_mut().skip(x).take(4 + 1) { | error: the loop variable `i` is only used to index `arr` - --> tests/ui/needless_range_loop2.rs:81:14 + --> tests/ui/needless_range_loop2.rs:85:14 | LL | for i in 0..3 { | ^^^^ @@ -73,7 +73,7 @@ LL + for in &arr { | error: the loop variable `i` is only used to index `arr` - --> tests/ui/needless_range_loop2.rs:86:14 + --> tests/ui/needless_range_loop2.rs:91:14 | LL | for i in 0..2 { | ^^^^ @@ -85,7 +85,7 @@ LL + for in arr.iter().take(2) { | error: the loop variable `i` is only used to index `arr` - --> tests/ui/needless_range_loop2.rs:91:14 + --> tests/ui/needless_range_loop2.rs:97:14 | LL | for i in 1..3 { | ^^^^ diff --git a/src/tools/clippy/tests/ui/needless_raw_string.fixed b/src/tools/clippy/tests/ui/needless_raw_string.fixed index ab061467488a8..88f9096db03cf 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.fixed +++ b/src/tools/clippy/tests/ui/needless_raw_string.fixed @@ -3,31 +3,41 @@ fn main() { "aaa"; + //~^ needless_raw_strings r#""aaa""#; r#"\s"#; b"aaa"; + //~^ needless_raw_strings br#""aaa""#; br#"\s"#; c"aaa"; + //~^ needless_raw_strings cr#""aaa""#; cr#"\s"#; " + //~^ needless_raw_strings a multiline string "; "no hashes"; + //~^ needless_raw_strings b"no hashes"; + //~^ needless_raw_strings c"no hashes"; + //~^ needless_raw_strings } fn issue_13503() { println!("SELECT * FROM posts"); + //~^ needless_raw_strings println!("SELECT * FROM posts"); + //~^ needless_raw_strings println!(r##"SELECT * FROM "posts""##); // Test arguments as well println!("{}", "foobar".len()); + //~^ needless_raw_strings } diff --git a/src/tools/clippy/tests/ui/needless_raw_string.rs b/src/tools/clippy/tests/ui/needless_raw_string.rs index 5be8bdeb4ad03..6913b8b755469 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.rs +++ b/src/tools/clippy/tests/ui/needless_raw_string.rs @@ -3,31 +3,41 @@ fn main() { r#"aaa"#; + //~^ needless_raw_strings r#""aaa""#; r#"\s"#; br#"aaa"#; + //~^ needless_raw_strings br#""aaa""#; br#"\s"#; cr#"aaa"#; + //~^ needless_raw_strings cr#""aaa""#; cr#"\s"#; r#" + //~^ needless_raw_strings a multiline string "#; r"no hashes"; + //~^ needless_raw_strings br"no hashes"; + //~^ needless_raw_strings cr"no hashes"; + //~^ needless_raw_strings } fn issue_13503() { println!(r"SELECT * FROM posts"); + //~^ needless_raw_strings println!(r#"SELECT * FROM posts"#); + //~^ needless_raw_strings println!(r##"SELECT * FROM "posts""##); // Test arguments as well println!("{}", r"foobar".len()); + //~^ needless_raw_strings } diff --git a/src/tools/clippy/tests/ui/needless_raw_string.stderr b/src/tools/clippy/tests/ui/needless_raw_string.stderr index 5169f08557388..99c60b10b21be 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string.stderr @@ -13,7 +13,7 @@ LL + "aaa"; | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:8:5 + --> tests/ui/needless_raw_string.rs:9:5 | LL | br#"aaa"#; | ^^^^^^^^^ @@ -25,7 +25,7 @@ LL + b"aaa"; | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:11:5 + --> tests/ui/needless_raw_string.rs:13:5 | LL | cr#"aaa"#; | ^^^^^^^^^ @@ -37,9 +37,10 @@ LL + c"aaa"; | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:15:5 + --> tests/ui/needless_raw_string.rs:18:5 | LL | / r#" +LL | | LL | | a LL | | multiline LL | | string @@ -49,14 +50,14 @@ LL | | "#; help: use a plain string literal instead | LL ~ " -LL | a -LL | multiline +LL | +... LL | string LL ~ "; | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:21:5 + --> tests/ui/needless_raw_string.rs:25:5 | LL | r"no hashes"; | ^^^^^^^^^^^^ @@ -68,7 +69,7 @@ LL + "no hashes"; | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:22:5 + --> tests/ui/needless_raw_string.rs:27:5 | LL | br"no hashes"; | ^^^^^^^^^^^^^ @@ -80,7 +81,7 @@ LL + b"no hashes"; | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:23:5 + --> tests/ui/needless_raw_string.rs:29:5 | LL | cr"no hashes"; | ^^^^^^^^^^^^^ @@ -92,7 +93,7 @@ LL + c"no hashes"; | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:27:14 + --> tests/ui/needless_raw_string.rs:34:14 | LL | println!(r"SELECT * FROM posts"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +105,7 @@ LL + println!("SELECT * FROM posts"); | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:28:14 + --> tests/ui/needless_raw_string.rs:36:14 | LL | println!(r#"SELECT * FROM posts"#); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -116,7 +117,7 @@ LL + println!("SELECT * FROM posts"); | error: unnecessary raw string literal - --> tests/ui/needless_raw_string.rs:32:20 + --> tests/ui/needless_raw_string.rs:41:20 | LL | println!("{}", r"foobar".len()); | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed index 4c1137091071e..bc7da202df4a9 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.fixed @@ -3,33 +3,51 @@ fn main() { r"\aaa"; + //~^ needless_raw_string_hashes r#"Hello "world"!"#; + //~^ needless_raw_string_hashes r####" "### "## "# "####; + //~^ needless_raw_string_hashes r###" "aa" "# "## "###; + //~^ needless_raw_string_hashes br"\aaa"; + //~^ needless_raw_string_hashes br#"Hello "world"!"#; + //~^ needless_raw_string_hashes br####" "### "## "# "####; + //~^ needless_raw_string_hashes br###" "aa" "# "## "###; + //~^ needless_raw_string_hashes cr"\aaa"; + //~^ needless_raw_string_hashes cr#"Hello "world"!"#; + //~^ needless_raw_string_hashes cr####" "### "## "# "####; + //~^ needless_raw_string_hashes cr###" "aa" "# "## "###; + //~^ needless_raw_string_hashes r" + //~^ needless_raw_string_hashes \a multiline string "; r"rust"; + //~^ needless_raw_string_hashes r"hello world"; + //~^ needless_raw_string_hashes } fn issue_13503() { println!(r"SELECT * FROM posts"); println!(r"SELECT * FROM posts"); + //~^ needless_raw_string_hashes println!(r#"SELECT * FROM "posts""#); + //~^ needless_raw_string_hashes println!(r#"SELECT * FROM "posts""#); + //~^ needless_raw_string_hashes // Test arguments as well println!("{}", r"foobar".len()); diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs index 7b6b4e784eea0..3f2f92a4097c3 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.rs @@ -3,33 +3,51 @@ fn main() { r#"\aaa"#; + //~^ needless_raw_string_hashes r##"Hello "world"!"##; + //~^ needless_raw_string_hashes r######" "### "## "# "######; + //~^ needless_raw_string_hashes r######" "aa" "# "## "######; + //~^ needless_raw_string_hashes br#"\aaa"#; + //~^ needless_raw_string_hashes br##"Hello "world"!"##; + //~^ needless_raw_string_hashes br######" "### "## "# "######; + //~^ needless_raw_string_hashes br######" "aa" "# "## "######; + //~^ needless_raw_string_hashes cr#"\aaa"#; + //~^ needless_raw_string_hashes cr##"Hello "world"!"##; + //~^ needless_raw_string_hashes cr######" "### "## "# "######; + //~^ needless_raw_string_hashes cr######" "aa" "# "## "######; + //~^ needless_raw_string_hashes r#" + //~^ needless_raw_string_hashes \a multiline string "#; r###"rust"###; + //~^ needless_raw_string_hashes r#"hello world"#; + //~^ needless_raw_string_hashes } fn issue_13503() { println!(r"SELECT * FROM posts"); println!(r#"SELECT * FROM posts"#); + //~^ needless_raw_string_hashes println!(r##"SELECT * FROM "posts""##); + //~^ needless_raw_string_hashes println!(r##"SELECT * FROM "posts""##); + //~^ needless_raw_string_hashes // Test arguments as well println!("{}", r"foobar".len()); diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr index a213ba3e74381..853ee70925287 100644 --- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr +++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr @@ -13,7 +13,7 @@ LL + r"\aaa"; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:6:5 + --> tests/ui/needless_raw_string_hashes.rs:7:5 | LL | r##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + r#"Hello "world"!"#; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:7:5 + --> tests/ui/needless_raw_string_hashes.rs:9:5 | LL | r######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + r####" "### "## "# "####; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:8:5 + --> tests/ui/needless_raw_string_hashes.rs:11:5 | LL | r######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + r###" "aa" "# "## "###; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:9:5 + --> tests/ui/needless_raw_string_hashes.rs:13:5 | LL | br#"\aaa"#; | ^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + br"\aaa"; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:10:5 + --> tests/ui/needless_raw_string_hashes.rs:15:5 | LL | br##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + br#"Hello "world"!"#; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:11:5 + --> tests/ui/needless_raw_string_hashes.rs:17:5 | LL | br######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + br####" "### "## "# "####; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:12:5 + --> tests/ui/needless_raw_string_hashes.rs:19:5 | LL | br######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + br###" "aa" "# "## "###; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:13:5 + --> tests/ui/needless_raw_string_hashes.rs:21:5 | LL | cr#"\aaa"#; | ^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + cr"\aaa"; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:14:5 + --> tests/ui/needless_raw_string_hashes.rs:23:5 | LL | cr##"Hello "world"!"##; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + cr#"Hello "world"!"#; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:15:5 + --> tests/ui/needless_raw_string_hashes.rs:25:5 | LL | cr######" "### "## "# "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + cr####" "### "## "# "####; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:16:5 + --> tests/ui/needless_raw_string_hashes.rs:27:5 | LL | cr######" "aa" "# "## "######; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,9 +145,10 @@ LL + cr###" "aa" "# "## "###; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:18:5 + --> tests/ui/needless_raw_string_hashes.rs:30:5 | LL | / r#" +LL | | LL | | \a LL | | multiline LL | | string @@ -157,14 +158,14 @@ LL | | "#; help: remove all the hashes around the string literal | LL ~ r" -LL | \a -LL | multiline +LL | +... LL | string LL ~ "; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:24:5 + --> tests/ui/needless_raw_string_hashes.rs:37:5 | LL | r###"rust"###; | ^^^^^^^^^^^^^ @@ -176,7 +177,7 @@ LL + r"rust"; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:25:5 + --> tests/ui/needless_raw_string_hashes.rs:39:5 | LL | r#"hello world"#; | ^^^^^^^^^^^^^^^^ @@ -188,7 +189,7 @@ LL + r"hello world"; | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:30:14 + --> tests/ui/needless_raw_string_hashes.rs:45:14 | LL | println!(r#"SELECT * FROM posts"#); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -200,7 +201,7 @@ LL + println!(r"SELECT * FROM posts"); | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:31:14 + --> tests/ui/needless_raw_string_hashes.rs:47:14 | LL | println!(r##"SELECT * FROM "posts""##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -212,7 +213,7 @@ LL + println!(r#"SELECT * FROM "posts""#); | error: unnecessary hashes around raw string literal - --> tests/ui/needless_raw_string_hashes.rs:32:14 + --> tests/ui/needless_raw_string_hashes.rs:49:14 | LL | println!(r##"SELECT * FROM "posts""##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index aa2a274525bce..efc073ebe8747 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -27,35 +27,43 @@ fn test_end_of_fn() -> bool { return true; } true + //~^ needless_return } fn test_no_semicolon() -> bool { true + //~^ needless_return } #[rustfmt::skip] fn test_multiple_semicolon() -> bool { true + //~^ needless_return } #[rustfmt::skip] fn test_multiple_semicolon_with_spaces() -> bool { true + //~^ needless_return } fn test_if_block() -> bool { if true { true + //~^ needless_return } else { false + //~^ needless_return } } fn test_match(x: bool) -> bool { match x { true => false, + //~^ needless_return false => { true + //~^ needless_return }, } } @@ -63,20 +71,26 @@ fn test_match(x: bool) -> bool { fn test_closure() { let _ = || { true + //~^ needless_return }; let _ = || true; + //~^ needless_return } fn test_macro_call() -> i32 { the_answer!() + //~^ needless_return } fn test_void_fun() { + //~^^ needless_return } fn test_void_if_fun(b: bool) { if b { + //~^^ needless_return } else { + //~^^ needless_return } } @@ -84,6 +98,7 @@ fn test_void_match(x: u32) { match x { 0 => (), _ => (), + //~^ needless_return } } @@ -92,8 +107,10 @@ fn test_nested_match(x: u32) { 0 => (), 1 => { let _ = 42; + //~^^ needless_return }, _ => (), + //~^ needless_return } } @@ -107,8 +124,10 @@ fn borrows_but_not_last(value: bool) -> String { let x = RefCell::::default(); let _a = x.borrow().clone(); String::from("test") + //~^ needless_return } else { String::new() + //~^ needless_return } } @@ -131,18 +150,22 @@ mod issue6501 { #[allow(clippy::unnecessary_lazy_evaluations)] fn foo(bar: Result<(), ()>) { bar.unwrap_or_else(|_| {}) + //~^ needless_return } fn test_closure() { let _ = || { + //~^^ needless_return }; let _ = || {}; + //~^ needless_return } struct Foo; #[allow(clippy::unnecessary_lazy_evaluations)] fn bar(res: Result) -> Foo { res.unwrap_or_else(|_| Foo) + //~^ needless_return } } @@ -152,25 +175,31 @@ async fn async_test_end_of_fn() -> bool { return true; } true + //~^ needless_return } async fn async_test_no_semicolon() -> bool { true + //~^ needless_return } async fn async_test_if_block() -> bool { if true { true + //~^ needless_return } else { false + //~^ needless_return } } async fn async_test_match(x: bool) -> bool { match x { true => false, + //~^ needless_return false => { true + //~^ needless_return }, } } @@ -178,20 +207,26 @@ async fn async_test_match(x: bool) -> bool { async fn async_test_closure() { let _ = || { true + //~^ needless_return }; let _ = || true; + //~^ needless_return } async fn async_test_macro_call() -> i32 { the_answer!() + //~^ needless_return } async fn async_test_void_fun() { + //~^^ needless_return } async fn async_test_void_if_fun(b: bool) { if b { + //~^^ needless_return } else { + //~^^ needless_return } } @@ -199,6 +234,7 @@ async fn async_test_void_match(x: u32) { match x { 0 => (), _ => (), + //~^ needless_return } } @@ -212,8 +248,10 @@ async fn async_borrows_but_not_last(value: bool) -> String { let x = RefCell::::default(); let _a = x.borrow().clone(); String::from("test") + //~^ needless_return } else { String::new() + //~^ needless_return } } @@ -230,6 +268,7 @@ fn needless_return_macro() -> String { let _ = "foo"; let _ = "bar"; format!("Hello {}", "world!") + //~^ needless_return } fn issue_9361(n: i32) -> i32 { @@ -271,8 +310,10 @@ fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); true + //~^ needless_return } else { false + //~^ needless_return } } @@ -280,9 +321,11 @@ fn issue8156(x: u8) -> u64 { match x { 80 => { 10 + //~^ needless_return }, _ => { 100 + //~^ needless_return }, } } @@ -291,6 +334,7 @@ fn issue8156(x: u8) -> u64 { fn issue9192() -> i32 { { 0 + //~^ needless_return } } @@ -298,8 +342,10 @@ fn issue9503(x: usize) -> isize { unsafe { if x > 12 { *(x as *const isize) + //~^ needless_return } else { !*(x as *const isize) + //~^ needless_return } } } @@ -307,11 +353,13 @@ fn issue9503(x: usize) -> isize { mod issue9416 { pub fn with_newline() { let _ = 42; + //~^^ needless_return } #[rustfmt::skip] pub fn oneline() { let _ = 42; + //~^ needless_return } } @@ -324,18 +372,22 @@ fn issue9947() -> Result<(), String> { fn issue10051() -> Result { if true { Ok(format!("ok!")) + //~^ needless_return } else { Err(format!("err!")) + //~^ needless_return } } mod issue10049 { fn single() -> u32 { if true { 1 } else { 2 } + //~^ needless_return } fn multiple(b1: bool, b2: bool, b3: bool) -> u32 { (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }) + //~^ needless_return } } @@ -357,10 +409,12 @@ fn allow_works() -> i32 { fn conjunctive_blocks() -> String { ({ "a".to_string() } + "b" + { "c" }) + //~^ needless_return } fn issue12907() -> String { "".split("").next().unwrap().to_string() + //~^ needless_return } fn issue13458() { diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index bf67cfd3698a1..283d86f25fe55 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -27,35 +27,43 @@ fn test_end_of_fn() -> bool { return true; } return true; + //~^ needless_return } fn test_no_semicolon() -> bool { return true; + //~^ needless_return } #[rustfmt::skip] fn test_multiple_semicolon() -> bool { return true;;; + //~^ needless_return } #[rustfmt::skip] fn test_multiple_semicolon_with_spaces() -> bool { return true;; ; ; + //~^ needless_return } fn test_if_block() -> bool { if true { return true; + //~^ needless_return } else { return false; + //~^ needless_return } } fn test_match(x: bool) -> bool { match x { true => return false, + //~^ needless_return false => { return true; + //~^ needless_return }, } } @@ -63,23 +71,29 @@ fn test_match(x: bool) -> bool { fn test_closure() { let _ = || { return true; + //~^ needless_return }; let _ = || return true; + //~^ needless_return } fn test_macro_call() -> i32 { return the_answer!(); + //~^ needless_return } fn test_void_fun() { return; + //~^^ needless_return } fn test_void_if_fun(b: bool) { if b { return; + //~^^ needless_return } else { return; + //~^^ needless_return } } @@ -87,6 +101,7 @@ fn test_void_match(x: u32) { match x { 0 => (), _ => return, + //~^ needless_return } } @@ -96,8 +111,10 @@ fn test_nested_match(x: u32) { 1 => { let _ = 42; return; + //~^^ needless_return }, _ => return, + //~^ needless_return } } @@ -111,8 +128,10 @@ fn borrows_but_not_last(value: bool) -> String { let x = RefCell::::default(); let _a = x.borrow().clone(); return String::from("test"); + //~^ needless_return } else { return String::new(); + //~^ needless_return } } @@ -135,19 +154,23 @@ mod issue6501 { #[allow(clippy::unnecessary_lazy_evaluations)] fn foo(bar: Result<(), ()>) { bar.unwrap_or_else(|_| return) + //~^ needless_return } fn test_closure() { let _ = || { return; + //~^^ needless_return }; let _ = || return; + //~^ needless_return } struct Foo; #[allow(clippy::unnecessary_lazy_evaluations)] fn bar(res: Result) -> Foo { res.unwrap_or_else(|_| return Foo) + //~^ needless_return } } @@ -157,25 +180,31 @@ async fn async_test_end_of_fn() -> bool { return true; } return true; + //~^ needless_return } async fn async_test_no_semicolon() -> bool { return true; + //~^ needless_return } async fn async_test_if_block() -> bool { if true { return true; + //~^ needless_return } else { return false; + //~^ needless_return } } async fn async_test_match(x: bool) -> bool { match x { true => return false, + //~^ needless_return false => { return true; + //~^ needless_return }, } } @@ -183,23 +212,29 @@ async fn async_test_match(x: bool) -> bool { async fn async_test_closure() { let _ = || { return true; + //~^ needless_return }; let _ = || return true; + //~^ needless_return } async fn async_test_macro_call() -> i32 { return the_answer!(); + //~^ needless_return } async fn async_test_void_fun() { return; + //~^^ needless_return } async fn async_test_void_if_fun(b: bool) { if b { return; + //~^^ needless_return } else { return; + //~^^ needless_return } } @@ -207,6 +242,7 @@ async fn async_test_void_match(x: u32) { match x { 0 => (), _ => return, + //~^ needless_return } } @@ -220,8 +256,10 @@ async fn async_borrows_but_not_last(value: bool) -> String { let x = RefCell::::default(); let _a = x.borrow().clone(); return String::from("test"); + //~^ needless_return } else { return String::new(); + //~^ needless_return } } @@ -238,6 +276,7 @@ fn needless_return_macro() -> String { let _ = "foo"; let _ = "bar"; return format!("Hello {}", "world!"); + //~^ needless_return } fn issue_9361(n: i32) -> i32 { @@ -279,8 +318,10 @@ fn issue8336(x: i32) -> bool { if x > 0 { println!("something"); return true; + //~^ needless_return } else { return false; + //~^ needless_return }; } @@ -288,9 +329,11 @@ fn issue8156(x: u8) -> u64 { match x { 80 => { return 10; + //~^ needless_return }, _ => { return 100; + //~^ needless_return }, }; } @@ -299,6 +342,7 @@ fn issue8156(x: u8) -> u64 { fn issue9192() -> i32 { { return 0; + //~^ needless_return }; } @@ -306,8 +350,10 @@ fn issue9503(x: usize) -> isize { unsafe { if x > 12 { return *(x as *const isize); + //~^ needless_return } else { return !*(x as *const isize); + //~^ needless_return }; }; } @@ -315,13 +361,14 @@ fn issue9503(x: usize) -> isize { mod issue9416 { pub fn with_newline() { let _ = 42; - return; + //~^^ needless_return } #[rustfmt::skip] pub fn oneline() { let _ = 42; return; + //~^ needless_return } } @@ -334,18 +381,22 @@ fn issue9947() -> Result<(), String> { fn issue10051() -> Result { if true { return Ok(format!("ok!")); + //~^ needless_return } else { return Err(format!("err!")); + //~^ needless_return } } mod issue10049 { fn single() -> u32 { return if true { 1 } else { 2 }; + //~^ needless_return } fn multiple(b1: bool, b2: bool, b3: bool) -> u32 { return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; + //~^ needless_return } } @@ -367,10 +418,12 @@ fn allow_works() -> i32 { fn conjunctive_blocks() -> String { return { "a".to_string() } + "b" + { "c" }; + //~^ needless_return } fn issue12907() -> String { return "".split("").next().unwrap().to_string(); + //~^ needless_return } fn issue13458() { diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 8d8b5b9e713d4..04c97a41d676b 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -13,7 +13,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:33:5 + --> tests/ui/needless_return.rs:34:5 | LL | return true; | ^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:38:5 + --> tests/ui/needless_return.rs:40:5 | LL | return true;;; | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:43:5 + --> tests/ui/needless_return.rs:46:5 | LL | return true;; ; ; | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:48:9 + --> tests/ui/needless_return.rs:52:9 | LL | return true; | ^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:50:9 + --> tests/ui/needless_return.rs:55:9 | LL | return false; | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:56:17 + --> tests/ui/needless_return.rs:62:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + true => false, | error: unneeded `return` statement - --> tests/ui/needless_return.rs:58:13 + --> tests/ui/needless_return.rs:65:13 | LL | return true; | ^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:65:9 + --> tests/ui/needless_return.rs:73:9 | LL | return true; | ^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:67:16 + --> tests/ui/needless_return.rs:76:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + let _ = || true; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:71:5 + --> tests/ui/needless_return.rs:81:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:74:21 + --> tests/ui/needless_return.rs:85:21 | LL | fn test_void_fun() { | _____________________^ @@ -148,7 +148,7 @@ LL + fn test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:79:11 + --> tests/ui/needless_return.rs:91:11 | LL | if b { | ___________^ @@ -163,7 +163,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:81:13 + --> tests/ui/needless_return.rs:94:13 | LL | } else { | _____________^ @@ -178,7 +178,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:89:14 + --> tests/ui/needless_return.rs:103:14 | LL | _ => return, | ^^^^^^ @@ -190,7 +190,7 @@ LL + _ => (), | error: unneeded `return` statement - --> tests/ui/needless_return.rs:97:24 + --> tests/ui/needless_return.rs:112:24 | LL | let _ = 42; | ________________________^ @@ -205,7 +205,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:100:14 + --> tests/ui/needless_return.rs:116:14 | LL | _ => return, | ^^^^^^ @@ -217,7 +217,7 @@ LL + _ => (), | error: unneeded `return` statement - --> tests/ui/needless_return.rs:113:9 + --> tests/ui/needless_return.rs:130:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:115:9 + --> tests/ui/needless_return.rs:133:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:137:32 + --> tests/ui/needless_return.rs:156:32 | LL | bar.unwrap_or_else(|_| return) | ^^^^^^ @@ -253,7 +253,7 @@ LL + bar.unwrap_or_else(|_| {}) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:141:21 + --> tests/ui/needless_return.rs:161:21 | LL | let _ = || { | _____________________^ @@ -268,7 +268,7 @@ LL + let _ = || { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:144:20 + --> tests/ui/needless_return.rs:165:20 | LL | let _ = || return; | ^^^^^^ @@ -280,7 +280,7 @@ LL + let _ = || {}; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:150:32 + --> tests/ui/needless_return.rs:172:32 | LL | res.unwrap_or_else(|_| return Foo) | ^^^^^^^^^^ @@ -292,7 +292,7 @@ LL + res.unwrap_or_else(|_| Foo) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:159:5 + --> tests/ui/needless_return.rs:182:5 | LL | return true; | ^^^^^^^^^^^ @@ -304,7 +304,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:163:5 + --> tests/ui/needless_return.rs:187:5 | LL | return true; | ^^^^^^^^^^^ @@ -316,7 +316,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:168:9 + --> tests/ui/needless_return.rs:193:9 | LL | return true; | ^^^^^^^^^^^ @@ -328,7 +328,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:170:9 + --> tests/ui/needless_return.rs:196:9 | LL | return false; | ^^^^^^^^^^^^ @@ -340,7 +340,7 @@ LL + false | error: unneeded `return` statement - --> tests/ui/needless_return.rs:176:17 + --> tests/ui/needless_return.rs:203:17 | LL | true => return false, | ^^^^^^^^^^^^ @@ -352,7 +352,7 @@ LL + true => false, | error: unneeded `return` statement - --> tests/ui/needless_return.rs:178:13 + --> tests/ui/needless_return.rs:206:13 | LL | return true; | ^^^^^^^^^^^ @@ -364,7 +364,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:185:9 + --> tests/ui/needless_return.rs:214:9 | LL | return true; | ^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL + true | error: unneeded `return` statement - --> tests/ui/needless_return.rs:187:16 + --> tests/ui/needless_return.rs:217:16 | LL | let _ = || return true; | ^^^^^^^^^^^ @@ -388,7 +388,7 @@ LL + let _ = || true; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:191:5 + --> tests/ui/needless_return.rs:222:5 | LL | return the_answer!(); | ^^^^^^^^^^^^^^^^^^^^ @@ -400,7 +400,7 @@ LL + the_answer!() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:194:33 + --> tests/ui/needless_return.rs:226:33 | LL | async fn async_test_void_fun() { | _________________________________^ @@ -415,7 +415,7 @@ LL + async fn async_test_void_fun() { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:199:11 + --> tests/ui/needless_return.rs:232:11 | LL | if b { | ___________^ @@ -430,7 +430,7 @@ LL + if b { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:201:13 + --> tests/ui/needless_return.rs:235:13 | LL | } else { | _____________^ @@ -445,7 +445,7 @@ LL + } else { | error: unneeded `return` statement - --> tests/ui/needless_return.rs:209:14 + --> tests/ui/needless_return.rs:244:14 | LL | _ => return, | ^^^^^^ @@ -457,7 +457,7 @@ LL + _ => (), | error: unneeded `return` statement - --> tests/ui/needless_return.rs:222:9 + --> tests/ui/needless_return.rs:258:9 | LL | return String::from("test"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -469,7 +469,7 @@ LL + String::from("test") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:224:9 + --> tests/ui/needless_return.rs:261:9 | LL | return String::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -481,7 +481,7 @@ LL + String::new() | error: unneeded `return` statement - --> tests/ui/needless_return.rs:240:5 + --> tests/ui/needless_return.rs:278:5 | LL | return format!("Hello {}", "world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -493,7 +493,7 @@ LL + format!("Hello {}", "world!") | error: unneeded `return` statement - --> tests/ui/needless_return.rs:281:9 + --> tests/ui/needless_return.rs:320:9 | LL | return true; | ^^^^^^^^^^^ @@ -501,13 +501,14 @@ LL | return true; help: remove `return` | LL ~ true -LL | } else { -LL | return false; +LL | +... +LL | LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:283:9 + --> tests/ui/needless_return.rs:323:9 | LL | return false; | ^^^^^^^^^^^^ @@ -515,11 +516,12 @@ LL | return false; help: remove `return` | LL ~ false +LL | LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:290:13 + --> tests/ui/needless_return.rs:331:13 | LL | return 10; | ^^^^^^^^^ @@ -527,14 +529,14 @@ LL | return 10; help: remove `return` | LL ~ 10 -LL | }, +LL | ... LL | }, LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:293:13 + --> tests/ui/needless_return.rs:335:13 | LL | return 100; | ^^^^^^^^^^ @@ -542,12 +544,13 @@ LL | return 100; help: remove `return` | LL ~ 100 +LL | LL | }, LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:301:9 + --> tests/ui/needless_return.rs:344:9 | LL | return 0; | ^^^^^^^^ @@ -555,11 +558,12 @@ LL | return 0; help: remove `return` | LL ~ 0 +LL | LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:308:13 + --> tests/ui/needless_return.rs:352:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -567,14 +571,15 @@ LL | return *(x as *const isize); help: remove `return` | LL ~ *(x as *const isize) -LL | } else { -LL | return !*(x as *const isize); +LL | +... +LL | LL ~ } LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:310:13 + --> tests/ui/needless_return.rs:355:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -582,29 +587,28 @@ LL | return !*(x as *const isize); help: remove `return` | LL ~ !*(x as *const isize) +LL | LL ~ } LL ~ } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:317:20 + --> tests/ui/needless_return.rs:363:20 | LL | let _ = 42; | ____________________^ -LL | | LL | | return; | |______________^ | help: remove `return` | LL - let _ = 42; -LL - LL - return; LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:324:20 + --> tests/ui/needless_return.rs:370:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -616,7 +620,7 @@ LL + let _ = 42; | error: unneeded `return` statement - --> tests/ui/needless_return.rs:336:9 + --> tests/ui/needless_return.rs:383:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -628,7 +632,7 @@ LL + Ok(format!("ok!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:338:9 + --> tests/ui/needless_return.rs:386:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -640,7 +644,7 @@ LL + Err(format!("err!")) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:344:9 + --> tests/ui/needless_return.rs:393:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -652,7 +656,7 @@ LL + if true { 1 } else { 2 } | error: unneeded `return` statement - --> tests/ui/needless_return.rs:348:9 + --> tests/ui/needless_return.rs:398:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -664,7 +668,7 @@ LL + (if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else | error: unneeded `return` statement - --> tests/ui/needless_return.rs:369:5 + --> tests/ui/needless_return.rs:420:5 | LL | return { "a".to_string() } + "b" + { "c" }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -676,7 +680,7 @@ LL + ({ "a".to_string() } + "b" + { "c" }) | error: unneeded `return` statement - --> tests/ui/needless_return.rs:373:5 + --> tests/ui/needless_return.rs:425:5 | LL | return "".split("").next().unwrap().to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed index 9b7da85266316..2c6faf37717d3 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.fixed @@ -27,6 +27,7 @@ fn c() -> Option<()> { fn main() -> Result<(), ()> { Err(())?; + //~^ needless_return_with_question_mark return Ok::<(), ()>(()); Err(())?; Ok::<(), ()>(()); diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs index 68e76d2b6402e..b4411fa195619 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.rs @@ -27,6 +27,7 @@ fn c() -> Option<()> { fn main() -> Result<(), ()> { return Err(())?; + //~^ needless_return_with_question_mark return Ok::<(), ()>(()); Err(())?; Ok::<(), ()>(()); diff --git a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr index 76dd5f953bc67..2af0f46a1ad0f 100644 --- a/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_return_with_question_mark.stderr @@ -8,7 +8,7 @@ LL | return Err(())?; = help: to override `-D warnings` add `#[allow(clippy::needless_return_with_question_mark)]` error: unneeded `return` statement with `?` operator - --> tests/ui/needless_return_with_question_mark.rs:69:9 + --> tests/ui/needless_return_with_question_mark.rs:70:9 | LL | return Err(())?; | ^^^^^^^ help: remove it diff --git a/src/tools/clippy/tests/ui/needless_splitn.fixed b/src/tools/clippy/tests/ui/needless_splitn.fixed index efc47533e2337..bf5c1717ae53d 100644 --- a/src/tools/clippy/tests/ui/needless_splitn.fixed +++ b/src/tools/clippy/tests/ui/needless_splitn.fixed @@ -11,29 +11,41 @@ use itertools::Itertools; fn main() { let str = "key=value=end"; let _ = str.split('=').next(); + //~^ needless_splitn let _ = str.split('=').nth(0); + //~^ needless_splitn let _ = str.splitn(2, '=').nth(1); let (_, _) = str.splitn(2, '=').next_tuple().unwrap(); let (_, _) = str.split('=').next_tuple().unwrap(); + //~^ needless_splitn let _: Vec<&str> = str.splitn(3, '=').collect(); let _ = str.rsplit('=').next(); + //~^ needless_splitn let _ = str.rsplit('=').nth(0); + //~^ needless_splitn let _ = str.rsplitn(2, '=').nth(1); let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap(); let (_, _) = str.rsplit('=').next_tuple().unwrap(); + //~^ needless_splitn let _ = str.split('=').next(); + //~^ needless_splitn let _ = str.split('=').nth(3); + //~^ needless_splitn let _ = str.splitn(5, '=').nth(4); let _ = str.splitn(5, '=').nth(5); } fn _question_mark(s: &str) -> Option<()> { let _ = s.split('=').next()?; + //~^ needless_splitn let _ = s.split('=').nth(0)?; + //~^ needless_splitn let _ = s.rsplit('=').next()?; + //~^ needless_splitn let _ = s.rsplit('=').nth(0)?; + //~^ needless_splitn Some(()) } @@ -42,4 +54,5 @@ fn _question_mark(s: &str) -> Option<()> { fn _test_msrv() { // `manual_split_once` MSRV shouldn't apply to `needless_splitn` let _ = "key=value".split('=').nth(0).unwrap(); + //~^ needless_splitn } diff --git a/src/tools/clippy/tests/ui/needless_splitn.rs b/src/tools/clippy/tests/ui/needless_splitn.rs index a4a3736eea2fe..fdfdcb9d5ca8a 100644 --- a/src/tools/clippy/tests/ui/needless_splitn.rs +++ b/src/tools/clippy/tests/ui/needless_splitn.rs @@ -11,29 +11,41 @@ use itertools::Itertools; fn main() { let str = "key=value=end"; let _ = str.splitn(2, '=').next(); + //~^ needless_splitn let _ = str.splitn(2, '=').nth(0); + //~^ needless_splitn let _ = str.splitn(2, '=').nth(1); let (_, _) = str.splitn(2, '=').next_tuple().unwrap(); let (_, _) = str.splitn(3, '=').next_tuple().unwrap(); + //~^ needless_splitn let _: Vec<&str> = str.splitn(3, '=').collect(); let _ = str.rsplitn(2, '=').next(); + //~^ needless_splitn let _ = str.rsplitn(2, '=').nth(0); + //~^ needless_splitn let _ = str.rsplitn(2, '=').nth(1); let (_, _) = str.rsplitn(2, '=').next_tuple().unwrap(); let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); + //~^ needless_splitn let _ = str.splitn(5, '=').next(); + //~^ needless_splitn let _ = str.splitn(5, '=').nth(3); + //~^ needless_splitn let _ = str.splitn(5, '=').nth(4); let _ = str.splitn(5, '=').nth(5); } fn _question_mark(s: &str) -> Option<()> { let _ = s.splitn(2, '=').next()?; + //~^ needless_splitn let _ = s.splitn(2, '=').nth(0)?; + //~^ needless_splitn let _ = s.rsplitn(2, '=').next()?; + //~^ needless_splitn let _ = s.rsplitn(2, '=').nth(0)?; + //~^ needless_splitn Some(()) } @@ -42,4 +54,5 @@ fn _question_mark(s: &str) -> Option<()> { fn _test_msrv() { // `manual_split_once` MSRV shouldn't apply to `needless_splitn` let _ = "key=value".splitn(2, '=').nth(0).unwrap(); + //~^ needless_splitn } diff --git a/src/tools/clippy/tests/ui/needless_splitn.stderr b/src/tools/clippy/tests/ui/needless_splitn.stderr index ffd82c3fcb13a..49387793a1220 100644 --- a/src/tools/clippy/tests/ui/needless_splitn.stderr +++ b/src/tools/clippy/tests/ui/needless_splitn.stderr @@ -8,73 +8,73 @@ LL | let _ = str.splitn(2, '=').next(); = help: to override `-D warnings` add `#[allow(clippy::needless_splitn)]` error: unnecessary use of `splitn` - --> tests/ui/needless_splitn.rs:14:13 + --> tests/ui/needless_splitn.rs:15:13 | LL | let _ = str.splitn(2, '=').nth(0); | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` - --> tests/ui/needless_splitn.rs:17:18 + --> tests/ui/needless_splitn.rs:19:18 | LL | let (_, _) = str.splitn(3, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `rsplitn` - --> tests/ui/needless_splitn.rs:20:13 + --> tests/ui/needless_splitn.rs:23:13 | LL | let _ = str.rsplitn(2, '=').next(); | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `rsplitn` - --> tests/ui/needless_splitn.rs:21:13 + --> tests/ui/needless_splitn.rs:25:13 | LL | let _ = str.rsplitn(2, '=').nth(0); | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `rsplitn` - --> tests/ui/needless_splitn.rs:24:18 + --> tests/ui/needless_splitn.rs:29:18 | LL | let (_, _) = str.rsplitn(3, '=').next_tuple().unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: try: `str.rsplit('=')` error: unnecessary use of `splitn` - --> tests/ui/needless_splitn.rs:26:13 + --> tests/ui/needless_splitn.rs:32:13 | LL | let _ = str.splitn(5, '=').next(); | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` - --> tests/ui/needless_splitn.rs:27:13 + --> tests/ui/needless_splitn.rs:34:13 | LL | let _ = str.splitn(5, '=').nth(3); | ^^^^^^^^^^^^^^^^^^ help: try: `str.split('=')` error: unnecessary use of `splitn` - --> tests/ui/needless_splitn.rs:33:13 + --> tests/ui/needless_splitn.rs:41:13 | LL | let _ = s.splitn(2, '=').next()?; | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')` error: unnecessary use of `splitn` - --> tests/ui/needless_splitn.rs:34:13 + --> tests/ui/needless_splitn.rs:43:13 | LL | let _ = s.splitn(2, '=').nth(0)?; | ^^^^^^^^^^^^^^^^ help: try: `s.split('=')` error: unnecessary use of `rsplitn` - --> tests/ui/needless_splitn.rs:35:13 + --> tests/ui/needless_splitn.rs:45:13 | LL | let _ = s.rsplitn(2, '=').next()?; | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')` error: unnecessary use of `rsplitn` - --> tests/ui/needless_splitn.rs:36:13 + --> tests/ui/needless_splitn.rs:47:13 | LL | let _ = s.rsplitn(2, '=').nth(0)?; | ^^^^^^^^^^^^^^^^^ help: try: `s.rsplit('=')` error: unnecessary use of `splitn` - --> tests/ui/needless_splitn.rs:44:13 + --> tests/ui/needless_splitn.rs:56:13 | LL | let _ = "key=value".splitn(2, '=').nth(0).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"key=value".split('=')` diff --git a/src/tools/clippy/tests/ui/needless_update.rs b/src/tools/clippy/tests/ui/needless_update.rs index 7c59abf07aba9..62e3492343193 100644 --- a/src/tools/clippy/tests/ui/needless_update.rs +++ b/src/tools/clippy/tests/ui/needless_update.rs @@ -17,8 +17,7 @@ fn main() { S { ..base }; // no error S { a: 1, ..base }; // no error S { a: 1, b: 1, ..base }; - //~^ ERROR: struct update has no effect, all the fields in the struct have already bee - //~| NOTE: `-D clippy::needless-update` implied by `-D warnings` + //~^ needless_update let base = T { x: 0, y: 0 }; T { ..base }; // no error diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs index c79fd26652601..27b51b4281705 100644 --- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.rs @@ -14,20 +14,19 @@ fn main() { // Not Less but potentially Greater, Equal or Uncomparable. let _not_less = !(a_value < another_value); - //~^ ERROR: the use of negated comparison operators on partially ordered types produce - //~| NOTE: `-D clippy::neg-cmp-op-on-partial-ord` implied by `-D warnings` + //~^ neg_cmp_op_on_partial_ord // Not Less or Equal but potentially Greater or Uncomparable. let _not_less_or_equal = !(a_value <= another_value); - //~^ ERROR: the use of negated comparison operators on partially ordered types produce + //~^ neg_cmp_op_on_partial_ord // Not Greater but potentially Less, Equal or Uncomparable. let _not_greater = !(a_value > another_value); - //~^ ERROR: the use of negated comparison operators on partially ordered types produce + //~^ neg_cmp_op_on_partial_ord // Not Greater or Equal but potentially Less or Uncomparable. let _not_greater_or_equal = !(a_value >= another_value); - //~^ ERROR: the use of negated comparison operators on partially ordered types produce + //~^ neg_cmp_op_on_partial_ord // --- Good --- diff --git a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr index d4f7f14f59a39..3c11d5b8826ab 100644 --- a/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr +++ b/src/tools/clippy/tests/ui/neg_cmp_op_on_partial_ord.stderr @@ -8,19 +8,19 @@ LL | let _not_less = !(a_value < another_value); = help: to override `-D warnings` add `#[allow(clippy::neg_cmp_op_on_partial_ord)]` error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable - --> tests/ui/neg_cmp_op_on_partial_ord.rs:21:30 + --> tests/ui/neg_cmp_op_on_partial_ord.rs:20:30 | LL | let _not_less_or_equal = !(a_value <= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable - --> tests/ui/neg_cmp_op_on_partial_ord.rs:25:24 + --> tests/ui/neg_cmp_op_on_partial_ord.rs:24:24 | LL | let _not_greater = !(a_value > another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the use of negated comparison operators on partially ordered types produces code that is hard to read and refactor, please consider using the `partial_cmp` method instead, to make it clear that the two values could be incomparable - --> tests/ui/neg_cmp_op_on_partial_ord.rs:29:33 + --> tests/ui/neg_cmp_op_on_partial_ord.rs:28:33 | LL | let _not_greater_or_equal = !(a_value >= another_value); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/neg_multiply.fixed b/src/tools/clippy/tests/ui/neg_multiply.fixed index 52edea73afbb7..995470493bfb7 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.fixed +++ b/src/tools/clippy/tests/ui/neg_multiply.fixed @@ -26,19 +26,27 @@ fn main() { let x = 0; -x; + //~^ neg_multiply -x; + //~^ neg_multiply 100 + -x; + //~^ neg_multiply -(100 + x); + //~^ neg_multiply -17; + //~^ neg_multiply 0xcafe | -0xff00; + //~^ neg_multiply -(3_usize as i32); + //~^ neg_multiply -(3_usize as i32); + //~^ neg_multiply -1 * -1; // should be ok diff --git a/src/tools/clippy/tests/ui/neg_multiply.rs b/src/tools/clippy/tests/ui/neg_multiply.rs index 23092a35e6064..95b94e29517fa 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.rs +++ b/src/tools/clippy/tests/ui/neg_multiply.rs @@ -26,19 +26,27 @@ fn main() { let x = 0; x * -1; + //~^ neg_multiply -1 * x; + //~^ neg_multiply 100 + x * -1; + //~^ neg_multiply (100 + x) * -1; + //~^ neg_multiply -1 * 17; + //~^ neg_multiply 0xcafe | 0xff00 * -1; + //~^ neg_multiply 3_usize as i32 * -1; + //~^ neg_multiply (3_usize as i32) * -1; + //~^ neg_multiply -1 * -1; // should be ok diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr index 13226c7c37b3f..9efa5d3ba1f1d 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.stderr +++ b/src/tools/clippy/tests/ui/neg_multiply.stderr @@ -8,43 +8,43 @@ LL | x * -1; = help: to override `-D warnings` add `#[allow(clippy::neg_multiply)]` error: this multiplication by -1 can be written more succinctly - --> tests/ui/neg_multiply.rs:30:5 + --> tests/ui/neg_multiply.rs:31:5 | LL | -1 * x; | ^^^^^^ help: consider using: `-x` error: this multiplication by -1 can be written more succinctly - --> tests/ui/neg_multiply.rs:32:11 + --> tests/ui/neg_multiply.rs:34:11 | LL | 100 + x * -1; | ^^^^^^ help: consider using: `-x` error: this multiplication by -1 can be written more succinctly - --> tests/ui/neg_multiply.rs:34:5 + --> tests/ui/neg_multiply.rs:37:5 | LL | (100 + x) * -1; | ^^^^^^^^^^^^^^ help: consider using: `-(100 + x)` error: this multiplication by -1 can be written more succinctly - --> tests/ui/neg_multiply.rs:36:5 + --> tests/ui/neg_multiply.rs:40:5 | LL | -1 * 17; | ^^^^^^^ help: consider using: `-17` error: this multiplication by -1 can be written more succinctly - --> tests/ui/neg_multiply.rs:38:14 + --> tests/ui/neg_multiply.rs:43:14 | LL | 0xcafe | 0xff00 * -1; | ^^^^^^^^^^^ help: consider using: `-0xff00` error: this multiplication by -1 can be written more succinctly - --> tests/ui/neg_multiply.rs:40:5 + --> tests/ui/neg_multiply.rs:46:5 | LL | 3_usize as i32 * -1; | ^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3_usize as i32)` error: this multiplication by -1 can be written more succinctly - --> tests/ui/neg_multiply.rs:41:5 + --> tests/ui/neg_multiply.rs:48:5 | LL | (3_usize as i32) * -1; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3_usize as i32)` diff --git a/src/tools/clippy/tests/ui/never_loop.rs b/src/tools/clippy/tests/ui/never_loop.rs index 93c69209c6980..2d8e04c192e40 100644 --- a/src/tools/clippy/tests/ui/never_loop.rs +++ b/src/tools/clippy/tests/ui/never_loop.rs @@ -10,8 +10,8 @@ fn test1() { let mut x = 0; loop { - //~^ ERROR: this loop never actually loops - //~| NOTE: `#[deny(clippy::never_loop)]` on by default + //~^ never_loop + // clippy::never_loop x += 1; if x == 1 { @@ -34,7 +34,8 @@ fn test2() { fn test3() { let mut x = 0; loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + // never loops x += 1; break; @@ -55,10 +56,12 @@ fn test4() { fn test5() { let i = 0; loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + // never loops while i == 0 { - //~^ ERROR: this loop never actually loops + //~^ never_loop + // never loops break; } @@ -71,7 +74,8 @@ fn test6() { 'outer: loop { x += 1; loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + // never loops if x == 5 { break; @@ -108,7 +112,8 @@ fn test8() { fn test9() { let x = Some(1); while let Some(y) = x { - //~^ ERROR: this loop never actually loops + //~^ never_loop + // never loops return; } @@ -116,7 +121,8 @@ fn test9() { fn test10() { for x in 0..10 { - //~^ ERROR: this loop never actually loops + //~^ never_loop + // never loops match x { 1 => break, @@ -165,7 +171,8 @@ pub fn test13() { pub fn test14() { let mut a = true; 'outer: while a { - //~^ ERROR: this loop never actually loops + //~^ never_loop + // never loops while a { if a { @@ -181,7 +188,8 @@ pub fn test14() { pub fn test15() { 'label: loop { while false { - //~^ ERROR: this loop never actually loops + //~^ never_loop + break 'label; } } @@ -233,7 +241,8 @@ pub fn test18() { }; // never loops let _ = loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + let Some(x) = x else { return; }; @@ -255,12 +264,12 @@ pub fn test19() { pub fn test20() { 'a: loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + 'b: { break 'b 'c: { break 'a; - //~^ ERROR: sub-expression diverges - //~| NOTE: `-D clippy::diverging-sub-expression` implied by `-D warnings` + //~^ diverging_sub_expression }; } } @@ -292,7 +301,8 @@ pub fn test23() { for _ in 0..10 { 'block: { for _ in 0..20 { - //~^ ERROR: this loop never actually loops + //~^ never_loop + break 'block; } } @@ -376,7 +386,8 @@ pub fn test31(b: bool) { 'a: loop { 'b: { 'c: loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + if b { break 'c } else { break 'b } } continue 'a; @@ -387,11 +398,13 @@ pub fn test31(b: bool) { pub fn test32() { loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + panic!("oh no"); } loop { - //~^ ERROR: this loop never actually loops + //~^ never_loop + unimplemented!("not yet"); } loop { diff --git a/src/tools/clippy/tests/ui/never_loop.stderr b/src/tools/clippy/tests/ui/never_loop.stderr index 203e332582256..f6d6d109542b5 100644 --- a/src/tools/clippy/tests/ui/never_loop.stderr +++ b/src/tools/clippy/tests/ui/never_loop.stderr @@ -13,64 +13,49 @@ error: this loop never actually loops --> tests/ui/never_loop.rs:36:5 | LL | / loop { -LL | | -LL | | // never loops -LL | | x += 1; +... | LL | | break; LL | | } | |_____^ error: this loop never actually loops - --> tests/ui/never_loop.rs:57:5 + --> tests/ui/never_loop.rs:58:5 | LL | / loop { -LL | | -LL | | // never loops -LL | | while i == 0 { ... | LL | | return; LL | | } | |_____^ error: this loop never actually loops - --> tests/ui/never_loop.rs:60:9 + --> tests/ui/never_loop.rs:62:9 | LL | / while i == 0 { -LL | | -LL | | // never loops -LL | | break; +... | LL | | } | |_________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:73:9 + --> tests/ui/never_loop.rs:76:9 | LL | / loop { -LL | | -LL | | // never loops -LL | | if x == 5 { ... | LL | | continue 'outer; LL | | } | |_________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:110:5 + --> tests/ui/never_loop.rs:114:5 | LL | / while let Some(y) = x { -LL | | -LL | | // never loops -LL | | return; +... | LL | | } | |_____^ error: this loop never actually loops - --> tests/ui/never_loop.rs:118:5 + --> tests/ui/never_loop.rs:123:5 | LL | / for x in 0..10 { -LL | | -LL | | // never loops -LL | | match x { ... | LL | | } | |_____^ @@ -82,52 +67,50 @@ LL + if let Some(x) = (0..10).next() { | error: this loop never actually loops - --> tests/ui/never_loop.rs:167:5 + --> tests/ui/never_loop.rs:173:5 | LL | / 'outer: while a { -LL | | -LL | | // never loops -LL | | while a { ... | LL | | break 'outer; LL | | } | |_____^ error: this loop never actually loops - --> tests/ui/never_loop.rs:183:9 + --> tests/ui/never_loop.rs:190:9 | LL | / while false { LL | | +LL | | LL | | break 'label; LL | | } | |_________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:235:13 + --> tests/ui/never_loop.rs:243:13 | LL | let _ = loop { | _____________^ LL | | +LL | | LL | | let Some(x) = x else { -LL | | return; ... | LL | | break x; LL | | }; | |_____^ error: this loop never actually loops - --> tests/ui/never_loop.rs:257:5 + --> tests/ui/never_loop.rs:266:5 | LL | / 'a: loop { LL | | +LL | | LL | | 'b: { -LL | | break 'b 'c: { ... | LL | | } | |_____^ error: sub-expression diverges - --> tests/ui/never_loop.rs:261:17 + --> tests/ui/never_loop.rs:271:17 | LL | break 'a; | ^^^^^^^^ @@ -136,10 +119,11 @@ LL | break 'a; = help: to override `-D warnings` add `#[allow(clippy::diverging_sub_expression)]` error: this loop never actually loops - --> tests/ui/never_loop.rs:294:13 + --> tests/ui/never_loop.rs:303:13 | LL | / for _ in 0..20 { LL | | +LL | | LL | | break 'block; LL | | } | |_____________^ @@ -151,28 +135,31 @@ LL + if let Some(_) = (0..20).next() { | error: this loop never actually loops - --> tests/ui/never_loop.rs:378:13 + --> tests/ui/never_loop.rs:388:13 | LL | / 'c: loop { LL | | +LL | | LL | | if b { break 'c } else { break 'b } LL | | } | |_____________^ error: this loop never actually loops - --> tests/ui/never_loop.rs:389:5 + --> tests/ui/never_loop.rs:400:5 | LL | / loop { LL | | +LL | | LL | | panic!("oh no"); LL | | } | |_____^ error: this loop never actually loops - --> tests/ui/never_loop.rs:393:5 + --> tests/ui/never_loop.rs:405:5 | LL | / loop { LL | | +LL | | LL | | unimplemented!("not yet"); LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.rs b/src/tools/clippy/tests/ui/new_ret_no_self.rs index 175b14d815a2c..d61973f09b171 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.rs +++ b/src/tools/clippy/tests/ui/new_ret_no_self.rs @@ -48,8 +48,8 @@ impl R for S3 { impl S3 { // should trigger the lint pub fn new(_: String) -> impl R { - //~^ ERROR: methods called `new` usually return `Self` - //~| NOTE: `-D clippy::new-ret-no-self` implied by `-D warnings` + //~^ new_ret_no_self + S3 } } @@ -82,7 +82,8 @@ struct U; impl U { // should trigger lint pub fn new() -> u32 { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + unimplemented!(); } } @@ -92,7 +93,8 @@ struct V; impl V { // should trigger lint pub fn new(_: String) -> u32 { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + unimplemented!(); } } @@ -129,7 +131,8 @@ struct TupleReturnerBad; impl TupleReturnerBad { // should trigger lint pub fn new() -> (u32, u32) { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + unimplemented!(); } } @@ -157,7 +160,8 @@ struct MutPointerReturnerBad; impl MutPointerReturnerBad { // should trigger lint pub fn new() -> *mut V { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + unimplemented!(); } } @@ -176,7 +180,8 @@ struct GenericReturnerBad; impl GenericReturnerBad { // should trigger lint pub fn new() -> Option { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + unimplemented!(); } } @@ -230,7 +235,7 @@ mod issue5435 { pub trait TraitRet { // should trigger lint as we are in trait definition fn new() -> String; - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self } pub struct StructRet; impl TraitRet for StructRet { @@ -243,7 +248,7 @@ mod issue5435 { pub trait TraitRet2 { // should trigger lint fn new(_: String) -> String; - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self } trait TupleReturnerOk { @@ -279,7 +284,8 @@ mod issue5435 { trait TupleReturnerBad { // should trigger lint fn new() -> (u32, u32) { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + unimplemented!(); } } @@ -307,7 +313,8 @@ mod issue5435 { trait MutPointerReturnerBad { // should trigger lint fn new() -> *mut V { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + unimplemented!(); } } @@ -378,7 +385,8 @@ mod issue7344 { impl RetImplTraitNoSelf { // should trigger lint fn new(t: T) -> impl Into { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self + 1 } } @@ -398,7 +406,7 @@ mod issue7344 { impl RetImplTraitNoSelf2 { // should trigger lint fn new(t: T) -> impl Trait2<(), i32> { - //~^ ERROR: methods called `new` usually return `Self` + //~^ new_ret_no_self } } diff --git a/src/tools/clippy/tests/ui/new_ret_no_self.stderr b/src/tools/clippy/tests/ui/new_ret_no_self.stderr index 3597ad65838f6..a758c746f9184 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self.stderr +++ b/src/tools/clippy/tests/ui/new_ret_no_self.stderr @@ -16,87 +16,95 @@ error: methods called `new` usually return `Self` | LL | / pub fn new() -> u32 { LL | | +LL | | LL | | unimplemented!(); LL | | } | |_____^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:94:5 + --> tests/ui/new_ret_no_self.rs:95:5 | LL | / pub fn new(_: String) -> u32 { LL | | +LL | | LL | | unimplemented!(); LL | | } | |_____^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:131:5 + --> tests/ui/new_ret_no_self.rs:133:5 | LL | / pub fn new() -> (u32, u32) { LL | | +LL | | LL | | unimplemented!(); LL | | } | |_____^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:159:5 + --> tests/ui/new_ret_no_self.rs:162:5 | LL | / pub fn new() -> *mut V { LL | | +LL | | LL | | unimplemented!(); LL | | } | |_____^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:178:5 + --> tests/ui/new_ret_no_self.rs:182:5 | LL | / pub fn new() -> Option { LL | | +LL | | LL | | unimplemented!(); LL | | } | |_____^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:232:9 + --> tests/ui/new_ret_no_self.rs:237:9 | LL | fn new() -> String; | ^^^^^^^^^^^^^^^^^^^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:245:9 + --> tests/ui/new_ret_no_self.rs:250:9 | LL | fn new(_: String) -> String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:281:9 + --> tests/ui/new_ret_no_self.rs:286:9 | LL | / fn new() -> (u32, u32) { LL | | +LL | | LL | | unimplemented!(); LL | | } | |_________^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:309:9 + --> tests/ui/new_ret_no_self.rs:315:9 | LL | / fn new() -> *mut V { LL | | +LL | | LL | | unimplemented!(); LL | | } | |_________^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:380:9 + --> tests/ui/new_ret_no_self.rs:387:9 | LL | / fn new(t: T) -> impl Into { LL | | +LL | | LL | | 1 LL | | } | |_________^ error: methods called `new` usually return `Self` - --> tests/ui/new_ret_no_self.rs:400:9 + --> tests/ui/new_ret_no_self.rs:408:9 | LL | / fn new(t: T) -> impl Trait2<(), i32> { LL | | diff --git a/src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs index 7bc6fec10ba64..f317674bc1ae4 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs +++ b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.rs @@ -17,7 +17,9 @@ mod issue10041 { struct Bomb2; impl Bomb2 { + #[define_opaque(X)] pub fn new() -> X { + //~^ ERROR: overflow evaluating the requirement 0i32 } } diff --git a/src/tools/clippy/tests/ui/new_ret_no_self_overflow.stderr b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.stderr index 77c1b64ebc8e3..8ecd0437e7dbd 100644 --- a/src/tools/clippy/tests/ui/new_ret_no_self_overflow.stderr +++ b/src/tools/clippy/tests/ui/new_ret_no_self_overflow.stderr @@ -1,5 +1,5 @@ error[E0275]: overflow evaluating the requirement `::Output == issue10041::X` - --> tests/ui/new_ret_no_self_overflow.rs:20:25 + --> tests/ui/new_ret_no_self_overflow.rs:21:25 | LL | pub fn new() -> X { | ^ diff --git a/src/tools/clippy/tests/ui/new_without_default.fixed b/src/tools/clippy/tests/ui/new_without_default.fixed index 5a6a92394a7fd..277c335cd8851 100644 --- a/src/tools/clippy/tests/ui/new_without_default.fixed +++ b/src/tools/clippy/tests/ui/new_without_default.fixed @@ -17,8 +17,8 @@ impl Default for Foo { impl Foo { pub fn new() -> Foo { - //~^ ERROR: you should consider adding a `Default` implementation for `Foo` - //~| NOTE: `-D clippy::new-without-default` implied by `-D warnings` + //~^ new_without_default + Foo } } @@ -33,7 +33,8 @@ impl Default for Bar { impl Bar { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `Bar` + //~^ new_without_default + Bar } } @@ -104,7 +105,8 @@ impl<'c> Default for LtKo<'c> { impl<'c> LtKo<'c> { pub fn new() -> LtKo<'c> { - //~^ ERROR: you should consider adding a `Default` implementation for `LtKo<'c>` + //~^ new_without_default + unimplemented!() } } @@ -143,6 +145,7 @@ impl Default for Const { impl Const { pub const fn new() -> Const { + //~^ new_without_default Const } // While Default is not const, it can still call const functions, so we should lint this } @@ -209,7 +212,8 @@ impl Default for NewNotEqualToDerive { impl NewNotEqualToDerive { // This `new` implementation is not equal to a derived `Default`, so do not suggest deriving. pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `NewNotEqualToDe + //~^ new_without_default + NewNotEqualToDerive { foo: 1 } } } @@ -224,7 +228,8 @@ impl Default for FooGenerics { impl FooGenerics { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `FooGenerics` + //~^ new_without_default + Self(Default::default()) } } @@ -238,7 +243,8 @@ impl Default for BarGenerics { impl BarGenerics { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `BarGenerics` + //~^ new_without_default + Self(Default::default()) } } @@ -256,7 +262,8 @@ pub mod issue7220 { impl Foo { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `Foo` + //~^ new_without_default + todo!() } } @@ -311,6 +318,7 @@ where K: std::hash::Hash + Eq + PartialEq, { pub fn new() -> Self { + //~^ new_without_default Self { _kv: None } } } diff --git a/src/tools/clippy/tests/ui/new_without_default.rs b/src/tools/clippy/tests/ui/new_without_default.rs index 12ea729253ac9..f2844897c93d9 100644 --- a/src/tools/clippy/tests/ui/new_without_default.rs +++ b/src/tools/clippy/tests/ui/new_without_default.rs @@ -11,8 +11,8 @@ pub struct Foo; impl Foo { pub fn new() -> Foo { - //~^ ERROR: you should consider adding a `Default` implementation for `Foo` - //~| NOTE: `-D clippy::new-without-default` implied by `-D warnings` + //~^ new_without_default + Foo } } @@ -21,7 +21,8 @@ pub struct Bar; impl Bar { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `Bar` + //~^ new_without_default + Bar } } @@ -86,7 +87,8 @@ pub struct LtKo<'a> { impl<'c> LtKo<'c> { pub fn new() -> LtKo<'c> { - //~^ ERROR: you should consider adding a `Default` implementation for `LtKo<'c>` + //~^ new_without_default + unimplemented!() } } @@ -119,6 +121,7 @@ pub struct Const; impl Const { pub const fn new() -> Const { + //~^ new_without_default Const } // While Default is not const, it can still call const functions, so we should lint this } @@ -179,7 +182,8 @@ pub struct NewNotEqualToDerive { impl NewNotEqualToDerive { // This `new` implementation is not equal to a derived `Default`, so do not suggest deriving. pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `NewNotEqualToDe + //~^ new_without_default + NewNotEqualToDerive { foo: 1 } } } @@ -188,7 +192,8 @@ impl NewNotEqualToDerive { pub struct FooGenerics(std::marker::PhantomData); impl FooGenerics { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `FooGenerics` + //~^ new_without_default + Self(Default::default()) } } @@ -196,7 +201,8 @@ impl FooGenerics { pub struct BarGenerics(std::marker::PhantomData); impl BarGenerics { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `BarGenerics` + //~^ new_without_default + Self(Default::default()) } } @@ -208,7 +214,8 @@ pub mod issue7220 { impl Foo { pub fn new() -> Self { - //~^ ERROR: you should consider adding a `Default` implementation for `Foo` + //~^ new_without_default + todo!() } } @@ -254,6 +261,7 @@ where K: std::hash::Hash + Eq + PartialEq, { pub fn new() -> Self { + //~^ new_without_default Self { _kv: None } } } diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr index 57bf4bd847cce..70a65aba464b8 100644 --- a/src/tools/clippy/tests/ui/new_without_default.stderr +++ b/src/tools/clippy/tests/ui/new_without_default.stderr @@ -24,6 +24,7 @@ error: you should consider adding a `Default` implementation for `Bar` | LL | / pub fn new() -> Self { LL | | +LL | | LL | | Bar LL | | } | |_____^ @@ -38,10 +39,11 @@ LL + } | error: you should consider adding a `Default` implementation for `LtKo<'c>` - --> tests/ui/new_without_default.rs:88:5 + --> tests/ui/new_without_default.rs:89:5 | LL | / pub fn new() -> LtKo<'c> { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -56,9 +58,10 @@ LL + } | error: you should consider adding a `Default` implementation for `Const` - --> tests/ui/new_without_default.rs:121:5 + --> tests/ui/new_without_default.rs:123:5 | LL | / pub const fn new() -> Const { +LL | | LL | | Const LL | | } // While Default is not const, it can still call const functions, so we should lint this | |_____^ @@ -73,10 +76,11 @@ LL + } | error: you should consider adding a `Default` implementation for `NewNotEqualToDerive` - --> tests/ui/new_without_default.rs:181:5 + --> tests/ui/new_without_default.rs:184:5 | LL | / pub fn new() -> Self { LL | | +LL | | LL | | NewNotEqualToDerive { foo: 1 } LL | | } | |_____^ @@ -91,10 +95,11 @@ LL + } | error: you should consider adding a `Default` implementation for `FooGenerics` - --> tests/ui/new_without_default.rs:190:5 + --> tests/ui/new_without_default.rs:194:5 | LL | / pub fn new() -> Self { LL | | +LL | | LL | | Self(Default::default()) LL | | } | |_____^ @@ -109,10 +114,11 @@ LL + } | error: you should consider adding a `Default` implementation for `BarGenerics` - --> tests/ui/new_without_default.rs:198:5 + --> tests/ui/new_without_default.rs:203:5 | LL | / pub fn new() -> Self { LL | | +LL | | LL | | Self(Default::default()) LL | | } | |_____^ @@ -127,10 +133,11 @@ LL + } | error: you should consider adding a `Default` implementation for `Foo` - --> tests/ui/new_without_default.rs:210:9 + --> tests/ui/new_without_default.rs:216:9 | LL | / pub fn new() -> Self { LL | | +LL | | LL | | todo!() LL | | } | |_________^ @@ -147,9 +154,10 @@ LL ~ impl Foo { | error: you should consider adding a `Default` implementation for `MyStruct` - --> tests/ui/new_without_default.rs:256:5 + --> tests/ui/new_without_default.rs:263:5 | LL | / pub fn new() -> Self { +LL | | LL | | Self { _kv: None } LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index 0ea911c343488..703c2a3d98479 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -113,62 +113,88 @@ fn main() { let s = get_struct(); 0; - //~^ ERROR: statement with no effect + //~^ no_effect + Tuple(0); - //~^ ERROR: statement with no effect + //~^ no_effect + Struct { field: 0 }; - //~^ ERROR: statement with no effect + //~^ no_effect + Struct { ..s }; - //~^ ERROR: statement with no effect + //~^ no_effect + Union { a: 0 }; - //~^ ERROR: statement with no effect + //~^ no_effect + Enum::Tuple(0); - //~^ ERROR: statement with no effect + //~^ no_effect + Enum::Struct { field: 0 }; - //~^ ERROR: statement with no effect + //~^ no_effect + 5 + 6; - //~^ ERROR: statement with no effect + //~^ no_effect + *&42; - //~^ ERROR: statement with no effect + //~^ no_effect + &6; - //~^ ERROR: statement with no effect + //~^ no_effect + (5, 6, 7); - //~^ ERROR: statement with no effect + //~^ no_effect + ..; - //~^ ERROR: statement with no effect + //~^ no_effect + 5..; - //~^ ERROR: statement with no effect + //~^ no_effect + ..5; - //~^ ERROR: statement with no effect + //~^ no_effect + 5..6; - //~^ ERROR: statement with no effect + //~^ no_effect + 5..=6; - //~^ ERROR: statement with no effect + //~^ no_effect + [42, 55]; - //~^ ERROR: statement with no effect + //~^ no_effect + [42, 55][1]; - //~^ ERROR: statement with no effect + //~^ no_effect + (42, 55).1; - //~^ ERROR: statement with no effect + //~^ no_effect + [42; 55]; - //~^ ERROR: statement with no effect + //~^ no_effect + [42; 55][13]; - //~^ ERROR: statement with no effect + //~^ no_effect + let mut x = 0; || x += 5; - //~^ ERROR: statement with no effect + //~^ no_effect + let s: String = "foo".into(); FooString { s: s }; - //~^ ERROR: statement with no effect + //~^ no_effect + let _unused = 1; - //~^ ERROR: binding to `_` prefixed variable with no side-effect - //~| NOTE: `-D clippy::no-effect-underscore-binding` implied by `-D warnings` + //~^ no_effect_underscore_binding + let _penguin = || println!("Some helpful closure"); - //~^ ERROR: binding to `_` prefixed variable with no side-effect + //~^ no_effect_underscore_binding + let _duck = Struct { field: 0 }; - //~^ ERROR: binding to `_` prefixed variable with no side-effect + //~^ no_effect_underscore_binding + let _cat = [2, 4, 6, 8][2]; - //~^ ERROR: binding to `_` prefixed variable with no side-effect + //~^ no_effect_underscore_binding + let _issue_12166 = 42; let underscore_variable_above_can_be_used_dont_lint = _issue_12166; diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr index 48ec997d938cd..58a9380cbfdeb 100644 --- a/src/tools/clippy/tests/ui/no_effect.stderr +++ b/src/tools/clippy/tests/ui/no_effect.stderr @@ -8,139 +8,139 @@ LL | 0; = help: to override `-D warnings` add `#[allow(clippy::no_effect)]` error: statement with no effect - --> tests/ui/no_effect.rs:117:5 + --> tests/ui/no_effect.rs:118:5 | LL | Tuple(0); | ^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:119:5 + --> tests/ui/no_effect.rs:121:5 | LL | Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:121:5 + --> tests/ui/no_effect.rs:124:5 | LL | Struct { ..s }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:123:5 + --> tests/ui/no_effect.rs:127:5 | LL | Union { a: 0 }; | ^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:125:5 + --> tests/ui/no_effect.rs:130:5 | LL | Enum::Tuple(0); | ^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:127:5 + --> tests/ui/no_effect.rs:133:5 | LL | Enum::Struct { field: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:129:5 + --> tests/ui/no_effect.rs:136:5 | LL | 5 + 6; | ^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:131:5 + --> tests/ui/no_effect.rs:139:5 | LL | *&42; | ^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:133:5 + --> tests/ui/no_effect.rs:142:5 | LL | &6; | ^^^ error: statement with no effect - --> tests/ui/no_effect.rs:135:5 + --> tests/ui/no_effect.rs:145:5 | LL | (5, 6, 7); | ^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:137:5 + --> tests/ui/no_effect.rs:148:5 | LL | ..; | ^^^ error: statement with no effect - --> tests/ui/no_effect.rs:139:5 + --> tests/ui/no_effect.rs:151:5 | LL | 5..; | ^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:141:5 + --> tests/ui/no_effect.rs:154:5 | LL | ..5; | ^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:143:5 + --> tests/ui/no_effect.rs:157:5 | LL | 5..6; | ^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:145:5 + --> tests/ui/no_effect.rs:160:5 | LL | 5..=6; | ^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:147:5 + --> tests/ui/no_effect.rs:163:5 | LL | [42, 55]; | ^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:149:5 + --> tests/ui/no_effect.rs:166:5 | LL | [42, 55][1]; | ^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:151:5 + --> tests/ui/no_effect.rs:169:5 | LL | (42, 55).1; | ^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:153:5 + --> tests/ui/no_effect.rs:172:5 | LL | [42; 55]; | ^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:155:5 + --> tests/ui/no_effect.rs:175:5 | LL | [42; 55][13]; | ^^^^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:158:5 + --> tests/ui/no_effect.rs:179:5 | LL | || x += 5; | ^^^^^^^^^^ error: statement with no effect - --> tests/ui/no_effect.rs:161:5 + --> tests/ui/no_effect.rs:183:5 | LL | FooString { s: s }; | ^^^^^^^^^^^^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:163:9 + --> tests/ui/no_effect.rs:186:9 | LL | let _unused = 1; | ^^^^^^^ @@ -149,19 +149,19 @@ LL | let _unused = 1; = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]` error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:166:9 + --> tests/ui/no_effect.rs:189:9 | LL | let _penguin = || println!("Some helpful closure"); | ^^^^^^^^ error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:168:9 + --> tests/ui/no_effect.rs:192:9 | LL | let _duck = Struct { field: 0 }; | ^^^^^ error: binding to `_` prefixed variable with no side-effect - --> tests/ui/no_effect.rs:170:9 + --> tests/ui/no_effect.rs:195:9 | LL | let _cat = [2, 4, 6, 8][2]; | ^^^^ diff --git a/src/tools/clippy/tests/ui/no_effect_async_fn.rs b/src/tools/clippy/tests/ui/no_effect_async_fn.rs index ef0f3d1df1acc..a036a7e27bef6 100644 --- a/src/tools/clippy/tests/ui/no_effect_async_fn.rs +++ b/src/tools/clippy/tests/ui/no_effect_async_fn.rs @@ -11,14 +11,14 @@ impl AsyncTrait for Bar { // Shouldn't lint `binding to `_` prefixed variable with no side-effect` async fn bar(_i: u64) { let _a = 0; - //~^ ERROR: binding to `_` prefixed variable with no side-effect + //~^ no_effect_underscore_binding // Shouldn't lint `binding to `_` prefixed variable with no side-effect` let _b = num(); let _ = async { let _c = 0; - //~^ ERROR: binding to `_` prefixed variable with no side-effect + //~^ no_effect_underscore_binding // Shouldn't lint `binding to `_` prefixed variable with no side-effect` let _d = num(); @@ -30,14 +30,14 @@ impl AsyncTrait for Bar { // Shouldn't lint `binding to `_` prefixed variable with no side-effect` async fn foo(_i: u64) { let _a = 0; - //~^ ERROR: binding to `_` prefixed variable with no side-effect + //~^ no_effect_underscore_binding // Shouldn't lint `binding to `_` prefixed variable with no side-effect` let _b = num(); let _ = async { let _c = 0; - //~^ ERROR: binding to `_` prefixed variable with no side-effect + //~^ no_effect_underscore_binding // Shouldn't lint `binding to `_` prefixed variable with no side-effect` let _d = num(); diff --git a/src/tools/clippy/tests/ui/no_effect_replace.rs b/src/tools/clippy/tests/ui/no_effect_replace.rs index e4fd5caae2a5d..245898f50740c 100644 --- a/src/tools/clippy/tests/ui/no_effect_replace.rs +++ b/src/tools/clippy/tests/ui/no_effect_replace.rs @@ -2,30 +2,35 @@ fn main() { let _ = "12345".replace('1', "1"); - //~^ ERROR: replacing text with itself - //~| NOTE: `-D clippy::no-effect-replace` implied by `-D warnings` + //~^ no_effect_replace + let _ = "12345".replace("12", "12"); - //~^ ERROR: replacing text with itself + //~^ no_effect_replace + let _ = String::new().replace("12", "12"); - //~^ ERROR: replacing text with itself + //~^ no_effect_replace let _ = "12345".replacen('1', "1", 1); - //~^ ERROR: replacing text with itself + //~^ no_effect_replace + let _ = "12345".replacen("12", "12", 1); - //~^ ERROR: replacing text with itself + //~^ no_effect_replace + let _ = String::new().replacen("12", "12", 1); - //~^ ERROR: replacing text with itself + //~^ no_effect_replace let _ = "12345".replace("12", "22"); let _ = "12345".replacen("12", "22", 1); let mut x = X::default(); let _ = "hello".replace(&x.f(), &x.f()); - //~^ ERROR: replacing text with itself + //~^ no_effect_replace + let _ = "hello".replace(&x.f(), &x.ff()); let _ = "hello".replace(&y(), &y()); - //~^ ERROR: replacing text with itself + //~^ no_effect_replace + let _ = "hello".replace(&y(), &z()); let _ = Replaceme.replace("a", "a"); diff --git a/src/tools/clippy/tests/ui/no_effect_replace.stderr b/src/tools/clippy/tests/ui/no_effect_replace.stderr index ded86c5c5b8d2..33d13b1d72e81 100644 --- a/src/tools/clippy/tests/ui/no_effect_replace.stderr +++ b/src/tools/clippy/tests/ui/no_effect_replace.stderr @@ -14,37 +14,37 @@ LL | let _ = "12345".replace("12", "12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:9:13 + --> tests/ui/no_effect_replace.rs:10:13 | LL | let _ = String::new().replace("12", "12"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:12:13 + --> tests/ui/no_effect_replace.rs:13:13 | LL | let _ = "12345".replacen('1', "1", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:14:13 + --> tests/ui/no_effect_replace.rs:16:13 | LL | let _ = "12345".replacen("12", "12", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:16:13 + --> tests/ui/no_effect_replace.rs:19:13 | LL | let _ = String::new().replacen("12", "12", 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:23:13 + --> tests/ui/no_effect_replace.rs:26:13 | LL | let _ = "hello".replace(&x.f(), &x.f()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: replacing text with itself - --> tests/ui/no_effect_replace.rs:27:13 + --> tests/ui/no_effect_replace.rs:31:13 | LL | let _ = "hello".replace(&y(), &y()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/no_effect_return.rs b/src/tools/clippy/tests/ui/no_effect_return.rs index e46c0d73518b9..4ba2fe07785d0 100644 --- a/src/tools/clippy/tests/ui/no_effect_return.rs +++ b/src/tools/clippy/tests/ui/no_effect_return.rs @@ -7,8 +7,7 @@ use std::ops::ControlFlow; fn a() -> u32 { { 0u32; - //~^ ERROR: statement with no effect - //~| NOTE: `-D clippy::no-effect` implied by `-D warnings` + //~^ no_effect } 0 } @@ -16,7 +15,7 @@ fn a() -> u32 { async fn b() -> u32 { { 0u32; - //~^ ERROR: statement with no effect + //~^ no_effect } 0 } @@ -25,7 +24,7 @@ type C = i32; async fn c() -> C { { 0i32 as C; - //~^ ERROR: statement with no effect + //~^ no_effect } 0 } @@ -34,7 +33,8 @@ fn d() -> u128 { { // not last stmt 0u128; - //~^ ERROR: statement with no effect + //~^ no_effect + println!("lol"); } 0 @@ -44,7 +44,7 @@ fn e() -> u32 { { // mismatched types 0u16; - //~^ ERROR: statement with no effect + //~^ no_effect } 0 } @@ -52,7 +52,7 @@ fn e() -> u32 { fn f() -> [u16; 1] { { [1u16]; - //~^ ERROR: statement with no effect + //~^ no_effect } [1] } @@ -60,7 +60,7 @@ fn f() -> [u16; 1] { fn g() -> ControlFlow<()> { { ControlFlow::Break::<()>(()); - //~^ ERROR: statement with no effect + //~^ no_effect } ControlFlow::Continue(()) } @@ -78,7 +78,7 @@ fn i() -> () { { // does not suggest on function with explicit unit return type (); - //~^ ERROR: statement with no effect + //~^ no_effect } () } @@ -87,7 +87,7 @@ fn j() { { // does not suggest on function without explicit return type (); - //~^ ERROR: statement with no effect + //~^ no_effect } () } diff --git a/src/tools/clippy/tests/ui/no_effect_return.stderr b/src/tools/clippy/tests/ui/no_effect_return.stderr index 3cfe375d034ad..e7bf7e4cd4f43 100644 --- a/src/tools/clippy/tests/ui/no_effect_return.stderr +++ b/src/tools/clippy/tests/ui/no_effect_return.stderr @@ -10,7 +10,7 @@ LL | 0u32; = help: to override `-D warnings` add `#[allow(clippy::no_effect)]` error: statement with no effect - --> tests/ui/no_effect_return.rs:18:9 + --> tests/ui/no_effect_return.rs:17:9 | LL | 0u32; | -^^^^ @@ -18,7 +18,7 @@ LL | 0u32; | help: did you mean to return it?: `return` error: statement with no effect - --> tests/ui/no_effect_return.rs:27:9 + --> tests/ui/no_effect_return.rs:26:9 | LL | 0i32 as C; | -^^^^^^^^^ @@ -26,7 +26,7 @@ LL | 0i32 as C; | help: did you mean to return it?: `return` error: statement with no effect - --> tests/ui/no_effect_return.rs:36:9 + --> tests/ui/no_effect_return.rs:35:9 | LL | 0u128; | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs index 8be149d186379..0d09b3ceecde7 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs @@ -4,28 +4,27 @@ #[unsafe(no_mangle)] fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI -//~| NOTE: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` +//~^ no_mangle_with_rust_abi #[unsafe(no_mangle)] pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI +//~^ no_mangle_with_rust_abi /// # Safety /// This function shouldn't be called unless the horsemen are ready #[unsafe(no_mangle)] pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI +//~^ no_mangle_with_rust_abi /// # Safety /// This function shouldn't be called unless the horsemen are ready #[unsafe(no_mangle)] unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI +//~^ no_mangle_with_rust_abi #[unsafe(no_mangle)] fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( - //~^ ERROR: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI + //~^ no_mangle_with_rust_abi arg_one: u32, arg_two: usize, ) -> u32 { @@ -51,6 +50,7 @@ extern "C" { mod r#fn { #[unsafe(no_mangle)] pub(in super::r#fn) fn with_some_fn_around() {} + //~^ no_mangle_with_rust_abi } fn main() { diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr index a00ebe5e1ac73..871f38e94b632 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.stderr @@ -16,7 +16,7 @@ LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} | +++++++++++++ error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi.rs:11:1 + --> tests/ui/no_mangle_with_rust_abi.rs:10:1 | LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} | +++++++++++++ error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi.rs:17:1 + --> tests/ui/no_mangle_with_rust_abi.rs:16:1 | LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) | +++++++++++++ error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi.rs:23:1 + --> tests/ui/no_mangle_with_rust_abi.rs:22:1 | LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} | +++++++++++++ error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi.rs:27:1 + --> tests/ui/no_mangle_with_rust_abi.rs:26:1 | LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( LL | | @@ -80,7 +80,7 @@ LL | extern "Rust" fn rust_abi_multiline_function_really_long_name_to_overflow_a | +++++++++++++ error: `#[unsafe(no_mangle)]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi.rs:53:5 + --> tests/ui/no_mangle_with_rust_abi.rs:52:5 | LL | pub(in super::r#fn) fn with_some_fn_around() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.rs index c7c9733534800..3d5c70cad2f3e 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.rs +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.rs @@ -8,28 +8,27 @@ #[no_mangle] fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI -//~| NOTE: `-D clippy::no-mangle-with-rust-abi` implied by `-D warnings` +//~^ no_mangle_with_rust_abi #[no_mangle] pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI +//~^ no_mangle_with_rust_abi /// # Safety /// This function shouldn't be called unless the horsemen are ready #[no_mangle] pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI +//~^ no_mangle_with_rust_abi /// # Safety /// This function shouldn't be called unless the horsemen are ready #[no_mangle] unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} -//~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI +//~^ no_mangle_with_rust_abi #[no_mangle] fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( - //~^ ERROR: `#[no_mangle]` set on a function with the default (`Rust`) ABI + //~^ no_mangle_with_rust_abi arg_one: u32, arg_two: usize, ) -> u32 { diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.stderr b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.stderr index 15075be72d0bf..abae8fafbeeef 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.stderr +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi_2021.stderr @@ -16,7 +16,7 @@ LL | extern "Rust" fn rust_abi_fn_one(arg_one: u32, arg_two: usize) {} | +++++++++++++ error: `#[no_mangle]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi_2021.rs:15:1 + --> tests/ui/no_mangle_with_rust_abi_2021.rs:14:1 | LL | pub fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | pub extern "Rust" fn rust_abi_fn_two(arg_one: u32, arg_two: usize) {} | +++++++++++++ error: `#[no_mangle]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi_2021.rs:21:1 + --> tests/ui/no_mangle_with_rust_abi_2021.rs:20:1 | LL | pub unsafe fn rust_abi_fn_three(arg_one: u32, arg_two: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | pub unsafe extern "Rust" fn rust_abi_fn_three(arg_one: u32, arg_two: usize) | +++++++++++++ error: `#[no_mangle]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi_2021.rs:27:1 + --> tests/ui/no_mangle_with_rust_abi_2021.rs:26:1 | LL | unsafe fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | unsafe extern "Rust" fn rust_abi_fn_four(arg_one: u32, arg_two: usize) {} | +++++++++++++ error: `#[no_mangle]` set on a function with the default (`Rust`) ABI - --> tests/ui/no_mangle_with_rust_abi_2021.rs:31:1 + --> tests/ui/no_mangle_with_rust_abi_2021.rs:30:1 | LL | / fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lines( LL | | diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs index a36c7ed44c247..7d101915517fe 100644 --- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs +++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.rs @@ -12,10 +12,12 @@ struct A(u32); impl Clone for A { fn clone(&self) -> Self { + //~^ non_canonical_clone_impl Self(self.0) } fn clone_from(&mut self, source: &Self) { + //~^ non_canonical_clone_impl source.clone(); *self = source.clone(); } @@ -83,10 +85,12 @@ struct F(u32); impl Clone for F { fn clone(&self) -> Self { + //~^ non_canonical_clone_impl Self(self.0) } fn clone_from(&mut self, source: &Self) { + //~^ non_canonical_clone_impl source.clone(); *self = source.clone(); } diff --git a/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr index f7cad58150f7d..5500984527170 100644 --- a/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr +++ b/src/tools/clippy/tests/ui/non_canonical_clone_impl.stderr @@ -3,6 +3,7 @@ error: non-canonical implementation of `clone` on a `Copy` type | LL | fn clone(&self) -> Self { | _____________________________^ +LL | | LL | | Self(self.0) LL | | } | |_____^ help: change this to: `{ *self }` @@ -11,27 +12,30 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::non_canonical_clone_impl)]` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:18:5 + --> tests/ui/non_canonical_clone_impl.rs:19:5 | LL | / fn clone_from(&mut self, source: &Self) { +LL | | LL | | source.clone(); LL | | *self = source.clone(); LL | | } | |_____^ help: remove it error: non-canonical implementation of `clone` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:85:29 + --> tests/ui/non_canonical_clone_impl.rs:87:29 | LL | fn clone(&self) -> Self { | _____________________________^ +LL | | LL | | Self(self.0) LL | | } | |_____^ help: change this to: `{ *self }` error: unnecessary implementation of `clone_from` on a `Copy` type - --> tests/ui/non_canonical_clone_impl.rs:89:5 + --> tests/ui/non_canonical_clone_impl.rs:92:5 | LL | / fn clone_from(&mut self, source: &Self) { +LL | | LL | | source.clone(); LL | | *self = source.clone(); LL | | } diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed index d444a753697f0..8774c666db11f 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed @@ -14,6 +14,7 @@ impl Ord for A { } impl PartialOrd for A { + //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } @@ -46,6 +47,7 @@ impl Ord for C { } impl PartialOrd for C { + //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs index dc6c4354604d0..568b97c8fff7b 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs @@ -14,6 +14,7 @@ impl Ord for A { } impl PartialOrd for A { + //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, other: &Self) -> Option { todo!(); } @@ -48,6 +49,7 @@ impl Ord for C { } impl PartialOrd for C { + //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, _: &Self) -> Option { todo!(); } diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr index 9f0c2ec43015a..86845df4ea906 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr @@ -2,6 +2,7 @@ error: non-canonical implementation of `partial_cmp` on an `Ord` type --> tests/ui/non_canonical_partial_ord_impl.rs:16:1 | LL | / impl PartialOrd for A { +LL | | LL | | fn partial_cmp(&self, other: &Self) -> Option { | | _____________________________________________________________- LL | || todo!(); @@ -14,9 +15,10 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::non_canonical_partial_ord_impl)]` error: non-canonical implementation of `partial_cmp` on an `Ord` type - --> tests/ui/non_canonical_partial_ord_impl.rs:50:1 + --> tests/ui/non_canonical_partial_ord_impl.rs:51:1 | LL | / impl PartialOrd for C { +LL | | LL | | fn partial_cmp(&self, _: &Self) -> Option { LL | | todo!(); LL | | } diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.rs index 2f8d5cf30c77a..99cd7ebac60cd 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.rs +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.rs @@ -21,6 +21,7 @@ impl cmp::Ord for A { } impl PartialOrd for A { + //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, other: &Self) -> Option { // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't // automatically applied @@ -44,6 +45,7 @@ impl cmp::Ord for B { } impl PartialOrd for B { + //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, other: &Self) -> Option { // This calls `B.cmp`, not `Ord::cmp`! Some(self.cmp(other)) diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.stderr index 8dd7face6ef4e..392b81dc8d742 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.stderr +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl_fully_qual.stderr @@ -2,6 +2,7 @@ error: non-canonical implementation of `partial_cmp` on an `Ord` type --> tests/ui/non_canonical_partial_ord_impl_fully_qual.rs:23:1 | LL | / impl PartialOrd for A { +LL | | LL | | fn partial_cmp(&self, other: &Self) -> Option { | | _____________________________________________________________- LL | || // NOTE: This suggestion is wrong, as `Ord` is not in scope. But this should be fine as it isn't @@ -16,9 +17,10 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::non_canonical_partial_ord_impl)]` error: non-canonical implementation of `partial_cmp` on an `Ord` type - --> tests/ui/non_canonical_partial_ord_impl_fully_qual.rs:46:1 + --> tests/ui/non_canonical_partial_ord_impl_fully_qual.rs:47:1 | LL | / impl PartialOrd for B { +LL | | LL | | fn partial_cmp(&self, other: &Self) -> Option { | | _____________________________________________________________- LL | || // This calls `B.cmp`, not `Ord::cmp`! diff --git a/src/tools/clippy/tests/ui/non_expressive_names.rs b/src/tools/clippy/tests/ui/non_expressive_names.rs index 987a4775ef074..b772c754f8b76 100644 --- a/src/tools/clippy/tests/ui/non_expressive_names.rs +++ b/src/tools/clippy/tests/ui/non_expressive_names.rs @@ -25,9 +25,12 @@ impl MaybeInst { } fn underscores_and_numbers() { - let _1 = 1; //~ERROR: consider choosing a more descriptive name - let ____1 = 1; //~ERROR: consider choosing a more descriptive name - let __1___2 = 12; //~ERROR: consider choosing a more descriptive name + let _1 = 1; + //~^ just_underscores_and_digits + let ____1 = 1; + //~^ just_underscores_and_digits + let __1___2 = 12; + //~^ just_underscores_and_digits let _1_ok = 1; } @@ -48,9 +51,12 @@ struct Bar; impl Bar { fn bar() { - let _1 = 1; //~ERROR: consider choosing a more descriptive name - let ____1 = 1; //~ERROR: consider choosing a more descriptive name - let __1___2 = 12; //~ERROR: consider choosing a more descriptive name + let _1 = 1; + //~^ just_underscores_and_digits + let ____1 = 1; + //~^ just_underscores_and_digits + let __1___2 = 12; + //~^ just_underscores_and_digits let _1_ok = 1; } } diff --git a/src/tools/clippy/tests/ui/non_expressive_names.stderr b/src/tools/clippy/tests/ui/non_expressive_names.stderr index d9c745f466b7b..3bd77a730fe78 100644 --- a/src/tools/clippy/tests/ui/non_expressive_names.stderr +++ b/src/tools/clippy/tests/ui/non_expressive_names.stderr @@ -8,31 +8,31 @@ LL | let _1 = 1; = help: to override `-D warnings` add `#[allow(clippy::just_underscores_and_digits)]` error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:29:9 + --> tests/ui/non_expressive_names.rs:30:9 | LL | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:30:9 + --> tests/ui/non_expressive_names.rs:32:9 | LL | let __1___2 = 12; | ^^^^^^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:51:13 + --> tests/ui/non_expressive_names.rs:54:13 | LL | let _1 = 1; | ^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:52:13 + --> tests/ui/non_expressive_names.rs:56:13 | LL | let ____1 = 1; | ^^^^^ error: consider choosing a more descriptive name - --> tests/ui/non_expressive_names.rs:53:13 + --> tests/ui/non_expressive_names.rs:58:13 | LL | let __1___2 = 12; | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.fixed b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed index 2fcecab452b8d..a2b69d0662ee9 100644 --- a/src/tools/clippy/tests/ui/non_minimal_cfg.fixed +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed @@ -1,12 +1,16 @@ #![allow(unused)] #[cfg(windows)] +//~^ non_minimal_cfg fn hermit() {} #[cfg(windows)] +//~^ non_minimal_cfg fn wasi() {} #[cfg(all(unix, not(windows)))] +//~^ non_minimal_cfg +//~| non_minimal_cfg fn the_end() {} #[cfg(any())] diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.rs b/src/tools/clippy/tests/ui/non_minimal_cfg.rs index e3ce11b73336b..7178cd189c08d 100644 --- a/src/tools/clippy/tests/ui/non_minimal_cfg.rs +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.rs @@ -1,12 +1,16 @@ #![allow(unused)] #[cfg(all(windows))] +//~^ non_minimal_cfg fn hermit() {} #[cfg(any(windows))] +//~^ non_minimal_cfg fn wasi() {} #[cfg(all(any(unix), all(not(windows))))] +//~^ non_minimal_cfg +//~| non_minimal_cfg fn the_end() {} #[cfg(any())] diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr index 707ff51d430c9..3bf306dd89c2f 100644 --- a/src/tools/clippy/tests/ui/non_minimal_cfg.stderr +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr @@ -8,19 +8,19 @@ LL | #[cfg(all(windows))] = help: to override `-D warnings` add `#[allow(clippy::non_minimal_cfg)]` error: unneeded sub `cfg` when there is only one condition - --> tests/ui/non_minimal_cfg.rs:6:7 + --> tests/ui/non_minimal_cfg.rs:7:7 | LL | #[cfg(any(windows))] | ^^^^^^^^^^^^ help: try: `windows` error: unneeded sub `cfg` when there is only one condition - --> tests/ui/non_minimal_cfg.rs:9:11 + --> tests/ui/non_minimal_cfg.rs:11:11 | LL | #[cfg(all(any(unix), all(not(windows))))] | ^^^^^^^^^ help: try: `unix` error: unneeded sub `cfg` when there is only one condition - --> tests/ui/non_minimal_cfg.rs:9:22 + --> tests/ui/non_minimal_cfg.rs:11:22 | LL | #[cfg(all(any(unix), all(not(windows))))] | ^^^^^^^^^^^^^^^^^ help: try: `not(windows)` diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.rs b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs index f9e3ba4dacdad..d073feedb1da2 100644 --- a/src/tools/clippy/tests/ui/non_minimal_cfg2.rs +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs @@ -1,3 +1,4 @@ +//@require-annotations-for-level: WARN #![allow(unused)] #[cfg(all())] diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr index 6d86e931edce9..169d2989aa13d 100644 --- a/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr @@ -1,5 +1,5 @@ error: unneeded sub `cfg` when there is no condition - --> tests/ui/non_minimal_cfg2.rs:3:7 + --> tests/ui/non_minimal_cfg2.rs:4:7 | LL | #[cfg(all())] | ^^^^^ diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed index f68d5e30d27e7..83f8991c94f81 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed @@ -10,11 +10,13 @@ fn main() { // OpenOptionsExt::mode let mut options = OpenOptions::new(); options.mode(0o440); + //~^ non_octal_unix_permissions options.mode(0o400); options.mode(permissions); // PermissionsExt::from_mode let _permissions = Permissions::from_mode(0o647); + //~^ non_octal_unix_permissions let _permissions = Permissions::from_mode(0o000); let _permissions = Permissions::from_mode(permissions); @@ -24,6 +26,7 @@ fn main() { let mut permissions = metadata.permissions(); permissions.set_mode(0o644); + //~^ non_octal_unix_permissions permissions.set_mode(0o704); // no error permissions.set_mode(0b111_000_100); @@ -31,6 +34,7 @@ fn main() { // DirBuilderExt::mode let mut builder = DirBuilder::new(); builder.mode(0o755); + //~^ non_octal_unix_permissions builder.mode(0o406); // no error permissions.set_mode(0b111000100); diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs index 647c3769d2c3f..ba1ee10a27871 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs @@ -10,11 +10,13 @@ fn main() { // OpenOptionsExt::mode let mut options = OpenOptions::new(); options.mode(440); + //~^ non_octal_unix_permissions options.mode(0o400); options.mode(permissions); // PermissionsExt::from_mode let _permissions = Permissions::from_mode(647); + //~^ non_octal_unix_permissions let _permissions = Permissions::from_mode(0o000); let _permissions = Permissions::from_mode(permissions); @@ -24,6 +26,7 @@ fn main() { let mut permissions = metadata.permissions(); permissions.set_mode(644); + //~^ non_octal_unix_permissions permissions.set_mode(0o704); // no error permissions.set_mode(0b111_000_100); @@ -31,6 +34,7 @@ fn main() { // DirBuilderExt::mode let mut builder = DirBuilder::new(); builder.mode(755); + //~^ non_octal_unix_permissions builder.mode(0o406); // no error permissions.set_mode(0b111000100); diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr index 890b308a1dc56..9027617c813a5 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.stderr @@ -8,19 +8,19 @@ LL | options.mode(440); = help: to override `-D warnings` add `#[allow(clippy::non_octal_unix_permissions)]` error: using a non-octal value to set unix file permissions - --> tests/ui/non_octal_unix_permissions.rs:17:47 + --> tests/ui/non_octal_unix_permissions.rs:18:47 | LL | let _permissions = Permissions::from_mode(647); | ^^^ help: consider using an octal literal instead: `0o647` error: using a non-octal value to set unix file permissions - --> tests/ui/non_octal_unix_permissions.rs:26:26 + --> tests/ui/non_octal_unix_permissions.rs:28:26 | LL | permissions.set_mode(644); | ^^^ help: consider using an octal literal instead: `0o644` error: using a non-octal value to set unix file permissions - --> tests/ui/non_octal_unix_permissions.rs:33:18 + --> tests/ui/non_octal_unix_permissions.rs:36:18 | LL | builder.mode(755); | ^^^ help: consider using an octal literal instead: `0o755` diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_no_std.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_no_std.rs index 6208612c69830..1170696b20308 100644 --- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_no_std.rs +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_no_std.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build:once_cell.rs //@aux-build:lazy_static.rs diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_other_once_cell.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_other_once_cell.rs index 8701a4b7729ad..f6d4f7250915f 100644 --- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_other_once_cell.rs +++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_other_once_cell.rs @@ -1,3 +1,4 @@ +//@ check-pass //@aux-build:once_cell.rs #![warn(clippy::non_std_lazy_statics)] diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions.fixed b/src/tools/clippy/tests/ui/non_zero_suggestions.fixed index e67c992fdde01..4573896ecd673 100644 --- a/src/tools/clippy/tests/ui/non_zero_suggestions.fixed +++ b/src/tools/clippy/tests/ui/non_zero_suggestions.fixed @@ -7,19 +7,19 @@ fn main() { let x: u64 = 100; let y = NonZeroU32::new(10).unwrap(); let r1 = x / NonZeroU64::from(y); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions let r2 = x % NonZeroU64::from(y); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions // U16 -> U32 let a: u32 = 50; let b = NonZeroU16::new(5).unwrap(); let r3 = a / NonZeroU32::from(b); - //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions let x = NonZeroU64::from(NonZeroU32::new(5).unwrap()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions /// Negative test cases (lint should not trigger) // Left hand side expressions should not be triggered @@ -50,7 +50,7 @@ fn main() { // Additional function to test the lint in a different context fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { x / NonZeroU64::from(y) - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions } struct Calculator { @@ -60,6 +60,6 @@ struct Calculator { impl Calculator { fn divide(&self, divisor: NonZeroU32) -> u64 { self.value / NonZeroU64::from(divisor) - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions } } diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions.rs b/src/tools/clippy/tests/ui/non_zero_suggestions.rs index de82371a8f294..3e7081e0c1c0c 100644 --- a/src/tools/clippy/tests/ui/non_zero_suggestions.rs +++ b/src/tools/clippy/tests/ui/non_zero_suggestions.rs @@ -7,19 +7,19 @@ fn main() { let x: u64 = 100; let y = NonZeroU32::new(10).unwrap(); let r1 = x / u64::from(y.get()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions let r2 = x % u64::from(y.get()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions // U16 -> U32 let a: u32 = 50; let b = NonZeroU16::new(5).unwrap(); let r3 = a / u32::from(b.get()); - //~^ ERROR: consider using `NonZeroU32::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions let x = u64::from(NonZeroU32::new(5).unwrap().get()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions /// Negative test cases (lint should not trigger) // Left hand side expressions should not be triggered @@ -50,7 +50,7 @@ fn main() { // Additional function to test the lint in a different context fn divide_numbers(x: u64, y: NonZeroU32) -> u64 { x / u64::from(y.get()) - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions } struct Calculator { @@ -60,6 +60,6 @@ struct Calculator { impl Calculator { fn divide(&self, divisor: NonZeroU32) -> u64 { self.value / u64::from(divisor.get()) - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions } } diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.rs b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.rs index 193c710e589ff..1224356236c71 100644 --- a/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.rs +++ b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.rs @@ -4,11 +4,12 @@ use std::num::{NonZeroI8, NonZeroI16, NonZeroU8, NonZeroU16, NonZeroU32, NonZero fn main() { let x: u64 = u64::from(NonZeroU32::new(5).unwrap().get()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions let n = NonZeroU32::new(20).unwrap(); let y = u64::from(n.get()); - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions + some_fn_that_only_takes_u64(y); let m = NonZeroU32::try_from(1).unwrap(); @@ -17,7 +18,7 @@ fn main() { fn return_non_zero(x: u64, y: NonZeroU32) -> u64 { u64::from(y.get()) - //~^ ERROR: consider using `NonZeroU64::from()` for more efficient and type-safe conversion + //~^ non_zero_suggestions } fn some_fn_that_only_takes_u64(_: u64) {} diff --git a/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.stderr b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.stderr index 787179f2a2d64..d2ac983d4f7f0 100644 --- a/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.stderr +++ b/src/tools/clippy/tests/ui/non_zero_suggestions_unfixable.stderr @@ -14,7 +14,7 @@ LL | let y = u64::from(n.get()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(n)` error: consider using `NonZeroU64::from()` for more efficient and type-safe conversion - --> tests/ui/non_zero_suggestions_unfixable.rs:19:5 + --> tests/ui/non_zero_suggestions_unfixable.rs:20:5 | LL | u64::from(y.get()) | ^^^^^^^^^^^^^^^^^^ help: replace with: `NonZeroU64::from(y)` diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs index 52b0155a762ea..a155ff3508be0 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs @@ -15,23 +15,28 @@ fn main() { let d: bool = unimplemented!(); let e: bool = unimplemented!(); let _ = !true; - //~^ ERROR: this boolean expression can be simplified - //~| NOTE: `-D clippy::nonminimal-bool` implied by `-D warnings` + //~^ nonminimal_bool + let _ = !false; - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = !!a; - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = false || a; - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + // don't lint on cfgs let _ = cfg!(you_shall_not_not_pass) && a; let _ = a || !b || !c || !d || !e; let _ = !(!a && b); - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = !(!a || b); - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = !a && !(b && c); - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool } fn equality_stuff() { @@ -40,15 +45,19 @@ fn equality_stuff() { let c: i32 = unimplemented!(); let d: i32 = unimplemented!(); let _ = a == b && c == 5 && a == b; - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = a == b || c == 5 || a == b; - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = a == b && c == 5 && b == a; - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = a != b || !(a != b || c == d); - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + let _ = a != b && !(a != b && c == d); - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool } fn issue3847(a: u32, b: u32) -> bool { @@ -79,7 +88,8 @@ fn check_expect() { fn issue9428() { if matches!(true, true) && true { - //~^ ERROR: this boolean expression can be simplified + //~^ nonminimal_bool + println!("foo"); } } @@ -158,19 +168,35 @@ fn issue11932() { fn issue_5794() { let a = 0; - if !(12 == a) {} //~ ERROR: this boolean expression can be simplified - if !(a == 12) {} //~ ERROR: this boolean expression can be simplified - if !(12 != a) {} //~ ERROR: this boolean expression can be simplified - if !(a != 12) {} //~ ERROR: this boolean expression can be simplified + if !(12 == a) {} + //~^ nonminimal_bool + if !(a == 12) {} + //~^ nonminimal_bool + if !(12 != a) {} + //~^ nonminimal_bool + if !(a != 12) {} + //~^ nonminimal_bool let b = true; let c = false; - if !b == true {} //~ ERROR: this boolean expression can be simplified - if !b != true {} //~ ERROR: this boolean expression can be simplified - if true == !b {} //~ ERROR: this boolean expression can be simplified - if true != !b {} //~ ERROR: this boolean expression can be simplified - if !b == !c {} //~ ERROR: this boolean expression can be simplified - if !b != !c {} //~ ERROR: this boolean expression can be simplified + if !b == true {} + //~^ nonminimal_bool + //~| bool_comparison + //~| bool_comparison + if !b != true {} + //~^ nonminimal_bool + //~| bool_comparison + if true == !b {} + //~^ nonminimal_bool + //~| bool_comparison + //~| bool_comparison + if true != !b {} + //~^ nonminimal_bool + //~| bool_comparison + if !b == !c {} + //~^ nonminimal_bool + if !b != !c {} + //~^ nonminimal_bool } fn issue_12371(x: usize) -> bool { @@ -183,3 +209,10 @@ fn issue_12371(x: usize) -> bool { fn many_ops(a: bool, b: bool, c: bool, d: bool, e: bool, f: bool) -> bool { (a && c && f) || (!a && b && !d) || (!b && !c && !e) || (d && e && !f) } + +fn issue14184(a: f32, b: bool) { + if !(a < 2.0 && !b) { + //~^ nonminimal_bool + println!("Hi"); + } +} diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr index 56d6eb10ac038..336cce40abf0d 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr @@ -14,37 +14,37 @@ LL | let _ = !false; | ^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:22:13 + --> tests/ui/nonminimal_bool.rs:23:13 | LL | let _ = !!a; | ^^^ help: try: `a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:24:13 + --> tests/ui/nonminimal_bool.rs:26:13 | LL | let _ = false || a; | ^^^^^^^^^^ help: try: `a` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:29:13 + --> tests/ui/nonminimal_bool.rs:32:13 | LL | let _ = !(!a && b); | ^^^^^^^^^^ help: try: `a || !b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:31:13 + --> tests/ui/nonminimal_bool.rs:35:13 | LL | let _ = !(!a || b); | ^^^^^^^^^^ help: try: `a && !b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:33:13 + --> tests/ui/nonminimal_bool.rs:38:13 | LL | let _ = !a && !(b && c); | ^^^^^^^^^^^^^^^ help: try: `!(a || b && c)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:42:13 + --> tests/ui/nonminimal_bool.rs:47:13 | LL | let _ = a == b && c == 5 && a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -59,7 +59,7 @@ LL + let _ = a == b && c == 5; | error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:44:13 + --> tests/ui/nonminimal_bool.rs:50:13 | LL | let _ = a == b || c == 5 || a == b; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +74,7 @@ LL + let _ = a == b || c == 5; | error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:46:13 + --> tests/ui/nonminimal_bool.rs:53:13 | LL | let _ = a == b && c == 5 && b == a; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL + let _ = a == b && c == 5; | error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:48:13 + --> tests/ui/nonminimal_bool.rs:56:13 | LL | let _ = a != b || !(a != b || c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL + let _ = a != b || c != d; | error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:50:13 + --> tests/ui/nonminimal_bool.rs:59:13 | LL | let _ = a != b && !(a != b && c == d); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,43 +119,43 @@ LL + let _ = a != b && c != d; | error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:81:8 + --> tests/ui/nonminimal_bool.rs:90:8 | LL | if matches!(true, true) && true { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(true, true)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:161:8 + --> tests/ui/nonminimal_bool.rs:171:8 | LL | if !(12 == a) {} | ^^^^^^^^^^ help: try: `(12 != a)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:162:8 + --> tests/ui/nonminimal_bool.rs:173:8 | LL | if !(a == 12) {} | ^^^^^^^^^^ help: try: `(a != 12)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:163:8 + --> tests/ui/nonminimal_bool.rs:175:8 | LL | if !(12 != a) {} | ^^^^^^^^^^ help: try: `(12 == a)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:164:8 + --> tests/ui/nonminimal_bool.rs:177:8 | LL | if !(a != 12) {} | ^^^^^^^^^^ help: try: `(a == 12)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:168:8 + --> tests/ui/nonminimal_bool.rs:182:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try: `b != true` error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:168:8 + --> tests/ui/nonminimal_bool.rs:182:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try simplifying it as shown: `b != true` @@ -164,64 +164,70 @@ LL | if !b == true {} = help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]` error: equality checks against true are unnecessary - --> tests/ui/nonminimal_bool.rs:168:8 + --> tests/ui/nonminimal_bool.rs:182:8 | LL | if !b == true {} | ^^^^^^^^^^ help: try simplifying it as shown: `!b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:169:8 + --> tests/ui/nonminimal_bool.rs:186:8 | LL | if !b != true {} | ^^^^^^^^^^ help: try: `b == true` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:169:8 + --> tests/ui/nonminimal_bool.rs:186:8 | LL | if !b != true {} | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:189:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try: `true != b` error: this comparison might be written more concisely - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:189:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `true != b` error: equality checks against true are unnecessary - --> tests/ui/nonminimal_bool.rs:170:8 + --> tests/ui/nonminimal_bool.rs:189:8 | LL | if true == !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `!b` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:171:8 + --> tests/ui/nonminimal_bool.rs:193:8 | LL | if true != !b {} | ^^^^^^^^^^ help: try: `true == b` error: inequality checks against true can be replaced by a negation - --> tests/ui/nonminimal_bool.rs:171:8 + --> tests/ui/nonminimal_bool.rs:193:8 | LL | if true != !b {} | ^^^^^^^^^^ help: try simplifying it as shown: `!(!b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:172:8 + --> tests/ui/nonminimal_bool.rs:196:8 | LL | if !b == !c {} | ^^^^^^^^ help: try: `b == c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool.rs:173:8 + --> tests/ui/nonminimal_bool.rs:198:8 | LL | if !b != !c {} | ^^^^^^^^ help: try: `b != c` -error: aborting due to 29 previous errors +error: this boolean expression can be simplified + --> tests/ui/nonminimal_bool.rs:214:8 + | +LL | if !(a < 2.0 && !b) { + | ^^^^^^^^^^^^^^^^ help: try: `!(a < 2.0) || b` + +error: aborting due to 30 previous errors diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed index 65ccaaca89189..c2377491f25b1 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed @@ -6,18 +6,27 @@ fn methods_with_negation() { let b: Result = unimplemented!(); let _ = a.is_some(); let _ = a.is_none(); + //~^ nonminimal_bool let _ = a.is_none(); let _ = a.is_some(); + //~^ nonminimal_bool let _ = b.is_err(); let _ = b.is_ok(); + //~^ nonminimal_bool let _ = b.is_ok(); let _ = b.is_err(); + //~^ nonminimal_bool let c = false; let _ = a.is_none() || c; + //~^ nonminimal_bool let _ = a.is_none() && c; + //~^ nonminimal_bool let _ = !(!c ^ c) || a.is_none(); + //~^ nonminimal_bool let _ = (!c ^ c) || a.is_none(); + //~^ nonminimal_bool let _ = !c ^ c || a.is_none(); + //~^ nonminimal_bool } // Simplified versions of https://github.com/rust-lang/rust-clippy/issues/2638 @@ -90,11 +99,15 @@ fn dont_warn_for_custom_methods_with_negation() { fn warn_for_built_in_methods_with_negation() { let res: Result = Ok(1); if res.is_err() {} + //~^ nonminimal_bool if res.is_ok() {} + //~^ nonminimal_bool let res = Some(1); if res.is_none() {} + //~^ nonminimal_bool if res.is_some() {} + //~^ nonminimal_bool } #[allow(clippy::neg_cmp_op_on_partial_ord)] @@ -110,24 +123,34 @@ fn dont_warn_for_negated_partial_ord_comparison() { fn issue_12625() { let a = 0; let b = 0; - if ((a as u64) < b) {} //~ ERROR: this boolean expression can be simplified - if ((a as u64) < b) {} //~ ERROR: this boolean expression can be simplified - if (a as u64 > b) {} //~ ERROR: this boolean expression can be simplified + if ((a as u64) < b) {} + //~^ nonminimal_bool + if ((a as u64) < b) {} + //~^ nonminimal_bool + if (a as u64 > b) {} + //~^ nonminimal_bool } fn issue_12761() { let a = 0; let b = 0; let c = 0; - if (a < b) as i32 == c {} //~ ERROR: this boolean expression can be simplified - if (a < b) | (a > c) {} //~ ERROR: this boolean expression can be simplified + if (a < b) as i32 == c {} + //~^ nonminimal_bool + if (a < b) | (a > c) {} + //~^ nonminimal_bool + //~| nonminimal_bool let opt: Option = Some(1); let res: Result = Ok(1); - if res.is_err() as i32 == c {} //~ ERROR: this boolean expression can be simplified - if res.is_err() | opt.is_some() {} //~ ERROR: this boolean expression can be simplified + if res.is_err() as i32 == c {} + //~^ nonminimal_bool + if res.is_err() | opt.is_some() {} + //~^ nonminimal_bool + //~| nonminimal_bool fn a(a: bool) -> bool { - (4 <= 3).b() //~ ERROR: this boolean expression can be simplified + (4 <= 3).b() + //~^ nonminimal_bool } trait B { @@ -152,12 +175,18 @@ fn issue_13436() { _ = opt.is_some_and(|x| x == 1000); _ = opt.is_some_and(|x| x != 1000); _ = opt.is_some_and(not_zero); - _ = opt.is_none_or(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_none_or(|x| x > 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_none_or(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_none_or(|x| x < 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_none_or(|x| x != 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_none_or(|x| x == 1000); //~ ERROR: this boolean expression can be simplified + _ = opt.is_none_or(|x| x >= 1000); + //~^ nonminimal_bool + _ = opt.is_none_or(|x| x > 1000); + //~^ nonminimal_bool + _ = opt.is_none_or(|x| x <= 1000); + //~^ nonminimal_bool + _ = opt.is_none_or(|x| x < 1000); + //~^ nonminimal_bool + _ = opt.is_none_or(|x| x != 1000); + //~^ nonminimal_bool + _ = opt.is_none_or(|x| x == 1000); + //~^ nonminimal_bool _ = !opt.is_some_and(not_zero); _ = opt.is_none_or(|x| x < 1000); _ = opt.is_none_or(|x| x <= 1000); @@ -166,33 +195,45 @@ fn issue_13436() { _ = opt.is_none_or(|x| x == 1000); _ = opt.is_none_or(|x| x != 1000); _ = opt.is_none_or(not_zero); - _ = opt.is_some_and(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_some_and(|x| x > 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_some_and(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_some_and(|x| x < 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_some_and(|x| x != 1000); //~ ERROR: this boolean expression can be simplified - _ = opt.is_some_and(|x| x == 1000); //~ ERROR: this boolean expression can be simplified + _ = opt.is_some_and(|x| x >= 1000); + //~^ nonminimal_bool + _ = opt.is_some_and(|x| x > 1000); + //~^ nonminimal_bool + _ = opt.is_some_and(|x| x <= 1000); + //~^ nonminimal_bool + _ = opt.is_some_and(|x| x < 1000); + //~^ nonminimal_bool + _ = opt.is_some_and(|x| x != 1000); + //~^ nonminimal_bool + _ = opt.is_some_and(|x| x == 1000); + //~^ nonminimal_bool _ = !opt.is_none_or(not_zero); let opt = Some(true); _ = opt.is_some_and(|x| x); _ = opt.is_some_and(|x| !x); _ = !opt.is_some_and(|x| x); - _ = opt.is_none_or(|x| x); //~ ERROR: this boolean expression can be simplified + _ = opt.is_none_or(|x| x); + //~^ nonminimal_bool _ = opt.is_none_or(|x| x); _ = opt.is_none_or(|x| !x); _ = !opt.is_none_or(|x| x); - _ = opt.is_some_and(|x| x); //~ ERROR: this boolean expression can be simplified + _ = opt.is_some_and(|x| x); + //~^ nonminimal_bool let opt: Option> = Some(Ok(123)); _ = opt.is_some_and(|x| x.is_ok()); _ = opt.is_some_and(|x| x.is_err()); _ = opt.is_none_or(|x| x.is_ok()); _ = opt.is_none_or(|x| x.is_err()); - _ = opt.is_none_or(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified - _ = opt.is_none_or(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified - _ = opt.is_some_and(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified - _ = opt.is_some_and(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified + _ = opt.is_none_or(|x| x.is_err()); + //~^ nonminimal_bool + _ = opt.is_none_or(|x| x.is_ok()); + //~^ nonminimal_bool + _ = opt.is_some_and(|x| x.is_err()); + //~^ nonminimal_bool + _ = opt.is_some_and(|x| x.is_ok()); + //~^ nonminimal_bool #[clippy::msrv = "1.81"] fn before_stabilization() { diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs index 06db3a1d4a5cf..1ae0f0064c6b6 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs @@ -6,18 +6,27 @@ fn methods_with_negation() { let b: Result = unimplemented!(); let _ = a.is_some(); let _ = !a.is_some(); + //~^ nonminimal_bool let _ = a.is_none(); let _ = !a.is_none(); + //~^ nonminimal_bool let _ = b.is_err(); let _ = !b.is_err(); + //~^ nonminimal_bool let _ = b.is_ok(); let _ = !b.is_ok(); + //~^ nonminimal_bool let c = false; let _ = !(a.is_some() && !c); + //~^ nonminimal_bool let _ = !(a.is_some() || !c); + //~^ nonminimal_bool let _ = !(!c ^ c) || !a.is_some(); + //~^ nonminimal_bool let _ = (!c ^ c) || !a.is_some(); + //~^ nonminimal_bool let _ = !c ^ c || !a.is_some(); + //~^ nonminimal_bool } // Simplified versions of https://github.com/rust-lang/rust-clippy/issues/2638 @@ -90,11 +99,15 @@ fn dont_warn_for_custom_methods_with_negation() { fn warn_for_built_in_methods_with_negation() { let res: Result = Ok(1); if !res.is_ok() {} + //~^ nonminimal_bool if !res.is_err() {} + //~^ nonminimal_bool let res = Some(1); if !res.is_some() {} + //~^ nonminimal_bool if !res.is_none() {} + //~^ nonminimal_bool } #[allow(clippy::neg_cmp_op_on_partial_ord)] @@ -110,24 +123,34 @@ fn dont_warn_for_negated_partial_ord_comparison() { fn issue_12625() { let a = 0; let b = 0; - if !(a as u64 >= b) {} //~ ERROR: this boolean expression can be simplified - if !((a as u64) >= b) {} //~ ERROR: this boolean expression can be simplified - if !(a as u64 <= b) {} //~ ERROR: this boolean expression can be simplified + if !(a as u64 >= b) {} + //~^ nonminimal_bool + if !((a as u64) >= b) {} + //~^ nonminimal_bool + if !(a as u64 <= b) {} + //~^ nonminimal_bool } fn issue_12761() { let a = 0; let b = 0; let c = 0; - if !(a >= b) as i32 == c {} //~ ERROR: this boolean expression can be simplified - if !(a >= b) | !(a <= c) {} //~ ERROR: this boolean expression can be simplified + if !(a >= b) as i32 == c {} + //~^ nonminimal_bool + if !(a >= b) | !(a <= c) {} + //~^ nonminimal_bool + //~| nonminimal_bool let opt: Option = Some(1); let res: Result = Ok(1); - if !res.is_ok() as i32 == c {} //~ ERROR: this boolean expression can be simplified - if !res.is_ok() | !opt.is_none() {} //~ ERROR: this boolean expression can be simplified + if !res.is_ok() as i32 == c {} + //~^ nonminimal_bool + if !res.is_ok() | !opt.is_none() {} + //~^ nonminimal_bool + //~| nonminimal_bool fn a(a: bool) -> bool { - (!(4 > 3)).b() //~ ERROR: this boolean expression can be simplified + (!(4 > 3)).b() + //~^ nonminimal_bool } trait B { @@ -152,12 +175,18 @@ fn issue_13436() { _ = opt.is_some_and(|x| x == 1000); _ = opt.is_some_and(|x| x != 1000); _ = opt.is_some_and(not_zero); - _ = !opt.is_some_and(|x| x < 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_some_and(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_some_and(|x| x > 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_some_and(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_some_and(|x| x == 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_some_and(|x| x != 1000); //~ ERROR: this boolean expression can be simplified + _ = !opt.is_some_and(|x| x < 1000); + //~^ nonminimal_bool + _ = !opt.is_some_and(|x| x <= 1000); + //~^ nonminimal_bool + _ = !opt.is_some_and(|x| x > 1000); + //~^ nonminimal_bool + _ = !opt.is_some_and(|x| x >= 1000); + //~^ nonminimal_bool + _ = !opt.is_some_and(|x| x == 1000); + //~^ nonminimal_bool + _ = !opt.is_some_and(|x| x != 1000); + //~^ nonminimal_bool _ = !opt.is_some_and(not_zero); _ = opt.is_none_or(|x| x < 1000); _ = opt.is_none_or(|x| x <= 1000); @@ -166,33 +195,45 @@ fn issue_13436() { _ = opt.is_none_or(|x| x == 1000); _ = opt.is_none_or(|x| x != 1000); _ = opt.is_none_or(not_zero); - _ = !opt.is_none_or(|x| x < 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_none_or(|x| x <= 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_none_or(|x| x > 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_none_or(|x| x >= 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_none_or(|x| x == 1000); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_none_or(|x| x != 1000); //~ ERROR: this boolean expression can be simplified + _ = !opt.is_none_or(|x| x < 1000); + //~^ nonminimal_bool + _ = !opt.is_none_or(|x| x <= 1000); + //~^ nonminimal_bool + _ = !opt.is_none_or(|x| x > 1000); + //~^ nonminimal_bool + _ = !opt.is_none_or(|x| x >= 1000); + //~^ nonminimal_bool + _ = !opt.is_none_or(|x| x == 1000); + //~^ nonminimal_bool + _ = !opt.is_none_or(|x| x != 1000); + //~^ nonminimal_bool _ = !opt.is_none_or(not_zero); let opt = Some(true); _ = opt.is_some_and(|x| x); _ = opt.is_some_and(|x| !x); _ = !opt.is_some_and(|x| x); - _ = !opt.is_some_and(|x| !x); //~ ERROR: this boolean expression can be simplified + _ = !opt.is_some_and(|x| !x); + //~^ nonminimal_bool _ = opt.is_none_or(|x| x); _ = opt.is_none_or(|x| !x); _ = !opt.is_none_or(|x| x); - _ = !opt.is_none_or(|x| !x); //~ ERROR: this boolean expression can be simplified + _ = !opt.is_none_or(|x| !x); + //~^ nonminimal_bool let opt: Option> = Some(Ok(123)); _ = opt.is_some_and(|x| x.is_ok()); _ = opt.is_some_and(|x| x.is_err()); _ = opt.is_none_or(|x| x.is_ok()); _ = opt.is_none_or(|x| x.is_err()); - _ = !opt.is_some_and(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_some_and(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_none_or(|x| x.is_ok()); //~ ERROR: this boolean expression can be simplified - _ = !opt.is_none_or(|x| x.is_err()); //~ ERROR: this boolean expression can be simplified + _ = !opt.is_some_and(|x| x.is_ok()); + //~^ nonminimal_bool + _ = !opt.is_some_and(|x| x.is_err()); + //~^ nonminimal_bool + _ = !opt.is_none_or(|x| x.is_ok()); + //~^ nonminimal_bool + _ = !opt.is_none_or(|x| x.is_err()); + //~^ nonminimal_bool #[clippy::msrv = "1.81"] fn before_stabilization() { diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr index 66c50f9ff1e10..b5155b3b16968 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.stderr @@ -8,241 +8,241 @@ LL | let _ = !a.is_some(); = help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:10:13 + --> tests/ui/nonminimal_bool_methods.rs:11:13 | LL | let _ = !a.is_none(); | ^^^^^^^^^^^^ help: try: `a.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:12:13 + --> tests/ui/nonminimal_bool_methods.rs:14:13 | LL | let _ = !b.is_err(); | ^^^^^^^^^^^ help: try: `b.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:14:13 + --> tests/ui/nonminimal_bool_methods.rs:17:13 | LL | let _ = !b.is_ok(); | ^^^^^^^^^^ help: try: `b.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:16:13 + --> tests/ui/nonminimal_bool_methods.rs:20:13 | LL | let _ = !(a.is_some() && !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() || c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:17:13 + --> tests/ui/nonminimal_bool_methods.rs:22:13 | LL | let _ = !(a.is_some() || !c); | ^^^^^^^^^^^^^^^^^^^^ help: try: `a.is_none() && c` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:18:26 + --> tests/ui/nonminimal_bool_methods.rs:24:26 | LL | let _ = !(!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:19:25 + --> tests/ui/nonminimal_bool_methods.rs:26:25 | LL | let _ = (!c ^ c) || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:20:23 + --> tests/ui/nonminimal_bool_methods.rs:28:23 | LL | let _ = !c ^ c || !a.is_some(); | ^^^^^^^^^^^^ help: try: `a.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:92:8 + --> tests/ui/nonminimal_bool_methods.rs:101:8 | LL | if !res.is_ok() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:93:8 + --> tests/ui/nonminimal_bool_methods.rs:103:8 | LL | if !res.is_err() {} | ^^^^^^^^^^^^^ help: try: `res.is_ok()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:96:8 + --> tests/ui/nonminimal_bool_methods.rs:107:8 | LL | if !res.is_some() {} | ^^^^^^^^^^^^^^ help: try: `res.is_none()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:97:8 + --> tests/ui/nonminimal_bool_methods.rs:109:8 | LL | if !res.is_none() {} | ^^^^^^^^^^^^^^ help: try: `res.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:113:8 + --> tests/ui/nonminimal_bool_methods.rs:126:8 | LL | if !(a as u64 >= b) {} | ^^^^^^^^^^^^^^^^ help: try: `((a as u64) < b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:114:8 + --> tests/ui/nonminimal_bool_methods.rs:128:8 | LL | if !((a as u64) >= b) {} | ^^^^^^^^^^^^^^^^^^ help: try: `((a as u64) < b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:115:8 + --> tests/ui/nonminimal_bool_methods.rs:130:8 | LL | if !(a as u64 <= b) {} | ^^^^^^^^^^^^^^^^ help: try: `(a as u64 > b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:122:8 + --> tests/ui/nonminimal_bool_methods.rs:138:8 | LL | if !(a >= b) as i32 == c {} | ^^^^^^^^^ help: try: `(a < b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:123:8 + --> tests/ui/nonminimal_bool_methods.rs:140:8 | LL | if !(a >= b) | !(a <= c) {} | ^^^^^^^^^ help: try: `(a < b)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:123:20 + --> tests/ui/nonminimal_bool_methods.rs:140:20 | LL | if !(a >= b) | !(a <= c) {} | ^^^^^^^^^ help: try: `(a > c)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:126:8 + --> tests/ui/nonminimal_bool_methods.rs:145:8 | LL | if !res.is_ok() as i32 == c {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:127:8 + --> tests/ui/nonminimal_bool_methods.rs:147:8 | LL | if !res.is_ok() | !opt.is_none() {} | ^^^^^^^^^^^^ help: try: `res.is_err()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:127:23 + --> tests/ui/nonminimal_bool_methods.rs:147:23 | LL | if !res.is_ok() | !opt.is_none() {} | ^^^^^^^^^^^^^^ help: try: `opt.is_some()` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:130:9 + --> tests/ui/nonminimal_bool_methods.rs:152:9 | LL | (!(4 > 3)).b() | ^^^^^^^^^^ help: try: `(4 <= 3)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:155:9 + --> tests/ui/nonminimal_bool_methods.rs:178:9 | LL | _ = !opt.is_some_and(|x| x < 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x >= 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:156:9 + --> tests/ui/nonminimal_bool_methods.rs:180:9 | LL | _ = !opt.is_some_and(|x| x <= 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x > 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:157:9 + --> tests/ui/nonminimal_bool_methods.rs:182:9 | LL | _ = !opt.is_some_and(|x| x > 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x <= 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:158:9 + --> tests/ui/nonminimal_bool_methods.rs:184:9 | LL | _ = !opt.is_some_and(|x| x >= 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x < 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:159:9 + --> tests/ui/nonminimal_bool_methods.rs:186:9 | LL | _ = !opt.is_some_and(|x| x == 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x != 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:160:9 + --> tests/ui/nonminimal_bool_methods.rs:188:9 | LL | _ = !opt.is_some_and(|x| x != 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x == 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:169:9 + --> tests/ui/nonminimal_bool_methods.rs:198:9 | LL | _ = !opt.is_none_or(|x| x < 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x >= 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:170:9 + --> tests/ui/nonminimal_bool_methods.rs:200:9 | LL | _ = !opt.is_none_or(|x| x <= 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x > 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:171:9 + --> tests/ui/nonminimal_bool_methods.rs:202:9 | LL | _ = !opt.is_none_or(|x| x > 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x <= 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:172:9 + --> tests/ui/nonminimal_bool_methods.rs:204:9 | LL | _ = !opt.is_none_or(|x| x >= 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x < 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:173:9 + --> tests/ui/nonminimal_bool_methods.rs:206:9 | LL | _ = !opt.is_none_or(|x| x == 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x != 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:174:9 + --> tests/ui/nonminimal_bool_methods.rs:208:9 | LL | _ = !opt.is_none_or(|x| x != 1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x == 1000)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:181:9 + --> tests/ui/nonminimal_bool_methods.rs:216:9 | LL | _ = !opt.is_some_and(|x| !x); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:185:9 + --> tests/ui/nonminimal_bool_methods.rs:221:9 | LL | _ = !opt.is_none_or(|x| !x); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x)` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:192:9 + --> tests/ui/nonminimal_bool_methods.rs:229:9 | LL | _ = !opt.is_some_and(|x| x.is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x.is_err())` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:193:9 + --> tests/ui/nonminimal_bool_methods.rs:231:9 | LL | _ = !opt.is_some_and(|x| x.is_err()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_none_or(|x| x.is_ok())` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:194:9 + --> tests/ui/nonminimal_bool_methods.rs:233:9 | LL | _ = !opt.is_none_or(|x| x.is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x.is_err())` error: this boolean expression can be simplified - --> tests/ui/nonminimal_bool_methods.rs:195:9 + --> tests/ui/nonminimal_bool_methods.rs:235:9 | LL | _ = !opt.is_none_or(|x| x.is_err()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.is_some_and(|x| x.is_ok())` diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs b/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs index 60b8da30a2f13..850eba4851b8f 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods_unfixable.rs @@ -3,7 +3,9 @@ fn issue_13436() { let opt_opt = Some(Some(500)); - _ = !opt_opt.is_some_and(|x| !x.is_some_and(|y| y != 1000)); //~ ERROR: this boolean expression can be simplified + _ = !opt_opt.is_some_and(|x| !x.is_some_and(|y| y != 1000)); + //~^ nonminimal_bool + //~| nonminimal_bool } fn main() {} diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed index bfe1c5e10cf8d..66f5070787b09 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed @@ -1,18 +1,77 @@ #![warn(clippy::obfuscated_if_else)] -#![allow(clippy::unnecessary_lazy_evaluations, clippy::unit_arg, clippy::unused_unit)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::unit_arg, + clippy::unused_unit, + clippy::unwrap_or_default +)] fn main() { if true { "a" } else { "b" }; + //~^ obfuscated_if_else + if true { "a" } else { "b" }; + //~^ obfuscated_if_else let a = 1; if a == 1 { "a" } else { "b" }; + //~^ obfuscated_if_else + if a == 1 { "a" } else { "b" }; + //~^ obfuscated_if_else let partial = (a == 1).then_some("a"); partial.unwrap_or("b"); // not lint let mut a = 0; if true { a += 1 } else { () }; + //~^ obfuscated_if_else + if true { () } else { a += 2 }; + //~^ obfuscated_if_else + + let mut n = 1; + if true { n = 1 } else { n = 2 }; + //~^ obfuscated_if_else + if true { 1 } else { n * 2 }; + //~^ obfuscated_if_else + if true { n += 1 } else { () }; + //~^ obfuscated_if_else + + let _ = if true { 1 } else { n * 2 }; + //~^ obfuscated_if_else + + if true { 1 } else { Default::default() }; + //~^ obfuscated_if_else + + let partial = true.then_some(1); + partial.unwrap_or_else(|| n * 2); // not lint +} + +fn issue11141() { + // Parentheses are required around the left side of a binary expression + let _ = (if true { 40 } else { 17 }) | 2; + //~^ obfuscated_if_else + + // Parentheses are required only for the leftmost expression + let _ = (if true { 30 } else { 17 }) | if true { 2 } else { 3 } | if true { 10 } else { 1 }; + //~^ obfuscated_if_else + //~| obfuscated_if_else + //~| obfuscated_if_else + + // Parentheses are not required around the right side of a binary expression + let _ = 2 | if true { 40 } else { 17 }; + //~^ obfuscated_if_else + + // Parentheses are not required for a cast + let _ = if true { 42 } else { 17 } as u8; + //~^ obfuscated_if_else + + // Parentheses are not required for a deref + let _ = *if true { &42 } else { &17 }; + //~^ obfuscated_if_else + + // Parentheses are not required for a deref followed by a cast + let _ = *if true { &42 } else { &17 } as u8; + //~^ obfuscated_if_else } diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.rs b/src/tools/clippy/tests/ui/obfuscated_if_else.rs index 0ded2a2ceedfb..4efd740eb60bb 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.rs +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.rs @@ -1,18 +1,77 @@ #![warn(clippy::obfuscated_if_else)] -#![allow(clippy::unnecessary_lazy_evaluations, clippy::unit_arg, clippy::unused_unit)] +#![allow( + clippy::unnecessary_lazy_evaluations, + clippy::unit_arg, + clippy::unused_unit, + clippy::unwrap_or_default +)] fn main() { true.then_some("a").unwrap_or("b"); + //~^ obfuscated_if_else + true.then(|| "a").unwrap_or("b"); + //~^ obfuscated_if_else let a = 1; (a == 1).then_some("a").unwrap_or("b"); + //~^ obfuscated_if_else + (a == 1).then(|| "a").unwrap_or("b"); + //~^ obfuscated_if_else let partial = (a == 1).then_some("a"); partial.unwrap_or("b"); // not lint let mut a = 0; true.then_some(a += 1).unwrap_or(()); + //~^ obfuscated_if_else + true.then_some(()).unwrap_or(a += 2); + //~^ obfuscated_if_else + + let mut n = 1; + true.then(|| n = 1).unwrap_or_else(|| n = 2); + //~^ obfuscated_if_else + true.then_some(1).unwrap_or_else(|| n * 2); + //~^ obfuscated_if_else + true.then_some(n += 1).unwrap_or_else(|| ()); + //~^ obfuscated_if_else + + let _ = true.then_some(1).unwrap_or_else(|| n * 2); + //~^ obfuscated_if_else + + true.then_some(1).unwrap_or_else(Default::default); + //~^ obfuscated_if_else + + let partial = true.then_some(1); + partial.unwrap_or_else(|| n * 2); // not lint +} + +fn issue11141() { + // Parentheses are required around the left side of a binary expression + let _ = true.then_some(40).unwrap_or(17) | 2; + //~^ obfuscated_if_else + + // Parentheses are required only for the leftmost expression + let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1); + //~^ obfuscated_if_else + //~| obfuscated_if_else + //~| obfuscated_if_else + + // Parentheses are not required around the right side of a binary expression + let _ = 2 | true.then_some(40).unwrap_or(17); + //~^ obfuscated_if_else + + // Parentheses are not required for a cast + let _ = true.then_some(42).unwrap_or(17) as u8; + //~^ obfuscated_if_else + + // Parentheses are not required for a deref + let _ = *true.then_some(&42).unwrap_or(&17); + //~^ obfuscated_if_else + + // Parentheses are not required for a deref followed by a cast + let _ = *true.then_some(&42).unwrap_or(&17) as u8; + //~^ obfuscated_if_else } diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr index 9ce1f475c4803..d676c25669570 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr @@ -1,5 +1,5 @@ error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:5:5 + --> tests/ui/obfuscated_if_else.rs:10:5 | LL | true.then_some("a").unwrap_or("b"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` @@ -8,34 +8,112 @@ LL | true.then_some("a").unwrap_or("b"); = help: to override `-D warnings` add `#[allow(clippy::obfuscated_if_else)]` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:6:5 + --> tests/ui/obfuscated_if_else.rs:13:5 | LL | true.then(|| "a").unwrap_or("b"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { "a" } else { "b" }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:9:5 + --> tests/ui/obfuscated_if_else.rs:17:5 | LL | (a == 1).then_some("a").unwrap_or("b"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:10:5 + --> tests/ui/obfuscated_if_else.rs:20:5 | LL | (a == 1).then(|| "a").unwrap_or("b"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if a == 1 { "a" } else { "b" }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:16:5 + --> tests/ui/obfuscated_if_else.rs:27:5 | LL | true.then_some(a += 1).unwrap_or(()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { a += 1 } else { () }` error: this method chain can be written more clearly with `if .. else ..` - --> tests/ui/obfuscated_if_else.rs:17:5 + --> tests/ui/obfuscated_if_else.rs:30:5 | LL | true.then_some(()).unwrap_or(a += 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { a += 2 }` -error: aborting due to 6 previous errors +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:34:5 + | +LL | true.then(|| n = 1).unwrap_or_else(|| n = 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { n = 1 } else { n = 2 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:36:5 + | +LL | true.then_some(1).unwrap_or_else(|| n * 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { n * 2 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:38:5 + | +LL | true.then_some(n += 1).unwrap_or_else(|| ()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { n += 1 } else { () }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:41:13 + | +LL | let _ = true.then_some(1).unwrap_or_else(|| n * 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { n * 2 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:44:5 + | +LL | true.then_some(1).unwrap_or_else(Default::default); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:53:13 + | +LL | let _ = true.then_some(40).unwrap_or(17) | 2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 40 } else { 17 })` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:57:13 + | +LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 30 } else { 17 })` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:57:48 + | +LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 2 } else { 3 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:57:81 + | +LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 10 } else { 1 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:63:17 + | +LL | let _ = 2 | true.then_some(40).unwrap_or(17); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 40 } else { 17 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:67:13 + | +LL | let _ = true.then_some(42).unwrap_or(17) as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 42 } else { 17 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:71:14 + | +LL | let _ = *true.then_some(&42).unwrap_or(&17); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }` + +error: this method chain can be written more clearly with `if .. else ..` + --> tests/ui/obfuscated_if_else.rs:75:14 + | +LL | let _ = *true.then_some(&42).unwrap_or(&17) as u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }` + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/octal_escapes.rs b/src/tools/clippy/tests/ui/octal_escapes.rs index f2664e2fa67ff..d91d6c1d7beec 100644 --- a/src/tools/clippy/tests/ui/octal_escapes.rs +++ b/src/tools/clippy/tests/ui/octal_escapes.rs @@ -2,20 +2,29 @@ #![warn(clippy::octal_escapes)] fn main() { - let _bad1 = "\033[0m"; //~ octal_escapes - let _bad2 = b"\033[0m"; //~ octal_escapes - let _bad3 = "\\\033[0m"; //~ octal_escapes + let _bad1 = "\033[0m"; + //~^ octal_escapes + let _bad2 = b"\033[0m"; + //~^ octal_escapes + let _bad3 = "\\\033[0m"; + //~^ octal_escapes // maximum 3 digits (\012 is the escape) - let _bad4 = "\01234567"; //~ octal_escapes - let _bad5 = "\0\03"; //~ octal_escapes + let _bad4 = "\01234567"; + //~^ octal_escapes + let _bad5 = "\0\03"; + //~^ octal_escapes let _bad6 = "Text-\055\077-MoreText"; //~^ octal_escapes //~| octal_escapes + let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; //~^ octal_escapes //~| octal_escapes - let _bad8 = "锈\01锈"; //~ octal_escapes - let _bad9 = "锈\011锈"; //~ octal_escapes + + let _bad8 = "锈\01锈"; + //~^ octal_escapes + let _bad9 = "锈\011锈"; + //~^ octal_escapes let _good1 = "\\033[0m"; let _good2 = "\0\\0"; diff --git a/src/tools/clippy/tests/ui/octal_escapes.stderr b/src/tools/clippy/tests/ui/octal_escapes.stderr index 61c781e316ef3..5271c13c08bdd 100644 --- a/src/tools/clippy/tests/ui/octal_escapes.stderr +++ b/src/tools/clippy/tests/ui/octal_escapes.stderr @@ -18,7 +18,7 @@ LL | let _bad1 = "\x0033[0m"; | ++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:6:19 + --> tests/ui/octal_escapes.rs:7:19 | LL | let _bad2 = b"\033[0m"; | ^^^^ @@ -34,7 +34,7 @@ LL | let _bad2 = b"\x0033[0m"; | ++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:7:20 + --> tests/ui/octal_escapes.rs:9:20 | LL | let _bad3 = "\\\033[0m"; | ^^^^ @@ -50,7 +50,7 @@ LL | let _bad3 = "\\\x0033[0m"; | ++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:9:18 + --> tests/ui/octal_escapes.rs:12:18 | LL | let _bad4 = "\01234567"; | ^^^^ @@ -66,7 +66,7 @@ LL | let _bad4 = "\x001234567"; | ++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:10:20 + --> tests/ui/octal_escapes.rs:14:20 | LL | let _bad5 = "\0\03"; | ^^^ @@ -81,7 +81,7 @@ LL | let _bad5 = "\0\x0003"; | +++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:11:23 + --> tests/ui/octal_escapes.rs:16:23 | LL | let _bad6 = "Text-\055\077-MoreText"; | ^^^^ @@ -97,7 +97,7 @@ LL | let _bad6 = "Text-\x0055\077-MoreText"; | ++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:11:27 + --> tests/ui/octal_escapes.rs:16:27 | LL | let _bad6 = "Text-\055\077-MoreText"; | ^^^^ @@ -113,7 +113,7 @@ LL | let _bad6 = "Text-\055\x0077-MoreText"; | ++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:14:31 + --> tests/ui/octal_escapes.rs:20:31 | LL | let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; | ^^^ @@ -128,7 +128,7 @@ LL | let _bad7 = "EvenMoreText-\x0001\02-ShortEscapes"; | +++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:14:34 + --> tests/ui/octal_escapes.rs:20:34 | LL | let _bad7 = "EvenMoreText-\01\02-ShortEscapes"; | ^^^ @@ -143,7 +143,7 @@ LL | let _bad7 = "EvenMoreText-\01\x0002-ShortEscapes"; | +++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:17:19 + --> tests/ui/octal_escapes.rs:24:19 | LL | let _bad8 = "锈\01锈"; | ^^^ @@ -158,7 +158,7 @@ LL | let _bad8 = "锈\x0001锈"; | +++ error: octal-looking escape in a literal - --> tests/ui/octal_escapes.rs:18:19 + --> tests/ui/octal_escapes.rs:26:19 | LL | let _bad9 = "锈\011锈"; | ^^^^ diff --git a/src/tools/clippy/tests/ui/ok_expect.rs b/src/tools/clippy/tests/ui/ok_expect.rs index c2ad21e22ff8c..efb56f242a746 100644 --- a/src/tools/clippy/tests/ui/ok_expect.rs +++ b/src/tools/clippy/tests/ui/ok_expect.rs @@ -14,21 +14,25 @@ fn main() { let _ = res.unwrap(); res.ok().expect("disaster!"); - //~^ ERROR: called `ok().expect()` on a `Result` value + //~^ ok_expect + // the following should not warn, since `expect` isn't implemented unless // the error type implements `Debug` let res2: Result = Ok(0); res2.ok().expect("oh noes!"); let res3: Result> = Ok(0); res3.ok().expect("whoof"); - //~^ ERROR: called `ok().expect()` on a `Result` value + //~^ ok_expect + let res4: Result = Ok(0); res4.ok().expect("argh"); - //~^ ERROR: called `ok().expect()` on a `Result` value + //~^ ok_expect + let res5: io::Result = Ok(0); res5.ok().expect("oops"); - //~^ ERROR: called `ok().expect()` on a `Result` value + //~^ ok_expect + let res6: Result = Ok(0); res6.ok().expect("meh"); - //~^ ERROR: called `ok().expect()` on a `Result` value + //~^ ok_expect } diff --git a/src/tools/clippy/tests/ui/ok_expect.stderr b/src/tools/clippy/tests/ui/ok_expect.stderr index 2fd4f007d06d9..a9e3533d8ca1a 100644 --- a/src/tools/clippy/tests/ui/ok_expect.stderr +++ b/src/tools/clippy/tests/ui/ok_expect.stderr @@ -9,7 +9,7 @@ LL | res.ok().expect("disaster!"); = help: to override `-D warnings` add `#[allow(clippy::ok_expect)]` error: called `ok().expect()` on a `Result` value - --> tests/ui/ok_expect.rs:23:5 + --> tests/ui/ok_expect.rs:24:5 | LL | res3.ok().expect("whoof"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | res3.ok().expect("whoof"); = help: you can call `expect()` directly on the `Result` error: called `ok().expect()` on a `Result` value - --> tests/ui/ok_expect.rs:26:5 + --> tests/ui/ok_expect.rs:28:5 | LL | res4.ok().expect("argh"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | res4.ok().expect("argh"); = help: you can call `expect()` directly on the `Result` error: called `ok().expect()` on a `Result` value - --> tests/ui/ok_expect.rs:29:5 + --> tests/ui/ok_expect.rs:32:5 | LL | res5.ok().expect("oops"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | res5.ok().expect("oops"); = help: you can call `expect()` directly on the `Result` error: called `ok().expect()` on a `Result` value - --> tests/ui/ok_expect.rs:32:5 + --> tests/ui/ok_expect.rs:36:5 | LL | res6.ok().expect("meh"); | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion.rs b/src/tools/clippy/tests/ui/only_used_in_recursion.rs index 169fb790f8c5c..7d6075ba9ea47 100644 --- a/src/tools/clippy/tests/ui/only_used_in_recursion.rs +++ b/src/tools/clippy/tests/ui/only_used_in_recursion.rs @@ -9,18 +9,21 @@ fn _simple2(x: u32) -> u32 { } fn _one_unused(flag: u32, a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { _one_unused(flag - 1, a) } } fn _two_unused(flag: u32, a: u32, b: i32) -> usize { - //~^ ERROR: parameter is only used in recursion - //~| ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + //~| only_used_in_recursion + if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) } } fn _with_calc(flag: u32, a: i64) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { @@ -34,8 +37,9 @@ fn _used_with_flag(flag: u32, a: u32) -> usize { } fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize { - //~^ ERROR: parameter is only used in recursion - //~| ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + //~| only_used_in_recursion + if flag == 0 { 0 } else { @@ -44,8 +48,9 @@ fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize { } fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize { - //~^ ERROR: parameter is only used in recursion - //~| ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + //~| only_used_in_recursion + if flag == 0 { 0 } else { @@ -54,7 +59,8 @@ fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize { } fn _not_primitive(flag: u32, b: String) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { _not_primitive(flag - 1, b) } } @@ -62,13 +68,15 @@ struct A; impl A { fn _method(flag: usize, a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { Self::_method(flag - 1, a) } } fn _method_self(&self, flag: usize, a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion - //~| ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + //~| only_used_in_recursion + if flag == 0 { 0 } else { self._method_self(flag - 1, a) } } } @@ -80,12 +88,14 @@ trait B { impl B for A { fn method(flag: u32, a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { Self::method(flag - 1, a) } } fn method_self(&self, flag: u32, a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { self.method_self(flag - 1, a) } } } @@ -112,12 +122,14 @@ impl B for u32 { trait C { fn method(flag: u32, a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { Self::method(flag - 1, a) } } fn method_self(&self, flag: u32, a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { self.method_self(flag - 1, a) } } } diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion.stderr b/src/tools/clippy/tests/ui/only_used_in_recursion.stderr index a3aee2697f380..ca08319e11200 100644 --- a/src/tools/clippy/tests/ui/only_used_in_recursion.stderr +++ b/src/tools/clippy/tests/ui/only_used_in_recursion.stderr @@ -5,7 +5,7 @@ LL | fn _one_unused(flag: u32, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:13:53 + --> tests/ui/only_used_in_recursion.rs:14:53 | LL | if flag == 0 { 0 } else { _one_unused(flag - 1, a) } | ^ @@ -13,181 +13,181 @@ LL | if flag == 0 { 0 } else { _one_unused(flag - 1, a) } = help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]` error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:16:27 + --> tests/ui/only_used_in_recursion.rs:17:27 | LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:19:53 + --> tests/ui/only_used_in_recursion.rs:21:53 | LL | if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:16:35 + --> tests/ui/only_used_in_recursion.rs:17:35 | LL | fn _two_unused(flag: u32, a: u32, b: i32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:19:56 + --> tests/ui/only_used_in_recursion.rs:21:56 | LL | if flag == 0 { 0 } else { _two_unused(flag - 1, a, b) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:22:26 + --> tests/ui/only_used_in_recursion.rs:24:26 | LL | fn _with_calc(flag: u32, a: i64) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:27:32 + --> tests/ui/only_used_in_recursion.rs:30:32 | LL | _with_calc(flag - 1, (-a + 10) * 5) | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:36:33 + --> tests/ui/only_used_in_recursion.rs:39:33 | LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:42:38 + --> tests/ui/only_used_in_recursion.rs:46:38 | LL | _used_with_unused(flag - 1, -a, a + b) | ^ ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:36:41 + --> tests/ui/only_used_in_recursion.rs:39:41 | LL | fn _used_with_unused(flag: u32, a: i32, b: i32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:42:45 + --> tests/ui/only_used_in_recursion.rs:46:45 | LL | _used_with_unused(flag - 1, -a, a + b) | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:46:35 + --> tests/ui/only_used_in_recursion.rs:50:35 | LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:52:39 + --> tests/ui/only_used_in_recursion.rs:57:39 | LL | _codependent_unused(flag - 1, a * b, a + b) | ^ ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:46:43 + --> tests/ui/only_used_in_recursion.rs:50:43 | LL | fn _codependent_unused(flag: u32, a: i32, b: i32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:52:43 + --> tests/ui/only_used_in_recursion.rs:57:43 | LL | _codependent_unused(flag - 1, a * b, a + b) | ^ ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:56:30 + --> tests/ui/only_used_in_recursion.rs:61:30 | LL | fn _not_primitive(flag: u32, b: String) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:58:56 + --> tests/ui/only_used_in_recursion.rs:64:56 | LL | if flag == 0 { 0 } else { _not_primitive(flag - 1, b) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:64:29 + --> tests/ui/only_used_in_recursion.rs:70:29 | LL | fn _method(flag: usize, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:66:59 + --> tests/ui/only_used_in_recursion.rs:73:59 | LL | if flag == 0 { 0 } else { Self::_method(flag - 1, a) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:69:22 + --> tests/ui/only_used_in_recursion.rs:76:22 | LL | fn _method_self(&self, flag: usize, a: usize) -> usize { | ^^^^ | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:72:35 + --> tests/ui/only_used_in_recursion.rs:80:35 | LL | if flag == 0 { 0 } else { self._method_self(flag - 1, a) } | ^^^^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:69:41 + --> tests/ui/only_used_in_recursion.rs:76:41 | LL | fn _method_self(&self, flag: usize, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:72:63 + --> tests/ui/only_used_in_recursion.rs:80:63 | LL | if flag == 0 { 0 } else { self._method_self(flag - 1, a) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:82:26 + --> tests/ui/only_used_in_recursion.rs:90:26 | LL | fn method(flag: u32, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:84:58 + --> tests/ui/only_used_in_recursion.rs:93:58 | LL | if flag == 0 { 0 } else { Self::method(flag - 1, a) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:87:38 + --> tests/ui/only_used_in_recursion.rs:96:38 | LL | fn method_self(&self, flag: u32, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:89:62 + --> tests/ui/only_used_in_recursion.rs:99:62 | LL | if flag == 0 { 0 } else { self.method_self(flag - 1, a) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:114:26 + --> tests/ui/only_used_in_recursion.rs:124:26 | LL | fn method(flag: u32, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:116:58 + --> tests/ui/only_used_in_recursion.rs:127:58 | LL | if flag == 0 { 0 } else { Self::method(flag - 1, a) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion.rs:119:38 + --> tests/ui/only_used_in_recursion.rs:130:38 | LL | fn method_self(&self, flag: u32, a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion.rs:121:62 + --> tests/ui/only_used_in_recursion.rs:133:62 | LL | if flag == 0 { 0 } else { self.method_self(flag - 1, a) } | ^ diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion2.rs b/src/tools/clippy/tests/ui/only_used_in_recursion2.rs index 1353ff8816ad1..2fe4e7b35d38a 100644 --- a/src/tools/clippy/tests/ui/only_used_in_recursion2.rs +++ b/src/tools/clippy/tests/ui/only_used_in_recursion2.rs @@ -1,9 +1,11 @@ #![warn(clippy::only_used_in_recursion)] //@no-rustfix fn _with_inner(flag: u32, a: u32, b: u32) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + fn inner(flag: u32, a: u32) -> u32 { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { inner(flag, a) } } @@ -12,7 +14,8 @@ fn _with_inner(flag: u32, a: u32, b: u32) -> usize { } fn _with_closure(a: Option, b: u32, f: impl Fn(u32, u32) -> Option) -> u32 { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if let Some(x) = a.and_then(|x| f(x, x)) { _with_closure(Some(x), b, f) } else { @@ -63,7 +66,8 @@ impl E<()> for () { } fn overwritten_param(flag: u32, mut a: usize) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { return 0; } else if flag > 5 { @@ -75,7 +79,8 @@ fn overwritten_param(flag: u32, mut a: usize) -> usize { } fn field_direct(flag: u32, mut a: (usize,)) -> usize { - //~^ ERROR: parameter is only used in recursion + //~^ only_used_in_recursion + if flag == 0 { 0 } else { diff --git a/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr b/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr index e39460c7e8f3e..a7cd8713cf7a7 100644 --- a/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr +++ b/src/tools/clippy/tests/ui/only_used_in_recursion2.stderr @@ -5,7 +5,7 @@ LL | fn _with_inner(flag: u32, a: u32, b: u32) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_b` | note: parameter used here - --> tests/ui/only_used_in_recursion2.rs:11:52 + --> tests/ui/only_used_in_recursion2.rs:13:52 | LL | if flag == 0 { 0 } else { _with_inner(flag, a, b + x) } | ^ @@ -13,49 +13,49 @@ LL | if flag == 0 { 0 } else { _with_inner(flag, a, b + x) } = help: to override `-D warnings` add `#[allow(clippy::only_used_in_recursion)]` error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion2.rs:5:25 + --> tests/ui/only_used_in_recursion2.rs:6:25 | LL | fn inner(flag: u32, a: u32) -> u32 { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion2.rs:7:47 + --> tests/ui/only_used_in_recursion2.rs:9:47 | LL | if flag == 0 { 0 } else { inner(flag, a) } | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion2.rs:14:34 + --> tests/ui/only_used_in_recursion2.rs:16:34 | LL | fn _with_closure(a: Option, b: u32, f: impl Fn(u32, u32) -> Option) -> u32 { | ^ help: if this is intentional, prefix it with an underscore: `_b` | note: parameter used here - --> tests/ui/only_used_in_recursion2.rs:17:32 + --> tests/ui/only_used_in_recursion2.rs:20:32 | LL | _with_closure(Some(x), b, f) | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion2.rs:65:37 + --> tests/ui/only_used_in_recursion2.rs:68:37 | LL | fn overwritten_param(flag: u32, mut a: usize) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion2.rs:74:29 + --> tests/ui/only_used_in_recursion2.rs:78:29 | LL | overwritten_param(flag, a) | ^ error: parameter is only used in recursion - --> tests/ui/only_used_in_recursion2.rs:77:32 + --> tests/ui/only_used_in_recursion2.rs:81:32 | LL | fn field_direct(flag: u32, mut a: (usize,)) -> usize { | ^ help: if this is intentional, prefix it with an underscore: `_a` | note: parameter used here - --> tests/ui/only_used_in_recursion2.rs:83:32 + --> tests/ui/only_used_in_recursion2.rs:88:32 | LL | field_direct(flag - 1, a) | ^ diff --git a/src/tools/clippy/tests/ui/op_ref.fixed b/src/tools/clippy/tests/ui/op_ref.fixed index 183dcf4f08635..46a59e419cce0 100644 --- a/src/tools/clippy/tests/ui/op_ref.fixed +++ b/src/tools/clippy/tests/ui/op_ref.fixed @@ -9,8 +9,7 @@ fn main() { let unwanted = &tracked_fds - &new_fds; let foo = 5 - 6; - //~^ ERROR: needlessly taken reference of both operands - //~| NOTE: `-D clippy::op-ref` implied by `-D warnings` + //~^ op_ref let bar = String::new(); let bar = "foo" == &bar; @@ -56,7 +55,7 @@ fn main() { let x = Y(1); let y = Y(2); let z = x & y; - //~^ ERROR: taken reference of right operand + //~^ op_ref } #[derive(Clone, Copy)] @@ -90,9 +89,11 @@ impl Mul for A { let two = 2; let three = 3; let _ = one * self; - //~^ ERROR: taken reference of right operand + //~^ op_ref + let _ = two + three; - //~^ ERROR: taken reference of right operand + //~^ op_ref + // Removing the reference would lead to unconditional recursion self * &rhs } diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs index 6ed4f23d2bd7b..e10840ff4b97b 100644 --- a/src/tools/clippy/tests/ui/op_ref.rs +++ b/src/tools/clippy/tests/ui/op_ref.rs @@ -9,8 +9,7 @@ fn main() { let unwanted = &tracked_fds - &new_fds; let foo = &5 - &6; - //~^ ERROR: needlessly taken reference of both operands - //~| NOTE: `-D clippy::op-ref` implied by `-D warnings` + //~^ op_ref let bar = String::new(); let bar = "foo" == &bar; @@ -56,7 +55,7 @@ fn main() { let x = Y(1); let y = Y(2); let z = x & &y; - //~^ ERROR: taken reference of right operand + //~^ op_ref } #[derive(Clone, Copy)] @@ -90,9 +89,11 @@ impl Mul for A { let two = 2; let three = 3; let _ = one * &self; - //~^ ERROR: taken reference of right operand + //~^ op_ref + let _ = two + &three; - //~^ ERROR: taken reference of right operand + //~^ op_ref + // Removing the reference would lead to unconditional recursion self * &rhs } diff --git a/src/tools/clippy/tests/ui/op_ref.stderr b/src/tools/clippy/tests/ui/op_ref.stderr index ad002437c0c6b..51c2963a9eed2 100644 --- a/src/tools/clippy/tests/ui/op_ref.stderr +++ b/src/tools/clippy/tests/ui/op_ref.stderr @@ -13,7 +13,7 @@ LL + let foo = 5 - 6; | error: taken reference of right operand - --> tests/ui/op_ref.rs:58:13 + --> tests/ui/op_ref.rs:57:13 | LL | let z = x & &y; | ^^^^-- @@ -21,7 +21,7 @@ LL | let z = x & &y; | help: use the right value directly: `y` error: taken reference of right operand - --> tests/ui/op_ref.rs:92:17 + --> tests/ui/op_ref.rs:91:17 | LL | let _ = one * &self; | ^^^^^^----- diff --git a/src/tools/clippy/tests/ui/open_options.rs b/src/tools/clippy/tests/ui/open_options.rs index 4acb3780df43e..f2f6e6edb4de2 100644 --- a/src/tools/clippy/tests/ui/open_options.rs +++ b/src/tools/clippy/tests/ui/open_options.rs @@ -15,28 +15,31 @@ impl OpenOptionsExt for OpenOptions { fn main() { OpenOptions::new().read(true).truncate(true).open("foo.txt"); - //~^ ERROR: file opened with `truncate` and `read` - //~| NOTE: `-D clippy::nonsensical-open-options` implied by `-D warnings` + //~^ nonsensical_open_options + OpenOptions::new().append(true).truncate(true).open("foo.txt"); - //~^ ERROR: file opened with `append` and `truncate` + //~^ nonsensical_open_options OpenOptions::new().read(true).read(false).open("foo.txt"); - //~^ ERROR: the method `read` is called more than once + //~^ nonsensical_open_options + OpenOptions::new() .create(true) .truncate(true) // Ensure we don't trigger suspicious open options by having create without truncate .create(false) - //~^ ERROR: the method `create` is called more than once + //~^ nonsensical_open_options .open("foo.txt"); OpenOptions::new().write(true).write(false).open("foo.txt"); - //~^ ERROR: the method `write` is called more than once + //~^ nonsensical_open_options + OpenOptions::new().append(true).append(false).open("foo.txt"); - //~^ ERROR: the method `append` is called more than once + //~^ nonsensical_open_options + OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); - //~^ ERROR: the method `truncate` is called more than once + //~^ nonsensical_open_options std::fs::File::options().read(true).read(false).open("foo.txt"); - //~^ ERROR: the method `read` is called more than once + //~^ nonsensical_open_options let mut options = std::fs::OpenOptions::new(); options.read(true); diff --git a/src/tools/clippy/tests/ui/open_options.stderr b/src/tools/clippy/tests/ui/open_options.stderr index 19755bce46c86..11b2d55fa0582 100644 --- a/src/tools/clippy/tests/ui/open_options.stderr +++ b/src/tools/clippy/tests/ui/open_options.stderr @@ -20,31 +20,31 @@ LL | OpenOptions::new().read(true).read(false).open("foo.txt"); | ^^^^^^^^^^^ error: the method `create` is called more than once - --> tests/ui/open_options.rs:28:10 + --> tests/ui/open_options.rs:29:10 | LL | .create(false) | ^^^^^^^^^^^^^ error: the method `write` is called more than once - --> tests/ui/open_options.rs:31:36 + --> tests/ui/open_options.rs:32:36 | LL | OpenOptions::new().write(true).write(false).open("foo.txt"); | ^^^^^^^^^^^^ error: the method `append` is called more than once - --> tests/ui/open_options.rs:33:37 + --> tests/ui/open_options.rs:35:37 | LL | OpenOptions::new().append(true).append(false).open("foo.txt"); | ^^^^^^^^^^^^^ error: the method `truncate` is called more than once - --> tests/ui/open_options.rs:35:39 + --> tests/ui/open_options.rs:38:39 | LL | OpenOptions::new().truncate(true).truncate(false).open("foo.txt"); | ^^^^^^^^^^^^^^^ error: the method `read` is called more than once - --> tests/ui/open_options.rs:38:41 + --> tests/ui/open_options.rs:41:41 | LL | std::fs::File::options().read(true).read(false).open("foo.txt"); | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/open_options_fixable.fixed b/src/tools/clippy/tests/ui/open_options_fixable.fixed index 90a129a9bdffd..7f601eec2cf06 100644 --- a/src/tools/clippy/tests/ui/open_options_fixable.fixed +++ b/src/tools/clippy/tests/ui/open_options_fixable.fixed @@ -3,5 +3,5 @@ use std::fs::OpenOptions; #[warn(clippy::suspicious_open_options)] fn main() { OpenOptions::new().create(true).truncate(true).open("foo.txt"); - //~^ ERROR: file opened with `create`, but `truncate` behavior not defined + //~^ suspicious_open_options } diff --git a/src/tools/clippy/tests/ui/open_options_fixable.rs b/src/tools/clippy/tests/ui/open_options_fixable.rs index 3a9e522ba1507..5f03528d7a569 100644 --- a/src/tools/clippy/tests/ui/open_options_fixable.rs +++ b/src/tools/clippy/tests/ui/open_options_fixable.rs @@ -3,5 +3,5 @@ use std::fs::OpenOptions; #[warn(clippy::suspicious_open_options)] fn main() { OpenOptions::new().create(true).open("foo.txt"); - //~^ ERROR: file opened with `create`, but `truncate` behavior not defined + //~^ suspicious_open_options } diff --git a/src/tools/clippy/tests/ui/option_as_ref_cloned.fixed b/src/tools/clippy/tests/ui/option_as_ref_cloned.fixed index 394dad219f777..cf21d1c0176eb 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_cloned.fixed +++ b/src/tools/clippy/tests/ui/option_as_ref_cloned.fixed @@ -5,10 +5,13 @@ fn main() { let mut x = Some(String::new()); let _: Option = x.clone(); + //~^ option_as_ref_cloned let _: Option = x.clone(); + //~^ option_as_ref_cloned let y = x.as_ref(); let _: Option<&String> = y.clone(); + //~^ option_as_ref_cloned macro_rules! cloned_recv { () => { diff --git a/src/tools/clippy/tests/ui/option_as_ref_cloned.rs b/src/tools/clippy/tests/ui/option_as_ref_cloned.rs index 7243957927b25..354638c4c3800 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_cloned.rs +++ b/src/tools/clippy/tests/ui/option_as_ref_cloned.rs @@ -5,10 +5,13 @@ fn main() { let mut x = Some(String::new()); let _: Option = x.as_ref().cloned(); + //~^ option_as_ref_cloned let _: Option = x.as_mut().cloned(); + //~^ option_as_ref_cloned let y = x.as_ref(); let _: Option<&String> = y.as_ref().cloned(); + //~^ option_as_ref_cloned macro_rules! cloned_recv { () => { diff --git a/src/tools/clippy/tests/ui/option_as_ref_cloned.stderr b/src/tools/clippy/tests/ui/option_as_ref_cloned.stderr index 0eda42b91b96b..9f650b90d5399 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_cloned.stderr +++ b/src/tools/clippy/tests/ui/option_as_ref_cloned.stderr @@ -13,7 +13,7 @@ LL + let _: Option = x.clone(); | error: cloning an `Option<_>` using `.as_mut().cloned()` - --> tests/ui/option_as_ref_cloned.rs:8:31 + --> tests/ui/option_as_ref_cloned.rs:9:31 | LL | let _: Option = x.as_mut().cloned(); | ^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let _: Option = x.clone(); | error: cloning an `Option<_>` using `.as_ref().cloned()` - --> tests/ui/option_as_ref_cloned.rs:11:32 + --> tests/ui/option_as_ref_cloned.rs:13:32 | LL | let _: Option<&String> = y.as_ref().cloned(); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed index c5a959ba566dc..9be89b5d484f6 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed @@ -9,25 +9,38 @@ fn main() { let mut opt = Some(String::from("123")); let _ = opt.clone().as_deref().map(str::len); + //~^ option_as_ref_deref #[rustfmt::skip] let _ = opt.clone().as_deref() .map(str::len); let _ = opt.as_deref_mut(); + //~^ option_as_ref_deref let _ = opt.as_deref(); + //~^ option_as_ref_deref let _ = opt.as_deref(); + //~^ option_as_ref_deref let _ = opt.as_deref_mut(); + //~^ option_as_ref_deref let _ = opt.as_deref_mut(); + //~^ option_as_ref_deref let _ = Some(CString::new(vec![]).unwrap()).as_deref(); + //~^ option_as_ref_deref let _ = Some(OsString::new()).as_deref(); + //~^ option_as_ref_deref let _ = Some(PathBuf::new()).as_deref(); + //~^ option_as_ref_deref let _ = Some(Vec::<()>::new()).as_deref(); + //~^ option_as_ref_deref let _ = Some(Vec::<()>::new()).as_deref_mut(); + //~^ option_as_ref_deref let _ = opt.as_deref(); + //~^ option_as_ref_deref let _ = opt.clone().as_deref_mut().map(|x| x.len()); + //~^ option_as_ref_deref let vc = vec![String::new()]; let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted @@ -35,10 +48,13 @@ fn main() { let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted let _ = opt.as_deref(); + //~^ option_as_ref_deref let _ = opt.as_deref_mut(); + //~^ option_as_ref_deref // Issue #5927 let _ = opt.as_deref(); + //~^ option_as_ref_deref } #[clippy::msrv = "1.39"] @@ -51,4 +67,5 @@ fn msrv_1_39() { fn msrv_1_40() { let opt = Some(String::from("123")); let _ = opt.as_deref(); + //~^ option_as_ref_deref } diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.rs b/src/tools/clippy/tests/ui/option_as_ref_deref.rs index 1aeedf211fe22..d6b29e5e61b1f 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.rs +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.rs @@ -9,28 +9,42 @@ fn main() { let mut opt = Some(String::from("123")); let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); + //~^ option_as_ref_deref #[rustfmt::skip] let _ = opt.clone() + //~^ option_as_ref_deref .as_ref().map( Deref::deref ) .map(str::len); let _ = opt.as_mut().map(DerefMut::deref_mut); + //~^ option_as_ref_deref let _ = opt.as_ref().map(String::as_str); + //~^ option_as_ref_deref let _ = opt.as_ref().map(|x| x.as_str()); + //~^ option_as_ref_deref let _ = opt.as_mut().map(String::as_mut_str); + //~^ option_as_ref_deref let _ = opt.as_mut().map(|x| x.as_mut_str()); + //~^ option_as_ref_deref let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); + //~^ option_as_ref_deref let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); + //~^ option_as_ref_deref let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); + //~^ option_as_ref_deref let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); + //~^ option_as_ref_deref let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); + //~^ option_as_ref_deref let _ = opt.as_ref().map(|x| x.deref()); + //~^ option_as_ref_deref let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); + //~^ option_as_ref_deref let vc = vec![String::new()]; let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted @@ -38,10 +52,13 @@ fn main() { let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted let _ = opt.as_ref().map(|x| &**x); + //~^ option_as_ref_deref let _ = opt.as_mut().map(|x| &mut **x); + //~^ option_as_ref_deref // Issue #5927 let _ = opt.as_ref().map(std::ops::Deref::deref); + //~^ option_as_ref_deref } #[clippy::msrv = "1.39"] @@ -54,4 +71,5 @@ fn msrv_1_39() { fn msrv_1_40() { let opt = Some(String::from("123")); let _ = opt.as_ref().map(String::as_str); + //~^ option_as_ref_deref } diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr index 8b7f47a1b9af0..ca924aec66ddb 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.stderr +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.stderr @@ -8,107 +8,108 @@ LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len); = help: to override `-D warnings` add `#[allow(clippy::option_as_ref_deref)]` error: called `.as_ref().map(Deref::deref)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:14:13 + --> tests/ui/option_as_ref_deref.rs:15:13 | LL | let _ = opt.clone() | _____________^ +LL | | LL | | .as_ref().map( LL | | Deref::deref LL | | ) | |_________^ help: consider using as_deref: `opt.clone().as_deref()` error: called `.as_mut().map(DerefMut::deref_mut)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:20:13 + --> tests/ui/option_as_ref_deref.rs:22:13 | LL | let _ = opt.as_mut().map(DerefMut::deref_mut); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(String::as_str)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:22:13 + --> tests/ui/option_as_ref_deref.rs:25:13 | LL | let _ = opt.as_ref().map(String::as_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_ref().map(|x| x.as_str())` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:23:13 + --> tests/ui/option_as_ref_deref.rs:27:13 | LL | let _ = opt.as_ref().map(|x| x.as_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(String::as_mut_str)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:24:13 + --> tests/ui/option_as_ref_deref.rs:29:13 | LL | let _ = opt.as_mut().map(String::as_mut_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_mut().map(|x| x.as_mut_str())` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:25:13 + --> tests/ui/option_as_ref_deref.rs:31:13 | LL | let _ = opt.as_mut().map(|x| x.as_mut_str()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(CString::as_c_str)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:26:13 + --> tests/ui/option_as_ref_deref.rs:33:13 | LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(CString::new(vec![]).unwrap()).as_deref()` error: called `.as_ref().map(OsString::as_os_str)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:27:13 + --> tests/ui/option_as_ref_deref.rs:35:13 | LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(OsString::new()).as_deref()` error: called `.as_ref().map(PathBuf::as_path)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:28:13 + --> tests/ui/option_as_ref_deref.rs:37:13 | LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(PathBuf::new()).as_deref()` error: called `.as_ref().map(Vec::as_slice)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:29:13 + --> tests/ui/option_as_ref_deref.rs:39:13 | LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `Some(Vec::<()>::new()).as_deref()` error: called `.as_mut().map(Vec::as_mut_slice)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:30:13 + --> tests/ui/option_as_ref_deref.rs:41:13 | LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `Some(Vec::<()>::new()).as_deref_mut()` error: called `.as_ref().map(|x| x.deref())` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:32:13 + --> tests/ui/option_as_ref_deref.rs:44:13 | LL | let _ = opt.as_ref().map(|x| x.deref()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(|x| x.deref_mut())` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:33:13 + --> tests/ui/option_as_ref_deref.rs:46:13 | LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.clone().as_deref_mut()` error: called `.as_ref().map(|x| &**x)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:40:13 + --> tests/ui/option_as_ref_deref.rs:54:13 | LL | let _ = opt.as_ref().map(|x| &**x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_mut().map(|x| &mut **x)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:41:13 + --> tests/ui/option_as_ref_deref.rs:56:13 | LL | let _ = opt.as_mut().map(|x| &mut **x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref_mut: `opt.as_deref_mut()` error: called `.as_ref().map(std::ops::Deref::deref)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:44:13 + --> tests/ui/option_as_ref_deref.rs:60:13 | LL | let _ = opt.as_ref().map(std::ops::Deref::deref); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` error: called `.as_ref().map(String::as_str)` on an `Option` value - --> tests/ui/option_as_ref_deref.rs:56:13 + --> tests/ui/option_as_ref_deref.rs:73:13 | LL | let _ = opt.as_ref().map(String::as_str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using as_deref: `opt.as_deref()` diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs index f8d382340f2f4..b8476830efe58 100644 --- a/src/tools/clippy/tests/ui/option_env_unwrap.rs +++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs @@ -8,10 +8,18 @@ use proc_macros::{external, inline_macros}; #[inline_macros] fn main() { let _ = option_env!("PATH").unwrap(); + //~^ option_env_unwrap let _ = option_env!("PATH").expect("environment variable PATH isn't set"); + //~^ option_env_unwrap let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your environment. + // + //~^^ option_env_unwrap let _ = inline!(option_env!($"PATH").unwrap()); + //~^ option_env_unwrap let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + //~^ option_env_unwrap let _ = external!(option_env!($"PATH").unwrap()); + //~^ option_env_unwrap let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); + //~^ option_env_unwrap } diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.stderr b/src/tools/clippy/tests/ui/option_env_unwrap.stderr index 169523269fbb5..bbcbfedb78822 100644 --- a/src/tools/clippy/tests/ui/option_env_unwrap.stderr +++ b/src/tools/clippy/tests/ui/option_env_unwrap.stderr @@ -9,7 +9,7 @@ LL | let _ = option_env!("PATH").unwrap(); = help: to override `-D warnings` add `#[allow(clippy::option_env_unwrap)]` error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> tests/ui/option_env_unwrap.rs:11:13 + --> tests/ui/option_env_unwrap.rs:12:13 | LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let _ = option_env!("PATH").expect("environment variable PATH isn't set = help: consider using the `env!` macro instead error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> tests/ui/option_env_unwrap.rs:12:13 + --> tests/ui/option_env_unwrap.rs:14:13 | LL | let _ = option_env!("__Y__do_not_use").unwrap(); // This test only works if you don't have a __Y__do_not_use env variable in your env... | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let _ = option_env!("__Y__do_not_use").unwrap(); // This test only work = help: consider using the `env!` macro instead error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> tests/ui/option_env_unwrap.rs:13:21 + --> tests/ui/option_env_unwrap.rs:17:21 | LL | let _ = inline!(option_env!($"PATH").unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | let _ = inline!(option_env!($"PATH").unwrap()); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> tests/ui/option_env_unwrap.rs:14:21 + --> tests/ui/option_env_unwrap.rs:19:21 | LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH isn't set")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | let _ = inline!(option_env!($"PATH").expect($"environment variable PATH = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> tests/ui/option_env_unwrap.rs:15:13 + --> tests/ui/option_env_unwrap.rs:21:13 | LL | let _ = external!(option_env!($"PATH").unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = external!(option_env!($"PATH").unwrap()); = note: this error originates in the macro `external` (in Nightly builds, run with -Z macro-backtrace for more info) error: this will panic at run-time if the environment variable doesn't exist at compile-time - --> tests/ui/option_env_unwrap.rs:16:13 + --> tests/ui/option_env_unwrap.rs:23:13 | LL | let _ = external!(option_env!($"PATH").expect($"environment variable PATH isn't set")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/option_filter_map.fixed b/src/tools/clippy/tests/ui/option_filter_map.fixed index b1c3cfa48a446..d390c41af53cf 100644 --- a/src/tools/clippy/tests/ui/option_filter_map.fixed +++ b/src/tools/clippy/tests/ui/option_filter_map.fixed @@ -3,18 +3,23 @@ fn main() { let _ = Some(Some(1)).flatten(); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = Some(Some(1)).flatten(); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = Some(1).map(odds_out).flatten(); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = Some(1).map(odds_out).flatten(); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map let _ = vec![Some(1)].into_iter().flatten(); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = vec![Some(1)].into_iter().flatten(); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = vec![1] .into_iter() .map(odds_out) diff --git a/src/tools/clippy/tests/ui/option_filter_map.rs b/src/tools/clippy/tests/ui/option_filter_map.rs index 2550b9cd2b369..2d3b983a76707 100644 --- a/src/tools/clippy/tests/ui/option_filter_map.rs +++ b/src/tools/clippy/tests/ui/option_filter_map.rs @@ -3,29 +3,34 @@ fn main() { let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap()); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap()); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap()); - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map + let _ = vec![1] .into_iter() .map(odds_out) .filter(Option::is_some) - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map .map(Option::unwrap); let _ = vec![1] .into_iter() .map(odds_out) .filter(|o| o.is_some()) - //~^ ERROR: `filter` for `Some` followed by `unwrap` + //~^ option_filter_map .map(|o| o.unwrap()); } diff --git a/src/tools/clippy/tests/ui/option_filter_map.stderr b/src/tools/clippy/tests/ui/option_filter_map.stderr index 401ac2b2296da..df3c1f9d47b8a 100644 --- a/src/tools/clippy/tests/ui/option_filter_map.stderr +++ b/src/tools/clippy/tests/ui/option_filter_map.stderr @@ -8,37 +8,37 @@ LL | let _ = Some(Some(1)).filter(Option::is_some).map(Option::unwrap); = help: to override `-D warnings` add `#[allow(clippy::option_filter_map)]` error: `filter` for `Some` followed by `unwrap` - --> tests/ui/option_filter_map.rs:7:27 + --> tests/ui/option_filter_map.rs:8:27 | LL | let _ = Some(Some(1)).filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> tests/ui/option_filter_map.rs:9:35 + --> tests/ui/option_filter_map.rs:11:35 | LL | let _ = Some(1).map(odds_out).filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> tests/ui/option_filter_map.rs:11:35 + --> tests/ui/option_filter_map.rs:14:35 | LL | let _ = Some(1).map(odds_out).filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> tests/ui/option_filter_map.rs:14:39 + --> tests/ui/option_filter_map.rs:17:39 | LL | let _ = vec![Some(1)].into_iter().filter(Option::is_some).map(Option::unwrap); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> tests/ui/option_filter_map.rs:16:39 + --> tests/ui/option_filter_map.rs:20:39 | LL | let _ = vec![Some(1)].into_iter().filter(|o| o.is_some()).map(|o| o.unwrap()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> tests/ui/option_filter_map.rs:21:10 + --> tests/ui/option_filter_map.rs:26:10 | LL | .filter(Option::is_some) | __________^ @@ -47,7 +47,7 @@ LL | | .map(Option::unwrap); | |____________________________^ help: consider using `flatten` instead: `flatten()` error: `filter` for `Some` followed by `unwrap` - --> tests/ui/option_filter_map.rs:27:10 + --> tests/ui/option_filter_map.rs:32:10 | LL | .filter(|o| o.is_some()) | __________^ diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed index 0ac89bf0d8eaf..f5a869cf28318 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -4,6 +4,7 @@ clippy::equatable_if_let, clippy::let_unit_value, clippy::redundant_locals, + clippy::manual_midpoint, clippy::manual_unwrap_or_default, clippy::manual_unwrap_or )] @@ -24,17 +25,23 @@ fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { fn unop_bad(string: &Option<&str>, mut num: Option) { let _ = string.map_or(0, |s| s.len()); + //~^ option_if_let_else let _ = num.as_ref().map_or(&0, |s| s); + //~^ option_if_let_else let _ = num.as_mut().map_or(&0, |s| { + //~^ option_if_let_else *s += 1; s }); let _ = num.as_ref().map_or(&0, |s| s); + //~^ option_if_let_else let _ = num.map_or(0, |mut s| { + //~^ option_if_let_else s += 1; s }); let _ = num.as_mut().map_or(&0, |s| { + //~^ option_if_let_else *s += 1; s }); @@ -42,6 +49,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option) { fn longer_body(arg: Option) -> u32 { arg.map_or(13, |x| { + //~^ option_if_let_else let y = x * x; y * y }) @@ -98,6 +106,7 @@ fn test_result_impure_else(variable: Result) -> bool { println!("Err"); false }, |binding| { + //~^ option_if_let_else println!("Ok {binding}"); true }) @@ -119,6 +128,7 @@ fn complex_subpat() -> DummyEnum { fn main() { let optional = Some(5); let _ = optional.map_or(5, |x| x + 2); + //~^ option_if_let_else let _ = bad1(None); let _ = else_if_option(None); unop_bad(&None, None); @@ -153,10 +163,12 @@ fn main() { let s = String::new(); // Lint, both branches immutably borrow `s`. let _ = Some(0).map_or(s.len(), |x| s.len() + x); + //~^ option_if_let_else let s = String::new(); // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`. let _ = Some(0).map_or(1, |x| { + //~^ option_if_let_else let s = s; s.len() + x }); @@ -200,6 +212,7 @@ fn main() { let _ = res.map_or(1, |a| a + 1); let _ = res.map_or(1, |a| a + 1); let _ = res.map_or(5, |a| a + 1); + //~^ option_if_let_else } #[allow(dead_code)] @@ -243,6 +256,7 @@ fn issue11429() { let mut _hashmap = opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone()); let mut _hm = opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone()); + //~^ option_if_let_else } fn issue11893() { diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs index b4f1b2cd1f7ff..d48272e618acc 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -4,12 +4,14 @@ clippy::equatable_if_let, clippy::let_unit_value, clippy::redundant_locals, + clippy::manual_midpoint, clippy::manual_unwrap_or_default, clippy::manual_unwrap_or )] fn bad1(string: Option<&str>) -> (bool, &str) { if let Some(x) = string { + //~^ option_if_let_else (true, x) } else { (false, "hello") @@ -28,21 +30,27 @@ fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { fn unop_bad(string: &Option<&str>, mut num: Option) { let _ = if let Some(s) = *string { s.len() } else { 0 }; + //~^ option_if_let_else let _ = if let Some(s) = &num { s } else { &0 }; + //~^ option_if_let_else let _ = if let Some(s) = &mut num { + //~^ option_if_let_else *s += 1; s } else { &0 }; let _ = if let Some(ref s) = num { s } else { &0 }; + //~^ option_if_let_else let _ = if let Some(mut s) = num { + //~^ option_if_let_else s += 1; s } else { 0 }; let _ = if let Some(ref mut s) = num { + //~^ option_if_let_else *s += 1; s } else { @@ -52,6 +60,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option) { fn longer_body(arg: Option) -> u32 { if let Some(x) = arg { + //~^ option_if_let_else let y = x * x; y * y } else { @@ -65,6 +74,7 @@ fn impure_else(arg: Option) { 1 }; let _ = if let Some(x) = arg { + //~^ option_if_let_else x } else { // map_or_else must be suggested @@ -74,6 +84,7 @@ fn impure_else(arg: Option) { fn test_map_or_else(arg: Option) { let _ = if let Some(x) = arg { + //~^ option_if_let_else x * x * x * x } else { let mut y = 1; @@ -107,6 +118,7 @@ fn pattern_to_vec(pattern: &str) -> Vec { .split('/') .flat_map(|s| { if let Some(idx) = s.find('.') { + //~^ option_if_let_else vec![s[..idx].to_string(), s[idx..].to_string()] } else { vec![s.to_string()] @@ -118,6 +130,7 @@ fn pattern_to_vec(pattern: &str) -> Vec { // #10335 fn test_result_impure_else(variable: Result) -> bool { if let Ok(binding) = variable { + //~^ option_if_let_else println!("Ok {binding}"); true } else { @@ -142,6 +155,7 @@ fn complex_subpat() -> DummyEnum { fn main() { let optional = Some(5); let _ = if let Some(x) = optional { x + 2 } else { 5 }; + //~^ option_if_let_else let _ = bad1(None); let _ = else_if_option(None); unop_bad(&None, None); @@ -152,6 +166,7 @@ fn main() { let _ = impure_else(None); let _ = if let Some(x) = Some(0) { + //~^ option_if_let_else loop { if x == 0 { break x; @@ -180,10 +195,12 @@ fn main() { let s = String::new(); // Lint, both branches immutably borrow `s`. let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; + //~^ option_if_let_else let s = String::new(); // Lint, `Some` branch consumes `s`, but else branch doesn't use `s`. let _ = if let Some(x) = Some(0) { + //~^ option_if_let_else let s = s; s.len() + x } else { @@ -223,24 +240,29 @@ fn main() { // issue #8492 let _ = match s { + //~^ option_if_let_else Some(string) => string.len(), None => 1, }; let _ = match Some(10) { + //~^ option_if_let_else Some(a) => a + 1, None => 5, }; let res: Result = Ok(5); let _ = match res { + //~^ option_if_let_else Ok(a) => a + 1, _ => 1, }; let _ = match res { + //~^ option_if_let_else Err(_) => 1, Ok(a) => a + 1, }; let _ = if let Ok(a) = res { a + 1 } else { 5 }; + //~^ option_if_let_else } #[allow(dead_code)] @@ -258,6 +280,7 @@ mod issue10729 { pub fn reproduce(initial: &Option) { // 👇 needs `.as_ref()` because initial is an `&Option<_>` let _ = match initial { + //~^ option_if_let_else Some(value) => do_something(value), None => 42, }; @@ -265,6 +288,7 @@ mod issue10729 { pub fn reproduce2(initial: &mut Option) { let _ = match initial { + //~^ option_if_let_else Some(value) => do_something2(value), None => 42, }; @@ -288,12 +312,14 @@ fn issue11429() { let opt: Option> = None; let mut _hashmap = if let Some(hm) = &opt { + //~^ option_if_let_else hm.clone() } else { HashMap::new() }; let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; + //~^ option_if_let_else } fn issue11893() { diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr index 32ff227632343..9eb41f81a539f 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -1,7 +1,8 @@ error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:12:5 + --> tests/ui/option_if_let_else.rs:13:5 | LL | / if let Some(x) = string { +LL | | LL | | (true, x) LL | | } else { LL | | (false, "hello") @@ -12,22 +13,23 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:30:13 + --> tests/ui/option_if_let_else.rs:32:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:31:13 + --> tests/ui/option_if_let_else.rs:34:13 | LL | let _ = if let Some(s) = &num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:32:13 + --> tests/ui/option_if_let_else.rs:36:13 | LL | let _ = if let Some(s) = &mut num { | _____________^ +LL | | LL | | *s += 1; LL | | s LL | | } else { @@ -38,22 +40,24 @@ LL | | }; help: try | LL ~ let _ = num.as_mut().map_or(&0, |s| { +LL + LL + *s += 1; LL + s LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:38:13 + --> tests/ui/option_if_let_else.rs:43:13 | LL | let _ = if let Some(ref s) = num { s } else { &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:39:13 + --> tests/ui/option_if_let_else.rs:45:13 | LL | let _ = if let Some(mut s) = num { | _____________^ +LL | | LL | | s += 1; LL | | s LL | | } else { @@ -64,16 +68,18 @@ LL | | }; help: try | LL ~ let _ = num.map_or(0, |mut s| { +LL + LL + s += 1; LL + s LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:45:13 + --> tests/ui/option_if_let_else.rs:52:13 | LL | let _ = if let Some(ref mut s) = num { | _____________^ +LL | | LL | | *s += 1; LL | | s LL | | } else { @@ -84,15 +90,17 @@ LL | | }; help: try | LL ~ let _ = num.as_mut().map_or(&0, |s| { +LL + LL + *s += 1; LL + s LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:54:5 + --> tests/ui/option_if_let_else.rs:62:5 | LL | / if let Some(x) = arg { +LL | | LL | | let y = x * x; LL | | y * y LL | | } else { @@ -103,30 +111,33 @@ LL | | } help: try | LL ~ arg.map_or(13, |x| { +LL + LL + let y = x * x; LL + y * y LL + }) | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:67:13 + --> tests/ui/option_if_let_else.rs:76:13 | LL | let _ = if let Some(x) = arg { | _____________^ +LL | | LL | | x LL | | } else { -... | +LL | | // map_or_else must be suggested +LL | | side_effect() LL | | }; | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:76:13 + --> tests/ui/option_if_let_else.rs:86:13 | LL | let _ = if let Some(x) = arg { | _____________^ +LL | | LL | | x * x * x * x LL | | } else { -LL | | let mut y = 1; ... | LL | | y LL | | }; @@ -143,9 +154,10 @@ LL ~ }, |x| x * x * x * x); | error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:109:13 + --> tests/ui/option_if_let_else.rs:120:13 | LL | / if let Some(idx) = s.find('.') { +LL | | LL | | vec![s[..idx].to_string(), s[idx..].to_string()] LL | | } else { LL | | vec![s.to_string()] @@ -153,13 +165,13 @@ LL | | } | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:120:5 + --> tests/ui/option_if_let_else.rs:132:5 | LL | / if let Ok(binding) = variable { +LL | | LL | | println!("Ok {binding}"); LL | | true -LL | | } else { -LL | | println!("Err"); +... | LL | | false LL | | } | |_____^ @@ -170,25 +182,26 @@ LL ~ variable.map_or_else(|_| { LL + println!("Err"); LL + false LL + }, |binding| { +LL + LL + println!("Ok {binding}"); LL + true LL + }) | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:144:13 + --> tests/ui/option_if_let_else.rs:157:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:154:13 + --> tests/ui/option_if_let_else.rs:168:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ +LL | | LL | | loop { LL | | if x == 0 { -LL | | break x; ... | LL | | 0 LL | | }; @@ -204,16 +217,17 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:182:13 + --> tests/ui/option_if_let_else.rs:197:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:186:13 + --> tests/ui/option_if_let_else.rs:202:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ +LL | | LL | | let s = s; LL | | s.len() + x LL | | } else { @@ -224,82 +238,90 @@ LL | | }; help: try | LL ~ let _ = Some(0).map_or(1, |x| { +LL + LL + let s = s; LL + s.len() + x LL ~ }); | error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:225:13 + --> tests/ui/option_if_let_else.rs:242:13 | LL | let _ = match s { | _____________^ +LL | | LL | | Some(string) => string.len(), LL | | None => 1, LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:229:13 + --> tests/ui/option_if_let_else.rs:247:13 | LL | let _ = match Some(10) { | _____________^ +LL | | LL | | Some(a) => a + 1, LL | | None => 5, LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:235:13 + --> tests/ui/option_if_let_else.rs:254:13 | LL | let _ = match res { | _____________^ +LL | | LL | | Ok(a) => a + 1, LL | | _ => 1, LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:239:13 + --> tests/ui/option_if_let_else.rs:259:13 | LL | let _ = match res { | _____________^ +LL | | LL | | Err(_) => 1, LL | | Ok(a) => a + 1, LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:243:13 + --> tests/ui/option_if_let_else.rs:264:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:260:17 + --> tests/ui/option_if_let_else.rs:282:17 | LL | let _ = match initial { | _________________^ +LL | | LL | | Some(value) => do_something(value), LL | | None => 42, LL | | }; | |_________^ help: try: `initial.as_ref().map_or(42, |value| do_something(value))` error: use Option::map_or instead of an if let/else - --> tests/ui/option_if_let_else.rs:267:17 + --> tests/ui/option_if_let_else.rs:290:17 | LL | let _ = match initial { | _________________^ +LL | | LL | | Some(value) => do_something2(value), LL | | None => 42, LL | | }; | |_________^ help: try: `initial.as_mut().map_or(42, |value| do_something2(value))` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:290:24 + --> tests/ui/option_if_let_else.rs:314:24 | LL | let mut _hashmap = if let Some(hm) = &opt { | ________________________^ +LL | | LL | | hm.clone() LL | | } else { LL | | HashMap::new() @@ -307,7 +329,7 @@ LL | | }; | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())` error: use Option::map_or_else instead of an if let/else - --> tests/ui/option_if_let_else.rs:296:19 + --> tests/ui/option_if_let_else.rs:321:19 | LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())` diff --git a/src/tools/clippy/tests/ui/option_map_or_err_ok.fixed b/src/tools/clippy/tests/ui/option_map_or_err_ok.fixed deleted file mode 100644 index 131f4b2093e71..0000000000000 --- a/src/tools/clippy/tests/ui/option_map_or_err_ok.fixed +++ /dev/null @@ -1,7 +0,0 @@ -#![warn(clippy::option_map_or_err_ok)] - -fn main() { - let x = Some("a"); - let _ = x.ok_or("a"); - //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value -} diff --git a/src/tools/clippy/tests/ui/option_map_or_err_ok.rs b/src/tools/clippy/tests/ui/option_map_or_err_ok.rs deleted file mode 100644 index 0f07a592ae5fd..0000000000000 --- a/src/tools/clippy/tests/ui/option_map_or_err_ok.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![warn(clippy::option_map_or_err_ok)] - -fn main() { - let x = Some("a"); - let _ = x.map_or(Err("a"), Ok); - //~^ ERROR: called `map_or(Err(_), Ok)` on an `Option` value -} diff --git a/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr b/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr deleted file mode 100644 index 1971af80aa8d4..0000000000000 --- a/src/tools/clippy/tests/ui/option_map_or_err_ok.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: called `map_or(Err(_), Ok)` on an `Option` value - --> tests/ui/option_map_or_err_ok.rs:5:13 - | -LL | let _ = x.map_or(Err("a"), Ok); - | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok_or`: `x.ok_or("a")` - | - = note: `-D clippy::option-map-or-err-ok` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::option_map_or_err_ok)]` - -error: aborting due to 1 previous error - diff --git a/src/tools/clippy/tests/ui/option_map_or_none.fixed b/src/tools/clippy/tests/ui/option_map_or_none.fixed index 5f0ef34d231ce..183bf32e5361e 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.fixed +++ b/src/tools/clippy/tests/ui/option_map_or_none.fixed @@ -8,12 +8,15 @@ fn main() { // Check `OPTION_MAP_OR_NONE`. // Single line case. let _: Option = opt.map(|x| x + 1); + //~^ option_map_or_none // Multi-line case. #[rustfmt::skip] let _: Option = opt.map(|x| x + 1); // function returning `Option` let _: Option = opt.and_then(bar); + //~^ option_map_or_none let _: Option = opt.and_then(|x| { + //~^ option_map_or_none let offset = 0; let height = x; Some(offset + height) @@ -21,4 +24,5 @@ fn main() { // Check `RESULT_MAP_OR_INTO_OPTION`. let _: Option = r.ok(); + //~^ result_map_or_into_option } diff --git a/src/tools/clippy/tests/ui/option_map_or_none.rs b/src/tools/clippy/tests/ui/option_map_or_none.rs index 56b1f61212d03..626f206b25981 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.rs +++ b/src/tools/clippy/tests/ui/option_map_or_none.rs @@ -8,14 +8,18 @@ fn main() { // Check `OPTION_MAP_OR_NONE`. // Single line case. let _: Option = opt.map_or(None, |x| Some(x + 1)); + //~^ option_map_or_none // Multi-line case. #[rustfmt::skip] let _: Option = opt.map_or(None, |x| { + //~^ option_map_or_none Some(x + 1) }); // function returning `Option` let _: Option = opt.map_or(None, bar); + //~^ option_map_or_none let _: Option = opt.map_or(None, |x| { + //~^ option_map_or_none let offset = 0; let height = x; Some(offset + height) @@ -23,4 +27,5 @@ fn main() { // Check `RESULT_MAP_OR_INTO_OPTION`. let _: Option = r.map_or(None, Some); + //~^ result_map_or_into_option } diff --git a/src/tools/clippy/tests/ui/option_map_or_none.stderr b/src/tools/clippy/tests/ui/option_map_or_none.stderr index cba29861296f3..f9290fb99bc1e 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.stderr +++ b/src/tools/clippy/tests/ui/option_map_or_none.stderr @@ -8,25 +8,27 @@ LL | let _: Option = opt.map_or(None, |x| Some(x + 1)); = help: to override `-D warnings` add `#[allow(clippy::option_map_or_none)]` error: called `map_or(None, ..)` on an `Option` value - --> tests/ui/option_map_or_none.rs:13:26 + --> tests/ui/option_map_or_none.rs:14:26 | LL | let _: Option = opt.map_or(None, |x| { | __________________________^ +LL | | LL | | Some(x + 1) LL | | }); | |_________________________^ help: consider using `map`: `opt.map(|x| x + 1)` error: called `map_or(None, ..)` on an `Option` value - --> tests/ui/option_map_or_none.rs:17:26 + --> tests/ui/option_map_or_none.rs:19:26 | LL | let _: Option = opt.map_or(None, bar); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `and_then`: `opt.and_then(bar)` error: called `map_or(None, ..)` on an `Option` value - --> tests/ui/option_map_or_none.rs:18:26 + --> tests/ui/option_map_or_none.rs:21:26 | LL | let _: Option = opt.map_or(None, |x| { | __________________________^ +LL | | LL | | let offset = 0; LL | | let height = x; LL | | Some(offset + height) @@ -36,6 +38,7 @@ LL | | }); help: consider using `and_then` | LL ~ let _: Option = opt.and_then(|x| { +LL + LL + let offset = 0; LL + let height = x; LL + Some(offset + height) @@ -43,7 +46,7 @@ LL ~ }); | error: called `map_or(None, Some)` on a `Result` value - --> tests/ui/option_map_or_none.rs:25:26 + --> tests/ui/option_map_or_none.rs:29:26 | LL | let _: Option = r.map_or(None, Some); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `r.ok()` diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed index 5dcc6464ff5f3..55c1b8f110ced 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed @@ -35,52 +35,71 @@ fn option_map_unit_fn() { let _ : Option<()> = x.field.map(do_nothing); if let Some(x_field) = x.field { do_nothing(x_field) } + //~^ option_map_unit_fn if let Some(x_field) = x.field { do_nothing(x_field) } + //~^ option_map_unit_fn if let Some(x_field) = x.field { diverge(x_field) } + //~^ option_map_unit_fn let captured = 10; if let Some(value) = x.field { do_nothing(value + captured) }; let _ : Option<()> = x.field.map(|value| do_nothing(value + captured)); if let Some(value) = x.field { x.do_option_nothing(value + captured) } + //~^ option_map_unit_fn if let Some(value) = x.field { x.do_option_plus_one(value + captured); } + //~^ option_map_unit_fn if let Some(value) = x.field { do_nothing(value + captured) } + //~^ option_map_unit_fn if let Some(value) = x.field { do_nothing(value + captured) } + //~^ option_map_unit_fn if let Some(value) = x.field { do_nothing(value + captured); } + //~^ option_map_unit_fn if let Some(value) = x.field { do_nothing(value + captured); } + //~^ option_map_unit_fn if let Some(value) = x.field { diverge(value + captured) } + //~^ option_map_unit_fn if let Some(value) = x.field { diverge(value + captured) } + //~^ option_map_unit_fn if let Some(value) = x.field { diverge(value + captured); } + //~^ option_map_unit_fn if let Some(value) = x.field { diverge(value + captured); } + //~^ option_map_unit_fn x.field.map(|value| plus_one(value + captured)); x.field.map(|value| { plus_one(value + captured) }); if let Some(value) = x.field { let y = plus_one(value + captured); } + //~^ option_map_unit_fn if let Some(value) = x.field { plus_one(value + captured); } + //~^ option_map_unit_fn if let Some(value) = x.field { plus_one(value + captured); } + //~^ option_map_unit_fn if let Some(ref value) = x.field { do_nothing(value + captured) } + //~^ option_map_unit_fn if let Some(a) = option() { do_nothing(a) } + //~^ option_map_unit_fn if let Some(value) = option() { println!("{:?}", value) } + //~^ option_map_unit_fn } fn main() {} diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs index 5489545fe3d98..5ed47e4c60b51 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs @@ -35,52 +35,71 @@ fn option_map_unit_fn() { let _ : Option<()> = x.field.map(do_nothing); x.field.map(do_nothing); + //~^ option_map_unit_fn x.field.map(do_nothing); + //~^ option_map_unit_fn x.field.map(diverge); + //~^ option_map_unit_fn let captured = 10; if let Some(value) = x.field { do_nothing(value + captured) }; let _ : Option<()> = x.field.map(|value| do_nothing(value + captured)); x.field.map(|value| x.do_option_nothing(value + captured)); + //~^ option_map_unit_fn x.field.map(|value| { x.do_option_plus_one(value + captured); }); + //~^ option_map_unit_fn x.field.map(|value| do_nothing(value + captured)); + //~^ option_map_unit_fn x.field.map(|value| { do_nothing(value + captured) }); + //~^ option_map_unit_fn x.field.map(|value| { do_nothing(value + captured); }); + //~^ option_map_unit_fn x.field.map(|value| { { do_nothing(value + captured); } }); + //~^ option_map_unit_fn x.field.map(|value| diverge(value + captured)); + //~^ option_map_unit_fn x.field.map(|value| { diverge(value + captured) }); + //~^ option_map_unit_fn x.field.map(|value| { diverge(value + captured); }); + //~^ option_map_unit_fn x.field.map(|value| { { diverge(value + captured); } }); + //~^ option_map_unit_fn x.field.map(|value| plus_one(value + captured)); x.field.map(|value| { plus_one(value + captured) }); x.field.map(|value| { let y = plus_one(value + captured); }); + //~^ option_map_unit_fn x.field.map(|value| { plus_one(value + captured); }); + //~^ option_map_unit_fn x.field.map(|value| { { plus_one(value + captured); } }); + //~^ option_map_unit_fn x.field.map(|ref value| { do_nothing(value + captured) }); + //~^ option_map_unit_fn option().map(do_nothing); + //~^ option_map_unit_fn option().map(|value| println!("{:?}", value)); + //~^ option_map_unit_fn } fn main() {} diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr index 5fd3dfd071c2f..3f7abae34eea7 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.stderr @@ -10,7 +10,7 @@ LL | x.field.map(do_nothing); = help: to override `-D warnings` add `#[allow(clippy::option_map_unit_fn)]` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:39:5 + --> tests/ui/option_map_unit_fn_fixable.rs:40:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -18,7 +18,7 @@ LL | x.field.map(do_nothing); | help: try: `if let Some(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:41:5 + --> tests/ui/option_map_unit_fn_fixable.rs:43:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -26,7 +26,7 @@ LL | x.field.map(diverge); | help: try: `if let Some(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:47:5 + --> tests/ui/option_map_unit_fn_fixable.rs:50:5 | LL | x.field.map(|value| x.do_option_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -34,7 +34,7 @@ LL | x.field.map(|value| x.do_option_nothing(value + captured)); | help: try: `if let Some(value) = x.field { x.do_option_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:49:5 + --> tests/ui/option_map_unit_fn_fixable.rs:53:5 | LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -42,7 +42,7 @@ LL | x.field.map(|value| { x.do_option_plus_one(value + captured); }); | help: try: `if let Some(value) = x.field { x.do_option_plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:52:5 + --> tests/ui/option_map_unit_fn_fixable.rs:57:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -50,7 +50,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:54:5 + --> tests/ui/option_map_unit_fn_fixable.rs:60:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -58,7 +58,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try: `if let Some(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:56:5 + --> tests/ui/option_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -66,7 +66,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:58:5 + --> tests/ui/option_map_unit_fn_fixable.rs:66:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -74,7 +74,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try: `if let Some(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:61:5 + --> tests/ui/option_map_unit_fn_fixable.rs:70:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -82,7 +82,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:63:5 + --> tests/ui/option_map_unit_fn_fixable.rs:73:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -90,7 +90,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try: `if let Some(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:65:5 + --> tests/ui/option_map_unit_fn_fixable.rs:76:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -98,7 +98,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:67:5 + --> tests/ui/option_map_unit_fn_fixable.rs:79:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -106,7 +106,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try: `if let Some(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:72:5 + --> tests/ui/option_map_unit_fn_fixable.rs:85:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -114,7 +114,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try: `if let Some(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:74:5 + --> tests/ui/option_map_unit_fn_fixable.rs:88:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -122,7 +122,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:76:5 + --> tests/ui/option_map_unit_fn_fixable.rs:91:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -130,7 +130,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try: `if let Some(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:79:5 + --> tests/ui/option_map_unit_fn_fixable.rs:95:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -138,7 +138,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try: `if let Some(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Option` value where `f` is a function that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:81:5 + --> tests/ui/option_map_unit_fn_fixable.rs:98:5 | LL | option().map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^^- @@ -146,7 +146,7 @@ LL | option().map(do_nothing); | help: try: `if let Some(a) = option() { do_nothing(a) }` error: called `map(f)` on an `Option` value where `f` is a closure that returns the unit type `()` - --> tests/ui/option_map_unit_fn_fixable.rs:83:5 + --> tests/ui/option_map_unit_fn_fixable.rs:101:5 | LL | option().map(|value| println!("{:?}", value)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs index 20e6c15b18d5f..dd2f80fefbeec 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.rs @@ -15,8 +15,10 @@ fn plus_one(value: usize) -> usize { fn option_map_unit_fn() { x.field.map(|value| { do_nothing(value); do_nothing(value) }); + //~^ ERROR: cannot find value x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); + //~^ ERROR: cannot find value // Suggestion for the let block should be `{ ... }` as it's too difficult to build a // proper suggestion for these cases @@ -24,7 +26,9 @@ fn option_map_unit_fn() { do_nothing(value); do_nothing(value) }); + //~^^^^ ERROR: cannot find value x.field.map(|value| { do_nothing(value); do_nothing(value); }); + //~^ ERROR: cannot find value // The following should suggest `if let Some(_X) ...` as it's difficult to generate a proper let variable name for them Some(42).map(diverge); diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr index 66271036113ca..8527850143295 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_unfixable.stderr @@ -5,19 +5,19 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); | ^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> tests/ui/option_map_unit_fn_unfixable.rs:19:5 + --> tests/ui/option_map_unit_fn_unfixable.rs:20:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> tests/ui/option_map_unit_fn_unfixable.rs:23:5 + --> tests/ui/option_map_unit_fn_unfixable.rs:25:5 | LL | x.field.map(|value| { | ^ not found in this scope error[E0425]: cannot find value `x` in this scope - --> tests/ui/option_map_unit_fn_unfixable.rs:27:5 + --> tests/ui/option_map_unit_fn_unfixable.rs:30:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^ not found in this scope diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index 625d654dd3964..1794ac57fe5b1 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -50,61 +50,80 @@ fn or_fun_call() { let with_constructor = Some(vec![1]); with_constructor.unwrap_or_else(make); + //~^ or_fun_call let with_new = Some(vec![1]); with_new.unwrap_or_default(); + //~^ unwrap_or_default let with_const_args = Some(vec![1]); with_const_args.unwrap_or_else(|| Vec::with_capacity(12)); + //~^ or_fun_call let with_err: Result<_, ()> = Ok(vec![1]); with_err.unwrap_or_else(|_| make()); + //~^ or_fun_call let with_err_args: Result<_, ()> = Ok(vec![1]); with_err_args.unwrap_or_else(|_| Vec::with_capacity(12)); + //~^ or_fun_call let with_default_trait = Some(1); with_default_trait.unwrap_or_default(); + //~^ unwrap_or_default let with_default_type = Some(1); with_default_type.unwrap_or_default(); + //~^ unwrap_or_default let self_default = None::; self_default.unwrap_or_else(::default); + //~^ or_fun_call let real_default = None::; real_default.unwrap_or_default(); + //~^ unwrap_or_default let with_vec = Some(vec![1]); with_vec.unwrap_or_default(); + //~^ unwrap_or_default let without_default = Some(Foo); without_default.unwrap_or_else(Foo::new); + //~^ or_fun_call let mut map = HashMap::::new(); map.entry(42).or_default(); + //~^ unwrap_or_default let mut map_vec = HashMap::>::new(); map_vec.entry(42).or_default(); + //~^ unwrap_or_default let mut btree = BTreeMap::::new(); btree.entry(42).or_default(); + //~^ unwrap_or_default let mut btree_vec = BTreeMap::>::new(); btree_vec.entry(42).or_default(); + //~^ unwrap_or_default let stringy = Some(String::new()); let _ = stringy.unwrap_or_default(); + //~^ unwrap_or_default let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or_else(|| format!("{} world.", hello)); + //~^ or_fun_call // index let map = HashMap::::new(); let _ = Some(1).unwrap_or_else(|| map[&1]); + //~^ or_fun_call let map = BTreeMap::::new(); let _ = Some(1).unwrap_or_else(|| map[&1]); + //~^ or_fun_call // don't lint index vec let vec = vec![1]; let _ = Some(1).unwrap_or(vec[1]); @@ -129,6 +148,7 @@ fn test_or_with_ctors() { let _ = opt.or(Some(two)); let _ = Some("a".to_string()).or_else(|| Some("b".to_string())); + //~^ or_fun_call let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) @@ -168,14 +188,17 @@ mod issue6675 { let s = "test".to_owned(); let s = &s as *const _; None.unwrap_or_else(|| ptr_to_ref(s)); + //~^ or_fun_call } fn bar() { let s = "test".to_owned(); let s = &s as *const _; None.unwrap_or_else(|| unsafe { ptr_to_ref(s) }); + //~^ or_fun_call #[rustfmt::skip] None.unwrap_or_else(|| unsafe { ptr_to_ref(s) }); + //~^ or_fun_call } } @@ -251,7 +274,9 @@ mod issue8993 { fn test_map_or() { let _ = Some(4).map_or_else(g, |v| v); + //~^ or_fun_call let _ = Some(4).map_or_else(g, f); + //~^ or_fun_call let _ = Some(4).map_or(0, f); } } @@ -283,24 +308,31 @@ mod lazy { let with_new = Some(vec![1]); with_new.unwrap_or_default(); + //~^ unwrap_or_default let with_default_trait = Some(1); with_default_trait.unwrap_or_default(); + //~^ unwrap_or_default let with_default_type = Some(1); with_default_type.unwrap_or_default(); + //~^ unwrap_or_default let real_default = None::; real_default.unwrap_or_default(); + //~^ unwrap_or_default let mut map = HashMap::::new(); map.entry(42).or_default(); + //~^ unwrap_or_default let mut btree = BTreeMap::::new(); btree.entry(42).or_default(); + //~^ unwrap_or_default let stringy = Some(String::new()); let _ = stringy.unwrap_or_default(); + //~^ unwrap_or_default // negative tests let self_default = None::; @@ -341,28 +373,36 @@ fn fn_call_in_nested_expr() { } let opt: Option = Some(1); - //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or_else(f); // suggest `.unwrap_or_else(f)` // - //~v ERROR: function call inside of `unwrap_or` + //~^^ or_fun_call + // + let _ = opt.unwrap_or_else(|| f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` // - //~v ERROR: function call inside of `unwrap_or` + //~^^ or_fun_call + // + let _ = opt.unwrap_or_else(|| { + //~^ or_fun_call let x = f(); x + 1 }); - //~v ERROR: function call inside of `map_or` + let _ = opt.map_or_else(|| f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` // - //~v ERROR: use of `unwrap_or` to construct default value + //~^^ or_fun_call + // + let _ = opt.unwrap_or_default(); + //~^ unwrap_or_default let opt_foo = Some(Foo { val: String::from("123"), }); - //~v ERROR: function call inside of `unwrap_or` + let _ = opt_foo.unwrap_or_else(|| Foo { val: String::default() }); + //~^ or_fun_call } fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index 5b7d8faec7bff..256db343c0573 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -50,61 +50,80 @@ fn or_fun_call() { let with_constructor = Some(vec![1]); with_constructor.unwrap_or(make()); + //~^ or_fun_call let with_new = Some(vec![1]); with_new.unwrap_or(Vec::new()); + //~^ unwrap_or_default let with_const_args = Some(vec![1]); with_const_args.unwrap_or(Vec::with_capacity(12)); + //~^ or_fun_call let with_err: Result<_, ()> = Ok(vec![1]); with_err.unwrap_or(make()); + //~^ or_fun_call let with_err_args: Result<_, ()> = Ok(vec![1]); with_err_args.unwrap_or(Vec::with_capacity(12)); + //~^ or_fun_call let with_default_trait = Some(1); with_default_trait.unwrap_or(Default::default()); + //~^ unwrap_or_default let with_default_type = Some(1); with_default_type.unwrap_or(u64::default()); + //~^ unwrap_or_default let self_default = None::; self_default.unwrap_or(::default()); + //~^ or_fun_call let real_default = None::; real_default.unwrap_or(::default()); + //~^ unwrap_or_default let with_vec = Some(vec![1]); with_vec.unwrap_or(vec![]); + //~^ unwrap_or_default let without_default = Some(Foo); without_default.unwrap_or(Foo::new()); + //~^ or_fun_call let mut map = HashMap::::new(); map.entry(42).or_insert(String::new()); + //~^ unwrap_or_default let mut map_vec = HashMap::>::new(); map_vec.entry(42).or_insert(vec![]); + //~^ unwrap_or_default let mut btree = BTreeMap::::new(); btree.entry(42).or_insert(String::new()); + //~^ unwrap_or_default let mut btree_vec = BTreeMap::>::new(); btree_vec.entry(42).or_insert(vec![]); + //~^ unwrap_or_default let stringy = Some(String::new()); let _ = stringy.unwrap_or(String::new()); + //~^ unwrap_or_default let opt = Some(1); let hello = "Hello"; let _ = opt.ok_or(format!("{} world.", hello)); + //~^ or_fun_call // index let map = HashMap::::new(); let _ = Some(1).unwrap_or(map[&1]); + //~^ or_fun_call let map = BTreeMap::::new(); let _ = Some(1).unwrap_or(map[&1]); + //~^ or_fun_call // don't lint index vec let vec = vec![1]; let _ = Some(1).unwrap_or(vec[1]); @@ -129,6 +148,7 @@ fn test_or_with_ctors() { let _ = opt.or(Some(two)); let _ = Some("a".to_string()).or(Some("b".to_string())); + //~^ or_fun_call let b = "b".to_string(); let _ = Some(Bar("a".to_string(), Duration::from_secs(1))) @@ -168,14 +188,17 @@ mod issue6675 { let s = "test".to_owned(); let s = &s as *const _; None.unwrap_or(ptr_to_ref(s)); + //~^ or_fun_call } fn bar() { let s = "test".to_owned(); let s = &s as *const _; None.unwrap_or(unsafe { ptr_to_ref(s) }); + //~^ or_fun_call #[rustfmt::skip] None.unwrap_or( unsafe { ptr_to_ref(s) } ); + //~^ or_fun_call } } @@ -251,7 +274,9 @@ mod issue8993 { fn test_map_or() { let _ = Some(4).map_or(g(), |v| v); + //~^ or_fun_call let _ = Some(4).map_or(g(), f); + //~^ or_fun_call let _ = Some(4).map_or(0, f); } } @@ -283,24 +308,31 @@ mod lazy { let with_new = Some(vec![1]); with_new.unwrap_or_else(Vec::new); + //~^ unwrap_or_default let with_default_trait = Some(1); with_default_trait.unwrap_or_else(Default::default); + //~^ unwrap_or_default let with_default_type = Some(1); with_default_type.unwrap_or_else(u64::default); + //~^ unwrap_or_default let real_default = None::; real_default.unwrap_or_else(::default); + //~^ unwrap_or_default let mut map = HashMap::::new(); map.entry(42).or_insert_with(String::new); + //~^ unwrap_or_default let mut btree = BTreeMap::::new(); btree.entry(42).or_insert_with(String::new); + //~^ unwrap_or_default let stringy = Some(String::new()); let _ = stringy.unwrap_or_else(String::new); + //~^ unwrap_or_default // negative tests let self_default = None::; @@ -341,28 +373,36 @@ fn fn_call_in_nested_expr() { } let opt: Option = Some(1); - //~v ERROR: function call inside of `unwrap_or` let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` // - //~v ERROR: function call inside of `unwrap_or` + //~^^ or_fun_call + // + let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` // - //~v ERROR: function call inside of `unwrap_or` + //~^^ or_fun_call + // + let _ = opt.unwrap_or({ + //~^ or_fun_call let x = f(); x + 1 }); - //~v ERROR: function call inside of `map_or` + let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` // - //~v ERROR: use of `unwrap_or` to construct default value + //~^^ or_fun_call + // + let _ = opt.unwrap_or({ i32::default() }); + //~^ unwrap_or_default let opt_foo = Some(Foo { val: String::from("123"), }); - //~v ERROR: function call inside of `unwrap_or` + let _ = opt_foo.unwrap_or(Foo { val: String::default() }); + //~^ or_fun_call } fn main() {} diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr index 9f90a830a2114..93c87b2f12cde 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.stderr +++ b/src/tools/clippy/tests/ui/or_fun_call.stderr @@ -8,7 +8,7 @@ LL | with_constructor.unwrap_or(make()); = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:55:14 + --> tests/ui/or_fun_call.rs:56:14 | LL | with_new.unwrap_or(Vec::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` @@ -17,202 +17,203 @@ LL | with_new.unwrap_or(Vec::new()); = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:58:21 + --> tests/ui/or_fun_call.rs:60:21 | LL | with_const_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Vec::with_capacity(12))` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:61:14 + --> tests/ui/or_fun_call.rs:64:14 | LL | with_err.unwrap_or(make()); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| make())` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:64:19 + --> tests/ui/or_fun_call.rs:68:19 | LL | with_err_args.unwrap_or(Vec::with_capacity(12)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|_| Vec::with_capacity(12))` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:67:24 + --> tests/ui/or_fun_call.rs:72:24 | LL | with_default_trait.unwrap_or(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:70:23 + --> tests/ui/or_fun_call.rs:76:23 | LL | with_default_type.unwrap_or(u64::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:73:18 + --> tests/ui/or_fun_call.rs:80:18 | LL | self_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(::default)` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:76:18 + --> tests/ui/or_fun_call.rs:84:18 | LL | real_default.unwrap_or(::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:79:14 + --> tests/ui/or_fun_call.rs:88:14 | LL | with_vec.unwrap_or(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:82:21 + --> tests/ui/or_fun_call.rs:92:21 | LL | without_default.unwrap_or(Foo::new()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(Foo::new)` error: use of `or_insert` to construct default value - --> tests/ui/or_fun_call.rs:85:19 + --> tests/ui/or_fun_call.rs:96:19 | LL | map.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` to construct default value - --> tests/ui/or_fun_call.rs:88:23 + --> tests/ui/or_fun_call.rs:100:23 | LL | map_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` to construct default value - --> tests/ui/or_fun_call.rs:91:21 + --> tests/ui/or_fun_call.rs:104:21 | LL | btree.entry(42).or_insert(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert` to construct default value - --> tests/ui/or_fun_call.rs:94:25 + --> tests/ui/or_fun_call.rs:108:25 | LL | btree_vec.entry(42).or_insert(vec![]); | ^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:97:21 + --> tests/ui/or_fun_call.rs:112:21 | LL | let _ = stringy.unwrap_or(String::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `ok_or` - --> tests/ui/or_fun_call.rs:101:17 + --> tests/ui/or_fun_call.rs:117:17 | LL | let _ = opt.ok_or(format!("{} world.", hello)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ok_or_else(|| format!("{} world.", hello))` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:105:21 + --> tests/ui/or_fun_call.rs:122:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:107:21 + --> tests/ui/or_fun_call.rs:125:21 | LL | let _ = Some(1).unwrap_or(map[&1]); | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| map[&1])` error: function call inside of `or` - --> tests/ui/or_fun_call.rs:131:35 + --> tests/ui/or_fun_call.rs:150:35 | LL | let _ = Some("a".to_string()).or(Some("b".to_string())); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:170:14 + --> tests/ui/or_fun_call.rs:190:14 | LL | None.unwrap_or(ptr_to_ref(s)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:176:14 + --> tests/ui/or_fun_call.rs:197:14 | LL | None.unwrap_or(unsafe { ptr_to_ref(s) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:178:14 + --> tests/ui/or_fun_call.rs:200:14 | LL | None.unwrap_or( unsafe { ptr_to_ref(s) } ); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })` error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:253:25 + --> tests/ui/or_fun_call.rs:276:25 | LL | let _ = Some(4).map_or(g(), |v| v); | ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)` error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:254:25 + --> tests/ui/or_fun_call.rs:278:25 | LL | let _ = Some(4).map_or(g(), f); | ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:285:18 + --> tests/ui/or_fun_call.rs:310:18 | LL | with_new.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:288:28 + --> tests/ui/or_fun_call.rs:314:28 | LL | with_default_trait.unwrap_or_else(Default::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:291:27 + --> tests/ui/or_fun_call.rs:318:27 | LL | with_default_type.unwrap_or_else(u64::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:294:22 + --> tests/ui/or_fun_call.rs:322:22 | LL | real_default.unwrap_or_else(::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `or_insert_with` to construct default value - --> tests/ui/or_fun_call.rs:297:23 + --> tests/ui/or_fun_call.rs:326:23 | LL | map.entry(42).or_insert_with(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `or_insert_with` to construct default value - --> tests/ui/or_fun_call.rs:300:25 + --> tests/ui/or_fun_call.rs:330:25 | LL | btree.entry(42).or_insert_with(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/or_fun_call.rs:303:25 + --> tests/ui/or_fun_call.rs:334:25 | LL | let _ = stringy.unwrap_or_else(String::new); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:345:17 + --> tests/ui/or_fun_call.rs:376:17 | LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:348:17 + --> tests/ui/or_fun_call.rs:381:17 | LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)` | ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:351:17 + --> tests/ui/or_fun_call.rs:386:17 | LL | let _ = opt.unwrap_or({ | _________________^ +LL | | LL | | let x = f(); LL | | x + 1 LL | | }); @@ -221,25 +222,26 @@ LL | | }); help: try | LL ~ let _ = opt.unwrap_or_else(|| { +LL + LL + let x = f(); LL + x + 1 LL ~ }); | error: function call inside of `map_or` - --> tests/ui/or_fun_call.rs:356:17 + --> tests/ui/or_fun_call.rs:392:17 | LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)` | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)` error: use of `unwrap_or` to construct default value - --> tests/ui/or_fun_call.rs:359:17 + --> tests/ui/or_fun_call.rs:397:17 | LL | let _ = opt.unwrap_or({ i32::default() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: function call inside of `unwrap_or` - --> tests/ui/or_fun_call.rs:365:21 + --> tests/ui/or_fun_call.rs:404:21 | LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })` diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.fixed b/src/tools/clippy/tests/ui/or_then_unwrap.fixed index c944786143521..ba9beef57afaa 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.fixed +++ b/src/tools/clippy/tests/ui/or_then_unwrap.fixed @@ -20,13 +20,19 @@ impl SomeOtherStruct { fn main() { let option: Option<&str> = None; let _ = option.unwrap_or("fallback"); // should trigger lint + // + //~^^ or_then_unwrap let result: Result<&str, &str> = Err("Error"); let _ = result.unwrap_or("fallback"); // should trigger lint + // + //~^^ or_then_unwrap // as part of a method chain let option: Option<&str> = None; let _ = option.map(|v| v).unwrap_or("fallback").to_string().chars(); // should trigger lint + // + //~^^ or_then_unwrap // Not Option/Result let instance = SomeStruct {}; diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.rs b/src/tools/clippy/tests/ui/or_then_unwrap.rs index 10e43e1d18969..fac90249a243c 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.rs +++ b/src/tools/clippy/tests/ui/or_then_unwrap.rs @@ -20,13 +20,19 @@ impl SomeOtherStruct { fn main() { let option: Option<&str> = None; let _ = option.or(Some("fallback")).unwrap(); // should trigger lint + // + //~^^ or_then_unwrap let result: Result<&str, &str> = Err("Error"); let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint + // + //~^^ or_then_unwrap // as part of a method chain let option: Option<&str> = None; let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint + // + //~^^ or_then_unwrap // Not Option/Result let instance = SomeStruct {}; diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.stderr b/src/tools/clippy/tests/ui/or_then_unwrap.stderr index f454316068f26..1160498c6053b 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.stderr +++ b/src/tools/clippy/tests/ui/or_then_unwrap.stderr @@ -8,13 +8,13 @@ LL | let _ = option.or(Some("fallback")).unwrap(); // should trigger lint = help: to override `-D warnings` add `#[allow(clippy::or_then_unwrap)]` error: found `.or(Ok(…)).unwrap()` - --> tests/ui/or_then_unwrap.rs:25:20 + --> tests/ui/or_then_unwrap.rs:27:20 | LL | let _ = result.or::<&str>(Ok("fallback")).unwrap(); // should trigger lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` error: found `.or(Some(…)).unwrap()` - --> tests/ui/or_then_unwrap.rs:29:31 + --> tests/ui/or_then_unwrap.rs:33:31 | LL | let _ = option.map(|v| v).or(Some("fallback")).unwrap().to_string().chars(); // should trigger lint | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or("fallback")` diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs index 81674653bdd3b..e1e0fa02a9371 100644 --- a/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs +++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/issue-3102.rs @@ -7,8 +7,8 @@ fn main() { // issue 3102 let num = 1; &x[num..10]; - //~^ ERROR: range is out of bounds - //~| NOTE: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` + //~^ out_of_bounds_indexing + &x[10..num]; - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing } diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs index c38ca51238165..e613e527eee48 100644 --- a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs +++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.rs @@ -5,18 +5,22 @@ fn main() { let x = [1, 2, 3, 4]; &x[..=4]; - //~^ ERROR: range is out of bounds - //~| NOTE: `-D clippy::out-of-bounds-indexing` implied by `-D warnings` + //~^ out_of_bounds_indexing + &x[1..5]; - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing + &x[5..]; - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing + &x[..5]; - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing + &x[5..].iter().map(|x| 2 * x).collect::>(); - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing + &x[0..=4]; - //~^ ERROR: range is out of bounds + //~^ out_of_bounds_indexing &x[4..]; // Ok, should not produce stderr. &x[..4]; // Ok, should not produce stderr. diff --git a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr index 87d1d574dcb85..f895317334317 100644 --- a/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr +++ b/src/tools/clippy/tests/ui/out_of_bounds_indexing/simple.stderr @@ -14,25 +14,25 @@ LL | &x[1..5]; | ^ error: range is out of bounds - --> tests/ui/out_of_bounds_indexing/simple.rs:12:8 + --> tests/ui/out_of_bounds_indexing/simple.rs:13:8 | LL | &x[5..]; | ^ error: range is out of bounds - --> tests/ui/out_of_bounds_indexing/simple.rs:14:10 + --> tests/ui/out_of_bounds_indexing/simple.rs:16:10 | LL | &x[..5]; | ^ error: range is out of bounds - --> tests/ui/out_of_bounds_indexing/simple.rs:16:8 + --> tests/ui/out_of_bounds_indexing/simple.rs:19:8 | LL | &x[5..].iter().map(|x| 2 * x).collect::>(); | ^ error: range is out of bounds - --> tests/ui/out_of_bounds_indexing/simple.rs:18:12 + --> tests/ui/out_of_bounds_indexing/simple.rs:22:12 | LL | &x[0..=4]; | ^ diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed index b21e91aa3ad40..6818f96725e78 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.fixed @@ -8,10 +8,12 @@ fn main() { let d: bool = unimplemented!(); let e: bool = unimplemented!(); let _ = a; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = !(a && b); let _ = false; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + // don't lint on cfgs let _ = cfg!(you_shall_not_not_pass) && a; let _ = a || !b || !c || !d || !e; @@ -22,11 +24,14 @@ fn equality_stuff() { let a: i32 = unimplemented!(); let b: i32 = unimplemented!(); let _ = false; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = false; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = false; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = a > b && a == b; } diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs index 35ef0a1240a5d..f1cd9562a855a 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs @@ -8,10 +8,12 @@ fn main() { let d: bool = unimplemented!(); let e: bool = unimplemented!(); let _ = a && b || a; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = !(a && b); let _ = false && a; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + // don't lint on cfgs let _ = cfg!(you_shall_not_not_pass) && a; let _ = a || !b || !c || !d || !e; @@ -22,11 +24,14 @@ fn equality_stuff() { let a: i32 = unimplemented!(); let b: i32 = unimplemented!(); let _ = a == b && a != b; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = a < b && a >= b; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = a > b && a <= b; - //~^ ERROR: this boolean expression contains a logic bug + //~^ overly_complex_bool_expr + let _ = a > b && a == b; } diff --git a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr index 5a754236fe4b2..42a48a3b5be8e 100644 --- a/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr @@ -13,49 +13,49 @@ LL | let _ = a && b || a; = help: to override `-D warnings` add `#[allow(clippy::overly_complex_bool_expr)]` error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:13:13 + --> tests/ui/overly_complex_bool_expr.rs:14:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:13:22 + --> tests/ui/overly_complex_bool_expr.rs:14:22 | LL | let _ = false && a; | ^ error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:24:13 + --> tests/ui/overly_complex_bool_expr.rs:26:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:24:13 + --> tests/ui/overly_complex_bool_expr.rs:26:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:26:13 + --> tests/ui/overly_complex_bool_expr.rs:29:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:26:13 + --> tests/ui/overly_complex_bool_expr.rs:29:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> tests/ui/overly_complex_bool_expr.rs:28:13 + --> tests/ui/overly_complex_bool_expr.rs:32:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> tests/ui/overly_complex_bool_expr.rs:28:13 + --> tests/ui/overly_complex_bool_expr.rs:32:13 | LL | let _ = a > b && a <= b; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/owned_cow.fixed b/src/tools/clippy/tests/ui/owned_cow.fixed new file mode 100644 index 0000000000000..b62e9107a561e --- /dev/null +++ b/src/tools/clippy/tests/ui/owned_cow.fixed @@ -0,0 +1,23 @@ +#![warn(clippy::owned_cow)] + +use std::borrow::Cow; +use std::ffi::{CString, OsString}; +use std::path::PathBuf; + +fn main() { + let x: Cow<'static, str> = Cow::Owned(String::from("Hi!")); + //~^ ERROR: needlessly owned Cow type + let y: Cow<'_, [u8]> = Cow::Owned(vec![]); + //~^ ERROR: needlessly owned Cow type + let z: Cow<'_, [_]> = Cow::Owned(vec![2_i32]); + //~^ ERROR: needlessly owned Cow type + let o: Cow<'_, std::ffi::OsStr> = Cow::Owned(OsString::new()); + //~^ ERROR: needlessly owned Cow type + let c: Cow<'_, std::ffi::CStr> = Cow::Owned(CString::new("").unwrap()); + //~^ ERROR: needlessly owned Cow type + let p: Cow<'_, std::path::Path> = Cow::Owned(PathBuf::new()); + //~^ ERROR: needlessly owned Cow type + + // false positive: borrowed type + let b: Cow<'_, str> = Cow::Borrowed("Hi!"); +} diff --git a/src/tools/clippy/tests/ui/owned_cow.rs b/src/tools/clippy/tests/ui/owned_cow.rs new file mode 100644 index 0000000000000..0e0f14711b7f8 --- /dev/null +++ b/src/tools/clippy/tests/ui/owned_cow.rs @@ -0,0 +1,23 @@ +#![warn(clippy::owned_cow)] + +use std::borrow::Cow; +use std::ffi::{CString, OsString}; +use std::path::PathBuf; + +fn main() { + let x: Cow<'static, String> = Cow::Owned(String::from("Hi!")); + //~^ ERROR: needlessly owned Cow type + let y: Cow<'_, Vec> = Cow::Owned(vec![]); + //~^ ERROR: needlessly owned Cow type + let z: Cow<'_, Vec<_>> = Cow::Owned(vec![2_i32]); + //~^ ERROR: needlessly owned Cow type + let o: Cow<'_, OsString> = Cow::Owned(OsString::new()); + //~^ ERROR: needlessly owned Cow type + let c: Cow<'_, CString> = Cow::Owned(CString::new("").unwrap()); + //~^ ERROR: needlessly owned Cow type + let p: Cow<'_, PathBuf> = Cow::Owned(PathBuf::new()); + //~^ ERROR: needlessly owned Cow type + + // false positive: borrowed type + let b: Cow<'_, str> = Cow::Borrowed("Hi!"); +} diff --git a/src/tools/clippy/tests/ui/owned_cow.stderr b/src/tools/clippy/tests/ui/owned_cow.stderr new file mode 100644 index 0000000000000..8985d6db623dd --- /dev/null +++ b/src/tools/clippy/tests/ui/owned_cow.stderr @@ -0,0 +1,41 @@ +error: needlessly owned Cow type + --> tests/ui/owned_cow.rs:8:25 + | +LL | let x: Cow<'static, String> = Cow::Owned(String::from("Hi!")); + | ^^^^^^ help: use: `str` + | + = note: `-D clippy::owned-cow` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::owned_cow)]` + +error: needlessly owned Cow type + --> tests/ui/owned_cow.rs:10:20 + | +LL | let y: Cow<'_, Vec> = Cow::Owned(vec![]); + | ^^^^^^^ help: use: `[u8]` + +error: needlessly owned Cow type + --> tests/ui/owned_cow.rs:12:20 + | +LL | let z: Cow<'_, Vec<_>> = Cow::Owned(vec![2_i32]); + | ^^^^^^ help: use: `[_]` + +error: needlessly owned Cow type + --> tests/ui/owned_cow.rs:14:20 + | +LL | let o: Cow<'_, OsString> = Cow::Owned(OsString::new()); + | ^^^^^^^^ help: use: `std::ffi::OsStr` + +error: needlessly owned Cow type + --> tests/ui/owned_cow.rs:16:20 + | +LL | let c: Cow<'_, CString> = Cow::Owned(CString::new("").unwrap()); + | ^^^^^^^ help: use: `std::ffi::CStr` + +error: needlessly owned Cow type + --> tests/ui/owned_cow.rs:18:20 + | +LL | let p: Cow<'_, PathBuf> = Cow::Owned(PathBuf::new()); + | ^^^^^^^ help: use: `std::path::Path` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.rs b/src/tools/clippy/tests/ui/panic_in_result_fn.rs index e2375aa996f7d..005e38db90216 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.rs +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.rs @@ -4,7 +4,7 @@ struct A; impl A { fn result_with_panic() -> Result // should emit lint - //~^ ERROR: used `panic!()` or assertion in a function that returns `Result` + //~^ panic_in_result_fn { panic!("error"); } @@ -51,12 +51,13 @@ impl A { } fn function_result_with_panic() -> Result // should emit lint -//~^ ERROR: used `panic!()` or assertion in a function that returns `Result` +//~^ panic_in_result_fn { panic!("error"); } fn in_closure() -> Result { + //~^ panic_in_result_fn let c = || panic!(); c() } diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr index 2d49b5ab1b8f1..1067f4fac11cf 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn.stderr +++ b/src/tools/clippy/tests/ui/panic_in_result_fn.stderr @@ -38,6 +38,7 @@ error: used `panic!()` or assertion in a function that returns `Result` --> tests/ui/panic_in_result_fn.rs:59:1 | LL | / fn in_closure() -> Result { +LL | | LL | | let c = || panic!(); LL | | c() LL | | } @@ -45,7 +46,7 @@ LL | | } | = help: `panic!()` or assertions should not be used in a function that returns `Result` as `Result` is expected to return an error instead of crashing note: return Err() instead of panicking - --> tests/ui/panic_in_result_fn.rs:60:16 + --> tests/ui/panic_in_result_fn.rs:61:16 | LL | let c = || panic!(); | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs index 672c4c7383392..4e70282415794 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs +++ b/src/tools/clippy/tests/ui/panic_in_result_fn_assertions.rs @@ -5,21 +5,21 @@ struct A; impl A { fn result_with_assert_with_message(x: i32) -> Result // should emit lint - //~^ ERROR: used `panic!()` or assertion in a function that returns `Result` + //~^ panic_in_result_fn { assert!(x == 5, "wrong argument"); Ok(true) } fn result_with_assert_eq(x: i32) -> Result // should emit lint - //~^ ERROR: used `panic!()` or assertion in a function that returns `Result` + //~^ panic_in_result_fn { assert_eq!(x, 5); Ok(true) } fn result_with_assert_ne(x: i32) -> Result // should emit lint - //~^ ERROR: used `panic!()` or assertion in a function that returns `Result` + //~^ panic_in_result_fn { assert_ne!(x, 1); Ok(true) diff --git a/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs b/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs index df89d8c50246a..c4549c6b84123 100644 --- a/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs +++ b/src/tools/clippy/tests/ui/panic_in_result_fn_debug_assertions.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::panic_in_result_fn)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/panicking_macros.rs b/src/tools/clippy/tests/ui/panicking_macros.rs index 2bbf5792ec4c2..65854d7eb4bf9 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.rs +++ b/src/tools/clippy/tests/ui/panicking_macros.rs @@ -20,61 +20,72 @@ fn inline_const() { fn panic() { let a = 2; panic!(); - //~^ ERROR: `panic` should not be present in production code - //~| NOTE: `-D clippy::panic` implied by `-D warnings` + //~^ panic + panic!("message"); - //~^ ERROR: `panic` should not be present in production code + //~^ panic + panic!("{} {}", "panic with", "multiple arguments"); - //~^ ERROR: `panic` should not be present in production code + //~^ panic + let b = a + 2; } fn todo() { let a = 2; todo!(); - //~^ ERROR: `todo` should not be present in production code - //~| NOTE: `-D clippy::todo` implied by `-D warnings` + //~^ todo + todo!("message"); - //~^ ERROR: `todo` should not be present in production code + //~^ todo + todo!("{} {}", "panic with", "multiple arguments"); - //~^ ERROR: `todo` should not be present in production code + //~^ todo + let b = a + 2; } fn unimplemented() { let a = 2; unimplemented!(); - //~^ ERROR: `unimplemented` should not be present in production code - //~| NOTE: `-D clippy::unimplemented` implied by `-D warnings` + //~^ unimplemented + unimplemented!("message"); - //~^ ERROR: `unimplemented` should not be present in production code + //~^ unimplemented + unimplemented!("{} {}", "panic with", "multiple arguments"); - //~^ ERROR: `unimplemented` should not be present in production code + //~^ unimplemented + let b = a + 2; } fn unreachable() { let a = 2; unreachable!(); - //~^ ERROR: usage of the `unreachable!` macro - //~| NOTE: `-D clippy::unreachable` implied by `-D warnings` + //~^ unreachable + unreachable!("message"); - //~^ ERROR: usage of the `unreachable!` macro + //~^ unreachable + unreachable!("{} {}", "panic with", "multiple arguments"); - //~^ ERROR: usage of the `unreachable!` macro + //~^ unreachable + let b = a + 2; } fn core_versions() { use core::{panic, todo, unimplemented, unreachable}; panic!(); - //~^ ERROR: `panic` should not be present in production code + //~^ panic + todo!(); - //~^ ERROR: `todo` should not be present in production code + //~^ todo + unimplemented!(); - //~^ ERROR: `unimplemented` should not be present in production code + //~^ unimplemented + unreachable!(); - //~^ ERROR: usage of the `unreachable!` macro + //~^ unreachable } fn assert() { diff --git a/src/tools/clippy/tests/ui/panicking_macros.stderr b/src/tools/clippy/tests/ui/panicking_macros.stderr index 7c0f0a7d37644..03e459e4ec6ec 100644 --- a/src/tools/clippy/tests/ui/panicking_macros.stderr +++ b/src/tools/clippy/tests/ui/panicking_macros.stderr @@ -14,13 +14,13 @@ LL | panic!("message"); | ^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:27:5 + --> tests/ui/panicking_macros.rs:28:5 | LL | panic!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:34:5 + --> tests/ui/panicking_macros.rs:36:5 | LL | todo!(); | ^^^^^^^ @@ -29,19 +29,19 @@ LL | todo!(); = help: to override `-D warnings` add `#[allow(clippy::todo)]` error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:37:5 + --> tests/ui/panicking_macros.rs:39:5 | LL | todo!("message"); | ^^^^^^^^^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:39:5 + --> tests/ui/panicking_macros.rs:42:5 | LL | todo!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:46:5 + --> tests/ui/panicking_macros.rs:50:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ @@ -50,19 +50,19 @@ LL | unimplemented!(); = help: to override `-D warnings` add `#[allow(clippy::unimplemented)]` error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:49:5 + --> tests/ui/panicking_macros.rs:53:5 | LL | unimplemented!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:51:5 + --> tests/ui/panicking_macros.rs:56:5 | LL | unimplemented!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:58:5 + --> tests/ui/panicking_macros.rs:64:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ @@ -71,37 +71,37 @@ LL | unreachable!(); = help: to override `-D warnings` add `#[allow(clippy::unreachable)]` error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:61:5 + --> tests/ui/panicking_macros.rs:67:5 | LL | unreachable!("message"); | ^^^^^^^^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:63:5 + --> tests/ui/panicking_macros.rs:70:5 | LL | unreachable!("{} {}", "panic with", "multiple arguments"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `panic` should not be present in production code - --> tests/ui/panicking_macros.rs:70:5 + --> tests/ui/panicking_macros.rs:78:5 | LL | panic!(); | ^^^^^^^^ error: `todo` should not be present in production code - --> tests/ui/panicking_macros.rs:72:5 + --> tests/ui/panicking_macros.rs:81:5 | LL | todo!(); | ^^^^^^^ error: `unimplemented` should not be present in production code - --> tests/ui/panicking_macros.rs:74:5 + --> tests/ui/panicking_macros.rs:84:5 | LL | unimplemented!(); | ^^^^^^^^^^^^^^^^ error: usage of the `unreachable!` macro - --> tests/ui/panicking_macros.rs:76:5 + --> tests/ui/panicking_macros.rs:87:5 | LL | unreachable!(); | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.rs b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs index dc2ddeada1e94..29789c9497567 100644 --- a/src/tools/clippy/tests/ui/panicking_overflow_checks.rs +++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.rs @@ -2,14 +2,20 @@ #![allow(clippy::needless_if)] fn test(a: u32, b: u32, c: u32) { - if a + b < a {} //~ panicking_overflow_checks - if a > a + b {} //~ panicking_overflow_checks - if a + b < b {} //~ panicking_overflow_checks - if b > a + b {} //~ panicking_overflow_checks + if a + b < a {} + //~^ panicking_overflow_checks + if a > a + b {} + //~^ panicking_overflow_checks + if a + b < b {} + //~^ panicking_overflow_checks + if b > a + b {} + //~^ panicking_overflow_checks if a - b > b {} if b < a - b {} - if a - b > a {} //~ panicking_overflow_checks - if a < a - b {} //~ panicking_overflow_checks + if a - b > a {} + //~^ panicking_overflow_checks + if a < a - b {} + //~^ panicking_overflow_checks if a + b < c {} if c > a + b {} if a - b < c {} diff --git a/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr index 1fae045788996..3022c9e52b0c2 100644 --- a/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr +++ b/src/tools/clippy/tests/ui/panicking_overflow_checks.stderr @@ -8,31 +8,31 @@ LL | if a + b < a {} = help: to override `-D warnings` add `#[allow(clippy::panicking_overflow_checks)]` error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/panicking_overflow_checks.rs:6:8 + --> tests/ui/panicking_overflow_checks.rs:7:8 | LL | if a > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/panicking_overflow_checks.rs:7:8 + --> tests/ui/panicking_overflow_checks.rs:9:8 | LL | if a + b < b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/panicking_overflow_checks.rs:8:8 + --> tests/ui/panicking_overflow_checks.rs:11:8 | LL | if b > a + b {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/panicking_overflow_checks.rs:11:8 + --> tests/ui/panicking_overflow_checks.rs:15:8 | LL | if a - b > a {} | ^^^^^^^^^ error: you are trying to use classic C overflow conditions that will fail in Rust - --> tests/ui/panicking_overflow_checks.rs:12:8 + --> tests/ui/panicking_overflow_checks.rs:17:8 | LL | if a < a - b {} | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/partial_pub_fields.rs b/src/tools/clippy/tests/ui/partial_pub_fields.rs index 316b36c25eacd..27f4b2a0b4fcb 100644 --- a/src/tools/clippy/tests/ui/partial_pub_fields.rs +++ b/src/tools/clippy/tests/ui/partial_pub_fields.rs @@ -8,23 +8,23 @@ fn main() { pub struct FileSet { files: HashMap, pub paths: HashMap, - //~^ ERROR: mixed usage of pub and non-pub fields + //~^ partial_pub_fields } pub struct Color { pub r: u8, pub g: u8, b: u8, - //~^ ERROR: mixed usage of pub and non-pub fields + //~^ partial_pub_fields } pub struct Point(i32, pub i32); - //~^ ERROR: mixed usage of pub and non-pub fields + //~^ partial_pub_fields pub struct Visibility { r#pub: bool, pub pos: u32, - //~^ ERROR: mixed usage of pub and non-pub fields + //~^ partial_pub_fields } // Don't lint on empty structs; diff --git a/src/tools/clippy/tests/ui/partialeq_ne_impl.rs b/src/tools/clippy/tests/ui/partialeq_ne_impl.rs index 555eeebe1c78a..a3b2b68708ba8 100644 --- a/src/tools/clippy/tests/ui/partialeq_ne_impl.rs +++ b/src/tools/clippy/tests/ui/partialeq_ne_impl.rs @@ -7,8 +7,8 @@ impl PartialEq for Foo { true } fn ne(&self, _: &Foo) -> bool { - //~^ ERROR: re-implementing `PartialEq::ne` is unnecessary - //~| NOTE: `-D clippy::partialeq-ne-impl` implied by `-D warnings` + //~^ partialeq_ne_impl + false } } diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed index 87adbca394847..e700cc56349f2 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.fixed +++ b/src/tools/clippy/tests/ui/partialeq_to_none.fixed @@ -12,6 +12,7 @@ impl PartialEq> for Foobar { #[allow(dead_code)] fn foo(f: Option) -> &'static str { if f.is_some() { "yay" } else { "nay" } + //~^ partialeq_to_none } fn foobar() -> Option<()> { @@ -42,19 +43,28 @@ fn main() { let x = Some(0); let _ = x.is_none(); + //~^ partialeq_to_none let _ = x.is_some(); + //~^ partialeq_to_none let _ = x.is_none(); + //~^ partialeq_to_none let _ = x.is_some(); + //~^ partialeq_to_none if foobar().is_none() {} + //~^ partialeq_to_none if bar().ok().is_some() {} + //~^ partialeq_to_none let _ = Some(1 + 2).is_some(); + //~^ partialeq_to_none let _ = { Some(0) }.is_none(); + //~^ partialeq_to_none let _ = { + //~^ partialeq_to_none /* This comment runs long */ @@ -65,10 +75,15 @@ fn main() { let _ = Foobar == None; let _ = optref().is_none(); + //~^ partialeq_to_none let _ = optref().is_some(); + //~^ partialeq_to_none let _ = optref().is_none(); + //~^ partialeq_to_none let _ = optref().is_some(); + //~^ partialeq_to_none let x = Box::new(Option::<()>::None); let _ = (*x).is_some(); + //~^ partialeq_to_none } diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs index b623e6a66268e..1bae076dd3377 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.rs +++ b/src/tools/clippy/tests/ui/partialeq_to_none.rs @@ -12,6 +12,7 @@ impl PartialEq> for Foobar { #[allow(dead_code)] fn foo(f: Option) -> &'static str { if f != None { "yay" } else { "nay" } + //~^ partialeq_to_none } fn foobar() -> Option<()> { @@ -42,19 +43,28 @@ fn main() { let x = Some(0); let _ = x == None; + //~^ partialeq_to_none let _ = x != None; + //~^ partialeq_to_none let _ = None == x; + //~^ partialeq_to_none let _ = None != x; + //~^ partialeq_to_none if foobar() == None {} + //~^ partialeq_to_none if bar().ok() != None {} + //~^ partialeq_to_none let _ = Some(1 + 2) != None; + //~^ partialeq_to_none let _ = { Some(0) } == None; + //~^ partialeq_to_none let _ = { + //~^ partialeq_to_none /* This comment runs long */ @@ -65,10 +75,15 @@ fn main() { let _ = Foobar == None; let _ = optref() == &&None; + //~^ partialeq_to_none let _ = &&None != optref(); + //~^ partialeq_to_none let _ = **optref() == None; + //~^ partialeq_to_none let _ = &None != *optref(); + //~^ partialeq_to_none let x = Box::new(Option::<()>::None); let _ = None != *x; + //~^ partialeq_to_none } diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr index b588fbf32b606..b09bd7fa0f420 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.stderr +++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr @@ -8,58 +8,59 @@ LL | if f != None { "yay" } else { "nay" } = help: to override `-D warnings` add `#[allow(clippy::partialeq_to_none)]` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:44:13 + --> tests/ui/partialeq_to_none.rs:45:13 | LL | let _ = x == None; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:45:13 + --> tests/ui/partialeq_to_none.rs:47:13 | LL | let _ = x != None; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:46:13 + --> tests/ui/partialeq_to_none.rs:49:13 | LL | let _ = None == x; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:47:13 + --> tests/ui/partialeq_to_none.rs:51:13 | LL | let _ = None != x; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:49:8 + --> tests/ui/partialeq_to_none.rs:54:8 | LL | if foobar() == None {} | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:51:8 + --> tests/ui/partialeq_to_none.rs:57:8 | LL | if bar().ok() != None {} | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:53:13 + --> tests/ui/partialeq_to_none.rs:60:13 | LL | let _ = Some(1 + 2) != None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:55:13 + --> tests/ui/partialeq_to_none.rs:63:13 | LL | let _ = { Some(0) } == None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:57:13 + --> tests/ui/partialeq_to_none.rs:66:13 | LL | let _ = { | _____________^ +LL | | LL | | /* LL | | This comment runs long LL | | */ @@ -70,6 +71,7 @@ LL | | } != None; help: use `Option::is_some()` instead | LL ~ let _ = { +LL + LL + /* LL + This comment runs long LL + */ @@ -78,31 +80,31 @@ LL ~ }.is_some(); | error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:67:13 + --> tests/ui/partialeq_to_none.rs:77:13 | LL | let _ = optref() == &&None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:68:13 + --> tests/ui/partialeq_to_none.rs:79:13 | LL | let _ = &&None != optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:69:13 + --> tests/ui/partialeq_to_none.rs:81:13 | LL | let _ = **optref() == None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:70:13 + --> tests/ui/partialeq_to_none.rs:83:13 | LL | let _ = &None != *optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> tests/ui/partialeq_to_none.rs:73:13 + --> tests/ui/partialeq_to_none.rs:87:13 | LL | let _ = None != *x; | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()` diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed b/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed index 1a46d72378f89..5c818bad3d53d 100644 --- a/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed +++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed @@ -5,4 +5,5 @@ use std::path::PathBuf; fn main() { let mut x = PathBuf::from("/foo"); x.push("bar"); + //~^ path_buf_push_overwrite } diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs b/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs index 3e3f84b17a4b9..650ae3286a0cb 100644 --- a/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs +++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs @@ -5,4 +5,5 @@ use std::path::PathBuf; fn main() { let mut x = PathBuf::from("/foo"); x.push("/bar"); + //~^ path_buf_push_overwrite } diff --git a/src/tools/clippy/tests/ui/path_ends_with_ext.fixed b/src/tools/clippy/tests/ui/path_ends_with_ext.fixed index 49767e242cee5..fa4286e11644f 100644 --- a/src/tools/clippy/tests/ui/path_ends_with_ext.fixed +++ b/src/tools/clippy/tests/ui/path_ends_with_ext.fixed @@ -9,7 +9,7 @@ macro_rules! arg { fn test(path: &Path) { path.extension().is_some_and(|ext| ext == "md"); - //~^ ERROR: this looks like a failed attempt at checking for the file extension + //~^ path_ends_with_ext // some "extensions" are allowed by default path.ends_with(".git"); @@ -30,7 +30,7 @@ fn test(path: &Path) { #[clippy::msrv = "1.69"] fn under_msv(path: &Path) -> bool { path.extension().map_or(false, |ext| ext == "md") - //~^ ERROR: this looks like a failed attempt at checking for the file extension + //~^ path_ends_with_ext } fn main() {} diff --git a/src/tools/clippy/tests/ui/path_ends_with_ext.rs b/src/tools/clippy/tests/ui/path_ends_with_ext.rs index 2dfd046218afa..00d7ede8ef936 100644 --- a/src/tools/clippy/tests/ui/path_ends_with_ext.rs +++ b/src/tools/clippy/tests/ui/path_ends_with_ext.rs @@ -9,7 +9,7 @@ macro_rules! arg { fn test(path: &Path) { path.ends_with(".md"); - //~^ ERROR: this looks like a failed attempt at checking for the file extension + //~^ path_ends_with_ext // some "extensions" are allowed by default path.ends_with(".git"); @@ -30,7 +30,7 @@ fn test(path: &Path) { #[clippy::msrv = "1.69"] fn under_msv(path: &Path) -> bool { path.ends_with(".md") - //~^ ERROR: this looks like a failed attempt at checking for the file extension + //~^ path_ends_with_ext } fn main() {} diff --git a/src/tools/clippy/tests/ui/pathbuf_init_then_push.rs b/src/tools/clippy/tests/ui/pathbuf_init_then_push.rs index 4a7ae00a73522..7b65392e9519f 100644 --- a/src/tools/clippy/tests/ui/pathbuf_init_then_push.rs +++ b/src/tools/clippy/tests/ui/pathbuf_init_then_push.rs @@ -3,17 +3,21 @@ use std::path::PathBuf; fn main() { - let mut path_buf = PathBuf::new(); //~ ERROR: calls to `push` immediately after creation + let mut path_buf = PathBuf::new(); + //~^ pathbuf_init_then_push path_buf.push("foo"); - path_buf = PathBuf::from("foo"); //~ ERROR: calls to `push` immediately after creation + path_buf = PathBuf::from("foo"); + //~^ pathbuf_init_then_push path_buf.push("bar"); let bar = "bar"; - path_buf = PathBuf::from("foo"); //~ ERROR: calls to `push` immediately after creation + path_buf = PathBuf::from("foo"); + //~^ pathbuf_init_then_push path_buf.push(bar); - let mut path_buf = PathBuf::from("foo").join("bar"); //~ ERROR: calls to `push` immediately after creation + let mut path_buf = PathBuf::from("foo").join("bar"); + //~^ pathbuf_init_then_push path_buf.push("buz"); let mut x = PathBuf::new(); diff --git a/src/tools/clippy/tests/ui/pathbuf_init_then_push.stderr b/src/tools/clippy/tests/ui/pathbuf_init_then_push.stderr index e7aa291035d2e..1aa730a0bea26 100644 --- a/src/tools/clippy/tests/ui/pathbuf_init_then_push.stderr +++ b/src/tools/clippy/tests/ui/pathbuf_init_then_push.stderr @@ -2,6 +2,7 @@ error: calls to `push` immediately after creation --> tests/ui/pathbuf_init_then_push.rs:6:5 | LL | / let mut path_buf = PathBuf::new(); +LL | | LL | | path_buf.push("foo"); | |_________________________^ help: consider using the `.join()`: `let mut path_buf = PathBuf::from("foo");` | @@ -9,23 +10,26 @@ LL | | path_buf.push("foo"); = help: to override `-D warnings` add `#[allow(clippy::pathbuf_init_then_push)]` error: calls to `push` immediately after creation - --> tests/ui/pathbuf_init_then_push.rs:9:5 + --> tests/ui/pathbuf_init_then_push.rs:10:5 | LL | / path_buf = PathBuf::from("foo"); +LL | | LL | | path_buf.push("bar"); | |_________________________^ help: consider using the `.join()`: `path_buf = PathBuf::from("foo").join("bar");` error: calls to `push` immediately after creation - --> tests/ui/pathbuf_init_then_push.rs:13:5 + --> tests/ui/pathbuf_init_then_push.rs:15:5 | LL | / path_buf = PathBuf::from("foo"); +LL | | LL | | path_buf.push(bar); | |_______________________^ help: consider using the `.join()`: `path_buf = PathBuf::from("foo").join(bar);` error: calls to `push` immediately after creation - --> tests/ui/pathbuf_init_then_push.rs:16:5 + --> tests/ui/pathbuf_init_then_push.rs:19:5 | LL | / let mut path_buf = PathBuf::from("foo").join("bar"); +LL | | LL | | path_buf.push("buz"); | |_________________________^ help: consider using the `.join()`: `let mut path_buf = PathBuf::from("foo").join("bar").join("buz");` diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs index 61dee47cb1927..bdac3764bf167 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs @@ -7,14 +7,14 @@ fn should_lint() { let value = &Some(23); match value { Some(_) => (), - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch _ => (), } let value = &mut Some(23); match value { Some(_) => (), - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch _ => (), } } diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs index 558d496ae2c0f..3c789f570b038 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs @@ -13,11 +13,13 @@ fn alternatives() { // not ok if let Value::B | Value::A(_) = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let &Value::B | &Value::A(Some(_)) = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let Value::B | Value::A(Some(_)) = *ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok if let &Value::B | &Value::A(_) = ref_value {} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr index e1aec2497cd15..763f688ea8975 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr @@ -9,7 +9,7 @@ LL | if let Value::B | Value::A(_) = ref_value {} = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:17:34 + --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:18:34 | LL | if let &Value::B | &Value::A(Some(_)) = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let &Value::B | &Value::A(Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:19:32 + --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:21:32 | LL | if let Value::B | Value::A(Some(_)) = *ref_value {} | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs index d9b22693f297f..7fc53d591a917 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs @@ -11,11 +11,13 @@ fn struct_types() { // not ok let Struct { .. } = ref_value; - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let &Struct { ref_inner: Some(_) } = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let Struct { ref_inner: Some(_) } = *ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok let &Struct { .. } = ref_value; @@ -33,15 +35,19 @@ fn struct_enum_variants() { // not ok if let StructEnum::Var { .. } = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let StructEnum::Empty = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok if let &StructEnum::Var { .. } = ref_value {} diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr index e5d6e9ed6f819..70f7bdc389061 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr @@ -9,7 +9,7 @@ LL | let Struct { .. } = ref_value; = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:15:33 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:16:33 | LL | if let &Struct { ref_inner: Some(_) } = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let &Struct { ref_inner: Some(_) } = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:17:32 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:19:32 | LL | if let Struct { ref_inner: Some(_) } = *ref_value {} | ^^^^^^^ @@ -25,7 +25,7 @@ LL | if let Struct { ref_inner: Some(_) } = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:35:12 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:37:12 | LL | if let StructEnum::Var { .. } = ref_value {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | if let StructEnum::Var { .. } = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:37:12 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:40:12 | LL | if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | if let StructEnum::Var { inner_ref: Some(_) } = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:39:42 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:43:42 | LL | if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} | ^^^^^^^ @@ -49,7 +49,7 @@ LL | if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:41:41 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:46:41 | LL | if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} | ^^^^^^^ @@ -57,7 +57,7 @@ LL | if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_structs.rs:43:12 + --> tests/ui/pattern_type_mismatch/pattern_structs.rs:49:12 | LL | if let StructEnum::Empty = ref_value {} | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs index f44e3543c96ad..ecd95d9ae2b3b 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs @@ -9,11 +9,13 @@ fn tuple_types() { // not ok let TupleStruct(_) = ref_value; - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let &TupleStruct(Some(_)) = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let TupleStruct(Some(_)) = *ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok let &TupleStruct(_) = ref_value; @@ -31,13 +33,16 @@ fn tuple_enum_variants() { // not ok if let TupleEnum::Var(_) = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let &TupleEnum::Var(Some(_)) = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let TupleEnum::Var(Some(_)) = *ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let TupleEnum::Empty = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok if let &TupleEnum::Var(_) = ref_value {} @@ -53,11 +58,13 @@ fn plain_tuples() { // not ok let (_a, _b) = ref_value; - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let &(_a, Some(_)) = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + if let (_a, Some(_)) = *ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok let &(_a, _b) = ref_value; diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr index 9ecf12a1d639f..d47c5d509c3fa 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr @@ -9,7 +9,7 @@ LL | let TupleStruct(_) = ref_value; = help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]` error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:13:25 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:14:25 | LL | if let &TupleStruct(Some(_)) = ref_value {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | if let &TupleStruct(Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:15:24 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:17:24 | LL | if let TupleStruct(Some(_)) = *ref_value {} | ^^^^^^^ @@ -25,7 +25,7 @@ LL | if let TupleStruct(Some(_)) = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:33:12 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:35:12 | LL | if let TupleEnum::Var(_) = ref_value {} | ^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | if let TupleEnum::Var(_) = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:35:28 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:38:28 | LL | if let &TupleEnum::Var(Some(_)) = ref_value {} | ^^^^^^^ @@ -41,7 +41,7 @@ LL | if let &TupleEnum::Var(Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:37:27 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:41:27 | LL | if let TupleEnum::Var(Some(_)) = *ref_value {} | ^^^^^^^ @@ -49,7 +49,7 @@ LL | if let TupleEnum::Var(Some(_)) = *ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:39:12 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:44:12 | LL | if let TupleEnum::Empty = ref_value {} | ^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | if let TupleEnum::Empty = ref_value {} = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:55:9 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:60:9 | LL | let (_a, _b) = ref_value; | ^^^^^^^^ @@ -65,7 +65,7 @@ LL | let (_a, _b) = ref_value; = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:57:18 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:63:18 | LL | if let &(_a, Some(_)) = ref_value {} | ^^^^^^^ @@ -73,7 +73,7 @@ LL | if let &(_a, Some(_)) = ref_value {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:59:17 + --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:66:17 | LL | if let (_a, Some(_)) = *ref_value {} | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs index dbc7c3f31061c..0bbc26a0c27c5 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs @@ -9,7 +9,7 @@ fn syntax_match() { // not ok match ref_value { Some(_) => (), - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch None => (), } @@ -29,7 +29,7 @@ fn syntax_if_let() { // not ok if let Some(_) = ref_value {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok if let &Some(_) = ref_value {} @@ -41,7 +41,8 @@ fn syntax_while_let() { // not ok while let Some(_) = ref_value { - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch + break; } @@ -60,7 +61,7 @@ fn syntax_for() { // not ok for (_a, _b) in slice.iter() {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok for &(_a, _b) in slice.iter() {} @@ -71,7 +72,7 @@ fn syntax_let() { // not ok let (_n, _m) = ref_value; - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok let &(_n, _m) = ref_value; @@ -81,7 +82,7 @@ fn syntax_let() { fn syntax_fn() { // not ok fn foo((_a, _b): &(i32, i32)) {} - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok fn foo_ok_1(&(_a, _b): &(i32, i32)) {} @@ -96,7 +97,7 @@ fn syntax_closure() { // not ok foo(|(_a, _b)| ()); - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch // ok foo(|&(_a, _b)| ()); @@ -113,7 +114,7 @@ fn macro_with_expression() { // not ok matching_macro!(match value { Some(_) => (), - //~^ ERROR: type of pattern does not match the expression type + //~^ pattern_type_mismatch _ => (), }); @@ -134,6 +135,7 @@ fn macro_expansion() { // not ok match $e { Some(_) => (), + //~^ pattern_type_mismatch _ => (), } diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr index 9186a01b9c75f..3f6b5feb9b07b 100644 --- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr +++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr @@ -25,7 +25,7 @@ LL | while let Some(_) = ref_value { = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:62:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:63:9 | LL | for (_a, _b) in slice.iter() {} | ^^^^^^^^ @@ -33,7 +33,7 @@ LL | for (_a, _b) in slice.iter() {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:73:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:74:9 | LL | let (_n, _m) = ref_value; | ^^^^^^^^ @@ -41,7 +41,7 @@ LL | let (_n, _m) = ref_value; = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:83:12 + --> tests/ui/pattern_type_mismatch/syntax.rs:84:12 | LL | fn foo((_a, _b): &(i32, i32)) {} | ^^^^^^^^ @@ -49,7 +49,7 @@ LL | fn foo((_a, _b): &(i32, i32)) {} = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:98:10 + --> tests/ui/pattern_type_mismatch/syntax.rs:99:10 | LL | foo(|(_a, _b)| ()); | ^^^^^^^^ @@ -57,7 +57,7 @@ LL | foo(|(_a, _b)| ()); = help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:115:9 + --> tests/ui/pattern_type_mismatch/syntax.rs:116:9 | LL | Some(_) => (), | ^^^^^^^ @@ -65,7 +65,7 @@ LL | Some(_) => (), = help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings error: type of pattern does not match the expression type - --> tests/ui/pattern_type_mismatch/syntax.rs:136:17 + --> tests/ui/pattern_type_mismatch/syntax.rs:137:17 | LL | Some(_) => (), | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/patterns.fixed b/src/tools/clippy/tests/ui/patterns.fixed index feaec33ac15a1..bcb8ecfc38d25 100644 --- a/src/tools/clippy/tests/ui/patterns.fixed +++ b/src/tools/clippy/tests/ui/patterns.fixed @@ -12,6 +12,7 @@ fn main() { match v { Some(x) => (), y => (), + //~^ redundant_pattern } match v { Some(x) => (), @@ -27,6 +28,7 @@ fn main() { // required "ref" left out in suggestion: #5271 match mutv { ref mut x => { + //~^ redundant_pattern x.push(4); println!("vec: {:?}", x); }, @@ -35,6 +37,7 @@ fn main() { match mutv { ref x => println!("vec: {:?}", x), + //~^ redundant_pattern ref y if y == &vec![0] => (), } external! { diff --git a/src/tools/clippy/tests/ui/patterns.rs b/src/tools/clippy/tests/ui/patterns.rs index 53812c7deec3e..19639ebd13d60 100644 --- a/src/tools/clippy/tests/ui/patterns.rs +++ b/src/tools/clippy/tests/ui/patterns.rs @@ -12,6 +12,7 @@ fn main() { match v { Some(x) => (), y @ _ => (), + //~^ redundant_pattern } match v { Some(x) => (), @@ -27,6 +28,7 @@ fn main() { // required "ref" left out in suggestion: #5271 match mutv { ref mut x @ _ => { + //~^ redundant_pattern x.push(4); println!("vec: {:?}", x); }, @@ -35,6 +37,7 @@ fn main() { match mutv { ref x @ _ => println!("vec: {:?}", x), + //~^ redundant_pattern ref y if y == &vec![0] => (), } external! { diff --git a/src/tools/clippy/tests/ui/patterns.stderr b/src/tools/clippy/tests/ui/patterns.stderr index fa4cf7f835622..b9950fe181cc7 100644 --- a/src/tools/clippy/tests/ui/patterns.stderr +++ b/src/tools/clippy/tests/ui/patterns.stderr @@ -8,13 +8,13 @@ LL | y @ _ => (), = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern)]` error: the `x @ _` pattern can be written as just `x` - --> tests/ui/patterns.rs:29:9 + --> tests/ui/patterns.rs:30:9 | LL | ref mut x @ _ => { | ^^^^^^^^^^^^^ help: try: `ref mut x` error: the `x @ _` pattern can be written as just `x` - --> tests/ui/patterns.rs:37:9 + --> tests/ui/patterns.rs:39:9 | LL | ref x @ _ => println!("vec: {:?}", x), | ^^^^^^^^^ help: try: `ref x` diff --git a/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs b/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs index 5a84a64fd2d10..ccca523da551c 100644 --- a/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs +++ b/src/tools/clippy/tests/ui/permissions_set_readonly_false.rs @@ -17,8 +17,8 @@ fn main() { let mut permissions = metadata.permissions(); // lint here permissions.set_readonly(false); - //~^ ERROR: call to `set_readonly` with argument `false` - //~| NOTE: on Unix platforms this results in the file being world writable + //~^ permissions_set_readonly_false + // no lint permissions.set_readonly(true); diff --git a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs index b5abcbb3474c2..171716be26024 100644 --- a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs +++ b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs @@ -9,7 +9,8 @@ unsafe fn nomem_bad(p: &i32) { asm!( "asdf {p1}, {p2}, {p3}", p1 = in(reg) p, - //~^ ERROR: passing pointers to nomem asm block + //~^ pointers_in_nomem_asm_block + p2 = in(reg) p as *const _ as usize, p3 = in(reg) p, options(nomem, nostack, preserves_flags) @@ -24,10 +25,10 @@ unsafe fn nomem_good(p: &i32) { unsafe fn nomem_bad2(p: &mut i32) { asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); - //~^ ERROR: passing pointers to nomem asm block + //~^ pointers_in_nomem_asm_block } unsafe fn nomem_fn(p: extern "C" fn()) { asm!("call {p}", p = in(reg) p, options(nomem)); - //~^ ERROR: passing pointers to nomem asm block + //~^ pointers_in_nomem_asm_block } diff --git a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr index cabeb37344f2b..ca24e34f63c0f 100644 --- a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr +++ b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr @@ -13,7 +13,7 @@ LL | p3 = in(reg) p, = help: to override `-D warnings` add `#[allow(clippy::pointers_in_nomem_asm_block)]` error: passing pointers to nomem asm block - --> tests/ui/pointers_in_nomem_asm_block.rs:26:22 + --> tests/ui/pointers_in_nomem_asm_block.rs:27:22 | LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags)); | ^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags = note: if this is intentional and no pointers are read or written to, consider allowing the lint error: passing pointers to nomem asm block - --> tests/ui/pointers_in_nomem_asm_block.rs:31:22 + --> tests/ui/pointers_in_nomem_asm_block.rs:32:22 | LL | asm!("call {p}", p = in(reg) p, options(nomem)); | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/precedence.fixed b/src/tools/clippy/tests/ui/precedence.fixed index 52144a18bac0c..cbb78bff68bff 100644 --- a/src/tools/clippy/tests/ui/precedence.fixed +++ b/src/tools/clippy/tests/ui/precedence.fixed @@ -14,12 +14,19 @@ macro_rules! trip { fn main() { 1 << (2 + 3); + //~^ precedence (1 + 2) << 3; + //~^ precedence 4 >> (1 + 1); + //~^ precedence (1 + 3) >> 2; + //~^ precedence 1 ^ (1 - 1); + //~^ precedence 3 | (2 - 1); + //~^ precedence 3 & (5 - 2); + //~^ precedence 0x0F00 & 0x00F0 << 4; 0x0F00 & 0xF000 >> 4; 0x0F00 << 1 ^ 3; diff --git a/src/tools/clippy/tests/ui/precedence.rs b/src/tools/clippy/tests/ui/precedence.rs index 9ef5c43833f88..c73a4020e2e51 100644 --- a/src/tools/clippy/tests/ui/precedence.rs +++ b/src/tools/clippy/tests/ui/precedence.rs @@ -14,12 +14,19 @@ macro_rules! trip { fn main() { 1 << 2 + 3; + //~^ precedence 1 + 2 << 3; + //~^ precedence 4 >> 1 + 1; + //~^ precedence 1 + 3 >> 2; + //~^ precedence 1 ^ 1 - 1; + //~^ precedence 3 | 2 - 1; + //~^ precedence 3 & 5 - 2; + //~^ precedence 0x0F00 & 0x00F0 << 4; 0x0F00 & 0xF000 >> 4; 0x0F00 << 1 ^ 3; diff --git a/src/tools/clippy/tests/ui/precedence.stderr b/src/tools/clippy/tests/ui/precedence.stderr index 68ad5cb4829ad..50cd8f4b81464 100644 --- a/src/tools/clippy/tests/ui/precedence.stderr +++ b/src/tools/clippy/tests/ui/precedence.stderr @@ -8,37 +8,37 @@ LL | 1 << 2 + 3; = help: to override `-D warnings` add `#[allow(clippy::precedence)]` error: operator precedence might not be obvious - --> tests/ui/precedence.rs:17:5 + --> tests/ui/precedence.rs:18:5 | LL | 1 + 2 << 3; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 2) << 3` error: operator precedence might not be obvious - --> tests/ui/precedence.rs:18:5 + --> tests/ui/precedence.rs:20:5 | LL | 4 >> 1 + 1; | ^^^^^^^^^^ help: consider parenthesizing your expression: `4 >> (1 + 1)` error: operator precedence might not be obvious - --> tests/ui/precedence.rs:19:5 + --> tests/ui/precedence.rs:22:5 | LL | 1 + 3 >> 2; | ^^^^^^^^^^ help: consider parenthesizing your expression: `(1 + 3) >> 2` error: operator precedence might not be obvious - --> tests/ui/precedence.rs:20:5 + --> tests/ui/precedence.rs:24:5 | LL | 1 ^ 1 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `1 ^ (1 - 1)` error: operator precedence might not be obvious - --> tests/ui/precedence.rs:21:5 + --> tests/ui/precedence.rs:26:5 | LL | 3 | 2 - 1; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 | (2 - 1)` error: operator precedence might not be obvious - --> tests/ui/precedence.rs:22:5 + --> tests/ui/precedence.rs:28:5 | LL | 3 & 5 - 2; | ^^^^^^^^^ help: consider parenthesizing your expression: `3 & (5 - 2)` diff --git a/src/tools/clippy/tests/ui/precedence_bits.fixed b/src/tools/clippy/tests/ui/precedence_bits.fixed index 82fea0d14e43b..e0ce4a992bb12 100644 --- a/src/tools/clippy/tests/ui/precedence_bits.fixed +++ b/src/tools/clippy/tests/ui/precedence_bits.fixed @@ -26,9 +26,13 @@ fn main() { 3 | 2 - 1; 3 & 5 - 2; 0x0F00 & (0x00F0 << 4); + //~^ precedence_bits 0x0F00 & (0xF000 >> 4); + //~^ precedence_bits (0x0F00 << 1) ^ 3; + //~^ precedence_bits (0x0F00 << 1) | 2; + //~^ precedence_bits let b = 3; trip!(b * 8); diff --git a/src/tools/clippy/tests/ui/precedence_bits.rs b/src/tools/clippy/tests/ui/precedence_bits.rs index 9b353308b6ee3..20d17e26c3554 100644 --- a/src/tools/clippy/tests/ui/precedence_bits.rs +++ b/src/tools/clippy/tests/ui/precedence_bits.rs @@ -26,9 +26,13 @@ fn main() { 3 | 2 - 1; 3 & 5 - 2; 0x0F00 & 0x00F0 << 4; + //~^ precedence_bits 0x0F00 & 0xF000 >> 4; + //~^ precedence_bits 0x0F00 << 1 ^ 3; + //~^ precedence_bits 0x0F00 << 1 | 2; + //~^ precedence_bits let b = 3; trip!(b * 8); diff --git a/src/tools/clippy/tests/ui/precedence_bits.stderr b/src/tools/clippy/tests/ui/precedence_bits.stderr index f468186b363c8..9cbdca8956d64 100644 --- a/src/tools/clippy/tests/ui/precedence_bits.stderr +++ b/src/tools/clippy/tests/ui/precedence_bits.stderr @@ -8,19 +8,19 @@ LL | 0x0F00 & 0x00F0 << 4; = help: to override `-D warnings` add `#[allow(clippy::precedence_bits)]` error: operator precedence might not be obvious - --> tests/ui/precedence_bits.rs:29:5 + --> tests/ui/precedence_bits.rs:30:5 | LL | 0x0F00 & 0xF000 >> 4; | ^^^^^^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `0x0F00 & (0xF000 >> 4)` error: operator precedence might not be obvious - --> tests/ui/precedence_bits.rs:30:5 + --> tests/ui/precedence_bits.rs:32:5 | LL | 0x0F00 << 1 ^ 3; | ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) ^ 3` error: operator precedence might not be obvious - --> tests/ui/precedence_bits.rs:31:5 + --> tests/ui/precedence_bits.rs:34:5 | LL | 0x0F00 << 1 | 2; | ^^^^^^^^^^^^^^^ help: consider parenthesizing your expression: `(0x0F00 << 1) | 2` diff --git a/src/tools/clippy/tests/ui/print.rs b/src/tools/clippy/tests/ui/print.rs index 9ac4b51e1afd9..ee3d9dc0de037 100644 --- a/src/tools/clippy/tests/ui/print.rs +++ b/src/tools/clippy/tests/ui/print.rs @@ -9,8 +9,7 @@ struct Foo; impl Display for Foo { fn fmt(&self, f: &mut Formatter) -> Result { write!(f, "{:?}", 43.1415) - //~^ ERROR: use of `Debug`-based formatting - //~| NOTE: `-D clippy::use-debug` implied by `-D warnings` + //~^ use_debug } } @@ -23,21 +22,21 @@ impl Debug for Foo { fn main() { println!("Hello"); - //~^ ERROR: use of `println!` - //~| NOTE: `-D clippy::print-stdout` implied by `-D warnings` + //~^ print_stdout + print!("Hello"); - //~^ ERROR: use of `print!` + //~^ print_stdout print!("Hello {}", "World"); - //~^ ERROR: use of `print!` + //~^ print_stdout print!("Hello {:?}", "World"); - //~^ ERROR: use of `print!` - //~| ERROR: use of `Debug`-based formatting + //~^ print_stdout + //~| use_debug print!("Hello {:#?}", "#orld"); - //~^ ERROR: use of `print!` - //~| ERROR: use of `Debug`-based formatting + //~^ print_stdout + //~| use_debug assert_eq!(42, 1337); diff --git a/src/tools/clippy/tests/ui/print.stderr b/src/tools/clippy/tests/ui/print.stderr index a8374241c8312..9dd216bd1449d 100644 --- a/src/tools/clippy/tests/ui/print.stderr +++ b/src/tools/clippy/tests/ui/print.stderr @@ -8,7 +8,7 @@ LL | write!(f, "{:?}", 43.1415) = help: to override `-D warnings` add `#[allow(clippy::use_debug)]` error: use of `println!` - --> tests/ui/print.rs:25:5 + --> tests/ui/print.rs:24:5 | LL | println!("Hello"); | ^^^^^^^^^^^^^^^^^ @@ -17,37 +17,37 @@ LL | println!("Hello"); = help: to override `-D warnings` add `#[allow(clippy::print_stdout)]` error: use of `print!` - --> tests/ui/print.rs:28:5 + --> tests/ui/print.rs:27:5 | LL | print!("Hello"); | ^^^^^^^^^^^^^^^ error: use of `print!` - --> tests/ui/print.rs:31:5 + --> tests/ui/print.rs:30:5 | LL | print!("Hello {}", "World"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `print!` - --> tests/ui/print.rs:34:5 + --> tests/ui/print.rs:33:5 | LL | print!("Hello {:?}", "World"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> tests/ui/print.rs:34:19 + --> tests/ui/print.rs:33:19 | LL | print!("Hello {:?}", "World"); | ^^^^ error: use of `print!` - --> tests/ui/print.rs:38:5 + --> tests/ui/print.rs:37:5 | LL | print!("Hello {:#?}", "#orld"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: use of `Debug`-based formatting - --> tests/ui/print.rs:38:19 + --> tests/ui/print.rs:37:19 | LL | print!("Hello {:#?}", "#orld"); | ^^^^^ diff --git a/src/tools/clippy/tests/ui/print_in_format_impl.rs b/src/tools/clippy/tests/ui/print_in_format_impl.rs index 261f50832199c..8bc7049212209 100644 --- a/src/tools/clippy/tests/ui/print_in_format_impl.rs +++ b/src/tools/clippy/tests/ui/print_in_format_impl.rs @@ -18,17 +18,21 @@ impl Debug for Foo { static WORKS_WITH_NESTED_ITEMS: bool = true; print!("{}", 1); - //~^ ERROR: use of `print!` in `Debug` impl - //~| NOTE: `-D clippy::print-in-format-impl` implied by `-D warnings` + //~^ print_in_format_impl + println!("{}", 2); - //~^ ERROR: use of `println!` in `Debug` impl + //~^ print_in_format_impl + eprint!("{}", 3); - //~^ ERROR: use of `eprint!` in `Debug` impl + //~^ print_in_format_impl + eprintln!("{}", 4); - //~^ ERROR: use of `eprintln!` in `Debug` impl + //~^ print_in_format_impl + nested! { println!("nested"); - //~^ ERROR: use of `println!` in `Debug` impl + //~^ print_in_format_impl + }; write!(f, "{}", 5); @@ -42,7 +46,8 @@ impl Debug for Foo { impl Display for Foo { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { print!("Display"); - //~^ ERROR: use of `print!` in `Display` impl + //~^ print_in_format_impl + write!(f, "Display"); Ok(()) @@ -53,7 +58,8 @@ struct UnnamedFormatter; impl Debug for UnnamedFormatter { fn fmt(&self, _: &mut Formatter) -> Result<(), Error> { println!("UnnamedFormatter"); - //~^ ERROR: use of `println!` in `Debug` impl + //~^ print_in_format_impl + Ok(()) } } diff --git a/src/tools/clippy/tests/ui/print_in_format_impl.stderr b/src/tools/clippy/tests/ui/print_in_format_impl.stderr index 3fb6b3f9c9110..91d6ce953849e 100644 --- a/src/tools/clippy/tests/ui/print_in_format_impl.stderr +++ b/src/tools/clippy/tests/ui/print_in_format_impl.stderr @@ -14,31 +14,31 @@ LL | println!("{}", 2); | ^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(f, ..)` error: use of `eprint!` in `Debug` impl - --> tests/ui/print_in_format_impl.rs:25:9 + --> tests/ui/print_in_format_impl.rs:26:9 | LL | eprint!("{}", 3); | ^^^^^^^^^^^^^^^^ help: replace with: `write!(f, ..)` error: use of `eprintln!` in `Debug` impl - --> tests/ui/print_in_format_impl.rs:27:9 + --> tests/ui/print_in_format_impl.rs:29:9 | LL | eprintln!("{}", 4); | ^^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(f, ..)` error: use of `println!` in `Debug` impl - --> tests/ui/print_in_format_impl.rs:30:13 + --> tests/ui/print_in_format_impl.rs:33:13 | LL | println!("nested"); | ^^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(f, ..)` error: use of `print!` in `Display` impl - --> tests/ui/print_in_format_impl.rs:44:9 + --> tests/ui/print_in_format_impl.rs:48:9 | LL | print!("Display"); | ^^^^^^^^^^^^^^^^^ help: replace with: `write!(f, ..)` error: use of `println!` in `Debug` impl - --> tests/ui/print_in_format_impl.rs:55:9 + --> tests/ui/print_in_format_impl.rs:60:9 | LL | println!("UnnamedFormatter"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `writeln!(..)` diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed index 328e9a9b999f6..24c45a4a61b99 100644 --- a/src/tools/clippy/tests/ui/print_literal.fixed +++ b/src/tools/clippy/tests/ui/print_literal.fixed @@ -25,28 +25,32 @@ fn main() { // these should throw warnings print!("Hello world"); - //~^ ERROR: literal with an empty format string - //~| NOTE: `-D clippy::print-literal` implied by `-D warnings` + //~^ print_literal + println!("Hello {} world", world); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("Hello world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("a literal {:.4}", 5); - //~^ ERROR: literal with an empty format string + //~^ print_literal // positional args don't change the fact // that we're using a literal -- this should // throw a warning println!("hello world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("world hello"); - //~^ ERROR: literal with an empty format string + //~^ print_literal // named args shouldn't change anything either println!("hello world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("world hello"); - //~^ ERROR: literal with an empty format string + //~^ print_literal // The string literal from `file!()` has a callsite span that isn't marked as coming from an // expansion @@ -54,23 +58,33 @@ fn main() { // Braces in unicode escapes should not be escaped println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}"); + //~^ print_literal println!("\\\u{1234}"); + //~^ print_literal // This does not lint because it would have to suggest unescaping the character println!(r"{}", "\u{ab123}"); // These are not unicode escapes println!("\\u{{ab123}} \\u{{{{"); + //~^ print_literal println!(r"\u{{ab123}} \u{{{{"); + //~^ print_literal println!("\\{{ab123}} \\u{{{{"); + //~^ print_literal println!("\\u{{ab123}}"); + //~^ print_literal println!("\\\\u{{1234}}"); + //~^ print_literal println!("mixed: {{hello}} {world}"); + //~^ print_literal } fn issue_13959() { println!("\""); + //~^ print_literal println!( " + //~^ print_literal foo \\ \\\\ diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs index 3130d0b6998eb..42ae589ca639c 100644 --- a/src/tools/clippy/tests/ui/print_literal.rs +++ b/src/tools/clippy/tests/ui/print_literal.rs @@ -25,28 +25,32 @@ fn main() { // these should throw warnings print!("Hello {}", "world"); - //~^ ERROR: literal with an empty format string - //~| NOTE: `-D clippy::print-literal` implied by `-D warnings` + //~^ print_literal + println!("Hello {} {}", world, "world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("Hello {}", "world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("{} {:.4}", "a literal", 5); - //~^ ERROR: literal with an empty format string + //~^ print_literal // positional args don't change the fact // that we're using a literal -- this should // throw a warning println!("{0} {1}", "hello", "world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("{1} {0}", "hello", "world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal // named args shouldn't change anything either println!("{foo} {bar}", foo = "hello", bar = "world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal + println!("{bar} {foo}", foo = "hello", bar = "world"); - //~^ ERROR: literal with an empty format string + //~^ print_literal // The string literal from `file!()` has a callsite span that isn't marked as coming from an // expansion @@ -54,24 +58,34 @@ fn main() { // Braces in unicode escapes should not be escaped println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); + //~^ print_literal println!("{}", "\\\u{1234}"); + //~^ print_literal // This does not lint because it would have to suggest unescaping the character println!(r"{}", "\u{ab123}"); // These are not unicode escapes println!("{}", r"\u{ab123} \u{{"); + //~^ print_literal println!(r"{}", r"\u{ab123} \u{{"); + //~^ print_literal println!("{}", r"\{ab123} \u{{"); + //~^ print_literal println!("{}", "\\u{ab123}"); + //~^ print_literal println!("{}", "\\\\u{1234}"); + //~^ print_literal println!("mixed: {} {world}", "{hello}"); + //~^ print_literal } fn issue_13959() { println!("{}", r#"""#); + //~^ print_literal println!( "{}", r#" + //~^ print_literal foo \ \\ diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr index d967b7c24070a..da663000686fd 100644 --- a/src/tools/clippy/tests/ui/print_literal.stderr +++ b/src/tools/clippy/tests/ui/print_literal.stderr @@ -25,7 +25,7 @@ LL + println!("Hello {} world", world); | error: literal with an empty format string - --> tests/ui/print_literal.rs:32:26 + --> tests/ui/print_literal.rs:33:26 | LL | println!("Hello {}", "world"); | ^^^^^^^ @@ -37,7 +37,7 @@ LL + println!("Hello world"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:34:26 + --> tests/ui/print_literal.rs:36:26 | LL | println!("{} {:.4}", "a literal", 5); | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + println!("a literal {:.4}", 5); | error: literal with an empty format string - --> tests/ui/print_literal.rs:40:25 + --> tests/ui/print_literal.rs:42:25 | LL | println!("{0} {1}", "hello", "world"); | ^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + println!("hello world"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:42:25 + --> tests/ui/print_literal.rs:45:25 | LL | println!("{1} {0}", "hello", "world"); | ^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + println!("world hello"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:46:35 + --> tests/ui/print_literal.rs:49:35 | LL | println!("{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + println!("hello world"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:48:35 + --> tests/ui/print_literal.rs:52:35 | LL | println!("{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + println!("world hello"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:56:20 + --> tests/ui/print_literal.rs:60:20 | LL | println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:57:20 + --> tests/ui/print_literal.rs:62:20 | LL | println!("{}", "\\\u{1234}"); | ^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + println!("\\\u{1234}"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:61:20 + --> tests/ui/print_literal.rs:67:20 | LL | println!("{}", r"\u{ab123} \u{{"); | ^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + println!("\\u{{ab123}} \\u{{{{"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:62:21 + --> tests/ui/print_literal.rs:69:21 | LL | println!(r"{}", r"\u{ab123} \u{{"); | ^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + println!(r"\u{{ab123}} \u{{{{"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:63:20 + --> tests/ui/print_literal.rs:71:20 | LL | println!("{}", r"\{ab123} \u{{"); | ^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + println!("\\{{ab123}} \\u{{{{"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:64:20 + --> tests/ui/print_literal.rs:73:20 | LL | println!("{}", "\\u{ab123}"); | ^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + println!("\\u{{ab123}}"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:65:20 + --> tests/ui/print_literal.rs:75:20 | LL | println!("{}", "\\\\u{1234}"); | ^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + println!("\\\\u{{1234}}"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:67:35 + --> tests/ui/print_literal.rs:78:35 | LL | println!("mixed: {} {world}", "{hello}"); | ^^^^^^^^^ @@ -193,7 +193,7 @@ LL + println!("mixed: {{hello}} {world}"); | error: literal with an empty format string - --> tests/ui/print_literal.rs:71:20 + --> tests/ui/print_literal.rs:83:20 | LL | println!("{}", r#"""#); | ^^^^^^ @@ -205,12 +205,12 @@ LL + println!("\""); | error: literal with an empty format string - --> tests/ui/print_literal.rs:74:9 + --> tests/ui/print_literal.rs:87:9 | LL | / r#" +LL | | LL | | foo LL | | \ -LL | | \\ ... | LL | | bar LL | | "# @@ -219,6 +219,7 @@ LL | | "# help: try | LL ~ " +LL + LL + foo LL + \\ LL + \\\\ diff --git a/src/tools/clippy/tests/ui/print_stderr.rs b/src/tools/clippy/tests/ui/print_stderr.rs index 109f43ffe25d1..a086dfd37758d 100644 --- a/src/tools/clippy/tests/ui/print_stderr.rs +++ b/src/tools/clippy/tests/ui/print_stderr.rs @@ -2,10 +2,11 @@ fn main() { eprintln!("Hello"); - //~^ ERROR: use of `eprintln!` - //~| NOTE: `-D clippy::print-stderr` implied by `-D warnings` + //~^ print_stderr + println!("This should not do anything"); eprint!("World"); - //~^ ERROR: use of `eprint!` + //~^ print_stderr + print!("Nor should this"); } diff --git a/src/tools/clippy/tests/ui/print_stdout_build_script.rs b/src/tools/clippy/tests/ui/print_stdout_build_script.rs index 91448cb0faf8e..f01b8538ef496 100644 --- a/src/tools/clippy/tests/ui/print_stdout_build_script.rs +++ b/src/tools/clippy/tests/ui/print_stdout_build_script.rs @@ -1,4 +1,5 @@ //@compile-flags: --crate-name=build_script_build +//@ check-pass #![warn(clippy::print_stdout)] diff --git a/src/tools/clippy/tests/ui/print_with_newline.fixed b/src/tools/clippy/tests/ui/print_with_newline.fixed index 7ac6d2870c123..96c5ee4c1e92c 100644 --- a/src/tools/clippy/tests/ui/print_with_newline.fixed +++ b/src/tools/clippy/tests/ui/print_with_newline.fixed @@ -5,16 +5,19 @@ fn main() { println!("Hello"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline - //~| NOTE: `-D clippy::print-with-newline` implied by `-D warnings` + //~^ print_with_newline + println!("Hello {}", "world"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + println!("Hello {} {}", "world", "#2"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + println!("{}", 1265); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + println!(); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline // these are all fine print!(""); @@ -37,7 +40,8 @@ fn main() { // #3514 print!("\\n"); println!("\\"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + print!("\\\\n"); // Raw strings @@ -46,11 +50,11 @@ fn main() { // Literal newlines should also fail println!( - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline ); println!( - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline ); @@ -59,7 +63,8 @@ fn main() { print!("foo\r\n"); // should fail println!("\\r"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + print!("foo\rbar\n"); // Ignore expanded format strings diff --git a/src/tools/clippy/tests/ui/print_with_newline.rs b/src/tools/clippy/tests/ui/print_with_newline.rs index 602d1ea3ec0e1..60d1e47883081 100644 --- a/src/tools/clippy/tests/ui/print_with_newline.rs +++ b/src/tools/clippy/tests/ui/print_with_newline.rs @@ -5,16 +5,19 @@ fn main() { print!("Hello\n"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline - //~| NOTE: `-D clippy::print-with-newline` implied by `-D warnings` + //~^ print_with_newline + print!("Hello {}\n", "world"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + print!("Hello {} {}\n", "world", "#2"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + print!("{}\n", 1265); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + print!("\n"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline // these are all fine print!(""); @@ -37,7 +40,8 @@ fn main() { // #3514 print!("\\n"); print!("\\\n"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + print!("\\\\n"); // Raw strings @@ -46,12 +50,12 @@ fn main() { // Literal newlines should also fail print!( - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline " " ); print!( - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline r" " ); @@ -61,7 +65,8 @@ fn main() { print!("foo\r\n"); // should fail print!("\\r\n"); - //~^ ERROR: using `print!()` with a format string that ends in a single newline + //~^ print_with_newline + print!("foo\rbar\n"); // Ignore expanded format strings diff --git a/src/tools/clippy/tests/ui/print_with_newline.stderr b/src/tools/clippy/tests/ui/print_with_newline.stderr index 9b07299e61d36..9ead0fca113bb 100644 --- a/src/tools/clippy/tests/ui/print_with_newline.stderr +++ b/src/tools/clippy/tests/ui/print_with_newline.stderr @@ -25,7 +25,7 @@ LL + println!("Hello {}", "world"); | error: using `print!()` with a format string that ends in a single newline - --> tests/ui/print_with_newline.rs:12:5 + --> tests/ui/print_with_newline.rs:13:5 | LL | print!("Hello {} {}\n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + println!("Hello {} {}", "world", "#2"); | error: using `print!()` with a format string that ends in a single newline - --> tests/ui/print_with_newline.rs:14:5 + --> tests/ui/print_with_newline.rs:16:5 | LL | print!("{}\n", 1265); | ^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + println!("{}", 1265); | error: using `print!()` with a format string that ends in a single newline - --> tests/ui/print_with_newline.rs:16:5 + --> tests/ui/print_with_newline.rs:19:5 | LL | print!("\n"); | ^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + println!(); | error: using `print!()` with a format string that ends in a single newline - --> tests/ui/print_with_newline.rs:39:5 + --> tests/ui/print_with_newline.rs:42:5 | LL | print!("\\\n"); | ^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + println!("\\"); | error: using `print!()` with a format string that ends in a single newline - --> tests/ui/print_with_newline.rs:48:5 + --> tests/ui/print_with_newline.rs:52:5 | LL | / print!( LL | | @@ -90,7 +90,7 @@ LL ~ | error: using `print!()` with a format string that ends in a single newline - --> tests/ui/print_with_newline.rs:53:5 + --> tests/ui/print_with_newline.rs:57:5 | LL | / print!( LL | | @@ -107,7 +107,7 @@ LL ~ | error: using `print!()` with a format string that ends in a single newline - --> tests/ui/print_with_newline.rs:63:5 + --> tests/ui/print_with_newline.rs:67:5 | LL | print!("\\r\n"); | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/println_empty_string.fixed b/src/tools/clippy/tests/ui/println_empty_string.fixed index 20811fc753234..05e262ec77868 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.fixed +++ b/src/tools/clippy/tests/ui/println_empty_string.fixed @@ -3,15 +3,19 @@ fn main() { println!(); println!(); + //~^ println_empty_string match "a" { _ => println!(), + //~^ println_empty_string } eprintln!(); eprintln!(); + //~^ println_empty_string match "a" { _ => eprintln!(), + //~^ println_empty_string } } diff --git a/src/tools/clippy/tests/ui/println_empty_string.rs b/src/tools/clippy/tests/ui/println_empty_string.rs index 47f7277dce790..028ddb60dbce4 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.rs +++ b/src/tools/clippy/tests/ui/println_empty_string.rs @@ -3,15 +3,19 @@ fn main() { println!(); println!(""); + //~^ println_empty_string match "a" { _ => println!(""), + //~^ println_empty_string } eprintln!(); eprintln!(""); + //~^ println_empty_string match "a" { _ => eprintln!(""), + //~^ println_empty_string } } diff --git a/src/tools/clippy/tests/ui/println_empty_string.stderr b/src/tools/clippy/tests/ui/println_empty_string.stderr index 17de05fa25a42..8b997aef90696 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.stderr +++ b/src/tools/clippy/tests/ui/println_empty_string.stderr @@ -10,7 +10,7 @@ LL | println!(""); = help: to override `-D warnings` add `#[allow(clippy::println_empty_string)]` error: empty string literal in `println!` - --> tests/ui/println_empty_string.rs:8:14 + --> tests/ui/println_empty_string.rs:9:14 | LL | _ => println!(""), | ^^^^^^^^^--^ @@ -18,7 +18,7 @@ LL | _ => println!(""), | help: remove the empty string error: empty string literal in `eprintln!` - --> tests/ui/println_empty_string.rs:12:5 + --> tests/ui/println_empty_string.rs:14:5 | LL | eprintln!(""); | ^^^^^^^^^^--^ @@ -26,7 +26,7 @@ LL | eprintln!(""); | help: remove the empty string error: empty string literal in `eprintln!` - --> tests/ui/println_empty_string.rs:15:14 + --> tests/ui/println_empty_string.rs:18:14 | LL | _ => eprintln!(""), | ^^^^^^^^^^--^ diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs index e8b42d3b913b0..2d77bf06ff942 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.rs +++ b/src/tools/clippy/tests/ui/ptr_arg.rs @@ -11,39 +11,45 @@ use std::borrow::Cow; use std::path::{Path, PathBuf}; fn do_vec(x: &Vec) { - //~^ ERROR: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - //~| NOTE: `-D clippy::ptr-arg` implied by `-D warnings` + //~^ ptr_arg + //Nothing here } fn do_vec_mut(x: &mut Vec) { - //~^ ERROR: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice w + //~^ ptr_arg + //Nothing here } fn do_vec_mut2(x: &mut Vec) { - //~^ ERROR: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice w + //~^ ptr_arg + x.len(); x.is_empty(); } fn do_str(x: &String) { - //~^ ERROR: writing `&String` instead of `&str` involves a new object where a slice will d + //~^ ptr_arg + //Nothing here either } fn do_str_mut(x: &mut String) { - //~^ ERROR: writing `&mut String` instead of `&mut str` involves a new object where a slic + //~^ ptr_arg + //Nothing here either } fn do_path(x: &PathBuf) { - //~^ ERROR: writing `&PathBuf` instead of `&Path` involves a new object where a slice will + //~^ ptr_arg + //Nothing here either } fn do_path_mut(x: &mut PathBuf) { - //~^ ERROR: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a sl + //~^ ptr_arg + //Nothing here either } @@ -52,7 +58,8 @@ fn main() {} trait Foo { type Item; fn do_vec(x: &Vec); - //~^ ERROR: writing `&Vec` instead of `&[_]` involves a new object where a slice will + //~^ ptr_arg + fn do_item(x: &Self::Item); } @@ -66,7 +73,8 @@ impl Foo for Bar { } fn cloned(x: &Vec) -> Vec { - //~^ ERROR: writing `&Vec` instead of `&[_]` involves a new object where a slice will do + //~^ ptr_arg + let e = x.clone(); let f = e.clone(); // OK let g = x; @@ -76,7 +84,8 @@ fn cloned(x: &Vec) -> Vec { } fn str_cloned(x: &String) -> String { - //~^ ERROR: writing `&String` instead of `&str` involves a new object where a slice will d + //~^ ptr_arg + let a = x.clone(); let b = x.clone(); let c = b.clone(); @@ -85,7 +94,8 @@ fn str_cloned(x: &String) -> String { } fn path_cloned(x: &PathBuf) -> PathBuf { - //~^ ERROR: writing `&PathBuf` instead of `&Path` involves a new object where a slice will + //~^ ptr_arg + let a = x.clone(); let b = x.clone(); let c = b.clone(); @@ -94,7 +104,8 @@ fn path_cloned(x: &PathBuf) -> PathBuf { } fn false_positive_capacity(x: &Vec, y: &String) { - //~^ ERROR: writing `&String` instead of `&str` involves a new object where a slice will d + //~^ ptr_arg + let a = x.capacity(); let b = y.clone(); let c = y.as_str(); @@ -109,7 +120,7 @@ fn false_positive_capacity_too(x: &String) -> String { #[allow(dead_code)] fn test_cow_with_ref(c: &Cow<[i32]>) {} -//~^ ERROR: using a reference to `Cow` is not recommended +//~^ ptr_arg fn test_cow(c: Cow<[i32]>) { let _c = c; @@ -139,7 +150,7 @@ mod issue_5644 { } fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec, _s: &String) {} - //~^ ERROR: writing `&String` instead of `&str` involves a new object where a slice wi + //~^ ptr_arg struct S; impl S { @@ -169,26 +180,30 @@ mod issue6509 { use std::path::PathBuf; fn foo_vec(vec: &Vec) { - //~^ ERROR: writing `&Vec` instead of `&[_]` involves a new object where a slice will + //~^ ptr_arg + let _ = vec.clone().pop(); let _ = vec.clone().clone(); } fn foo_path(path: &PathBuf) { - //~^ ERROR: writing `&PathBuf` instead of `&Path` involves a new object where a slice + //~^ ptr_arg + let _ = path.clone().pop(); let _ = path.clone().clone(); } fn foo_str(str: &PathBuf) { - //~^ ERROR: writing `&PathBuf` instead of `&Path` involves a new object where a slice + //~^ ptr_arg + let _ = str.clone().pop(); let _ = str.clone().clone(); } } fn mut_vec_slice_methods(v: &mut Vec) { - //~^ ERROR: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice w + //~^ ptr_arg + v.copy_within(1..5, 10); } @@ -251,9 +266,10 @@ fn dyn_trait_ok(a: &mut Vec, b: &mut String, c: &mut PathBuf) { } fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { - //~^ ERROR: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice w - //~| ERROR: writing `&mut String` instead of `&mut str` involves a new object where a slic - //~| ERROR: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a sl + //~^ ptr_arg + //~| ptr_arg + //~| ptr_arg + trait T {} impl T for Vec {} impl T for [U] {} @@ -277,22 +293,26 @@ mod issue_9218 { // This one has an anonymous lifetime so it's not okay fn cow_elided_lifetime<'a>(input: &'a Cow) -> &'a str { - //~^ ERROR: using a reference to `Cow` is not recommended + //~^ ptr_arg + todo!() } // These two's return types don't use 'a so it's not okay fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str { - //~^ ERROR: using a reference to `Cow` is not recommended + //~^ ptr_arg + todo!() } fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { - //~^ ERROR: using a reference to `Cow` is not recommended + //~^ ptr_arg + todo!() } // Inferred to be `&'a str`, afaik. fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { + //~^ ERROR: elided lifetime has a name todo!() } } @@ -325,8 +345,9 @@ mod issue_13308 { // Other cases that are still ok to lint and ideally shouldn't regress fn good(v1: &String, v2: &String) { - //~^ ERROR: writing `&String` instead of `&str` - //~^^ ERROR: writing `&String` instead of `&str` + //~^ ptr_arg + //~| ptr_arg + h1(v1); h2(String::new(), v2); } diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr index 1a6b3aa1f8d41..741e60cbd749c 100644 --- a/src/tools/clippy/tests/ui/ptr_arg.stderr +++ b/src/tools/clippy/tests/ui/ptr_arg.stderr @@ -1,5 +1,5 @@ error: elided lifetime has a name - --> tests/ui/ptr_arg.rs:295:56 + --> tests/ui/ptr_arg.rs:314:56 | LL | fn cow_good_ret_ty<'a>(input: &'a Cow<'a, str>) -> &str { | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` @@ -23,43 +23,43 @@ LL | fn do_vec_mut(x: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:24:19 + --> tests/ui/ptr_arg.rs:25:19 | LL | fn do_vec_mut2(x: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [i64]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:30:14 + --> tests/ui/ptr_arg.rs:32:14 | LL | fn do_str(x: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:35:18 + --> tests/ui/ptr_arg.rs:38:18 | LL | fn do_str_mut(x: &mut String) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:40:15 + --> tests/ui/ptr_arg.rs:44:15 | LL | fn do_path(x: &PathBuf) { | ^^^^^^^^ help: change this to: `&Path` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:45:19 + --> tests/ui/ptr_arg.rs:50:19 | LL | fn do_path_mut(x: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:54:18 + --> tests/ui/ptr_arg.rs:60:18 | LL | fn do_vec(x: &Vec); | ^^^^^^^^^ help: change this to: `&[i64]` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:68:14 + --> tests/ui/ptr_arg.rs:75:14 | LL | fn cloned(x: &Vec) -> Vec { | ^^^^^^^^ @@ -68,6 +68,7 @@ help: change this to | LL ~ fn cloned(x: &[u8]) -> Vec { LL | +LL | LL ~ let e = x.to_owned(); LL | let f = e.clone(); // OK LL | let g = x; @@ -77,7 +78,7 @@ LL ~ x.to_owned() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:78:18 + --> tests/ui/ptr_arg.rs:86:18 | LL | fn str_cloned(x: &String) -> String { | ^^^^^^^ @@ -86,6 +87,7 @@ help: change this to | LL ~ fn str_cloned(x: &str) -> String { LL | +LL | LL ~ let a = x.to_owned(); LL ~ let b = x.to_owned(); LL | let c = b.clone(); @@ -94,7 +96,7 @@ LL ~ x.to_owned() | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:87:19 + --> tests/ui/ptr_arg.rs:96:19 | LL | fn path_cloned(x: &PathBuf) -> PathBuf { | ^^^^^^^^ @@ -103,6 +105,7 @@ help: change this to | LL ~ fn path_cloned(x: &Path) -> PathBuf { LL | +LL | LL ~ let a = x.to_path_buf(); LL ~ let b = x.to_path_buf(); LL | let c = b.clone(); @@ -111,7 +114,7 @@ LL ~ x.to_path_buf() | error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:96:44 + --> tests/ui/ptr_arg.rs:106:44 | LL | fn false_positive_capacity(x: &Vec, y: &String) { | ^^^^^^^ @@ -120,25 +123,26 @@ help: change this to | LL ~ fn false_positive_capacity(x: &Vec, y: &str) { LL | +LL | LL | let a = x.capacity(); LL ~ let b = y.to_owned(); LL ~ let c = y; | error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:111:25 + --> tests/ui/ptr_arg.rs:122:25 | LL | fn test_cow_with_ref(c: &Cow<[i32]>) {} | ^^^^^^^^^^^ help: change this to: `&[i32]` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:141:66 + --> tests/ui/ptr_arg.rs:152:66 | LL | fn some_allowed(#[allow(clippy::ptr_arg)] _v: &Vec, _s: &String) {} | ^^^^^^^ help: change this to: `&str` error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:171:21 + --> tests/ui/ptr_arg.rs:182:21 | LL | fn foo_vec(vec: &Vec) { | ^^^^^^^^ @@ -147,12 +151,13 @@ help: change this to | LL ~ fn foo_vec(vec: &[u8]) { LL | +LL | LL ~ let _ = vec.to_owned().pop(); LL ~ let _ = vec.to_owned().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:177:23 + --> tests/ui/ptr_arg.rs:189:23 | LL | fn foo_path(path: &PathBuf) { | ^^^^^^^^ @@ -161,12 +166,13 @@ help: change this to | LL ~ fn foo_path(path: &Path) { LL | +LL | LL ~ let _ = path.to_path_buf().pop(); LL ~ let _ = path.to_path_buf().clone(); | error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:183:21 + --> tests/ui/ptr_arg.rs:196:21 | LL | fn foo_str(str: &PathBuf) { | ^^^^^^^^ @@ -175,60 +181,61 @@ help: change this to | LL ~ fn foo_str(str: &Path) { LL | +LL | LL ~ let _ = str.to_path_buf().pop(); LL ~ let _ = str.to_path_buf().clone(); | error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:190:29 + --> tests/ui/ptr_arg.rs:204:29 | LL | fn mut_vec_slice_methods(v: &mut Vec) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:253:17 + --> tests/ui/ptr_arg.rs:268:17 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^^ help: change this to: `&mut [u32]` error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:253:35 + --> tests/ui/ptr_arg.rs:268:35 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^ help: change this to: `&mut str` error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:253:51 + --> tests/ui/ptr_arg.rs:268:51 | LL | fn dyn_trait(a: &mut Vec, b: &mut String, c: &mut PathBuf) { | ^^^^^^^^^^^^ help: change this to: `&mut Path` error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:279:39 + --> tests/ui/ptr_arg.rs:295:39 | LL | fn cow_elided_lifetime<'a>(input: &'a Cow) -> &'a str { | ^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:285:36 + --> tests/ui/ptr_arg.rs:302:36 | LL | fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` error: using a reference to `Cow` is not recommended - --> tests/ui/ptr_arg.rs:289:40 + --> tests/ui/ptr_arg.rs:307:40 | LL | fn cow_bad_ret_ty_2<'a, 'b>(input: &'a Cow<'a, str>) -> &'b str { | ^^^^^^^^^^^^^^^^ help: change this to: `&str` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:327:17 + --> tests/ui/ptr_arg.rs:347:17 | LL | fn good(v1: &String, v2: &String) { | ^^^^^^^ help: change this to: `&str` error: writing `&String` instead of `&str` involves a new object where a slice will do - --> tests/ui/ptr_arg.rs:327:30 + --> tests/ui/ptr_arg.rs:347:30 | LL | fn good(v1: &String, v2: &String) { | ^^^^^^^ help: change this to: `&str` diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index fa15c323540ff..2033f31c1eec7 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -16,6 +16,7 @@ mod issue_11278_b { pub fn f(o: &mut super::issue_11278_a::T) -> super::issue_11278_a::T { // Retain `super` *unsafe { Box::from_raw(Box::into_raw(Box::new(o)).cast::>()) } + //~^ ptr_as_ptr } } @@ -25,12 +26,15 @@ fn main() { let mut_ptr: *mut u32 = &mut 42_u32; let _ = ptr.cast::(); + //~^ ptr_as_ptr let _ = mut_ptr.cast::(); + //~^ ptr_as_ptr // Make sure the lint can handle the difference in their operator precedences. unsafe { let ptr_ptr: *const *const u32 = &ptr; let _ = (*ptr_ptr).cast::(); + //~^ ptr_as_ptr } // Changes in mutability. Do not lint this. @@ -44,10 +48,13 @@ fn main() { // Ensure the lint doesn't produce unnecessary turbofish for inferred types. let _: *const i32 = ptr.cast(); + //~^ ptr_as_ptr let _: *mut i32 = mut_ptr.cast(); + //~^ ptr_as_ptr // Make sure the lint is triggered inside a macro let _ = inline!($ptr.cast::()); + //~^ ptr_as_ptr // Do not lint inside macros from external crates let _ = external!($ptr as *const i32); @@ -69,7 +76,9 @@ fn _msrv_1_38() { let mut_ptr: *mut u32 = &mut 42_u32; let _ = ptr.cast::(); + //~^ ptr_as_ptr let _ = mut_ptr.cast::(); + //~^ ptr_as_ptr } #[allow(clippy::unnecessary_cast)] @@ -77,37 +86,45 @@ mod null { fn use_path_mut() -> *mut u32 { use std::ptr; ptr::null_mut::() + //~^ ptr_as_ptr } fn full_path_mut() -> *mut u32 { std::ptr::null_mut::() + //~^ ptr_as_ptr } fn core_path_mut() -> *mut u32 { use core::ptr; ptr::null_mut::() + //~^ ptr_as_ptr } fn full_core_path_mut() -> *mut u32 { core::ptr::null_mut::() + //~^ ptr_as_ptr } fn use_path() -> *const u32 { use std::ptr; ptr::null::() + //~^ ptr_as_ptr } fn full_path() -> *const u32 { std::ptr::null::() + //~^ ptr_as_ptr } fn core_path() -> *const u32 { use core::ptr; ptr::null::() + //~^ ptr_as_ptr } fn full_core_path() -> *const u32 { core::ptr::null::() + //~^ ptr_as_ptr } } @@ -115,37 +132,45 @@ mod null_ptr_infer { fn use_path_mut() -> *mut u32 { use std::ptr; ptr::null_mut() + //~^ ptr_as_ptr } fn full_path_mut() -> *mut u32 { std::ptr::null_mut() + //~^ ptr_as_ptr } fn core_path_mut() -> *mut u32 { use core::ptr; ptr::null_mut() + //~^ ptr_as_ptr } fn full_core_path_mut() -> *mut u32 { core::ptr::null_mut() + //~^ ptr_as_ptr } fn use_path() -> *const u32 { use std::ptr; ptr::null() + //~^ ptr_as_ptr } fn full_path() -> *const u32 { std::ptr::null() + //~^ ptr_as_ptr } fn core_path() -> *const u32 { use core::ptr; ptr::null() + //~^ ptr_as_ptr } fn full_core_path() -> *const u32 { core::ptr::null() + //~^ ptr_as_ptr } } @@ -153,36 +178,44 @@ mod null_entire_infer { fn use_path_mut() -> *mut u32 { use std::ptr; ptr::null_mut() + //~^ ptr_as_ptr } fn full_path_mut() -> *mut u32 { std::ptr::null_mut() + //~^ ptr_as_ptr } fn core_path_mut() -> *mut u32 { use core::ptr; ptr::null_mut() + //~^ ptr_as_ptr } fn full_core_path_mut() -> *mut u32 { core::ptr::null_mut() + //~^ ptr_as_ptr } fn use_path() -> *const u32 { use std::ptr; ptr::null() + //~^ ptr_as_ptr } fn full_path() -> *const u32 { std::ptr::null() + //~^ ptr_as_ptr } fn core_path() -> *const u32 { use core::ptr; ptr::null() + //~^ ptr_as_ptr } fn full_core_path() -> *const u32 { core::ptr::null() + //~^ ptr_as_ptr } } diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index 7ab52e63da556..224d09b0eb6e5 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -16,6 +16,7 @@ mod issue_11278_b { pub fn f(o: &mut super::issue_11278_a::T) -> super::issue_11278_a::T { // Retain `super` *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::issue_11278_a::T) } + //~^ ptr_as_ptr } } @@ -25,12 +26,15 @@ fn main() { let mut_ptr: *mut u32 = &mut 42_u32; let _ = ptr as *const i32; + //~^ ptr_as_ptr let _ = mut_ptr as *mut i32; + //~^ ptr_as_ptr // Make sure the lint can handle the difference in their operator precedences. unsafe { let ptr_ptr: *const *const u32 = &ptr; let _ = *ptr_ptr as *const i32; + //~^ ptr_as_ptr } // Changes in mutability. Do not lint this. @@ -44,10 +48,13 @@ fn main() { // Ensure the lint doesn't produce unnecessary turbofish for inferred types. let _: *const i32 = ptr as *const _; + //~^ ptr_as_ptr let _: *mut i32 = mut_ptr as _; + //~^ ptr_as_ptr // Make sure the lint is triggered inside a macro let _ = inline!($ptr as *const i32); + //~^ ptr_as_ptr // Do not lint inside macros from external crates let _ = external!($ptr as *const i32); @@ -69,7 +76,9 @@ fn _msrv_1_38() { let mut_ptr: *mut u32 = &mut 42_u32; let _ = ptr as *const i32; + //~^ ptr_as_ptr let _ = mut_ptr as *mut i32; + //~^ ptr_as_ptr } #[allow(clippy::unnecessary_cast)] @@ -77,37 +86,45 @@ mod null { fn use_path_mut() -> *mut u32 { use std::ptr; ptr::null_mut() as *mut u32 + //~^ ptr_as_ptr } fn full_path_mut() -> *mut u32 { std::ptr::null_mut() as *mut u32 + //~^ ptr_as_ptr } fn core_path_mut() -> *mut u32 { use core::ptr; ptr::null_mut() as *mut u32 + //~^ ptr_as_ptr } fn full_core_path_mut() -> *mut u32 { core::ptr::null_mut() as *mut u32 + //~^ ptr_as_ptr } fn use_path() -> *const u32 { use std::ptr; ptr::null() as *const u32 + //~^ ptr_as_ptr } fn full_path() -> *const u32 { std::ptr::null() as *const u32 + //~^ ptr_as_ptr } fn core_path() -> *const u32 { use core::ptr; ptr::null() as *const u32 + //~^ ptr_as_ptr } fn full_core_path() -> *const u32 { core::ptr::null() as *const u32 + //~^ ptr_as_ptr } } @@ -115,37 +132,45 @@ mod null_ptr_infer { fn use_path_mut() -> *mut u32 { use std::ptr; ptr::null_mut() as *mut _ + //~^ ptr_as_ptr } fn full_path_mut() -> *mut u32 { std::ptr::null_mut() as *mut _ + //~^ ptr_as_ptr } fn core_path_mut() -> *mut u32 { use core::ptr; ptr::null_mut() as *mut _ + //~^ ptr_as_ptr } fn full_core_path_mut() -> *mut u32 { core::ptr::null_mut() as *mut _ + //~^ ptr_as_ptr } fn use_path() -> *const u32 { use std::ptr; ptr::null() as *const _ + //~^ ptr_as_ptr } fn full_path() -> *const u32 { std::ptr::null() as *const _ + //~^ ptr_as_ptr } fn core_path() -> *const u32 { use core::ptr; ptr::null() as *const _ + //~^ ptr_as_ptr } fn full_core_path() -> *const u32 { core::ptr::null() as *const _ + //~^ ptr_as_ptr } } @@ -153,36 +178,44 @@ mod null_entire_infer { fn use_path_mut() -> *mut u32 { use std::ptr; ptr::null_mut() as _ + //~^ ptr_as_ptr } fn full_path_mut() -> *mut u32 { std::ptr::null_mut() as _ + //~^ ptr_as_ptr } fn core_path_mut() -> *mut u32 { use core::ptr; ptr::null_mut() as _ + //~^ ptr_as_ptr } fn full_core_path_mut() -> *mut u32 { core::ptr::null_mut() as _ + //~^ ptr_as_ptr } fn use_path() -> *const u32 { use std::ptr; ptr::null() as _ + //~^ ptr_as_ptr } fn full_path() -> *const u32 { std::ptr::null() as _ + //~^ ptr_as_ptr } fn core_path() -> *const u32 { use core::ptr; ptr::null() as _ + //~^ ptr_as_ptr } fn full_core_path() -> *const u32 { core::ptr::null() as _ + //~^ ptr_as_ptr } } diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index 18462620b0a30..66dae8e0135e3 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -8,37 +8,37 @@ LL | *unsafe { Box::from_raw(Box::into_raw(Box::new(o)) as *mut super::i = help: to override `-D warnings` add `#[allow(clippy::ptr_as_ptr)]` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:27:13 + --> tests/ui/ptr_as_ptr.rs:28:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:28:13 + --> tests/ui/ptr_as_ptr.rs:30:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:33:17 + --> tests/ui/ptr_as_ptr.rs:36:17 | LL | let _ = *ptr_ptr as *const i32; | ^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(*ptr_ptr).cast::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:46:25 + --> tests/ui/ptr_as_ptr.rs:50:25 | LL | let _: *const i32 = ptr as *const _; | ^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:47:23 + --> tests/ui/ptr_as_ptr.rs:52:23 | LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:50:21 + --> tests/ui/ptr_as_ptr.rs:56:21 | LL | let _ = inline!($ptr as *const i32); | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::()` @@ -46,157 +46,157 @@ LL | let _ = inline!($ptr as *const i32); = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:71:13 + --> tests/ui/ptr_as_ptr.rs:78:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:72:13 + --> tests/ui/ptr_as_ptr.rs:80:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:79:9 + --> tests/ui/ptr_as_ptr.rs:88:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:83:9 + --> tests/ui/ptr_as_ptr.rs:93:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:88:9 + --> tests/ui/ptr_as_ptr.rs:99:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:92:9 + --> tests/ui/ptr_as_ptr.rs:104:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:97:9 + --> tests/ui/ptr_as_ptr.rs:110:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:101:9 + --> tests/ui/ptr_as_ptr.rs:115:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:106:9 + --> tests/ui/ptr_as_ptr.rs:121:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:110:9 + --> tests/ui/ptr_as_ptr.rs:126:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:117:9 + --> tests/ui/ptr_as_ptr.rs:134:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:121:9 + --> tests/ui/ptr_as_ptr.rs:139:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:126:9 + --> tests/ui/ptr_as_ptr.rs:145:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:130:9 + --> tests/ui/ptr_as_ptr.rs:150:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:135:9 + --> tests/ui/ptr_as_ptr.rs:156:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:139:9 + --> tests/ui/ptr_as_ptr.rs:161:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:144:9 + --> tests/ui/ptr_as_ptr.rs:167:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:148:9 + --> tests/ui/ptr_as_ptr.rs:172:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:155:9 + --> tests/ui/ptr_as_ptr.rs:180:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:159:9 + --> tests/ui/ptr_as_ptr.rs:185:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:164:9 + --> tests/ui/ptr_as_ptr.rs:191:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:168:9 + --> tests/ui/ptr_as_ptr.rs:196:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:173:9 + --> tests/ui/ptr_as_ptr.rs:202:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:177:9 + --> tests/ui/ptr_as_ptr.rs:207:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:182:9 + --> tests/ui/ptr_as_ptr.rs:213:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:186:9 + --> tests/ui/ptr_as_ptr.rs:218:9 | LL | core::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed index 9a5272c7adc36..6dded72d3e191 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed @@ -13,7 +13,9 @@ use proc_macros::{external, inline_macros}; unsafe fn ptr_to_ref(p: *const T, om: *mut U) { let _: &mut T = std::mem::transmute(p.cast_mut()); + //~^ ptr_cast_constness let _ = &mut *p.cast_mut(); + //~^ ptr_cast_constness let _: &T = &*(om as *const T); } @@ -29,10 +31,13 @@ fn main() { unsafe { let ptr_ptr: *const *const u32 = &ptr; let _ = (*ptr_ptr).cast_mut(); + //~^ ptr_cast_constness } let _ = ptr.cast_mut(); + //~^ ptr_cast_constness let _ = mut_ptr.cast_const(); + //~^ ptr_cast_constness // Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4]; @@ -66,20 +71,28 @@ fn _msrv_1_65() { let mut_ptr: *mut u32 = &mut 42_u32; let _ = ptr.cast_mut(); + //~^ ptr_cast_constness let _ = mut_ptr.cast_const(); + //~^ ptr_cast_constness } #[inline_macros] fn null_pointers() { use std::ptr; let _ = std::ptr::null_mut::(); + //~^ ptr_cast_constness let _ = std::ptr::null::(); + //~^ ptr_cast_constness let _ = std::ptr::null_mut::(); + //~^ ptr_cast_constness let _ = std::ptr::null::(); + //~^ ptr_cast_constness // Make sure the lint is triggered inside a macro let _ = inline!(std::ptr::null_mut::()); + //~^ ptr_cast_constness let _ = inline!(std::ptr::null_mut::()); + //~^ ptr_cast_constness // Do not lint inside macros from external crates let _ = external!(ptr::null::() as *mut u32); diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs index 43ab5f5ba7ccc..e9629f5290ec1 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.rs +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs @@ -13,7 +13,9 @@ use proc_macros::{external, inline_macros}; unsafe fn ptr_to_ref(p: *const T, om: *mut U) { let _: &mut T = std::mem::transmute(p as *mut T); + //~^ ptr_cast_constness let _ = &mut *(p as *mut T); + //~^ ptr_cast_constness let _: &T = &*(om as *const T); } @@ -29,10 +31,13 @@ fn main() { unsafe { let ptr_ptr: *const *const u32 = &ptr; let _ = *ptr_ptr as *mut u32; + //~^ ptr_cast_constness } let _ = ptr as *mut u32; + //~^ ptr_cast_constness let _ = mut_ptr as *const u32; + //~^ ptr_cast_constness // Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4]; @@ -66,20 +71,28 @@ fn _msrv_1_65() { let mut_ptr: *mut u32 = &mut 42_u32; let _ = ptr as *mut u32; + //~^ ptr_cast_constness let _ = mut_ptr as *const u32; + //~^ ptr_cast_constness } #[inline_macros] fn null_pointers() { use std::ptr; let _ = ptr::null::() as *mut String; + //~^ ptr_cast_constness let _ = ptr::null_mut::() as *const u32; + //~^ ptr_cast_constness let _ = ptr::null::().cast_mut(); + //~^ ptr_cast_constness let _ = ptr::null_mut::().cast_const(); + //~^ ptr_cast_constness // Make sure the lint is triggered inside a macro let _ = inline!(ptr::null::() as *mut u32); + //~^ ptr_cast_constness let _ = inline!(ptr::null::().cast_mut()); + //~^ ptr_cast_constness // Do not lint inside macros from external crates let _ = external!(ptr::null::() as *mut u32); diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr index a693793a4ae96..1eeeef7470138 100644 --- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr +++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr @@ -8,67 +8,67 @@ 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:16:19 + --> tests/ui/ptr_cast_constness.rs:17: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:31:17 + --> tests/ui/ptr_cast_constness.rs:33: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:34:13 + --> tests/ui/ptr_cast_constness.rs:37: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:35:13 + --> tests/ui/ptr_cast_constness.rs:39: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:68:13 + --> tests/ui/ptr_cast_constness.rs:73: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:69:13 + --> tests/ui/ptr_cast_constness.rs:75:13 | LL | let _ = mut_ptr as *const u32; | ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()` error: `as` casting to make a const null pointer into a mutable null pointer - --> tests/ui/ptr_cast_constness.rs:75:13 + --> tests/ui/ptr_cast_constness.rs:82:13 | LL | let _ = ptr::null::() as *mut String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` error: `as` casting to make a mutable null pointer into a const null pointer - --> tests/ui/ptr_cast_constness.rs:76:13 + --> tests/ui/ptr_cast_constness.rs:84:13 | LL | let _ = ptr::null_mut::() as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` error: changing constness of a null pointer - --> tests/ui/ptr_cast_constness.rs:77:13 + --> tests/ui/ptr_cast_constness.rs:86:13 | LL | let _ = ptr::null::().cast_mut(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` error: changing constness of a null pointer - --> tests/ui/ptr_cast_constness.rs:78:13 + --> tests/ui/ptr_cast_constness.rs:88:13 | LL | let _ = ptr::null_mut::().cast_const(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::()` error: `as` casting to make a const null pointer into a mutable null pointer - --> tests/ui/ptr_cast_constness.rs:81:21 + --> tests/ui/ptr_cast_constness.rs:92:21 | LL | let _ = inline!(ptr::null::() as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` @@ -76,7 +76,7 @@ LL | let _ = inline!(ptr::null::() as *mut u32); = note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info) error: changing constness of a null pointer - --> tests/ui/ptr_cast_constness.rs:82:21 + --> tests/ui/ptr_cast_constness.rs:94:21 | LL | let _ = inline!(ptr::null::().cast_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::()` diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed index 3ae6df18c0a06..1ccd2c2237dee 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.fixed +++ b/src/tools/clippy/tests/ui/ptr_eq.fixed @@ -17,7 +17,9 @@ fn main() { let b = &[1, 2, 3]; let _ = std::ptr::eq(a, b); + //~^ ptr_eq let _ = std::ptr::eq(a, b); + //~^ ptr_eq let _ = a.as_ptr() == b as *const _; let _ = a.as_ptr() == b.as_ptr(); diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs index 440d5d94a8313..0bc58a57fa53d 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.rs +++ b/src/tools/clippy/tests/ui/ptr_eq.rs @@ -17,7 +17,9 @@ fn main() { let b = &[1, 2, 3]; let _ = a as *const _ as usize == b as *const _ as usize; + //~^ ptr_eq let _ = a as *const _ == b as *const _; + //~^ ptr_eq let _ = a.as_ptr() == b as *const _; let _ = a.as_ptr() == b.as_ptr(); diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr index bf8c2b5c08fb4..8e8b34f26ff77 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.stderr +++ b/src/tools/clippy/tests/ui/ptr_eq.stderr @@ -8,7 +8,7 @@ LL | let _ = a as *const _ as usize == b as *const _ as usize; = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:20:13 + --> tests/ui/ptr_eq.rs:21:13 | LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed index 97c8c394c03d4..b3e82fae38f30 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed @@ -29,7 +29,9 @@ fn main() { let b = &[1, 2, 3]; let _ = core::ptr::eq(a, b); + //~^ ptr_eq let _ = core::ptr::eq(a, b); + //~^ ptr_eq let _ = a.as_ptr() == b as *const _; let _ = a.as_ptr() == b.as_ptr(); diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs index a7ba9b4d81746..ba78f5ee5f84f 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs @@ -29,7 +29,9 @@ fn main() { let b = &[1, 2, 3]; let _ = a as *const _ as usize == b as *const _ as usize; + //~^ ptr_eq let _ = a as *const _ == b as *const _; + //~^ ptr_eq let _ = a.as_ptr() == b as *const _; let _ = a.as_ptr() == b.as_ptr(); diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr index 0463b75b720b9..8c7b1ff76661f 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr @@ -8,7 +8,7 @@ LL | let _ = a as *const _ as usize == b as *const _ as usize; = help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]` error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:32:13 + --> tests/ui/ptr_eq_no_std.rs:33:13 | LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed index 929512be63d48..4fe9dcf46c357 100644 --- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed +++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed @@ -10,10 +10,12 @@ fn main() { unsafe { let _ = ptr.add(offset_usize); + //~^ ptr_offset_with_cast let _ = ptr.offset(offset_isize as isize); let _ = ptr.offset(offset_u8 as isize); let _ = ptr.wrapping_add(offset_usize); + //~^ ptr_offset_with_cast let _ = ptr.wrapping_offset(offset_isize as isize); let _ = ptr.wrapping_offset(offset_u8 as isize); } diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs index 146bc27765ada..a1fb892733d35 100644 --- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs +++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs @@ -10,10 +10,12 @@ fn main() { unsafe { let _ = ptr.offset(offset_usize as isize); + //~^ ptr_offset_with_cast let _ = ptr.offset(offset_isize as isize); let _ = ptr.offset(offset_u8 as isize); let _ = ptr.wrapping_offset(offset_usize as isize); + //~^ ptr_offset_with_cast let _ = ptr.wrapping_offset(offset_isize as isize); let _ = ptr.wrapping_offset(offset_u8 as isize); } diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr index 87ff10adc9467..dcd5e027d1829 100644 --- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr +++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.stderr @@ -8,7 +8,7 @@ LL | let _ = ptr.offset(offset_usize as isize); = help: to override `-D warnings` add `#[allow(clippy::ptr_offset_with_cast)]` error: use of `wrapping_offset` with a `usize` casted to an `isize` - --> tests/ui/ptr_offset_with_cast.rs:16:17 + --> tests/ui/ptr_offset_with_cast.rs:17:17 | LL | let _ = ptr.wrapping_offset(offset_usize as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr.wrapping_add(offset_usize)` diff --git a/src/tools/clippy/tests/ui/pub_use.rs b/src/tools/clippy/tests/ui/pub_use.rs index aef947e406a68..be4d1b2a964bc 100644 --- a/src/tools/clippy/tests/ui/pub_use.rs +++ b/src/tools/clippy/tests/ui/pub_use.rs @@ -8,7 +8,7 @@ pub mod outer { } // should be linted pub use inner::Test; - //~^ ERROR: using `pub use` + //~^ pub_use } // should not be linted diff --git a/src/tools/clippy/tests/ui/pub_with_shorthand.fixed b/src/tools/clippy/tests/ui/pub_with_shorthand.fixed index 028209de06661..4036de8bbc0a6 100644 --- a/src/tools/clippy/tests/ui/pub_with_shorthand.fixed +++ b/src/tools/clippy/tests/ui/pub_with_shorthand.fixed @@ -11,14 +11,18 @@ extern crate proc_macros; pub(in self) fn a() {} +//~^ pub_with_shorthand pub(in self) fn b() {} pub fn c() {} mod a { pub(in super) fn d() {} pub(in super) fn e() {} + //~^ pub_with_shorthand pub(in self) fn f() {} + //~^ pub_with_shorthand pub(in crate) fn k() {} + //~^ pub_with_shorthand pub(in crate) fn m() {} mod b { pub(in crate::a) fn l() {} diff --git a/src/tools/clippy/tests/ui/pub_with_shorthand.rs b/src/tools/clippy/tests/ui/pub_with_shorthand.rs index 8578e3e0c4347..fac4ba990447a 100644 --- a/src/tools/clippy/tests/ui/pub_with_shorthand.rs +++ b/src/tools/clippy/tests/ui/pub_with_shorthand.rs @@ -11,14 +11,18 @@ extern crate proc_macros; pub(self) fn a() {} +//~^ pub_with_shorthand pub(in self) fn b() {} pub fn c() {} mod a { pub(in super) fn d() {} pub(super) fn e() {} + //~^ pub_with_shorthand pub(self) fn f() {} + //~^ pub_with_shorthand pub(crate) fn k() {} + //~^ pub_with_shorthand pub(in crate) fn m() {} mod b { pub(in crate::a) fn l() {} diff --git a/src/tools/clippy/tests/ui/pub_with_shorthand.stderr b/src/tools/clippy/tests/ui/pub_with_shorthand.stderr index 8978244c4c04a..00a3fc28ecb64 100644 --- a/src/tools/clippy/tests/ui/pub_with_shorthand.stderr +++ b/src/tools/clippy/tests/ui/pub_with_shorthand.stderr @@ -8,19 +8,19 @@ LL | pub(self) fn a() {} = help: to override `-D warnings` add `#[allow(clippy::pub_with_shorthand)]` error: usage of `pub` without `in` - --> tests/ui/pub_with_shorthand.rs:19:5 + --> tests/ui/pub_with_shorthand.rs:20:5 | LL | pub(super) fn e() {} | ^^^^^^^^^^ help: add it: `pub(in super)` error: usage of `pub` without `in` - --> tests/ui/pub_with_shorthand.rs:20:5 + --> tests/ui/pub_with_shorthand.rs:22:5 | LL | pub(self) fn f() {} | ^^^^^^^^^ help: add it: `pub(in self)` error: usage of `pub` without `in` - --> tests/ui/pub_with_shorthand.rs:21:5 + --> tests/ui/pub_with_shorthand.rs:24:5 | LL | pub(crate) fn k() {} | ^^^^^^^^^^ help: add it: `pub(in crate)` diff --git a/src/tools/clippy/tests/ui/pub_without_shorthand.fixed b/src/tools/clippy/tests/ui/pub_without_shorthand.fixed index 715e86c176458..fbe3326400cbc 100644 --- a/src/tools/clippy/tests/ui/pub_without_shorthand.fixed +++ b/src/tools/clippy/tests/ui/pub_without_shorthand.fixed @@ -12,14 +12,17 @@ extern crate proc_macros; pub(self) fn a() {} pub(self) fn b() {} +//~^ pub_without_shorthand pub fn c() {} mod a { pub(super) fn d() {} + //~^ pub_without_shorthand pub(super) fn e() {} pub(self) fn f() {} pub(crate) fn k() {} pub(crate) fn m() {} + //~^ pub_without_shorthand mod b { pub(in crate::a) fn l() {} } diff --git a/src/tools/clippy/tests/ui/pub_without_shorthand.rs b/src/tools/clippy/tests/ui/pub_without_shorthand.rs index ed2fd6f0f6174..fb756096c9d95 100644 --- a/src/tools/clippy/tests/ui/pub_without_shorthand.rs +++ b/src/tools/clippy/tests/ui/pub_without_shorthand.rs @@ -12,14 +12,17 @@ extern crate proc_macros; pub(self) fn a() {} pub(in self) fn b() {} +//~^ pub_without_shorthand pub fn c() {} mod a { pub(in super) fn d() {} + //~^ pub_without_shorthand pub(super) fn e() {} pub(self) fn f() {} pub(crate) fn k() {} pub(in crate) fn m() {} + //~^ pub_without_shorthand mod b { pub(in crate::a) fn l() {} } diff --git a/src/tools/clippy/tests/ui/pub_without_shorthand.stderr b/src/tools/clippy/tests/ui/pub_without_shorthand.stderr index e37c731732ba5..c823af6432de0 100644 --- a/src/tools/clippy/tests/ui/pub_without_shorthand.stderr +++ b/src/tools/clippy/tests/ui/pub_without_shorthand.stderr @@ -8,13 +8,13 @@ LL | pub(in self) fn b() {} = help: to override `-D warnings` add `#[allow(clippy::pub_without_shorthand)]` error: usage of `pub` with `in` - --> tests/ui/pub_without_shorthand.rs:18:5 + --> tests/ui/pub_without_shorthand.rs:19:5 | LL | pub(in super) fn d() {} | ^^^^^^^^^^^^^ help: remove it: `pub(super)` error: usage of `pub` with `in` - --> tests/ui/pub_without_shorthand.rs:22:5 + --> tests/ui/pub_without_shorthand.rs:24:5 | LL | pub(in crate) fn m() {} | ^^^^^^^^^^^^^ help: remove it: `pub(crate)` diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index b6e148e9f7724..8dfef3202be9c 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -141,6 +141,7 @@ fn func_returning_result() -> Result { fn result_func(x: Result) -> Result { let _ = x?; + //~^ question_mark x?; @@ -371,5 +372,6 @@ fn issue12412(foo: &Foo, bar: &Bar) -> Option<()> { }; // lint let v = bar.foo.owned.clone()?; + //~^^^ question_mark Some(()) } diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index 48dc9eb0a6261..fffaa803f39c2 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -5,6 +5,7 @@ fn some_func(a: Option) -> Option { if a.is_none() { + //~^ question_mark return None; } @@ -50,20 +51,24 @@ impl CopyStruct { #[rustfmt::skip] pub fn func(&self) -> Option { if (self.opt).is_none() { + //~^ question_mark return None; } if self.opt.is_none() { + //~^ question_mark return None } let _ = if self.opt.is_none() { + //~^ question_mark return None; } else { self.opt }; let _ = if let Some(x) = self.opt { + //~^ question_mark x } else { return None; @@ -81,6 +86,7 @@ pub struct MoveStruct { impl MoveStruct { pub fn ref_func(&self) -> Option> { if self.opt.is_none() { + //~^ question_mark return None; } @@ -89,6 +95,7 @@ impl MoveStruct { pub fn mov_func_reuse(self) -> Option> { if self.opt.is_none() { + //~^ question_mark return None; } @@ -97,6 +104,7 @@ impl MoveStruct { pub fn mov_func_no_use(self) -> Option> { if self.opt.is_none() { + //~^ question_mark return None; } Some(Vec::new()) @@ -104,6 +112,7 @@ impl MoveStruct { pub fn if_let_ref_func(self) -> Option> { let v: &Vec<_> = if let Some(ref v) = self.opt { + //~^ question_mark v } else { return None; @@ -114,6 +123,7 @@ impl MoveStruct { pub fn if_let_mov_func(self) -> Option> { let v = if let Some(v) = self.opt { + //~^ question_mark v } else { return None; @@ -135,10 +145,12 @@ fn func() -> Option { } if f().is_none() { + //~^ question_mark return None; } let _val = match f() { + //~^ question_mark Some(val) => val, None => return None, }; @@ -149,11 +161,13 @@ fn func() -> Option { }; match f() { + //~^ question_mark Some(val) => val, None => return None, }; match opt_none!() { + //~^ question_mark Some(x) => x, None => return None, }; @@ -180,17 +194,21 @@ fn func_returning_result() -> Result { fn result_func(x: Result) -> Result { let _ = if let Ok(x) = x { x } else { return x }; + //~^ question_mark if x.is_err() { + //~^ question_mark return x; } let _val = match func_returning_result() { + //~^ question_mark Ok(val) => val, Err(err) => return Err(err), }; match func_returning_result() { + //~^ question_mark Ok(val) => val, Err(err) => return Err(err), }; @@ -282,6 +300,7 @@ fn do_something() {} fn err_immediate_return() -> Result { if let Err(err) = func_returning_result() { + //~^ question_mark return Err(err); } Ok(1) @@ -289,6 +308,7 @@ fn err_immediate_return() -> Result { fn err_immediate_return_and_do_something() -> Result { if let Err(err) = func_returning_result() { + //~^ question_mark return Err(err); } do_something(); @@ -366,6 +386,7 @@ fn issue6828_nested_body() -> Option { try { fn f2(a: Option) -> Option { if a.is_none() { + //~^ question_mark return None; // do lint here, the outer `try` is not relevant here // https://github.com/rust-lang/rust-clippy/pull/11001#issuecomment-1610636867 @@ -428,5 +449,6 @@ fn issue12412(foo: &Foo, bar: &Bar) -> Option<()> { let Some(v) = bar.foo.owned.clone() else { return None; }; + //~^^^ question_mark Some(()) } diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 06a8bd0de349f..c4db0fbc30229 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -2,6 +2,7 @@ error: this block may be rewritten with the `?` operator --> tests/ui/question_mark.rs:7:5 | LL | / if a.is_none() { +LL | | LL | | return None; LL | | } | |_____^ help: replace it with: `a?;` @@ -10,26 +11,29 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::question_mark)]` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:52:9 + --> tests/ui/question_mark.rs:53:9 | LL | / if (self.opt).is_none() { +LL | | LL | | return None; LL | | } | |_________^ help: replace it with: `(self.opt)?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:56:9 + --> tests/ui/question_mark.rs:58:9 | LL | / if self.opt.is_none() { +LL | | LL | | return None LL | | } | |_________^ help: replace it with: `self.opt?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:60:17 + --> tests/ui/question_mark.rs:63:17 | LL | let _ = if self.opt.is_none() { | _________________^ +LL | | LL | | return None; LL | | } else { LL | | self.opt @@ -37,10 +41,11 @@ LL | | }; | |_________^ help: replace it with: `Some(self.opt?)` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:66:17 + --> tests/ui/question_mark.rs:70:17 | LL | let _ = if let Some(x) = self.opt { | _________________^ +LL | | LL | | x LL | | } else { LL | | return None; @@ -48,34 +53,38 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:83:9 + --> tests/ui/question_mark.rs:88:9 | LL | / if self.opt.is_none() { +LL | | LL | | return None; LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:91:9 + --> tests/ui/question_mark.rs:97:9 | LL | / if self.opt.is_none() { +LL | | LL | | return None; LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:99:9 + --> tests/ui/question_mark.rs:106:9 | LL | / if self.opt.is_none() { +LL | | LL | | return None; LL | | } | |_________^ help: replace it with: `self.opt.as_ref()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:106:26 + --> tests/ui/question_mark.rs:114:26 | LL | let v: &Vec<_> = if let Some(ref v) = self.opt { | __________________________^ +LL | | LL | | v LL | | } else { LL | | return None; @@ -83,10 +92,11 @@ LL | | }; | |_________^ help: replace it with: `self.opt.as_ref()?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:116:17 + --> tests/ui/question_mark.rs:125:17 | LL | let v = if let Some(v) = self.opt { | _________________^ +LL | | LL | | v LL | | } else { LL | | return None; @@ -94,101 +104,111 @@ LL | | }; | |_________^ help: replace it with: `self.opt?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:137:5 + --> tests/ui/question_mark.rs:147:5 | LL | / if f().is_none() { +LL | | LL | | return None; LL | | } | |_____^ help: replace it with: `f()?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:141:16 + --> tests/ui/question_mark.rs:152:16 | LL | let _val = match f() { | ________________^ +LL | | LL | | Some(val) => val, LL | | None => return None, LL | | }; | |_____^ help: try instead: `f()?` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:151:5 + --> tests/ui/question_mark.rs:163:5 | LL | / match f() { +LL | | LL | | Some(val) => val, LL | | None => return None, LL | | }; | |_____^ help: try instead: `f()?` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:156:5 + --> tests/ui/question_mark.rs:169:5 | LL | / match opt_none!() { +LL | | LL | | Some(x) => x, LL | | None => return None, LL | | }; | |_____^ help: try instead: `opt_none!()?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:182:13 + --> tests/ui/question_mark.rs:196:13 | LL | let _ = if let Ok(x) = x { x } else { return x }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:184:5 + --> tests/ui/question_mark.rs:199:5 | LL | / if x.is_err() { +LL | | LL | | return x; LL | | } | |_____^ help: replace it with: `x?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:188:16 + --> tests/ui/question_mark.rs:204:16 | LL | let _val = match func_returning_result() { | ________________^ +LL | | LL | | Ok(val) => val, LL | | Err(err) => return Err(err), LL | | }; | |_____^ help: try instead: `func_returning_result()?` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:193:5 + --> tests/ui/question_mark.rs:210:5 | LL | / match func_returning_result() { +LL | | LL | | Ok(val) => val, LL | | Err(err) => return Err(err), LL | | }; | |_____^ help: try instead: `func_returning_result()?` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:284:5 + --> tests/ui/question_mark.rs:302:5 | LL | / if let Err(err) = func_returning_result() { +LL | | LL | | return Err(err); LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:291:5 + --> tests/ui/question_mark.rs:310:5 | LL | / if let Err(err) = func_returning_result() { +LL | | LL | | return Err(err); LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:368:13 + --> tests/ui/question_mark.rs:388:13 | LL | / if a.is_none() { +LL | | LL | | return None; ... | LL | | } | |_____________^ help: replace it with: `a?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:428:5 + --> tests/ui/question_mark.rs:449:5 | LL | / let Some(v) = bar.foo.owned.clone() else { LL | | return None; diff --git a/src/tools/clippy/tests/ui/question_mark_used.rs b/src/tools/clippy/tests/ui/question_mark_used.rs index 715d7fab8eed2..9e204d1e9f3c2 100644 --- a/src/tools/clippy/tests/ui/question_mark_used.rs +++ b/src/tools/clippy/tests/ui/question_mark_used.rs @@ -9,7 +9,8 @@ fn other_function() -> Option { fn my_function() -> Option { other_function()?; - //~^ ERROR: question mark operator was used + //~^ question_mark_used + None } diff --git a/src/tools/clippy/tests/ui/range.fixed b/src/tools/clippy/tests/ui/range.fixed new file mode 100644 index 0000000000000..0e951d88091b7 --- /dev/null +++ b/src/tools/clippy/tests/ui/range.fixed @@ -0,0 +1,19 @@ +#![allow(clippy::useless_vec)] +#[warn(clippy::range_zip_with_len)] +fn main() { + let v1 = vec![1, 2, 3]; + let v2 = vec![4, 5]; + let _x = v1.iter().enumerate(); + //~^ range_zip_with_len + + let _y = v1.iter().zip(0..v2.len()); // No error +} + +#[allow(unused)] +fn no_panic_with_fake_range_types() { + struct Range { + foo: i32, + } + + let _ = Range { foo: 0 }; +} diff --git a/src/tools/clippy/tests/ui/range.rs b/src/tools/clippy/tests/ui/range.rs index 9541812b06911..5343801647434 100644 --- a/src/tools/clippy/tests/ui/range.rs +++ b/src/tools/clippy/tests/ui/range.rs @@ -4,8 +4,8 @@ fn main() { let v1 = vec![1, 2, 3]; let v2 = vec![4, 5]; let _x = v1.iter().zip(0..v1.len()); - //~^ ERROR: it is more idiomatic to use `v1.iter().enumerate()` - //~| NOTE: `-D clippy::range-zip-with-len` implied by `-D warnings` + //~^ range_zip_with_len + let _y = v1.iter().zip(0..v2.len()); // No error } diff --git a/src/tools/clippy/tests/ui/range.stderr b/src/tools/clippy/tests/ui/range.stderr index 8c71a209700e1..798ce1842d8b5 100644 --- a/src/tools/clippy/tests/ui/range.stderr +++ b/src/tools/clippy/tests/ui/range.stderr @@ -1,8 +1,8 @@ -error: it is more idiomatic to use `v1.iter().enumerate()` +error: using `.zip()` with a range and `.len()` --> tests/ui/range.rs:6:14 | LL | let _x = v1.iter().zip(0..v1.len()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `v1.iter().enumerate()` | = note: `-D clippy::range-zip-with-len` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::range_zip_with_len)]` diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed index ed248df374d16..19d6165e9820c 100644 --- a/src/tools/clippy/tests/ui/range_contains.fixed +++ b/src/tools/clippy/tests/ui/range_contains.fixed @@ -11,23 +11,35 @@ fn main() { // order shouldn't matter (8..12).contains(&x); + //~^ manual_range_contains (21..42).contains(&x); + //~^ manual_range_contains (1..100).contains(&x); + //~^ manual_range_contains // also with inclusive ranges (9..=99).contains(&x); + //~^ manual_range_contains (1..=33).contains(&x); + //~^ manual_range_contains (1..=999).contains(&x); + //~^ manual_range_contains // and the outside !(8..12).contains(&x); + //~^ manual_range_contains !(21..42).contains(&x); + //~^ manual_range_contains !(1..100).contains(&x); + //~^ manual_range_contains // also with the outside of inclusive ranges !(9..=99).contains(&x); + //~^ manual_range_contains !(1..=33).contains(&x); + //~^ manual_range_contains !(1..=999).contains(&x); + //~^ manual_range_contains // not a range.contains x > 8 && x < 12; // lower bound not inclusive @@ -43,18 +55,26 @@ fn main() { // Fix #6315 let y = 3.; (0. ..1.).contains(&y); + //~^ manual_range_contains !(0. ..=1.).contains(&y); + //~^ manual_range_contains // handle negatives #8721 (-10..=10).contains(&x); + //~^ manual_range_contains x >= 10 && x <= -10; (-3. ..=3.).contains(&y); + //~^ manual_range_contains y >= 3. && y <= -3.; // Fix #8745 let z = 42; (0..=10).contains(&x) && (0..=10).contains(&z); + //~^ manual_range_contains + //~| manual_range_contains !(0..10).contains(&x) || !(0..10).contains(&z); + //~^ manual_range_contains + //~| manual_range_contains // Make sure operators in parens don't give a breaking suggestion ((x % 2 == 0) || (x < 0)) || (x >= 10); } @@ -74,4 +94,5 @@ fn msrv_1_34() { fn msrv_1_35() { let x = 5; (8..35).contains(&x); + //~^ manual_range_contains } diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs index c3188ec6d92be..80bf40806697e 100644 --- a/src/tools/clippy/tests/ui/range_contains.rs +++ b/src/tools/clippy/tests/ui/range_contains.rs @@ -11,23 +11,35 @@ fn main() { // order shouldn't matter x >= 8 && x < 12; + //~^ manual_range_contains x < 42 && x >= 21; + //~^ manual_range_contains 100 > x && 1 <= x; + //~^ manual_range_contains // also with inclusive ranges x >= 9 && x <= 99; + //~^ manual_range_contains x <= 33 && x >= 1; + //~^ manual_range_contains 999 >= x && 1 <= x; + //~^ manual_range_contains // and the outside x < 8 || x >= 12; + //~^ manual_range_contains x >= 42 || x < 21; + //~^ manual_range_contains 100 <= x || 1 > x; + //~^ manual_range_contains // also with the outside of inclusive ranges x < 9 || x > 99; + //~^ manual_range_contains x > 33 || x < 1; + //~^ manual_range_contains 999 < x || 1 > x; + //~^ manual_range_contains // not a range.contains x > 8 && x < 12; // lower bound not inclusive @@ -43,18 +55,26 @@ fn main() { // Fix #6315 let y = 3.; y >= 0. && y < 1.; + //~^ manual_range_contains y < 0. || y > 1.; + //~^ manual_range_contains // handle negatives #8721 x >= -10 && x <= 10; + //~^ manual_range_contains x >= 10 && x <= -10; y >= -3. && y <= 3.; + //~^ manual_range_contains y >= 3. && y <= -3.; // Fix #8745 let z = 42; (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10); + //~^ manual_range_contains + //~| manual_range_contains (x < 0) || (x >= 10) || (z < 0) || (z >= 10); + //~^ manual_range_contains + //~| manual_range_contains // Make sure operators in parens don't give a breaking suggestion ((x % 2 == 0) || (x < 0)) || (x >= 10); } @@ -74,4 +94,5 @@ fn msrv_1_34() { fn msrv_1_35() { let x = 5; x >= 8 && x < 35; + //~^ manual_range_contains } diff --git a/src/tools/clippy/tests/ui/range_contains.stderr b/src/tools/clippy/tests/ui/range_contains.stderr index 58ed1292ac7c9..67bd5aad093dc 100644 --- a/src/tools/clippy/tests/ui/range_contains.stderr +++ b/src/tools/clippy/tests/ui/range_contains.stderr @@ -8,121 +8,121 @@ LL | x >= 8 && x < 12; = help: to override `-D warnings` add `#[allow(clippy::manual_range_contains)]` error: manual `Range::contains` implementation - --> tests/ui/range_contains.rs:14:5 + --> tests/ui/range_contains.rs:15:5 | LL | x < 42 && x >= 21; | ^^^^^^^^^^^^^^^^^ help: use: `(21..42).contains(&x)` error: manual `Range::contains` implementation - --> tests/ui/range_contains.rs:15:5 + --> tests/ui/range_contains.rs:17:5 | LL | 100 > x && 1 <= x; | ^^^^^^^^^^^^^^^^^ help: use: `(1..100).contains(&x)` error: manual `RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:18:5 + --> tests/ui/range_contains.rs:21:5 | LL | x >= 9 && x <= 99; | ^^^^^^^^^^^^^^^^^ help: use: `(9..=99).contains(&x)` error: manual `RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:19:5 + --> tests/ui/range_contains.rs:23:5 | LL | x <= 33 && x >= 1; | ^^^^^^^^^^^^^^^^^ help: use: `(1..=33).contains(&x)` error: manual `RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:20:5 + --> tests/ui/range_contains.rs:25:5 | LL | 999 >= x && 1 <= x; | ^^^^^^^^^^^^^^^^^^ help: use: `(1..=999).contains(&x)` error: manual `!Range::contains` implementation - --> tests/ui/range_contains.rs:23:5 + --> tests/ui/range_contains.rs:29:5 | LL | x < 8 || x >= 12; | ^^^^^^^^^^^^^^^^ help: use: `!(8..12).contains(&x)` error: manual `!Range::contains` implementation - --> tests/ui/range_contains.rs:24:5 + --> tests/ui/range_contains.rs:31:5 | LL | x >= 42 || x < 21; | ^^^^^^^^^^^^^^^^^ help: use: `!(21..42).contains(&x)` error: manual `!Range::contains` implementation - --> tests/ui/range_contains.rs:25:5 + --> tests/ui/range_contains.rs:33:5 | LL | 100 <= x || 1 > x; | ^^^^^^^^^^^^^^^^^ help: use: `!(1..100).contains(&x)` error: manual `!RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:28:5 + --> tests/ui/range_contains.rs:37:5 | LL | x < 9 || x > 99; | ^^^^^^^^^^^^^^^ help: use: `!(9..=99).contains(&x)` error: manual `!RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:29:5 + --> tests/ui/range_contains.rs:39:5 | LL | x > 33 || x < 1; | ^^^^^^^^^^^^^^^ help: use: `!(1..=33).contains(&x)` error: manual `!RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:30:5 + --> tests/ui/range_contains.rs:41:5 | LL | 999 < x || 1 > x; | ^^^^^^^^^^^^^^^^ help: use: `!(1..=999).contains(&x)` error: manual `Range::contains` implementation - --> tests/ui/range_contains.rs:45:5 + --> tests/ui/range_contains.rs:57:5 | LL | y >= 0. && y < 1.; | ^^^^^^^^^^^^^^^^^ help: use: `(0. ..1.).contains(&y)` error: manual `!RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:46:5 + --> tests/ui/range_contains.rs:59:5 | LL | y < 0. || y > 1.; | ^^^^^^^^^^^^^^^^ help: use: `!(0. ..=1.).contains(&y)` error: manual `RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:49:5 + --> tests/ui/range_contains.rs:63:5 | LL | x >= -10 && x <= 10; | ^^^^^^^^^^^^^^^^^^^ help: use: `(-10..=10).contains(&x)` error: manual `RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:51:5 + --> tests/ui/range_contains.rs:66:5 | LL | y >= -3. && y <= 3.; | ^^^^^^^^^^^^^^^^^^^ help: use: `(-3. ..=3.).contains(&y)` error: manual `RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:56:30 + --> tests/ui/range_contains.rs:72:30 | LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&z)` error: manual `RangeInclusive::contains` implementation - --> tests/ui/range_contains.rs:56:5 + --> tests/ui/range_contains.rs:72:5 | LL | (x >= 0) && (x <= 10) && (z >= 0) && (z <= 10); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `(0..=10).contains(&x)` error: manual `!Range::contains` implementation - --> tests/ui/range_contains.rs:57:29 + --> tests/ui/range_contains.rs:75:29 | LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10); | ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&z)` error: manual `!Range::contains` implementation - --> tests/ui/range_contains.rs:57:5 + --> tests/ui/range_contains.rs:75:5 | LL | (x < 0) || (x >= 10) || (z < 0) || (z >= 10); | ^^^^^^^^^^^^^^^^^^^^ help: use: `!(0..10).contains(&x)` error: manual `Range::contains` implementation - --> tests/ui/range_contains.rs:76:5 + --> tests/ui/range_contains.rs:96:5 | LL | x >= 8 && x < 35; | ^^^^^^^^^^^^^^^^ help: use: `(8..35).contains(&x)` diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed index e701dde869338..ee716ef3a6a02 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed @@ -27,29 +27,38 @@ fn main() { for _ in 0..=2 {} for _ in 0..=3 {} + //~^ range_plus_one for _ in 0..=3 + 1 {} for _ in 0..=5 {} + //~^ range_plus_one for _ in 0..=1 + 5 {} for _ in 1..=1 {} + //~^ range_plus_one for _ in 1..=1 + 1 {} for _ in 0..13 + 13 {} for _ in 0..=13 - 7 {} for _ in 0..=f() {} + //~^ range_plus_one for _ in 0..=(1 + f()) {} let _ = ..11 - 1; let _ = ..11; + //~^ range_minus_one let _ = ..11; + //~^ range_minus_one let _ = (1..=11); + //~^ range_plus_one let _ = ((f() + 1)..=f()); + //~^ range_plus_one const ONE: usize = 1; // integer consts are linted, too for _ in 1..=ONE {} + //~^ range_plus_one let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.rs b/src/tools/clippy/tests/ui/range_plus_minus_one.rs index 7057fa8e3f0d7..f2d5ae2c15065 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.rs +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.rs @@ -27,29 +27,38 @@ fn main() { for _ in 0..=2 {} for _ in 0..3 + 1 {} + //~^ range_plus_one for _ in 0..=3 + 1 {} for _ in 0..1 + 5 {} + //~^ range_plus_one for _ in 0..=1 + 5 {} for _ in 1..1 + 1 {} + //~^ range_plus_one for _ in 1..=1 + 1 {} for _ in 0..13 + 13 {} for _ in 0..=13 - 7 {} for _ in 0..(1 + f()) {} + //~^ range_plus_one for _ in 0..=(1 + f()) {} let _ = ..11 - 1; let _ = ..=11 - 1; + //~^ range_minus_one let _ = ..=(11 - 1); + //~^ range_minus_one let _ = (1..11 + 1); + //~^ range_plus_one let _ = (f() + 1)..(f() + 1); + //~^ range_plus_one const ONE: usize = 1; // integer consts are linted, too for _ in 1..ONE + ONE {} + //~^ range_plus_one let mut vec: Vec<()> = std::vec::Vec::new(); vec.drain(..); diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr index 0b1883bc5ff22..9b23a8b8c0b46 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.stderr +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.stderr @@ -8,25 +8,25 @@ LL | for _ in 0..3 + 1 {} = help: to override `-D warnings` add `#[allow(clippy::range_plus_one)]` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:32:14 + --> tests/ui/range_plus_minus_one.rs:33:14 | LL | for _ in 0..1 + 5 {} | ^^^^^^^^ help: use: `0..=5` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:35:14 + --> tests/ui/range_plus_minus_one.rs:37:14 | LL | for _ in 1..1 + 1 {} | ^^^^^^^^ help: use: `1..=1` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:41:14 + --> tests/ui/range_plus_minus_one.rs:44:14 | LL | for _ in 0..(1 + f()) {} | ^^^^^^^^^^^^ help: use: `0..=f()` error: an exclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:45:13 + --> tests/ui/range_plus_minus_one.rs:49:13 | LL | let _ = ..=11 - 1; | ^^^^^^^^^ help: use: `..11` @@ -35,25 +35,25 @@ LL | let _ = ..=11 - 1; = help: to override `-D warnings` add `#[allow(clippy::range_minus_one)]` error: an exclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:46:13 + --> tests/ui/range_plus_minus_one.rs:51:13 | LL | let _ = ..=(11 - 1); | ^^^^^^^^^^^ help: use: `..11` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:47:13 + --> tests/ui/range_plus_minus_one.rs:53:13 | LL | let _ = (1..11 + 1); | ^^^^^^^^^^^ help: use: `(1..=11)` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:48:13 + --> tests/ui/range_plus_minus_one.rs:55:13 | LL | let _ = (f() + 1)..(f() + 1); | ^^^^^^^^^^^^^^^^^^^^ help: use: `((f() + 1)..=f())` error: an inclusive range would be more readable - --> tests/ui/range_plus_minus_one.rs:52:14 + --> tests/ui/range_plus_minus_one.rs:60:14 | LL | for _ in 1..ONE + ONE {} | ^^^^^^^^^^^^ help: use: `1..=ONE` diff --git a/src/tools/clippy/tests/ui/rc_buffer.fixed b/src/tools/clippy/tests/ui/rc_buffer.fixed index 35ac95a76a914..c71a4072b9623 100644 --- a/src/tools/clippy/tests/ui/rc_buffer.fixed +++ b/src/tools/clippy/tests/ui/rc_buffer.fixed @@ -9,18 +9,26 @@ use std::rc::Rc; struct S { // triggers lint bad1: Rc, + //~^ rc_buffer bad2: Rc, + //~^ rc_buffer bad3: Rc<[u8]>, + //~^ rc_buffer bad4: Rc, + //~^ rc_buffer // does not trigger lint good1: Rc>, } // triggers lint fn func_bad1(_: Rc) {} +//~^ rc_buffer fn func_bad2(_: Rc) {} +//~^ rc_buffer fn func_bad3(_: Rc<[u8]>) {} +//~^ rc_buffer fn func_bad4(_: Rc) {} +//~^ rc_buffer // does not trigger lint fn func_good1(_: Rc>) {} diff --git a/src/tools/clippy/tests/ui/rc_buffer.rs b/src/tools/clippy/tests/ui/rc_buffer.rs index e78fb5a6d9d83..686c2644da170 100644 --- a/src/tools/clippy/tests/ui/rc_buffer.rs +++ b/src/tools/clippy/tests/ui/rc_buffer.rs @@ -9,18 +9,26 @@ use std::rc::Rc; struct S { // triggers lint bad1: Rc, + //~^ rc_buffer bad2: Rc, + //~^ rc_buffer bad3: Rc>, + //~^ rc_buffer bad4: Rc, + //~^ rc_buffer // does not trigger lint good1: Rc>, } // triggers lint fn func_bad1(_: Rc) {} +//~^ rc_buffer fn func_bad2(_: Rc) {} +//~^ rc_buffer fn func_bad3(_: Rc>) {} +//~^ rc_buffer fn func_bad4(_: Rc) {} +//~^ rc_buffer // does not trigger lint fn func_good1(_: Rc>) {} diff --git a/src/tools/clippy/tests/ui/rc_buffer.stderr b/src/tools/clippy/tests/ui/rc_buffer.stderr index 922f09288bf38..7500523ab4acc 100644 --- a/src/tools/clippy/tests/ui/rc_buffer.stderr +++ b/src/tools/clippy/tests/ui/rc_buffer.stderr @@ -8,43 +8,43 @@ LL | bad1: Rc, = help: to override `-D warnings` add `#[allow(clippy::rc_buffer)]` error: usage of `Rc` when T is a buffer type - --> tests/ui/rc_buffer.rs:12:11 + --> tests/ui/rc_buffer.rs:13:11 | LL | bad2: Rc, | ^^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> tests/ui/rc_buffer.rs:13:11 + --> tests/ui/rc_buffer.rs:15:11 | LL | bad3: Rc>, | ^^^^^^^^^^^ help: try: `Rc<[u8]>` error: usage of `Rc` when T is a buffer type - --> tests/ui/rc_buffer.rs:14:11 + --> tests/ui/rc_buffer.rs:17:11 | LL | bad4: Rc, | ^^^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> tests/ui/rc_buffer.rs:20:17 + --> tests/ui/rc_buffer.rs:24:17 | LL | fn func_bad1(_: Rc) {} | ^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> tests/ui/rc_buffer.rs:21:17 + --> tests/ui/rc_buffer.rs:26:17 | LL | fn func_bad2(_: Rc) {} | ^^^^^^^^^^^ help: try: `Rc` error: usage of `Rc` when T is a buffer type - --> tests/ui/rc_buffer.rs:22:17 + --> tests/ui/rc_buffer.rs:28:17 | LL | fn func_bad3(_: Rc>) {} | ^^^^^^^^^^^ help: try: `Rc<[u8]>` error: usage of `Rc` when T is a buffer type - --> tests/ui/rc_buffer.rs:23:17 + --> tests/ui/rc_buffer.rs:30:17 | LL | fn func_bad4(_: Rc) {} | ^^^^^^^^^^^^ help: try: `Rc` diff --git a/src/tools/clippy/tests/ui/rc_buffer_arc.fixed b/src/tools/clippy/tests/ui/rc_buffer_arc.fixed index 0d01c7c476f75..27059e3f2e1fd 100644 --- a/src/tools/clippy/tests/ui/rc_buffer_arc.fixed +++ b/src/tools/clippy/tests/ui/rc_buffer_arc.fixed @@ -8,18 +8,26 @@ use std::sync::{Arc, Mutex}; struct S { // triggers lint bad1: Arc, + //~^ rc_buffer bad2: Arc, + //~^ rc_buffer bad3: Arc<[u8]>, + //~^ rc_buffer bad4: Arc, + //~^ rc_buffer // does not trigger lint good1: Arc>, } // triggers lint fn func_bad1(_: Arc) {} +//~^ rc_buffer fn func_bad2(_: Arc) {} +//~^ rc_buffer fn func_bad3(_: Arc<[u8]>) {} +//~^ rc_buffer fn func_bad4(_: Arc) {} +//~^ rc_buffer // does not trigger lint fn func_good1(_: Arc>) {} diff --git a/src/tools/clippy/tests/ui/rc_buffer_arc.rs b/src/tools/clippy/tests/ui/rc_buffer_arc.rs index 61ab16dc18292..5261eae2f26ac 100644 --- a/src/tools/clippy/tests/ui/rc_buffer_arc.rs +++ b/src/tools/clippy/tests/ui/rc_buffer_arc.rs @@ -8,18 +8,26 @@ use std::sync::{Arc, Mutex}; struct S { // triggers lint bad1: Arc, + //~^ rc_buffer bad2: Arc, + //~^ rc_buffer bad3: Arc>, + //~^ rc_buffer bad4: Arc, + //~^ rc_buffer // does not trigger lint good1: Arc>, } // triggers lint fn func_bad1(_: Arc) {} +//~^ rc_buffer fn func_bad2(_: Arc) {} +//~^ rc_buffer fn func_bad3(_: Arc>) {} +//~^ rc_buffer fn func_bad4(_: Arc) {} +//~^ rc_buffer // does not trigger lint fn func_good1(_: Arc>) {} diff --git a/src/tools/clippy/tests/ui/rc_buffer_arc.stderr b/src/tools/clippy/tests/ui/rc_buffer_arc.stderr index 5ef5da2f67f84..786715463232b 100644 --- a/src/tools/clippy/tests/ui/rc_buffer_arc.stderr +++ b/src/tools/clippy/tests/ui/rc_buffer_arc.stderr @@ -8,43 +8,43 @@ LL | bad1: Arc, = help: to override `-D warnings` add `#[allow(clippy::rc_buffer)]` error: usage of `Arc` when T is a buffer type - --> tests/ui/rc_buffer_arc.rs:11:11 + --> tests/ui/rc_buffer_arc.rs:12:11 | LL | bad2: Arc, | ^^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> tests/ui/rc_buffer_arc.rs:12:11 + --> tests/ui/rc_buffer_arc.rs:14:11 | LL | bad3: Arc>, | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` error: usage of `Arc` when T is a buffer type - --> tests/ui/rc_buffer_arc.rs:13:11 + --> tests/ui/rc_buffer_arc.rs:16:11 | LL | bad4: Arc, | ^^^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> tests/ui/rc_buffer_arc.rs:19:17 + --> tests/ui/rc_buffer_arc.rs:23:17 | LL | fn func_bad1(_: Arc) {} | ^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> tests/ui/rc_buffer_arc.rs:20:17 + --> tests/ui/rc_buffer_arc.rs:25:17 | LL | fn func_bad2(_: Arc) {} | ^^^^^^^^^^^^ help: try: `Arc` error: usage of `Arc` when T is a buffer type - --> tests/ui/rc_buffer_arc.rs:21:17 + --> tests/ui/rc_buffer_arc.rs:27:17 | LL | fn func_bad3(_: Arc>) {} | ^^^^^^^^^^^^ help: try: `Arc<[u8]>` error: usage of `Arc` when T is a buffer type - --> tests/ui/rc_buffer_arc.rs:22:17 + --> tests/ui/rc_buffer_arc.rs:29:17 | LL | fn func_bad4(_: Arc) {} | ^^^^^^^^^^^^^ help: try: `Arc` diff --git a/src/tools/clippy/tests/ui/rc_buffer_redefined_string.rs b/src/tools/clippy/tests/ui/rc_buffer_redefined_string.rs index 5d31a848cf72c..49a8ba3e2efbb 100644 --- a/src/tools/clippy/tests/ui/rc_buffer_redefined_string.rs +++ b/src/tools/clippy/tests/ui/rc_buffer_redefined_string.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::rc_buffer)] use std::rc::Rc; diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.rs b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.rs index 1c9e9aa7ef47d..ad5d131f34bc6 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.rs +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.rs @@ -7,8 +7,7 @@ fn main() {} fn should_warn_simple_case() { let v = vec![Arc::new("x".to_string()); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Arc` instance + //~^ rc_clone_in_vec_init } fn should_warn_simple_case_with_big_indentation() { @@ -17,16 +16,16 @@ fn should_warn_simple_case_with_big_indentation() { dbg!(k); if true { let v = vec![Arc::new("x".to_string()); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Arc` instance + //~^ rc_clone_in_vec_init } } } fn should_warn_complex_case() { let v = vec![ - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Arc` instance + //~^ rc_clone_in_vec_init + + std::sync::Arc::new(Mutex::new({ let x = 1; dbg!(x); @@ -36,8 +35,9 @@ fn should_warn_complex_case() { ]; let v1 = vec![ - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Arc` instance + //~^ rc_clone_in_vec_init + + Arc::new(Mutex::new({ let x = 1; dbg!(x); diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr index 1078a97542f2c..598d3c0ae5774 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/arc.stderr @@ -24,7 +24,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/arc.rs:19:21 + --> tests/ui/rc_clone_in_vec_init/arc.rs:18:21 | LL | let v = vec![Arc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,13 +47,10 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/arc.rs:27:13 + --> tests/ui/rc_clone_in_vec_init/arc.rs:25:13 | LL | let v = vec![ | _____________^ -LL | | -LL | | -LL | | std::sync::Arc::new(Mutex::new({ ... | LL | | 2 LL | | ]; @@ -77,13 +74,10 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/arc.rs:38:14 + --> tests/ui/rc_clone_in_vec_init/arc.rs:37:14 | LL | let v1 = vec![ | ______________^ -LL | | -LL | | -LL | | Arc::new(Mutex::new({ ... | LL | | 2 LL | | ]; diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.rs b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.rs index 01cc433cbdae1..d5af17c29e1d8 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.rs +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.rs @@ -8,8 +8,7 @@ fn main() {} fn should_warn_simple_case() { let v = vec![Rc::new("x".to_string()); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Rc` instance + //~^ rc_clone_in_vec_init } fn should_warn_simple_case_with_big_indentation() { @@ -18,16 +17,16 @@ fn should_warn_simple_case_with_big_indentation() { dbg!(k); if true { let v = vec![Rc::new("x".to_string()); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Rc` instance + //~^ rc_clone_in_vec_init } } } fn should_warn_complex_case() { let v = vec![ - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Rc` instance + //~^ rc_clone_in_vec_init + + std::rc::Rc::new(Mutex::new({ let x = 1; dbg!(x); @@ -37,8 +36,9 @@ fn should_warn_complex_case() { ]; let v1 = vec![ - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Rc` instance + //~^ rc_clone_in_vec_init + + Rc::new(Mutex::new({ let x = 1; dbg!(x); diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr index 702266d62d2c3..60d7f33ada9c5 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/rc.stderr @@ -24,7 +24,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/rc.rs:20:21 + --> tests/ui/rc_clone_in_vec_init/rc.rs:19:21 | LL | let v = vec![Rc::new("x".to_string()); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -47,13 +47,10 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/rc.rs:28:13 + --> tests/ui/rc_clone_in_vec_init/rc.rs:26:13 | LL | let v = vec![ | _____________^ -LL | | -LL | | -LL | | std::rc::Rc::new(Mutex::new({ ... | LL | | 2 LL | | ]; @@ -77,13 +74,10 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/rc.rs:39:14 + --> tests/ui/rc_clone_in_vec_init/rc.rs:38:14 | LL | let v1 = vec![ | ______________^ -LL | | -LL | | -LL | | Rc::new(Mutex::new({ ... | LL | | 2 LL | | ]; diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.rs b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.rs index fd2895d40458a..add09b6ba859e 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.rs +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.rs @@ -8,18 +8,16 @@ fn main() {} fn should_warn_simple_case() { let v = vec![SyncWeak::::new(); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init + let v2 = vec![UnSyncWeak::::new(); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init let v = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init + let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init } fn should_warn_simple_case_with_big_indentation() { @@ -28,19 +26,19 @@ fn should_warn_simple_case_with_big_indentation() { dbg!(k); if true { let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init + let v2 = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init } } } fn should_warn_complex_case() { let v = vec![ - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init + + Arc::downgrade(&Arc::new(Mutex::new({ let x = 1; dbg!(x); @@ -50,8 +48,9 @@ fn should_warn_complex_case() { ]; let v1 = vec![ - //~^ ERROR: initializing a reference-counted pointer in `vec![elem; len]` - //~| NOTE: each element will point to the same `Weak` instance + //~^ rc_clone_in_vec_init + + Rc::downgrade(&Rc::new(Mutex::new({ let x = 1; dbg!(x); diff --git a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr index 68ca2a7eb848c..8bd018ab586cb 100644 --- a/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr +++ b/src/tools/clippy/tests/ui/rc_clone_in_vec_init/weak.stderr @@ -47,7 +47,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/weak.rs:17:13 + --> tests/ui/rc_clone_in_vec_init/weak.rs:16:13 | LL | let v = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/weak.rs:20:13 + --> tests/ui/rc_clone_in_vec_init/weak.rs:19:13 | LL | let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/weak.rs:30:21 + --> tests/ui/rc_clone_in_vec_init/weak.rs:28:21 | LL | let v = vec![Arc::downgrade(&Arc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -116,7 +116,7 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/weak.rs:33:22 + --> tests/ui/rc_clone_in_vec_init/weak.rs:31:22 | LL | let v2 = vec![Rc::downgrade(&Rc::new("x".to_string())); 2]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,13 +139,10 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/weak.rs:41:13 + --> tests/ui/rc_clone_in_vec_init/weak.rs:38:13 | LL | let v = vec![ | _____________^ -LL | | -LL | | -LL | | Arc::downgrade(&Arc::new(Mutex::new({ ... | LL | | 2 LL | | ]; @@ -169,13 +166,10 @@ LL ~ }; | error: initializing a reference-counted pointer in `vec![elem; len]` - --> tests/ui/rc_clone_in_vec_init/weak.rs:52:14 + --> tests/ui/rc_clone_in_vec_init/weak.rs:50:14 | LL | let v1 = vec![ | ______________^ -LL | | -LL | | -LL | | Rc::downgrade(&Rc::new(Mutex::new({ ... | LL | | 2 LL | | ]; diff --git a/src/tools/clippy/tests/ui/rc_mutex.rs b/src/tools/clippy/tests/ui/rc_mutex.rs index 40adb3ddce955..c8700e13b11e5 100644 --- a/src/tools/clippy/tests/ui/rc_mutex.rs +++ b/src/tools/clippy/tests/ui/rc_mutex.rs @@ -6,7 +6,7 @@ use std::sync::Mutex; pub struct MyStructWithPrivItem { foo: Rc>, - //~^ ERROR: usage of `Rc>` + //~^ rc_mutex } pub struct MyStructWithPubItem { @@ -25,11 +25,13 @@ pub enum MyEnum { // All of these test should be trigger the lint because they are not // part of the public api fn test1(foo: Rc>) {} -//~^ ERROR: usage of `Rc>` +//~^ rc_mutex + fn test2(foo: Rc>) {} -//~^ ERROR: usage of `Rc>` +//~^ rc_mutex + fn test3(foo: Rc>>) {} -//~^ ERROR: usage of `Rc>` +//~^ rc_mutex // All of these test should be allowed because they are part of the // public api and `avoid_breaking_exported_api` is `false` by default. diff --git a/src/tools/clippy/tests/ui/rc_mutex.stderr b/src/tools/clippy/tests/ui/rc_mutex.stderr index 9aa18336df00c..5b589cfa309a4 100644 --- a/src/tools/clippy/tests/ui/rc_mutex.stderr +++ b/src/tools/clippy/tests/ui/rc_mutex.stderr @@ -17,7 +17,7 @@ LL | fn test1(foo: Rc>) {} = help: consider using `Rc>` or `Arc>` instead error: usage of `Rc>` - --> tests/ui/rc_mutex.rs:29:15 + --> tests/ui/rc_mutex.rs:30:15 | LL | fn test2(foo: Rc>) {} | ^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | fn test2(foo: Rc>) {} = help: consider using `Rc>` or `Arc>` instead error: usage of `Rc>` - --> tests/ui/rc_mutex.rs:31:15 + --> tests/ui/rc_mutex.rs:33:15 | LL | fn test3(foo: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/read_line_without_trim.fixed b/src/tools/clippy/tests/ui/read_line_without_trim.fixed index 523ad55527479..e7f208e78d203 100644 --- a/src/tools/clippy/tests/ui/read_line_without_trim.fixed +++ b/src/tools/clippy/tests/ui/read_line_without_trim.fixed @@ -10,22 +10,27 @@ fn main() { let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x: i32 = input.trim_end().parse().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.trim_end().parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.trim_end().parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.trim_end().parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.trim_end().parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); @@ -36,12 +41,14 @@ fn main() { let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); if input.trim_end() == "foo" { + //~^ read_line_without_trim println!("This will never ever execute!"); } let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); if input.trim_end().ends_with("foo") { + //~^ read_line_without_trim println!("Neither will this"); } } diff --git a/src/tools/clippy/tests/ui/read_line_without_trim.rs b/src/tools/clippy/tests/ui/read_line_without_trim.rs index e31ff0cde61de..6664278b5a876 100644 --- a/src/tools/clippy/tests/ui/read_line_without_trim.rs +++ b/src/tools/clippy/tests/ui/read_line_without_trim.rs @@ -10,22 +10,27 @@ fn main() { let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x: i32 = input.parse().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); let _x = input.parse::().unwrap(); + //~^ read_line_without_trim let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); @@ -36,12 +41,14 @@ fn main() { let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); if input == "foo" { + //~^ read_line_without_trim println!("This will never ever execute!"); } let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); if input.ends_with("foo") { + //~^ read_line_without_trim println!("Neither will this"); } } diff --git a/src/tools/clippy/tests/ui/read_line_without_trim.stderr b/src/tools/clippy/tests/ui/read_line_without_trim.stderr index b54229f762a32..5e5618111432a 100644 --- a/src/tools/clippy/tests/ui/read_line_without_trim.stderr +++ b/src/tools/clippy/tests/ui/read_line_without_trim.stderr @@ -15,7 +15,7 @@ LL | std::io::stdin().read_line(&mut input).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::read_line_without_trim)]` error: calling `.parse()` on a string without trimming the trailing newline character - --> tests/ui/read_line_without_trim.rs:16:20 + --> tests/ui/read_line_without_trim.rs:17:20 | LL | let _x = input.parse::().unwrap(); | ----- ^^^^^^^^^^^^^^ @@ -23,13 +23,13 @@ LL | let _x = input.parse::().unwrap(); | help: try: `input.trim_end()` | note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause the checking to always fail - --> tests/ui/read_line_without_trim.rs:15:5 + --> tests/ui/read_line_without_trim.rs:16:5 | LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `.parse()` on a string without trimming the trailing newline character - --> tests/ui/read_line_without_trim.rs:20:20 + --> tests/ui/read_line_without_trim.rs:22:20 | LL | let _x = input.parse::().unwrap(); | ----- ^^^^^^^^^^^^^^ @@ -37,13 +37,13 @@ LL | let _x = input.parse::().unwrap(); | help: try: `input.trim_end()` | note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause the checking to always fail - --> tests/ui/read_line_without_trim.rs:19:5 + --> tests/ui/read_line_without_trim.rs:21:5 | LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `.parse()` on a string without trimming the trailing newline character - --> tests/ui/read_line_without_trim.rs:24:20 + --> tests/ui/read_line_without_trim.rs:27:20 | LL | let _x = input.parse::().unwrap(); | ----- ^^^^^^^^^^^^^^ @@ -51,13 +51,13 @@ LL | let _x = input.parse::().unwrap(); | help: try: `input.trim_end()` | note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause the checking to always fail - --> tests/ui/read_line_without_trim.rs:23:5 + --> tests/ui/read_line_without_trim.rs:26:5 | LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `.parse()` on a string without trimming the trailing newline character - --> tests/ui/read_line_without_trim.rs:28:20 + --> tests/ui/read_line_without_trim.rs:32:20 | LL | let _x = input.parse::().unwrap(); | ----- ^^^^^^^^^^^^^^^ @@ -65,13 +65,13 @@ LL | let _x = input.parse::().unwrap(); | help: try: `input.trim_end()` | note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause the checking to always fail - --> tests/ui/read_line_without_trim.rs:27:5 + --> tests/ui/read_line_without_trim.rs:31:5 | LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: comparing a string literal without trimming the trailing newline character - --> tests/ui/read_line_without_trim.rs:38:8 + --> tests/ui/read_line_without_trim.rs:43:8 | LL | if input == "foo" { | -----^^^^^^^^^ @@ -79,13 +79,13 @@ LL | if input == "foo" { | help: try: `input.trim_end()` | note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause the comparison to always fail - --> tests/ui/read_line_without_trim.rs:37:5 + --> tests/ui/read_line_without_trim.rs:42:5 | LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: checking the end of a string without trimming the trailing newline character - --> tests/ui/read_line_without_trim.rs:44:8 + --> tests/ui/read_line_without_trim.rs:50:8 | LL | if input.ends_with("foo") { | -----^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL | if input.ends_with("foo") { | help: try: `input.trim_end()` | note: call to `.read_line()` here, which leaves a trailing newline character in the buffer, which in turn will cause the parsing to always fail - --> tests/ui/read_line_without_trim.rs:43:5 + --> tests/ui/read_line_without_trim.rs:49:5 | LL | std::io::stdin().read_line(&mut input).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs index 68acf4334699b..938d61b68607c 100644 --- a/src/tools/clippy/tests/ui/read_zero_byte_vec.rs +++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.rs @@ -8,6 +8,7 @@ use std::fs::File; use std::io; use std::io::prelude::*; //@no-rustfix +//@require-annotations-for-level: WARN extern crate futures; use futures::io::{AsyncRead, AsyncReadExt}; use tokio::io::{AsyncRead as TokioAsyncRead, AsyncReadExt as _, AsyncWrite as TokioAsyncWrite, AsyncWriteExt as _}; diff --git a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr index e2356f1cb56be..8f255bc87ab82 100644 --- a/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr +++ b/src/tools/clippy/tests/ui/read_zero_byte_vec.stderr @@ -1,5 +1,5 @@ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:21:5 + --> tests/ui/read_zero_byte_vec.rs:22:5 | LL | f.read_exact(&mut data).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data.resize(20, 0); f.read_exact(&mut data)` @@ -8,61 +8,61 @@ LL | f.read_exact(&mut data).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::read_zero_byte_vec)]` error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:27:5 + --> tests/ui/read_zero_byte_vec.rs:28:5 | LL | f.read_exact(&mut data2)?; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `data2.resize(cap, 0); f.read_exact(&mut data2)` error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:32:5 + --> tests/ui/read_zero_byte_vec.rs:33:5 | LL | f.read_exact(&mut data3)?; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:37:13 + --> tests/ui/read_zero_byte_vec.rs:38:13 | LL | let _ = f.read(&mut data4)?; | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:43:9 + --> tests/ui/read_zero_byte_vec.rs:44:9 | LL | f.read(&mut data5) | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:50:9 + --> tests/ui/read_zero_byte_vec.rs:51:9 | LL | f.read(&mut data6) | ^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:84:9 + --> tests/ui/read_zero_byte_vec.rs:85:9 | LL | f.read(&mut v)?; | ^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:94:5 + --> tests/ui/read_zero_byte_vec.rs:95:5 | LL | r.read(&mut data).await.unwrap(); | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:99:5 + --> tests/ui/read_zero_byte_vec.rs:100:5 | LL | r.read_exact(&mut data2).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:106:5 + --> tests/ui/read_zero_byte_vec.rs:107:5 | LL | r.read(&mut data).await.unwrap(); | ^^^^^^^^^^^^^^^^^ error: reading zero byte data to `Vec` - --> tests/ui/read_zero_byte_vec.rs:111:5 + --> tests/ui/read_zero_byte_vec.rs:112:5 | LL | r.read_exact(&mut data2).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.fixed b/src/tools/clippy/tests/ui/readonly_write_lock.fixed index 4db13482ac786..0cb91247232b0 100644 --- a/src/tools/clippy/tests/ui/readonly_write_lock.fixed +++ b/src/tools/clippy/tests/ui/readonly_write_lock.fixed @@ -14,14 +14,15 @@ fn main() { { let writer = lock.read().unwrap(); - //~^ ERROR: this write lock is used only for reading - //~| NOTE: `-D clippy::readonly-write-lock` implied by `-D warnings` + //~^ readonly_write_lock + dbg!(&writer); } { let writer = lock.read().unwrap(); - //~^ ERROR: this write lock is used only for reading + //~^ readonly_write_lock + accept_i32(*writer); } diff --git a/src/tools/clippy/tests/ui/readonly_write_lock.rs b/src/tools/clippy/tests/ui/readonly_write_lock.rs index 66ba1b2d6969e..843755fe792c9 100644 --- a/src/tools/clippy/tests/ui/readonly_write_lock.rs +++ b/src/tools/clippy/tests/ui/readonly_write_lock.rs @@ -14,14 +14,15 @@ fn main() { { let writer = lock.write().unwrap(); - //~^ ERROR: this write lock is used only for reading - //~| NOTE: `-D clippy::readonly-write-lock` implied by `-D warnings` + //~^ readonly_write_lock + dbg!(&writer); } { let writer = lock.write().unwrap(); - //~^ ERROR: this write lock is used only for reading + //~^ readonly_write_lock + accept_i32(*writer); } diff --git a/src/tools/clippy/tests/ui/recursive_format_impl.rs b/src/tools/clippy/tests/ui/recursive_format_impl.rs index b3eafc6dad7a9..9f46fef62354a 100644 --- a/src/tools/clippy/tests/ui/recursive_format_impl.rs +++ b/src/tools/clippy/tests/ui/recursive_format_impl.rs @@ -29,8 +29,7 @@ impl B for A { impl fmt::Display for A { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.to_string()) - //~^ ERROR: using `self.to_string` in `fmt::Display` implementation will cause inf - //~| NOTE: `-D clippy::recursive-format-impl` implied by `-D warnings` + //~^ recursive_format_impl } } @@ -75,7 +74,7 @@ struct G; impl std::fmt::Display for G { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self) - //~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs + //~^ recursive_format_impl } } @@ -85,14 +84,14 @@ struct H; impl std::fmt::Display for H { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", &self) - //~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs + //~^ recursive_format_impl } } impl std::fmt::Debug for H { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", &self) - //~^ ERROR: using `self` as `Debug` in `impl Debug` will cause infinite recursion + //~^ recursive_format_impl } } @@ -102,7 +101,7 @@ struct H2; impl std::fmt::Display for H2 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", &&&self) - //~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs + //~^ recursive_format_impl } } @@ -177,14 +176,14 @@ impl std::ops::Deref for J { impl std::fmt::Display for J { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", &*self) - //~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs + //~^ recursive_format_impl } } impl std::fmt::Debug for J { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{:?}", &*self) - //~^ ERROR: using `self` as `Debug` in `impl Debug` will cause infinite recursion + //~^ recursive_format_impl } } @@ -201,7 +200,7 @@ impl std::ops::Deref for J2 { impl std::fmt::Display for J2 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", *self) - //~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs + //~^ recursive_format_impl } } @@ -218,7 +217,7 @@ impl std::ops::Deref for J3 { impl std::fmt::Display for J3 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", **&&*self) - //~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs + //~^ recursive_format_impl } } @@ -235,7 +234,7 @@ impl std::ops::Deref for J4 { impl std::fmt::Display for J4 { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", &&**&&*self) - //~^ ERROR: using `self` as `Display` in `impl Display` will cause infinite recurs + //~^ recursive_format_impl } } diff --git a/src/tools/clippy/tests/ui/recursive_format_impl.stderr b/src/tools/clippy/tests/ui/recursive_format_impl.stderr index f80aff01eb53e..31960c7193b44 100644 --- a/src/tools/clippy/tests/ui/recursive_format_impl.stderr +++ b/src/tools/clippy/tests/ui/recursive_format_impl.stderr @@ -8,7 +8,7 @@ LL | write!(f, "{}", self.to_string()) = help: to override `-D warnings` add `#[allow(clippy::recursive_format_impl)]` error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:77:9 + --> tests/ui/recursive_format_impl.rs:76:9 | LL | write!(f, "{}", self) | ^^^^^^^^^^^^^^^^^^^^^ @@ -16,7 +16,7 @@ LL | write!(f, "{}", self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:87:9 + --> tests/ui/recursive_format_impl.rs:86:9 | LL | write!(f, "{}", &self) | ^^^^^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ LL | write!(f, "{}", &self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Debug` in `impl Debug` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:94:9 + --> tests/ui/recursive_format_impl.rs:93:9 | LL | write!(f, "{:?}", &self) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL | write!(f, "{:?}", &self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:104:9 + --> tests/ui/recursive_format_impl.rs:103:9 | LL | write!(f, "{}", &&&self) | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -40,7 +40,7 @@ LL | write!(f, "{}", &&&self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:179:9 + --> tests/ui/recursive_format_impl.rs:178:9 | LL | write!(f, "{}", &*self) | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -48,7 +48,7 @@ LL | write!(f, "{}", &*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Debug` in `impl Debug` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:186:9 + --> tests/ui/recursive_format_impl.rs:185:9 | LL | write!(f, "{:?}", &*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -56,7 +56,7 @@ LL | write!(f, "{:?}", &*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:203:9 + --> tests/ui/recursive_format_impl.rs:202:9 | LL | write!(f, "{}", *self) | ^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | write!(f, "{}", *self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:220:9 + --> tests/ui/recursive_format_impl.rs:219:9 | LL | write!(f, "{}", **&&*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | write!(f, "{}", **&&*self) = note: this error originates in the macro `write` (in Nightly builds, run with -Z macro-backtrace for more info) error: using `self` as `Display` in `impl Display` will cause infinite recursion - --> tests/ui/recursive_format_impl.rs:237:9 + --> tests/ui/recursive_format_impl.rs:236:9 | LL | write!(f, "{}", &&**&&*self) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs index e70f8e71fae85..0562f7dcc7614 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation.rs +++ b/src/tools/clippy/tests/ui/redundant_allocation.rs @@ -14,24 +14,21 @@ mod outer_box { use std::sync::Arc; pub fn box_test6(foo: Box>) {} - //~^ ERROR: usage of `Box>` - //~| NOTE: `Rc` is already on the heap, `Box>` makes an extra allocation + //~^ redundant_allocation pub fn box_test7(foo: Box>) {} - //~^ ERROR: usage of `Box>` - //~| NOTE: `Arc` is already on the heap, `Box>` makes an extra allocation + //~^ redundant_allocation pub fn box_test8() -> Box>> { - //~^ ERROR: usage of `Box>>` - //~| NOTE: `Rc>` is already on the heap, `Box>>` makes an e + //~^ redundant_allocation + unimplemented!(); } pub fn box_test9(foo: Box>) -> Box>> { - //~^ ERROR: usage of `Box>` - //~| NOTE: `Arc` is already on the heap, `Box>` makes an extra allocation - //~| ERROR: usage of `Box>>` - //~| NOTE: `Arc>` is already on the heap, `Box>>` makes an extra a + //~^ redundant_allocation + //~| redundant_allocation + unimplemented!(); } } @@ -43,24 +40,21 @@ mod outer_rc { use std::sync::Arc; pub fn rc_test5(a: Rc>) {} - //~^ ERROR: usage of `Rc>` - //~| NOTE: `Box` is already on the heap, `Rc>` makes an extra allocati + //~^ redundant_allocation pub fn rc_test7(a: Rc>) {} - //~^ ERROR: usage of `Rc>` - //~| NOTE: `Arc` is already on the heap, `Rc>` makes an extra allocati + //~^ redundant_allocation pub fn rc_test8() -> Rc>> { - //~^ ERROR: usage of `Rc>>` - //~| NOTE: `Box>` is already on the heap, `Rc>>` makes an + //~^ redundant_allocation + unimplemented!(); } pub fn rc_test9(foo: Rc>) -> Rc>> { - //~^ ERROR: usage of `Rc>` - //~| NOTE: `Arc` is already on the heap, `Rc>` makes an extra allocation - //~| ERROR: usage of `Rc>>` - //~| NOTE: `Arc>` is already on the heap, `Rc>>` makes an extra al + //~^ redundant_allocation + //~| redundant_allocation + unimplemented!(); } } @@ -72,24 +66,21 @@ mod outer_arc { use std::sync::Arc; pub fn arc_test5(a: Arc>) {} - //~^ ERROR: usage of `Arc>` - //~| NOTE: `Box` is already on the heap, `Arc>` makes an extra allocat + //~^ redundant_allocation pub fn arc_test6(a: Arc>) {} - //~^ ERROR: usage of `Arc>` - //~| NOTE: `Rc` is already on the heap, `Arc>` makes an extra allocatio + //~^ redundant_allocation pub fn arc_test8() -> Arc>> { - //~^ ERROR: usage of `Arc>>` - //~| NOTE: `Box>` is already on the heap, `Arc>>` makes an + //~^ redundant_allocation + unimplemented!(); } pub fn arc_test9(foo: Arc>) -> Arc>> { - //~^ ERROR: usage of `Arc>` - //~| NOTE: `Rc` is already on the heap, `Arc>` makes an extra allocation - //~| ERROR: usage of `Arc>>` - //~| NOTE: `Rc>` is already on the heap, `Arc>>` makes an extra all + //~^ redundant_allocation + //~| redundant_allocation + unimplemented!(); } } @@ -112,8 +103,7 @@ mod box_dyn { pub fn test_rc(_: Rc>) {} pub fn test_arc(_: Arc>) {} pub fn test_rc_box(_: Rc>>) {} - //~^ ERROR: usage of `Rc>>` - //~| NOTE: `Box>` is already on the heap, `Rc>>` makes an ex + //~^ redundant_allocation } // https://github.com/rust-lang/rust-clippy/issues/8604 @@ -146,17 +136,16 @@ mod box_fat_ptr { pub fn test_box_custom(_: Box>) {} pub fn test_rc_box_str(_: Rc>>) {} - //~^ ERROR: usage of `Rc>>` - //~| NOTE: `Box>` is already on the heap, `Rc>>` makes an extra + //~^ redundant_allocation + pub fn test_rc_box_slice(_: Rc>>) {} - //~^ ERROR: usage of `Rc>>` - //~| NOTE: `Box>` is already on the heap, `Rc>>` makes a + //~^ redundant_allocation + pub fn test_rc_box_path(_: Rc>>) {} - //~^ ERROR: usage of `Rc>>` - //~| NOTE: `Box>` is already on the heap, `Rc>>` makes an extr + //~^ redundant_allocation + pub fn test_rc_box_custom(_: Rc>>) {} - //~^ ERROR: usage of `Rc>>` - //~| NOTE: `Box>` is already on the heap, `Rc>>` makes + //~^ redundant_allocation } // https://github.com/rust-lang/rust-clippy/issues/11417 diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr index 8a043013e07a9..44d30f95d7bc3 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation.stderr +++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr @@ -10,7 +10,7 @@ LL | pub fn box_test6(foo: Box>) {} = help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]` error: usage of `Box>` - --> tests/ui/redundant_allocation.rs:20:30 + --> tests/ui/redundant_allocation.rs:19:30 | LL | pub fn box_test7(foo: Box>) {} | ^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | pub fn box_test7(foo: Box>) {} = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> tests/ui/redundant_allocation.rs:24:27 + --> tests/ui/redundant_allocation.rs:22:27 | LL | pub fn box_test8() -> Box>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | pub fn box_test8() -> Box>> { = help: consider using just `Box>` or `Rc>` error: usage of `Box>` - --> tests/ui/redundant_allocation.rs:30:30 + --> tests/ui/redundant_allocation.rs:28:30 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box` or `Arc` error: usage of `Box>>` - --> tests/ui/redundant_allocation.rs:30:46 + --> tests/ui/redundant_allocation.rs:28:46 | LL | pub fn box_test9(foo: Box>) -> Box>> { | ^^^^^^^^^^^^^^^^^ @@ -46,7 +46,7 @@ LL | pub fn box_test9(foo: Box>) -> Box>> { = help: consider using just `Box>` or `Arc>` error: usage of `Rc>` - --> tests/ui/redundant_allocation.rs:45:24 + --> tests/ui/redundant_allocation.rs:42:24 | LL | pub fn rc_test5(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -55,7 +55,7 @@ LL | pub fn rc_test5(a: Rc>) {} = help: consider using just `Rc` or `Box` error: usage of `Rc>` - --> tests/ui/redundant_allocation.rs:49:24 + --> tests/ui/redundant_allocation.rs:45:24 | LL | pub fn rc_test7(a: Rc>) {} | ^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL | pub fn rc_test7(a: Rc>) {} = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:53:26 + --> tests/ui/redundant_allocation.rs:48:26 | LL | pub fn rc_test8() -> Rc>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | pub fn rc_test8() -> Rc>> { = help: consider using just `Rc>` or `Box>` error: usage of `Rc>` - --> tests/ui/redundant_allocation.rs:59:29 + --> tests/ui/redundant_allocation.rs:54:29 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^ @@ -82,7 +82,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc` or `Arc` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:59:44 + --> tests/ui/redundant_allocation.rs:54:44 | LL | pub fn rc_test9(foo: Rc>) -> Rc>> { | ^^^^^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL | pub fn rc_test9(foo: Rc>) -> Rc>> { = help: consider using just `Rc>` or `Arc>` error: usage of `Arc>` - --> tests/ui/redundant_allocation.rs:74:25 + --> tests/ui/redundant_allocation.rs:68:25 | LL | pub fn arc_test5(a: Arc>) {} | ^^^^^^^^^^^^^^ @@ -100,7 +100,7 @@ LL | pub fn arc_test5(a: Arc>) {} = help: consider using just `Arc` or `Box` error: usage of `Arc>` - --> tests/ui/redundant_allocation.rs:78:25 + --> tests/ui/redundant_allocation.rs:71:25 | LL | pub fn arc_test6(a: Arc>) {} | ^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL | pub fn arc_test6(a: Arc>) {} = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> tests/ui/redundant_allocation.rs:82:27 + --> tests/ui/redundant_allocation.rs:74:27 | LL | pub fn arc_test8() -> Arc>> { | ^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL | pub fn arc_test8() -> Arc>> { = help: consider using just `Arc>` or `Box>` error: usage of `Arc>` - --> tests/ui/redundant_allocation.rs:88:30 + --> tests/ui/redundant_allocation.rs:80:30 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^ @@ -127,7 +127,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc` or `Rc` error: usage of `Arc>>` - --> tests/ui/redundant_allocation.rs:88:45 + --> tests/ui/redundant_allocation.rs:80:45 | LL | pub fn arc_test9(foo: Arc>) -> Arc>> { | ^^^^^^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL | pub fn arc_test9(foo: Arc>) -> Arc>> { = help: consider using just `Arc>` or `Rc>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:114:27 + --> tests/ui/redundant_allocation.rs:105:27 | LL | pub fn test_rc_box(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | pub fn test_rc_box(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:148:31 + --> tests/ui/redundant_allocation.rs:138:31 | LL | pub fn test_rc_box_str(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | pub fn test_rc_box_str(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:151:33 + --> tests/ui/redundant_allocation.rs:141:33 | LL | pub fn test_rc_box_slice(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +163,7 @@ LL | pub fn test_rc_box_slice(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:154:32 + --> tests/ui/redundant_allocation.rs:144:32 | LL | pub fn test_rc_box_path(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL | pub fn test_rc_box_path(_: Rc>>) {} = help: consider using just `Rc>` or `Box>` error: usage of `Rc>>` - --> tests/ui/redundant_allocation.rs:157:34 + --> tests/ui/redundant_allocation.rs:147:34 | LL | pub fn test_rc_box_custom(_: Rc>>) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed index 61c989c67a1a4..7773ba11f973e 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed @@ -21,14 +21,18 @@ mod outer_box { use std::sync::Arc; pub fn box_test1(foo: &T) {} + //~^ redundant_allocation pub fn box_test2(foo: &MyStruct) {} + //~^ redundant_allocation pub fn box_test3(foo: &MyEnum) {} + //~^ redundant_allocation pub fn box_test4_neg(foo: Box>) {} pub fn box_test5(foo: Box) {} + //~^ redundant_allocation } mod outer_rc { @@ -38,14 +42,18 @@ mod outer_rc { use std::sync::Arc; pub fn rc_test1(foo: &T) {} + //~^ redundant_allocation pub fn rc_test2(foo: &MyStruct) {} + //~^ redundant_allocation pub fn rc_test3(foo: &MyEnum) {} + //~^ redundant_allocation pub fn rc_test4_neg(foo: Rc>) {} pub fn rc_test6(a: Rc) {} + //~^ redundant_allocation } mod outer_arc { @@ -55,14 +63,18 @@ mod outer_arc { use std::sync::Arc; pub fn arc_test1(foo: &T) {} + //~^ redundant_allocation pub fn arc_test2(foo: &MyStruct) {} + //~^ redundant_allocation pub fn arc_test3(foo: &MyEnum) {} + //~^ redundant_allocation pub fn arc_test4_neg(foo: Arc>) {} pub fn arc_test7(a: Arc) {} + //~^ redundant_allocation } fn main() {} diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs index 3ad1e9a978df7..fb86ed2b3cfdf 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs @@ -21,14 +21,18 @@ mod outer_box { use std::sync::Arc; pub fn box_test1(foo: Box<&T>) {} + //~^ redundant_allocation pub fn box_test2(foo: Box<&MyStruct>) {} + //~^ redundant_allocation pub fn box_test3(foo: Box<&MyEnum>) {} + //~^ redundant_allocation pub fn box_test4_neg(foo: Box>) {} pub fn box_test5(foo: Box>) {} + //~^ redundant_allocation } mod outer_rc { @@ -38,14 +42,18 @@ mod outer_rc { use std::sync::Arc; pub fn rc_test1(foo: Rc<&T>) {} + //~^ redundant_allocation pub fn rc_test2(foo: Rc<&MyStruct>) {} + //~^ redundant_allocation pub fn rc_test3(foo: Rc<&MyEnum>) {} + //~^ redundant_allocation pub fn rc_test4_neg(foo: Rc>) {} pub fn rc_test6(a: Rc>) {} + //~^ redundant_allocation } mod outer_arc { @@ -55,14 +63,18 @@ mod outer_arc { use std::sync::Arc; pub fn arc_test1(foo: Arc<&T>) {} + //~^ redundant_allocation pub fn arc_test2(foo: Arc<&MyStruct>) {} + //~^ redundant_allocation pub fn arc_test3(foo: Arc<&MyEnum>) {} + //~^ redundant_allocation pub fn arc_test4_neg(foo: Arc>) {} pub fn arc_test7(a: Arc>) {} + //~^ redundant_allocation } fn main() {} diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr index 34a1a21bdadcd..ed8282cc82ce9 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr @@ -9,7 +9,7 @@ LL | pub fn box_test1(foo: Box<&T>) {} = help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]` error: usage of `Box<&MyStruct>` - --> tests/ui/redundant_allocation_fixable.rs:25:27 + --> tests/ui/redundant_allocation_fixable.rs:26:27 | LL | pub fn box_test2(foo: Box<&MyStruct>) {} | ^^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -17,7 +17,7 @@ LL | pub fn box_test2(foo: Box<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Box<&MyStruct>` allocates a pointer on the heap error: usage of `Box<&MyEnum>` - --> tests/ui/redundant_allocation_fixable.rs:27:27 + --> tests/ui/redundant_allocation_fixable.rs:29:27 | LL | pub fn box_test3(foo: Box<&MyEnum>) {} | ^^^^^^^^^^^^ help: try: `&MyEnum` @@ -25,7 +25,7 @@ LL | pub fn box_test3(foo: Box<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Box<&MyEnum>` allocates a pointer on the heap error: usage of `Box>` - --> tests/ui/redundant_allocation_fixable.rs:31:30 + --> tests/ui/redundant_allocation_fixable.rs:34:30 | LL | pub fn box_test5(foo: Box>) {} | ^^^^^^^^^^^ help: try: `Box` @@ -33,7 +33,7 @@ LL | pub fn box_test5(foo: Box>) {} = note: `Box` is already on the heap, `Box>` makes an extra allocation error: usage of `Rc<&T>` - --> tests/ui/redundant_allocation_fixable.rs:40:29 + --> tests/ui/redundant_allocation_fixable.rs:44:29 | LL | pub fn rc_test1(foo: Rc<&T>) {} | ^^^^^^ help: try: `&T` @@ -41,7 +41,7 @@ LL | pub fn rc_test1(foo: Rc<&T>) {} = note: `&T` is already a pointer, `Rc<&T>` allocates a pointer on the heap error: usage of `Rc<&MyStruct>` - --> tests/ui/redundant_allocation_fixable.rs:42:26 + --> tests/ui/redundant_allocation_fixable.rs:47:26 | LL | pub fn rc_test2(foo: Rc<&MyStruct>) {} | ^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -49,7 +49,7 @@ LL | pub fn rc_test2(foo: Rc<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Rc<&MyStruct>` allocates a pointer on the heap error: usage of `Rc<&MyEnum>` - --> tests/ui/redundant_allocation_fixable.rs:44:26 + --> tests/ui/redundant_allocation_fixable.rs:50:26 | LL | pub fn rc_test3(foo: Rc<&MyEnum>) {} | ^^^^^^^^^^^ help: try: `&MyEnum` @@ -57,7 +57,7 @@ LL | pub fn rc_test3(foo: Rc<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Rc<&MyEnum>` allocates a pointer on the heap error: usage of `Rc>` - --> tests/ui/redundant_allocation_fixable.rs:48:24 + --> tests/ui/redundant_allocation_fixable.rs:55:24 | LL | pub fn rc_test6(a: Rc>) {} | ^^^^^^^^^^^^ help: try: `Rc` @@ -65,7 +65,7 @@ LL | pub fn rc_test6(a: Rc>) {} = note: `Rc` is already on the heap, `Rc>` makes an extra allocation error: usage of `Arc<&T>` - --> tests/ui/redundant_allocation_fixable.rs:57:30 + --> tests/ui/redundant_allocation_fixable.rs:65:30 | LL | pub fn arc_test1(foo: Arc<&T>) {} | ^^^^^^^ help: try: `&T` @@ -73,7 +73,7 @@ LL | pub fn arc_test1(foo: Arc<&T>) {} = note: `&T` is already a pointer, `Arc<&T>` allocates a pointer on the heap error: usage of `Arc<&MyStruct>` - --> tests/ui/redundant_allocation_fixable.rs:59:27 + --> tests/ui/redundant_allocation_fixable.rs:68:27 | LL | pub fn arc_test2(foo: Arc<&MyStruct>) {} | ^^^^^^^^^^^^^^ help: try: `&MyStruct` @@ -81,7 +81,7 @@ LL | pub fn arc_test2(foo: Arc<&MyStruct>) {} = note: `&MyStruct` is already a pointer, `Arc<&MyStruct>` allocates a pointer on the heap error: usage of `Arc<&MyEnum>` - --> tests/ui/redundant_allocation_fixable.rs:61:27 + --> tests/ui/redundant_allocation_fixable.rs:71:27 | LL | pub fn arc_test3(foo: Arc<&MyEnum>) {} | ^^^^^^^^^^^^ help: try: `&MyEnum` @@ -89,7 +89,7 @@ LL | pub fn arc_test3(foo: Arc<&MyEnum>) {} = note: `&MyEnum` is already a pointer, `Arc<&MyEnum>` allocates a pointer on the heap error: usage of `Arc>` - --> tests/ui/redundant_allocation_fixable.rs:65:25 + --> tests/ui/redundant_allocation_fixable.rs:76:25 | LL | pub fn arc_test7(a: Arc>) {} | ^^^^^^^^^^^^^^ help: try: `Arc` diff --git a/src/tools/clippy/tests/ui/redundant_as_str.fixed b/src/tools/clippy/tests/ui/redundant_as_str.fixed index 708a1cc91506d..4c5f7893d42e0 100644 --- a/src/tools/clippy/tests/ui/redundant_as_str.fixed +++ b/src/tools/clippy/tests/ui/redundant_as_str.fixed @@ -6,7 +6,9 @@ fn main() { // These methods are redundant and the `as_str` can be removed let _redundant = string.as_bytes(); + //~^ redundant_as_str let _redundant = string.is_empty(); + //~^ redundant_as_str // These methods don't use `as_str` when they are redundant let _no_as_str = string.as_bytes(); diff --git a/src/tools/clippy/tests/ui/redundant_as_str.rs b/src/tools/clippy/tests/ui/redundant_as_str.rs index 257af591ceffb..e3baec754595c 100644 --- a/src/tools/clippy/tests/ui/redundant_as_str.rs +++ b/src/tools/clippy/tests/ui/redundant_as_str.rs @@ -6,7 +6,9 @@ fn main() { // These methods are redundant and the `as_str` can be removed let _redundant = string.as_str().as_bytes(); + //~^ redundant_as_str let _redundant = string.as_str().is_empty(); + //~^ redundant_as_str // These methods don't use `as_str` when they are redundant let _no_as_str = string.as_bytes(); diff --git a/src/tools/clippy/tests/ui/redundant_as_str.stderr b/src/tools/clippy/tests/ui/redundant_as_str.stderr index f5379d701db82..fc99c008220e5 100644 --- a/src/tools/clippy/tests/ui/redundant_as_str.stderr +++ b/src/tools/clippy/tests/ui/redundant_as_str.stderr @@ -8,7 +8,7 @@ LL | let _redundant = string.as_str().as_bytes(); = help: to override `-D warnings` add `#[allow(clippy::redundant_as_str)]` error: this `as_str` is redundant and can be removed as the method immediately following exists on `String` too - --> tests/ui/redundant_as_str.rs:9:29 + --> tests/ui/redundant_as_str.rs:10:29 | LL | let _redundant = string.as_str().is_empty(); | ^^^^^^^^^^^^^^^^^ help: try: `is_empty` diff --git a/src/tools/clippy/tests/ui/redundant_async_block.fixed b/src/tools/clippy/tests/ui/redundant_async_block.fixed index a1875c1c06e1a..2f14f27e70562 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.fixed +++ b/src/tools/clippy/tests/ui/redundant_async_block.fixed @@ -11,6 +11,7 @@ async fn func2() -> String { let s = String::from("some string"); let f = async { (*s).to_owned() }; let x = f; + //~^ redundant_async_block x.await } @@ -18,13 +19,16 @@ fn main() { let fut1 = async { 17 }; // Lint let fut2 = fut1; + //~^ redundant_async_block let fut1 = async { 25 }; // Lint let fut2 = fut1; + //~^ redundant_async_block // Lint let fut = async { 42 }; + //~^ redundant_async_block // Do not lint: not a single expression let fut = async { @@ -41,6 +45,7 @@ fn capture_local() -> impl Future { let fut = async { 17 }; // Lint fut + //~^ redundant_async_block } fn capture_local_closure(s: &str) -> impl Future { @@ -54,11 +59,13 @@ fn capture_arg(s: &str) -> impl Future { let fut = async move { s }; // Lint fut + //~^ redundant_async_block } fn capture_future_arg(f: impl Future) -> impl Future { // Lint f + //~^ redundant_async_block } fn capture_func_result(f: FN) -> impl Future @@ -82,6 +89,7 @@ where { // Lint async { f().await + 1 } + //~^ redundant_async_block } #[derive(Debug, Clone)] @@ -145,6 +153,7 @@ fn all_from_macro() -> impl Future { () => { // Lint async { 42 } + //~^ redundant_async_block }; } mac!() @@ -165,6 +174,7 @@ fn safe_parts_from_macro() -> impl Future { ($e: expr) => { // Lint async { $e } + //~^ redundant_async_block }; } mac!(42) diff --git a/src/tools/clippy/tests/ui/redundant_async_block.rs b/src/tools/clippy/tests/ui/redundant_async_block.rs index bb43403a043ed..f5fe26b19cc8a 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.rs +++ b/src/tools/clippy/tests/ui/redundant_async_block.rs @@ -11,6 +11,7 @@ async fn func2() -> String { let s = String::from("some string"); let f = async { (*s).to_owned() }; let x = async { f.await }; + //~^ redundant_async_block x.await } @@ -18,13 +19,16 @@ fn main() { let fut1 = async { 17 }; // Lint let fut2 = async { fut1.await }; + //~^ redundant_async_block let fut1 = async { 25 }; // Lint let fut2 = async move { fut1.await }; + //~^ redundant_async_block // Lint let fut = async { async { 42 }.await }; + //~^ redundant_async_block // Do not lint: not a single expression let fut = async { @@ -41,6 +45,7 @@ fn capture_local() -> impl Future { let fut = async { 17 }; // Lint async move { fut.await } + //~^ redundant_async_block } fn capture_local_closure(s: &str) -> impl Future { @@ -54,11 +59,13 @@ fn capture_arg(s: &str) -> impl Future { let fut = async move { s }; // Lint async move { fut.await } + //~^ redundant_async_block } fn capture_future_arg(f: impl Future) -> impl Future { // Lint async { f.await } + //~^ redundant_async_block } fn capture_func_result(f: FN) -> impl Future @@ -82,6 +89,7 @@ where { // Lint async { async { f().await + 1 }.await } + //~^ redundant_async_block } #[derive(Debug, Clone)] @@ -145,6 +153,7 @@ fn all_from_macro() -> impl Future { () => { // Lint async { async { 42 }.await } + //~^ redundant_async_block }; } mac!() @@ -165,6 +174,7 @@ fn safe_parts_from_macro() -> impl Future { ($e: expr) => { // Lint async { async { $e }.await } + //~^ redundant_async_block }; } mac!(42) diff --git a/src/tools/clippy/tests/ui/redundant_async_block.stderr b/src/tools/clippy/tests/ui/redundant_async_block.stderr index c6a5e2f28adae..386f00a25c2f9 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.stderr +++ b/src/tools/clippy/tests/ui/redundant_async_block.stderr @@ -8,49 +8,49 @@ LL | let x = async { f.await }; = help: to override `-D warnings` add `#[allow(clippy::redundant_async_block)]` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:20:16 + --> tests/ui/redundant_async_block.rs:21:16 | LL | let fut2 = async { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:24:16 + --> tests/ui/redundant_async_block.rs:26:16 | LL | let fut2 = async move { fut1.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut1` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:27:15 + --> tests/ui/redundant_async_block.rs:30:15 | LL | let fut = async { async { 42 }.await }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:43:5 + --> tests/ui/redundant_async_block.rs:47:5 | LL | async move { fut.await } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:56:5 + --> tests/ui/redundant_async_block.rs:61:5 | LL | async move { fut.await } | ^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `fut` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:61:5 + --> tests/ui/redundant_async_block.rs:67:5 | LL | async { f.await } | ^^^^^^^^^^^^^^^^^ help: you can reduce it to: `f` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:84:5 + --> tests/ui/redundant_async_block.rs:91:5 | LL | async { async { f().await + 1 }.await } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { f().await + 1 }` error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:147:13 + --> tests/ui/redundant_async_block.rs:155:13 | LL | async { async { 42 }.await } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { 42 }` @@ -61,7 +61,7 @@ LL | mac!() = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) error: this async expression only awaits a single future - --> tests/ui/redundant_async_block.rs:167:13 + --> tests/ui/redundant_async_block.rs:176:13 | LL | async { async { $e }.await } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `async { $e }` diff --git a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.fixed b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.fixed index a7997637372e8..908b9051b7ef0 100644 --- a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.fixed +++ b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.fixed @@ -7,13 +7,19 @@ extern crate proc_macros; fn main() { if let a = [()] {} + //~^ redundant_at_rest_pattern if let ref a = [()] {} + //~^ redundant_at_rest_pattern if let mut a = [()] {} + //~^ redundant_at_rest_pattern if let ref mut a = [()] {} + //~^ redundant_at_rest_pattern let v = vec![()]; if let a = &*v {} + //~^ redundant_at_rest_pattern let s = &[()]; if let a = s {} + //~^ redundant_at_rest_pattern // Don't lint if let [..] = &*v {} if let [a] = &*v {} diff --git a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.rs b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.rs index f103d1f1a1794..0f19459773a94 100644 --- a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.rs +++ b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.rs @@ -7,13 +7,19 @@ extern crate proc_macros; fn main() { if let [a @ ..] = [()] {} + //~^ redundant_at_rest_pattern if let [ref a @ ..] = [()] {} + //~^ redundant_at_rest_pattern if let [mut a @ ..] = [()] {} + //~^ redundant_at_rest_pattern if let [ref mut a @ ..] = [()] {} + //~^ redundant_at_rest_pattern let v = vec![()]; if let [a @ ..] = &*v {} + //~^ redundant_at_rest_pattern let s = &[()]; if let [a @ ..] = s {} + //~^ redundant_at_rest_pattern // Don't lint if let [..] = &*v {} if let [a] = &*v {} diff --git a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr index 012ba550ca113..3a6f6cf6500ab 100644 --- a/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr +++ b/src/tools/clippy/tests/ui/redundant_at_rest_pattern.stderr @@ -8,31 +8,31 @@ LL | if let [a @ ..] = [()] {} = help: to override `-D warnings` add `#[allow(clippy::redundant_at_rest_pattern)]` error: using a rest pattern to bind an entire slice to a local - --> tests/ui/redundant_at_rest_pattern.rs:10:12 + --> tests/ui/redundant_at_rest_pattern.rs:11:12 | LL | if let [ref a @ ..] = [()] {} | ^^^^^^^^^^^^ help: this is better represented with just the binding: `ref a` error: using a rest pattern to bind an entire slice to a local - --> tests/ui/redundant_at_rest_pattern.rs:11:12 + --> tests/ui/redundant_at_rest_pattern.rs:13:12 | LL | if let [mut a @ ..] = [()] {} | ^^^^^^^^^^^^ help: this is better represented with just the binding: `mut a` error: using a rest pattern to bind an entire slice to a local - --> tests/ui/redundant_at_rest_pattern.rs:12:12 + --> tests/ui/redundant_at_rest_pattern.rs:15:12 | LL | if let [ref mut a @ ..] = [()] {} | ^^^^^^^^^^^^^^^^ help: this is better represented with just the binding: `ref mut a` error: using a rest pattern to bind an entire slice to a local - --> tests/ui/redundant_at_rest_pattern.rs:14:12 + --> tests/ui/redundant_at_rest_pattern.rs:18:12 | LL | if let [a @ ..] = &*v {} | ^^^^^^^^ help: this is better represented with just the binding: `a` error: using a rest pattern to bind an entire slice to a local - --> tests/ui/redundant_at_rest_pattern.rs:16:12 + --> tests/ui/redundant_at_rest_pattern.rs:21:12 | LL | if let [a @ ..] = s {} | ^^^^^^^^ help: this is better represented with just the binding: `a` diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed index 1d04cca9b9ed9..23c00b34a00a8 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.fixed +++ b/src/tools/clippy/tests/ui/redundant_clone.fixed @@ -13,23 +13,31 @@ use std::path::Path; fn main() { let _s = ["lorem", "ipsum"].join(" "); + //~^ redundant_clone let s = String::from("foo"); let _s = s; + //~^ redundant_clone let s = String::from("foo"); let _s = s; + //~^ redundant_clone let s = String::from("foo"); let _s = s; + //~^ redundant_clone let _s = Path::new("/a/b/").join("c"); + //~^ redundant_clone let _s = Path::new("/a/b/").join("c"); + //~^ redundant_clone let _s = OsString::new(); + //~^ redundant_clone let _s = OsString::new(); + //~^ redundant_clone // Check that lint level works #[allow(clippy::redundant_clone)] @@ -41,6 +49,7 @@ fn main() { let tup = (String::from("foo"),); let _t = tup.0; + //~^ redundant_clone let tup_ref = &(String::from("foo"),); let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed @@ -73,6 +82,7 @@ fn main() { struct Alpha; fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) { if b { (a.clone(), a) } else { (Alpha, a) } + //~^ redundant_clone } fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) { @@ -130,7 +140,9 @@ fn borrower_propagation() { } let _s = s; + //~^ redundant_clone let _t = t; + //~^ redundant_clone #[derive(Clone)] struct Foo { @@ -141,6 +153,7 @@ fn borrower_propagation() { let f = Foo { x: 123 }; let _x = Some(f.x); let _f = f; + //~^ redundant_clone } { @@ -153,6 +166,7 @@ fn borrower_propagation() { fn not_consumed() { let x = std::path::PathBuf::from("home"); let y = x.join("matthias"); + //~^ redundant_clone // join() creates a new owned PathBuf, does not take a &mut to x variable, thus the .clone() is // redundant. (It also does not consume the PathBuf) @@ -207,6 +221,7 @@ fn clone_then_move_cloned() { let x = Alpha; // ok, data is moved while the clone is in use. foo(&x, move || { + //~^ redundant_clone let _ = x; }); diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs index 738744fec98f7..f9fe8ba0236d0 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.rs +++ b/src/tools/clippy/tests/ui/redundant_clone.rs @@ -13,23 +13,31 @@ use std::path::Path; fn main() { let _s = ["lorem", "ipsum"].join(" ").to_string(); + //~^ redundant_clone let s = String::from("foo"); let _s = s.clone(); + //~^ redundant_clone let s = String::from("foo"); let _s = s.to_string(); + //~^ redundant_clone let s = String::from("foo"); let _s = s.to_owned(); + //~^ redundant_clone let _s = Path::new("/a/b/").join("c").to_owned(); + //~^ redundant_clone let _s = Path::new("/a/b/").join("c").to_path_buf(); + //~^ redundant_clone let _s = OsString::new().to_owned(); + //~^ redundant_clone let _s = OsString::new().to_os_string(); + //~^ redundant_clone // Check that lint level works #[allow(clippy::redundant_clone)] @@ -41,6 +49,7 @@ fn main() { let tup = (String::from("foo"),); let _t = tup.0.clone(); + //~^ redundant_clone let tup_ref = &(String::from("foo"),); let _s = tup_ref.0.clone(); // this `.clone()` cannot be removed @@ -73,6 +82,7 @@ fn main() { struct Alpha; fn with_branch(a: Alpha, b: bool) -> (Alpha, Alpha) { if b { (a.clone(), a.clone()) } else { (Alpha, a) } + //~^ redundant_clone } fn cannot_double_move(a: Alpha) -> (Alpha, Alpha) { @@ -130,7 +140,9 @@ fn borrower_propagation() { } let _s = s.clone(); + //~^ redundant_clone let _t = t.clone(); + //~^ redundant_clone #[derive(Clone)] struct Foo { @@ -141,6 +153,7 @@ fn borrower_propagation() { let f = Foo { x: 123 }; let _x = Some(f.x); let _f = f.clone(); + //~^ redundant_clone } { @@ -153,6 +166,7 @@ fn borrower_propagation() { fn not_consumed() { let x = std::path::PathBuf::from("home"); let y = x.clone().join("matthias"); + //~^ redundant_clone // join() creates a new owned PathBuf, does not take a &mut to x variable, thus the .clone() is // redundant. (It also does not consume the PathBuf) @@ -207,6 +221,7 @@ fn clone_then_move_cloned() { let x = Alpha; // ok, data is moved while the clone is in use. foo(&x.clone(), move || { + //~^ redundant_clone let _ = x; }); diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index 3c37288f55078..5be081f0f2f8e 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -13,169 +13,169 @@ LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> tests/ui/redundant_clone.rs:18:15 + --> tests/ui/redundant_clone.rs:19:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:18:14 + --> tests/ui/redundant_clone.rs:19:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:21:15 + --> tests/ui/redundant_clone.rs:23:15 | LL | let _s = s.to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:21:14 + --> tests/ui/redundant_clone.rs:23:14 | LL | let _s = s.to_string(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:24:15 + --> tests/ui/redundant_clone.rs:27:15 | LL | let _s = s.to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:24:14 + --> tests/ui/redundant_clone.rs:27:14 | LL | let _s = s.to_owned(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:26:42 + --> tests/ui/redundant_clone.rs:30:42 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:26:14 + --> tests/ui/redundant_clone.rs:30:14 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:28:42 + --> tests/ui/redundant_clone.rs:33:42 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:28:14 + --> tests/ui/redundant_clone.rs:33:14 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:30:29 + --> tests/ui/redundant_clone.rs:36:29 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:30:14 + --> tests/ui/redundant_clone.rs:36:14 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:32:29 + --> tests/ui/redundant_clone.rs:39:29 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:32:14 + --> tests/ui/redundant_clone.rs:39:14 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:43:19 + --> tests/ui/redundant_clone.rs:51:19 | LL | let _t = tup.0.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:43:14 + --> tests/ui/redundant_clone.rs:51:14 | LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:75:25 + --> tests/ui/redundant_clone.rs:84:25 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:75:24 + --> tests/ui/redundant_clone.rs:84:24 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:132:15 + --> tests/ui/redundant_clone.rs:142:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:132:14 + --> tests/ui/redundant_clone.rs:142:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:133:15 + --> tests/ui/redundant_clone.rs:144:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:133:14 + --> tests/ui/redundant_clone.rs:144:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:143:19 + --> tests/ui/redundant_clone.rs:155:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:143:18 + --> tests/ui/redundant_clone.rs:155:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> tests/ui/redundant_clone.rs:155:14 + --> tests/ui/redundant_clone.rs:168:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> tests/ui/redundant_clone.rs:155:13 + --> tests/ui/redundant_clone.rs:168:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ error: redundant clone - --> tests/ui/redundant_clone.rs:209:11 + --> tests/ui/redundant_clone.rs:223:11 | LL | foo(&x.clone(), move || { | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/redundant_clone.rs:209:10 + --> tests/ui/redundant_clone.rs:223:10 | LL | foo(&x.clone(), move || { | ^ diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_early.rs b/src/tools/clippy/tests/ui/redundant_closure_call_early.rs index 6f9c9fd522241..722f7c03909f0 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_early.rs +++ b/src/tools/clippy/tests/ui/redundant_closure_call_early.rs @@ -7,12 +7,11 @@ fn main() { // lint here let mut k = (|m| m + 1)(i); - //~^ ERROR: try not to call a closure in the expression where it is declared - //~| NOTE: `-D clippy::redundant-closure-call` implied by `-D warnings` + //~^ redundant_closure_call // lint here k = (|a, b| a * b)(1, 5); - //~^ ERROR: try not to call a closure in the expression where it is declared + //~^ redundant_closure_call // don't lint these #[allow(clippy::needless_return)] diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr index 038144a5d6134..1dd24baf9daeb 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_early.stderr @@ -8,7 +8,7 @@ LL | let mut k = (|m| m + 1)(i); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_early.rs:14:9 + --> tests/ui/redundant_closure_call_early.rs:13:9 | LL | k = (|a, b| a * b)(1, 5); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed index 9138a8bacfe17..099c118e64e35 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed @@ -13,17 +13,21 @@ async fn something_else() -> u32 { fn main() { let a = 42; + //~^ redundant_closure_call let b = async { + //~^ redundant_closure_call let x = something().await; let y = something_else().await; x * y }; let c = { + //~^ redundant_closure_call let x = 21; let y = 2; x * y }; let d = async { something().await }; + //~^ redundant_closure_call macro_rules! m { () => { @@ -33,14 +37,17 @@ fn main() { macro_rules! m2 { () => { m!() + //~^ redundant_closure_call }; } m2!(); + //~^ redundant_closure_call issue9956(); } fn issue9956() { assert_eq!(43, 42); + //~^ redundant_closure_call // ... and some more interesting cases I've found while implementing the fix @@ -50,13 +57,16 @@ fn issue9956() { // immediately calling it inside of a macro dbg!(42); + //~^ redundant_closure_call // immediately calling only one closure, so we can't remove the other ones let a = (|| || 123); + //~^ redundant_closure_call dbg!(a()()); // nested async closures let a = async { 1 }; + //~^ redundant_closure_call let h = async { a.await }; // macro expansion tests @@ -66,8 +76,10 @@ fn issue9956() { }; } let a = 1; + //~^ redundant_closure_call assert_eq!(a, 1); let a = 123; + //~^ redundant_closure_call assert_eq!(a, 123); // chaining calls, but not closures @@ -81,11 +93,14 @@ fn issue9956() { } fn foo(_: i32, _: i32) {} bar()(42, 5); + //~^ redundant_closure_call foo(42, 5); + //~^ redundant_closure_call } async fn issue11357() { async {}.await; + //~^ redundant_closure_call } mod issue11707 { @@ -95,11 +110,13 @@ mod issue11707 { fn demo() { spawn_on(async move {}); + //~^ redundant_closure_call } } fn avoid_double_parens() { std::convert::identity(13_i32 + 36_i32).leading_zeros(); + //~^ redundant_closure_call } fn fp_11274() { diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs index ede6fa27778be..da5dd7ef263b6 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs @@ -13,17 +13,21 @@ async fn something_else() -> u32 { fn main() { let a = (|| 42)(); + //~^ redundant_closure_call let b = (async || { + //~^ redundant_closure_call let x = something().await; let y = something_else().await; x * y })(); let c = (|| { + //~^ redundant_closure_call let x = 21; let y = 2; x * y })(); let d = (async || something().await)(); + //~^ redundant_closure_call macro_rules! m { () => { @@ -33,14 +37,17 @@ fn main() { macro_rules! m2 { () => { (|| m!())() + //~^ redundant_closure_call }; } m2!(); + //~^ redundant_closure_call issue9956(); } fn issue9956() { assert_eq!((|| || 43)()(), 42); + //~^ redundant_closure_call // ... and some more interesting cases I've found while implementing the fix @@ -50,13 +57,16 @@ fn issue9956() { // immediately calling it inside of a macro dbg!((|| 42)()); + //~^ redundant_closure_call // immediately calling only one closure, so we can't remove the other ones let a = (|| || || 123)(); + //~^ redundant_closure_call dbg!(a()()); // nested async closures let a = (|| || || || async || 1)()()()()(); + //~^ redundant_closure_call let h = async { a.await }; // macro expansion tests @@ -66,8 +76,10 @@ fn issue9956() { }; } let a = (|| echo!(|| echo!(|| 1)))()()(); + //~^ redundant_closure_call assert_eq!(a, 1); let a = (|| echo!((|| 123)))()(); + //~^ redundant_closure_call assert_eq!(a, 123); // chaining calls, but not closures @@ -81,11 +93,14 @@ fn issue9956() { } fn foo(_: i32, _: i32) {} bar()((|| || 42)()(), 5); + //~^ redundant_closure_call foo((|| || 42)()(), 5); + //~^ redundant_closure_call } async fn issue11357() { (|| async {})().await; + //~^ redundant_closure_call } mod issue11707 { @@ -95,11 +110,13 @@ mod issue11707 { fn demo() { spawn_on((|| async move {})()); + //~^ redundant_closure_call } } fn avoid_double_parens() { std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); + //~^ redundant_closure_call } fn fp_11274() { diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr index 8e0d37df96b83..2c35aafbe3109 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr @@ -8,10 +8,11 @@ LL | let a = (|| 42)(); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:16:13 + --> tests/ui/redundant_closure_call_fixable.rs:17:13 | LL | let b = (async || { | _____________^ +LL | | LL | | let x = something().await; LL | | let y = something_else().await; LL | | x * y @@ -21,6 +22,7 @@ LL | | })(); help: try doing something like | LL ~ let b = async { +LL + LL + let x = something().await; LL + let y = something_else().await; LL + x * y @@ -28,10 +30,11 @@ LL ~ }; | error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:21:13 + --> tests/ui/redundant_closure_call_fixable.rs:23:13 | LL | let c = (|| { | _____________^ +LL | | LL | | let x = 21; LL | | let y = 2; LL | | x * y @@ -41,6 +44,7 @@ LL | | })(); help: try doing something like | LL ~ let c = { +LL + LL + let x = 21; LL + let y = 2; LL + x * y @@ -48,13 +52,13 @@ LL ~ }; | error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:26:13 + --> tests/ui/redundant_closure_call_fixable.rs:29:13 | LL | let d = (async || something().await)(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:35:13 + --> tests/ui/redundant_closure_call_fixable.rs:39:13 | LL | (|| m!())() | ^^^^^^^^^^^ help: try doing something like: `m!()` @@ -65,7 +69,7 @@ LL | m2!(); = note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:30:13 + --> tests/ui/redundant_closure_call_fixable.rs:34:13 | LL | (|| 0)() | ^^^^^^^^ help: try doing something like: `0` @@ -76,67 +80,67 @@ LL | m2!(); = note: this error originates in the macro `m` which comes from the expansion of the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info) error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:43:16 + --> tests/ui/redundant_closure_call_fixable.rs:49:16 | LL | assert_eq!((|| || 43)()(), 42); | ^^^^^^^^^^^^^^ help: try doing something like: `43` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:52:10 + --> tests/ui/redundant_closure_call_fixable.rs:59:10 | LL | dbg!((|| 42)()); | ^^^^^^^^^ help: try doing something like: `42` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:55:13 + --> tests/ui/redundant_closure_call_fixable.rs:63:13 | LL | let a = (|| || || 123)(); | ^^^^^^^^^^^^^^^^ help: try doing something like: `(|| || 123)` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:59:13 + --> tests/ui/redundant_closure_call_fixable.rs:68:13 | LL | let a = (|| || || || async || 1)()()()()(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { 1 }` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:68:13 + --> tests/ui/redundant_closure_call_fixable.rs:78:13 | LL | let a = (|| echo!(|| echo!(|| 1)))()()(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `1` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:70:13 + --> tests/ui/redundant_closure_call_fixable.rs:81:13 | LL | let a = (|| echo!((|| 123)))()(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `123` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:83:11 + --> tests/ui/redundant_closure_call_fixable.rs:95:11 | LL | bar()((|| || 42)()(), 5); | ^^^^^^^^^^^^^^ help: try doing something like: `42` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:84:9 + --> tests/ui/redundant_closure_call_fixable.rs:97:9 | LL | foo((|| || 42)()(), 5); | ^^^^^^^^^^^^^^ help: try doing something like: `42` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:88:5 + --> tests/ui/redundant_closure_call_fixable.rs:102:5 | LL | (|| async {})().await; | ^^^^^^^^^^^^^^^ help: try doing something like: `async {}` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:97:18 + --> tests/ui/redundant_closure_call_fixable.rs:112:18 | LL | spawn_on((|| async move {})()); | ^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async move {}` error: try not to call a closure in the expression where it is declared - --> tests/ui/redundant_closure_call_fixable.rs:102:28 + --> tests/ui/redundant_closure_call_fixable.rs:118:28 | LL | std::convert::identity((|| 13_i32 + 36_i32)()).leading_zeros(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `13_i32 + 36_i32` diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_late.rs b/src/tools/clippy/tests/ui/redundant_closure_call_late.rs index dc369c3bc092f..fd997b1b5fa7b 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_late.rs +++ b/src/tools/clippy/tests/ui/redundant_closure_call_late.rs @@ -14,16 +14,16 @@ fn main() { // lint here let redun_closure = || 1; i = redun_closure(); - //~^ ERROR: closure called just once immediately after it was declared - //~| NOTE: `-D clippy::redundant-closure-call` implied by `-D warnings` + //~^ redundant_closure_call // shadowed closures are supported, lint here let shadowed_closure = || 1; i = shadowed_closure(); - //~^ ERROR: closure called just once immediately after it was declared + //~^ redundant_closure_call + let shadowed_closure = || 2; i = shadowed_closure(); - //~^ ERROR: closure called just once immediately after it was declared + //~^ redundant_closure_call // don't lint here let shadowed_closure = || 2; diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr index 023e766a5d2b5..ce2a21c23872e 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_late.stderr @@ -8,7 +8,7 @@ LL | i = redun_closure(); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_call)]` error: closure called just once immediately after it was declared - --> tests/ui/redundant_closure_call_late.rs:22:5 + --> tests/ui/redundant_closure_call_late.rs:21:5 | LL | i = shadowed_closure(); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_else.fixed b/src/tools/clippy/tests/ui/redundant_else.fixed index 47aa79302d2cf..8a3279f50180b 100644 --- a/src/tools/clippy/tests/ui/redundant_else.fixed +++ b/src/tools/clippy/tests/ui/redundant_else.fixed @@ -8,14 +8,16 @@ fn main() { println!("Love your neighbor;"); break; } - //~^ ERROR: redundant else block + //~^ redundant_else + println!("yet don't pull down your hedge."); // continue if foo() { println!("He that lies down with Dogs,"); continue; } - //~^ ERROR: redundant else block + //~^ redundant_else + println!("shall rise up with fleas."); // match block if foo() { @@ -24,7 +26,8 @@ fn main() { _ => return, } } - //~^ ERROR: redundant else block + //~^ redundant_else + println!("You may delay, but time will not."); } // else if @@ -33,14 +36,16 @@ fn main() { } else if foo() { return; } - //~^ ERROR: redundant else block + //~^ redundant_else + println!("A fat kitchen makes a lean will."); // let binding outside of block let _ = { if foo() { return; } - //~^ ERROR: redundant else block + //~^ redundant_else + 1 }; // else if with let binding outside of block @@ -50,7 +55,8 @@ fn main() { } else if foo() { return; } - //~^ ERROR: redundant else block + //~^ redundant_else + 2 }; // inside if let @@ -59,7 +65,8 @@ fn main() { if foo() { return; } - //~^ ERROR: redundant else block + //~^ redundant_else + 1 } else { 1 diff --git a/src/tools/clippy/tests/ui/redundant_else.rs b/src/tools/clippy/tests/ui/redundant_else.rs index 8bcf2ce5233da..78abf4247a568 100644 --- a/src/tools/clippy/tests/ui/redundant_else.rs +++ b/src/tools/clippy/tests/ui/redundant_else.rs @@ -8,7 +8,8 @@ fn main() { println!("Love your neighbor;"); break; } else { - //~^ ERROR: redundant else block + //~^ redundant_else + println!("yet don't pull down your hedge."); } // continue @@ -16,7 +17,8 @@ fn main() { println!("He that lies down with Dogs,"); continue; } else { - //~^ ERROR: redundant else block + //~^ redundant_else + println!("shall rise up with fleas."); } // match block @@ -26,7 +28,8 @@ fn main() { _ => return, } } else { - //~^ ERROR: redundant else block + //~^ redundant_else + println!("You may delay, but time will not."); } } @@ -36,7 +39,8 @@ fn main() { } else if foo() { return; } else { - //~^ ERROR: redundant else block + //~^ redundant_else + println!("A fat kitchen makes a lean will."); } // let binding outside of block @@ -44,7 +48,8 @@ fn main() { if foo() { return; } else { - //~^ ERROR: redundant else block + //~^ redundant_else + 1 } }; @@ -55,7 +60,8 @@ fn main() { } else if foo() { return; } else { - //~^ ERROR: redundant else block + //~^ redundant_else + 2 } }; @@ -65,7 +71,8 @@ fn main() { if foo() { return; } else { - //~^ ERROR: redundant else block + //~^ redundant_else + 1 } } else { diff --git a/src/tools/clippy/tests/ui/redundant_else.stderr b/src/tools/clippy/tests/ui/redundant_else.stderr index ecc16f7cda5e5..0902c97af0dd7 100644 --- a/src/tools/clippy/tests/ui/redundant_else.stderr +++ b/src/tools/clippy/tests/ui/redundant_else.stderr @@ -4,6 +4,7 @@ error: redundant else block LL | } else { | __________^ LL | | +LL | | LL | | println!("yet don't pull down your hedge."); LL | | } | |_________^ @@ -14,15 +15,17 @@ help: remove the `else` block and move the contents out | LL ~ } LL + +LL + LL + println!("yet don't pull down your hedge."); | error: redundant else block - --> tests/ui/redundant_else.rs:18:10 + --> tests/ui/redundant_else.rs:19:10 | LL | } else { | __________^ LL | | +LL | | LL | | println!("shall rise up with fleas."); LL | | } | |_________^ @@ -31,15 +34,17 @@ help: remove the `else` block and move the contents out | LL ~ } LL + +LL + LL + println!("shall rise up with fleas."); | error: redundant else block - --> tests/ui/redundant_else.rs:28:10 + --> tests/ui/redundant_else.rs:30:10 | LL | } else { | __________^ LL | | +LL | | LL | | println!("You may delay, but time will not."); LL | | } | |_________^ @@ -48,15 +53,17 @@ help: remove the `else` block and move the contents out | LL ~ } LL + +LL + LL + println!("You may delay, but time will not."); | error: redundant else block - --> tests/ui/redundant_else.rs:38:6 + --> tests/ui/redundant_else.rs:41:6 | LL | } else { | ______^ LL | | +LL | | LL | | println!("A fat kitchen makes a lean will."); LL | | } | |_____^ @@ -65,15 +72,17 @@ help: remove the `else` block and move the contents out | LL ~ } LL + +LL + LL + println!("A fat kitchen makes a lean will."); | error: redundant else block - --> tests/ui/redundant_else.rs:46:10 + --> tests/ui/redundant_else.rs:50:10 | LL | } else { | __________^ LL | | +LL | | LL | | 1 LL | | } | |_________^ @@ -82,15 +91,17 @@ help: remove the `else` block and move the contents out | LL ~ } LL + +LL + LL + 1 | error: redundant else block - --> tests/ui/redundant_else.rs:57:10 + --> tests/ui/redundant_else.rs:62:10 | LL | } else { | __________^ LL | | +LL | | LL | | 2 LL | | } | |_________^ @@ -99,15 +110,17 @@ help: remove the `else` block and move the contents out | LL ~ } LL + +LL + LL + 2 | error: redundant else block - --> tests/ui/redundant_else.rs:67:10 + --> tests/ui/redundant_else.rs:73:10 | LL | } else { | __________^ LL | | +LL | | LL | | 1 LL | | } | |_________^ @@ -116,6 +129,7 @@ help: remove the `else` block and move the contents out | LL ~ } LL + +LL + LL + 1 | diff --git a/src/tools/clippy/tests/ui/redundant_field_names.fixed b/src/tools/clippy/tests/ui/redundant_field_names.fixed index 72fc4cb7333ec..4c922030eb66b 100644 --- a/src/tools/clippy/tests/ui/redundant_field_names.fixed +++ b/src/tools/clippy/tests/ui/redundant_field_names.fixed @@ -31,8 +31,9 @@ fn main() { let me = Person { gender, + //~^ redundant_field_names age, - + //~^ redundant_field_names name, //should be ok buzz: fizz, //should be ok foo: foo::BAR, //should be ok @@ -53,10 +54,15 @@ fn main() { // hand-written Range family structs are linted let _ = RangeFrom { start }; + //~^ redundant_field_names let _ = RangeTo { end }; + //~^ redundant_field_names let _ = Range { start, end }; + //~^ redundant_field_names + //~| redundant_field_names let _ = RangeInclusive::new(start, end); let _ = RangeToInclusive { end }; + //~^ redundant_field_names external! { let v = 1; @@ -69,6 +75,7 @@ fn main() { macro_rules! internal { ($i:ident) => { let _ = S { v }; + //~^ redundant_field_names let _ = S { $i: v }; let _ = S { v: $i }; let _ = S { $i: $i }; @@ -97,4 +104,5 @@ fn msrv_1_16() { fn msrv_1_17() { let start = 0; let _ = RangeFrom { start }; + //~^ redundant_field_names } diff --git a/src/tools/clippy/tests/ui/redundant_field_names.rs b/src/tools/clippy/tests/ui/redundant_field_names.rs index 2617d7e728379..7d03e269cf25e 100644 --- a/src/tools/clippy/tests/ui/redundant_field_names.rs +++ b/src/tools/clippy/tests/ui/redundant_field_names.rs @@ -31,8 +31,9 @@ fn main() { let me = Person { gender: gender, + //~^ redundant_field_names age: age, - + //~^ redundant_field_names name, //should be ok buzz: fizz, //should be ok foo: foo::BAR, //should be ok @@ -53,10 +54,15 @@ fn main() { // hand-written Range family structs are linted let _ = RangeFrom { start: start }; + //~^ redundant_field_names let _ = RangeTo { end: end }; + //~^ redundant_field_names let _ = Range { start: start, end: end }; + //~^ redundant_field_names + //~| redundant_field_names let _ = RangeInclusive::new(start, end); let _ = RangeToInclusive { end: end }; + //~^ redundant_field_names external! { let v = 1; @@ -69,6 +75,7 @@ fn main() { macro_rules! internal { ($i:ident) => { let _ = S { v: v }; + //~^ redundant_field_names let _ = S { $i: v }; let _ = S { v: $i }; let _ = S { $i: $i }; @@ -97,4 +104,5 @@ fn msrv_1_16() { fn msrv_1_17() { let start = 0; let _ = RangeFrom { start: start }; + //~^ redundant_field_names } diff --git a/src/tools/clippy/tests/ui/redundant_field_names.stderr b/src/tools/clippy/tests/ui/redundant_field_names.stderr index 38c021fdba370..5554c28b7cff3 100644 --- a/src/tools/clippy/tests/ui/redundant_field_names.stderr +++ b/src/tools/clippy/tests/ui/redundant_field_names.stderr @@ -8,43 +8,43 @@ LL | gender: gender, = help: to override `-D warnings` add `#[allow(clippy::redundant_field_names)]` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:34:9 + --> tests/ui/redundant_field_names.rs:35:9 | LL | age: age, | ^^^^^^^^ help: replace it with: `age` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:55:25 + --> tests/ui/redundant_field_names.rs:56:25 | LL | let _ = RangeFrom { start: start }; | ^^^^^^^^^^^^ help: replace it with: `start` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:56:23 + --> tests/ui/redundant_field_names.rs:58:23 | LL | let _ = RangeTo { end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:57:21 + --> tests/ui/redundant_field_names.rs:60:21 | LL | let _ = Range { start: start, end: end }; | ^^^^^^^^^^^^ help: replace it with: `start` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:57:35 + --> tests/ui/redundant_field_names.rs:60:35 | LL | let _ = Range { start: start, end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:59:32 + --> tests/ui/redundant_field_names.rs:64:32 | LL | let _ = RangeToInclusive { end: end }; | ^^^^^^^^ help: replace it with: `end` error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:71:25 + --> tests/ui/redundant_field_names.rs:77:25 | LL | let _ = S { v: v }; | ^^^^ help: replace it with: `v` @@ -55,7 +55,7 @@ LL | internal!(v); = note: this error originates in the macro `internal` (in Nightly builds, run with -Z macro-backtrace for more info) error: redundant field names in struct initialization - --> tests/ui/redundant_field_names.rs:99:25 + --> tests/ui/redundant_field_names.rs:106:25 | LL | let _ = RangeFrom { start: start }; | ^^^^^^^^^^^^ help: replace it with: `start` diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed index ff7b233f004ec..9dd9d341db2ef 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.fixed +++ b/src/tools/clippy/tests/ui/redundant_guards.fixed @@ -20,12 +20,14 @@ struct FloatWrapper(f32); fn issue11304() { match 0.1 { 0.0 => todo!(), + //~^ redundant_guards // Pattern matching NAN is illegal x if x == f64::NAN => todo!(), _ => todo!(), } match FloatWrapper(0.1) { FloatWrapper(0.0) => todo!(), + //~^ redundant_guards _ => todo!(), } } @@ -41,19 +43,25 @@ fn main() { let c = C(1, 2); match c { C(x, 1) => .., + //~^ redundant_guards _ => todo!(), }; let x = Some(Some(1)); match x { Some(Some(1)) if true => .., + //~^ redundant_guards Some(Some(1)) => { + //~^ redundant_guards println!("a"); .. }, Some(Some(1)) => .., + //~^ redundant_guards Some(Some(2)) => .., + //~^ redundant_guards Some(Some(2)) => .., + //~^ redundant_guards // Don't lint, since x is used in the body Some(x) if let Some(1) = x => { x; @@ -79,6 +87,7 @@ fn main() { let b = B { e: Some(A(0)) }; match b { B { e: Some(A(2)) } => .., + //~^ redundant_guards _ => todo!(), }; // Do not lint, since we cannot represent this as a pattern (at least, without a conversion) @@ -116,6 +125,7 @@ fn i() { // Do not lint E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {}, E::A("not from an or pattern") => {}, + //~^ redundant_guards _ => {}, }; } @@ -123,6 +133,7 @@ fn i() { fn h(v: Option) { match v { Some(0) => .., + //~^ redundant_guards _ => .., }; } @@ -130,7 +141,9 @@ fn h(v: Option) { fn negative_literal(i: i32) { match i { -1 => {}, + //~^ redundant_guards 1 => {}, + //~^ redundant_guards _ => {}, } } @@ -193,9 +206,13 @@ mod issue11465 { let c = Some(1); match c { Some(1) => {}, + //~^ redundant_guards Some(1) => {}, + //~^ redundant_guards Some(2) => {}, + //~^ redundant_guards Some(3) => {}, + //~^ redundant_guards _ => {}, }; @@ -216,9 +233,13 @@ mod issue11465 { B { ref b, .. } if b == "bar" => {}, B { ref b, .. } if "bar" == b => {}, B { c: 1, .. } => {}, + //~^ redundant_guards B { c: 1, .. } => {}, + //~^ redundant_guards B { c: 1, .. } => {}, + //~^ redundant_guards B { c: 1, .. } => {}, + //~^ redundant_guards _ => {}, } } @@ -229,6 +250,7 @@ fn issue11807() { match Some(Some("")) { Some(Some("")) => {}, + //~^ redundant_guards _ => {}, } @@ -240,11 +262,13 @@ fn issue11807() { match Some(Some(&[] as &[i32])) { Some(Some([])) => {}, + //~^ redundant_guards _ => {}, } match Some(Some([] as [i32; 0])) { Some(Some([])) => {}, + //~^ redundant_guards _ => {}, } @@ -256,21 +280,25 @@ fn issue11807() { match Some(Some(&[] as &[i32])) { Some(Some([..])) => {}, + //~^ redundant_guards _ => {}, } match Some(Some(&[] as &[i32])) { Some(Some([1, ..])) => {}, + //~^ redundant_guards _ => {}, } match Some(Some(&[] as &[i32])) { Some(Some([1, 2, ..])) => {}, + //~^ redundant_guards _ => {}, } match Some(Some(&[] as &[i32])) { Some(Some([.., 1, 2])) => {}, + //~^ redundant_guards _ => {}, } diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs index b4d4ef5b170d7..e9950d3bbd1d2 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.rs +++ b/src/tools/clippy/tests/ui/redundant_guards.rs @@ -20,12 +20,14 @@ struct FloatWrapper(f32); fn issue11304() { match 0.1 { x if x == 0.0 => todo!(), + //~^ redundant_guards // Pattern matching NAN is illegal x if x == f64::NAN => todo!(), _ => todo!(), } match FloatWrapper(0.1) { x if x == FloatWrapper(0.0) => todo!(), + //~^ redundant_guards _ => todo!(), } } @@ -41,19 +43,25 @@ fn main() { let c = C(1, 2); match c { C(x, y) if let 1 = y => .., + //~^ redundant_guards _ => todo!(), }; let x = Some(Some(1)); match x { Some(x) if matches!(x, Some(1) if true) => .., + //~^ redundant_guards Some(x) if matches!(x, Some(1)) => { + //~^ redundant_guards println!("a"); .. }, Some(x) if let Some(1) = x => .., + //~^ redundant_guards Some(x) if x == Some(2) => .., + //~^ redundant_guards Some(x) if Some(2) == x => .., + //~^ redundant_guards // Don't lint, since x is used in the body Some(x) if let Some(1) = x => { x; @@ -79,6 +87,7 @@ fn main() { let b = B { e: Some(A(0)) }; match b { B { e } if matches!(e, Some(A(2))) => .., + //~^ redundant_guards _ => todo!(), }; // Do not lint, since we cannot represent this as a pattern (at least, without a conversion) @@ -116,6 +125,7 @@ fn i() { // Do not lint E::A(x) | E::B(x) | E::C(x) if x == "from an or pattern" => {}, E::A(y) if y == "not from an or pattern" => {}, + //~^ redundant_guards _ => {}, }; } @@ -123,6 +133,7 @@ fn i() { fn h(v: Option) { match v { x if matches!(x, Some(0)) => .., + //~^ redundant_guards _ => .., }; } @@ -130,7 +141,9 @@ fn h(v: Option) { fn negative_literal(i: i32) { match i { i if i == -1 => {}, + //~^ redundant_guards i if i == 1 => {}, + //~^ redundant_guards _ => {}, } } @@ -193,9 +206,13 @@ mod issue11465 { let c = Some(1); match c { Some(ref x) if x == &1 => {}, + //~^ redundant_guards Some(ref x) if &1 == x => {}, + //~^ redundant_guards Some(ref x) if let &2 = x => {}, + //~^ redundant_guards Some(ref x) if matches!(x, &3) => {}, + //~^ redundant_guards _ => {}, }; @@ -216,9 +233,13 @@ mod issue11465 { B { ref b, .. } if b == "bar" => {}, B { ref b, .. } if "bar" == b => {}, B { ref c, .. } if c == &1 => {}, + //~^ redundant_guards B { ref c, .. } if &1 == c => {}, + //~^ redundant_guards B { ref c, .. } if let &1 = c => {}, + //~^ redundant_guards B { ref c, .. } if matches!(c, &1) => {}, + //~^ redundant_guards _ => {}, } } @@ -229,6 +250,7 @@ fn issue11807() { match Some(Some("")) { Some(Some(x)) if x.is_empty() => {}, + //~^ redundant_guards _ => {}, } @@ -240,11 +262,13 @@ fn issue11807() { match Some(Some(&[] as &[i32])) { Some(Some(x)) if x.is_empty() => {}, + //~^ redundant_guards _ => {}, } match Some(Some([] as [i32; 0])) { Some(Some(x)) if x.is_empty() => {}, + //~^ redundant_guards _ => {}, } @@ -256,21 +280,25 @@ fn issue11807() { match Some(Some(&[] as &[i32])) { Some(Some(x)) if x.starts_with(&[]) => {}, + //~^ redundant_guards _ => {}, } match Some(Some(&[] as &[i32])) { Some(Some(x)) if x.starts_with(&[1]) => {}, + //~^ redundant_guards _ => {}, } match Some(Some(&[] as &[i32])) { Some(Some(x)) if x.starts_with(&[1, 2]) => {}, + //~^ redundant_guards _ => {}, } match Some(Some(&[] as &[i32])) { Some(Some(x)) if x.ends_with(&[1, 2]) => {}, + //~^ redundant_guards _ => {}, } diff --git a/src/tools/clippy/tests/ui/redundant_guards.stderr b/src/tools/clippy/tests/ui/redundant_guards.stderr index a10cd5c2f481b..cb7b9b119e20f 100644 --- a/src/tools/clippy/tests/ui/redundant_guards.stderr +++ b/src/tools/clippy/tests/ui/redundant_guards.stderr @@ -13,7 +13,7 @@ LL + 0.0 => todo!(), | error: redundant guard - --> tests/ui/redundant_guards.rs:28:14 + --> tests/ui/redundant_guards.rs:29:14 | LL | x if x == FloatWrapper(0.0) => todo!(), | ^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + FloatWrapper(0.0) => todo!(), | error: redundant guard - --> tests/ui/redundant_guards.rs:43:20 + --> tests/ui/redundant_guards.rs:45:20 | LL | C(x, y) if let 1 = y => .., | ^^^^^^^^^ @@ -37,7 +37,7 @@ LL + C(x, 1) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:49:20 + --> tests/ui/redundant_guards.rs:52:20 | LL | Some(x) if matches!(x, Some(1) if true) => .., | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + Some(Some(1)) if true => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:50:20 + --> tests/ui/redundant_guards.rs:54:20 | LL | Some(x) if matches!(x, Some(1)) => { | ^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + Some(Some(1)) => { | error: redundant guard - --> tests/ui/redundant_guards.rs:54:20 + --> tests/ui/redundant_guards.rs:59:20 | LL | Some(x) if let Some(1) = x => .., | ^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + Some(Some(1)) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:55:20 + --> tests/ui/redundant_guards.rs:61:20 | LL | Some(x) if x == Some(2) => .., | ^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + Some(Some(2)) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:56:20 + --> tests/ui/redundant_guards.rs:63:20 | LL | Some(x) if Some(2) == x => .., | ^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + Some(Some(2)) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:81:20 + --> tests/ui/redundant_guards.rs:89:20 | LL | B { e } if matches!(e, Some(A(2))) => .., | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + B { e: Some(A(2)) } => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:118:20 + --> tests/ui/redundant_guards.rs:127:20 | LL | E::A(y) if y == "not from an or pattern" => {}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + E::A("not from an or pattern") => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:125:14 + --> tests/ui/redundant_guards.rs:135:14 | LL | x if matches!(x, Some(0)) => .., | ^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + Some(0) => .., | error: redundant guard - --> tests/ui/redundant_guards.rs:132:14 + --> tests/ui/redundant_guards.rs:143:14 | LL | i if i == -1 => {}, | ^^^^^^^ @@ -145,7 +145,7 @@ LL + -1 => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:133:14 + --> tests/ui/redundant_guards.rs:145:14 | LL | i if i == 1 => {}, | ^^^^^^ @@ -157,7 +157,7 @@ LL + 1 => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:195:28 + --> tests/ui/redundant_guards.rs:208:28 | LL | Some(ref x) if x == &1 => {}, | ^^^^^^^ @@ -169,7 +169,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:196:28 + --> tests/ui/redundant_guards.rs:210:28 | LL | Some(ref x) if &1 == x => {}, | ^^^^^^^ @@ -181,7 +181,7 @@ LL + Some(1) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:197:28 + --> tests/ui/redundant_guards.rs:212:28 | LL | Some(ref x) if let &2 = x => {}, | ^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + Some(2) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:198:28 + --> tests/ui/redundant_guards.rs:214:28 | LL | Some(ref x) if matches!(x, &3) => {}, | ^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + Some(3) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:218:32 + --> tests/ui/redundant_guards.rs:235:32 | LL | B { ref c, .. } if c == &1 => {}, | ^^^^^^^ @@ -217,7 +217,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:219:32 + --> tests/ui/redundant_guards.rs:237:32 | LL | B { ref c, .. } if &1 == c => {}, | ^^^^^^^ @@ -229,7 +229,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:220:32 + --> tests/ui/redundant_guards.rs:239:32 | LL | B { ref c, .. } if let &1 = c => {}, | ^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:221:32 + --> tests/ui/redundant_guards.rs:241:32 | LL | B { ref c, .. } if matches!(c, &1) => {}, | ^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL + B { c: 1, .. } => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:231:26 + --> tests/ui/redundant_guards.rs:252:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL + Some(Some("")) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:242:26 + --> tests/ui/redundant_guards.rs:264:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:247:26 + --> tests/ui/redundant_guards.rs:270:26 | LL | Some(Some(x)) if x.is_empty() => {}, | ^^^^^^^^^^^^ @@ -289,7 +289,7 @@ LL + Some(Some([])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:258:26 + --> tests/ui/redundant_guards.rs:282:26 | LL | Some(Some(x)) if x.starts_with(&[]) => {}, | ^^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL + Some(Some([..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:263:26 + --> tests/ui/redundant_guards.rs:288:26 | LL | Some(Some(x)) if x.starts_with(&[1]) => {}, | ^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + Some(Some([1, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:268:26 + --> tests/ui/redundant_guards.rs:294:26 | LL | Some(Some(x)) if x.starts_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + Some(Some([1, 2, ..])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:273:26 + --> tests/ui/redundant_guards.rs:300:26 | LL | Some(Some(x)) if x.ends_with(&[1, 2]) => {}, | ^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + Some(Some([.., 1, 2])) => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:295:18 + --> tests/ui/redundant_guards.rs:323:18 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + "" => {}, | error: redundant guard - --> tests/ui/redundant_guards.rs:314:22 + --> tests/ui/redundant_guards.rs:342:22 | LL | y if y.is_empty() => {}, | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs index 3e7695106a7f1..b66532dd22eec 100644 --- a/src/tools/clippy/tests/ui/redundant_locals.rs +++ b/src/tools/clippy/tests/ui/redundant_locals.rs @@ -11,11 +11,13 @@ fn main() {} fn immutable() { let x = 1; let x = x; + //~^ redundant_locals } fn mutable() { let mut x = 1; let mut x = x; + //~^ redundant_locals } fn upgraded_mutability() { @@ -46,27 +48,35 @@ fn coercion(par: &mut i32) { fn parameter(x: i32) { let x = x; + //~^ redundant_locals } fn many() { let x = 1; let x = x; + //~^ redundant_locals let x = x; + //~^ redundant_locals let x = x; + //~^ redundant_locals let x = x; + //~^ redundant_locals } fn interleaved() { let a = 1; let b = 2; let a = a; + //~^ redundant_locals let b = b; + //~^ redundant_locals } fn block() { { let x = 1; let x = x; + //~^ redundant_locals } } @@ -74,9 +84,11 @@ fn closure() { || { let x = 1; let x = x; + //~^ redundant_locals }; |x: i32| { let x = x; + //~^ redundant_locals }; } @@ -96,6 +108,7 @@ fn inconsequential_drop_order() { { let x = x; + //~^ redundant_locals } } @@ -151,6 +164,7 @@ fn without_drop() { let a = WithoutDrop(1); let b = WithoutDrop(2); let a = a; + //~^ redundant_locals } fn drop_inner() { diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr index 541b988eefe98..ae3631cdf15f1 100644 --- a/src/tools/clippy/tests/ui/redundant_locals.stderr +++ b/src/tools/clippy/tests/ui/redundant_locals.stderr @@ -13,157 +13,157 @@ LL | let x = 1; = help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]` error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:18:5 + --> tests/ui/redundant_locals.rs:19:5 | LL | let mut x = x; | ^^^^^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:17:9 + --> tests/ui/redundant_locals.rs:18:9 | LL | let mut x = 1; | ^^^^^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:48:5 + --> tests/ui/redundant_locals.rs:50:5 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:47:14 + --> tests/ui/redundant_locals.rs:49:14 | LL | fn parameter(x: i32) { | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:53:5 + --> tests/ui/redundant_locals.rs:56:5 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:52:9 + --> tests/ui/redundant_locals.rs:55:9 | LL | let x = 1; | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:54:5 + --> tests/ui/redundant_locals.rs:58:5 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:53:9 + --> tests/ui/redundant_locals.rs:56:9 | LL | let x = x; | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:55:5 + --> tests/ui/redundant_locals.rs:60:5 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:54:9 + --> tests/ui/redundant_locals.rs:58:9 | LL | let x = x; | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:56:5 + --> tests/ui/redundant_locals.rs:62:5 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:55:9 + --> tests/ui/redundant_locals.rs:60:9 | LL | let x = x; | ^ error: redundant redefinition of a binding `a` - --> tests/ui/redundant_locals.rs:62:5 + --> tests/ui/redundant_locals.rs:69:5 | LL | let a = a; | ^^^^^^^^^^ | help: `a` is initially defined here - --> tests/ui/redundant_locals.rs:60:9 + --> tests/ui/redundant_locals.rs:67:9 | LL | let a = 1; | ^ error: redundant redefinition of a binding `b` - --> tests/ui/redundant_locals.rs:63:5 + --> tests/ui/redundant_locals.rs:71:5 | LL | let b = b; | ^^^^^^^^^^ | help: `b` is initially defined here - --> tests/ui/redundant_locals.rs:61:9 + --> tests/ui/redundant_locals.rs:68:9 | LL | let b = 2; | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:69:9 + --> tests/ui/redundant_locals.rs:78:9 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:68:13 + --> tests/ui/redundant_locals.rs:77:13 | LL | let x = 1; | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:76:9 + --> tests/ui/redundant_locals.rs:86:9 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:75:13 + --> tests/ui/redundant_locals.rs:85:13 | LL | let x = 1; | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:79:9 + --> tests/ui/redundant_locals.rs:90:9 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:78:6 + --> tests/ui/redundant_locals.rs:89:6 | LL | |x: i32| { | ^ error: redundant redefinition of a binding `x` - --> tests/ui/redundant_locals.rs:98:9 + --> tests/ui/redundant_locals.rs:110:9 | LL | let x = x; | ^^^^^^^^^^ | help: `x` is initially defined here - --> tests/ui/redundant_locals.rs:95:9 + --> tests/ui/redundant_locals.rs:107:9 | LL | let x = 1; | ^ error: redundant redefinition of a binding `a` - --> tests/ui/redundant_locals.rs:153:5 + --> tests/ui/redundant_locals.rs:166:5 | LL | let a = a; | ^^^^^^^^^^ | help: `a` is initially defined here - --> tests/ui/redundant_locals.rs:151:9 + --> tests/ui/redundant_locals.rs:164:9 | LL | let a = WithoutDrop(1); | ^ diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed index 148eaa4b33a67..1141b5db3ebf4 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed @@ -13,49 +13,71 @@ fn main() { // Result if m.lock().is_ok() {} + //~^ redundant_pattern_matching if Err::<(), _>(m.lock().unwrap().0).is_err() {} + //~^ redundant_pattern_matching { if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() {} + //~^ redundant_pattern_matching } if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() { + //~^ redundant_pattern_matching } else { } if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok() {} + //~^ redundant_pattern_matching if Err::, _>(()).is_err() {} + //~^ redundant_pattern_matching if Ok::<_, ()>(String::new()).is_ok() {} + //~^ redundant_pattern_matching if Err::<(), _>((String::new(), ())).is_err() {} + //~^ redundant_pattern_matching // Option if Some(m.lock()).is_some() {} + //~^ redundant_pattern_matching if Some(m.lock().unwrap().0).is_some() {} + //~^ redundant_pattern_matching { if None::>.is_none() {} + //~^ redundant_pattern_matching } if None::>.is_none() { + //~^ redundant_pattern_matching } else { } if None::>.is_none() {} + //~^ redundant_pattern_matching if Some(String::new()).is_some() {} + //~^ redundant_pattern_matching if Some((String::new(), ())).is_some() {} + //~^ redundant_pattern_matching // Poll if Ready(m.lock()).is_ready() {} + //~^ redundant_pattern_matching if Ready(m.lock().unwrap().0).is_ready() {} + //~^ redundant_pattern_matching { if Pending::>.is_pending() {} + //~^ redundant_pattern_matching } if Pending::>.is_pending() { + //~^ redundant_pattern_matching } else { } if Pending::>.is_pending() {} + //~^ redundant_pattern_matching if Ready(String::new()).is_ready() {} + //~^ redundant_pattern_matching if Ready((String::new(), ())).is_ready() {} + //~^ redundant_pattern_matching } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs index 5bc06f3cc529c..f60ddf4683096 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs @@ -13,49 +13,71 @@ fn main() { // Result if let Ok(_) = m.lock() {} + //~^ redundant_pattern_matching if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} + //~^ redundant_pattern_matching { if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} + //~^ redundant_pattern_matching } if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { + //~^ redundant_pattern_matching } else { } if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} + //~^ redundant_pattern_matching if let Err(_) = Err::, _>(()) {} + //~^ redundant_pattern_matching if let Ok(_) = Ok::<_, ()>(String::new()) {} + //~^ redundant_pattern_matching if let Err(_) = Err::<(), _>((String::new(), ())) {} + //~^ redundant_pattern_matching // Option if let Some(_) = Some(m.lock()) {} + //~^ redundant_pattern_matching if let Some(_) = Some(m.lock().unwrap().0) {} + //~^ redundant_pattern_matching { if let None = None::> {} + //~^ redundant_pattern_matching } if let None = None::> { + //~^ redundant_pattern_matching } else { } if let None = None::> {} + //~^ redundant_pattern_matching if let Some(_) = Some(String::new()) {} + //~^ redundant_pattern_matching if let Some(_) = Some((String::new(), ())) {} + //~^ redundant_pattern_matching // Poll if let Ready(_) = Ready(m.lock()) {} + //~^ redundant_pattern_matching if let Ready(_) = Ready(m.lock().unwrap().0) {} + //~^ redundant_pattern_matching { if let Pending = Pending::> {} + //~^ redundant_pattern_matching } if let Pending = Pending::> { + //~^ redundant_pattern_matching } else { } if let Pending = Pending::> {} + //~^ redundant_pattern_matching if let Ready(_) = Ready(String::new()) {} + //~^ redundant_pattern_matching if let Ready(_) = Ready((String::new(), ())) {} + //~^ redundant_pattern_matching } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr index 1a99cb9fc32b5..74462f022f702 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.stderr @@ -10,7 +10,7 @@ LL | if let Ok(_) = m.lock() {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:16:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:17:12 | LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>(m.lock().unwrap().0).is_err()` @@ -19,7 +19,7 @@ LL | if let Err(_) = Err::<(), _>(m.lock().unwrap().0) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:19:16 + --> tests/ui/redundant_pattern_matching_drop_order.rs:21:16 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` @@ -28,7 +28,7 @@ LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:21:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:24:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` @@ -37,31 +37,31 @@ LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) { = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:24:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:28:12 | LL | if let Ok(_) = Ok::<_, std::sync::MutexGuard<()>>(()) {} | -------^^^^^----------------------------------------- help: try: `if Ok::<_, std::sync::MutexGuard<()>>(()).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:25:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:30:12 | LL | if let Err(_) = Err::, _>(()) {} | -------^^^^^^------------------------------------------ help: try: `if Err::, _>(()).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:27:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:33:12 | LL | if let Ok(_) = Ok::<_, ()>(String::new()) {} | -------^^^^^----------------------------- help: try: `if Ok::<_, ()>(String::new()).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:28:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:35:12 | LL | if let Err(_) = Err::<(), _>((String::new(), ())) {} | -------^^^^^^------------------------------------ help: try: `if Err::<(), _>((String::new(), ())).is_err()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:31:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:39:12 | LL | if let Some(_) = Some(m.lock()) {} | -------^^^^^^^----------------- help: try: `if Some(m.lock()).is_some()` @@ -70,7 +70,7 @@ LL | if let Some(_) = Some(m.lock()) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:32:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:41:12 | LL | if let Some(_) = Some(m.lock().unwrap().0) {} | -------^^^^^^^---------------------------- help: try: `if Some(m.lock().unwrap().0).is_some()` @@ -79,7 +79,7 @@ LL | if let Some(_) = Some(m.lock().unwrap().0) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:35:16 + --> tests/ui/redundant_pattern_matching_drop_order.rs:45:16 | LL | if let None = None::> {} | -------^^^^------------------------------------ help: try: `if None::>.is_none()` @@ -88,7 +88,7 @@ LL | if let None = None::> {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:37:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:48:12 | LL | if let None = None::> { | -------^^^^------------------------------------ help: try: `if None::>.is_none()` @@ -97,25 +97,25 @@ LL | if let None = None::> { = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:41:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:53:12 | LL | if let None = None::> {} | -------^^^^------------------------------------ help: try: `if None::>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:43:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:56:12 | LL | if let Some(_) = Some(String::new()) {} | -------^^^^^^^---------------------- help: try: `if Some(String::new()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:44:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:58:12 | LL | if let Some(_) = Some((String::new(), ())) {} | -------^^^^^^^---------------------------- help: try: `if Some((String::new(), ())).is_some()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:47:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:62:12 | LL | if let Ready(_) = Ready(m.lock()) {} | -------^^^^^^^^------------------ help: try: `if Ready(m.lock()).is_ready()` @@ -124,7 +124,7 @@ LL | if let Ready(_) = Ready(m.lock()) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:48:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:64:12 | LL | if let Ready(_) = Ready(m.lock().unwrap().0) {} | -------^^^^^^^^----------------------------- help: try: `if Ready(m.lock().unwrap().0).is_ready()` @@ -133,7 +133,7 @@ LL | if let Ready(_) = Ready(m.lock().unwrap().0) {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:51:16 + --> tests/ui/redundant_pattern_matching_drop_order.rs:68:16 | LL | if let Pending = Pending::> {} | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` @@ -142,7 +142,7 @@ LL | if let Pending = Pending::> {} = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:53:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:71:12 | LL | if let Pending = Pending::> { | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` @@ -151,19 +151,19 @@ LL | if let Pending = Pending::> { = note: add `#[allow(clippy::redundant_pattern_matching)]` if this is important error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:57:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:76:12 | LL | if let Pending = Pending::> {} | -------^^^^^^^--------------------------------------- help: try: `if Pending::>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:59:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:79:12 | LL | if let Ready(_) = Ready(String::new()) {} | -------^^^^^^^^----------------------- help: try: `if Ready(String::new()).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_drop_order.rs:60:12 + --> tests/ui/redundant_pattern_matching_drop_order.rs:81:12 | LL | if let Ready(_) = Ready((String::new(), ())) {} | -------^^^^^^^^----------------------------- help: try: `if Ready((String::new(), ())).is_ready()` diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed index 6d91067893405..980455da2ee7e 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.fixed @@ -20,18 +20,25 @@ fn main() { let mut k = 5; if k > 1 {} + //~^ redundant_pattern_matching if !(k > 5) {} + //~^ redundant_pattern_matching if k > 1 {} + //~^ redundant_pattern_matching if let (true, true) = (k > 1, k > 2) {} while k > 1 { + //~^ redundant_pattern_matching k += 1; } while condition!() { + //~^ redundant_pattern_matching k += 1; } k > 5; + //~^ redundant_pattern_matching !(k > 5); + //~^ redundant_pattern_matching // Whole loop is from a macro expansion, don't lint: lettrue!(if); lettrue!(while); diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs index a82e673982a38..9cb0fe2e65f63 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.rs @@ -20,18 +20,25 @@ fn main() { let mut k = 5; if let true = k > 1 {} + //~^ redundant_pattern_matching if let false = k > 5 {} + //~^ redundant_pattern_matching if let (true) = k > 1 {} + //~^ redundant_pattern_matching if let (true, true) = (k > 1, k > 2) {} while let true = k > 1 { + //~^ redundant_pattern_matching k += 1; } while let true = condition!() { + //~^ redundant_pattern_matching k += 1; } matches!(k > 5, true); + //~^ redundant_pattern_matching matches!(k > 5, false); + //~^ redundant_pattern_matching // Whole loop is from a macro expansion, don't lint: lettrue!(if); lettrue!(while); diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr index 43d5cd07cec77..db86462706097 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_if_let_true.stderr @@ -8,37 +8,37 @@ LL | if let true = k > 1 {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: using `if let` to pattern match a bool - --> tests/ui/redundant_pattern_matching_if_let_true.rs:23:8 + --> tests/ui/redundant_pattern_matching_if_let_true.rs:24:8 | LL | if let false = k > 5 {} | ^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)` error: using `if let` to pattern match a bool - --> tests/ui/redundant_pattern_matching_if_let_true.rs:24:8 + --> tests/ui/redundant_pattern_matching_if_let_true.rs:26:8 | LL | if let (true) = k > 1 {} | ^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1` error: using `if let` to pattern match a bool - --> tests/ui/redundant_pattern_matching_if_let_true.rs:26:11 + --> tests/ui/redundant_pattern_matching_if_let_true.rs:29:11 | LL | while let true = k > 1 { | ^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 1` error: using `if let` to pattern match a bool - --> tests/ui/redundant_pattern_matching_if_let_true.rs:29:11 + --> tests/ui/redundant_pattern_matching_if_let_true.rs:33:11 | LL | while let true = condition!() { | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `condition!()` error: using `matches!` to pattern match a bool - --> tests/ui/redundant_pattern_matching_if_let_true.rs:33:5 + --> tests/ui/redundant_pattern_matching_if_let_true.rs:38:5 | LL | matches!(k > 5, true); | ^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `k > 5` error: using `matches!` to pattern match a bool - --> tests/ui/redundant_pattern_matching_if_let_true.rs:34:5 + --> tests/ui/redundant_pattern_matching_if_let_true.rs:40:5 | LL | matches!(k > 5, false); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using the condition directly: `!(k > 5)` diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed index 429d33118a58f..549c97d9534ad 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -13,20 +13,27 @@ use std::net::{Ipv4Addr, Ipv6Addr}; fn main() { let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); if ipaddr.is_ipv4() {} + //~^ redundant_pattern_matching if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + //~^ redundant_pattern_matching if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + //~^ redundant_pattern_matching // Issue 6459 if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + //~^ redundant_pattern_matching // Issue 6459 if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + //~^ redundant_pattern_matching while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + //~^ redundant_pattern_matching while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + //~^ redundant_pattern_matching if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} @@ -45,6 +52,7 @@ fn main() { V6(Ipv6Addr::LOCALHOST).is_ipv4(); let _ = if V4(Ipv4Addr::LOCALHOST).is_ipv4() { + //~^ redundant_pattern_matching true } else { false @@ -53,8 +61,10 @@ fn main() { ipaddr_const(); let _ = if gen_ipaddr().is_ipv4() { + //~^ redundant_pattern_matching 1 } else if gen_ipaddr().is_ipv6() { + //~^ redundant_pattern_matching 2 } else { 3 @@ -67,12 +77,16 @@ fn gen_ipaddr() -> IpAddr { const fn ipaddr_const() { if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + //~^ redundant_pattern_matching if V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + //~^ redundant_pattern_matching while V4(Ipv4Addr::LOCALHOST).is_ipv4() {} + //~^ redundant_pattern_matching while V6(Ipv6Addr::LOCALHOST).is_ipv6() {} + //~^ redundant_pattern_matching V4(Ipv4Addr::LOCALHOST).is_ipv4(); diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs index e7136b72c20c8..decb1396d56dd 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -13,20 +13,27 @@ use std::net::{Ipv4Addr, Ipv6Addr}; fn main() { let ipaddr: IpAddr = V4(Ipv4Addr::LOCALHOST); if let V4(_) = &ipaddr {} + //~^ redundant_pattern_matching if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + //~^ redundant_pattern_matching if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + //~^ redundant_pattern_matching // Issue 6459 if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {} + //~^ redundant_pattern_matching // Issue 6459 if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {} + //~^ redundant_pattern_matching while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + //~^ redundant_pattern_matching while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + //~^ redundant_pattern_matching if V4(Ipv4Addr::LOCALHOST).is_ipv4() {} @@ -37,26 +44,31 @@ fn main() { } match V4(Ipv4Addr::LOCALHOST) { + //~^ redundant_pattern_matching V4(_) => true, V6(_) => false, }; match V4(Ipv4Addr::LOCALHOST) { + //~^ redundant_pattern_matching V4(_) => false, V6(_) => true, }; match V6(Ipv6Addr::LOCALHOST) { + //~^ redundant_pattern_matching V4(_) => false, V6(_) => true, }; match V6(Ipv6Addr::LOCALHOST) { + //~^ redundant_pattern_matching V4(_) => true, V6(_) => false, }; let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { + //~^ redundant_pattern_matching true } else { false @@ -65,8 +77,10 @@ fn main() { ipaddr_const(); let _ = if let V4(_) = gen_ipaddr() { + //~^ redundant_pattern_matching 1 } else if let V6(_) = gen_ipaddr() { + //~^ redundant_pattern_matching 2 } else { 3 @@ -79,19 +93,25 @@ fn gen_ipaddr() -> IpAddr { const fn ipaddr_const() { if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + //~^ redundant_pattern_matching if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + //~^ redundant_pattern_matching while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} + //~^ redundant_pattern_matching while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} + //~^ redundant_pattern_matching match V4(Ipv4Addr::LOCALHOST) { + //~^ redundant_pattern_matching V4(_) => true, V6(_) => false, }; match V6(Ipv6Addr::LOCALHOST) { + //~^ redundant_pattern_matching V4(_) => false, V6(_) => true, }; diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr index a4930ad839f91..66d2cecdc0c91 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr @@ -8,132 +8,138 @@ LL | if let V4(_) = &ipaddr {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:17:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:18:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:19:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:21:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:22:8 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:25:8 | LL | if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:25:8 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:29:8 | LL | if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:27:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:32:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:29:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:35:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:39:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:46:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:44:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:52:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:49:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:58:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:54:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:64:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; | |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:59:20 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:70:20 | LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) { | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:67:20 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:79:20 | LL | let _ = if let V4(_) = gen_ipaddr() { | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:69:19 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:82:19 | LL | } else if let V6(_) = gen_ipaddr() { | -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:81:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:95:12 | LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:83:12 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:98:12 | LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:85:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:101:15 | LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:87:15 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:104:15 | LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {} | ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()` error: redundant pattern matching, consider using `is_ipv4()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:89:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:107:5 | LL | / match V4(Ipv4Addr::LOCALHOST) { +LL | | LL | | V4(_) => true, LL | | V6(_) => false, LL | | }; | |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()` error: redundant pattern matching, consider using `is_ipv6()` - --> tests/ui/redundant_pattern_matching_ipaddr.rs:94:5 + --> tests/ui/redundant_pattern_matching_ipaddr.rs:113:5 | LL | / match V6(Ipv6Addr::LOCALHOST) { +LL | | LL | | V4(_) => false, LL | | V6(_) => true, LL | | }; diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed index c7e0cd2610f0e..5585006dc362b 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed @@ -12,10 +12,13 @@ fn issue_11174(boolean: bool, maybe_some: Option) -> bool { maybe_some.is_none() && (!boolean) + //~^ redundant_pattern_matching } fn issue_11174_edge_cases(boolean: bool, boolean2: bool, maybe_some: Option) { let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses + // + //~^^ redundant_pattern_matching let _ = match maybe_some { // can't use `matches!` here // because `expr` metavars in macros don't allow let exprs @@ -30,23 +33,30 @@ fn issue_11174_edge_cases(boolean: bool, boolean2: bool, maybe_some: Option.is_none() {} + //~^ redundant_pattern_matching if Some(42).is_some() {} + //~^ redundant_pattern_matching if Some(42).is_some() { + //~^ redundant_pattern_matching foo(); } else { bar(); } while Some(42).is_some() {} + //~^ redundant_pattern_matching while Some(42).is_none() {} + //~^ redundant_pattern_matching while None::<()>.is_none() {} + //~^ redundant_pattern_matching let mut v = vec![1, 2, 3]; while v.pop().is_some() { + //~^ redundant_pattern_matching foo(); } @@ -62,20 +72,24 @@ fn main() { let opt = Some(false); let _ = if opt.is_some() { true } else { false }; + //~^ redundant_pattern_matching issue6067(); issue10726(); issue10803(); let _ = if gen_opt().is_some() { + //~^ redundant_pattern_matching 1 } else if gen_opt().is_none() { + //~^ redundant_pattern_matching 2 } else { 3 }; if gen_opt().is_some() {} + //~^ redundant_pattern_matching } fn gen_opt() -> Option<()> { @@ -91,12 +105,16 @@ fn bar() {} // so the following should be linted. const fn issue6067() { if Some(42).is_some() {} + //~^ redundant_pattern_matching if None::<()>.is_none() {} + //~^ redundant_pattern_matching while Some(42).is_some() {} + //~^ redundant_pattern_matching while None::<()>.is_none() {} + //~^ redundant_pattern_matching Some(42).is_some(); @@ -106,7 +124,9 @@ const fn issue6067() { #[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)] fn issue7921() { if (&None::<()>).is_none() {} + //~^ redundant_pattern_matching if (&None::<()>).is_none() {} + //~^ redundant_pattern_matching } fn issue10726() { @@ -131,8 +151,10 @@ fn issue10803() { let x = Some(42); let _ = x.is_some(); + //~^ redundant_pattern_matching let _ = x.is_none(); + //~^ redundant_pattern_matching // Don't lint let _ = matches!(x, Some(16)); @@ -143,5 +165,6 @@ fn issue13902() { let p = &raw const x; unsafe { let _ = (*p).is_none(); + //~^ redundant_pattern_matching } } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs index 6d9a9f7f9428b..581a432f38e11 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs @@ -12,10 +12,13 @@ fn issue_11174(boolean: bool, maybe_some: Option) -> bool { matches!(maybe_some, None if !boolean) + //~^ redundant_pattern_matching } fn issue_11174_edge_cases(boolean: bool, boolean2: bool, maybe_some: Option) { let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses + // + //~^^ redundant_pattern_matching let _ = match maybe_some { // can't use `matches!` here // because `expr` metavars in macros don't allow let exprs @@ -30,23 +33,30 @@ fn issue_11174_edge_cases(boolean: bool, boolean2: bool, maybe_some: Option {} + //~^ redundant_pattern_matching if let Some(_) = Some(42) {} + //~^ redundant_pattern_matching if let Some(_) = Some(42) { + //~^ redundant_pattern_matching foo(); } else { bar(); } while let Some(_) = Some(42) {} + //~^ redundant_pattern_matching while let None = Some(42) {} + //~^ redundant_pattern_matching while let None = None::<()> {} + //~^ redundant_pattern_matching let mut v = vec![1, 2, 3]; while let Some(_) = v.pop() { + //~^ redundant_pattern_matching foo(); } @@ -55,36 +65,43 @@ fn main() { if Some(42).is_some() {} match Some(42) { + //~^ redundant_pattern_matching Some(_) => true, None => false, }; match None::<()> { + //~^ redundant_pattern_matching Some(_) => false, None => true, }; let _ = match None::<()> { + //~^ redundant_pattern_matching Some(_) => false, None => true, }; let opt = Some(false); let _ = if let Some(_) = opt { true } else { false }; + //~^ redundant_pattern_matching issue6067(); issue10726(); issue10803(); let _ = if let Some(_) = gen_opt() { + //~^ redundant_pattern_matching 1 } else if let None = gen_opt() { + //~^ redundant_pattern_matching 2 } else { 3 }; if let Some(..) = gen_opt() {} + //~^ redundant_pattern_matching } fn gen_opt() -> Option<()> { @@ -100,19 +117,25 @@ fn bar() {} // so the following should be linted. const fn issue6067() { if let Some(_) = Some(42) {} + //~^ redundant_pattern_matching if let None = None::<()> {} + //~^ redundant_pattern_matching while let Some(_) = Some(42) {} + //~^ redundant_pattern_matching while let None = None::<()> {} + //~^ redundant_pattern_matching match Some(42) { + //~^ redundant_pattern_matching Some(_) => true, None => false, }; match None::<()> { + //~^ redundant_pattern_matching Some(_) => false, None => true, }; @@ -121,28 +144,34 @@ const fn issue6067() { #[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)] fn issue7921() { if let None = *(&None::<()>) {} + //~^ redundant_pattern_matching if let None = *&None::<()> {} + //~^ redundant_pattern_matching } fn issue10726() { let x = Some(42); match x { + //~^ redundant_pattern_matching Some(_) => true, _ => false, }; match x { + //~^ redundant_pattern_matching None => true, _ => false, }; match x { + //~^ redundant_pattern_matching Some(_) => false, _ => true, }; match x { + //~^ redundant_pattern_matching None => false, _ => true, }; @@ -158,8 +187,10 @@ fn issue10803() { let x = Some(42); let _ = matches!(x, Some(_)); + //~^ redundant_pattern_matching let _ = matches!(x, None); + //~^ redundant_pattern_matching // Don't lint let _ = matches!(x, Some(16)); @@ -170,5 +201,6 @@ fn issue13902() { let p = &raw const x; unsafe { let _ = matches!(*p, None); + //~^ redundant_pattern_matching } } diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr index 34d80f5ca7820..681602567d2f2 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr @@ -8,209 +8,218 @@ LL | matches!(maybe_some, None if !boolean) = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:18:13 + --> tests/ui/redundant_pattern_matching_option.rs:19:13 | LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:32:12 + --> tests/ui/redundant_pattern_matching_option.rs:35:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:34:12 + --> tests/ui/redundant_pattern_matching_option.rs:38:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:36:12 + --> tests/ui/redundant_pattern_matching_option.rs:41:12 | LL | if let Some(_) = Some(42) { | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:42:15 + --> tests/ui/redundant_pattern_matching_option.rs:48:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:44:15 + --> tests/ui/redundant_pattern_matching_option.rs:51:15 | LL | while let None = Some(42) {} | ----------^^^^----------- help: try: `while Some(42).is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:46:15 + --> tests/ui/redundant_pattern_matching_option.rs:54:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:49:15 + --> tests/ui/redundant_pattern_matching_option.rs:58:15 | LL | while let Some(_) = v.pop() { | ----------^^^^^^^---------- help: try: `while v.pop().is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:57:5 + --> tests/ui/redundant_pattern_matching_option.rs:67:5 | LL | / match Some(42) { +LL | | LL | | Some(_) => true, LL | | None => false, LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:62:5 + --> tests/ui/redundant_pattern_matching_option.rs:73:5 | LL | / match None::<()> { +LL | | LL | | Some(_) => false, LL | | None => true, LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:67:13 + --> tests/ui/redundant_pattern_matching_option.rs:79:13 | LL | let _ = match None::<()> { | _____________^ +LL | | LL | | Some(_) => false, LL | | None => true, LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:73:20 + --> tests/ui/redundant_pattern_matching_option.rs:86:20 | LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:79:20 + --> tests/ui/redundant_pattern_matching_option.rs:93:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:81:19 + --> tests/ui/redundant_pattern_matching_option.rs:96:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:87:12 + --> tests/ui/redundant_pattern_matching_option.rs:103:12 | LL | if let Some(..) = gen_opt() {} | -------^^^^^^^^------------ help: try: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:102:12 + --> tests/ui/redundant_pattern_matching_option.rs:119:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:104:12 + --> tests/ui/redundant_pattern_matching_option.rs:122:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:106:15 + --> tests/ui/redundant_pattern_matching_option.rs:125:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:108:15 + --> tests/ui/redundant_pattern_matching_option.rs:128:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:110:5 + --> tests/ui/redundant_pattern_matching_option.rs:131:5 | LL | / match Some(42) { +LL | | LL | | Some(_) => true, LL | | None => false, LL | | }; | |_____^ help: try: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:115:5 + --> tests/ui/redundant_pattern_matching_option.rs:137:5 | LL | / match None::<()> { +LL | | LL | | Some(_) => false, LL | | None => true, LL | | }; | |_____^ help: try: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:123:12 + --> tests/ui/redundant_pattern_matching_option.rs:146:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:124:12 + --> tests/ui/redundant_pattern_matching_option.rs:148:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:130:5 + --> tests/ui/redundant_pattern_matching_option.rs:155:5 | LL | / match x { +LL | | LL | | Some(_) => true, LL | | _ => false, LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:135:5 + --> tests/ui/redundant_pattern_matching_option.rs:161:5 | LL | / match x { +LL | | LL | | None => true, LL | | _ => false, LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:140:5 + --> tests/ui/redundant_pattern_matching_option.rs:167:5 | LL | / match x { +LL | | LL | | Some(_) => false, LL | | _ => true, LL | | }; | |_____^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:145:5 + --> tests/ui/redundant_pattern_matching_option.rs:173:5 | LL | / match x { +LL | | LL | | None => false, LL | | _ => true, LL | | }; | |_____^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_option.rs:160:13 + --> tests/ui/redundant_pattern_matching_option.rs:189:13 | LL | let _ = matches!(x, Some(_)); | ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:162:13 + --> tests/ui/redundant_pattern_matching_option.rs:192:13 | LL | let _ = matches!(x, None); | ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/redundant_pattern_matching_option.rs:172:17 + --> tests/ui/redundant_pattern_matching_option.rs:203:17 | LL | let _ = matches!(*p, None); | ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()` diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed index 08d83f87e4c39..c8e18e8676f21 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed @@ -13,10 +13,13 @@ use std::task::Poll::{self, Pending, Ready}; fn main() { if Pending::<()>.is_pending() {} + //~^ redundant_pattern_matching if Ready(42).is_ready() {} + //~^ redundant_pattern_matching if Ready(42).is_ready() { + //~^ redundant_pattern_matching foo(); } else { bar(); @@ -24,15 +27,20 @@ fn main() { // Issue 6459 if Ready(42).is_ready() {} + //~^ redundant_pattern_matching // Issue 6459 if Pending::<()>.is_pending() {} + //~^ redundant_pattern_matching while Ready(42).is_ready() {} + //~^ redundant_pattern_matching while Ready(42).is_pending() {} + //~^ redundant_pattern_matching while Pending::<()>.is_pending() {} + //~^ redundant_pattern_matching if Pending::.is_pending() {} @@ -46,12 +54,15 @@ fn main() { let poll = Ready(false); let _ = if poll.is_ready() { true } else { false }; + //~^ redundant_pattern_matching poll_const(); let _ = if gen_poll().is_ready() { + //~^ redundant_pattern_matching 1 } else if gen_poll().is_pending() { + //~^ redundant_pattern_matching 2 } else { 3 @@ -68,12 +79,16 @@ fn bar() {} const fn poll_const() { if Ready(42).is_ready() {} + //~^ redundant_pattern_matching if Pending::<()>.is_pending() {} + //~^ redundant_pattern_matching while Ready(42).is_ready() {} + //~^ redundant_pattern_matching while Pending::<()>.is_pending() {} + //~^ redundant_pattern_matching Ready(42).is_ready(); diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs index 7bc2b3be4d346..727503d21a54a 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs @@ -13,10 +13,13 @@ use std::task::Poll::{self, Pending, Ready}; fn main() { if let Pending = Pending::<()> {} + //~^ redundant_pattern_matching if let Ready(_) = Ready(42) {} + //~^ redundant_pattern_matching if let Ready(_) = Ready(42) { + //~^ redundant_pattern_matching foo(); } else { bar(); @@ -24,43 +27,54 @@ fn main() { // Issue 6459 if matches!(Ready(42), Ready(_)) {} + //~^ redundant_pattern_matching // Issue 6459 if matches!(Pending::<()>, Pending) {} + //~^ redundant_pattern_matching while let Ready(_) = Ready(42) {} + //~^ redundant_pattern_matching while let Pending = Ready(42) {} + //~^ redundant_pattern_matching while let Pending = Pending::<()> {} + //~^ redundant_pattern_matching if Pending::.is_pending() {} if Ready(42).is_ready() {} match Ready(42) { + //~^ redundant_pattern_matching Ready(_) => true, Pending => false, }; match Pending::<()> { + //~^ redundant_pattern_matching Ready(_) => false, Pending => true, }; let _ = match Pending::<()> { + //~^ redundant_pattern_matching Ready(_) => false, Pending => true, }; let poll = Ready(false); let _ = if let Ready(_) = poll { true } else { false }; + //~^ redundant_pattern_matching poll_const(); let _ = if let Ready(_) = gen_poll() { + //~^ redundant_pattern_matching 1 } else if let Pending = gen_poll() { + //~^ redundant_pattern_matching 2 } else { 3 @@ -77,19 +91,25 @@ fn bar() {} const fn poll_const() { if let Ready(_) = Ready(42) {} + //~^ redundant_pattern_matching if let Pending = Pending::<()> {} + //~^ redundant_pattern_matching while let Ready(_) = Ready(42) {} + //~^ redundant_pattern_matching while let Pending = Pending::<()> {} + //~^ redundant_pattern_matching match Ready(42) { + //~^ redundant_pattern_matching Ready(_) => true, Pending => false, }; match Pending::<()> { + //~^ redundant_pattern_matching Ready(_) => false, Pending => true, }; diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr index 2b0f087fb9939..5f659184f7b38 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr @@ -8,130 +8,135 @@ LL | if let Pending = Pending::<()> {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:17:12 + --> tests/ui/redundant_pattern_matching_poll.rs:18:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:19:12 + --> tests/ui/redundant_pattern_matching_poll.rs:21:12 | LL | if let Ready(_) = Ready(42) { | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:26:8 + --> tests/ui/redundant_pattern_matching_poll.rs:29:8 | LL | if matches!(Ready(42), Ready(_)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:29:8 + --> tests/ui/redundant_pattern_matching_poll.rs:33:8 | LL | if matches!(Pending::<()>, Pending) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:31:15 + --> tests/ui/redundant_pattern_matching_poll.rs:36:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:33:15 + --> tests/ui/redundant_pattern_matching_poll.rs:39:15 | LL | while let Pending = Ready(42) {} | ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:35:15 + --> tests/ui/redundant_pattern_matching_poll.rs:42:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:41:5 + --> tests/ui/redundant_pattern_matching_poll.rs:49:5 | LL | / match Ready(42) { +LL | | LL | | Ready(_) => true, LL | | Pending => false, LL | | }; | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:46:5 + --> tests/ui/redundant_pattern_matching_poll.rs:55:5 | LL | / match Pending::<()> { +LL | | LL | | Ready(_) => false, LL | | Pending => true, LL | | }; | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:51:13 + --> tests/ui/redundant_pattern_matching_poll.rs:61:13 | LL | let _ = match Pending::<()> { | _____________^ +LL | | LL | | Ready(_) => false, LL | | Pending => true, LL | | }; | |_____^ help: try: `Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:57:20 + --> tests/ui/redundant_pattern_matching_poll.rs:68:20 | LL | let _ = if let Ready(_) = poll { true } else { false }; | -------^^^^^^^^------- help: try: `if poll.is_ready()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:61:20 + --> tests/ui/redundant_pattern_matching_poll.rs:73:20 | LL | let _ = if let Ready(_) = gen_poll() { | -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:63:19 + --> tests/ui/redundant_pattern_matching_poll.rs:76:19 | LL | } else if let Pending = gen_poll() { | -------^^^^^^^------------- help: try: `if gen_poll().is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:79:12 + --> tests/ui/redundant_pattern_matching_poll.rs:93:12 | LL | if let Ready(_) = Ready(42) {} | -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:81:12 + --> tests/ui/redundant_pattern_matching_poll.rs:96:12 | LL | if let Pending = Pending::<()> {} | -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:83:15 + --> tests/ui/redundant_pattern_matching_poll.rs:99:15 | LL | while let Ready(_) = Ready(42) {} | ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:85:15 + --> tests/ui/redundant_pattern_matching_poll.rs:102:15 | LL | while let Pending = Pending::<()> {} | ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()` error: redundant pattern matching, consider using `is_ready()` - --> tests/ui/redundant_pattern_matching_poll.rs:87:5 + --> tests/ui/redundant_pattern_matching_poll.rs:105:5 | LL | / match Ready(42) { +LL | | LL | | Ready(_) => true, LL | | Pending => false, LL | | }; | |_____^ help: try: `Ready(42).is_ready()` error: redundant pattern matching, consider using `is_pending()` - --> tests/ui/redundant_pattern_matching_poll.rs:92:5 + --> tests/ui/redundant_pattern_matching_poll.rs:111:5 | LL | / match Pending::<()> { +LL | | LL | | Ready(_) => false, LL | | Pending => true, LL | | }; diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed index 9571aaee74248..1158796083147 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed @@ -13,14 +13,19 @@ fn main() { let result: Result = Err(5); if result.is_ok() {} + //~^ redundant_pattern_matching if Ok::(42).is_ok() {} + //~^ redundant_pattern_matching if Err::(42).is_err() {} + //~^ redundant_pattern_matching while Ok::(10).is_ok() {} + //~^ redundant_pattern_matching while Ok::(10).is_err() {} + //~^ redundant_pattern_matching if Ok::(42).is_ok() {} @@ -39,6 +44,7 @@ fn main() { Err::(42).is_ok(); let _ = if Ok::(4).is_ok() { true } else { false }; + //~^ redundant_pattern_matching issue5504(); issue6067(); @@ -47,8 +53,10 @@ fn main() { issue10803(); let _ = if gen_res().is_ok() { + //~^ redundant_pattern_matching 1 } else if gen_res().is_err() { + //~^ redundant_pattern_matching 2 } else { 3 @@ -72,14 +80,18 @@ fn issue5504() { fn try_result_opt() -> Result { while r#try!(result_opt()).is_some() {} + //~^ redundant_pattern_matching if r#try!(result_opt()).is_some() {} + //~^ redundant_pattern_matching Ok(42) } try_result_opt(); if m!().is_some() {} + //~^ redundant_pattern_matching while m!().is_some() {} + //~^ redundant_pattern_matching } fn issue6065() { @@ -98,12 +110,16 @@ fn issue6065() { // so the following should be linted. const fn issue6067() { if Ok::(42).is_ok() {} + //~^ redundant_pattern_matching if Err::(42).is_err() {} + //~^ redundant_pattern_matching while Ok::(10).is_ok() {} + //~^ redundant_pattern_matching while Ok::(10).is_err() {} + //~^ redundant_pattern_matching Ok::(42).is_ok(); @@ -139,8 +155,10 @@ fn issue10803() { let x: Result = Ok(42); let _ = x.is_ok(); + //~^ redundant_pattern_matching let _ = x.is_err(); + //~^ redundant_pattern_matching // Don't lint let _ = matches!(x, Ok(16)); diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs index 4fc65aa70b54a..35f8f91b31527 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs @@ -13,14 +13,19 @@ fn main() { let result: Result = Err(5); if let Ok(_) = &result {} + //~^ redundant_pattern_matching if let Ok(_) = Ok::(42) {} + //~^ redundant_pattern_matching if let Err(_) = Err::(42) {} + //~^ redundant_pattern_matching while let Ok(_) = Ok::(10) {} + //~^ redundant_pattern_matching while let Err(_) = Ok::(10) {} + //~^ redundant_pattern_matching if Ok::(42).is_ok() {} @@ -31,26 +36,31 @@ fn main() { } match Ok::(42) { + //~^ redundant_pattern_matching Ok(_) => true, Err(_) => false, }; match Ok::(42) { + //~^ redundant_pattern_matching Ok(_) => false, Err(_) => true, }; match Err::(42) { + //~^ redundant_pattern_matching Ok(_) => false, Err(_) => true, }; match Err::(42) { + //~^ redundant_pattern_matching Ok(_) => true, Err(_) => false, }; let _ = if let Ok(_) = Ok::(4) { true } else { false }; + //~^ redundant_pattern_matching issue5504(); issue6067(); @@ -59,8 +69,10 @@ fn main() { issue10803(); let _ = if let Ok(_) = gen_res() { + //~^ redundant_pattern_matching 1 } else if let Err(_) = gen_res() { + //~^ redundant_pattern_matching 2 } else { 3 @@ -84,14 +96,18 @@ fn issue5504() { fn try_result_opt() -> Result { while let Some(_) = r#try!(result_opt()) {} + //~^ redundant_pattern_matching if let Some(_) = r#try!(result_opt()) {} + //~^ redundant_pattern_matching Ok(42) } try_result_opt(); if let Some(_) = m!() {} + //~^ redundant_pattern_matching while let Some(_) = m!() {} + //~^ redundant_pattern_matching } fn issue6065() { @@ -110,19 +126,25 @@ fn issue6065() { // so the following should be linted. const fn issue6067() { if let Ok(_) = Ok::(42) {} + //~^ redundant_pattern_matching if let Err(_) = Err::(42) {} + //~^ redundant_pattern_matching while let Ok(_) = Ok::(10) {} + //~^ redundant_pattern_matching while let Err(_) = Ok::(10) {} + //~^ redundant_pattern_matching match Ok::(42) { + //~^ redundant_pattern_matching Ok(_) => true, Err(_) => false, }; match Err::(42) { + //~^ redundant_pattern_matching Ok(_) => false, Err(_) => true, }; @@ -133,21 +155,25 @@ fn issue10726() { let x: Result = Ok(42); match x { + //~^ redundant_pattern_matching Ok(_) => true, _ => false, }; match x { + //~^ redundant_pattern_matching Ok(_) => false, _ => true, }; match x { + //~^ redundant_pattern_matching Err(_) => true, _ => false, }; match x { + //~^ redundant_pattern_matching Err(_) => false, _ => true, }; @@ -169,8 +195,10 @@ fn issue10803() { let x: Result = Ok(42); let _ = matches!(x, Ok(_)); + //~^ redundant_pattern_matching let _ = matches!(x, Err(_)); + //~^ redundant_pattern_matching // Don't lint let _ = matches!(x, Ok(16)); diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr index 991e6225ecb6d..4f78b95356c21 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr @@ -8,193 +8,203 @@ LL | if let Ok(_) = &result {} = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:17:12 + --> tests/ui/redundant_pattern_matching_result.rs:18:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:19:12 + --> tests/ui/redundant_pattern_matching_result.rs:21:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:21:15 + --> tests/ui/redundant_pattern_matching_result.rs:24:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:23:15 + --> tests/ui/redundant_pattern_matching_result.rs:27:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:33:5 + --> tests/ui/redundant_pattern_matching_result.rs:38:5 | LL | / match Ok::(42) { +LL | | LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:38:5 + --> tests/ui/redundant_pattern_matching_result.rs:44:5 | LL | / match Ok::(42) { +LL | | LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; | |_____^ help: try: `Ok::(42).is_err()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:43:5 + --> tests/ui/redundant_pattern_matching_result.rs:50:5 | LL | / match Err::(42) { +LL | | LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:48:5 + --> tests/ui/redundant_pattern_matching_result.rs:56:5 | LL | / match Err::(42) { +LL | | LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; | |_____^ help: try: `Err::(42).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:53:20 + --> tests/ui/redundant_pattern_matching_result.rs:62:20 | LL | let _ = if let Ok(_) = Ok::(4) { true } else { false }; | -------^^^^^--------------------- help: try: `if Ok::(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:61:20 + --> tests/ui/redundant_pattern_matching_result.rs:71:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:63:19 + --> tests/ui/redundant_pattern_matching_result.rs:74:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:86:19 + --> tests/ui/redundant_pattern_matching_result.rs:98:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:87:16 + --> tests/ui/redundant_pattern_matching_result.rs:100:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:93:12 + --> tests/ui/redundant_pattern_matching_result.rs:107:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> tests/ui/redundant_pattern_matching_result.rs:94:15 + --> tests/ui/redundant_pattern_matching_result.rs:109:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:112:12 + --> tests/ui/redundant_pattern_matching_result.rs:128:12 | LL | if let Ok(_) = Ok::(42) {} | -------^^^^^--------------------- help: try: `if Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:114:12 + --> tests/ui/redundant_pattern_matching_result.rs:131:12 | LL | if let Err(_) = Err::(42) {} | -------^^^^^^---------------------- help: try: `if Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:116:15 + --> tests/ui/redundant_pattern_matching_result.rs:134:15 | LL | while let Ok(_) = Ok::(10) {} | ----------^^^^^--------------------- help: try: `while Ok::(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:118:15 + --> tests/ui/redundant_pattern_matching_result.rs:137:15 | LL | while let Err(_) = Ok::(10) {} | ----------^^^^^^--------------------- help: try: `while Ok::(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:120:5 + --> tests/ui/redundant_pattern_matching_result.rs:140:5 | LL | / match Ok::(42) { +LL | | LL | | Ok(_) => true, LL | | Err(_) => false, LL | | }; | |_____^ help: try: `Ok::(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:125:5 + --> tests/ui/redundant_pattern_matching_result.rs:146:5 | LL | / match Err::(42) { +LL | | LL | | Ok(_) => false, LL | | Err(_) => true, LL | | }; | |_____^ help: try: `Err::(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:135:5 + --> tests/ui/redundant_pattern_matching_result.rs:157:5 | LL | / match x { +LL | | LL | | Ok(_) => true, LL | | _ => false, LL | | }; | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:140:5 + --> tests/ui/redundant_pattern_matching_result.rs:163:5 | LL | / match x { +LL | | LL | | Ok(_) => false, LL | | _ => true, LL | | }; | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:145:5 + --> tests/ui/redundant_pattern_matching_result.rs:169:5 | LL | / match x { +LL | | LL | | Err(_) => true, LL | | _ => false, LL | | }; | |_____^ help: try: `x.is_err()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:150:5 + --> tests/ui/redundant_pattern_matching_result.rs:175:5 | LL | / match x { +LL | | LL | | Err(_) => false, LL | | _ => true, LL | | }; | |_____^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> tests/ui/redundant_pattern_matching_result.rs:171:13 + --> tests/ui/redundant_pattern_matching_result.rs:197:13 | LL | let _ = matches!(x, Ok(_)); | ^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok()` error: redundant pattern matching, consider using `is_err()` - --> tests/ui/redundant_pattern_matching_result.rs:173:13 + --> tests/ui/redundant_pattern_matching_result.rs:200:13 | LL | let _ = matches!(x, Err(_)); | ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()` diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed index 8882a4d50a5f8..a6450123f4c9d 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed @@ -5,24 +5,33 @@ mod m1 { fn f() {} pub fn g() {} // private due to m1 + // + //~^^ redundant_pub_crate pub fn h() {} mod m1_1 { fn f() {} pub fn g() {} // private due to m1_1 and m1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub mod m1_2 { + //~^ redundant_pub_crate //:^ private due to m1 fn f() {} pub fn g() {} // private due to m1_2 and m1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub mod m1_3 { fn f() {} pub fn g() {} // private due to m1 + // + //~^^ redundant_pub_crate pub fn h() {} } } @@ -30,24 +39,33 @@ mod m1 { pub(crate) mod m2 { fn f() {} pub fn g() {} // already crate visible due to m2 + // + //~^^ redundant_pub_crate pub fn h() {} mod m2_1 { fn f() {} pub fn g() {} // private due to m2_1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub mod m2_2 { + //~^ redundant_pub_crate //:^ already crate visible due to m2 fn f() {} pub fn g() {} // already crate visible due to m2_2 and m2 + // + //~^^ redundant_pub_crate pub fn h() {} } pub mod m2_3 { fn f() {} pub fn g() {} // already crate visible due to m2 + // + //~^^ redundant_pub_crate pub fn h() {} } } @@ -60,6 +78,8 @@ pub mod m3 { mod m3_1 { fn f() {} pub fn g() {} // private due to m3_1 + // + //~^^ redundant_pub_crate pub fn h() {} } @@ -67,6 +87,8 @@ pub mod m3 { //:^ ok fn f() {} pub fn g() {} // already crate visible due to m3_2 + // + //~^^ redundant_pub_crate pub fn h() {} } @@ -80,18 +102,25 @@ pub mod m3 { mod m4 { fn f() {} pub fn g() {} // private: not re-exported by `pub use m4::*` + // + //~^^ redundant_pub_crate pub fn h() {} mod m4_1 { fn f() {} pub fn g() {} // private due to m4_1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub mod m4_2 { + //~^ redundant_pub_crate //:^ private: not re-exported by `pub use m4::*` fn f() {} pub fn g() {} // private due to m4_2 + // + //~^^ redundant_pub_crate pub fn h() {} } diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.rs b/src/tools/clippy/tests/ui/redundant_pub_crate.rs index 5c8cab9be161d..7415d34d50cc7 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.rs +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.rs @@ -5,24 +5,33 @@ mod m1 { fn f() {} pub(crate) fn g() {} // private due to m1 + // + //~^^ redundant_pub_crate pub fn h() {} mod m1_1 { fn f() {} pub(crate) fn g() {} // private due to m1_1 and m1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub(crate) mod m1_2 { + //~^ redundant_pub_crate //:^ private due to m1 fn f() {} pub(crate) fn g() {} // private due to m1_2 and m1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub mod m1_3 { fn f() {} pub(crate) fn g() {} // private due to m1 + // + //~^^ redundant_pub_crate pub fn h() {} } } @@ -30,24 +39,33 @@ mod m1 { pub(crate) mod m2 { fn f() {} pub(crate) fn g() {} // already crate visible due to m2 + // + //~^^ redundant_pub_crate pub fn h() {} mod m2_1 { fn f() {} pub(crate) fn g() {} // private due to m2_1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub(crate) mod m2_2 { + //~^ redundant_pub_crate //:^ already crate visible due to m2 fn f() {} pub(crate) fn g() {} // already crate visible due to m2_2 and m2 + // + //~^^ redundant_pub_crate pub fn h() {} } pub mod m2_3 { fn f() {} pub(crate) fn g() {} // already crate visible due to m2 + // + //~^^ redundant_pub_crate pub fn h() {} } } @@ -60,6 +78,8 @@ pub mod m3 { mod m3_1 { fn f() {} pub(crate) fn g() {} // private due to m3_1 + // + //~^^ redundant_pub_crate pub fn h() {} } @@ -67,6 +87,8 @@ pub mod m3 { //:^ ok fn f() {} pub(crate) fn g() {} // already crate visible due to m3_2 + // + //~^^ redundant_pub_crate pub fn h() {} } @@ -80,18 +102,25 @@ pub mod m3 { mod m4 { fn f() {} pub(crate) fn g() {} // private: not re-exported by `pub use m4::*` + // + //~^^ redundant_pub_crate pub fn h() {} mod m4_1 { fn f() {} pub(crate) fn g() {} // private due to m4_1 + // + //~^^ redundant_pub_crate pub fn h() {} } pub(crate) mod m4_2 { + //~^ redundant_pub_crate //:^ private: not re-exported by `pub use m4::*` fn f() {} pub(crate) fn g() {} // private due to m4_2 + // + //~^^ redundant_pub_crate pub fn h() {} } diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr index 699e19b1abcf1..95909ea8b0663 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr @@ -10,7 +10,7 @@ LL | pub(crate) fn g() {} // private due to m1 = help: to override `-D warnings` add `#[allow(clippy::redundant_pub_crate)]` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:12:9 + --> tests/ui/redundant_pub_crate.rs:14:9 | LL | pub(crate) fn g() {} // private due to m1_1 and m1 | ----------^^^^^ @@ -18,7 +18,7 @@ LL | pub(crate) fn g() {} // private due to m1_1 and m1 | help: consider using: `pub` error: pub(crate) module inside private module - --> tests/ui/redundant_pub_crate.rs:16:5 + --> tests/ui/redundant_pub_crate.rs:20:5 | LL | pub(crate) mod m1_2 { | ----------^^^^^^^^^ @@ -26,7 +26,7 @@ LL | pub(crate) mod m1_2 { | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:19:9 + --> tests/ui/redundant_pub_crate.rs:24:9 | LL | pub(crate) fn g() {} // private due to m1_2 and m1 | ----------^^^^^ @@ -34,7 +34,7 @@ LL | pub(crate) fn g() {} // private due to m1_2 and m1 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:25:9 + --> tests/ui/redundant_pub_crate.rs:32:9 | LL | pub(crate) fn g() {} // private due to m1 | ----------^^^^^ @@ -42,7 +42,7 @@ LL | pub(crate) fn g() {} // private due to m1 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:32:5 + --> tests/ui/redundant_pub_crate.rs:41:5 | LL | pub(crate) fn g() {} // already crate visible due to m2 | ----------^^^^^ @@ -50,7 +50,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:37:9 + --> tests/ui/redundant_pub_crate.rs:48:9 | LL | pub(crate) fn g() {} // private due to m2_1 | ----------^^^^^ @@ -58,7 +58,7 @@ LL | pub(crate) fn g() {} // private due to m2_1 | help: consider using: `pub` error: pub(crate) module inside private module - --> tests/ui/redundant_pub_crate.rs:41:5 + --> tests/ui/redundant_pub_crate.rs:54:5 | LL | pub(crate) mod m2_2 { | ----------^^^^^^^^^ @@ -66,7 +66,7 @@ LL | pub(crate) mod m2_2 { | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:44:9 + --> tests/ui/redundant_pub_crate.rs:58:9 | LL | pub(crate) fn g() {} // already crate visible due to m2_2 and m2 | ----------^^^^^ @@ -74,7 +74,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m2_2 and m2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:50:9 + --> tests/ui/redundant_pub_crate.rs:66:9 | LL | pub(crate) fn g() {} // already crate visible due to m2 | ----------^^^^^ @@ -82,7 +82,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:62:9 + --> tests/ui/redundant_pub_crate.rs:80:9 | LL | pub(crate) fn g() {} // private due to m3_1 | ----------^^^^^ @@ -90,7 +90,7 @@ LL | pub(crate) fn g() {} // private due to m3_1 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:69:9 + --> tests/ui/redundant_pub_crate.rs:89:9 | LL | pub(crate) fn g() {} // already crate visible due to m3_2 | ----------^^^^^ @@ -98,7 +98,7 @@ LL | pub(crate) fn g() {} // already crate visible due to m3_2 | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:82:5 + --> tests/ui/redundant_pub_crate.rs:104:5 | LL | pub(crate) fn g() {} // private: not re-exported by `pub use m4::*` | ----------^^^^^ @@ -106,7 +106,7 @@ LL | pub(crate) fn g() {} // private: not re-exported by `pub use m4::*` | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:87:9 + --> tests/ui/redundant_pub_crate.rs:111:9 | LL | pub(crate) fn g() {} // private due to m4_1 | ----------^^^^^ @@ -114,7 +114,7 @@ LL | pub(crate) fn g() {} // private due to m4_1 | help: consider using: `pub` error: pub(crate) module inside private module - --> tests/ui/redundant_pub_crate.rs:91:5 + --> tests/ui/redundant_pub_crate.rs:117:5 | LL | pub(crate) mod m4_2 { | ----------^^^^^^^^^ @@ -122,7 +122,7 @@ LL | pub(crate) mod m4_2 { | help: consider using: `pub` error: pub(crate) function inside private module - --> tests/ui/redundant_pub_crate.rs:94:9 + --> tests/ui/redundant_pub_crate.rs:121:9 | LL | pub(crate) fn g() {} // private due to m4_2 | ----------^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_slicing.fixed b/src/tools/clippy/tests/ui/redundant_slicing.fixed index a4c035ba8407f..385a5d97cf1ab 100644 --- a/src/tools/clippy/tests/ui/redundant_slicing.fixed +++ b/src/tools/clippy/tests/ui/redundant_slicing.fixed @@ -6,10 +6,14 @@ use std::io::Read; fn main() { let slice: &[u32] = &[0]; let _ = slice; // Redundant slice + // + //~^^ redundant_slicing let v = vec![0]; let _ = &v[..]; // Ok, results in `&[_]` let _ = (&*v); // Outer borrow is redundant + // + //~^^ redundant_slicing static S: &[u8] = &[0, 1, 2]; let _ = &mut &S[..]; // Ok, re-borrows slice @@ -27,6 +31,7 @@ fn main() { }; } let _ = slice; + //~^ redundant_slicing macro_rules! m2 { ($e:expr) => { diff --git a/src/tools/clippy/tests/ui/redundant_slicing.rs b/src/tools/clippy/tests/ui/redundant_slicing.rs index 67fe702acf547..04f181da250dc 100644 --- a/src/tools/clippy/tests/ui/redundant_slicing.rs +++ b/src/tools/clippy/tests/ui/redundant_slicing.rs @@ -6,10 +6,14 @@ use std::io::Read; fn main() { let slice: &[u32] = &[0]; let _ = &slice[..]; // Redundant slice + // + //~^^ redundant_slicing let v = vec![0]; let _ = &v[..]; // Ok, results in `&[_]` let _ = &(&*v)[..]; // Outer borrow is redundant + // + //~^^ redundant_slicing static S: &[u8] = &[0, 1, 2]; let _ = &mut &S[..]; // Ok, re-borrows slice @@ -27,6 +31,7 @@ fn main() { }; } let _ = &m!(slice)[..]; + //~^ redundant_slicing macro_rules! m2 { ($e:expr) => { diff --git a/src/tools/clippy/tests/ui/redundant_slicing.stderr b/src/tools/clippy/tests/ui/redundant_slicing.stderr index 269a597b32267..964111bccf888 100644 --- a/src/tools/clippy/tests/ui/redundant_slicing.stderr +++ b/src/tools/clippy/tests/ui/redundant_slicing.stderr @@ -8,13 +8,13 @@ LL | let _ = &slice[..]; // Redundant slice = help: to override `-D warnings` add `#[allow(clippy::redundant_slicing)]` error: redundant slicing of the whole range - --> tests/ui/redundant_slicing.rs:12:13 + --> tests/ui/redundant_slicing.rs:14:13 | LL | let _ = &(&*v)[..]; // Outer borrow is redundant | ^^^^^^^^^^ help: use the original value instead: `(&*v)` error: redundant slicing of the whole range - --> tests/ui/redundant_slicing.rs:29:13 + --> tests/ui/redundant_slicing.rs:33:13 | LL | let _ = &m!(slice)[..]; | ^^^^^^^^^^^^^^ help: use the original value instead: `slice` diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed index 3d1c78bd12d9e..86c6ca17eb20e 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed @@ -6,40 +6,57 @@ struct Foo; const VAR_ONE: &str = "Test constant #1"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning. const VAR_THREE: &[&str] = &["one", "two"]; // ERROR: Consider removing 'static +//~^ redundant_static_lifetimes const VAR_FOUR: (&str, (&str, &str), &str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static +//~^ redundant_static_lifetimes +//~| redundant_static_lifetimes const VAR_SIX: &u8 = &5; +//~^ redundant_static_lifetimes const VAR_HEIGHT: &Foo = &Foo {}; +//~^ redundant_static_lifetimes const VAR_SLICE: &[u8] = b"Test constant #1"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes const VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes const VAR_ARRAY: &[u8; 1] = b"T"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_ONE: &str = "Test static #1"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning. static STATIC_VAR_THREE: &[&str] = &["one", "two"]; // ERROR: Consider removing 'static +//~^ redundant_static_lifetimes static STATIC_VAR_SIX: &u8 = &5; +//~^ redundant_static_lifetimes static STATIC_VAR_HEIGHT: &Foo = &Foo {}; +//~^ redundant_static_lifetimes static STATIC_VAR_SLICE: &[u8] = b"Test static #3"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_TUPLE: &(u8, u8) = &(1, 2); // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_ARRAY: &[u8; 1] = b"T"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static mut STATIC_MUT_SLICE: &mut [u32] = &mut [0]; +//~^ redundant_static_lifetimes fn main() { let false_positive: &'static str = "test"; @@ -69,4 +86,5 @@ fn msrv_1_16() { #[clippy::msrv = "1.17"] fn msrv_1_17() { static V: &u8 = &17; + //~^ redundant_static_lifetimes } diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs index 5932f14b8d9a9..6fefe6c232d2f 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs @@ -6,40 +6,57 @@ struct Foo; const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes const VAR_TWO: &str = "Test constant #2"; // This line should not raise a warning. const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static +//~^ redundant_static_lifetimes const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static +//~^ redundant_static_lifetimes +//~| redundant_static_lifetimes const VAR_SIX: &'static u8 = &5; +//~^ redundant_static_lifetimes const VAR_HEIGHT: &'static Foo = &Foo {}; +//~^ redundant_static_lifetimes const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_TWO: &str = "Test static #2"; // This line should not raise a warning. static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static +//~^ redundant_static_lifetimes static STATIC_VAR_SIX: &'static u8 = &5; +//~^ redundant_static_lifetimes static STATIC_VAR_HEIGHT: &'static Foo = &Foo {}; +//~^ redundant_static_lifetimes static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. +//~^ redundant_static_lifetimes static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0]; +//~^ redundant_static_lifetimes fn main() { let false_positive: &'static str = "test"; @@ -69,4 +86,5 @@ fn msrv_1_16() { #[clippy::msrv = "1.17"] fn msrv_1_17() { static V: &'static u8 = &17; + //~^ redundant_static_lifetimes } diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr index 48871eba2dc75..9558827039554 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.stderr @@ -8,103 +8,103 @@ LL | const VAR_ONE: &'static str = "Test constant #1"; // ERROR: Consider removi = help: to override `-D warnings` add `#[allow(clippy::redundant_static_lifetimes)]` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:12:21 + --> tests/ui/redundant_static_lifetimes.rs:13:21 | LL | const VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:14:32 + --> tests/ui/redundant_static_lifetimes.rs:16:32 | LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:14:47 + --> tests/ui/redundant_static_lifetimes.rs:16:47 | LL | const VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:16:17 + --> tests/ui/redundant_static_lifetimes.rs:20:17 | LL | const VAR_SIX: &'static u8 = &5; | -^^^^^^^--- help: consider removing `'static`: `&u8` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:18:20 + --> tests/ui/redundant_static_lifetimes.rs:23:20 | LL | const VAR_HEIGHT: &'static Foo = &Foo {}; | -^^^^^^^---- help: consider removing `'static`: `&Foo` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:20:19 + --> tests/ui/redundant_static_lifetimes.rs:26:19 | LL | const VAR_SLICE: &'static [u8] = b"Test constant #1"; // ERROR: Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:22:19 + --> tests/ui/redundant_static_lifetimes.rs:29:19 | LL | const VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:24:19 + --> tests/ui/redundant_static_lifetimes.rs:32:19 | LL | const VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:26:25 + --> tests/ui/redundant_static_lifetimes.rs:35:25 | LL | static STATIC_VAR_ONE: &'static str = "Test static #1"; // ERROR: Consider removing 'static. | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:30:29 + --> tests/ui/redundant_static_lifetimes.rs:40:29 | LL | static STATIC_VAR_THREE: &[&'static str] = &["one", "two"]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:32:25 + --> tests/ui/redundant_static_lifetimes.rs:43:25 | LL | static STATIC_VAR_SIX: &'static u8 = &5; | -^^^^^^^--- help: consider removing `'static`: `&u8` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:34:28 + --> tests/ui/redundant_static_lifetimes.rs:46:28 | LL | static STATIC_VAR_HEIGHT: &'static Foo = &Foo {}; | -^^^^^^^---- help: consider removing `'static`: `&Foo` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:36:27 + --> tests/ui/redundant_static_lifetimes.rs:49:27 | LL | static STATIC_VAR_SLICE: &'static [u8] = b"Test static #3"; // ERROR: Consider removing 'static. | -^^^^^^^----- help: consider removing `'static`: `&[u8]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:38:27 + --> tests/ui/redundant_static_lifetimes.rs:52:27 | LL | static STATIC_VAR_TUPLE: &'static (u8, u8) = &(1, 2); // ERROR: Consider removing 'static. | -^^^^^^^--------- help: consider removing `'static`: `&(u8, u8)` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:40:27 + --> tests/ui/redundant_static_lifetimes.rs:55:27 | LL | static STATIC_VAR_ARRAY: &'static [u8; 1] = b"T"; // ERROR: Consider removing 'static. | -^^^^^^^-------- help: consider removing `'static`: `&[u8; 1]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:42:31 + --> tests/ui/redundant_static_lifetimes.rs:58:31 | LL | static mut STATIC_MUT_SLICE: &'static mut [u32] = &mut [0]; | -^^^^^^^---------- help: consider removing `'static`: `&mut [u32]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes.rs:71:16 + --> tests/ui/redundant_static_lifetimes.rs:88:16 | LL | static V: &'static u8 = &17; | -^^^^^^^--- help: consider removing `'static`: `&u8` diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs index bfcab420b1f40..8cb6e44918426 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.rs @@ -2,24 +2,23 @@ // these are rustfixable, but run-rustfix tests cannot handle them const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static -//~^ ERROR: constants have by default a `'static` lifetime -//~| NOTE: `-D clippy::redundant-static-lifetimes` implied by `-D warnings` -//~| ERROR: constants have by default a `'static` lifetime +//~^ redundant_static_lifetimes +//~| redundant_static_lifetimes const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; -//~^ ERROR: constants have by default a `'static` lifetime -//~| ERROR: constants have by default a `'static` lifetime +//~^ redundant_static_lifetimes +//~| redundant_static_lifetimes static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static -//~^ ERROR: statics have by default a `'static` lifetime -//~| ERROR: statics have by default a `'static` lifetime +//~^ redundant_static_lifetimes +//~| redundant_static_lifetimes static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static -//~^ ERROR: statics have by default a `'static` lifetime -//~| ERROR: statics have by default a `'static` lifetime +//~^ redundant_static_lifetimes +//~| redundant_static_lifetimes static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; -//~^ ERROR: statics have by default a `'static` lifetime -//~| ERROR: statics have by default a `'static` lifetime +//~^ redundant_static_lifetimes +//~| redundant_static_lifetimes fn main() {} diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr index 330703d9eff12..aed16204f1c2e 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes_multiple.stderr @@ -14,49 +14,49 @@ LL | const VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; | -^^^^^^^---- help: consider removing `'static`: `&str` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:9:29 + --> tests/ui/redundant_static_lifetimes_multiple.rs:8:29 | LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]` error: constants have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:9:39 + --> tests/ui/redundant_static_lifetimes_multiple.rs:8:39 | LL | const VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:13:40 + --> tests/ui/redundant_static_lifetimes_multiple.rs:12:40 | LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:13:55 + --> tests/ui/redundant_static_lifetimes_multiple.rs:12:55 | LL | static STATIC_VAR_FOUR: (&str, (&str, &'static str), &'static str) = ("on", ("th", "th"), "on"); // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:17:26 + --> tests/ui/redundant_static_lifetimes_multiple.rs:16:26 | LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static | -^^^^^^^------------------ help: consider removing `'static`: `&[&[&'static str]]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:17:38 + --> tests/ui/redundant_static_lifetimes_multiple.rs:16:38 | LL | static STATIC_VAR_FIVE: &'static [&[&'static str]] = &[&["test"], &["other one"]]; // ERROR: Consider removing 'static | -^^^^^^^---- help: consider removing `'static`: `&str` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:21:37 + --> tests/ui/redundant_static_lifetimes_multiple.rs:20:37 | LL | static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^--------------- help: consider removing `'static`: `&[&'static str]` error: statics have by default a `'static` lifetime - --> tests/ui/redundant_static_lifetimes_multiple.rs:21:47 + --> tests/ui/redundant_static_lifetimes_multiple.rs:20:47 | LL | static STATIC_VAR_SEVEN: &[&(&str, &'static [&'static str])] = &[&("one", &["other one"])]; | -^^^^^^^---- help: consider removing `'static`: `&str` diff --git a/src/tools/clippy/tests/ui/redundant_type_annotations.rs b/src/tools/clippy/tests/ui/redundant_type_annotations.rs index dc9b073ffba85..55c19d194a490 100644 --- a/src/tools/clippy/tests/ui/redundant_type_annotations.rs +++ b/src/tools/clippy/tests/ui/redundant_type_annotations.rs @@ -79,12 +79,13 @@ impl Pie { // Everything here should be lint let v: u32 = self.return_an_int(); - //~^ ERROR: redundant type annotation - //~| NOTE: `-D clippy::redundant-type-annotations` implied by `-D warnings` + //~^ redundant_type_annotations + let v: &u32 = self.return_a_ref(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations + let v: &Slice = self.return_a_ref_to_struct(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations } } @@ -157,50 +158,50 @@ fn test_functions() { // Everything here should be lint let _return: String = return_a_string(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _return: Pie = return_a_struct(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _return: Pizza = return_an_enum(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _return: u32 = return_an_int(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _return: String = String::new(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let new_pie: Pie = Pie::new(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _return: u32 = new_pie.return_an_int(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _return: u32 = Pie::associated_return_an_int(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _return: String = Pie::associated_return_a_string(); - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations } fn test_simple_types() { // Everything here should be lint let _var: u32 = u32::MAX; - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _var: u32 = 5_u32; - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _var: &str = "test"; - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _var: &[u8; 4] = b"test"; - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations let _var: bool = false; - //~^ ERROR: redundant type annotation + //~^ redundant_type_annotations } fn issue12212() { diff --git a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr index 4768f4d3c57ce..d2f04cc4768e1 100644 --- a/src/tools/clippy/tests/ui/redundant_type_annotations.stderr +++ b/src/tools/clippy/tests/ui/redundant_type_annotations.stderr @@ -14,91 +14,91 @@ LL | let v: &u32 = self.return_a_ref(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:86:9 + --> tests/ui/redundant_type_annotations.rs:87:9 | LL | let v: &Slice = self.return_a_ref_to_struct(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:159:5 + --> tests/ui/redundant_type_annotations.rs:160:5 | LL | let _return: String = return_a_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:162:5 + --> tests/ui/redundant_type_annotations.rs:163:5 | LL | let _return: Pie = return_a_struct(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:165:5 + --> tests/ui/redundant_type_annotations.rs:166:5 | LL | let _return: Pizza = return_an_enum(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:168:5 + --> tests/ui/redundant_type_annotations.rs:169:5 | LL | let _return: u32 = return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:171:5 + --> tests/ui/redundant_type_annotations.rs:172:5 | LL | let _return: String = String::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:174:5 + --> tests/ui/redundant_type_annotations.rs:175:5 | LL | let new_pie: Pie = Pie::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:177:5 + --> tests/ui/redundant_type_annotations.rs:178:5 | LL | let _return: u32 = new_pie.return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:180:5 + --> tests/ui/redundant_type_annotations.rs:181:5 | LL | let _return: u32 = Pie::associated_return_an_int(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:183:5 + --> tests/ui/redundant_type_annotations.rs:184:5 | LL | let _return: String = Pie::associated_return_a_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:190:5 + --> tests/ui/redundant_type_annotations.rs:191:5 | LL | let _var: u32 = u32::MAX; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:193:5 + --> tests/ui/redundant_type_annotations.rs:194:5 | LL | let _var: u32 = 5_u32; | ^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:196:5 + --> tests/ui/redundant_type_annotations.rs:197:5 | LL | let _var: &str = "test"; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:199:5 + --> tests/ui/redundant_type_annotations.rs:200:5 | LL | let _var: &[u8; 4] = b"test"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant type annotation - --> tests/ui/redundant_type_annotations.rs:202:5 + --> tests/ui/redundant_type_annotations.rs:203:5 | LL | let _var: bool = false; | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.fixed b/src/tools/clippy/tests/ui/ref_as_ptr.fixed index 6048267092f1b..ce144508581ea 100644 --- a/src/tools/clippy/tests/ui/ref_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ref_as_ptr.fixed @@ -5,53 +5,86 @@ fn f(_: T) {} fn main() { f(std::ptr::from_ref(&1u8)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&2u32)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&3.0f64)); + //~^ ref_as_ptr f(std::ptr::from_ref(&4) as *const f32); + //~^ ref_as_ptr f(std::ptr::from_ref::(&5.0f32) as *const u32); + //~^ ref_as_ptr f(std::ptr::from_ref(&mut 6u8)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&mut 7u32)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&mut 8.0f64)); + //~^ ref_as_ptr f(std::ptr::from_ref(&mut 9) as *const f32); + //~^ ref_as_ptr f(std::ptr::from_ref::(&mut 10.0f32) as *const u32); + //~^ ref_as_ptr f(std::ptr::from_mut(&mut 11u8)); + //~^ ref_as_ptr f(std::ptr::from_mut::(&mut 12u32)); + //~^ ref_as_ptr f(std::ptr::from_mut::(&mut 13.0f64)); + //~^ ref_as_ptr f(std::ptr::from_mut(&mut 14) as *const f32); + //~^ ref_as_ptr f(std::ptr::from_mut::(&mut 15.0f32) as *const u32); + //~^ ref_as_ptr f(std::ptr::from_ref(&1u8)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&2u32)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&3.0f64)); + //~^ ref_as_ptr f(std::ptr::from_ref(&4) as *const f32); + //~^ ref_as_ptr f(std::ptr::from_ref::(&5.0f32) as *const u32); + //~^ ref_as_ptr let val = 1; f(std::ptr::from_ref(&val)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&val)); + //~^ ref_as_ptr f(std::ptr::from_ref(&val) as *const f32); + //~^ ref_as_ptr f(std::ptr::from_ref::(&val) as *const f64); + //~^ ref_as_ptr let mut val: u8 = 2; f(std::ptr::from_mut::(&mut val)); + //~^ ref_as_ptr f(std::ptr::from_mut(&mut val)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&mut val)); + //~^ ref_as_ptr f(std::ptr::from_ref(&mut val)); + //~^ ref_as_ptr f(std::ptr::from_ref::(&mut val) as *const f64); + //~^ ref_as_ptr f::<*const Option>(std::ptr::from_ref(&mut val) as *const _); + //~^ ref_as_ptr f(std::ptr::from_ref::<[usize; 7]>(&std::array::from_fn(|i| i * i))); + //~^ ref_as_ptr f(std::ptr::from_ref::<[usize; 8]>(&mut std::array::from_fn(|i| i * i))); + //~^ ref_as_ptr f(std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i))); + //~^ ref_as_ptr let _ = &String::new() as *const _; let _ = &mut String::new() as *mut _; @@ -74,17 +107,23 @@ fn _msrv_1_76() { let mut_val = &mut 42_i32; f(std::ptr::from_ref::(val)); + //~^ ref_as_ptr f(std::ptr::from_mut::(mut_val)); + //~^ ref_as_ptr } fn foo(val: &[u8]) { f(std::ptr::from_ref(val)); + //~^ ref_as_ptr f(std::ptr::from_ref::<[u8]>(val)); + //~^ ref_as_ptr } fn bar(val: &mut str) { f(std::ptr::from_mut(val)); + //~^ ref_as_ptr f(std::ptr::from_mut::(val)); + //~^ ref_as_ptr } struct X<'a>(&'a i32); @@ -92,10 +131,12 @@ struct X<'a>(&'a i32); impl<'a> X<'a> { fn foo(&self) -> *const i64 { std::ptr::from_ref(self.0) as *const _ + //~^ ref_as_ptr } fn bar(&mut self) -> *const i64 { std::ptr::from_ref(self.0) as *const _ + //~^ ref_as_ptr } } @@ -104,13 +145,16 @@ struct Y<'a>(&'a mut i32); impl<'a> Y<'a> { fn foo(&self) -> *const i64 { std::ptr::from_ref(self.0) as *const _ + //~^ ref_as_ptr } fn bar(&mut self) -> *const i64 { std::ptr::from_ref(self.0) as *const _ + //~^ ref_as_ptr } fn baz(&mut self) -> *const i64 { std::ptr::from_mut(self.0) as *mut _ + //~^ ref_as_ptr } } diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.rs b/src/tools/clippy/tests/ui/ref_as_ptr.rs index 7f1d59b856e4b..acdff2c2ba297 100644 --- a/src/tools/clippy/tests/ui/ref_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ref_as_ptr.rs @@ -5,53 +5,86 @@ fn f(_: T) {} fn main() { f(&1u8 as *const _); + //~^ ref_as_ptr f(&2u32 as *const u32); + //~^ ref_as_ptr f(&3.0f64 as *const f64); + //~^ ref_as_ptr f(&4 as *const _ as *const f32); + //~^ ref_as_ptr f(&5.0f32 as *const f32 as *const u32); + //~^ ref_as_ptr f(&mut 6u8 as *const _); + //~^ ref_as_ptr f(&mut 7u32 as *const u32); + //~^ ref_as_ptr f(&mut 8.0f64 as *const f64); + //~^ ref_as_ptr f(&mut 9 as *const _ as *const f32); + //~^ ref_as_ptr f(&mut 10.0f32 as *const f32 as *const u32); + //~^ ref_as_ptr f(&mut 11u8 as *mut _); + //~^ ref_as_ptr f(&mut 12u32 as *mut u32); + //~^ ref_as_ptr f(&mut 13.0f64 as *mut f64); + //~^ ref_as_ptr f(&mut 14 as *mut _ as *const f32); + //~^ ref_as_ptr f(&mut 15.0f32 as *mut f32 as *const u32); + //~^ ref_as_ptr f(&1u8 as *const _); + //~^ ref_as_ptr f(&2u32 as *const u32); + //~^ ref_as_ptr f(&3.0f64 as *const f64); + //~^ ref_as_ptr f(&4 as *const _ as *const f32); + //~^ ref_as_ptr f(&5.0f32 as *const f32 as *const u32); + //~^ ref_as_ptr let val = 1; f(&val as *const _); + //~^ ref_as_ptr f(&val as *const i32); + //~^ ref_as_ptr f(&val as *const _ as *const f32); + //~^ ref_as_ptr f(&val as *const i32 as *const f64); + //~^ ref_as_ptr let mut val: u8 = 2; f(&mut val as *mut u8); + //~^ ref_as_ptr f(&mut val as *mut _); + //~^ ref_as_ptr f(&mut val as *const u8); + //~^ ref_as_ptr f(&mut val as *const _); + //~^ ref_as_ptr f(&mut val as *const u8 as *const f64); + //~^ ref_as_ptr f::<*const Option>(&mut val as *const _ as *const _); + //~^ ref_as_ptr f(&std::array::from_fn(|i| i * i) as *const [usize; 7]); + //~^ ref_as_ptr f(&mut std::array::from_fn(|i| i * i) as *const [usize; 8]); + //~^ ref_as_ptr f(&mut std::array::from_fn(|i| i * i) as *mut [usize; 9]); + //~^ ref_as_ptr let _ = &String::new() as *const _; let _ = &mut String::new() as *mut _; @@ -74,17 +107,23 @@ fn _msrv_1_76() { let mut_val = &mut 42_i32; f(val as *const i32); + //~^ ref_as_ptr f(mut_val as *mut i32); + //~^ ref_as_ptr } fn foo(val: &[u8]) { f(val as *const _); + //~^ ref_as_ptr f(val as *const [u8]); + //~^ ref_as_ptr } fn bar(val: &mut str) { f(val as *mut _); + //~^ ref_as_ptr f(val as *mut str); + //~^ ref_as_ptr } struct X<'a>(&'a i32); @@ -92,10 +131,12 @@ struct X<'a>(&'a i32); impl<'a> X<'a> { fn foo(&self) -> *const i64 { self.0 as *const _ as *const _ + //~^ ref_as_ptr } fn bar(&mut self) -> *const i64 { self.0 as *const _ as *const _ + //~^ ref_as_ptr } } @@ -104,13 +145,16 @@ struct Y<'a>(&'a mut i32); impl<'a> Y<'a> { fn foo(&self) -> *const i64 { self.0 as *const _ as *const _ + //~^ ref_as_ptr } fn bar(&mut self) -> *const i64 { self.0 as *const _ as *const _ + //~^ ref_as_ptr } fn baz(&mut self) -> *const i64 { self.0 as *mut _ as *mut _ + //~^ ref_as_ptr } } diff --git a/src/tools/clippy/tests/ui/ref_as_ptr.stderr b/src/tools/clippy/tests/ui/ref_as_ptr.stderr index c5e9af38aea09..79db29e596bd2 100644 --- a/src/tools/clippy/tests/ui/ref_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ref_as_ptr.stderr @@ -8,259 +8,259 @@ LL | f(&1u8 as *const _); = help: to override `-D warnings` add `#[allow(clippy::ref_as_ptr)]` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:8:7 + --> tests/ui/ref_as_ptr.rs:9:7 | LL | f(&2u32 as *const u32); | ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&2u32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:9:7 + --> tests/ui/ref_as_ptr.rs:11:7 | LL | f(&3.0f64 as *const f64); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&3.0f64)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:11:7 + --> tests/ui/ref_as_ptr.rs:14:7 | LL | f(&4 as *const _ as *const f32); | ^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&4)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:12:7 + --> tests/ui/ref_as_ptr.rs:16:7 | LL | f(&5.0f32 as *const f32 as *const u32); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&5.0f32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:14:7 + --> tests/ui/ref_as_ptr.rs:19:7 | LL | f(&mut 6u8 as *const _); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut 6u8)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:15:7 + --> tests/ui/ref_as_ptr.rs:21:7 | LL | f(&mut 7u32 as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&mut 7u32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:16:7 + --> tests/ui/ref_as_ptr.rs:23:7 | LL | f(&mut 8.0f64 as *const f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&mut 8.0f64)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:18:7 + --> tests/ui/ref_as_ptr.rs:26:7 | LL | f(&mut 9 as *const _ as *const f32); | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut 9)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:19:7 + --> tests/ui/ref_as_ptr.rs:28:7 | LL | f(&mut 10.0f32 as *const f32 as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&mut 10.0f32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:21:7 + --> tests/ui/ref_as_ptr.rs:31:7 | LL | f(&mut 11u8 as *mut _); | ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(&mut 11u8)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:22:7 + --> tests/ui/ref_as_ptr.rs:33:7 | LL | f(&mut 12u32 as *mut u32); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(&mut 12u32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:23:7 + --> tests/ui/ref_as_ptr.rs:35:7 | LL | f(&mut 13.0f64 as *mut f64); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(&mut 13.0f64)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:25:7 + --> tests/ui/ref_as_ptr.rs:38:7 | LL | f(&mut 14 as *mut _ as *const f32); | ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(&mut 14)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:26:7 + --> tests/ui/ref_as_ptr.rs:40:7 | LL | f(&mut 15.0f32 as *mut f32 as *const u32); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(&mut 15.0f32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:28:7 + --> tests/ui/ref_as_ptr.rs:43:7 | LL | f(&1u8 as *const _); | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&1u8)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:29:7 + --> tests/ui/ref_as_ptr.rs:45:7 | LL | f(&2u32 as *const u32); | ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&2u32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:30:7 + --> tests/ui/ref_as_ptr.rs:47:7 | LL | f(&3.0f64 as *const f64); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&3.0f64)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:32:7 + --> tests/ui/ref_as_ptr.rs:50:7 | LL | f(&4 as *const _ as *const f32); | ^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&4)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:33:7 + --> tests/ui/ref_as_ptr.rs:52:7 | LL | f(&5.0f32 as *const f32 as *const u32); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&5.0f32)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:36:7 + --> tests/ui/ref_as_ptr.rs:56:7 | LL | f(&val as *const _); | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:37:7 + --> tests/ui/ref_as_ptr.rs:58:7 | LL | f(&val as *const i32); | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:39:7 + --> tests/ui/ref_as_ptr.rs:61:7 | LL | f(&val as *const _ as *const f32); | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:40:7 + --> tests/ui/ref_as_ptr.rs:63:7 | LL | f(&val as *const i32 as *const f64); | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:43:7 + --> tests/ui/ref_as_ptr.rs:67:7 | LL | f(&mut val as *mut u8); | ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(&mut val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:44:7 + --> tests/ui/ref_as_ptr.rs:69:7 | LL | f(&mut val as *mut _); | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(&mut val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:46:7 + --> tests/ui/ref_as_ptr.rs:72:7 | LL | f(&mut val as *const u8); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&mut val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:47:7 + --> tests/ui/ref_as_ptr.rs:74:7 | LL | f(&mut val as *const _); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:49:7 + --> tests/ui/ref_as_ptr.rs:77:7 | LL | f(&mut val as *const u8 as *const f64); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(&mut val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:50:28 + --> tests/ui/ref_as_ptr.rs:79:28 | LL | f::<*const Option>(&mut val as *const _ as *const _); | ^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(&mut val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:52:7 + --> tests/ui/ref_as_ptr.rs:82:7 | LL | f(&std::array::from_fn(|i| i * i) as *const [usize; 7]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[usize; 7]>(&std::array::from_fn(|i| i * i))` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:53:7 + --> tests/ui/ref_as_ptr.rs:84:7 | LL | f(&mut std::array::from_fn(|i| i * i) as *const [usize; 8]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[usize; 8]>(&mut std::array::from_fn(|i| i * i))` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:54:7 + --> tests/ui/ref_as_ptr.rs:86:7 | LL | f(&mut std::array::from_fn(|i| i * i) as *mut [usize; 9]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i))` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:76:7 + --> tests/ui/ref_as_ptr.rs:109:7 | LL | f(val as *const i32); | ^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:77:7 + --> tests/ui/ref_as_ptr.rs:111:7 | LL | f(mut_val as *mut i32); | ^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(mut_val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:81:7 + --> tests/ui/ref_as_ptr.rs:116:7 | LL | f(val as *const _); | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:82:7 + --> tests/ui/ref_as_ptr.rs:118:7 | LL | f(val as *const [u8]); | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref::<[u8]>(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:86:7 + --> tests/ui/ref_as_ptr.rs:123:7 | LL | f(val as *mut _); | ^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:87:7 + --> tests/ui/ref_as_ptr.rs:125:7 | LL | f(val as *mut str); | ^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut::(val)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:94:9 + --> tests/ui/ref_as_ptr.rs:133:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:98:9 + --> tests/ui/ref_as_ptr.rs:138:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:106:9 + --> tests/ui/ref_as_ptr.rs:147:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:110:9 + --> tests/ui/ref_as_ptr.rs:152:9 | LL | self.0 as *const _ as *const _ | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_ref(self.0)` error: reference as raw pointer - --> tests/ui/ref_as_ptr.rs:114:9 + --> tests/ui/ref_as_ptr.rs:157:9 | LL | self.0 as *mut _ as *mut _ | ^^^^^^^^^^^^^^^^ help: try: `std::ptr::from_mut(self.0)` diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs index 001ed31194909..365fd8edea789 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs @@ -28,15 +28,15 @@ fn main() { // Err, reference to a &String let _: &&String = match Some(&x) { Some(ref x) => x, - //~^ ERROR: this pattern creates a reference to a reference - //~| NOTE: `-D clippy::ref-binding-to-reference` implied by `-D warnings` + //~^ ref_binding_to_reference None => return, }; // Err, reference to a &String let _: &&String = match Some(&x) { Some(ref x) => { - //~^ ERROR: this pattern creates a reference to a reference + //~^ ref_binding_to_reference + f1(x); f1(*x); x @@ -47,20 +47,22 @@ fn main() { // Err, reference to a &String match Some(&x) { Some(ref x) => m2!(x), - //~^ ERROR: this pattern creates a reference to a reference + //~^ ref_binding_to_reference None => return, } // Err, reference to a &String let _ = |&ref x: &&String| { - //~^ ERROR: this pattern creates a reference to a reference + //~^ ref_binding_to_reference + let _: &&String = x; }; } // Err, reference to a &String fn f2<'a>(&ref x: &&'a String) -> &'a String { - //~^ ERROR: this pattern creates a reference to a reference + //~^ ref_binding_to_reference + let _: &&String = x; *x } @@ -68,7 +70,8 @@ fn f2<'a>(&ref x: &&'a String) -> &'a String { trait T1 { // Err, reference to a &String fn f(&ref x: &&String) { - //~^ ERROR: this pattern creates a reference to a reference + //~^ ref_binding_to_reference + let _: &&String = x; } } @@ -77,7 +80,8 @@ struct S; impl T1 for S { // Err, reference to a &String fn f(&ref x: &&String) { - //~^ ERROR: this pattern creates a reference to a reference + //~^ ref_binding_to_reference + let _: &&String = x; } } diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr index 233416351a0a5..c1adfab12bcba 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr @@ -13,7 +13,7 @@ LL + Some(x) => &x, | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:38:14 + --> tests/ui/ref_binding_to_reference.rs:37:14 | LL | Some(ref x) => { | ^^^^^ @@ -22,6 +22,7 @@ help: try | LL ~ Some(x) => { LL | +LL | LL | f1(x); LL ~ f1(x); LL ~ &x @@ -49,11 +50,12 @@ help: try | LL ~ let _ = |&x: &&String| { LL | +LL | LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:62:12 + --> tests/ui/ref_binding_to_reference.rs:63:12 | LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { | ^^^^^ @@ -62,12 +64,13 @@ help: try | LL ~ fn f2<'a>(&x: &&'a String) -> &'a String { LL | +LL | LL ~ let _: &&String = &x; LL ~ x | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:70:11 + --> tests/ui/ref_binding_to_reference.rs:72:11 | LL | fn f(&ref x: &&String) { | ^^^^^ @@ -76,11 +79,12 @@ help: try | LL ~ fn f(&x: &&String) { LL | +LL | LL ~ let _: &&String = &x; | error: this pattern creates a reference to a reference - --> tests/ui/ref_binding_to_reference.rs:79:11 + --> tests/ui/ref_binding_to_reference.rs:82:11 | LL | fn f(&ref x: &&String) { | ^^^^^ @@ -89,6 +93,7 @@ help: try | LL ~ fn f(&x: &&String) { LL | +LL | LL ~ let _: &&String = &x; | diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed index 47781a97c983f..4159e916f1995 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed +++ b/src/tools/clippy/tests/ui/ref_option/ref_option.all.fixed @@ -6,42 +6,59 @@ #![warn(clippy::ref_option)] fn opt_u8(a: Option<&u8>) {} +//~^ ref_option fn opt_gen(a: Option<&T>) {} +//~^ ref_option fn opt_string(a: std::option::Option<&String>) {} +//~^ ref_option fn ret_string<'a>(p: &'a str) -> Option<&'a u8> { + //~^ ref_option panic!() } fn ret_string_static() -> Option<&'static u8> { + //~^ ref_option panic!() } fn mult_string(a: Option<&String>, b: Option<&Vec>) {} +//~^ ref_option fn ret_box<'a>() -> Option<&'a Box> { + //~^ ref_option panic!() } pub fn pub_opt_string(a: Option<&String>) {} +//~[all]^ ref_option pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec>) {} +//~[all]^ ref_option pub trait PubTrait { fn pub_trait_opt(&self, a: Option<&Vec>); + //~[all]^ ref_option fn pub_trait_ret(&self) -> Option<&Vec>; + //~[all]^ ref_option } trait PrivateTrait { fn trait_opt(&self, a: Option<&String>); + //~^ ref_option fn trait_ret(&self) -> Option<&String>; + //~^ ref_option } pub struct PubStruct; impl PubStruct { pub fn pub_opt_params(&self, a: Option<&()>) {} + //~[all]^ ref_option pub fn pub_opt_ret(&self) -> Option<&String> { + //~[all]^ ref_option panic!() } fn private_opt_params(&self, a: Option<&()>) {} + //~^ ref_option fn private_opt_ret(&self) -> Option<&String> { + //~^ ref_option panic!() } } diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr index fd30628bdd818..bd43c28336eb3 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr +++ b/src/tools/clippy/tests/ui/ref_option/ref_option.all.stderr @@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option) {} = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:9:1 + --> tests/ui/ref_option/ref_option.rs:10:1 | LL | fn opt_gen(a: &Option) {} | ^^^^^^^^^^^^^^^^^----------^^^^ @@ -18,7 +18,7 @@ LL | fn opt_gen(a: &Option) {} | help: change this to: `Option<&T>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:10:1 + --> tests/ui/ref_option/ref_option.rs:12:1 | LL | fn opt_string(a: &std::option::Option) {} | ^^^^^^^^^^^^^^^^^----------------------------^^^^ @@ -26,29 +26,31 @@ LL | fn opt_string(a: &std::option::Option) {} | help: change this to: `std::option::Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:11:1 + --> tests/ui/ref_option/ref_option.rs:14:1 | LL | fn ret_string<'a>(p: &'a str) -> &'a Option { | ^ -------------- help: change this to: `Option<&'a u8>` | _| | | +LL | | LL | | panic!() LL | | } | |_^ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:14:1 + --> tests/ui/ref_option/ref_option.rs:18:1 | LL | fn ret_string_static() -> &'static Option { | ^ ------------------- help: change this to: `Option<&'static u8>` | _| | | +LL | | LL | | panic!() LL | | } | |_^ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:17:1 + --> tests/ui/ref_option/ref_option.rs:22:1 | LL | fn mult_string(a: &Option, b: &Option>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,18 +62,19 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec>) {} | error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:18:1 + --> tests/ui/ref_option/ref_option.rs:24:1 | LL | fn ret_box<'a>() -> &'a Option> { | ^ ------------------- help: change this to: `Option<&'a Box>` | _| | | +LL | | LL | | panic!() LL | | } | |_^ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:22:1 + --> tests/ui/ref_option/ref_option.rs:29:1 | LL | pub fn pub_opt_string(a: &Option) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^---------------^^^^ @@ -79,7 +82,7 @@ LL | pub fn pub_opt_string(a: &Option) {} | help: change this to: `Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:23:1 + --> tests/ui/ref_option/ref_option.rs:31:1 | LL | pub fn pub_mult_string(a: &Option, b: &Option>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,7 +94,7 @@ LL + pub fn pub_mult_string(a: Option<&String>, b: Option<&Vec>) {} | error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:26:5 + --> tests/ui/ref_option/ref_option.rs:35:5 | LL | fn pub_trait_opt(&self, a: &Option>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^ @@ -99,7 +102,7 @@ LL | fn pub_trait_opt(&self, a: &Option>); | help: change this to: `Option<&Vec>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:27:5 + --> tests/ui/ref_option/ref_option.rs:37:5 | LL | fn pub_trait_ret(&self) -> &Option>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^ @@ -107,7 +110,7 @@ LL | fn pub_trait_ret(&self) -> &Option>; | help: change this to: `Option<&Vec>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:31:5 + --> tests/ui/ref_option/ref_option.rs:42:5 | LL | fn trait_opt(&self, a: &Option); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ @@ -115,7 +118,7 @@ LL | fn trait_opt(&self, a: &Option); | help: change this to: `Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:32:5 + --> tests/ui/ref_option/ref_option.rs:44:5 | LL | fn trait_ret(&self) -> &Option; | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -123,7 +126,7 @@ LL | fn trait_ret(&self) -> &Option; | help: change this to: `Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:38:5 + --> tests/ui/ref_option/ref_option.rs:51:5 | LL | pub fn pub_opt_params(&self, a: &Option<()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ @@ -131,18 +134,19 @@ LL | pub fn pub_opt_params(&self, a: &Option<()>) {} | help: change this to: `Option<&()>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:39:5 + --> tests/ui/ref_option/ref_option.rs:53:5 | LL | pub fn pub_opt_ret(&self) -> &Option { | ^ --------------- help: change this to: `Option<&String>` | _____| | | +LL | | LL | | panic!() LL | | } | |_____^ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:43:5 + --> tests/ui/ref_option/ref_option.rs:58:5 | LL | fn private_opt_params(&self, a: &Option<()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ @@ -150,12 +154,13 @@ LL | fn private_opt_params(&self, a: &Option<()>) {} | help: change this to: `Option<&()>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:44:5 + --> tests/ui/ref_option/ref_option.rs:60:5 | LL | fn private_opt_ret(&self) -> &Option { | ^ --------------- help: change this to: `Option<&String>` | _____| | | +LL | | LL | | panic!() LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed b/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed index 8c42556e9b0d7..3b158befb926e 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed +++ b/src/tools/clippy/tests/ui/ref_option/ref_option.private.fixed @@ -6,42 +6,59 @@ #![warn(clippy::ref_option)] fn opt_u8(a: Option<&u8>) {} +//~^ ref_option fn opt_gen(a: Option<&T>) {} +//~^ ref_option fn opt_string(a: std::option::Option<&String>) {} +//~^ ref_option fn ret_string<'a>(p: &'a str) -> Option<&'a u8> { + //~^ ref_option panic!() } fn ret_string_static() -> Option<&'static u8> { + //~^ ref_option panic!() } fn mult_string(a: Option<&String>, b: Option<&Vec>) {} +//~^ ref_option fn ret_box<'a>() -> Option<&'a Box> { + //~^ ref_option panic!() } pub fn pub_opt_string(a: &Option) {} +//~[all]^ ref_option pub fn pub_mult_string(a: &Option, b: &Option>) {} +//~[all]^ ref_option pub trait PubTrait { fn pub_trait_opt(&self, a: &Option>); + //~[all]^ ref_option fn pub_trait_ret(&self) -> &Option>; + //~[all]^ ref_option } trait PrivateTrait { fn trait_opt(&self, a: Option<&String>); + //~^ ref_option fn trait_ret(&self) -> Option<&String>; + //~^ ref_option } pub struct PubStruct; impl PubStruct { pub fn pub_opt_params(&self, a: &Option<()>) {} + //~[all]^ ref_option pub fn pub_opt_ret(&self) -> &Option { + //~[all]^ ref_option panic!() } fn private_opt_params(&self, a: Option<&()>) {} + //~^ ref_option fn private_opt_ret(&self) -> Option<&String> { + //~^ ref_option panic!() } } diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr index d3428f1891f35..88c65e429d870 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr +++ b/src/tools/clippy/tests/ui/ref_option/ref_option.private.stderr @@ -10,7 +10,7 @@ LL | fn opt_u8(a: &Option) {} = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:9:1 + --> tests/ui/ref_option/ref_option.rs:10:1 | LL | fn opt_gen(a: &Option) {} | ^^^^^^^^^^^^^^^^^----------^^^^ @@ -18,7 +18,7 @@ LL | fn opt_gen(a: &Option) {} | help: change this to: `Option<&T>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:10:1 + --> tests/ui/ref_option/ref_option.rs:12:1 | LL | fn opt_string(a: &std::option::Option) {} | ^^^^^^^^^^^^^^^^^----------------------------^^^^ @@ -26,29 +26,31 @@ LL | fn opt_string(a: &std::option::Option) {} | help: change this to: `std::option::Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:11:1 + --> tests/ui/ref_option/ref_option.rs:14:1 | LL | fn ret_string<'a>(p: &'a str) -> &'a Option { | ^ -------------- help: change this to: `Option<&'a u8>` | _| | | +LL | | LL | | panic!() LL | | } | |_^ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:14:1 + --> tests/ui/ref_option/ref_option.rs:18:1 | LL | fn ret_string_static() -> &'static Option { | ^ ------------------- help: change this to: `Option<&'static u8>` | _| | | +LL | | LL | | panic!() LL | | } | |_^ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:17:1 + --> tests/ui/ref_option/ref_option.rs:22:1 | LL | fn mult_string(a: &Option, b: &Option>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,18 +62,19 @@ LL + fn mult_string(a: Option<&String>, b: Option<&Vec>) {} | error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:18:1 + --> tests/ui/ref_option/ref_option.rs:24:1 | LL | fn ret_box<'a>() -> &'a Option> { | ^ ------------------- help: change this to: `Option<&'a Box>` | _| | | +LL | | LL | | panic!() LL | | } | |_^ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:31:5 + --> tests/ui/ref_option/ref_option.rs:42:5 | LL | fn trait_opt(&self, a: &Option); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ @@ -79,7 +82,7 @@ LL | fn trait_opt(&self, a: &Option); | help: change this to: `Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:32:5 + --> tests/ui/ref_option/ref_option.rs:44:5 | LL | fn trait_ret(&self) -> &Option; | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ @@ -87,7 +90,7 @@ LL | fn trait_ret(&self) -> &Option; | help: change this to: `Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:43:5 + --> tests/ui/ref_option/ref_option.rs:58:5 | LL | fn private_opt_params(&self, a: &Option<()>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^ @@ -95,12 +98,13 @@ LL | fn private_opt_params(&self, a: &Option<()>) {} | help: change this to: `Option<&()>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option.rs:44:5 + --> tests/ui/ref_option/ref_option.rs:60:5 | LL | fn private_opt_ret(&self) -> &Option { | ^ --------------- help: change this to: `Option<&String>` | _____| | | +LL | | LL | | panic!() LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option.rs b/src/tools/clippy/tests/ui/ref_option/ref_option.rs index 05251bcf12cd0..35cd94174f8bc 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option.rs +++ b/src/tools/clippy/tests/ui/ref_option/ref_option.rs @@ -6,42 +6,59 @@ #![warn(clippy::ref_option)] fn opt_u8(a: &Option) {} +//~^ ref_option fn opt_gen(a: &Option) {} +//~^ ref_option fn opt_string(a: &std::option::Option) {} +//~^ ref_option fn ret_string<'a>(p: &'a str) -> &'a Option { + //~^ ref_option panic!() } fn ret_string_static() -> &'static Option { + //~^ ref_option panic!() } fn mult_string(a: &Option, b: &Option>) {} +//~^ ref_option fn ret_box<'a>() -> &'a Option> { + //~^ ref_option panic!() } pub fn pub_opt_string(a: &Option) {} +//~[all]^ ref_option pub fn pub_mult_string(a: &Option, b: &Option>) {} +//~[all]^ ref_option pub trait PubTrait { fn pub_trait_opt(&self, a: &Option>); + //~[all]^ ref_option fn pub_trait_ret(&self) -> &Option>; + //~[all]^ ref_option } trait PrivateTrait { fn trait_opt(&self, a: &Option); + //~^ ref_option fn trait_ret(&self) -> &Option; + //~^ ref_option } pub struct PubStruct; impl PubStruct { pub fn pub_opt_params(&self, a: &Option<()>) {} + //~[all]^ ref_option pub fn pub_opt_ret(&self) -> &Option { + //~[all]^ ref_option panic!() } fn private_opt_params(&self, a: &Option<()>) {} + //~^ ref_option fn private_opt_ret(&self) -> &Option { + //~^ ref_option panic!() } } diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr index a9967168c12e3..030a9a28ec684 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr +++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr @@ -10,7 +10,7 @@ LL | fn pub_trait_opt(&self, a: &Option>); = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:11:5 + --> tests/ui/ref_option/ref_option_traits.rs:12:5 | LL | fn pub_trait_ret(&self) -> &Option>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^ @@ -18,7 +18,7 @@ LL | fn pub_trait_ret(&self) -> &Option>; | help: change this to: `Option<&Vec>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:15:5 + --> tests/ui/ref_option/ref_option_traits.rs:17:5 | LL | fn trait_opt(&self, a: &Option); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ @@ -26,7 +26,7 @@ LL | fn trait_opt(&self, a: &Option); | help: change this to: `Option<&String>` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:16:5 + --> tests/ui/ref_option/ref_option_traits.rs:19:5 | LL | fn trait_ret(&self) -> &Option; | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr index 36d0833af8a23..2837ee80fb2ef 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr +++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr @@ -1,5 +1,5 @@ error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:15:5 + --> tests/ui/ref_option/ref_option_traits.rs:17:5 | LL | fn trait_opt(&self, a: &Option); | ^^^^^^^^^^^^^^^^^^^^^^^---------------^^ @@ -10,7 +10,7 @@ LL | fn trait_opt(&self, a: &Option); = help: to override `-D warnings` add `#[allow(clippy::ref_option)]` error: it is more idiomatic to use `Option<&T>` instead of `&Option` - --> tests/ui/ref_option/ref_option_traits.rs:16:5 + --> tests/ui/ref_option/ref_option_traits.rs:19:5 | LL | fn trait_ret(&self) -> &Option; | ^^^^^^^^^^^^^^^^^^^^^^^---------------^ diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs index 5d5f113c83db5..811da2eb4d500 100644 --- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs +++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs @@ -8,12 +8,16 @@ pub trait PubTrait { fn pub_trait_opt(&self, a: &Option>); + //~[all]^ ref_option fn pub_trait_ret(&self) -> &Option>; + //~[all]^ ref_option } trait PrivateTrait { fn trait_opt(&self, a: &Option); + //~^ ref_option fn trait_ret(&self) -> &Option; + //~^ ref_option } pub struct PubStruct; diff --git a/src/tools/clippy/tests/ui/ref_option_ref.rs b/src/tools/clippy/tests/ui/ref_option_ref.rs index 44001c45e99a9..9632611f7df4d 100644 --- a/src/tools/clippy/tests/ui/ref_option_ref.rs +++ b/src/tools/clippy/tests/ui/ref_option_ref.rs @@ -8,37 +8,39 @@ static THRESHOLD: i32 = 10; static REF_THRESHOLD: &Option<&i32> = &Some(&THRESHOLD); -//~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Opt -//~| NOTE: `-D clippy::ref-option-ref` implied by `-D warnings` +//~^ ref_option_ref + const CONST_THRESHOLD: &i32 = &10; const REF_CONST: &Option<&i32> = &Some(CONST_THRESHOLD); -//~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Opt +//~^ ref_option_ref type RefOptRefU32<'a> = &'a Option<&'a u32>; -//~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Opt +//~^ ref_option_ref + type RefOptRef<'a, T> = &'a Option<&'a T>; -//~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Opt +//~^ ref_option_ref fn foo(data: &Option<&u32>) {} -//~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Opt +//~^ ref_option_ref fn bar(data: &u32) -> &Option<&u32> { - //~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Opt + //~^ ref_option_ref + &None } struct StructRef<'a> { data: &'a Option<&'a u32>, - //~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to + //~^ ref_option_ref } struct StructTupleRef<'a>(u32, &'a Option<&'a u32>); -//~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Opt +//~^ ref_option_ref enum EnumRef<'a> { Variant1(u32), Variant2(&'a Option<&'a u32>), - //~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to + //~^ ref_option_ref } trait RefOptTrait { @@ -48,14 +50,14 @@ trait RefOptTrait { impl RefOptTrait for u32 { type A = &'static Option<&'static Self>; - //~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to + //~^ ref_option_ref fn foo(&self, _: Self::A) {} } fn main() { let x: &Option<&u32> = &None; - //~^ ERROR: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to + //~^ ref_option_ref } fn issue9682(arg: &Option<&mut String>) { diff --git a/src/tools/clippy/tests/ui/ref_option_ref.stderr b/src/tools/clippy/tests/ui/ref_option_ref.stderr index 1cb64e1182a55..25064a61ee88b 100644 --- a/src/tools/clippy/tests/ui/ref_option_ref.stderr +++ b/src/tools/clippy/tests/ui/ref_option_ref.stderr @@ -20,49 +20,49 @@ LL | type RefOptRefU32<'a> = &'a Option<&'a u32>; | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:19:25 + --> tests/ui/ref_option_ref.rs:20:25 | LL | type RefOptRef<'a, T> = &'a Option<&'a T>; | ^^^^^^^^^^^^^^^^^ help: try: `Option<&'a T>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:22:14 + --> tests/ui/ref_option_ref.rs:23:14 | LL | fn foo(data: &Option<&u32>) {} | ^^^^^^^^^^^^^ help: try: `Option<&u32>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:25:23 + --> tests/ui/ref_option_ref.rs:26:23 | LL | fn bar(data: &u32) -> &Option<&u32> { | ^^^^^^^^^^^^^ help: try: `Option<&u32>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:31:11 + --> tests/ui/ref_option_ref.rs:33:11 | LL | data: &'a Option<&'a u32>, | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:35:32 + --> tests/ui/ref_option_ref.rs:37:32 | LL | struct StructTupleRef<'a>(u32, &'a Option<&'a u32>); | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:40:14 + --> tests/ui/ref_option_ref.rs:42:14 | LL | Variant2(&'a Option<&'a u32>), | ^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'a u32>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:50:14 + --> tests/ui/ref_option_ref.rs:52:14 | LL | type A = &'static Option<&'static Self>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Option<&'static Self>` error: since `&` implements the `Copy` trait, `&Option<&T>` can be simplified to `Option<&T>` - --> tests/ui/ref_option_ref.rs:57:12 + --> tests/ui/ref_option_ref.rs:59:12 | LL | let x: &Option<&u32> = &None; | ^^^^^^^^^^^^^ help: try: `Option<&u32>` diff --git a/src/tools/clippy/tests/ui/ref_patterns.rs b/src/tools/clippy/tests/ui/ref_patterns.rs index acd42ec89b62f..2905af13ccb63 100644 --- a/src/tools/clippy/tests/ui/ref_patterns.rs +++ b/src/tools/clippy/tests/ui/ref_patterns.rs @@ -6,17 +6,17 @@ fn use_in_pattern() { match opt { None => {}, Some(ref opt) => {}, - //~^ ERROR: usage of ref pattern + //~^ ref_patterns } } fn use_in_binding() { let x = 5; let ref y = x; - //~^ ERROR: usage of ref pattern + //~^ ref_patterns } fn use_in_parameter(ref x: i32) {} -//~^ ERROR: usage of ref pattern +//~^ ref_patterns fn main() {} diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs index f607a2d50c6d5..c63d549b75534 100644 --- a/src/tools/clippy/tests/ui/regex.rs +++ b/src/tools/clippy/tests/ui/regex.rs @@ -1,3 +1,4 @@ +//@require-annotations-for-level: WARN #![allow( unused, clippy::needless_raw_strings, @@ -27,11 +28,14 @@ fn syntax_error() { //~^ ERROR: regex syntax error: invalid character class range, the start must be <= th let some_regex = Regex::new(OPENING_PAREN); + //~^ invalid_regex let binary_pipe_in_wrong_position = BRegex::new("|"); //~^ ERROR: trivial regex let some_binary_regex = BRegex::new(OPENING_PAREN); + //~^ invalid_regex let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); + //~^ invalid_regex let closing_paren = ")"; let not_linted = Regex::new(closing_paren); @@ -44,7 +48,9 @@ fn syntax_error() { ]); let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); + //~^ invalid_regex let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); + //~^ invalid_regex // These following three cases are considering valid since regex-1.8.0 let raw_string_error = Regex::new(r"[...\/...]"); @@ -52,6 +58,7 @@ fn syntax_error() { let _ = Regex::new(r"(?hi)").unwrap(); let escaped_string_span = Regex::new("\\b\\c"); + //~^ invalid_regex let aux_span = Regex::new("(?ixi)"); //~^ ERROR: regex syntax error: duplicate flag diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr index 18dd538c68b44..aaec3bc142003 100644 --- a/src/tools/clippy/tests/ui/regex.stderr +++ b/src/tools/clippy/tests/ui/regex.stderr @@ -1,5 +1,5 @@ error: trivial regex - --> tests/ui/regex.rs:19:45 + --> tests/ui/regex.rs:20:45 | LL | let pipe_in_wrong_position = Regex::new("|"); | ^^^ @@ -9,7 +9,7 @@ LL | let pipe_in_wrong_position = Regex::new("|"); = help: to override `-D warnings` add `#[allow(clippy::trivial_regex)]` error: trivial regex - --> tests/ui/regex.rs:21:60 + --> tests/ui/regex.rs:22:60 | LL | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); | ^^^ @@ -17,7 +17,7 @@ LL | let pipe_in_wrong_position_builder = RegexBuilder::new("|"); = help: the regex is unlikely to be useful as it is error: regex syntax error: invalid character class range, the start must be <= the end - --> tests/ui/regex.rs:23:42 + --> tests/ui/regex.rs:24:42 | LL | let wrong_char_ranice = Regex::new("[z-a]"); | ^^^ @@ -26,7 +26,7 @@ LL | let wrong_char_ranice = Regex::new("[z-a]"); = help: to override `-D warnings` add `#[allow(clippy::invalid_regex)]` error: regex syntax error: invalid character class range, the start must be <= the end - --> tests/ui/regex.rs:26:37 + --> tests/ui/regex.rs:27:37 | LL | let some_unicode = Regex::new("[é-è]"); | ^^^ @@ -35,13 +35,13 @@ error: regex parse error: ( ^ error: unclosed group - --> tests/ui/regex.rs:29:33 + --> tests/ui/regex.rs:30:33 | LL | let some_regex = Regex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ error: trivial regex - --> tests/ui/regex.rs:31:53 + --> tests/ui/regex.rs:33:53 | LL | let binary_pipe_in_wrong_position = BRegex::new("|"); | ^^^ @@ -52,7 +52,7 @@ error: regex parse error: ( ^ error: unclosed group - --> tests/ui/regex.rs:33:41 + --> tests/ui/regex.rs:35:41 | LL | let some_binary_regex = BRegex::new(OPENING_PAREN); | ^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ error: regex parse error: ( ^ error: unclosed group - --> tests/ui/regex.rs:34:56 + --> tests/ui/regex.rs:37:56 | LL | let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN); | ^^^^^^^^^^^^^ @@ -70,7 +70,7 @@ error: regex parse error: ( ^ error: unclosed group - --> tests/ui/regex.rs:46:37 + --> tests/ui/regex.rs:50:37 | LL | let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); | ^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ error: regex parse error: ( ^ error: unclosed group - --> tests/ui/regex.rs:47:39 + --> tests/ui/regex.rs:52:39 | LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); | ^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ error: regex parse error: \b\c ^^ error: unrecognized escape sequence - --> tests/ui/regex.rs:54:42 + --> tests/ui/regex.rs:60:42 | LL | let escaped_string_span = Regex::new("\\b\\c"); | ^^^^^^^^ @@ -96,19 +96,19 @@ LL | let escaped_string_span = Regex::new("\\b\\c"); = help: consider using a raw string literal: `r".."` error: regex syntax error: duplicate flag - --> tests/ui/regex.rs:56:34 + --> tests/ui/regex.rs:63:34 | LL | let aux_span = Regex::new("(?ixi)"); | ^ ^ error: regex syntax error: pattern can match invalid UTF-8 - --> tests/ui/regex.rs:62:53 + --> tests/ui/regex.rs:69:53 | LL | let invalid_utf8_should_lint = Regex::new("(?-u)."); | ^ error: trivial regex - --> tests/ui/regex.rs:67:33 + --> tests/ui/regex.rs:74:33 | LL | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ @@ -116,7 +116,7 @@ LL | let trivial_eq = Regex::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> tests/ui/regex.rs:70:48 + --> tests/ui/regex.rs:77:48 | LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ @@ -124,7 +124,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> tests/ui/regex.rs:73:42 + --> tests/ui/regex.rs:80:42 | LL | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ @@ -132,7 +132,7 @@ LL | let trivial_starts_with = Regex::new("^foobar"); = help: consider using `str::starts_with` error: trivial regex - --> tests/ui/regex.rs:76:40 + --> tests/ui/regex.rs:83:40 | LL | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ @@ -140,7 +140,7 @@ LL | let trivial_ends_with = Regex::new("foobar$"); = help: consider using `str::ends_with` error: trivial regex - --> tests/ui/regex.rs:79:39 + --> tests/ui/regex.rs:86:39 | LL | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ @@ -148,7 +148,7 @@ LL | let trivial_contains = Regex::new("foobar"); = help: consider using `str::contains` error: trivial regex - --> tests/ui/regex.rs:82:39 + --> tests/ui/regex.rs:89:39 | LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); = help: consider using `str::contains` error: trivial regex - --> tests/ui/regex.rs:85:40 + --> tests/ui/regex.rs:92:40 | LL | let trivial_backslash = Regex::new("a\\.b"); | ^^^^^^^ @@ -164,7 +164,7 @@ LL | let trivial_backslash = Regex::new("a\\.b"); = help: consider using `str::contains` error: trivial regex - --> tests/ui/regex.rs:89:36 + --> tests/ui/regex.rs:96:36 | LL | let trivial_empty = Regex::new(""); | ^^ @@ -172,7 +172,7 @@ LL | let trivial_empty = Regex::new(""); = help: the regex is unlikely to be useful as it is error: trivial regex - --> tests/ui/regex.rs:92:36 + --> tests/ui/regex.rs:99:36 | LL | let trivial_empty = Regex::new("^"); | ^^^ @@ -180,7 +180,7 @@ LL | let trivial_empty = Regex::new("^"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> tests/ui/regex.rs:95:36 + --> tests/ui/regex.rs:102:36 | LL | let trivial_empty = Regex::new("^$"); | ^^^^ @@ -188,7 +188,7 @@ LL | let trivial_empty = Regex::new("^$"); = help: consider using `str::is_empty` error: trivial regex - --> tests/ui/regex.rs:98:44 + --> tests/ui/regex.rs:105:44 | LL | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ @@ -196,13 +196,13 @@ LL | let binary_trivial_empty = BRegex::new("^$"); = help: consider using `str::is_empty` error: compiling a regex in a loop - --> tests/ui/regex.rs:125:21 + --> tests/ui/regex.rs:132:21 | LL | let regex = Regex::new("a.b"); | ^^^^^^^^^^ | help: move the regex construction outside this loop - --> tests/ui/regex.rs:122:5 + --> tests/ui/regex.rs:129:5 | LL | loop { | ^^^^ @@ -210,37 +210,37 @@ LL | loop { = help: to override `-D warnings` add `#[allow(clippy::regex_creation_in_loops)]` error: compiling a regex in a loop - --> tests/ui/regex.rs:127:21 + --> tests/ui/regex.rs:134:21 | LL | let regex = BRegex::new("a.b"); | ^^^^^^^^^^^ | help: move the regex construction outside this loop - --> tests/ui/regex.rs:122:5 + --> tests/ui/regex.rs:129:5 | LL | loop { | ^^^^ error: compiling a regex in a loop - --> tests/ui/regex.rs:133:25 + --> tests/ui/regex.rs:140:25 | LL | let regex = Regex::new("a.b"); | ^^^^^^^^^^ | help: move the regex construction outside this loop - --> tests/ui/regex.rs:122:5 + --> tests/ui/regex.rs:129:5 | LL | loop { | ^^^^ error: compiling a regex in a loop - --> tests/ui/regex.rs:138:32 + --> tests/ui/regex.rs:145:32 | LL | let nested_regex = Regex::new("a.b"); | ^^^^^^^^^^ | help: move the regex construction outside this loop - --> tests/ui/regex.rs:137:9 + --> tests/ui/regex.rs:144:9 | LL | for _ in 0..10 { | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed b/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed index aebf8712dd923..1ad7d8702bc00 100644 --- a/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed +++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed @@ -1,4 +1,5 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes #[clippy::cognitive_complexity = "1"] +//~^ ERROR: usage of deprecated attribute fn main() {} diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.rs b/src/tools/clippy/tests/ui/renamed_builtin_attr.rs index 6c18151195f54..0fb43b7f49016 100644 --- a/src/tools/clippy/tests/ui/renamed_builtin_attr.rs +++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes #[clippy::cyclomatic_complexity = "1"] +//~^ ERROR: usage of deprecated attribute fn main() {} diff --git a/src/tools/clippy/tests/ui/repeat_once.fixed b/src/tools/clippy/tests/ui/repeat_once.fixed index 72e97350a0c89..e739e176f0acd 100644 --- a/src/tools/clippy/tests/ui/repeat_once.fixed +++ b/src/tools/clippy/tests/ui/repeat_once.fixed @@ -7,9 +7,15 @@ fn main() { let slice = [1; 5]; let a = [1; 5].to_vec(); + //~^ repeat_once let b = slice.to_vec(); + //~^ repeat_once let c = "hello".to_string(); + //~^ repeat_once let d = "hi".to_string(); + //~^ repeat_once let e = s.to_string(); + //~^ repeat_once let f = string.clone(); + //~^ repeat_once } diff --git a/src/tools/clippy/tests/ui/repeat_once.rs b/src/tools/clippy/tests/ui/repeat_once.rs index 7557c4d0bd417..89ab94bbaee85 100644 --- a/src/tools/clippy/tests/ui/repeat_once.rs +++ b/src/tools/clippy/tests/ui/repeat_once.rs @@ -7,9 +7,15 @@ fn main() { let slice = [1; 5]; let a = [1; 5].repeat(1); + //~^ repeat_once let b = slice.repeat(1); + //~^ repeat_once let c = "hello".repeat(N); + //~^ repeat_once let d = "hi".repeat(1); + //~^ repeat_once let e = s.repeat(1); + //~^ repeat_once let f = string.repeat(1); + //~^ repeat_once } diff --git a/src/tools/clippy/tests/ui/repeat_once.stderr b/src/tools/clippy/tests/ui/repeat_once.stderr index 6996dc5eee7d3..3db7a3568f8e6 100644 --- a/src/tools/clippy/tests/ui/repeat_once.stderr +++ b/src/tools/clippy/tests/ui/repeat_once.stderr @@ -8,31 +8,31 @@ LL | let a = [1; 5].repeat(1); = help: to override `-D warnings` add `#[allow(clippy::repeat_once)]` error: calling `repeat(1)` on slice - --> tests/ui/repeat_once.rs:10:13 + --> tests/ui/repeat_once.rs:11:13 | LL | let b = slice.repeat(1); | ^^^^^^^^^^^^^^^ help: consider using `.to_vec()` instead: `slice.to_vec()` error: calling `repeat(1)` on str - --> tests/ui/repeat_once.rs:11:13 + --> tests/ui/repeat_once.rs:13:13 | LL | let c = "hello".repeat(N); | ^^^^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hello".to_string()` error: calling `repeat(1)` on str - --> tests/ui/repeat_once.rs:12:13 + --> tests/ui/repeat_once.rs:15:13 | LL | let d = "hi".repeat(1); | ^^^^^^^^^^^^^^ help: consider using `.to_string()` instead: `"hi".to_string()` error: calling `repeat(1)` on str - --> tests/ui/repeat_once.rs:13:13 + --> tests/ui/repeat_once.rs:17:13 | LL | let e = s.repeat(1); | ^^^^^^^^^^^ help: consider using `.to_string()` instead: `s.to_string()` error: calling `repeat(1)` on a string literal - --> tests/ui/repeat_once.rs:14:13 + --> tests/ui/repeat_once.rs:19:13 | LL | let f = string.repeat(1); | ^^^^^^^^^^^^^^^^ help: consider using `.clone()` instead: `string.clone()` diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed index f72b61b5f6cd8..8a3b0b4f193f9 100644 --- a/src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.fixed @@ -4,13 +4,13 @@ fn main() { { (0..123).map(|_| Vec::<()>::with_capacity(42)).collect::>(); - //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + //~^ repeat_vec_with_capacity } { let n = 123; (0..n).map(|_| Vec::<()>::with_capacity(42)).collect::>(); - //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + //~^ repeat_vec_with_capacity } { @@ -25,7 +25,7 @@ fn main() { { std::iter::repeat_with(|| Vec::<()>::with_capacity(42)); - //~^ ERROR: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity + //~^ repeat_vec_with_capacity } { @@ -37,3 +37,8 @@ fn main() { from_macro!(Vec::<()>::with_capacity(42)); } } + +#[clippy::msrv = "1.27.0"] +fn msrv_check() { + std::iter::repeat(Vec::<()>::with_capacity(42)); +} diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs index c0cc81f784365..011202d84757d 100644 --- a/src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity.rs @@ -4,13 +4,13 @@ fn main() { { vec![Vec::<()>::with_capacity(42); 123]; - //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + //~^ repeat_vec_with_capacity } { let n = 123; vec![Vec::<()>::with_capacity(42); n]; - //~^ ERROR: repeating `Vec::with_capacity` using `vec![x; n]`, which does not retain capacity + //~^ repeat_vec_with_capacity } { @@ -25,7 +25,7 @@ fn main() { { std::iter::repeat(Vec::<()>::with_capacity(42)); - //~^ ERROR: repeating `Vec::with_capacity` using `iter::repeat`, which does not retain capacity + //~^ repeat_vec_with_capacity } { @@ -37,3 +37,8 @@ fn main() { from_macro!(Vec::<()>::with_capacity(42)); } } + +#[clippy::msrv = "1.27.0"] +fn msrv_check() { + std::iter::repeat(Vec::<()>::with_capacity(42)); +} diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.fixed b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.fixed index ef316f1def41c..dcff18723b6ce 100644 --- a/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.fixed +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.fixed @@ -7,4 +7,5 @@ use alloc::vec::Vec; fn nostd() { let _: Vec> = core::iter::repeat_with(|| Vec::with_capacity(42)).take(123).collect(); + //~^ repeat_vec_with_capacity } diff --git a/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.rs b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.rs index 83b418a566749..84cc78de35ec8 100644 --- a/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.rs +++ b/src/tools/clippy/tests/ui/repeat_vec_with_capacity_nostd.rs @@ -7,4 +7,5 @@ use alloc::vec::Vec; fn nostd() { let _: Vec> = iter::repeat(Vec::with_capacity(42)).take(123).collect(); + //~^ repeat_vec_with_capacity } diff --git a/src/tools/clippy/tests/ui/repl_uninit.rs b/src/tools/clippy/tests/ui/repl_uninit.rs index 01bdf79e64225..e9469d4c5e2ff 100644 --- a/src/tools/clippy/tests/ui/repl_uninit.rs +++ b/src/tools/clippy/tests/ui/repl_uninit.rs @@ -13,22 +13,24 @@ fn main() { // the following is UB if `might_panic` panics unsafe { let taken_v = mem::replace(&mut v, mem::uninitialized()); - //~^ ERROR: replacing with `mem::uninitialized()` - //~| NOTE: `-D clippy::mem-replace-with-uninit` implied by `-D warnings` + //~^ mem_replace_with_uninit + let new_v = might_panic(taken_v); std::mem::forget(mem::replace(&mut v, new_v)); } unsafe { let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assume_init()); - //~^ ERROR: replacing with `mem::MaybeUninit::uninit().assume_init()` + //~^ mem_replace_with_uninit + let new_v = might_panic(taken_v); std::mem::forget(mem::replace(&mut v, new_v)); } unsafe { let taken_v = mem::replace(&mut v, mem::zeroed()); - //~^ ERROR: replacing with `mem::zeroed()` + //~^ mem_replace_with_uninit + let new_v = might_panic(taken_v); std::mem::forget(mem::replace(&mut v, new_v)); } @@ -41,6 +43,7 @@ fn main() { // this is still not OK, because uninit let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) }; - //~^ ERROR: replacing with `mem::uninitialized()` + //~^ mem_replace_with_uninit + *uref = taken_u + 1; } diff --git a/src/tools/clippy/tests/ui/repl_uninit.stderr b/src/tools/clippy/tests/ui/repl_uninit.stderr index 645c4a16a07eb..08b0b265942d7 100644 --- a/src/tools/clippy/tests/ui/repl_uninit.stderr +++ b/src/tools/clippy/tests/ui/repl_uninit.stderr @@ -14,7 +14,7 @@ LL | let taken_v = mem::replace(&mut v, mem::MaybeUninit::uninit().assum | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(&mut v)` error: replacing with `mem::zeroed()` - --> tests/ui/repl_uninit.rs:30:23 + --> tests/ui/repl_uninit.rs:31:23 | LL | let taken_v = mem::replace(&mut v, mem::zeroed()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | let taken_v = mem::replace(&mut v, mem::zeroed()); = help: consider using a default value or the `take_mut` crate instead error: replacing with `mem::uninitialized()` - --> tests/ui/repl_uninit.rs:43:28 + --> tests/ui/repl_uninit.rs:45:28 | LL | let taken_u = unsafe { mem::replace(uref, mem::uninitialized()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::ptr::read(uref)` diff --git a/src/tools/clippy/tests/ui/repr_packed_without_abi.rs b/src/tools/clippy/tests/ui/repr_packed_without_abi.rs index 16b5ededee990..c5f1852e98b81 100644 --- a/src/tools/clippy/tests/ui/repr_packed_without_abi.rs +++ b/src/tools/clippy/tests/ui/repr_packed_without_abi.rs @@ -2,12 +2,14 @@ #[repr(packed)] struct NetworkPacketHeader { + //~^ repr_packed_without_abi header_length: u8, header_version: u16, } #[repr(packed)] union Foo { + //~^ repr_packed_without_abi a: u8, b: u16, } diff --git a/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr b/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr index 4f7acd00db3d8..d1078b3e8e48e 100644 --- a/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr +++ b/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr @@ -4,6 +4,7 @@ error: item uses `packed` representation without ABI-qualification LL | #[repr(packed)] | ------ `packed` representation set here LL | / struct NetworkPacketHeader { +LL | | LL | | header_length: u8, LL | | header_version: u16, LL | | } @@ -18,11 +19,12 @@ LL | #![deny(clippy::repr_packed_without_abi)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: item uses `packed` representation without ABI-qualification - --> tests/ui/repr_packed_without_abi.rs:10:1 + --> tests/ui/repr_packed_without_abi.rs:11:1 | LL | #[repr(packed)] | ------ `packed` representation set here LL | / union Foo { +LL | | LL | | a: u8, LL | | b: u16, LL | | } diff --git a/src/tools/clippy/tests/ui/reserve_after_initialization.rs b/src/tools/clippy/tests/ui/reserve_after_initialization.rs index b57a8e162c539..7f79dac465361 100644 --- a/src/tools/clippy/tests/ui/reserve_after_initialization.rs +++ b/src/tools/clippy/tests/ui/reserve_after_initialization.rs @@ -8,6 +8,7 @@ use proc_macros::{external, with_span}; // Should lint fn standard() { let mut v1: Vec = vec![]; + //~^ reserve_after_initialization v1.reserve(10); } @@ -15,6 +16,7 @@ fn standard() { fn capacity_as_expr() { let capacity = 10; let mut v2: Vec = vec![]; + //~^ reserve_after_initialization v2.reserve(capacity); } @@ -33,6 +35,7 @@ fn called_with_capacity() { fn assign_expression() { let mut v5: Vec = Vec::new(); v5 = Vec::new(); + //~^ reserve_after_initialization v5.reserve(10); } diff --git a/src/tools/clippy/tests/ui/reserve_after_initialization.stderr b/src/tools/clippy/tests/ui/reserve_after_initialization.stderr index b6dbebb3f14c2..e79b59a35d418 100644 --- a/src/tools/clippy/tests/ui/reserve_after_initialization.stderr +++ b/src/tools/clippy/tests/ui/reserve_after_initialization.stderr @@ -2,6 +2,7 @@ error: call to `reserve` immediately after creation --> tests/ui/reserve_after_initialization.rs:10:5 | LL | / let mut v1: Vec = vec![]; +LL | | LL | | v1.reserve(10); | |___________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `let mut v1: Vec = Vec::with_capacity(10);` | @@ -9,16 +10,18 @@ LL | | v1.reserve(10); = help: to override `-D warnings` add `#[allow(clippy::reserve_after_initialization)]` error: call to `reserve` immediately after creation - --> tests/ui/reserve_after_initialization.rs:17:5 + --> tests/ui/reserve_after_initialization.rs:18:5 | LL | / let mut v2: Vec = vec![]; +LL | | LL | | v2.reserve(capacity); | |_________________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `let mut v2: Vec = Vec::with_capacity(capacity);` error: call to `reserve` immediately after creation - --> tests/ui/reserve_after_initialization.rs:35:5 + --> tests/ui/reserve_after_initialization.rs:37:5 | LL | / v5 = Vec::new(); +LL | | LL | | v5.reserve(10); | |___________________^ help: consider using `Vec::with_capacity(/* Space hint */)`: `v5 = Vec::with_capacity(10);` diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs index 51fe346d09264..bede01688972a 100644 --- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs +++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs @@ -21,16 +21,16 @@ fn main() { match a_struct { A { a: 5, b: 42, c: "", .. } => {}, // Lint - //~^ ERROR: unnecessary use of `..` pattern in struct binding. All fields were alr + //~^ rest_pat_in_fully_bound_structs A { a: 0, b: 0, c: "", .. } => {}, // Lint - //~^ ERROR: unnecessary use of `..` pattern in struct binding. All fields were alr + //~^ rest_pat_in_fully_bound_structs _ => {}, } match a_struct { A { a: 5, b: 42, .. } => {}, A { a: 0, b: 0, c: "", .. } => {}, // Lint - //~^ ERROR: unnecessary use of `..` pattern in struct binding. All fields were alr + //~^ rest_pat_in_fully_bound_structs _ => {}, } diff --git a/src/tools/clippy/tests/ui/result_filter_map.rs b/src/tools/clippy/tests/ui/result_filter_map.rs index bfe47ffcf380c..ebd9c4288e3b7 100644 --- a/src/tools/clippy/tests/ui/result_filter_map.rs +++ b/src/tools/clippy/tests/ui/result_filter_map.rs @@ -11,25 +11,25 @@ fn main() { let _ = vec![Ok(1) as Result] .into_iter() .filter(Result::is_ok) - //~^ ERROR: `filter` for `Ok` followed by `unwrap` + //~^ result_filter_map .map(Result::unwrap); let _ = vec![Ok(1) as Result] .into_iter() .filter(|o| o.is_ok()) - //~^ ERROR: `filter` for `Ok` followed by `unwrap` + //~^ result_filter_map .map(|o| o.unwrap()); let _ = vec![1] .into_iter() .map(odds_out) .filter(Result::is_ok) - //~^ ERROR: `filter` for `Ok` followed by `unwrap` + //~^ result_filter_map .map(Result::unwrap); let _ = vec![1] .into_iter() .map(odds_out) .filter(|o| o.is_ok()) - //~^ ERROR: `filter` for `Ok` followed by `unwrap` + //~^ result_filter_map .map(|o| o.unwrap()); } diff --git a/src/tools/clippy/tests/ui/result_large_err.rs b/src/tools/clippy/tests/ui/result_large_err.rs index 9c39f023da2da..fa57b3f553fc9 100644 --- a/src/tools/clippy/tests/ui/result_large_err.rs +++ b/src/tools/clippy/tests/ui/result_large_err.rs @@ -8,7 +8,8 @@ pub fn small_err() -> Result<(), u128> { } pub fn large_err() -> Result<(), [u8; 512]> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } @@ -20,19 +21,22 @@ pub struct FullyDefinedLargeError { impl FullyDefinedLargeError { pub fn ret() -> Result<(), Self> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } } pub fn struct_error() -> Result<(), FullyDefinedLargeError> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } type Fdlr = std::result::Result; pub fn large_err_via_type_alias(x: T) -> Fdlr { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(x) } @@ -41,7 +45,8 @@ pub fn param_small_error() -> Result<(), (R, u128)> { } pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeError)> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } @@ -53,7 +58,8 @@ pub enum LargeErrorVariants { impl LargeErrorVariants<()> { pub fn large_enum_error() -> Result<(), Self> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } } @@ -66,14 +72,16 @@ enum MultipleLargeVariants { impl MultipleLargeVariants { fn large_enum_error() -> Result<(), Self> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } } trait TraitForcesLargeError { fn large_error() -> Result<(), [u8; 512]> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } } @@ -93,7 +101,8 @@ pub union FullyDefinedUnionError { } pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } @@ -103,7 +112,8 @@ pub union UnionError { } pub fn param_large_union() -> Result<(), UnionError> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } @@ -113,12 +123,14 @@ pub struct ArrayError { } pub fn array_error_subst() -> Result<(), ArrayError> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { - //~^ ERROR: the `Err`-variant returned from this function is very large + //~^ result_large_err + Ok(()) } diff --git a/src/tools/clippy/tests/ui/result_large_err.stderr b/src/tools/clippy/tests/ui/result_large_err.stderr index 1dff3f9efe81c..72fbc3f589615 100644 --- a/src/tools/clippy/tests/ui/result_large_err.stderr +++ b/src/tools/clippy/tests/ui/result_large_err.stderr @@ -9,7 +9,7 @@ LL | pub fn large_err() -> Result<(), [u8; 512]> { = help: to override `-D warnings` add `#[allow(clippy::result_large_err)]` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:22:21 + --> tests/ui/result_large_err.rs:23:21 | LL | pub fn ret() -> Result<(), Self> { | ^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes @@ -17,7 +17,7 @@ LL | pub fn ret() -> Result<(), Self> { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:28:26 + --> tests/ui/result_large_err.rs:30:26 | LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 240 bytes @@ -25,7 +25,7 @@ LL | pub fn struct_error() -> Result<(), FullyDefinedLargeError> { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:34:45 + --> tests/ui/result_large_err.rs:37:45 | LL | pub fn large_err_via_type_alias(x: T) -> Fdlr { | ^^^^^^^ the `Err`-variant is at least 240 bytes @@ -33,7 +33,7 @@ LL | pub fn large_err_via_type_alias(x: T) -> Fdlr { = help: try reducing the size of `FullyDefinedLargeError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:43:34 + --> tests/ui/result_large_err.rs:47:34 | LL | pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeError)> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 256 bytes @@ -41,7 +41,7 @@ LL | pub fn param_large_error() -> Result<(), (u128, R, FullyDefinedLargeErro = help: try reducing the size of `(u128, R, FullyDefinedLargeError)`, for example by boxing large elements or replacing it with `Box<(u128, R, FullyDefinedLargeError)>` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:55:34 + --> tests/ui/result_large_err.rs:60:34 | LL | _Omg([u8; 512]), | --------------- the largest variant contains at least 512 bytes @@ -52,7 +52,7 @@ LL | pub fn large_enum_error() -> Result<(), Self> { = help: try reducing the size of `LargeErrorVariants<()>`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:68:30 + --> tests/ui/result_large_err.rs:74:30 | LL | _Biggest([u8; 1024]), | -------------------- the largest variant contains at least 1024 bytes @@ -65,7 +65,7 @@ LL | fn large_enum_error() -> Result<(), Self> { = help: try reducing the size of `MultipleLargeVariants`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:75:25 + --> tests/ui/result_large_err.rs:82:25 | LL | fn large_error() -> Result<(), [u8; 512]> { | ^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -73,7 +73,7 @@ LL | fn large_error() -> Result<(), [u8; 512]> { = help: try reducing the size of `[u8; 512]`, for example by boxing large elements or replacing it with `Box<[u8; 512]>` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:95:29 + --> tests/ui/result_large_err.rs:103:29 | LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -81,7 +81,7 @@ LL | pub fn large_union_err() -> Result<(), FullyDefinedUnionError> { = help: try reducing the size of `FullyDefinedUnionError`, for example by boxing large elements or replacing it with `Box` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:105:40 + --> tests/ui/result_large_err.rs:114:40 | LL | pub fn param_large_union() -> Result<(), UnionError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 512 bytes @@ -89,7 +89,7 @@ LL | pub fn param_large_union() -> Result<(), UnionError> { = help: try reducing the size of `UnionError`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:115:34 + --> tests/ui/result_large_err.rs:125:34 | LL | pub fn array_error_subst() -> Result<(), ArrayError> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes @@ -97,7 +97,7 @@ LL | pub fn array_error_subst() -> Result<(), ArrayError> { = help: try reducing the size of `ArrayError`, for example by boxing large elements or replacing it with `Box>` error: the `Err`-variant returned from this function is very large - --> tests/ui/result_large_err.rs:120:31 + --> tests/ui/result_large_err.rs:131:31 | LL | pub fn array_error() -> Result<(), ArrayError<(i32, T), U>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the `Err`-variant is at least 128 bytes diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed index cf42b24b2dda7..4cf218b846424 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed @@ -3,12 +3,14 @@ fn main() { let opt: Result = Ok(1); let _ = opt.ok(); - //~^ ERROR: called `map_or(None, Some)` on a `Result` value + //~^ result_map_or_into_option + let _ = opt.ok(); - //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + //~^ result_map_or_into_option + #[rustfmt::skip] let _ = opt.ok(); - //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + //~^ result_map_or_into_option let rewrap = |s: u32| -> Option { Some(s) }; diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.rs b/src/tools/clippy/tests/ui/result_map_or_into_option.rs index cdb45d6b82a0a..9a0bde8569e8f 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.rs +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.rs @@ -3,12 +3,14 @@ fn main() { let opt: Result = Ok(1); let _ = opt.map_or(None, Some); - //~^ ERROR: called `map_or(None, Some)` on a `Result` value + //~^ result_map_or_into_option + let _ = opt.map_or_else(|_| None, Some); - //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + //~^ result_map_or_into_option + #[rustfmt::skip] let _ = opt.map_or_else(|_| { None }, Some); - //~^ ERROR: called `map_or_else(|_| None, Some)` on a `Result` value + //~^ result_map_or_into_option let rewrap = |s: u32| -> Option { Some(s) }; diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.stderr b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr index 4cb510d77a060..f9058d35e6c6a 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.stderr +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.stderr @@ -8,13 +8,13 @@ LL | let _ = opt.map_or(None, Some); = help: to override `-D warnings` add `#[allow(clippy::result_map_or_into_option)]` error: called `map_or_else(|_| None, Some)` on a `Result` value - --> tests/ui/result_map_or_into_option.rs:7:13 + --> tests/ui/result_map_or_into_option.rs:8:13 | LL | let _ = opt.map_or_else(|_| None, Some); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` error: called `map_or_else(|_| None, Some)` on a `Result` value - --> tests/ui/result_map_or_into_option.rs:10:13 + --> tests/ui/result_map_or_into_option.rs:12:13 | LL | let _ = opt.map_or_else(|_| { None }, Some); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `ok`: `opt.ok()` diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed index 3890f916b606e..6bee013c3f470 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed @@ -32,50 +32,68 @@ fn result_map_unit_fn() { let _: Result<(), usize> = x.field.map(do_nothing); if let Ok(x_field) = x.field { do_nothing(x_field) } + //~^ result_map_unit_fn if let Ok(x_field) = x.field { do_nothing(x_field) } + //~^ result_map_unit_fn if let Ok(x_field) = x.field { diverge(x_field) } + //~^ result_map_unit_fn let captured = 10; if let Ok(value) = x.field { do_nothing(value + captured) }; let _: Result<(), usize> = x.field.map(|value| do_nothing(value + captured)); if let Ok(value) = x.field { x.do_result_nothing(value + captured) } + //~^ result_map_unit_fn if let Ok(value) = x.field { x.do_result_plus_one(value + captured); } + //~^ result_map_unit_fn if let Ok(value) = x.field { do_nothing(value + captured) } + //~^ result_map_unit_fn if let Ok(value) = x.field { do_nothing(value + captured) } + //~^ result_map_unit_fn if let Ok(value) = x.field { do_nothing(value + captured); } + //~^ result_map_unit_fn if let Ok(value) = x.field { do_nothing(value + captured); } + //~^ result_map_unit_fn if let Ok(value) = x.field { diverge(value + captured) } + //~^ result_map_unit_fn if let Ok(value) = x.field { diverge(value + captured) } + //~^ result_map_unit_fn if let Ok(value) = x.field { diverge(value + captured); } + //~^ result_map_unit_fn if let Ok(value) = x.field { diverge(value + captured); } + //~^ result_map_unit_fn x.field.map(|value| plus_one(value + captured)); x.field.map(|value| { plus_one(value + captured) }); if let Ok(value) = x.field { let y = plus_one(value + captured); } + //~^ result_map_unit_fn if let Ok(value) = x.field { plus_one(value + captured); } + //~^ result_map_unit_fn if let Ok(value) = x.field { plus_one(value + captured); } + //~^ result_map_unit_fn if let Ok(ref value) = x.field { do_nothing(value + captured) } + //~^ result_map_unit_fn if let Ok(value) = x.field { println!("{:?}", value) } + //~^ result_map_unit_fn } fn main() {} diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs index c3f5aca7bfbeb..a206cfe6842ff 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs @@ -32,50 +32,68 @@ fn result_map_unit_fn() { let _: Result<(), usize> = x.field.map(do_nothing); x.field.map(do_nothing); + //~^ result_map_unit_fn x.field.map(do_nothing); + //~^ result_map_unit_fn x.field.map(diverge); + //~^ result_map_unit_fn let captured = 10; if let Ok(value) = x.field { do_nothing(value + captured) }; let _: Result<(), usize> = x.field.map(|value| do_nothing(value + captured)); x.field.map(|value| x.do_result_nothing(value + captured)); + //~^ result_map_unit_fn x.field.map(|value| { x.do_result_plus_one(value + captured); }); + //~^ result_map_unit_fn x.field.map(|value| do_nothing(value + captured)); + //~^ result_map_unit_fn x.field.map(|value| { do_nothing(value + captured) }); + //~^ result_map_unit_fn x.field.map(|value| { do_nothing(value + captured); }); + //~^ result_map_unit_fn x.field.map(|value| { { do_nothing(value + captured); } }); + //~^ result_map_unit_fn x.field.map(|value| diverge(value + captured)); + //~^ result_map_unit_fn x.field.map(|value| { diverge(value + captured) }); + //~^ result_map_unit_fn x.field.map(|value| { diverge(value + captured); }); + //~^ result_map_unit_fn x.field.map(|value| { { diverge(value + captured); } }); + //~^ result_map_unit_fn x.field.map(|value| plus_one(value + captured)); x.field.map(|value| { plus_one(value + captured) }); x.field.map(|value| { let y = plus_one(value + captured); }); + //~^ result_map_unit_fn x.field.map(|value| { plus_one(value + captured); }); + //~^ result_map_unit_fn x.field.map(|value| { { plus_one(value + captured); } }); + //~^ result_map_unit_fn x.field.map(|ref value| { do_nothing(value + captured) }); + //~^ result_map_unit_fn x.field.map(|value| println!("{:?}", value)); + //~^ result_map_unit_fn } fn main() {} diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr index 4f3bc2e954495..eca844e06cc06 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.stderr @@ -10,7 +10,7 @@ LL | x.field.map(do_nothing); = help: to override `-D warnings` add `#[allow(clippy::result_map_unit_fn)]` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:36:5 + --> tests/ui/result_map_unit_fn_fixable.rs:37:5 | LL | x.field.map(do_nothing); | ^^^^^^^^^^^^^^^^^^^^^^^- @@ -18,7 +18,7 @@ LL | x.field.map(do_nothing); | help: try: `if let Ok(x_field) = x.field { do_nothing(x_field) }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:38:5 + --> tests/ui/result_map_unit_fn_fixable.rs:40:5 | LL | x.field.map(diverge); | ^^^^^^^^^^^^^^^^^^^^- @@ -26,7 +26,7 @@ LL | x.field.map(diverge); | help: try: `if let Ok(x_field) = x.field { diverge(x_field) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:44:5 + --> tests/ui/result_map_unit_fn_fixable.rs:47:5 | LL | x.field.map(|value| x.do_result_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -34,7 +34,7 @@ LL | x.field.map(|value| x.do_result_nothing(value + captured)); | help: try: `if let Ok(value) = x.field { x.do_result_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:46:5 + --> tests/ui/result_map_unit_fn_fixable.rs:50:5 | LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -42,7 +42,7 @@ LL | x.field.map(|value| { x.do_result_plus_one(value + captured); }); | help: try: `if let Ok(value) = x.field { x.do_result_plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:49:5 + --> tests/ui/result_map_unit_fn_fixable.rs:54:5 | LL | x.field.map(|value| do_nothing(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -50,7 +50,7 @@ LL | x.field.map(|value| do_nothing(value + captured)); | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:51:5 + --> tests/ui/result_map_unit_fn_fixable.rs:57:5 | LL | x.field.map(|value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -58,7 +58,7 @@ LL | x.field.map(|value| { do_nothing(value + captured) }); | help: try: `if let Ok(value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:53:5 + --> tests/ui/result_map_unit_fn_fixable.rs:60:5 | LL | x.field.map(|value| { do_nothing(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -66,7 +66,7 @@ LL | x.field.map(|value| { do_nothing(value + captured); }); | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:55:5 + --> tests/ui/result_map_unit_fn_fixable.rs:63:5 | LL | x.field.map(|value| { { do_nothing(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -74,7 +74,7 @@ LL | x.field.map(|value| { { do_nothing(value + captured); } }); | help: try: `if let Ok(value) = x.field { do_nothing(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:58:5 + --> tests/ui/result_map_unit_fn_fixable.rs:67:5 | LL | x.field.map(|value| diverge(value + captured)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -82,7 +82,7 @@ LL | x.field.map(|value| diverge(value + captured)); | help: try: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:60:5 + --> tests/ui/result_map_unit_fn_fixable.rs:70:5 | LL | x.field.map(|value| { diverge(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -90,7 +90,7 @@ LL | x.field.map(|value| { diverge(value + captured) }); | help: try: `if let Ok(value) = x.field { diverge(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:62:5 + --> tests/ui/result_map_unit_fn_fixable.rs:73:5 | LL | x.field.map(|value| { diverge(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -98,7 +98,7 @@ LL | x.field.map(|value| { diverge(value + captured); }); | help: try: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:64:5 + --> tests/ui/result_map_unit_fn_fixable.rs:76:5 | LL | x.field.map(|value| { { diverge(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -106,7 +106,7 @@ LL | x.field.map(|value| { { diverge(value + captured); } }); | help: try: `if let Ok(value) = x.field { diverge(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:69:5 + --> tests/ui/result_map_unit_fn_fixable.rs:82:5 | LL | x.field.map(|value| { let y = plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -114,7 +114,7 @@ LL | x.field.map(|value| { let y = plus_one(value + captured); }); | help: try: `if let Ok(value) = x.field { let y = plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:71:5 + --> tests/ui/result_map_unit_fn_fixable.rs:85:5 | LL | x.field.map(|value| { plus_one(value + captured); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -122,7 +122,7 @@ LL | x.field.map(|value| { plus_one(value + captured); }); | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:73:5 + --> tests/ui/result_map_unit_fn_fixable.rs:88:5 | LL | x.field.map(|value| { { plus_one(value + captured); } }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -130,7 +130,7 @@ LL | x.field.map(|value| { { plus_one(value + captured); } }); | help: try: `if let Ok(value) = x.field { plus_one(value + captured); }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:76:5 + --> tests/ui/result_map_unit_fn_fixable.rs:92:5 | LL | x.field.map(|ref value| { do_nothing(value + captured) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -138,7 +138,7 @@ LL | x.field.map(|ref value| { do_nothing(value + captured) }); | help: try: `if let Ok(ref value) = x.field { do_nothing(value + captured) }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_fixable.rs:78:5 + --> tests/ui/result_map_unit_fn_fixable.rs:95:5 | LL | x.field.map(|value| println!("{:?}", value)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs index 62798b6d3d6f3..fe3d8ece39f4c 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.rs @@ -21,33 +21,39 @@ fn result_map_unit_fn() { let x = HasResult { field: Ok(10) }; x.field.map(|value| { do_nothing(value); do_nothing(value) }); - //~^ ERROR: called `map(f)` on an `Result` value where `f` is a closure that returns t - //~| NOTE: `-D clippy::result-map-unit-fn` implied by `-D warnings` + //~^ result_map_unit_fn + + x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); - //~^ ERROR: called `map(f)` on an `Result` value where `f` is a closure that returns t + //~^ result_map_unit_fn + // Suggestion for the let block should be `{ ... }` as it's too difficult to build a // proper suggestion for these cases x.field.map(|value| { - //~^ ERROR: called `map(f)` on an `Result` value where `f` is a closure that returns t + //~^ result_map_unit_fn + do_nothing(value); do_nothing(value) }); x.field.map(|value| { do_nothing(value); do_nothing(value); }); - //~^ ERROR: called `map(f)` on an `Result` value where `f` is a closure that returns t + //~^ result_map_unit_fn + // The following should suggest `if let Ok(_X) ...` as it's difficult to generate a proper let variable name for them let res: Result = Ok(42).map(diverge); "12".parse::().map(diverge); - //~^ ERROR: called `map(f)` on an `Result` value where `f` is a function that returns + //~^ result_map_unit_fn + let res: Result<(), usize> = Ok(plus_one(1)).map(do_nothing); // Should suggest `if let Ok(_y) ...` to not override the existing foo variable let y: Result = Ok(42); y.map(do_nothing); - //~^ ERROR: called `map(f)` on an `Result` value where `f` is a function that returns + //~^ result_map_unit_fn + } fn main() {} diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr index d69c86c70e291..a6e38d808afa7 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_unfixable.stderr @@ -10,7 +10,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value) }); = help: to override `-D warnings` add `#[allow(clippy::result_map_unit_fn)]` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_unfixable.rs:27:5 + --> tests/ui/result_map_unit_fn_unfixable.rs:28:5 | LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -18,10 +18,11 @@ LL | x.field.map(|value| if value > 0 { do_nothing(value); do_nothing(value) | help: try: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_unfixable.rs:32:5 + --> tests/ui/result_map_unit_fn_unfixable.rs:34:5 | LL | // x.field.map(|value| { LL | || +LL | || LL | || do_nothing(value); LL | || do_nothing(value) LL | || }); @@ -30,7 +31,7 @@ LL | || }); | error: called `map(f)` on an `Result` value where `f` is a closure that returns the unit type `()` - --> tests/ui/result_map_unit_fn_unfixable.rs:37:5 + --> tests/ui/result_map_unit_fn_unfixable.rs:40:5 | LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -38,7 +39,7 @@ LL | x.field.map(|value| { do_nothing(value); do_nothing(value); }); | help: try: `if let Ok(value) = x.field { ... }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` - --> tests/ui/result_map_unit_fn_unfixable.rs:42:5 + --> tests/ui/result_map_unit_fn_unfixable.rs:46:5 | LL | "12".parse::().map(diverge); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- @@ -46,7 +47,7 @@ LL | "12".parse::().map(diverge); | help: try: `if let Ok(a) = "12".parse::() { diverge(a) }` error: called `map(f)` on an `Result` value where `f` is a function that returns the unit type `()` - --> tests/ui/result_map_unit_fn_unfixable.rs:49:5 + --> tests/ui/result_map_unit_fn_unfixable.rs:54:5 | LL | y.map(do_nothing); | ^^^^^^^^^^^^^^^^^- diff --git a/src/tools/clippy/tests/ui/result_unit_error.rs b/src/tools/clippy/tests/ui/result_unit_error.rs index f3159f2e95154..ddbe0eb556c85 100644 --- a/src/tools/clippy/tests/ui/result_unit_error.rs +++ b/src/tools/clippy/tests/ui/result_unit_error.rs @@ -1,7 +1,8 @@ #![warn(clippy::result_unit_err)] pub fn returns_unit_error() -> Result { - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err + Err(()) } @@ -11,10 +12,11 @@ fn private_unit_errors() -> Result { pub trait HasUnitError { fn get_that_error(&self) -> Result; - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err fn get_this_one_too(&self) -> Result { - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err + Err(()) } } @@ -33,7 +35,8 @@ pub struct UnitErrorHolder; impl UnitErrorHolder { pub fn unit_error(&self) -> Result { - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err + Ok(0) } } @@ -43,7 +46,8 @@ pub mod issue_6546 { type ResInv = Result; pub fn should_lint() -> ResInv<(), usize> { - //~^ ERROR: this returns a `Result<_, ()>` + //~^ result_unit_err + Ok(0) } diff --git a/src/tools/clippy/tests/ui/result_unit_error.stderr b/src/tools/clippy/tests/ui/result_unit_error.stderr index e869a31597752..d6c0924d88689 100644 --- a/src/tools/clippy/tests/ui/result_unit_error.stderr +++ b/src/tools/clippy/tests/ui/result_unit_error.stderr @@ -9,7 +9,7 @@ LL | pub fn returns_unit_error() -> Result { = help: to override `-D warnings` add `#[allow(clippy::result_unit_err)]` error: this returns a `Result<_, ()>` - --> tests/ui/result_unit_error.rs:13:5 + --> tests/ui/result_unit_error.rs:14:5 | LL | fn get_that_error(&self) -> Result; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn get_that_error(&self) -> Result; = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> tests/ui/result_unit_error.rs:16:5 + --> tests/ui/result_unit_error.rs:17:5 | LL | fn get_this_one_too(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | fn get_this_one_too(&self) -> Result { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> tests/ui/result_unit_error.rs:35:5 + --> tests/ui/result_unit_error.rs:37:5 | LL | pub fn unit_error(&self) -> Result { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | pub fn unit_error(&self) -> Result { = help: use a custom `Error` type instead error: this returns a `Result<_, ()>` - --> tests/ui/result_unit_error.rs:45:5 + --> tests/ui/result_unit_error.rs:48:5 | LL | pub fn should_lint() -> ResInv<(), usize> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs index c9f4996c36899..8a1849b8490ab 100644 --- a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs +++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs @@ -10,6 +10,7 @@ pub fn returns_unit_error_no_lint() -> Result { #[clippy::msrv = "1.81"] pub fn returns_unit_error_lint() -> Result { + //~^ result_unit_err Err(()) } diff --git a/src/tools/clippy/tests/ui/return_and_then.fixed b/src/tools/clippy/tests/ui/return_and_then.fixed index 9736a51ac8687..74efa14eeec81 100644 --- a/src/tools/clippy/tests/ui/return_and_then.fixed +++ b/src/tools/clippy/tests/ui/return_and_then.fixed @@ -3,6 +3,7 @@ fn main() { fn test_opt_block(opt: Option) -> Option { let n = opt?; + //~^ return_and_then let mut ret = n + 1; ret += n; if n > 1 { Some(ret) } else { None } @@ -11,32 +12,38 @@ fn main() { fn test_opt_func(opt: Option) -> Option { let n = opt?; test_opt_block(Some(n)) + //~^ return_and_then } fn test_call_chain() -> Option { let n = gen_option(1)?; test_opt_block(Some(n)) + //~^ return_and_then } fn test_res_block(opt: Result) -> Result { let n = opt?; if n > 1 { Ok(n + 1) } else { Err(n) } + //~^ return_and_then } fn test_res_func(opt: Result) -> Result { let n = opt?; test_res_block(Ok(n)) + //~^ return_and_then } fn test_ref_only() -> Option { // ref: empty string let x = Some("")?; if x.len() > 2 { Some(3) } else { None } + //~^ return_and_then } fn test_tmp_only() -> Option { // unused temporary: vec![1, 2, 4] let x = Some(match (vec![1, 2, 3], vec![1, 2, 4]) { + //~^ return_and_then (a, _) if a.len() > 1 => a, (_, b) => b, })?; diff --git a/src/tools/clippy/tests/ui/return_and_then.rs b/src/tools/clippy/tests/ui/return_and_then.rs index 8bcbdfc3a6325..188dc57e588cf 100644 --- a/src/tools/clippy/tests/ui/return_and_then.rs +++ b/src/tools/clippy/tests/ui/return_and_then.rs @@ -3,6 +3,7 @@ fn main() { fn test_opt_block(opt: Option) -> Option { opt.and_then(|n| { + //~^ return_and_then let mut ret = n + 1; ret += n; if n > 1 { Some(ret) } else { None } @@ -11,28 +12,34 @@ fn main() { fn test_opt_func(opt: Option) -> Option { opt.and_then(|n| test_opt_block(Some(n))) + //~^ return_and_then } fn test_call_chain() -> Option { gen_option(1).and_then(|n| test_opt_block(Some(n))) + //~^ return_and_then } fn test_res_block(opt: Result) -> Result { opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) }) + //~^ return_and_then } fn test_res_func(opt: Result) -> Result { opt.and_then(|n| test_res_block(Ok(n))) + //~^ return_and_then } fn test_ref_only() -> Option { // ref: empty string Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) + //~^ return_and_then } fn test_tmp_only() -> Option { // unused temporary: vec![1, 2, 4] Some(match (vec![1, 2, 3], vec![1, 2, 4]) { + //~^ return_and_then (a, _) if a.len() > 1 => a, (_, b) => b, }) diff --git a/src/tools/clippy/tests/ui/return_and_then.stderr b/src/tools/clippy/tests/ui/return_and_then.stderr index b2e8bf2ca45a0..cc611c3dba679 100644 --- a/src/tools/clippy/tests/ui/return_and_then.stderr +++ b/src/tools/clippy/tests/ui/return_and_then.stderr @@ -2,6 +2,7 @@ error: use the question mark operator instead of an `and_then` call --> tests/ui/return_and_then.rs:5:9 | LL | / opt.and_then(|n| { +LL | | LL | | let mut ret = n + 1; LL | | ret += n; LL | | if n > 1 { Some(ret) } else { None } @@ -13,13 +14,14 @@ LL | | }) help: try | LL ~ let n = opt?; +LL + LL + let mut ret = n + 1; LL + ret += n; LL + if n > 1 { Some(ret) } else { None } | error: use the question mark operator instead of an `and_then` call - --> tests/ui/return_and_then.rs:13:9 + --> tests/ui/return_and_then.rs:14:9 | LL | opt.and_then(|n| test_opt_block(Some(n))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +33,7 @@ LL + test_opt_block(Some(n)) | error: use the question mark operator instead of an `and_then` call - --> tests/ui/return_and_then.rs:17:9 + --> tests/ui/return_and_then.rs:19:9 | LL | gen_option(1).and_then(|n| test_opt_block(Some(n))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -43,7 +45,7 @@ LL + test_opt_block(Some(n)) | error: use the question mark operator instead of an `and_then` call - --> tests/ui/return_and_then.rs:21:9 + --> tests/ui/return_and_then.rs:24:9 | LL | opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) }) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -55,7 +57,7 @@ LL + if n > 1 { Ok(n + 1) } else { Err(n) } | error: use the question mark operator instead of an `and_then` call - --> tests/ui/return_and_then.rs:25:9 + --> tests/ui/return_and_then.rs:29:9 | LL | opt.and_then(|n| test_res_block(Ok(n))) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,7 +69,7 @@ LL + test_res_block(Ok(n)) | error: use the question mark operator instead of an `and_then` call - --> tests/ui/return_and_then.rs:30:9 + --> tests/ui/return_and_then.rs:35:9 | LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -79,9 +81,10 @@ LL + if x.len() > 2 { Some(3) } else { None } | error: use the question mark operator instead of an `and_then` call - --> tests/ui/return_and_then.rs:35:9 + --> tests/ui/return_and_then.rs:41:9 | LL | / Some(match (vec![1, 2, 3], vec![1, 2, 4]) { +LL | | LL | | (a, _) if a.len() > 1 => a, LL | | (_, b) => b, LL | | }) @@ -91,6 +94,7 @@ LL | | .and_then(|x| if x.len() > 2 { Some(3) } else { None }) help: try | LL ~ let x = Some(match (vec![1, 2, 3], vec![1, 2, 4]) { +LL + LL + (a, _) if a.len() > 1 => a, LL + (_, b) => b, LL + })?; diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.rs b/src/tools/clippy/tests/ui/return_self_not_must_use.rs index ec6f0feb8e656..83965662d15e1 100644 --- a/src/tools/clippy/tests/ui/return_self_not_must_use.rs +++ b/src/tools/clippy/tests/ui/return_self_not_must_use.rs @@ -6,7 +6,8 @@ pub struct Bar; pub trait Whatever { fn what(&self) -> Self; - //~^ ERROR: missing `#[must_use]` attribute on a method returning `Self` + //~^ return_self_not_must_use + // There should be no warning here! (returns a reference) fn what2(&self) -> &Self; } @@ -17,11 +18,13 @@ impl Bar { Self } pub fn foo(&self) -> Self { - //~^ ERROR: missing `#[must_use]` attribute on a method returning `Self` + //~^ return_self_not_must_use + Self } pub fn bar(self) -> Self { - //~^ ERROR: missing `#[must_use]` attribute on a method returning `Self` + //~^ return_self_not_must_use + self } // There should be no warning here! (private method) diff --git a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr index 01f826b94a803..3e6a28f329207 100644 --- a/src/tools/clippy/tests/ui/return_self_not_must_use.stderr +++ b/src/tools/clippy/tests/ui/return_self_not_must_use.stderr @@ -9,10 +9,11 @@ LL | fn what(&self) -> Self; = help: to override `-D warnings` add `#[allow(clippy::return_self_not_must_use)]` error: missing `#[must_use]` attribute on a method returning `Self` - --> tests/ui/return_self_not_must_use.rs:19:5 + --> tests/ui/return_self_not_must_use.rs:20:5 | LL | / pub fn foo(&self) -> Self { LL | | +LL | | LL | | Self LL | | } | |_____^ @@ -20,10 +21,11 @@ LL | | } = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type error: missing `#[must_use]` attribute on a method returning `Self` - --> tests/ui/return_self_not_must_use.rs:23:5 + --> tests/ui/return_self_not_must_use.rs:25:5 | LL | / pub fn bar(self) -> Self { LL | | +LL | | LL | | self LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed index c8bf1b35085da..ba5059bbaa37e 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed @@ -7,10 +7,14 @@ fn main() { // These should be linted: (21..=42).rev().for_each(|x| println!("{}", x)); + //~^ reversed_empty_ranges let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect::>(); + //~^ reversed_empty_ranges for _ in (-42..=-21).rev() {} + //~^ reversed_empty_ranges for _ in (21u32..42u32).rev() {} + //~^ reversed_empty_ranges // These should be ignored as they are not empty ranges: diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs index 6733c096420b8..4068bc393066b 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs @@ -7,10 +7,14 @@ fn main() { // These should be linted: (42..=21).for_each(|x| println!("{}", x)); + //~^ reversed_empty_ranges let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); + //~^ reversed_empty_ranges for _ in -21..=-42 {} + //~^ reversed_empty_ranges for _ in 42u32..21u32 {} + //~^ reversed_empty_ranges // These should be ignored as they are not empty ranges: diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr index 24cb959c96af9..3fadc4c169f13 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.stderr @@ -13,7 +13,7 @@ LL + (21..=42).rev().for_each(|x| println!("{}", x)); | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_fixable.rs:10:13 + --> tests/ui/reversed_empty_ranges_fixable.rs:11:13 | LL | let _ = (ANSWER..21).filter(|x| x % 2 == 0).take(10).collect::>(); | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let _ = (21..ANSWER).rev().filter(|x| x % 2 == 0).take(10).collect:: tests/ui/reversed_empty_ranges_fixable.rs:12:14 + --> tests/ui/reversed_empty_ranges_fixable.rs:14:14 | LL | for _ in -21..=-42 {} | ^^^^^^^^^ @@ -37,7 +37,7 @@ LL + for _ in (-42..=-21).rev() {} | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_fixable.rs:13:14 + --> tests/ui/reversed_empty_ranges_fixable.rs:16:14 | LL | for _ in 42u32..21u32 {} | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed index df5f2c441f41b..55080da8a1377 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed @@ -5,14 +5,17 @@ fn main() { const MAX_LEN: usize = 42; for i in (0..10).rev() { + //~^ reversed_empty_ranges println!("{}", i); } for i in (0..=10).rev() { + //~^ reversed_empty_ranges println!("{}", i); } for i in (0..MAX_LEN).rev() { + //~^ reversed_empty_ranges println!("{}", i); } @@ -32,15 +35,18 @@ fn main() { } for i in (0..10).rev().map(|x| x * 2) { + //~^ reversed_empty_ranges println!("{}", i); } // testing that the empty range lint folds constants for i in (5 + 4..10).rev() { + //~^ reversed_empty_ranges println!("{}", i); } for i in ((3 - 1)..(5 + 2)).rev() { + //~^ reversed_empty_ranges println!("{}", i); } diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs index 92481be6cfc9b..e51557bc2796a 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs @@ -5,14 +5,17 @@ fn main() { const MAX_LEN: usize = 42; for i in 10..0 { + //~^ reversed_empty_ranges println!("{}", i); } for i in 10..=0 { + //~^ reversed_empty_ranges println!("{}", i); } for i in MAX_LEN..0 { + //~^ reversed_empty_ranges println!("{}", i); } @@ -32,15 +35,18 @@ fn main() { } for i in (10..0).map(|x| x * 2) { + //~^ reversed_empty_ranges println!("{}", i); } // testing that the empty range lint folds constants for i in 10..5 + 4 { + //~^ reversed_empty_ranges println!("{}", i); } for i in (5 + 2)..(3 - 1) { + //~^ reversed_empty_ranges println!("{}", i); } diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr index 3e9ccb653fe71..eadd9d3675e1c 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.stderr @@ -13,7 +13,7 @@ LL + for i in (0..10).rev() { | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_loops_fixable.rs:11:14 + --> tests/ui/reversed_empty_ranges_loops_fixable.rs:12:14 | LL | for i in 10..=0 { | ^^^^^^ @@ -25,7 +25,7 @@ LL + for i in (0..=10).rev() { | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_loops_fixable.rs:15:14 + --> tests/ui/reversed_empty_ranges_loops_fixable.rs:17:14 | LL | for i in MAX_LEN..0 { | ^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + for i in (0..MAX_LEN).rev() { | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_loops_fixable.rs:34:14 + --> tests/ui/reversed_empty_ranges_loops_fixable.rs:37:14 | LL | for i in (10..0).map(|x| x * 2) { | ^^^^^^^ @@ -49,7 +49,7 @@ LL + for i in (0..10).rev().map(|x| x * 2) { | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_loops_fixable.rs:39:14 + --> tests/ui/reversed_empty_ranges_loops_fixable.rs:43:14 | LL | for i in 10..5 + 4 { | ^^^^^^^^^ @@ -61,7 +61,7 @@ LL + for i in (5 + 4..10).rev() { | error: this range is empty so it will yield no values - --> tests/ui/reversed_empty_ranges_loops_fixable.rs:43:14 + --> tests/ui/reversed_empty_ranges_loops_fixable.rs:48:14 | LL | for i in (5 + 2)..(3 - 1) { | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs index cd1701dd4bf23..00aa20d25bdad 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_unfixable.rs @@ -3,13 +3,14 @@ fn main() { for i in 5..5 { - //~^ ERROR: this range is empty so it will yield no values - //~| NOTE: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + //~^ reversed_empty_ranges + println!("{}", i); } for i in (5 + 2)..(8 - 1) { - //~^ ERROR: this range is empty so it will yield no values + //~^ reversed_empty_ranges + println!("{}", i); } } diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs index 16c1121ae0697..7bf434544378f 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_unfixable.rs @@ -6,13 +6,13 @@ const SOME_NUM: usize = 3; fn main() { let arr = [1, 2, 3, 4, 5]; let _ = &arr[3usize..=1usize]; - //~^ ERROR: this range is reversed and using it to index a slice will panic at run-tim - //~| NOTE: `-D clippy::reversed-empty-ranges` implied by `-D warnings` + //~^ reversed_empty_ranges + let _ = &arr[SOME_NUM..1]; - //~^ ERROR: this range is reversed and using it to index a slice will panic at run-tim + //~^ reversed_empty_ranges for _ in ANSWER..ANSWER {} - //~^ ERROR: this range is empty so it will yield no values + //~^ reversed_empty_ranges // Should not be linted, see issue #5689 let _ = (42 + 10..42 + 10).map(|x| x / 2).find(|&x| x == 21); diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs index a207e42213558..b7ed3aab00434 100644 --- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs +++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs @@ -37,33 +37,33 @@ fn ifs_same_cond_fn() { if function() { } else if function() { - //~^ ERROR: `if` has the same function call as a previous `if` + //~^ same_functions_in_if_condition } if fn_arg(a) { } else if fn_arg(a) { - //~^ ERROR: `if` has the same function call as a previous `if` + //~^ same_functions_in_if_condition } if obj.method() { } else if obj.method() { - //~^ ERROR: `if` has the same function call as a previous `if` + //~^ same_functions_in_if_condition } if obj.method_arg(a) { } else if obj.method_arg(a) { - //~^ ERROR: `if` has the same function call as a previous `if` + //~^ same_functions_in_if_condition } let mut v = vec![1]; if v.pop().is_none() { } else if v.pop().is_none() { - //~^ ERROR: `if` has the same function call as a previous `if` + //~^ same_functions_in_if_condition } if v.len() == 42 { } else if v.len() == 42 { - //~^ ERROR: `if` has the same function call as a previous `if` + //~^ same_functions_in_if_condition } if v.len() == 1 { diff --git a/src/tools/clippy/tests/ui/same_item_push.rs b/src/tools/clippy/tests/ui/same_item_push.rs index 87fd59ad31794..a08e8872a9324 100644 --- a/src/tools/clippy/tests/ui/same_item_push.rs +++ b/src/tools/clippy/tests/ui/same_item_push.rs @@ -21,33 +21,33 @@ fn main() { let item = 2; for _ in 5..=20 { vec.push(item); - //~^ ERROR: it looks like the same item is being pushed into this `Vec` + //~^ same_item_push } let mut vec: Vec = Vec::new(); for _ in 0..15 { let item = 2; vec.push(item); - //~^ ERROR: it looks like the same item is being pushed into this `Vec` + //~^ same_item_push } let mut vec: Vec = Vec::new(); for _ in 0..15 { vec.push(13); - //~^ ERROR: it looks like the same item is being pushed into this `Vec` + //~^ same_item_push } let mut vec = Vec::new(); for _ in 0..20 { vec.push(VALUE); - //~^ ERROR: it looks like the same item is being pushed into this `Vec` + //~^ same_item_push } let mut vec = Vec::new(); let item = VALUE; for _ in 0..20 { vec.push(item); - //~^ ERROR: it looks like the same item is being pushed into this `Vec` + //~^ same_item_push } #[clippy::msrv = "1.81"] @@ -56,7 +56,7 @@ fn main() { let item = VALUE; for _ in 0..20 { vec.push(item); - //~^ ERROR: it looks like the same item is being pushed into this `Vec` + //~^ same_item_push } } diff --git a/src/tools/clippy/tests/ui/same_name_method.rs b/src/tools/clippy/tests/ui/same_name_method.rs index ba876c2b5a3f7..43c664b1505fa 100644 --- a/src/tools/clippy/tests/ui/same_name_method.rs +++ b/src/tools/clippy/tests/ui/same_name_method.rs @@ -18,7 +18,7 @@ mod should_lint { impl S { fn foo() {} - //~^ ERROR: method's name is the same as an existing method in a trait + //~^ same_name_method } impl T1 for S { @@ -33,7 +33,7 @@ mod should_lint { impl S { fn clone() {} - //~^ ERROR: method's name is the same as an existing method in a trait + //~^ same_name_method } } @@ -44,7 +44,7 @@ mod should_lint { impl S { fn foo() {} - //~^ ERROR: method's name is the same as an existing method in a trait + //~^ same_name_method } impl T1 for S { @@ -59,7 +59,7 @@ mod should_lint { impl S { fn foo() {} - //~^ ERROR: method's name is the same as an existing method in a trait + //~^ same_name_method } impl T1 for S {} @@ -72,8 +72,8 @@ mod should_lint { impl S { fn foo() {} - //~^ ERROR: method's name is the same as an existing method in a trait - //~| ERROR: method's name is the same as an existing method in a trait + //~^ same_name_method + //~| same_name_method } impl T1 for S {} diff --git a/src/tools/clippy/tests/ui/same_name_method.stderr b/src/tools/clippy/tests/ui/same_name_method.stderr index fefdb5c9c23d0..b2624ac4d2644 100644 --- a/src/tools/clippy/tests/ui/same_name_method.stderr +++ b/src/tools/clippy/tests/ui/same_name_method.stderr @@ -23,7 +23,6 @@ note: existing `clone` defined here | LL | #[derive(Clone)] | ^^^^^ - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) error: method's name is the same as an existing method in a trait --> tests/ui/same_name_method.rs:46:13 diff --git a/src/tools/clippy/tests/ui/search_is_some.rs b/src/tools/clippy/tests/ui/search_is_some.rs index 9a9aaba56adc5..4143b8bfba58b 100644 --- a/src/tools/clippy/tests/ui/search_is_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some.rs @@ -14,18 +14,21 @@ fn main() { // Check `find().is_some()`, multi-line case. let _ = v.iter().find(|&x| { + //~^ search_is_some *x < 0 } ).is_some(); // Check `position().is_some()`, multi-line case. let _ = v.iter().position(|&x| { + //~^ search_is_some x < 0 } ).is_some(); // Check `rposition().is_some()`, multi-line case. let _ = v.iter().rposition(|&x| { + //~^ search_is_some x < 0 } ).is_some(); @@ -41,6 +44,7 @@ fn main() { let some_closure = |x: &u32| *x == 0; let _ = (0..1).find(some_closure).is_some(); + //~^ search_is_some } #[rustfmt::skip] @@ -51,18 +55,21 @@ fn is_none() { // Check `find().is_none()`, multi-line case. let _ = v.iter().find(|&x| { + //~^ search_is_some *x < 0 } ).is_none(); // Check `position().is_none()`, multi-line case. let _ = v.iter().position(|&x| { + //~^ search_is_some x < 0 } ).is_none(); // Check `rposition().is_none()`, multi-line case. let _ = v.iter().rposition(|&x| { + //~^ search_is_some x < 0 } ).is_none(); @@ -78,4 +85,5 @@ fn is_none() { let some_closure = |x: &u32| *x == 0; let _ = (0..1).find(some_closure).is_none(); + //~^ search_is_some } diff --git a/src/tools/clippy/tests/ui/search_is_some.stderr b/src/tools/clippy/tests/ui/search_is_some.stderr index b5ef553417701..d9a43c8915e85 100644 --- a/src/tools/clippy/tests/ui/search_is_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some.stderr @@ -3,6 +3,7 @@ error: called `is_some()` after searching an `Iterator` with `find` | LL | let _ = v.iter().find(|&x| { | _____________^ +LL | | LL | | *x < 0 LL | | } LL | | ).is_some(); @@ -13,10 +14,11 @@ LL | | ).is_some(); = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_some()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:22:13 + --> tests/ui/search_is_some.rs:23:13 | LL | let _ = v.iter().position(|&x| { | _____________^ +LL | | LL | | x < 0 LL | | } LL | | ).is_some(); @@ -25,10 +27,11 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:28:13 + --> tests/ui/search_is_some.rs:30:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ +LL | | LL | | x < 0 LL | | } LL | | ).is_some(); @@ -37,16 +40,17 @@ LL | | ).is_some(); = help: this is more succinctly expressed by calling `any()` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:43:20 + --> tests/ui/search_is_some.rs:46:20 | LL | let _ = (0..1).find(some_closure).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(some_closure)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:53:13 + --> tests/ui/search_is_some.rs:57:13 | LL | let _ = v.iter().find(|&x| { | _____________^ +LL | | LL | | *x < 0 LL | | } LL | | ).is_none(); @@ -55,10 +59,11 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some.rs:59:13 + --> tests/ui/search_is_some.rs:64:13 | LL | let _ = v.iter().position(|&x| { | _____________^ +LL | | LL | | x < 0 LL | | } LL | | ).is_none(); @@ -67,10 +72,11 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some.rs:65:13 + --> tests/ui/search_is_some.rs:71:13 | LL | let _ = v.iter().rposition(|&x| { | _____________^ +LL | | LL | | x < 0 LL | | } LL | | ).is_none(); @@ -79,7 +85,7 @@ LL | | ).is_none(); = help: this is more succinctly expressed by calling `any()` with negation error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some.rs:80:13 + --> tests/ui/search_is_some.rs:87:13 | LL | let _ = (0..1).find(some_closure).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(some_closure)` diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed index 86a937b4dae1c..847e5140d3e65 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed @@ -1,4 +1,4 @@ -#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)] #![warn(clippy::search_is_some)] fn main() { @@ -7,36 +7,56 @@ fn main() { // Check `find().is_none()`, single-line case. let _ = !v.iter().any(|x| *x < 0); + //~^ search_is_some let _ = !(0..1).any(|x| **y == x); // one dereference less + // + //~^^ search_is_some let _ = !(0..1).any(|x| x == 0); + //~^ search_is_some let _ = !v.iter().any(|x| *x == 0); + //~^ search_is_some let _ = !(4..5).any(|x| x == 1 || x == 3 || x == 5); + //~^ search_is_some let _ = !(1..3).any(|x| [1, 2, 3].contains(&x)); + //~^ search_is_some let _ = !(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x)); + //~^ search_is_some let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0); + //~^ search_is_some let _ = !(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1); // Check `position().is_none()`, single-line case. let _ = !v.iter().any(|&x| x < 0); + //~^ search_is_some // Check `rposition().is_none()`, single-line case. let _ = !v.iter().any(|&x| x < 0); + //~^ search_is_some let s1 = String::from("hello world"); let s2 = String::from("world"); // caller of `find()` is a `&`static str` let _ = !"hello world".contains("world"); + //~^ search_is_some let _ = !"hello world".contains(&s2); + //~^ search_is_some let _ = !"hello world".contains(&s2[2..]); + //~^ search_is_some // caller of `find()` is a `String` let _ = !s1.contains("world"); + //~^ search_is_some let _ = !s1.contains(&s2); + //~^ search_is_some let _ = !s1.contains(&s2[2..]); + //~^ search_is_some // caller of `find()` is slice of `String` let _ = !s1[2..].contains("world"); + //~^ search_is_some let _ = !s1[2..].contains(&s2); + //~^ search_is_some let _ = !s1[2..].contains(&s2[2..]); + //~^ search_is_some } #[allow(clippy::clone_on_copy, clippy::map_clone)] @@ -53,6 +73,7 @@ mod issue7392 { .hand .iter() .filter(|c| !filter_hand.iter().any(|cc| c == &cc)) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -69,6 +90,7 @@ mod issue7392 { .hand .iter() .filter(|(c, _)| !filter_hand.iter().any(|cc| c == cc)) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -80,21 +102,25 @@ mod issue7392 { } let vfoo = vec![Foo { foo: 1, bar: 2 }]; let _ = !vfoo.iter().any(|v| v.foo == 1 && v.bar == 2); + //~^ search_is_some let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; let _ = !vfoo + //~^ search_is_some .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2); } fn index_projection() { let vfoo = vec![[0, 1, 2, 3]]; let _ = !vfoo.iter().any(|a| a[0] == 42); + //~^ search_is_some } #[allow(clippy::match_like_matches_macro)] fn slice_projection() { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = !vfoo.iter().any(|sub| sub[1..4].len() == 3); + //~^ search_is_some } fn please(x: &u32) -> bool { @@ -113,16 +139,22 @@ mod issue7392 { let x = 19; let ppx: &u32 = &x; let _ = ![ppx].iter().any(|ppp_x: &&u32| please(ppp_x)); + //~^ search_is_some let _ = ![String::from("Hey hey")].iter().any(|s| s.len() == 2); + //~^ search_is_some let v = vec![3, 2, 1, 0]; let _ = !v.iter().any(|x| deref_enough(*x)); + //~^ search_is_some let _ = !v.iter().any(|x: &u32| deref_enough(*x)); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = !v.iter().any(|x| arg_no_deref(&x)); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = !v.iter().any(|x: &u32| arg_no_deref(&x)); + //~^ search_is_some } fn field_index_projection() { @@ -143,6 +175,7 @@ mod issue7392 { }, }]; let _ = !vfoo + //~^ search_is_some .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2); } @@ -157,11 +190,13 @@ mod issue7392 { inner: vec![Foo { bar: 0 }], }]; let _ = !vfoo.iter().any(|v| v.inner[0].bar == 2); + //~^ search_is_some } fn double_deref_index_projection() { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = !vfoo.iter().any(|x| (**x)[0] == 9); + //~^ search_is_some } fn method_call_by_ref() { @@ -175,11 +210,14 @@ mod issue7392 { } let vfoo = vec![Foo { bar: 1 }]; let _ = !vfoo.iter().any(|v| v.by_ref(&v.bar)); + //~^ search_is_some } fn ref_bindings() { let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some } fn test_string_1(s: &str) -> bool { @@ -199,7 +237,9 @@ mod issue7392 { let lst = &[String::from("Hello"), String::from("world")]; let v: Vec<&[String]> = vec![lst]; let _ = !v.iter().any(|s| s[0].is_empty()); + //~^ search_is_some let _ = !v.iter().any(|s| test_string_1(&s[0])); + //~^ search_is_some // Field projections struct FieldProjection<'a> { @@ -209,8 +249,11 @@ mod issue7392 { let instance = FieldProjection { field: &field }; let v = vec![instance]; let _ = !v.iter().any(|fp| fp.field.is_power_of_two()); + //~^ search_is_some let _ = !v.iter().any(|fp| test_u32_1(fp.field)); + //~^ search_is_some let _ = !v.iter().any(|fp| test_u32_2(*fp.field)); + //~^ search_is_some } } @@ -227,39 +270,51 @@ mod issue_11910 { fn test_normal_for_iter() { let v = vec![3, 2, 1, 0, -1, -2, -3]; let _ = !v.iter().any(|x| *x == 42); + //~^ search_is_some Foo.bar(!v.iter().any(|x| *x == 42)); + //~^ search_is_some } fn test_then_for_iter() { let v = vec![3, 2, 1, 0, -1, -2, -3]; (!v.iter().any(|x| *x == 42)).then(computations); + //~^ search_is_some } fn test_then_some_for_iter() { let v = vec![3, 2, 1, 0, -1, -2, -3]; (!v.iter().any(|x| *x == 42)).then_some(0); + //~^ search_is_some } fn test_normal_for_str() { let s = "hello"; let _ = !s.contains("world"); + //~^ search_is_some Foo.bar(!s.contains("world")); + //~^ search_is_some let s = String::from("hello"); let _ = !s.contains("world"); + //~^ search_is_some Foo.bar(!s.contains("world")); + //~^ search_is_some } fn test_then_for_str() { let s = "hello"; let _ = (!s.contains("world")).then(computations); + //~^ search_is_some let s = String::from("hello"); let _ = (!s.contains("world")).then(computations); + //~^ search_is_some } fn test_then_some_for_str() { let s = "hello"; let _ = (!s.contains("world")).then_some(0); + //~^ search_is_some let s = String::from("hello"); let _ = (!s.contains("world")).then_some(0); + //~^ search_is_some } } diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs index c0103a015097d..e976d12600cc1 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs @@ -1,4 +1,4 @@ -#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)] #![warn(clippy::search_is_some)] fn main() { @@ -7,38 +7,59 @@ fn main() { // Check `find().is_none()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_none(); + //~^ search_is_some let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less + // + //~^^ search_is_some let _ = (0..1).find(|x| *x == 0).is_none(); + //~^ search_is_some let _ = v.iter().find(|x| **x == 0).is_none(); + //~^ search_is_some let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none(); + //~^ search_is_some let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none(); + //~^ search_is_some let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none(); + //~^ search_is_some let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none(); + //~^ search_is_some let _ = (1..3) + //~^ search_is_some .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) .is_none(); // Check `position().is_none()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_none(); + //~^ search_is_some // Check `rposition().is_none()`, single-line case. let _ = v.iter().rposition(|&x| x < 0).is_none(); + //~^ search_is_some let s1 = String::from("hello world"); let s2 = String::from("world"); // caller of `find()` is a `&`static str` let _ = "hello world".find("world").is_none(); + //~^ search_is_some let _ = "hello world".find(&s2).is_none(); + //~^ search_is_some let _ = "hello world".find(&s2[2..]).is_none(); + //~^ search_is_some // caller of `find()` is a `String` let _ = s1.find("world").is_none(); + //~^ search_is_some let _ = s1.find(&s2).is_none(); + //~^ search_is_some let _ = s1.find(&s2[2..]).is_none(); + //~^ search_is_some // caller of `find()` is slice of `String` let _ = s1[2..].find("world").is_none(); + //~^ search_is_some let _ = s1[2..].find(&s2).is_none(); + //~^ search_is_some let _ = s1[2..].find(&s2[2..]).is_none(); + //~^ search_is_some } #[allow(clippy::clone_on_copy, clippy::map_clone)] @@ -55,6 +76,7 @@ mod issue7392 { .hand .iter() .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -71,6 +93,7 @@ mod issue7392 { .hand .iter() .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -82,9 +105,11 @@ mod issue7392 { } let vfoo = vec![Foo { foo: 1, bar: 2 }]; let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none(); + //~^ search_is_some let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; let _ = vfoo + //~^ search_is_some .iter() .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) .is_none(); @@ -93,12 +118,14 @@ mod issue7392 { fn index_projection() { let vfoo = vec![[0, 1, 2, 3]]; let _ = vfoo.iter().find(|a| a[0] == 42).is_none(); + //~^ search_is_some } #[allow(clippy::match_like_matches_macro)] fn slice_projection() { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); + //~^ search_is_some } fn please(x: &u32) -> bool { @@ -117,16 +144,22 @@ mod issue7392 { let x = 19; let ppx: &u32 = &x; let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); + //~^ search_is_some let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); + //~^ search_is_some let v = vec![3, 2, 1, 0]; let _ = v.iter().find(|x| deref_enough(**x)).is_none(); + //~^ search_is_some let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none(); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none(); + //~^ search_is_some } fn field_index_projection() { @@ -147,6 +180,7 @@ mod issue7392 { }, }]; let _ = vfoo + //~^ search_is_some .iter() .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) .is_none(); @@ -163,11 +197,13 @@ mod issue7392 { inner: vec![Foo { bar: 0 }], }]; let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none(); + //~^ search_is_some } fn double_deref_index_projection() { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); + //~^ search_is_some } fn method_call_by_ref() { @@ -181,11 +217,14 @@ mod issue7392 { } let vfoo = vec![Foo { bar: 1 }]; let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); + //~^ search_is_some } fn ref_bindings() { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); + //~^ search_is_some let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); + //~^ search_is_some } fn test_string_1(s: &str) -> bool { @@ -205,7 +244,9 @@ mod issue7392 { let lst = &[String::from("Hello"), String::from("world")]; let v: Vec<&[String]> = vec![lst]; let _ = v.iter().find(|s| s[0].is_empty()).is_none(); + //~^ search_is_some let _ = v.iter().find(|s| test_string_1(&s[0])).is_none(); + //~^ search_is_some // Field projections struct FieldProjection<'a> { @@ -215,8 +256,11 @@ mod issue7392 { let instance = FieldProjection { field: &field }; let v = vec![instance]; let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none(); + //~^ search_is_some let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none(); + //~^ search_is_some let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); + //~^ search_is_some } } @@ -233,39 +277,51 @@ mod issue_11910 { fn test_normal_for_iter() { let v = vec![3, 2, 1, 0, -1, -2, -3]; let _ = v.iter().find(|x| **x == 42).is_none(); + //~^ search_is_some Foo.bar(v.iter().find(|x| **x == 42).is_none()); + //~^ search_is_some } fn test_then_for_iter() { let v = vec![3, 2, 1, 0, -1, -2, -3]; v.iter().find(|x| **x == 42).is_none().then(computations); + //~^ search_is_some } fn test_then_some_for_iter() { let v = vec![3, 2, 1, 0, -1, -2, -3]; v.iter().find(|x| **x == 42).is_none().then_some(0); + //~^ search_is_some } fn test_normal_for_str() { let s = "hello"; let _ = s.find("world").is_none(); + //~^ search_is_some Foo.bar(s.find("world").is_none()); + //~^ search_is_some let s = String::from("hello"); let _ = s.find("world").is_none(); + //~^ search_is_some Foo.bar(s.find("world").is_none()); + //~^ search_is_some } fn test_then_for_str() { let s = "hello"; let _ = s.find("world").is_none().then(computations); + //~^ search_is_some let s = String::from("hello"); let _ = s.find("world").is_none().then(computations); + //~^ search_is_some } fn test_then_some_for_str() { let s = "hello"; let _ = s.find("world").is_none().then_some(0); + //~^ search_is_some let s = String::from("hello"); let _ = s.find("world").is_none().then_some(0); + //~^ search_is_some } } diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr index 2c858b9fb10ef..ccc17025222d9 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr @@ -8,145 +8,147 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_none(); = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:10:13 + --> tests/ui/search_is_some_fixable_none.rs:11:13 | LL | let _ = (0..1).find(|x| **y == *x).is_none(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(|x| **y == x)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:11:13 + --> tests/ui/search_is_some_fixable_none.rs:14:13 | LL | let _ = (0..1).find(|x| *x == 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(0..1).any(|x| x == 0)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:12:13 + --> tests/ui/search_is_some_fixable_none.rs:16:13 | LL | let _ = v.iter().find(|x| **x == 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 0)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:13:13 + --> tests/ui/search_is_some_fixable_none.rs:18:13 | LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(4..5).any(|x| x == 1 || x == 3 || x == 5)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:14:13 + --> tests/ui/search_is_some_fixable_none.rs:20:13 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:15:13 + --> tests/ui/search_is_some_fixable_none.rs:22:13 | LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| x == 0 || [1, 2, 3].contains(&x))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:16:13 + --> tests/ui/search_is_some_fixable_none.rs:24:13 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:17:13 + --> tests/ui/search_is_some_fixable_none.rs:26:13 | LL | let _ = (1..3) | _____________^ +LL | | LL | | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) LL | | .is_none(); | |__________________^ help: consider using: `!(1..3).any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` error: called `is_none()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some_fixable_none.rs:22:13 + --> tests/ui/search_is_some_fixable_none.rs:32:13 | LL | let _ = v.iter().position(|&x| x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some_fixable_none.rs:25:13 + --> tests/ui/search_is_some_fixable_none.rs:36:13 | LL | let _ = v.iter().rposition(|&x| x < 0).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|&x| x < 0)` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:31:13 + --> tests/ui/search_is_some_fixable_none.rs:43:13 | LL | let _ = "hello world".find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:32:13 + --> tests/ui/search_is_some_fixable_none.rs:45:13 | LL | let _ = "hello world".find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:33:13 + --> tests/ui/search_is_some_fixable_none.rs:47:13 | LL | let _ = "hello world".find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!"hello world".contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:35:13 + --> tests/ui/search_is_some_fixable_none.rs:50:13 | LL | let _ = s1.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:36:13 + --> tests/ui/search_is_some_fixable_none.rs:52:13 | LL | let _ = s1.find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:37:13 + --> tests/ui/search_is_some_fixable_none.rs:54:13 | LL | let _ = s1.find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1.contains(&s2[2..])` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:39:13 + --> tests/ui/search_is_some_fixable_none.rs:57:13 | LL | let _ = s1[2..].find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:40:13 + --> tests/ui/search_is_some_fixable_none.rs:59:13 | LL | let _ = s1[2..].find(&s2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains(&s2)` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:41:13 + --> tests/ui/search_is_some_fixable_none.rs:61:13 | LL | let _ = s1[2..].find(&s2[2..]).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s1[2..].contains(&s2[2..])` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:57:25 + --> tests/ui/search_is_some_fixable_none.rs:78:25 | LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_none()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!filter_hand.iter().any(|cc| c == &cc)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:73:30 + --> tests/ui/search_is_some_fixable_none.rs:95:30 | LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_none()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!filter_hand.iter().any(|cc| c == cc)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:84:17 + --> tests/ui/search_is_some_fixable_none.rs:107:17 | LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.foo == 1 && v.bar == 2)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:87:17 + --> tests/ui/search_is_some_fixable_none.rs:111:17 | LL | let _ = vfoo | _________________^ +LL | | LL | | .iter() LL | | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) LL | | .is_none(); @@ -155,62 +157,64 @@ LL | | .is_none(); help: consider using | LL ~ let _ = !vfoo +LL + LL ~ .iter().any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2); | error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:95:17 + --> tests/ui/search_is_some_fixable_none.rs:120:17 | LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|a| a[0] == 42)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:101:17 + --> tests/ui/search_is_some_fixable_none.rs:127:17 | LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|sub| sub[1..4].len() == 3)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:119:17 + --> tests/ui/search_is_some_fixable_none.rs:146:17 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![ppx].iter().any(|ppp_x: &&u32| please(ppp_x))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:120:17 + --> tests/ui/search_is_some_fixable_none.rs:148:17 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![String::from("Hey hey")].iter().any(|s| s.len() == 2)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:123:17 + --> tests/ui/search_is_some_fixable_none.rs:152:17 | LL | let _ = v.iter().find(|x| deref_enough(**x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| deref_enough(*x))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:124:17 + --> tests/ui/search_is_some_fixable_none.rs:154:17 | LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x: &u32| deref_enough(*x))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:127:17 + --> tests/ui/search_is_some_fixable_none.rs:158:17 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| arg_no_deref(&x))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:129:17 + --> tests/ui/search_is_some_fixable_none.rs:161:17 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x: &u32| arg_no_deref(&x))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:149:17 + --> tests/ui/search_is_some_fixable_none.rs:182:17 | LL | let _ = vfoo | _________________^ +LL | | LL | | .iter() LL | | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) LL | | .is_none(); @@ -219,137 +223,138 @@ LL | | .is_none(); help: consider using | LL ~ let _ = !vfoo +LL + LL ~ .iter().any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2); | error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:165:17 + --> tests/ui/search_is_some_fixable_none.rs:199:17 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.inner[0].bar == 2)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:170:17 + --> tests/ui/search_is_some_fixable_none.rs:205:17 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|x| (**x)[0] == 9)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:183:17 + --> tests/ui/search_is_some_fixable_none.rs:219:17 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!vfoo.iter().any(|v| v.by_ref(&v.bar))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:187:17 + --> tests/ui/search_is_some_fixable_none.rs:224:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:188:17 + --> tests/ui/search_is_some_fixable_none.rs:226:17 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:207:17 + --> tests/ui/search_is_some_fixable_none.rs:246:17 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| s[0].is_empty())` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:208:17 + --> tests/ui/search_is_some_fixable_none.rs:248:17 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| test_string_1(&s[0]))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:217:17 + --> tests/ui/search_is_some_fixable_none.rs:258:17 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| fp.field.is_power_of_two())` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:218:17 + --> tests/ui/search_is_some_fixable_none.rs:260:17 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_1(fp.field))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:219:17 + --> tests/ui/search_is_some_fixable_none.rs:262:17 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:235:17 + --> tests/ui/search_is_some_fixable_none.rs:279:17 | LL | let _ = v.iter().find(|x| **x == 42).is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:236:17 + --> tests/ui/search_is_some_fixable_none.rs:281:17 | LL | Foo.bar(v.iter().find(|x| **x == 42).is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:241:9 + --> tests/ui/search_is_some_fixable_none.rs:287:9 | LL | v.iter().find(|x| **x == 42).is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` error: called `is_none()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_none.rs:246:9 + --> tests/ui/search_is_some_fixable_none.rs:293:9 | LL | v.iter().find(|x| **x == 42).is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:251:17 + --> tests/ui/search_is_some_fixable_none.rs:299:17 | LL | let _ = s.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:252:17 + --> tests/ui/search_is_some_fixable_none.rs:301:17 | LL | Foo.bar(s.find("world").is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:254:17 + --> tests/ui/search_is_some_fixable_none.rs:304:17 | LL | let _ = s.find("world").is_none(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:255:17 + --> tests/ui/search_is_some_fixable_none.rs:306:17 | LL | Foo.bar(s.find("world").is_none()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:260:17 + --> tests/ui/search_is_some_fixable_none.rs:312:17 | LL | let _ = s.find("world").is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:262:17 + --> tests/ui/search_is_some_fixable_none.rs:315:17 | LL | let _ = s.find("world").is_none().then(computations); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:267:17 + --> tests/ui/search_is_some_fixable_none.rs:321:17 | LL | let _ = s.find("world").is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` error: called `is_none()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_none.rs:269:17 + --> tests/ui/search_is_some_fixable_none.rs:324:17 | LL | let _ = s.find("world").is_none().then_some(0); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))` diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed index ae3cbc3c4da2a..05e88b8528f15 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed @@ -1,4 +1,4 @@ -#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)] #![warn(clippy::search_is_some)] fn main() { @@ -7,36 +7,56 @@ fn main() { // Check `find().is_some()`, single-line case. let _ = v.iter().any(|x| *x < 0); + //~^ search_is_some let _ = (0..1).any(|x| **y == x); // one dereference less + // + //~^^ search_is_some let _ = (0..1).any(|x| x == 0); + //~^ search_is_some let _ = v.iter().any(|x| *x == 0); + //~^ search_is_some let _ = (4..5).any(|x| x == 1 || x == 3 || x == 5); + //~^ search_is_some let _ = (1..3).any(|x| [1, 2, 3].contains(&x)); + //~^ search_is_some let _ = (1..3).any(|x| x == 0 || [1, 2, 3].contains(&x)); + //~^ search_is_some let _ = (1..3).any(|x| [1, 2, 3].contains(&x) || x == 0); + //~^ search_is_some let _ = (1..3) .any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1); // Check `position().is_some()`, single-line case. let _ = v.iter().any(|&x| x < 0); + //~^ search_is_some // Check `rposition().is_some()`, single-line case. let _ = v.iter().any(|&x| x < 0); + //~^ search_is_some let s1 = String::from("hello world"); let s2 = String::from("world"); // caller of `find()` is a `&`static str` let _ = "hello world".contains("world"); + //~^ search_is_some let _ = "hello world".contains(&s2); + //~^ search_is_some let _ = "hello world".contains(&s2[2..]); + //~^ search_is_some // caller of `find()` is a `String` let _ = s1.contains("world"); + //~^ search_is_some let _ = s1.contains(&s2); + //~^ search_is_some let _ = s1.contains(&s2[2..]); + //~^ search_is_some // caller of `find()` is slice of `String` let _ = s1[2..].contains("world"); + //~^ search_is_some let _ = s1[2..].contains(&s2); + //~^ search_is_some let _ = s1[2..].contains(&s2[2..]); + //~^ search_is_some } #[allow(clippy::clone_on_copy, clippy::map_clone)] @@ -53,6 +73,7 @@ mod issue7392 { .hand .iter() .filter(|c| filter_hand.iter().any(|cc| c == &cc)) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -69,6 +90,7 @@ mod issue7392 { .hand .iter() .filter(|(c, _)| filter_hand.iter().any(|cc| c == cc)) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -80,6 +102,7 @@ mod issue7392 { } let vfoo = vec![Foo { foo: 1, bar: 2 }]; let _ = vfoo.iter().any(|v| v.foo == 1 && v.bar == 2); + //~^ search_is_some let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; let _ = vfoo @@ -90,12 +113,14 @@ mod issue7392 { fn index_projection() { let vfoo = vec![[0, 1, 2, 3]]; let _ = vfoo.iter().any(|a| a[0] == 42); + //~^ search_is_some } #[allow(clippy::match_like_matches_macro)] fn slice_projection() { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = vfoo.iter().any(|sub| sub[1..4].len() == 3); + //~^ search_is_some } fn please(x: &u32) -> bool { @@ -114,16 +139,22 @@ mod issue7392 { let x = 19; let ppx: &u32 = &x; let _ = [ppx].iter().any(|ppp_x: &&u32| please(ppp_x)); + //~^ search_is_some let _ = [String::from("Hey hey")].iter().any(|s| s.len() == 2); + //~^ search_is_some let v = vec![3, 2, 1, 0]; let _ = v.iter().any(|x| deref_enough(*x)); + //~^ search_is_some let _ = v.iter().any(|x: &u32| deref_enough(*x)); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().any(|x| arg_no_deref(&x)); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().any(|x: &u32| arg_no_deref(&x)); + //~^ search_is_some } fn field_index_projection() { @@ -159,11 +190,13 @@ mod issue7392 { inner: vec![Foo { bar: 0 }], }]; let _ = vfoo.iter().any(|v| v.inner[0].bar == 2); + //~^ search_is_some } fn double_deref_index_projection() { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = vfoo.iter().any(|x| (**x)[0] == 9); + //~^ search_is_some } fn method_call_by_ref() { @@ -177,11 +210,14 @@ mod issue7392 { } let vfoo = vec![Foo { bar: 1 }]; let _ = vfoo.iter().any(|v| v.by_ref(&v.bar)); + //~^ search_is_some } fn ref_bindings() { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y); + //~^ search_is_some } fn test_string_1(s: &str) -> bool { @@ -201,7 +237,9 @@ mod issue7392 { let lst = &[String::from("Hello"), String::from("world")]; let v: Vec<&[String]> = vec![lst]; let _ = v.iter().any(|s| s[0].is_empty()); + //~^ search_is_some let _ = v.iter().any(|s| test_string_1(&s[0])); + //~^ search_is_some // Field projections struct FieldProjection<'a> { @@ -211,8 +249,11 @@ mod issue7392 { let instance = FieldProjection { field: &field }; let v = vec![instance]; let _ = v.iter().any(|fp| fp.field.is_power_of_two()); + //~^ search_is_some let _ = v.iter().any(|fp| test_u32_1(fp.field)); + //~^ search_is_some let _ = v.iter().any(|fp| test_u32_2(*fp.field)); + //~^ search_is_some } } @@ -228,6 +269,7 @@ mod issue9120 { fn wrapper bool>(v: Vec, func: T) -> bool { #[allow(clippy::redundant_closure)] v.iter().any(|x: &u32| func(&x)) + //~^ search_is_some } fn do_tests() { @@ -237,11 +279,14 @@ mod issue9120 { #[allow(clippy::redundant_closure)] let _ = v.iter().any(|x: &u32| arg_no_deref_impl(&x)); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().any(|x: &u32| arg_no_deref_dyn(&x)); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().any(|x: &u32| (*arg_no_deref_dyn)(&x)); + //~^ search_is_some } } diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs index 19a44803fd543..caab816f24361 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs @@ -1,4 +1,4 @@ -#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec)] +#![allow(dead_code, clippy::explicit_auto_deref, clippy::useless_vec, clippy::manual_contains)] #![warn(clippy::search_is_some)] fn main() { @@ -7,37 +7,58 @@ fn main() { // Check `find().is_some()`, single-line case. let _ = v.iter().find(|&x| *x < 0).is_some(); + //~^ search_is_some let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less + // + //~^^ search_is_some let _ = (0..1).find(|x| *x == 0).is_some(); + //~^ search_is_some let _ = v.iter().find(|x| **x == 0).is_some(); + //~^ search_is_some let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some(); + //~^ search_is_some let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some(); + //~^ search_is_some let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some(); + //~^ search_is_some let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some(); + //~^ search_is_some let _ = (1..3) .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) + //~^ search_is_some .is_some(); // Check `position().is_some()`, single-line case. let _ = v.iter().position(|&x| x < 0).is_some(); + //~^ search_is_some // Check `rposition().is_some()`, single-line case. let _ = v.iter().rposition(|&x| x < 0).is_some(); + //~^ search_is_some let s1 = String::from("hello world"); let s2 = String::from("world"); // caller of `find()` is a `&`static str` let _ = "hello world".find("world").is_some(); + //~^ search_is_some let _ = "hello world".find(&s2).is_some(); + //~^ search_is_some let _ = "hello world".find(&s2[2..]).is_some(); + //~^ search_is_some // caller of `find()` is a `String` let _ = s1.find("world").is_some(); + //~^ search_is_some let _ = s1.find(&s2).is_some(); + //~^ search_is_some let _ = s1.find(&s2[2..]).is_some(); + //~^ search_is_some // caller of `find()` is slice of `String` let _ = s1[2..].find("world").is_some(); + //~^ search_is_some let _ = s1[2..].find(&s2).is_some(); + //~^ search_is_some let _ = s1[2..].find(&s2[2..]).is_some(); + //~^ search_is_some } #[allow(clippy::clone_on_copy, clippy::map_clone)] @@ -54,6 +75,7 @@ mod issue7392 { .hand .iter() .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some()) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -70,6 +92,7 @@ mod issue7392 { .hand .iter() .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some()) + //~^ search_is_some .map(|c| c.clone()) .collect::>(); } @@ -81,23 +104,27 @@ mod issue7392 { } let vfoo = vec![Foo { foo: 1, bar: 2 }]; let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some(); + //~^ search_is_some let vfoo = vec![(42, Foo { foo: 1, bar: 2 })]; let _ = vfoo .iter() .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) + //~^ search_is_some .is_some(); } fn index_projection() { let vfoo = vec![[0, 1, 2, 3]]; let _ = vfoo.iter().find(|a| a[0] == 42).is_some(); + //~^ search_is_some } #[allow(clippy::match_like_matches_macro)] fn slice_projection() { let vfoo = vec![[0, 1, 2, 3, 0, 1, 2, 3]]; let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); + //~^ search_is_some } fn please(x: &u32) -> bool { @@ -116,16 +143,22 @@ mod issue7392 { let x = 19; let ppx: &u32 = &x; let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); + //~^ search_is_some let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); + //~^ search_is_some let v = vec![3, 2, 1, 0]; let _ = v.iter().find(|x| deref_enough(**x)).is_some(); + //~^ search_is_some let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some(); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some(); + //~^ search_is_some } fn field_index_projection() { @@ -148,6 +181,7 @@ mod issue7392 { let _ = vfoo .iter() .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) + //~^ search_is_some .is_some(); } @@ -162,11 +196,13 @@ mod issue7392 { inner: vec![Foo { bar: 0 }], }]; let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some(); + //~^ search_is_some } fn double_deref_index_projection() { let vfoo = vec![&&[0, 1, 2, 3]]; let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); + //~^ search_is_some } fn method_call_by_ref() { @@ -180,11 +216,14 @@ mod issue7392 { } let vfoo = vec![Foo { bar: 1 }]; let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); + //~^ search_is_some } fn ref_bindings() { let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); + //~^ search_is_some let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); + //~^ search_is_some } fn test_string_1(s: &str) -> bool { @@ -204,7 +243,9 @@ mod issue7392 { let lst = &[String::from("Hello"), String::from("world")]; let v: Vec<&[String]> = vec![lst]; let _ = v.iter().find(|s| s[0].is_empty()).is_some(); + //~^ search_is_some let _ = v.iter().find(|s| test_string_1(&s[0])).is_some(); + //~^ search_is_some // Field projections struct FieldProjection<'a> { @@ -214,8 +255,11 @@ mod issue7392 { let instance = FieldProjection { field: &field }; let v = vec![instance]; let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some(); + //~^ search_is_some let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some(); + //~^ search_is_some let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); + //~^ search_is_some } } @@ -231,6 +275,7 @@ mod issue9120 { fn wrapper bool>(v: Vec, func: T) -> bool { #[allow(clippy::redundant_closure)] v.iter().find(|x: &&u32| func(x)).is_some() + //~^ search_is_some } fn do_tests() { @@ -240,11 +285,14 @@ mod issue9120 { #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x: &&u32| arg_no_deref_impl(x)).is_some(); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x: &&u32| arg_no_deref_dyn(x)).is_some(); + //~^ search_is_some #[allow(clippy::redundant_closure)] let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some(); + //~^ search_is_some } } diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr index af1de7f82f80c..af719b78831a1 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr @@ -8,283 +8,286 @@ LL | let _ = v.iter().find(|&x| *x < 0).is_some(); = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:10:20 + --> tests/ui/search_is_some_fixable_some.rs:11:20 | LL | let _ = (0..1).find(|x| **y == *x).is_some(); // one dereference less | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| **y == x)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:11:20 + --> tests/ui/search_is_some_fixable_some.rs:14:20 | LL | let _ = (0..1).find(|x| *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 0)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:12:22 + --> tests/ui/search_is_some_fixable_some.rs:16:22 | LL | let _ = v.iter().find(|x| **x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| *x == 0)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:13:20 + --> tests/ui/search_is_some_fixable_some.rs:18:20 | LL | let _ = (4..5).find(|x| *x == 1 || *x == 3 || *x == 5).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 1 || x == 3 || x == 5)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:14:20 + --> tests/ui/search_is_some_fixable_some.rs:20:20 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| [1, 2, 3].contains(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:15:20 + --> tests/ui/search_is_some_fixable_some.rs:22:20 | LL | let _ = (1..3).find(|x| *x == 0 || [1, 2, 3].contains(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| x == 0 || [1, 2, 3].contains(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:16:20 + --> tests/ui/search_is_some_fixable_some.rs:24:20 | LL | let _ = (1..3).find(|x| [1, 2, 3].contains(x) || *x == 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| [1, 2, 3].contains(&x) || x == 0)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:18:10 + --> tests/ui/search_is_some_fixable_some.rs:27:10 | LL | .find(|x| [1, 2, 3].contains(x) || *x == 0 || [4, 5, 6].contains(x) || *x == -1) | __________^ +LL | | LL | | .is_some(); | |__________________^ help: consider using: `any(|x| [1, 2, 3].contains(&x) || x == 0 || [4, 5, 6].contains(&x) || x == -1)` error: called `is_some()` after searching an `Iterator` with `position` - --> tests/ui/search_is_some_fixable_some.rs:22:22 + --> tests/ui/search_is_some_fixable_some.rs:32:22 | LL | let _ = v.iter().position(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|&x| x < 0)` error: called `is_some()` after searching an `Iterator` with `rposition` - --> tests/ui/search_is_some_fixable_some.rs:25:22 + --> tests/ui/search_is_some_fixable_some.rs:36:22 | LL | let _ = v.iter().rposition(|&x| x < 0).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|&x| x < 0)` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:30:27 + --> tests/ui/search_is_some_fixable_some.rs:42:27 | LL | let _ = "hello world".find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:31:27 + --> tests/ui/search_is_some_fixable_some.rs:44:27 | LL | let _ = "hello world".find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:32:27 + --> tests/ui/search_is_some_fixable_some.rs:46:27 | LL | let _ = "hello world".find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:34:16 + --> tests/ui/search_is_some_fixable_some.rs:49:16 | LL | let _ = s1.find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:35:16 + --> tests/ui/search_is_some_fixable_some.rs:51:16 | LL | let _ = s1.find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:36:16 + --> tests/ui/search_is_some_fixable_some.rs:53:16 | LL | let _ = s1.find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:38:21 + --> tests/ui/search_is_some_fixable_some.rs:56:21 | LL | let _ = s1[2..].find("world").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains("world")` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:39:21 + --> tests/ui/search_is_some_fixable_some.rs:58:21 | LL | let _ = s1[2..].find(&s2).is_some(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2)` error: called `is_some()` after calling `find()` on a string - --> tests/ui/search_is_some_fixable_some.rs:40:21 + --> tests/ui/search_is_some_fixable_some.rs:60:21 | LL | let _ = s1[2..].find(&s2[2..]).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `contains(&s2[2..])` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:56:44 + --> tests/ui/search_is_some_fixable_some.rs:77:44 | LL | .filter(|c| filter_hand.iter().find(|cc| c == cc).is_some()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|cc| c == &cc)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:72:49 + --> tests/ui/search_is_some_fixable_some.rs:94:49 | LL | .filter(|(c, _)| filter_hand.iter().find(|cc| c == *cc).is_some()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|cc| c == cc)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:83:29 + --> tests/ui/search_is_some_fixable_some.rs:106:29 | LL | let _ = vfoo.iter().find(|v| v.foo == 1 && v.bar == 2).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.foo == 1 && v.bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:88:14 + --> tests/ui/search_is_some_fixable_some.rs:112:14 | LL | .find(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2) | ______________^ +LL | | LL | | .is_some(); | |______________________^ help: consider using: `any(|(i, v)| *i == 42 && v.foo == 1 && v.bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:94:29 + --> tests/ui/search_is_some_fixable_some.rs:119:29 | LL | let _ = vfoo.iter().find(|a| a[0] == 42).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|a| a[0] == 42)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:100:29 + --> tests/ui/search_is_some_fixable_some.rs:126:29 | LL | let _ = vfoo.iter().find(|sub| sub[1..4].len() == 3).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|sub| sub[1..4].len() == 3)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:118:30 + --> tests/ui/search_is_some_fixable_some.rs:145:30 | LL | let _ = [ppx].iter().find(|ppp_x: &&&u32| please(**ppp_x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|ppp_x: &&u32| please(ppp_x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:119:50 + --> tests/ui/search_is_some_fixable_some.rs:147:50 | LL | let _ = [String::from("Hey hey")].iter().find(|s| s.len() == 2).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s.len() == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:122:26 + --> tests/ui/search_is_some_fixable_some.rs:151:26 | LL | let _ = v.iter().find(|x| deref_enough(**x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| deref_enough(*x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:123:26 + --> tests/ui/search_is_some_fixable_some.rs:153:26 | LL | let _ = v.iter().find(|x: &&u32| deref_enough(**x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| deref_enough(*x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:126:26 + --> tests/ui/search_is_some_fixable_some.rs:157:26 | LL | let _ = v.iter().find(|x| arg_no_deref(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| arg_no_deref(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:128:26 + --> tests/ui/search_is_some_fixable_some.rs:160:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:150:14 + --> tests/ui/search_is_some_fixable_some.rs:183:14 | LL | .find(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2) | ______________^ +LL | | LL | | .is_some(); | |______________________^ help: consider using: `any(|v| v.inner_double.bar[0][0] == 2 && v.inner.bar[0] == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:164:29 + --> tests/ui/search_is_some_fixable_some.rs:198:29 | LL | let _ = vfoo.iter().find(|v| v.inner[0].bar == 2).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.inner[0].bar == 2)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:169:29 + --> tests/ui/search_is_some_fixable_some.rs:204:29 | LL | let _ = vfoo.iter().find(|x| (**x)[0] == 9).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x| (**x)[0] == 9)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:182:29 + --> tests/ui/search_is_some_fixable_some.rs:218:29 | LL | let _ = vfoo.iter().find(|v| v.by_ref(&v.bar)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.by_ref(&v.bar))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:186:55 + --> tests/ui/search_is_some_fixable_some.rs:223:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:187:55 + --> tests/ui/search_is_some_fixable_some.rs:225:55 | LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:206:26 + --> tests/ui/search_is_some_fixable_some.rs:245:26 | LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s[0].is_empty())` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:207:26 + --> tests/ui/search_is_some_fixable_some.rs:247:26 | LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| test_string_1(&s[0]))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:216:26 + --> tests/ui/search_is_some_fixable_some.rs:257:26 | LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| fp.field.is_power_of_two())` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:217:26 + --> tests/ui/search_is_some_fixable_some.rs:259:26 | LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_1(fp.field))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:218:26 + --> tests/ui/search_is_some_fixable_some.rs:261:26 | LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_2(*fp.field))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:233:18 + --> tests/ui/search_is_some_fixable_some.rs:277:18 | LL | v.iter().find(|x: &&u32| func(x)).is_some() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| func(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:242:26 + --> tests/ui/search_is_some_fixable_some.rs:287:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_impl(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_impl(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:245:26 + --> tests/ui/search_is_some_fixable_some.rs:291:26 | LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_dyn(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_dyn(&x))` error: called `is_some()` after searching an `Iterator` with `find` - --> tests/ui/search_is_some_fixable_some.rs:248:26 + --> tests/ui/search_is_some_fixable_some.rs:295:26 | LL | let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| (*arg_no_deref_dyn)(&x))` diff --git a/src/tools/clippy/tests/ui/seek_from_current.fixed b/src/tools/clippy/tests/ui/seek_from_current.fixed index 543f0c681393f..08eb15fe4e786 100644 --- a/src/tools/clippy/tests/ui/seek_from_current.fixed +++ b/src/tools/clippy/tests/ui/seek_from_current.fixed @@ -17,6 +17,7 @@ fn _msrv_1_51() -> io::Result<()> { let mut f = File::create("foo.txt")?; f.write_all(b"Hi!")?; f.stream_position()?; + //~^ seek_from_current f.seek(SeekFrom::Current(1))?; Ok(()) } diff --git a/src/tools/clippy/tests/ui/seek_from_current.rs b/src/tools/clippy/tests/ui/seek_from_current.rs index 4ed877f8ec211..1974fd60dec70 100644 --- a/src/tools/clippy/tests/ui/seek_from_current.rs +++ b/src/tools/clippy/tests/ui/seek_from_current.rs @@ -17,6 +17,7 @@ fn _msrv_1_51() -> io::Result<()> { let mut f = File::create("foo.txt")?; f.write_all(b"Hi!")?; f.seek(SeekFrom::Current(0))?; + //~^ seek_from_current f.seek(SeekFrom::Current(1))?; Ok(()) } diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed index 8859a68320f00..87747eafc4430 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -50,11 +50,13 @@ fn seek_to_start_false_trait_bound(t: &mut T) { // This should trigger clippy warning fn seek_to_start(t: &mut T) { t.rewind(); + //~^ seek_to_start_instead_of_rewind } // This should trigger clippy warning fn owned_seek_to_start(mut t: T) { t.rewind(); + //~^ seek_to_start_instead_of_rewind } // This should NOT trigger clippy warning because @@ -134,6 +136,7 @@ fn msrv_1_55() { write!(f, "{hello}").unwrap(); f.rewind(); + //~^ seek_to_start_instead_of_rewind let mut buf = String::new(); f.read_to_string(&mut buf).unwrap(); diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs index 7b72efb34ff82..e824a9b1ec317 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs @@ -50,11 +50,13 @@ fn seek_to_start_false_trait_bound(t: &mut T) { // This should trigger clippy warning fn seek_to_start(t: &mut T) { t.seek(SeekFrom::Start(0)); + //~^ seek_to_start_instead_of_rewind } // This should trigger clippy warning fn owned_seek_to_start(mut t: T) { t.seek(SeekFrom::Start(0)); + //~^ seek_to_start_instead_of_rewind } // This should NOT trigger clippy warning because @@ -134,6 +136,7 @@ fn msrv_1_55() { write!(f, "{hello}").unwrap(); f.seek(SeekFrom::Start(0)); + //~^ seek_to_start_instead_of_rewind let mut buf = String::new(); f.read_to_string(&mut buf).unwrap(); diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr index 2c3c45820e107..6c6575cc02f52 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.stderr @@ -8,13 +8,13 @@ LL | t.seek(SeekFrom::Start(0)); = help: to override `-D warnings` add `#[allow(clippy::seek_to_start_instead_of_rewind)]` error: used `seek` to go to the start of the stream - --> tests/ui/seek_to_start_instead_of_rewind.rs:57:7 + --> tests/ui/seek_to_start_instead_of_rewind.rs:58:7 | LL | t.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` error: used `seek` to go to the start of the stream - --> tests/ui/seek_to_start_instead_of_rewind.rs:136:7 + --> tests/ui/seek_to_start_instead_of_rewind.rs:138:7 | LL | f.seek(SeekFrom::Start(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `rewind()` diff --git a/src/tools/clippy/tests/ui/self_assignment.rs b/src/tools/clippy/tests/ui/self_assignment.rs index 213bca6c45158..6e82b42cf6d70 100644 --- a/src/tools/clippy/tests/ui/self_assignment.rs +++ b/src/tools/clippy/tests/ui/self_assignment.rs @@ -11,30 +11,38 @@ pub struct S<'a> { pub fn positives(mut a: usize, b: &mut u32, mut s: S) { a = a; - //~^ ERROR: self-assignment of `a` to `a` - //~| NOTE: `-D clippy::self-assignment` implied by `-D warnings` + //~^ self_assignment + *b = *b; - //~^ ERROR: self-assignment of `*b` to `*b` + //~^ self_assignment + s = s; - //~^ ERROR: self-assignment of `s` to `s` + //~^ self_assignment + s.a = s.a; - //~^ ERROR: self-assignment of `s.a` to `s.a` + //~^ self_assignment + s.b[9] = s.b[5 + 4]; - //~^ ERROR: self-assignment of `s.b[5 + 4]` to `s.b[9]` + //~^ self_assignment + s.c[0][1] = s.c[0][1]; - //~^ ERROR: self-assignment of `s.c[0][1]` to `s.c[0][1]` + //~^ self_assignment + s.b[a] = s.b[a]; - //~^ ERROR: self-assignment of `s.b[a]` to `s.b[a]` + //~^ self_assignment + *s.e = *s.e; - //~^ ERROR: self-assignment of `*s.e` to `*s.e` + //~^ self_assignment + s.b[a + 10] = s.b[10 + a]; - //~^ ERROR: self-assignment of `s.b[10 + a]` to `s.b[a + 10]` + //~^ self_assignment let mut t = (0, 1); t.1 = t.1; - //~^ ERROR: self-assignment of `t.1` to `t.1` + //~^ self_assignment + t.0 = (t.0); - //~^ ERROR: self-assignment of `(t.0)` to `t.0` + //~^ self_assignment } pub fn negatives_not_equal(mut a: usize, b: &mut usize, mut s: S) { diff --git a/src/tools/clippy/tests/ui/self_assignment.stderr b/src/tools/clippy/tests/ui/self_assignment.stderr index e92414163d4c4..e9a2164187ced 100644 --- a/src/tools/clippy/tests/ui/self_assignment.stderr +++ b/src/tools/clippy/tests/ui/self_assignment.stderr @@ -14,55 +14,55 @@ LL | *b = *b; | ^^^^^^^ error: self-assignment of `s` to `s` - --> tests/ui/self_assignment.rs:18:5 + --> tests/ui/self_assignment.rs:19:5 | LL | s = s; | ^^^^^ error: self-assignment of `s.a` to `s.a` - --> tests/ui/self_assignment.rs:20:5 + --> tests/ui/self_assignment.rs:22:5 | LL | s.a = s.a; | ^^^^^^^^^ error: self-assignment of `s.b[5 + 4]` to `s.b[9]` - --> tests/ui/self_assignment.rs:22:5 + --> tests/ui/self_assignment.rs:25:5 | LL | s.b[9] = s.b[5 + 4]; | ^^^^^^^^^^^^^^^^^^^ error: self-assignment of `s.c[0][1]` to `s.c[0][1]` - --> tests/ui/self_assignment.rs:24:5 + --> tests/ui/self_assignment.rs:28:5 | LL | s.c[0][1] = s.c[0][1]; | ^^^^^^^^^^^^^^^^^^^^^ error: self-assignment of `s.b[a]` to `s.b[a]` - --> tests/ui/self_assignment.rs:26:5 + --> tests/ui/self_assignment.rs:31:5 | LL | s.b[a] = s.b[a]; | ^^^^^^^^^^^^^^^ error: self-assignment of `*s.e` to `*s.e` - --> tests/ui/self_assignment.rs:28:5 + --> tests/ui/self_assignment.rs:34:5 | LL | *s.e = *s.e; | ^^^^^^^^^^^ error: self-assignment of `s.b[10 + a]` to `s.b[a + 10]` - --> tests/ui/self_assignment.rs:30:5 + --> tests/ui/self_assignment.rs:37:5 | LL | s.b[a + 10] = s.b[10 + a]; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: self-assignment of `t.1` to `t.1` - --> tests/ui/self_assignment.rs:34:5 + --> tests/ui/self_assignment.rs:41:5 | LL | t.1 = t.1; | ^^^^^^^^^ error: self-assignment of `(t.0)` to `t.0` - --> tests/ui/self_assignment.rs:36:5 + --> tests/ui/self_assignment.rs:44:5 | LL | t.0 = (t.0); | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/self_named_constructors.rs b/src/tools/clippy/tests/ui/self_named_constructors.rs index dc326b399481c..8b6453e0d1d7b 100644 --- a/src/tools/clippy/tests/ui/self_named_constructors.rs +++ b/src/tools/clippy/tests/ui/self_named_constructors.rs @@ -5,8 +5,8 @@ struct ShouldNotSpawn; impl ShouldSpawn { pub fn should_spawn() -> ShouldSpawn { - //~^ ERROR: constructor `should_spawn` has the same name as the type - //~| NOTE: `-D clippy::self-named-constructors` implied by `-D warnings` + //~^ self_named_constructors + ShouldSpawn } diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed index 6c8c835d0e0e3..3de14e9d2595e 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.fixed @@ -16,21 +16,25 @@ fn get_unit() {} // the functions below trigger the lint fn main() { println!("Hello"); + //~^ semicolon_if_nothing_returned } fn hello() { get_unit(); + //~^ semicolon_if_nothing_returned } fn basic101(x: i32) { let y: i32; y = x + 1; + //~^ semicolon_if_nothing_returned } #[rustfmt::skip] fn closure_error() { let _d = || { hello(); + //~^ semicolon_if_nothing_returned }; } @@ -42,6 +46,7 @@ fn unsafe_checks_error() { let mut s = MaybeUninit::::uninit(); let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()); + //~^ semicolon_if_nothing_returned }; } diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs index 2c2e4c0241904..304f43fb457cf 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.rs @@ -16,21 +16,25 @@ fn get_unit() {} // the functions below trigger the lint fn main() { println!("Hello") + //~^ semicolon_if_nothing_returned } fn hello() { get_unit() + //~^ semicolon_if_nothing_returned } fn basic101(x: i32) { let y: i32; y = x + 1 + //~^ semicolon_if_nothing_returned } #[rustfmt::skip] fn closure_error() { let _d = || { hello() + //~^ semicolon_if_nothing_returned }; } @@ -42,6 +46,7 @@ fn unsafe_checks_error() { let mut s = MaybeUninit::::uninit(); let _d = || unsafe { ptr::drop_in_place(s.as_mut_ptr()) + //~^ semicolon_if_nothing_returned }; } diff --git a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr index 69e434b142cf4..d7d117e05bdf7 100644 --- a/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr +++ b/src/tools/clippy/tests/ui/semicolon_if_nothing_returned.stderr @@ -8,25 +8,25 @@ LL | println!("Hello") = help: to override `-D warnings` add `#[allow(clippy::semicolon_if_nothing_returned)]` error: consider adding a `;` to the last statement for consistent formatting - --> tests/ui/semicolon_if_nothing_returned.rs:22:5 + --> tests/ui/semicolon_if_nothing_returned.rs:23:5 | LL | get_unit() | ^^^^^^^^^^ help: add a `;` here: `get_unit();` error: consider adding a `;` to the last statement for consistent formatting - --> tests/ui/semicolon_if_nothing_returned.rs:27:5 + --> tests/ui/semicolon_if_nothing_returned.rs:29:5 | LL | y = x + 1 | ^^^^^^^^^ help: add a `;` here: `y = x + 1;` error: consider adding a `;` to the last statement for consistent formatting - --> tests/ui/semicolon_if_nothing_returned.rs:33:9 + --> tests/ui/semicolon_if_nothing_returned.rs:36:9 | LL | hello() | ^^^^^^^ help: add a `;` here: `hello();` error: consider adding a `;` to the last statement for consistent formatting - --> tests/ui/semicolon_if_nothing_returned.rs:44:9 + --> tests/ui/semicolon_if_nothing_returned.rs:48:9 | LL | ptr::drop_in_place(s.as_mut_ptr()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: add a `;` here: `ptr::drop_in_place(s.as_mut_ptr());` diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed index 21681e71589e9..7eb53e733ad50 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed @@ -36,7 +36,9 @@ fn main() { } { unit_fn_block(); } + //~^ semicolon_inside_block unsafe { unit_fn_block(); } + //~^ semicolon_inside_block { unit_fn_block(); } unsafe { unit_fn_block(); } @@ -45,6 +47,7 @@ fn main() { unsafe { unit_fn_block(); }; { + //~^ semicolon_inside_block unit_fn_block(); unit_fn_block(); } @@ -58,6 +61,7 @@ fn main() { }; { m!(()); } + //~^ semicolon_inside_block { m!(()); } { m!(()); }; m!(0); diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs index 3a81661cd16f5..9fa5b117194d7 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs @@ -36,7 +36,9 @@ fn main() { } { unit_fn_block() }; + //~^ semicolon_inside_block unsafe { unit_fn_block() }; + //~^ semicolon_inside_block { unit_fn_block(); } unsafe { unit_fn_block(); } @@ -45,6 +47,7 @@ fn main() { unsafe { unit_fn_block(); }; { + //~^ semicolon_inside_block unit_fn_block(); unit_fn_block() }; @@ -58,6 +61,7 @@ fn main() { }; { m!(()) }; + //~^ semicolon_inside_block { m!(()); } { m!(()); }; m!(0); diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr index d32fb681d3b99..23433f4e7ef90 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.stderr +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.stderr @@ -13,7 +13,7 @@ LL + { unit_fn_block(); } | error: consider moving the `;` inside the block for consistent formatting - --> tests/ui/semicolon_inside_block.rs:39:5 + --> tests/ui/semicolon_inside_block.rs:40:5 | LL | unsafe { unit_fn_block() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,9 +25,10 @@ LL + unsafe { unit_fn_block(); } | error: consider moving the `;` inside the block for consistent formatting - --> tests/ui/semicolon_inside_block.rs:47:5 + --> tests/ui/semicolon_inside_block.rs:49:5 | LL | / { +LL | | LL | | unit_fn_block(); LL | | unit_fn_block() LL | | }; @@ -40,7 +41,7 @@ LL ~ } | error: consider moving the `;` inside the block for consistent formatting - --> tests/ui/semicolon_inside_block.rs:60:5 + --> tests/ui/semicolon_inside_block.rs:63:5 | LL | { m!(()) }; | ^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed index ac7e86631caea..52fae9a3aff13 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed @@ -39,7 +39,9 @@ fn main() { unsafe { unit_fn_block() }; { unit_fn_block() }; + //~^ semicolon_outside_block unsafe { unit_fn_block() }; + //~^ semicolon_outside_block { unit_fn_block(); }; unsafe { unit_fn_block(); }; @@ -49,6 +51,7 @@ fn main() { unit_fn_block() }; { + //~^ semicolon_outside_block unit_fn_block(); unit_fn_block() }; @@ -59,6 +62,7 @@ fn main() { { m!(()) }; { m!(()) }; + //~^ semicolon_outside_block { m!(()); }; m!(0); m!(1); @@ -81,10 +85,12 @@ fn main() { { unit_fn_block(); }; unsafe { + //~^ semicolon_outside_block std::arch::asm!("") }; { + //~^ semicolon_outside_block line!() }; diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.rs b/src/tools/clippy/tests/ui/semicolon_outside_block.rs index 68f25339e3228..5975e66fbb819 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.rs @@ -39,7 +39,9 @@ fn main() { unsafe { unit_fn_block() }; { unit_fn_block(); } + //~^ semicolon_outside_block unsafe { unit_fn_block(); } + //~^ semicolon_outside_block { unit_fn_block(); }; unsafe { unit_fn_block(); }; @@ -49,6 +51,7 @@ fn main() { unit_fn_block() }; { + //~^ semicolon_outside_block unit_fn_block(); unit_fn_block(); } @@ -59,6 +62,7 @@ fn main() { { m!(()) }; { m!(()); } + //~^ semicolon_outside_block { m!(()); }; m!(0); m!(1); @@ -81,10 +85,12 @@ fn main() { { unit_fn_block(); }; unsafe { + //~^ semicolon_outside_block std::arch::asm!(""); } { + //~^ semicolon_outside_block line!(); } diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui/semicolon_outside_block.stderr index ff8c00048f630..18d6dc697f2e3 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.stderr +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.stderr @@ -13,7 +13,7 @@ LL + { unit_fn_block() }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui/semicolon_outside_block.rs:42:5 + --> tests/ui/semicolon_outside_block.rs:43:5 | LL | unsafe { unit_fn_block(); } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,9 +25,10 @@ LL + unsafe { unit_fn_block() }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui/semicolon_outside_block.rs:51:5 + --> tests/ui/semicolon_outside_block.rs:53:5 | LL | / { +LL | | LL | | unit_fn_block(); LL | | unit_fn_block(); LL | | } @@ -40,7 +41,7 @@ LL ~ }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui/semicolon_outside_block.rs:61:5 + --> tests/ui/semicolon_outside_block.rs:64:5 | LL | { m!(()); } | ^^^^^^^^^^^ @@ -52,9 +53,10 @@ LL + { m!(()) }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui/semicolon_outside_block.rs:83:5 + --> tests/ui/semicolon_outside_block.rs:87:5 | LL | / unsafe { +LL | | LL | | std::arch::asm!(""); LL | | } | |_____^ @@ -66,9 +68,10 @@ LL ~ }; | error: consider moving the `;` outside the block for consistent formatting - --> tests/ui/semicolon_outside_block.rs:87:5 + --> tests/ui/semicolon_outside_block.rs:92:5 | LL | / { +LL | | LL | | line!(); LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/serde.rs b/src/tools/clippy/tests/ui/serde.rs index af8b10f3e6aeb..8ab1144e57006 100644 --- a/src/tools/clippy/tests/ui/serde.rs +++ b/src/tools/clippy/tests/ui/serde.rs @@ -37,8 +37,7 @@ impl<'de> serde::de::Visitor<'de> for B { } fn visit_string(self, _v: String) -> Result - //~^ ERROR: you should not implement `visit_string` without also implementing `visit_s - //~| NOTE: `-D clippy::serde-api-misuse` implied by `-D warnings` + //~^ serde_api_misuse where E: serde::de::Error, { diff --git a/src/tools/clippy/tests/ui/serde.stderr b/src/tools/clippy/tests/ui/serde.stderr index f71d41d58aae1..eb6b7c6b0c36a 100644 --- a/src/tools/clippy/tests/ui/serde.stderr +++ b/src/tools/clippy/tests/ui/serde.stderr @@ -3,9 +3,9 @@ error: you should not implement `visit_string` without also implementing `visit_ | LL | / fn visit_string(self, _v: String) -> Result LL | | -LL | | LL | | where -... | +LL | | E: serde::de::Error, +LL | | { LL | | unimplemented!() LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.rs b/src/tools/clippy/tests/ui/set_contains_or_insert.rs index d3a3e1c878b3a..575cfda139a4c 100644 --- a/src/tools/clippy/tests/ui/set_contains_or_insert.rs +++ b/src/tools/clippy/tests/ui/set_contains_or_insert.rs @@ -10,35 +10,42 @@ fn should_warn_hashset() { let value = 5; if !set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); println!("Just a comment"); } if set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); println!("Just a comment"); } if !set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); } if !!set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); println!("Just a comment"); } if (&set).contains(&value) { + //~^ set_contains_or_insert set.insert(value); } let borrow_value = &6; if !set.contains(borrow_value) { + //~^ set_contains_or_insert set.insert(*borrow_value); } let borrow_set = &mut set; if !borrow_set.contains(&value) { + //~^ set_contains_or_insert borrow_set.insert(value); } } @@ -77,35 +84,42 @@ fn should_warn_btreeset() { let value = 5; if !set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); println!("Just a comment"); } if set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); println!("Just a comment"); } if !set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); } if !!set.contains(&value) { + //~^ set_contains_or_insert set.insert(value); println!("Just a comment"); } if (&set).contains(&value) { + //~^ set_contains_or_insert set.insert(value); } let borrow_value = &6; if !set.contains(borrow_value) { + //~^ set_contains_or_insert set.insert(*borrow_value); } let borrow_set = &mut set; if !borrow_set.contains(&value) { + //~^ set_contains_or_insert borrow_set.insert(value); } } diff --git a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr index 14ad630054482..3152b1136458f 100644 --- a/src/tools/clippy/tests/ui/set_contains_or_insert.stderr +++ b/src/tools/clippy/tests/ui/set_contains_or_insert.stderr @@ -3,6 +3,7 @@ error: usage of `HashSet::insert` after `HashSet::contains` | LL | if !set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ | @@ -10,106 +11,119 @@ LL | set.insert(value); = help: to override `-D warnings` add `#[allow(clippy::set_contains_or_insert)]` error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/set_contains_or_insert.rs:17:12 + --> tests/ui/set_contains_or_insert.rs:18:12 | LL | if set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/set_contains_or_insert.rs:22:13 + --> tests/ui/set_contains_or_insert.rs:24:13 | LL | if !set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/set_contains_or_insert.rs:26:14 + --> tests/ui/set_contains_or_insert.rs:29:14 | LL | if !!set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/set_contains_or_insert.rs:31:15 + --> tests/ui/set_contains_or_insert.rs:35:15 | LL | if (&set).contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/set_contains_or_insert.rs:36:13 + --> tests/ui/set_contains_or_insert.rs:41:13 | LL | if !set.contains(borrow_value) { | ^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | set.insert(*borrow_value); | ^^^^^^^^^^^^^^^^^^^^^ error: usage of `HashSet::insert` after `HashSet::contains` - --> tests/ui/set_contains_or_insert.rs:41:20 + --> tests/ui/set_contains_or_insert.rs:47:20 | LL | if !borrow_set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | borrow_set.insert(value); | ^^^^^^^^^^^^^ error: usage of `BTreeSet::insert` after `BTreeSet::contains` - --> tests/ui/set_contains_or_insert.rs:79:13 + --> tests/ui/set_contains_or_insert.rs:86:13 | LL | if !set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `BTreeSet::insert` after `BTreeSet::contains` - --> tests/ui/set_contains_or_insert.rs:84:12 + --> tests/ui/set_contains_or_insert.rs:92:12 | LL | if set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `BTreeSet::insert` after `BTreeSet::contains` - --> tests/ui/set_contains_or_insert.rs:89:13 + --> tests/ui/set_contains_or_insert.rs:98:13 | LL | if !set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `BTreeSet::insert` after `BTreeSet::contains` - --> tests/ui/set_contains_or_insert.rs:93:14 + --> tests/ui/set_contains_or_insert.rs:103:14 | LL | if !!set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `BTreeSet::insert` after `BTreeSet::contains` - --> tests/ui/set_contains_or_insert.rs:98:15 + --> tests/ui/set_contains_or_insert.rs:109:15 | LL | if (&set).contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | set.insert(value); | ^^^^^^^^^^^^^ error: usage of `BTreeSet::insert` after `BTreeSet::contains` - --> tests/ui/set_contains_or_insert.rs:103:13 + --> tests/ui/set_contains_or_insert.rs:115:13 | LL | if !set.contains(borrow_value) { | ^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | set.insert(*borrow_value); | ^^^^^^^^^^^^^^^^^^^^^ error: usage of `BTreeSet::insert` after `BTreeSet::contains` - --> tests/ui/set_contains_or_insert.rs:108:20 + --> tests/ui/set_contains_or_insert.rs:121:20 | LL | if !borrow_set.contains(&value) { | ^^^^^^^^^^^^^^^^ +LL | LL | borrow_set.insert(value); | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs index 31944f5ef1b1d..7d503a1cf6c17 100644 --- a/src/tools/clippy/tests/ui/shadow.rs +++ b/src/tools/clippy/tests/ui/shadow.rs @@ -22,22 +22,34 @@ macro_rules! reuse { fn shadow_same() { let x = 1; let x = x; + //~^ shadow_same let mut x = &x; + //~^ shadow_same let x = &mut x; + //~^ shadow_same let x = *x; + //~^ shadow_same } fn shadow_reuse() -> Option<()> { let x = ([[0]], ()); let x = x.0; + //~^ shadow_reuse let x = x[0]; + //~^ shadow_reuse let [x] = x; + //~^ shadow_reuse let x = Some(x); + //~^ shadow_reuse let x = foo(x); + //~^ shadow_reuse let x = || x; + //~^ shadow_reuse let x = Some(1).map(|_| x)?; + //~^ shadow_reuse let y = 1; let y = match y { + //~^ shadow_reuse 1 => 2, _ => 3, }; @@ -53,27 +65,36 @@ fn shadow_reuse_macro() { fn shadow_unrelated() { let x = 1; let x = 2; + //~^ shadow_unrelated } fn syntax() { fn f(x: u32) { let x = 1; + //~^ shadow_unrelated } let x = 1; match Some(1) { Some(1) => {}, Some(x) => { + //~^ shadow_unrelated let x = 1; + //~^ shadow_unrelated }, _ => {}, } if let Some(x) = Some(1) {} + //~^ shadow_unrelated while let Some(x) = Some(1) {} + //~^ shadow_unrelated let _ = |[x]: [u32; 1]| { + //~^ shadow_unrelated let x = 1; + //~^ shadow_unrelated }; let y = Some(1); if let Some(y) = y {} + //~^ shadow_reuse } fn negative() { @@ -110,12 +131,14 @@ pub async fn foo1(_a: i32) {} pub async fn foo2(_a: i32, _b: i64) { let _b = _a; + //~^ shadow_unrelated } fn ice_8748() { let _ = [0; { let x = 1; if let Some(x) = Some(1) { x } else { 1 } + //~^ shadow_unrelated }]; } @@ -126,10 +149,12 @@ fn shadow_closure() { #[allow(clippy::shadow_reuse)] let y = x.map(|x| x + 1); let z = x.map(|x| x + 1); + //~^ shadow_reuse let a: Vec> = [100u8, 120, 140] .iter() .map(|i| i.checked_mul(2)) .map(|i| i.map(|i| i - 10)) + //~^ shadow_reuse .collect(); } @@ -139,6 +164,7 @@ struct Issue13795 { fn issue13795(value: Issue13795) { let Issue13795 { value, .. } = value; + //~^ shadow_same } fn main() {} diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr index c8c524b3a2f58..649f843575a7a 100644 --- a/src/tools/clippy/tests/ui/shadow.stderr +++ b/src/tools/clippy/tests/ui/shadow.stderr @@ -13,7 +13,7 @@ LL | let x = 1; = help: to override `-D warnings` add `#[allow(clippy::shadow_same)]` error: `mut x` is shadowed by itself in `&x` - --> tests/ui/shadow.rs:25:13 + --> tests/ui/shadow.rs:26:13 | LL | let mut x = &x; | ^ @@ -25,37 +25,37 @@ LL | let x = x; | ^ error: `x` is shadowed by itself in `&mut x` - --> tests/ui/shadow.rs:26:9 + --> tests/ui/shadow.rs:28:9 | LL | let x = &mut x; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:25:9 + --> tests/ui/shadow.rs:26:9 | LL | let mut x = &x; | ^^^^^ error: `x` is shadowed by itself in `*x` - --> tests/ui/shadow.rs:27:9 + --> tests/ui/shadow.rs:30:9 | LL | let x = *x; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:26:9 + --> tests/ui/shadow.rs:28:9 | LL | let x = &mut x; | ^ error: `x` is shadowed - --> tests/ui/shadow.rs:32:9 + --> tests/ui/shadow.rs:36:9 | LL | let x = x.0; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:31:9 + --> tests/ui/shadow.rs:35:9 | LL | let x = ([[0]], ()); | ^ @@ -63,97 +63,97 @@ LL | let x = ([[0]], ()); = help: to override `-D warnings` add `#[allow(clippy::shadow_reuse)]` error: `x` is shadowed - --> tests/ui/shadow.rs:33:9 + --> tests/ui/shadow.rs:38:9 | LL | let x = x[0]; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:32:9 + --> tests/ui/shadow.rs:36:9 | LL | let x = x.0; | ^ error: `x` is shadowed - --> tests/ui/shadow.rs:34:10 + --> tests/ui/shadow.rs:40:10 | LL | let [x] = x; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:33:9 + --> tests/ui/shadow.rs:38:9 | LL | let x = x[0]; | ^ error: `x` is shadowed - --> tests/ui/shadow.rs:35:9 + --> tests/ui/shadow.rs:42:9 | LL | let x = Some(x); | ^ | note: previous binding is here - --> tests/ui/shadow.rs:34:10 + --> tests/ui/shadow.rs:40:10 | LL | let [x] = x; | ^ error: `x` is shadowed - --> tests/ui/shadow.rs:36:9 + --> tests/ui/shadow.rs:44:9 | LL | let x = foo(x); | ^ | note: previous binding is here - --> tests/ui/shadow.rs:35:9 + --> tests/ui/shadow.rs:42:9 | LL | let x = Some(x); | ^ error: `x` is shadowed - --> tests/ui/shadow.rs:37:9 + --> tests/ui/shadow.rs:46:9 | LL | let x = || x; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:36:9 + --> tests/ui/shadow.rs:44:9 | LL | let x = foo(x); | ^ error: `x` is shadowed - --> tests/ui/shadow.rs:38:9 + --> tests/ui/shadow.rs:48:9 | LL | let x = Some(1).map(|_| x)?; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:37:9 + --> tests/ui/shadow.rs:46:9 | LL | let x = || x; | ^ error: `y` is shadowed - --> tests/ui/shadow.rs:40:9 + --> tests/ui/shadow.rs:51:9 | LL | let y = match y { | ^ | note: previous binding is here - --> tests/ui/shadow.rs:39:9 + --> tests/ui/shadow.rs:50:9 | LL | let y = 1; | ^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:55:9 + --> tests/ui/shadow.rs:67:9 | LL | let x = 2; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:54:9 + --> tests/ui/shadow.rs:66:9 | LL | let x = 1; | ^ @@ -161,157 +161,157 @@ LL | let x = 1; = help: to override `-D warnings` add `#[allow(clippy::shadow_unrelated)]` error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:60:13 + --> tests/ui/shadow.rs:73:13 | LL | let x = 1; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:59:10 + --> tests/ui/shadow.rs:72:10 | LL | fn f(x: u32) { | ^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:65:14 + --> tests/ui/shadow.rs:79:14 | LL | Some(x) => { | ^ | note: previous binding is here - --> tests/ui/shadow.rs:62:9 + --> tests/ui/shadow.rs:76:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:66:17 + --> tests/ui/shadow.rs:81:17 | LL | let x = 1; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:65:14 + --> tests/ui/shadow.rs:79:14 | LL | Some(x) => { | ^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:70:17 + --> tests/ui/shadow.rs:86:17 | LL | if let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> tests/ui/shadow.rs:62:9 + --> tests/ui/shadow.rs:76:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:71:20 + --> tests/ui/shadow.rs:88:20 | LL | while let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> tests/ui/shadow.rs:62:9 + --> tests/ui/shadow.rs:76:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:72:15 + --> tests/ui/shadow.rs:90:15 | LL | let _ = |[x]: [u32; 1]| { | ^ | note: previous binding is here - --> tests/ui/shadow.rs:62:9 + --> tests/ui/shadow.rs:76:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:73:13 + --> tests/ui/shadow.rs:92:13 | LL | let x = 1; | ^ | note: previous binding is here - --> tests/ui/shadow.rs:72:15 + --> tests/ui/shadow.rs:90:15 | LL | let _ = |[x]: [u32; 1]| { | ^ error: `y` is shadowed - --> tests/ui/shadow.rs:76:17 + --> tests/ui/shadow.rs:96:17 | LL | if let Some(y) = y {} | ^ | note: previous binding is here - --> tests/ui/shadow.rs:75:9 + --> tests/ui/shadow.rs:95:9 | LL | let y = Some(1); | ^ error: `_b` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:112:9 + --> tests/ui/shadow.rs:133:9 | LL | let _b = _a; | ^^ | note: previous binding is here - --> tests/ui/shadow.rs:111:28 + --> tests/ui/shadow.rs:132:28 | LL | pub async fn foo2(_a: i32, _b: i64) { | ^^ error: `x` shadows a previous, unrelated binding - --> tests/ui/shadow.rs:118:21 + --> tests/ui/shadow.rs:140:21 | LL | if let Some(x) = Some(1) { x } else { 1 } | ^ | note: previous binding is here - --> tests/ui/shadow.rs:117:13 + --> tests/ui/shadow.rs:139:13 | LL | let x = 1; | ^ error: `x` is shadowed - --> tests/ui/shadow.rs:128:20 + --> tests/ui/shadow.rs:151:20 | LL | let z = x.map(|x| x + 1); | ^ | note: previous binding is here - --> tests/ui/shadow.rs:125:9 + --> tests/ui/shadow.rs:148:9 | LL | let x = Some(1); | ^ error: `i` is shadowed - --> tests/ui/shadow.rs:132:25 + --> tests/ui/shadow.rs:156:25 | LL | .map(|i| i.map(|i| i - 10)) | ^ | note: previous binding is here - --> tests/ui/shadow.rs:132:15 + --> tests/ui/shadow.rs:156:15 | LL | .map(|i| i.map(|i| i - 10)) | ^ error: `value` is shadowed by itself in `value` - --> tests/ui/shadow.rs:141:22 + --> tests/ui/shadow.rs:166:22 | LL | let Issue13795 { value, .. } = value; | ^^^^^ | note: previous binding is here - --> tests/ui/shadow.rs:140:15 + --> tests/ui/shadow.rs:165:15 | LL | fn issue13795(value: Issue13795) { | ^^^^^ diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.fixed b/src/tools/clippy/tests/ui/short_circuit_statement.fixed index a2bf07ac60523..133d296e259cf 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.fixed +++ b/src/tools/clippy/tests/ui/short_circuit_statement.fixed @@ -3,15 +3,19 @@ fn main() { if f() { g(); } - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + if !f() { g(); } - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + if 1 != 2 { g(); } - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + if f() || g() { H * 2; } - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + if !(f() || g()) { H * 2; } - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement macro_rules! mac { ($f:ident or $g:ident) => { @@ -26,9 +30,10 @@ fn main() { } if mac!() { mac!(); } - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + if !mac!() { mac!(); } - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement // Do not lint if the expression comes from a macro mac!(); diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.rs b/src/tools/clippy/tests/ui/short_circuit_statement.rs index bdba546ad8f63..4275ae64fdd65 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.rs +++ b/src/tools/clippy/tests/ui/short_circuit_statement.rs @@ -3,15 +3,19 @@ fn main() { f() && g(); - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + f() || g(); - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + 1 == 2 || g(); - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + (f() || g()) && (H * 2); - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + (f() || g()) || (H * 2); - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement macro_rules! mac { ($f:ident or $g:ident) => { @@ -26,9 +30,10 @@ fn main() { } mac!() && mac!(); - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement + mac!() || mac!(); - //~^ ERROR: boolean short circuit operator in statement + //~^ short_circuit_statement // Do not lint if the expression comes from a macro mac!(); diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.stderr b/src/tools/clippy/tests/ui/short_circuit_statement.stderr index ecf6676405b4e..acd28d41a33ae 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.stderr +++ b/src/tools/clippy/tests/ui/short_circuit_statement.stderr @@ -8,37 +8,37 @@ LL | f() && g(); = help: to override `-D warnings` add `#[allow(clippy::short_circuit_statement)]` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:7:5 + --> tests/ui/short_circuit_statement.rs:8:5 | LL | f() || g(); | ^^^^^^^^^^^ help: replace it with: `if !f() { g(); }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:9:5 + --> tests/ui/short_circuit_statement.rs:11:5 | LL | 1 == 2 || g(); | ^^^^^^^^^^^^^^ help: replace it with: `if 1 != 2 { g(); }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:11:5 + --> tests/ui/short_circuit_statement.rs:14:5 | LL | (f() || g()) && (H * 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `if f() || g() { H * 2; }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:13:5 + --> tests/ui/short_circuit_statement.rs:17:5 | LL | (f() || g()) || (H * 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `if !(f() || g()) { H * 2; }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:28:5 + --> tests/ui/short_circuit_statement.rs:32:5 | LL | mac!() && mac!(); | ^^^^^^^^^^^^^^^^^ help: replace it with: `if mac!() { mac!(); }` error: boolean short circuit operator in statement may be clearer using an explicit test - --> tests/ui/short_circuit_statement.rs:30:5 + --> tests/ui/short_circuit_statement.rs:35:5 | LL | mac!() || mac!(); | ^^^^^^^^^^^^^^^^^ help: replace it with: `if !mac!() { mac!(); }` diff --git a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs index 50999c6f2198b..4ec0f02d66451 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::all, clippy::pedantic)] #![allow( clippy::missing_errors_doc, diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs index 85eed3f06f64a..87b3a7d2fa0cf 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs @@ -23,77 +23,92 @@ impl T { // trait method list part 1, should lint all // ***************************************** pub fn add(self, other: T) -> T { - //~^ ERROR: method `add` can be confused for the standard trait method `std::ops::Add: + //~^ should_implement_trait + unimplemented!() } pub fn as_mut(&mut self) -> &mut T { - //~^ ERROR: method `as_mut` can be confused for the standard trait method `std::conver + //~^ should_implement_trait + unimplemented!() } pub fn as_ref(&self) -> &T { - //~^ ERROR: method `as_ref` can be confused for the standard trait method `std::conver + //~^ should_implement_trait + unimplemented!() } pub fn bitand(self, rhs: T) -> T { - //~^ ERROR: method `bitand` can be confused for the standard trait method `std::ops::B + //~^ should_implement_trait + unimplemented!() } pub fn bitor(self, rhs: Self) -> Self { - //~^ ERROR: method `bitor` can be confused for the standard trait method `std::ops::Bi + //~^ should_implement_trait + unimplemented!() } pub fn bitxor(self, rhs: Self) -> Self { - //~^ ERROR: method `bitxor` can be confused for the standard trait method `std::ops::B + //~^ should_implement_trait + unimplemented!() } pub fn borrow(&self) -> &str { - //~^ ERROR: method `borrow` can be confused for the standard trait method `std::borrow + //~^ should_implement_trait + unimplemented!() } pub fn borrow_mut(&mut self) -> &mut str { - //~^ ERROR: method `borrow_mut` can be confused for the standard trait method `std::bo + //~^ should_implement_trait + unimplemented!() } pub fn clone(&self) -> Self { - //~^ ERROR: method `clone` can be confused for the standard trait method `std::clone:: + //~^ should_implement_trait + unimplemented!() } pub fn cmp(&self, other: &Self) -> Self { - //~^ ERROR: method `cmp` can be confused for the standard trait method `std::cmp::Ord: + //~^ should_implement_trait + unimplemented!() } pub fn default() -> Self { - //~^ ERROR: method `default` can be confused for the standard trait method `std::defau + //~^ should_implement_trait + unimplemented!() } pub fn deref(&self) -> &Self { - //~^ ERROR: method `deref` can be confused for the standard trait method `std::ops::De + //~^ should_implement_trait + unimplemented!() } pub fn deref_mut(&mut self) -> &mut Self { - //~^ ERROR: method `deref_mut` can be confused for the standard trait method `std::ops + //~^ should_implement_trait + unimplemented!() } pub fn div(self, rhs: Self) -> Self { - //~^ ERROR: method `div` can be confused for the standard trait method `std::ops::Div: + //~^ should_implement_trait + unimplemented!() } pub fn drop(&mut self) { - //~^ ERROR: method `drop` can be confused for the standard trait method `std::ops::Dro + //~^ should_implement_trait + unimplemented!() } // ********** diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr index dfa55ace40f0a..8738b61192a3c 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr @@ -3,6 +3,7 @@ error: method `add` can be confused for the standard trait method `std::ops::Add | LL | / pub fn add(self, other: T) -> T { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -12,10 +13,11 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]` error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut` - --> tests/ui/should_impl_trait/method_list_1.rs:30:5 + --> tests/ui/should_impl_trait/method_list_1.rs:31:5 | LL | / pub fn as_mut(&mut self) -> &mut T { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -23,10 +25,11 @@ LL | | } = help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref` - --> tests/ui/should_impl_trait/method_list_1.rs:35:5 + --> tests/ui/should_impl_trait/method_list_1.rs:37:5 | LL | / pub fn as_ref(&self) -> &T { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -34,10 +37,11 @@ LL | | } = help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand` - --> tests/ui/should_impl_trait/method_list_1.rs:40:5 + --> tests/ui/should_impl_trait/method_list_1.rs:43:5 | LL | / pub fn bitand(self, rhs: T) -> T { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -45,10 +49,11 @@ LL | | } = help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor` - --> tests/ui/should_impl_trait/method_list_1.rs:45:5 + --> tests/ui/should_impl_trait/method_list_1.rs:49:5 | LL | / pub fn bitor(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -56,10 +61,11 @@ LL | | } = help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor` - --> tests/ui/should_impl_trait/method_list_1.rs:50:5 + --> tests/ui/should_impl_trait/method_list_1.rs:55:5 | LL | / pub fn bitxor(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -67,10 +73,11 @@ LL | | } = help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow` - --> tests/ui/should_impl_trait/method_list_1.rs:55:5 + --> tests/ui/should_impl_trait/method_list_1.rs:61:5 | LL | / pub fn borrow(&self) -> &str { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -78,10 +85,11 @@ LL | | } = help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut` - --> tests/ui/should_impl_trait/method_list_1.rs:60:5 + --> tests/ui/should_impl_trait/method_list_1.rs:67:5 | LL | / pub fn borrow_mut(&mut self) -> &mut str { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -89,10 +97,11 @@ LL | | } = help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone` - --> tests/ui/should_impl_trait/method_list_1.rs:65:5 + --> tests/ui/should_impl_trait/method_list_1.rs:73:5 | LL | / pub fn clone(&self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -100,10 +109,11 @@ LL | | } = help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp` - --> tests/ui/should_impl_trait/method_list_1.rs:70:5 + --> tests/ui/should_impl_trait/method_list_1.rs:79:5 | LL | / pub fn cmp(&self, other: &Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -111,10 +121,11 @@ LL | | } = help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name error: method `default` can be confused for the standard trait method `std::default::Default::default` - --> tests/ui/should_impl_trait/method_list_1.rs:75:5 + --> tests/ui/should_impl_trait/method_list_1.rs:85:5 | LL | / pub fn default() -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -122,10 +133,11 @@ LL | | } = help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref` - --> tests/ui/should_impl_trait/method_list_1.rs:80:5 + --> tests/ui/should_impl_trait/method_list_1.rs:91:5 | LL | / pub fn deref(&self) -> &Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -133,10 +145,11 @@ LL | | } = help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut` - --> tests/ui/should_impl_trait/method_list_1.rs:85:5 + --> tests/ui/should_impl_trait/method_list_1.rs:97:5 | LL | / pub fn deref_mut(&mut self) -> &mut Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -144,10 +157,11 @@ LL | | } = help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name error: method `div` can be confused for the standard trait method `std::ops::Div::div` - --> tests/ui/should_impl_trait/method_list_1.rs:90:5 + --> tests/ui/should_impl_trait/method_list_1.rs:103:5 | LL | / pub fn div(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -155,10 +169,11 @@ LL | | } = help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop` - --> tests/ui/should_impl_trait/method_list_1.rs:95:5 + --> tests/ui/should_impl_trait/method_list_1.rs:109:5 | LL | / pub fn drop(&mut self) { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs index 33211b32d74b3..f0c4d4f15cb63 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs @@ -24,77 +24,92 @@ impl T { // ***************************************** pub fn eq(&self, other: &Self) -> bool { - //~^ ERROR: method `eq` can be confused for the standard trait method `std::cmp::Parti + //~^ should_implement_trait + unimplemented!() } pub fn from_iter(iter: T) -> Self { - //~^ ERROR: method `from_iter` can be confused for the standard trait method `std::ite + //~^ should_implement_trait + unimplemented!() } pub fn from_str(s: &str) -> Result { - //~^ ERROR: method `from_str` can be confused for the standard trait method `std::str: + //~^ should_implement_trait + unimplemented!() } pub fn hash(&self, state: &mut T) { - //~^ ERROR: method `hash` can be confused for the standard trait method `std::hash::Ha + //~^ should_implement_trait + unimplemented!() } pub fn index(&self, index: usize) -> &Self { - //~^ ERROR: method `index` can be confused for the standard trait method `std::ops::In + //~^ should_implement_trait + unimplemented!() } pub fn index_mut(&mut self, index: usize) -> &mut Self { - //~^ ERROR: method `index_mut` can be confused for the standard trait method `std::ops + //~^ should_implement_trait + unimplemented!() } pub fn into_iter(self) -> Self { - //~^ ERROR: method `into_iter` can be confused for the standard trait method `std::ite + //~^ should_implement_trait + unimplemented!() } pub fn mul(self, rhs: Self) -> Self { - //~^ ERROR: method `mul` can be confused for the standard trait method `std::ops::Mul: + //~^ should_implement_trait + unimplemented!() } pub fn neg(self) -> Self { - //~^ ERROR: method `neg` can be confused for the standard trait method `std::ops::Neg: + //~^ should_implement_trait + unimplemented!() } pub fn next(&mut self) -> Option { - //~^ ERROR: method `next` can be confused for the standard trait method `std::iter::It + //~^ should_implement_trait + unimplemented!() } pub fn not(self) -> Self { - //~^ ERROR: method `not` can be confused for the standard trait method `std::ops::Not: + //~^ should_implement_trait + unimplemented!() } pub fn rem(self, rhs: Self) -> Self { - //~^ ERROR: method `rem` can be confused for the standard trait method `std::ops::Rem: + //~^ should_implement_trait + unimplemented!() } pub fn shl(self, rhs: Self) -> Self { - //~^ ERROR: method `shl` can be confused for the standard trait method `std::ops::Shl: + //~^ should_implement_trait + unimplemented!() } pub fn shr(self, rhs: Self) -> Self { - //~^ ERROR: method `shr` can be confused for the standard trait method `std::ops::Shr: + //~^ should_implement_trait + unimplemented!() } pub fn sub(self, rhs: Self) -> Self { - //~^ ERROR: method `sub` can be confused for the standard trait method `std::ops::Sub: + //~^ should_implement_trait + unimplemented!() } // ********** diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr index b1e5bbbfa4c5f..85de74337020d 100644 --- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr +++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr @@ -3,6 +3,7 @@ error: method `eq` can be confused for the standard trait method `std::cmp::Part | LL | / pub fn eq(&self, other: &Self) -> bool { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -12,10 +13,11 @@ LL | | } = help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]` error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter` - --> tests/ui/should_impl_trait/method_list_2.rs:31:5 + --> tests/ui/should_impl_trait/method_list_2.rs:32:5 | LL | / pub fn from_iter(iter: T) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -23,10 +25,11 @@ LL | | } = help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str` - --> tests/ui/should_impl_trait/method_list_2.rs:36:5 + --> tests/ui/should_impl_trait/method_list_2.rs:38:5 | LL | / pub fn from_str(s: &str) -> Result { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -34,10 +37,11 @@ LL | | } = help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash` - --> tests/ui/should_impl_trait/method_list_2.rs:41:5 + --> tests/ui/should_impl_trait/method_list_2.rs:44:5 | LL | / pub fn hash(&self, state: &mut T) { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -45,10 +49,11 @@ LL | | } = help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name error: method `index` can be confused for the standard trait method `std::ops::Index::index` - --> tests/ui/should_impl_trait/method_list_2.rs:46:5 + --> tests/ui/should_impl_trait/method_list_2.rs:50:5 | LL | / pub fn index(&self, index: usize) -> &Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -56,10 +61,11 @@ LL | | } = help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut` - --> tests/ui/should_impl_trait/method_list_2.rs:51:5 + --> tests/ui/should_impl_trait/method_list_2.rs:56:5 | LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -67,10 +73,11 @@ LL | | } = help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter` - --> tests/ui/should_impl_trait/method_list_2.rs:56:5 + --> tests/ui/should_impl_trait/method_list_2.rs:62:5 | LL | / pub fn into_iter(self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -78,10 +85,11 @@ LL | | } = help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul` - --> tests/ui/should_impl_trait/method_list_2.rs:61:5 + --> tests/ui/should_impl_trait/method_list_2.rs:68:5 | LL | / pub fn mul(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -89,10 +97,11 @@ LL | | } = help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg` - --> tests/ui/should_impl_trait/method_list_2.rs:66:5 + --> tests/ui/should_impl_trait/method_list_2.rs:74:5 | LL | / pub fn neg(self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -100,10 +109,11 @@ LL | | } = help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name error: method `next` can be confused for the standard trait method `std::iter::Iterator::next` - --> tests/ui/should_impl_trait/method_list_2.rs:71:5 + --> tests/ui/should_impl_trait/method_list_2.rs:80:5 | LL | / pub fn next(&mut self) -> Option { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -111,10 +121,11 @@ LL | | } = help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name error: method `not` can be confused for the standard trait method `std::ops::Not::not` - --> tests/ui/should_impl_trait/method_list_2.rs:76:5 + --> tests/ui/should_impl_trait/method_list_2.rs:86:5 | LL | / pub fn not(self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -122,10 +133,11 @@ LL | | } = help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem` - --> tests/ui/should_impl_trait/method_list_2.rs:81:5 + --> tests/ui/should_impl_trait/method_list_2.rs:92:5 | LL | / pub fn rem(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -133,10 +145,11 @@ LL | | } = help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl` - --> tests/ui/should_impl_trait/method_list_2.rs:86:5 + --> tests/ui/should_impl_trait/method_list_2.rs:98:5 | LL | / pub fn shl(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -144,10 +157,11 @@ LL | | } = help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr` - --> tests/ui/should_impl_trait/method_list_2.rs:91:5 + --> tests/ui/should_impl_trait/method_list_2.rs:104:5 | LL | / pub fn shr(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ @@ -155,10 +169,11 @@ LL | | } = help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub` - --> tests/ui/should_impl_trait/method_list_2.rs:96:5 + --> tests/ui/should_impl_trait/method_list_2.rs:110:5 | LL | / pub fn sub(self, rhs: Self) -> Self { LL | | +LL | | LL | | unimplemented!() LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/should_panic_without_expect.rs b/src/tools/clippy/tests/ui/should_panic_without_expect.rs index b554fdaf22495..a209f794b105b 100644 --- a/src/tools/clippy/tests/ui/should_panic_without_expect.rs +++ b/src/tools/clippy/tests/ui/should_panic_without_expect.rs @@ -3,6 +3,7 @@ #[test] #[should_panic] +//~^ should_panic_without_expect fn no_message() {} #[test] diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs index 39d550398d705..4f65a06680d6c 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs @@ -58,8 +58,7 @@ fn should_trigger_lint_with_mutex_guard_in_match_scrutinee() { // is preserved until the end of the match, but there is no clear indication that this is the // case. match mutex.lock().unwrap().foo() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee true => { mutex.lock().unwrap().bar(); }, @@ -146,8 +145,7 @@ fn should_trigger_lint_with_wrapped_mutex() { // lifetime is not obvious. Additionally, it is not obvious from looking at the scrutinee that // the temporary contains such a type, making it potentially even more surprising. match s.lock_m().get_the_value() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee 1 => { println!("Got 1. Is it still 1?"); println!("{}", s.lock_m().get_the_value()); @@ -169,8 +167,7 @@ fn should_trigger_lint_with_double_wrapped_mutex() { // looking at the scrutinee that the temporary contains such a type, making it potentially even // more surprising. match s.lock_m_m().get_the_value() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee 1 => { println!("Got 1. Is it still 1?"); println!("{}", s.lock_m().get_the_value()); @@ -219,8 +216,7 @@ fn should_trigger_lint_for_vec() { // which have significant drops. The types with significant drops are also non-obvious when // reading the expression in the scrutinee. match counter.temp_increment().len() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee 2 => { let current_count = counter.i.load(Ordering::Relaxed); println!("Current count {}", current_count); @@ -244,8 +240,7 @@ fn should_trigger_lint_for_tuple_in_scrutinee() { { match (mutex1.lock().unwrap().s.len(), true) { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee (3, _) => { println!("started"); mutex1.lock().unwrap().s.len(); @@ -255,8 +250,7 @@ fn should_trigger_lint_for_tuple_in_scrutinee() { }; match (true, mutex1.lock().unwrap().s.len(), true) { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee (_, 3, _) => { println!("started"); mutex1.lock().unwrap().s.len(); @@ -267,10 +261,8 @@ fn should_trigger_lint_for_tuple_in_scrutinee() { let mutex2 = Mutex::new(StateWithField { s: "two".to_owned() }); match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until - //~| NOTE: this might lead to deadlocks or other unexpected behavior - //~| ERROR: temporary with significant `Drop` in `match` scrutinee will live until - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee + //~| significant_drop_in_scrutinee (3, _, 3) => { println!("started"); mutex1.lock().unwrap().s.len(); @@ -322,8 +314,7 @@ fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() { let mutex = Mutex::new(StateWithField { s: "state".to_owned() }); match mutex.lock().unwrap().s.len() > 1 { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee true => { mutex.lock().unwrap().s.len(); }, @@ -331,8 +322,7 @@ fn should_trigger_lint_for_accessing_field_in_mutex_in_one_side_of_binary_op() { }; match 1 < mutex.lock().unwrap().s.len() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee true => { mutex.lock().unwrap().s.len(); }, @@ -351,8 +341,8 @@ fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op( }); match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee + //~| significant_drop_in_scrutinee true => { println!( "{} < {}", @@ -364,8 +354,8 @@ fn should_trigger_lint_for_accessing_fields_in_mutex_in_both_sides_of_binary_op( }; match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee + //~| significant_drop_in_scrutinee true => { println!( "{} >= {}", @@ -401,8 +391,7 @@ fn should_trigger_lint_for_return_from_closure_in_scrutinee() { // Should trigger lint because the temporary with a significant drop is returned from the // closure but not used directly in any match arms, so it has a potentially surprising lifetime. match get_mutex_guard().s.len() > 1 { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee true => { mutex1.lock().unwrap().s.len(); }, @@ -420,8 +409,7 @@ fn should_trigger_lint_for_return_from_match_in_scrutinee() { // significant drop is but not used directly in any match arms, so it has a potentially // surprising lifetime. match match i { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee 100 => mutex1.lock().unwrap(), _ => mutex2.lock().unwrap(), } @@ -448,8 +436,7 @@ fn should_trigger_lint_for_return_from_if_in_scrutinee() { // with a significant drop is but not used directly in any match arms, so it has a potentially // surprising lifetime. match if i > 1 { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee mutex1.lock().unwrap() } else { mutex2.lock().unwrap() @@ -504,8 +491,7 @@ fn should_trigger_lint_for_boxed_mutex_guard() { // Should trigger lint because a temporary Box holding a type with a significant drop in a match // scrutinee may have a potentially surprising lifetime. match s.lock().deref().deref() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee 0 | 1 => println!("Value was less than 2"), _ => println!("Value is {}", s.lock().deref()), }; @@ -554,32 +540,28 @@ fn should_trigger_lint_in_assign_expr() { let mut i = 100; match mutex.lock().unwrap().i = i { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee _ => { println!("{}", mutex.lock().unwrap().i); }, }; match i = mutex.lock().unwrap().i { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee _ => { println!("{}", mutex.lock().unwrap().i); }, }; match mutex.lock().unwrap().i += 1 { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee _ => { println!("{}", mutex.lock().unwrap().i); }, }; match i += mutex.lock().unwrap().i { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee _ => { println!("{}", mutex.lock().unwrap().i); }, @@ -643,8 +625,7 @@ impl ResultReturner { fn should_trigger_lint_for_non_ref_move_and_clone_suggestion() { let rwlock = RwLock::::new(ResultReturner { s: "1".to_string() }); match rwlock.read().unwrap().to_number() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee Ok(n) => println!("Converted to number: {}", n), Err(e) => println!("Could not convert {} to number", e), }; @@ -671,8 +652,7 @@ fn should_trigger_lint_without_significant_drop_in_arm() { // is preserved until the end of the match, but there is no clear indication that this is the // case. match mutex.lock().unwrap().foo() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee true => do_bar(&mutex), false => {}, }; @@ -734,8 +714,7 @@ fn should_not_trigger_for_significant_drop_ref() { } match guard.take().len() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee 0 => println!("empty"), _ => println!("not empty"), }; @@ -760,8 +739,7 @@ fn should_trigger_lint_if_and_only_if_lifetime_is_irrelevant() { // Should trigger lint even if `copy_old_lifetime()` has a lifetime, as the lifetime of // `&vec` is unrelated to the temporary with significant drop (i.e., the `MutexGuard`). for val in mutex.lock().unwrap().copy_old_lifetime() { - //~^ ERROR: temporary with significant `Drop` in `for` loop condition will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee println!("{}", val); } @@ -800,8 +778,7 @@ fn should_not_trigger_lint_with_explicit_drop() { // Should trigger lint if there is no explicit drop. for val in [mutex.lock().unwrap()[0], 2] { - //~^ ERROR: temporary with significant `Drop` in `for` loop condition will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee println!("{:?}", val); } } @@ -810,8 +787,7 @@ fn should_trigger_lint_in_if_let() { let mutex = Mutex::new(vec![1]); if let Some(val) = mutex.lock().unwrap().first().copied() { - //~^ ERROR: temporary with significant `Drop` in `if let` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee println!("{}", val); } @@ -826,8 +802,7 @@ fn should_trigger_lint_in_while_let() { let mutex = Mutex::new(vec![1]); while let Some(val) = mutex.lock().unwrap().pop() { - //~^ ERROR: temporary with significant `Drop` in `while let` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee println!("{}", val); } } @@ -838,6 +813,7 @@ async fn foo_async(mutex: &Mutex) -> Option> { async fn should_trigger_lint_for_async(mutex: Mutex) -> i32 { match *foo_async(&mutex).await.unwrap() { + //~^ significant_drop_in_scrutinee n if n < 10 => n, _ => 10, } @@ -857,8 +833,7 @@ fn should_trigger_lint_in_match_expr() { // is preserved until the end of the match, but there is no clear indication that this is the // case. let _ = match mutex.lock().unwrap().foo() { - //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the - //~| NOTE: this might lead to deadlocks or other unexpected behavior + //~^ significant_drop_in_scrutinee true => 0, false => 1, }; diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr index f99d862aa6b25..b32b249fd4296 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr @@ -20,7 +20,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:148:11 + --> tests/ui/significant_drop_in_scrutinee.rs:147:11 | LL | match s.lock_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +42,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:171:11 + --> tests/ui/significant_drop_in_scrutinee.rs:169:11 | LL | match s.lock_m_m().get_the_value() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -64,7 +64,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:221:11 + --> tests/ui/significant_drop_in_scrutinee.rs:218:11 | LL | match counter.temp_increment().len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -80,7 +80,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:246:16 + --> tests/ui/significant_drop_in_scrutinee.rs:242:16 | LL | match (mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL ~ match (value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:257:22 + --> tests/ui/significant_drop_in_scrutinee.rs:252:22 | LL | match (true, mutex1.lock().unwrap().s.len(), true) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,7 +118,7 @@ LL ~ match (true, value, true) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:269:16 + --> tests/ui/significant_drop_in_scrutinee.rs:263:16 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,7 +139,7 @@ LL ~ match (value, true, mutex2.lock().unwrap().s.len()) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:269:54 + --> tests/ui/significant_drop_in_scrutinee.rs:263:54 | LL | match (mutex1.lock().unwrap().s.len(), true, mutex2.lock().unwrap().s.len()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL ~ match (mutex1.lock().unwrap().s.len(), true, value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:324:11 + --> tests/ui/significant_drop_in_scrutinee.rs:316:11 | LL | match mutex.lock().unwrap().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +179,7 @@ LL ~ match value > 1 { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:333:15 + --> tests/ui/significant_drop_in_scrutinee.rs:324:15 | LL | match 1 < mutex.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -198,7 +198,7 @@ LL ~ match 1 < value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:353:11 + --> tests/ui/significant_drop_in_scrutinee.rs:343:11 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +219,7 @@ LL ~ match value < mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:353:44 + --> tests/ui/significant_drop_in_scrutinee.rs:343:44 | LL | match mutex1.lock().unwrap().s.len() < mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -240,7 +240,7 @@ LL ~ match mutex1.lock().unwrap().s.len() < value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:366:11 + --> tests/ui/significant_drop_in_scrutinee.rs:356:11 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -261,7 +261,7 @@ LL ~ match value >= mutex2.lock().unwrap().s.len() { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:366:45 + --> tests/ui/significant_drop_in_scrutinee.rs:356:45 | LL | match mutex1.lock().unwrap().s.len() >= mutex2.lock().unwrap().s.len() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -282,7 +282,7 @@ LL ~ match mutex1.lock().unwrap().s.len() >= value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:403:11 + --> tests/ui/significant_drop_in_scrutinee.rs:393:11 | LL | match get_mutex_guard().s.len() > 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -301,14 +301,14 @@ LL ~ match value > 1 { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:422:11 + --> tests/ui/significant_drop_in_scrutinee.rs:411:11 | LL | match match i { | ___________^ LL | | -LL | | LL | | 100 => mutex1.lock().unwrap(), -... | +LL | | _ => mutex2.lock().unwrap(), +LL | | } LL | | .s LL | | .len() | |__________^ @@ -324,7 +324,6 @@ help: try moving the temporary above the match | LL ~ let value = match i { LL + -LL + LL + 100 => mutex1.lock().unwrap(), LL + _ => mutex2.lock().unwrap(), LL + } @@ -334,13 +333,13 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:450:11 + --> tests/ui/significant_drop_in_scrutinee.rs:438:11 | LL | match if i > 1 { | ___________^ LL | | -LL | | LL | | mutex1.lock().unwrap() +LL | | } else { ... | LL | | .s LL | | .len() @@ -357,7 +356,6 @@ help: try moving the temporary above the match | LL ~ let value = if i > 1 { LL + -LL + LL + mutex1.lock().unwrap() LL + } else { LL + mutex2.lock().unwrap() @@ -368,7 +366,7 @@ LL ~ match value | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:506:11 + --> tests/ui/significant_drop_in_scrutinee.rs:493:11 | LL | match s.lock().deref().deref() { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -386,7 +384,7 @@ LL ~ match (&value) { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:556:11 + --> tests/ui/significant_drop_in_scrutinee.rs:542:11 | LL | match mutex.lock().unwrap().i = i { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -405,7 +403,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:564:15 + --> tests/ui/significant_drop_in_scrutinee.rs:549:15 | LL | match i = mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -424,7 +422,7 @@ LL ~ match i = value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:572:11 + --> tests/ui/significant_drop_in_scrutinee.rs:556:11 | LL | match mutex.lock().unwrap().i += 1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +441,7 @@ LL ~ match () { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:580:16 + --> tests/ui/significant_drop_in_scrutinee.rs:563:16 | LL | match i += mutex.lock().unwrap().i { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -462,7 +460,7 @@ LL ~ match i += value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:645:11 + --> tests/ui/significant_drop_in_scrutinee.rs:627:11 | LL | match rwlock.read().unwrap().to_number() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -478,7 +476,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:673:11 + --> tests/ui/significant_drop_in_scrutinee.rs:654:11 | LL | match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -494,7 +492,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:736:11 + --> tests/ui/significant_drop_in_scrutinee.rs:716:11 | LL | match guard.take().len() { | ^^^^^^^^^^^^^^^^^^ @@ -510,7 +508,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> tests/ui/significant_drop_in_scrutinee.rs:762:16 + --> tests/ui/significant_drop_in_scrutinee.rs:741:16 | LL | for val in mutex.lock().unwrap().copy_old_lifetime() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -526,7 +524,7 @@ LL ~ for val in value { | error: temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression - --> tests/ui/significant_drop_in_scrutinee.rs:802:17 + --> tests/ui/significant_drop_in_scrutinee.rs:780:17 | LL | for val in [mutex.lock().unwrap()[0], 2] { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -542,7 +540,7 @@ LL ~ for val in [value, 2] { | error: temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression - --> tests/ui/significant_drop_in_scrutinee.rs:812:24 + --> tests/ui/significant_drop_in_scrutinee.rs:789:24 | LL | if let Some(val) = mutex.lock().unwrap().first().copied() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -558,7 +556,7 @@ LL ~ if let Some(val) = value { | error: temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression - --> tests/ui/significant_drop_in_scrutinee.rs:828:27 + --> tests/ui/significant_drop_in_scrutinee.rs:804:27 | LL | while let Some(val) = mutex.lock().unwrap().pop() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -569,7 +567,7 @@ LL | } = note: this might lead to deadlocks or other unexpected behavior error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:840:11 + --> tests/ui/significant_drop_in_scrutinee.rs:815:11 | LL | match *foo_async(&mutex).await.unwrap() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -585,7 +583,7 @@ LL ~ match value { | error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression - --> tests/ui/significant_drop_in_scrutinee.rs:859:19 + --> tests/ui/significant_drop_in_scrutinee.rs:835:19 | LL | let _ = match mutex.lock().unwrap().foo() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed index ed05f6e0c8d35..3d416056226cb 100644 --- a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed +++ b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed @@ -8,6 +8,7 @@ pub fn complex_return_triggers_the_lint() -> i32 { } let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); + //~^ significant_drop_tightening let _ = *lock; let _ = *lock; drop(lock); @@ -103,6 +104,7 @@ pub fn unnecessary_contention_with_multiple_owned_results() { { let mutex = Mutex::new(1i32); let lock = mutex.lock().unwrap(); + //~^ significant_drop_tightening let rslt0 = lock.abs(); let rslt1 = lock.is_positive(); drop(lock); @@ -126,6 +128,7 @@ pub fn unnecessary_contention_with_single_owned_results() { let mutex = Mutex::new(1i32); let rslt0 = mutex.lock().unwrap().abs(); + //~^ significant_drop_tightening do_heavy_computation_that_takes_time(rslt0); } @@ -133,6 +136,7 @@ pub fn unnecessary_contention_with_single_owned_results() { let mutex = Mutex::new(vec![1i32]); mutex.lock().unwrap().clear(); + //~^ significant_drop_tightening do_heavy_computation_that_takes_time(()); } diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.rs b/src/tools/clippy/tests/ui/significant_drop_tightening.rs index e5f17278f0f6a..d9c4ad5435933 100644 --- a/src/tools/clippy/tests/ui/significant_drop_tightening.rs +++ b/src/tools/clippy/tests/ui/significant_drop_tightening.rs @@ -8,6 +8,7 @@ pub fn complex_return_triggers_the_lint() -> i32 { } let mutex = Mutex::new(1); let lock = mutex.lock().unwrap(); + //~^ significant_drop_tightening let _ = *lock; let _ = *lock; foo() @@ -102,6 +103,7 @@ pub fn unnecessary_contention_with_multiple_owned_results() { { let mutex = Mutex::new(1i32); let lock = mutex.lock().unwrap(); + //~^ significant_drop_tightening let rslt0 = lock.abs(); let rslt1 = lock.is_positive(); do_heavy_computation_that_takes_time((rslt0, rslt1)); @@ -123,12 +125,14 @@ pub fn unnecessary_contention_with_single_owned_results() { { let mutex = Mutex::new(1i32); let lock = mutex.lock().unwrap(); + //~^ significant_drop_tightening let rslt0 = lock.abs(); do_heavy_computation_that_takes_time(rslt0); } { let mutex = Mutex::new(vec![1i32]); let mut lock = mutex.lock().unwrap(); + //~^ significant_drop_tightening lock.clear(); do_heavy_computation_that_takes_time(()); } diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr index aef774a3d3600..25cd9da73a100 100644 --- a/src/tools/clippy/tests/ui/significant_drop_tightening.stderr +++ b/src/tools/clippy/tests/ui/significant_drop_tightening.stderr @@ -23,14 +23,13 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:104:13 + --> tests/ui/significant_drop_tightening.rs:105:13 | LL | / { LL | | let mutex = Mutex::new(1i32); LL | | let lock = mutex.lock().unwrap(); | | ^^^^ -LL | | let rslt0 = lock.abs(); -LL | | let rslt1 = lock.is_positive(); +... | LL | | do_heavy_computation_that_takes_time((rslt0, rslt1)); LL | | } | |_____- temporary `lock` is currently being dropped at the end of its contained scope @@ -43,13 +42,13 @@ LL + drop(lock); | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:125:13 + --> tests/ui/significant_drop_tightening.rs:127:13 | LL | / { LL | | let mutex = Mutex::new(1i32); LL | | let lock = mutex.lock().unwrap(); | | ^^^^ -LL | | let rslt0 = lock.abs(); +... | LL | | do_heavy_computation_that_takes_time(rslt0); LL | | } | |_____- temporary `lock` is currently being dropped at the end of its contained scope @@ -59,17 +58,18 @@ help: merge the temporary construction with its single usage | LL ~ LL + let rslt0 = mutex.lock().unwrap().abs(); +LL | LL ~ | error: temporary with significant `Drop` can be early dropped - --> tests/ui/significant_drop_tightening.rs:131:17 + --> tests/ui/significant_drop_tightening.rs:134:17 | LL | / { LL | | let mutex = Mutex::new(vec![1i32]); LL | | let mut lock = mutex.lock().unwrap(); | | ^^^^ -LL | | lock.clear(); +... | LL | | do_heavy_computation_that_takes_time(()); LL | | } | |_____- temporary `lock` is currently being dropped at the end of its contained scope @@ -79,6 +79,7 @@ help: merge the temporary construction with its single usage | LL ~ LL + mutex.lock().unwrap().clear(); +LL | LL ~ | diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs index f09693344915b..69b6ab6220bf2 100644 --- a/src/tools/clippy/tests/ui/similar_names.rs +++ b/src/tools/clippy/tests/ui/similar_names.rs @@ -45,12 +45,12 @@ fn main() { let blubx: i32; let bluby: i32; - //~^ ERROR: binding's name is too similar to existing binding + //~^ similar_names let cake: i32; let cakes: i32; let coke: i32; - //~^ ERROR: binding's name is too similar to existing binding + //~^ similar_names match 5 { cheese @ 1 => {}, @@ -69,12 +69,12 @@ fn main() { let xyz1abc: i32; let xyz2abc: i32; let xyzeabc: i32; - //~^ ERROR: binding's name is too similar to existing binding + //~^ similar_names let parser: i32; let parsed: i32; let parsee: i32; - //~^ ERROR: binding's name is too similar to existing binding + //~^ similar_names let setter: i32; let getter: i32; @@ -96,7 +96,7 @@ fn foo() { let Foo { apple: spring, bpple: sprang, - //~^ ERROR: binding's name is too similar to existing binding + //~^ similar_names } = unimplemented!(); } diff --git a/src/tools/clippy/tests/ui/single_call_fn.rs b/src/tools/clippy/tests/ui/single_call_fn.rs index a0597664da55c..c1cc4032bec99 100644 --- a/src/tools/clippy/tests/ui/single_call_fn.rs +++ b/src/tools/clippy/tests/ui/single_call_fn.rs @@ -11,7 +11,9 @@ extern crate proc_macros; pub fn f() {} fn i() {} +//~^ single_call_fn fn j() {} +//~^ single_call_fn fn h() { // Linted @@ -32,6 +34,7 @@ fn g() { } fn c() { + //~^ single_call_fn println!("really"); println!("long"); println!("function..."); @@ -42,6 +45,7 @@ fn d() { } fn a() {} +//~^ single_call_fn fn b() { a(); @@ -87,6 +91,7 @@ fn l() { trait Trait { fn default() {} + //~^ single_call_fn fn foo(&self); } extern "C" { @@ -100,6 +105,7 @@ fn m(v: T) { struct S; impl S { fn foo() {} + //~^ single_call_fn } T::default(); S::foo(); diff --git a/src/tools/clippy/tests/ui/single_call_fn.stderr b/src/tools/clippy/tests/ui/single_call_fn.stderr index 14529beac616a..8dd90a1238522 100644 --- a/src/tools/clippy/tests/ui/single_call_fn.stderr +++ b/src/tools/clippy/tests/ui/single_call_fn.stderr @@ -5,7 +5,7 @@ LL | fn i() {} | ^^^^^^^^^ | note: used here - --> tests/ui/single_call_fn.rs:18:13 + --> tests/ui/single_call_fn.rs:20:13 | LL | let a = i; | ^ @@ -13,21 +13,22 @@ LL | let a = i; = help: to override `-D warnings` add `#[allow(clippy::single_call_fn)]` error: this function is only used once - --> tests/ui/single_call_fn.rs:14:1 + --> tests/ui/single_call_fn.rs:15:1 | LL | fn j() {} | ^^^^^^^^^ | note: used here - --> tests/ui/single_call_fn.rs:25:9 + --> tests/ui/single_call_fn.rs:27:9 | LL | j(); | ^ error: this function is only used once - --> tests/ui/single_call_fn.rs:34:1 + --> tests/ui/single_call_fn.rs:36:1 | LL | / fn c() { +LL | | LL | | println!("really"); LL | | println!("long"); LL | | println!("function..."); @@ -35,43 +36,43 @@ LL | | } | |_^ | note: used here - --> tests/ui/single_call_fn.rs:41:5 + --> tests/ui/single_call_fn.rs:44:5 | LL | c(); | ^ error: this function is only used once - --> tests/ui/single_call_fn.rs:44:1 + --> tests/ui/single_call_fn.rs:47:1 | LL | fn a() {} | ^^^^^^^^^ | note: used here - --> tests/ui/single_call_fn.rs:47:5 + --> tests/ui/single_call_fn.rs:51:5 | LL | a(); | ^ error: this function is only used once - --> tests/ui/single_call_fn.rs:89:5 + --> tests/ui/single_call_fn.rs:93:5 | LL | fn default() {} | ^^^^^^^^^^^^^^^ | note: used here - --> tests/ui/single_call_fn.rs:104:5 + --> tests/ui/single_call_fn.rs:110:5 | LL | T::default(); | ^^^^^^^^^^ error: this function is only used once - --> tests/ui/single_call_fn.rs:102:9 + --> tests/ui/single_call_fn.rs:107:9 | LL | fn foo() {} | ^^^^^^^^^^^ | note: used here - --> tests/ui/single_call_fn.rs:105:5 + --> tests/ui/single_call_fn.rs:111:5 | LL | S::foo(); | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/single_char_add_str.fixed b/src/tools/clippy/tests/ui/single_char_add_str.fixed index aef15252b1bce..b729cf8b2ca13 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.fixed +++ b/src/tools/clippy/tests/ui/single_char_add_str.fixed @@ -12,44 +12,65 @@ fn main() { let mut string = String::new(); string.push('R'); + //~^ single_char_add_str string.push('\''); + //~^ single_char_add_str string.push('u'); string.push_str("st"); string.push_str(""); string.push('\x52'); + //~^ single_char_add_str string.push('\u{0052}'); + //~^ single_char_add_str string.push('a'); + //~^ single_char_add_str let c_ref = &'a'; string.push(*c_ref); + //~^ single_char_add_str let c = 'a'; string.push(c); + //~^ single_char_add_str string.push('a'); + //~^ single_char_add_str get_string!().push('ö'); + //~^ single_char_add_str // `insert_str` tests let mut string = String::new(); string.insert(0, 'R'); + //~^ single_char_add_str string.insert(1, '\''); + //~^ single_char_add_str string.insert(0, 'u'); string.insert_str(2, "st"); string.insert_str(0, ""); string.insert(0, '\x52'); + //~^ single_char_add_str string.insert(0, '\u{0052}'); + //~^ single_char_add_str let x: usize = 2; string.insert(x, 'a'); + //~^ single_char_add_str const Y: usize = 1; string.insert(Y, 'a'); + //~^ single_char_add_str string.insert(Y, '"'); + //~^ single_char_add_str string.insert(Y, '\''); + //~^ single_char_add_str string.insert(0, *c_ref); + //~^ single_char_add_str string.insert(0, c); + //~^ single_char_add_str string.insert(0, 'a'); + //~^ single_char_add_str get_string!().insert(1, '?'); + //~^ single_char_add_str } diff --git a/src/tools/clippy/tests/ui/single_char_add_str.rs b/src/tools/clippy/tests/ui/single_char_add_str.rs index 7f97250dacd48..a768c47db391e 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.rs +++ b/src/tools/clippy/tests/ui/single_char_add_str.rs @@ -12,44 +12,65 @@ fn main() { let mut string = String::new(); string.push_str("R"); + //~^ single_char_add_str string.push_str("'"); + //~^ single_char_add_str string.push('u'); string.push_str("st"); string.push_str(""); string.push_str("\x52"); + //~^ single_char_add_str string.push_str("\u{0052}"); + //~^ single_char_add_str string.push_str(r##"a"##); + //~^ single_char_add_str let c_ref = &'a'; string.push_str(&c_ref.to_string()); + //~^ single_char_add_str let c = 'a'; string.push_str(&c.to_string()); + //~^ single_char_add_str string.push_str(&'a'.to_string()); + //~^ single_char_add_str get_string!().push_str("ö"); + //~^ single_char_add_str // `insert_str` tests let mut string = String::new(); string.insert_str(0, "R"); + //~^ single_char_add_str string.insert_str(1, "'"); + //~^ single_char_add_str string.insert(0, 'u'); string.insert_str(2, "st"); string.insert_str(0, ""); string.insert_str(0, "\x52"); + //~^ single_char_add_str string.insert_str(0, "\u{0052}"); + //~^ single_char_add_str let x: usize = 2; string.insert_str(x, r##"a"##); + //~^ single_char_add_str const Y: usize = 1; string.insert_str(Y, r##"a"##); + //~^ single_char_add_str string.insert_str(Y, r##"""##); + //~^ single_char_add_str string.insert_str(Y, r##"'"##); + //~^ single_char_add_str string.insert_str(0, &c_ref.to_string()); + //~^ single_char_add_str string.insert_str(0, &c.to_string()); + //~^ single_char_add_str string.insert_str(0, &'a'.to_string()); + //~^ single_char_add_str get_string!().insert_str(1, "?"); + //~^ single_char_add_str } diff --git a/src/tools/clippy/tests/ui/single_char_add_str.stderr b/src/tools/clippy/tests/ui/single_char_add_str.stderr index 7791c67578aa2..a1fae93462c90 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.stderr +++ b/src/tools/clippy/tests/ui/single_char_add_str.stderr @@ -8,121 +8,121 @@ LL | string.push_str("R"); = help: to override `-D warnings` add `#[allow(clippy::single_char_add_str)]` error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:15:5 + --> tests/ui/single_char_add_str.rs:16:5 | LL | string.push_str("'"); | ^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('\'')` error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:20:5 + --> tests/ui/single_char_add_str.rs:22:5 | LL | string.push_str("\x52"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('\x52')` error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:21:5 + --> tests/ui/single_char_add_str.rs:24:5 | LL | string.push_str("\u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('\u{0052}')` error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:22:5 + --> tests/ui/single_char_add_str.rs:26:5 | LL | string.push_str(r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `string.push('a')` error: calling `push_str()` using a single-character converted to string - --> tests/ui/single_char_add_str.rs:25:5 + --> tests/ui/single_char_add_str.rs:30:5 | LL | string.push_str(&c_ref.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(*c_ref)` error: calling `push_str()` using a single-character converted to string - --> tests/ui/single_char_add_str.rs:27:5 + --> tests/ui/single_char_add_str.rs:33:5 | LL | string.push_str(&c.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push(c)` error: calling `push_str()` using a single-character converted to string - --> tests/ui/single_char_add_str.rs:28:5 + --> tests/ui/single_char_add_str.rs:35:5 | LL | string.push_str(&'a'.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` without `to_string()`: `string.push('a')` error: calling `push_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:30:5 + --> tests/ui/single_char_add_str.rs:38:5 | LL | get_string!().push_str("ö"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `get_string!().push('ö')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:35:5 + --> tests/ui/single_char_add_str.rs:44:5 | LL | string.insert_str(0, "R"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, 'R')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:36:5 + --> tests/ui/single_char_add_str.rs:46:5 | LL | string.insert_str(1, "'"); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(1, '\'')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:41:5 + --> tests/ui/single_char_add_str.rs:52:5 | LL | string.insert_str(0, "\x52"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\x52')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:42:5 + --> tests/ui/single_char_add_str.rs:54:5 | LL | string.insert_str(0, "\u{0052}"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(0, '\u{0052}')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:44:5 + --> tests/ui/single_char_add_str.rs:57:5 | LL | string.insert_str(x, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(x, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:46:5 + --> tests/ui/single_char_add_str.rs:60:5 | LL | string.insert_str(Y, r##"a"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:47:5 + --> tests/ui/single_char_add_str.rs:62:5 | LL | string.insert_str(Y, r##"""##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '"')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:48:5 + --> tests/ui/single_char_add_str.rs:64:5 | LL | string.insert_str(Y, r##"'"##); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `string.insert(Y, '\'')` error: calling `insert_str()` using a single-character converted to string - --> tests/ui/single_char_add_str.rs:50:5 + --> tests/ui/single_char_add_str.rs:67:5 | LL | string.insert_str(0, &c_ref.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, *c_ref)` error: calling `insert_str()` using a single-character converted to string - --> tests/ui/single_char_add_str.rs:51:5 + --> tests/ui/single_char_add_str.rs:69:5 | LL | string.insert_str(0, &c.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, c)` error: calling `insert_str()` using a single-character converted to string - --> tests/ui/single_char_add_str.rs:52:5 + --> tests/ui/single_char_add_str.rs:71:5 | LL | string.insert_str(0, &'a'.to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` without `to_string()`: `string.insert(0, 'a')` error: calling `insert_str()` using a single-character string literal - --> tests/ui/single_char_add_str.rs:54:5 + --> tests/ui/single_char_add_str.rs:74:5 | LL | get_string!().insert_str(1, "?"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `insert` with a character literal: `get_string!().insert(1, '?')` diff --git a/src/tools/clippy/tests/ui/single_char_lifetime_names.rs b/src/tools/clippy/tests/ui/single_char_lifetime_names.rs index 6731b5b13564d..f4dcf46b0e2d3 100644 --- a/src/tools/clippy/tests/ui/single_char_lifetime_names.rs +++ b/src/tools/clippy/tests/ui/single_char_lifetime_names.rs @@ -3,8 +3,8 @@ // Lifetimes should only be linted when they're introduced struct DiagnosticCtx<'a, 'b> -//~^ ERROR: single-character lifetime names are likely uninformative -//~| ERROR: single-character lifetime names are likely uninformative +//~^ single_char_lifetime_names +//~| single_char_lifetime_names where 'a: 'b, { @@ -14,8 +14,9 @@ where // Only the lifetimes on the `impl`'s generics should be linted impl<'a, 'b> DiagnosticCtx<'a, 'b> { - //~^ ERROR: single-character lifetime names are likely uninformative - //~| ERROR: single-character lifetime names are likely uninformative + //~^ single_char_lifetime_names + //~| single_char_lifetime_names + fn new(source: &'a str, unit: &'b ()) -> DiagnosticCtx<'a, 'b> { Self { _source: source, @@ -36,7 +37,8 @@ impl<'src, 'unit> DiagnosticCtx<'src, 'unit> { // Only 'a should be linted here fn split_once<'a>(base: &'a str, other: &'_ str) -> (&'a str, Option<&'a str>) { - //~^ ERROR: single-character lifetime names are likely uninformative + //~^ single_char_lifetime_names + base.split_once(other) .map(|(left, right)| (left, Some(right))) .unwrap_or((base, None)) diff --git a/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr b/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr index 005c897b19bac..834b654baa572 100644 --- a/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr +++ b/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr @@ -33,7 +33,7 @@ LL | impl<'a, 'b> DiagnosticCtx<'a, 'b> { = help: use a more informative name error: single-character lifetime names are likely uninformative - --> tests/ui/single_char_lifetime_names.rs:38:15 + --> tests/ui/single_char_lifetime_names.rs:39:15 | LL | fn split_once<'a>(base: &'a str, other: &'_ str) -> (&'a str, Option<&'a str>) { | ^^ diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed index a18d6319f89db..9bf9d66304411 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.fixed +++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed @@ -5,6 +5,7 @@ use std::collections::HashSet; fn main() { let x = "foo"; x.split('x'); + //~^ single_char_pattern x.split("xx"); x.split('x'); @@ -16,38 +17,67 @@ fn main() { // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); x.split_inclusive('x'); + //~^ single_char_pattern x.contains('x'); + //~^ single_char_pattern x.starts_with('x'); + //~^ single_char_pattern x.ends_with('x'); + //~^ single_char_pattern x.find('x'); + //~^ single_char_pattern x.rfind('x'); + //~^ single_char_pattern x.rsplit('x'); + //~^ single_char_pattern x.split_terminator('x'); + //~^ single_char_pattern x.rsplit_terminator('x'); + //~^ single_char_pattern x.splitn(2, 'x'); + //~^ single_char_pattern x.rsplitn(2, 'x'); + //~^ single_char_pattern x.split_once('x'); + //~^ single_char_pattern x.rsplit_once('x'); + //~^ single_char_pattern x.matches('x'); + //~^ single_char_pattern x.rmatches('x'); + //~^ single_char_pattern x.match_indices('x'); + //~^ single_char_pattern x.rmatch_indices('x'); + //~^ single_char_pattern x.trim_start_matches('x'); + //~^ single_char_pattern x.trim_end_matches('x'); + //~^ single_char_pattern x.replace('x', "y"); + //~^ single_char_pattern x.replacen('x', "y", 3); + //~^ single_char_pattern // Make sure we escape characters correctly. x.split('\n'); + //~^ single_char_pattern x.split('\''); + //~^ single_char_pattern x.split('\''); + //~^ single_char_pattern // Issue #11973: Don't escape `"` in `'"'` x.split('"'); + //~^ single_char_pattern let h = HashSet::::new(); h.contains("X"); // should not warn x.replace(';', ",").split(','); // issue #2978 + // + //~^^ single_char_pattern x.starts_with('\x03'); // issue #2996 + // + //~^^ single_char_pattern // Issue #3204 const S: &str = "#"; @@ -55,13 +85,20 @@ fn main() { // Raw string x.split('a'); + //~^ single_char_pattern x.split('a'); + //~^ single_char_pattern x.split('a'); + //~^ single_char_pattern x.split('\''); + //~^ single_char_pattern x.split('#'); + //~^ single_char_pattern // Must escape backslash in raw strings when converting to char #8060 x.split('\\'); + //~^ single_char_pattern x.split('\\'); + //~^ single_char_pattern // should not warn, the char versions are actually slower in some cases x.strip_prefix("x"); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs index b52e6fb2fdfba..0560a848fe9de 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.rs +++ b/src/tools/clippy/tests/ui/single_char_pattern.rs @@ -5,6 +5,7 @@ use std::collections::HashSet; fn main() { let x = "foo"; x.split("x"); + //~^ single_char_pattern x.split("xx"); x.split('x'); @@ -16,38 +17,67 @@ fn main() { // Can't use this lint for unicode code points which don't fit in a char x.split("❤️"); x.split_inclusive("x"); + //~^ single_char_pattern x.contains("x"); + //~^ single_char_pattern x.starts_with("x"); + //~^ single_char_pattern x.ends_with("x"); + //~^ single_char_pattern x.find("x"); + //~^ single_char_pattern x.rfind("x"); + //~^ single_char_pattern x.rsplit("x"); + //~^ single_char_pattern x.split_terminator("x"); + //~^ single_char_pattern x.rsplit_terminator("x"); + //~^ single_char_pattern x.splitn(2, "x"); + //~^ single_char_pattern x.rsplitn(2, "x"); + //~^ single_char_pattern x.split_once("x"); + //~^ single_char_pattern x.rsplit_once("x"); + //~^ single_char_pattern x.matches("x"); + //~^ single_char_pattern x.rmatches("x"); + //~^ single_char_pattern x.match_indices("x"); + //~^ single_char_pattern x.rmatch_indices("x"); + //~^ single_char_pattern x.trim_start_matches("x"); + //~^ single_char_pattern x.trim_end_matches("x"); + //~^ single_char_pattern x.replace("x", "y"); + //~^ single_char_pattern x.replacen("x", "y", 3); + //~^ single_char_pattern // Make sure we escape characters correctly. x.split("\n"); + //~^ single_char_pattern x.split("'"); + //~^ single_char_pattern x.split("\'"); + //~^ single_char_pattern // Issue #11973: Don't escape `"` in `'"'` x.split("\""); + //~^ single_char_pattern let h = HashSet::::new(); h.contains("X"); // should not warn x.replace(';', ",").split(","); // issue #2978 + // + //~^^ single_char_pattern x.starts_with("\x03"); // issue #2996 + // + //~^^ single_char_pattern // Issue #3204 const S: &str = "#"; @@ -55,13 +85,20 @@ fn main() { // Raw string x.split(r"a"); + //~^ single_char_pattern x.split(r#"a"#); + //~^ single_char_pattern x.split(r###"a"###); + //~^ single_char_pattern x.split(r###"'"###); + //~^ single_char_pattern x.split(r###"#"###); + //~^ single_char_pattern // Must escape backslash in raw strings when converting to char #8060 x.split(r#"\"#); + //~^ single_char_pattern x.split(r"\"); + //~^ single_char_pattern // should not warn, the char versions are actually slower in some cases x.strip_prefix("x"); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr index b2deed23cbd53..aa4ba28884a8c 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.stderr +++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr @@ -8,205 +8,205 @@ LL | x.split("x"); = help: to override `-D warnings` add `#[allow(clippy::single_char_pattern)]` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:18:23 + --> tests/ui/single_char_pattern.rs:19:23 | LL | x.split_inclusive("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:19:16 + --> tests/ui/single_char_pattern.rs:21:16 | LL | x.contains("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:20:19 + --> tests/ui/single_char_pattern.rs:23:19 | LL | x.starts_with("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:21:17 + --> tests/ui/single_char_pattern.rs:25:17 | LL | x.ends_with("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:22:12 + --> tests/ui/single_char_pattern.rs:27:12 | LL | x.find("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:23:13 + --> tests/ui/single_char_pattern.rs:29:13 | LL | x.rfind("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:24:14 + --> tests/ui/single_char_pattern.rs:31:14 | LL | x.rsplit("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:25:24 + --> tests/ui/single_char_pattern.rs:33:24 | LL | x.split_terminator("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:26:25 + --> tests/ui/single_char_pattern.rs:35:25 | LL | x.rsplit_terminator("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:27:17 + --> tests/ui/single_char_pattern.rs:37:17 | LL | x.splitn(2, "x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:28:18 + --> tests/ui/single_char_pattern.rs:39:18 | LL | x.rsplitn(2, "x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:29:18 + --> tests/ui/single_char_pattern.rs:41:18 | LL | x.split_once("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:30:19 + --> tests/ui/single_char_pattern.rs:43:19 | LL | x.rsplit_once("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:31:15 + --> tests/ui/single_char_pattern.rs:45:15 | LL | x.matches("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:32:16 + --> tests/ui/single_char_pattern.rs:47:16 | LL | x.rmatches("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:33:21 + --> tests/ui/single_char_pattern.rs:49:21 | LL | x.match_indices("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:34:22 + --> tests/ui/single_char_pattern.rs:51:22 | LL | x.rmatch_indices("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:35:26 + --> tests/ui/single_char_pattern.rs:53:26 | LL | x.trim_start_matches("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:36:24 + --> tests/ui/single_char_pattern.rs:55:24 | LL | x.trim_end_matches("x"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:37:15 + --> tests/ui/single_char_pattern.rs:57:15 | LL | x.replace("x", "y"); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:38:16 + --> tests/ui/single_char_pattern.rs:59:16 | LL | x.replacen("x", "y", 3); | ^^^ help: consider using a `char`: `'x'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:40:13 + --> tests/ui/single_char_pattern.rs:62:13 | LL | x.split("\n"); | ^^^^ help: consider using a `char`: `'\n'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:41:13 + --> tests/ui/single_char_pattern.rs:64:13 | LL | x.split("'"); | ^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:42:13 + --> tests/ui/single_char_pattern.rs:66:13 | LL | x.split("\'"); | ^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:44:13 + --> tests/ui/single_char_pattern.rs:69:13 | LL | x.split("\""); | ^^^^ help: consider using a `char`: `'"'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:49:31 + --> tests/ui/single_char_pattern.rs:75:31 | LL | x.replace(';', ",").split(","); // issue #2978 | ^^^ help: consider using a `char`: `','` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:50:19 + --> tests/ui/single_char_pattern.rs:78:19 | LL | x.starts_with("\x03"); // issue #2996 | ^^^^^^ help: consider using a `char`: `'\x03'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:57:13 + --> tests/ui/single_char_pattern.rs:87:13 | LL | x.split(r"a"); | ^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:58:13 + --> tests/ui/single_char_pattern.rs:89:13 | LL | x.split(r#"a"#); | ^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:59:13 + --> tests/ui/single_char_pattern.rs:91:13 | LL | x.split(r###"a"###); | ^^^^^^^^^^ help: consider using a `char`: `'a'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:60:13 + --> tests/ui/single_char_pattern.rs:93:13 | LL | x.split(r###"'"###); | ^^^^^^^^^^ help: consider using a `char`: `'\''` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:61:13 + --> tests/ui/single_char_pattern.rs:95:13 | LL | x.split(r###"#"###); | ^^^^^^^^^^ help: consider using a `char`: `'#'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:63:13 + --> tests/ui/single_char_pattern.rs:98:13 | LL | x.split(r#"\"#); | ^^^^^^ help: consider using a `char`: `'\\'` error: single-character string constant used as pattern - --> tests/ui/single_char_pattern.rs:64:13 + --> tests/ui/single_char_pattern.rs:100:13 | LL | x.split(r"\"); | ^^^^ help: consider using a `char`: `'\\'` diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.fixed b/src/tools/clippy/tests/ui/single_component_path_imports.fixed index 3e81bcd5e4870..180a55813b19f 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.fixed +++ b/src/tools/clippy/tests/ui/single_component_path_imports.fixed @@ -3,6 +3,7 @@ use core; +//~^ single_component_path_imports use serde as edres; @@ -29,6 +30,7 @@ fn main() { mod hello_mod { + //~^ single_component_path_imports #[allow(dead_code)] fn hello_mod() {} } diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.rs b/src/tools/clippy/tests/ui/single_component_path_imports.rs index 2d72f122adf2b..888c533c534c7 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports.rs @@ -4,6 +4,7 @@ use core; use regex; +//~^ single_component_path_imports use serde as edres; @@ -30,6 +31,7 @@ fn main() { mod hello_mod { use regex; + //~^ single_component_path_imports #[allow(dead_code)] fn hello_mod() {} } diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.stderr b/src/tools/clippy/tests/ui/single_component_path_imports.stderr index 95d7e4d85b7c3..f1c56b14358ff 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.stderr +++ b/src/tools/clippy/tests/ui/single_component_path_imports.stderr @@ -8,7 +8,7 @@ LL | use regex; = help: to override `-D warnings` add `#[allow(clippy::single_component_path_imports)]` error: this import is redundant - --> tests/ui/single_component_path_imports.rs:32:5 + --> tests/ui/single_component_path_imports.rs:33:5 | LL | use regex; | ^^^^^^^^^^ help: remove it entirely diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs b/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs index fda294a61546b..f655ea482d1cf 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_macro.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs index b4a1ce1d6aec4..acfda8b3a9c8a 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.rs @@ -2,8 +2,7 @@ #![allow(unused_imports)] //@no-rustfix use regex; -//~^ ERROR: this import is redundant -//~| NOTE: `-D clippy::single-component-path-imports` implied by `-D warnings` +//~^ single_component_path_imports use serde as edres; @@ -15,8 +14,9 @@ fn main() { mod root_nested_use_mod { use {regex, serde}; - //~^ ERROR: this import is redundant - //~| ERROR: this import is redundant + //~^ single_component_path_imports + //~| single_component_path_imports + #[allow(dead_code)] fn root_nested_use_mod() {} } diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr index 8eec877860e7e..6dbfd2711b4a8 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr +++ b/src/tools/clippy/tests/ui/single_component_path_imports_nested_first.stderr @@ -8,7 +8,7 @@ LL | use regex; = help: to override `-D warnings` add `#[allow(clippy::single_component_path_imports)]` error: this import is redundant - --> tests/ui/single_component_path_imports_nested_first.rs:17:10 + --> tests/ui/single_component_path_imports_nested_first.rs:16:10 | LL | use {regex, serde}; | ^^^^^ @@ -16,7 +16,7 @@ LL | use {regex, serde}; = help: remove this import error: this import is redundant - --> tests/ui/single_component_path_imports_nested_first.rs:17:17 + --> tests/ui/single_component_path_imports_nested_first.rs:16:17 | LL | use {regex, serde}; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs b/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs index 5723d480a2e1b..a0f2cf6908091 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_self_after.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs b/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs index 8a4fbf0dc5b6a..b80580da10c39 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports_self_before.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_element_loop.fixed b/src/tools/clippy/tests/ui/single_element_loop.fixed index 64cbd5e9c9050..76c3cf56c11ec 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.fixed +++ b/src/tools/clippy/tests/ui/single_element_loop.fixed @@ -7,27 +7,33 @@ fn main() { let item1 = 2; { let item = &item1; + //~^ single_element_loop dbg!(item); } { let item = &item1; + //~^ single_element_loop dbg!(item); } for item in 0..5 { + //~^ single_element_loop dbg!(item); } for item in 0..5 { + //~^ single_element_loop dbg!(item); } for item in 0..5 { + //~^ single_element_loop dbg!(item); } for item in 0..5 { + //~^ single_element_loop dbg!(item); } @@ -48,6 +54,7 @@ fn main() { // should lint (issue #10018) { let _ = 42; + //~^ single_element_loop let _f = |n: u32| { for i in 0..n { if i > 10 { @@ -63,6 +70,7 @@ fn main() { { let (Ok(mut _x) | Err(mut _x)) = res_void; + //~^ single_element_loop let ptr: *const bool = std::ptr::null(); } } diff --git a/src/tools/clippy/tests/ui/single_element_loop.rs b/src/tools/clippy/tests/ui/single_element_loop.rs index 92406f1c1cac7..2eb928397b0a6 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.rs +++ b/src/tools/clippy/tests/ui/single_element_loop.rs @@ -6,26 +6,32 @@ fn main() { let item1 = 2; for item in &[item1] { + //~^ single_element_loop dbg!(item); } for item in [item1].iter() { + //~^ single_element_loop dbg!(item); } for item in &[0..5] { + //~^ single_element_loop dbg!(item); } for item in [0..5].iter_mut() { + //~^ single_element_loop dbg!(item); } for item in [0..5] { + //~^ single_element_loop dbg!(item); } for item in [0..5].into_iter() { + //~^ single_element_loop dbg!(item); } @@ -45,6 +51,7 @@ fn main() { // should lint (issue #10018) for _ in [42] { + //~^ single_element_loop let _f = |n: u32| { for i in 0..n { if i > 10 { @@ -59,6 +66,7 @@ fn main() { let res_void: Result = Ok(true); for (Ok(mut _x) | Err(mut _x)) in [res_void] { + //~^ single_element_loop let ptr: *const bool = std::ptr::null(); } } diff --git a/src/tools/clippy/tests/ui/single_element_loop.stderr b/src/tools/clippy/tests/ui/single_element_loop.stderr index 73453dd2dfd8c..639f8d2d1b98f 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.stderr +++ b/src/tools/clippy/tests/ui/single_element_loop.stderr @@ -2,6 +2,7 @@ error: for loop over a single element --> tests/ui/single_element_loop.rs:8:5 | LL | / for item in &[item1] { +LL | | LL | | dbg!(item); LL | | } | |_____^ @@ -12,14 +13,16 @@ help: try | LL ~ { LL + let item = &item1; +LL + LL + dbg!(item); LL + } | error: for loop over a single element - --> tests/ui/single_element_loop.rs:12:5 + --> tests/ui/single_element_loop.rs:13:5 | LL | / for item in [item1].iter() { +LL | | LL | | dbg!(item); LL | | } | |_____^ @@ -28,41 +31,42 @@ help: try | LL ~ { LL + let item = &item1; +LL + LL + dbg!(item); LL + } | error: this loops only once with `item` being `0..5` - --> tests/ui/single_element_loop.rs:16:17 + --> tests/ui/single_element_loop.rs:18:17 | LL | for item in &[0..5] { | ^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` error: this loops only once with `item` being `0..5` - --> tests/ui/single_element_loop.rs:20:17 + --> tests/ui/single_element_loop.rs:23:17 | LL | for item in [0..5].iter_mut() { | ^^^^^^^^^^^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` error: this loops only once with `item` being `0..5` - --> tests/ui/single_element_loop.rs:24:17 + --> tests/ui/single_element_loop.rs:28:17 | LL | for item in [0..5] { | ^^^^^^ help: did you mean to iterate over the range instead?: `0..5` error: this loops only once with `item` being `0..5` - --> tests/ui/single_element_loop.rs:28:17 + --> tests/ui/single_element_loop.rs:33:17 | LL | for item in [0..5].into_iter() { | ^^^^^^^^^^^^^^^^^^ help: did you mean to iterate over the range instead?: `0..5` error: for loop over a single element - --> tests/ui/single_element_loop.rs:47:5 + --> tests/ui/single_element_loop.rs:53:5 | LL | / for _ in [42] { +LL | | LL | | let _f = |n: u32| { LL | | for i in 0..n { -LL | | if i > 10 { ... | LL | | }; LL | | } @@ -72,6 +76,7 @@ help: try | LL ~ { LL + let _ = 42; +LL + LL + let _f = |n: u32| { LL + for i in 0..n { LL + if i > 10 { @@ -84,9 +89,10 @@ LL + } | error: for loop over a single element - --> tests/ui/single_element_loop.rs:61:5 + --> tests/ui/single_element_loop.rs:68:5 | LL | / for (Ok(mut _x) | Err(mut _x)) in [res_void] { +LL | | LL | | let ptr: *const bool = std::ptr::null(); LL | | } | |_____^ @@ -95,6 +101,7 @@ help: try | LL ~ { LL + let (Ok(mut _x) | Err(mut _x)) = res_void; +LL + LL + let ptr: *const bool = std::ptr::null(); LL + } | diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed index d3d5fd8b35c87..c6ffe93eb7ab3 100644 --- a/src/tools/clippy/tests/ui/single_match.fixed +++ b/src/tools/clippy/tests/ui/single_match.fixed @@ -15,6 +15,7 @@ fn single_match() { if let Some(y) = x { println!("{:?}", y); }; + //~^^^^^^ single_match let x = Some(1u8); match x { @@ -27,6 +28,7 @@ fn single_match() { let z = (1u8, 1u8); if let (2..=3, 7..=9) = z { dummy() }; + //~^^^^ single_match // Not linted (pattern guards used) match x { @@ -53,12 +55,15 @@ fn single_match_know_enum() { let y: Result<_, i8> = Ok(1i8); if let Some(y) = x { dummy() }; + //~^^^^ single_match if let Ok(y) = y { dummy() }; + //~^^^^ single_match let c = Cow::Borrowed(""); if let Cow::Borrowed(..) = c { dummy() }; + //~^^^^ single_match let z = Foo::Bar; // no warning @@ -77,6 +82,7 @@ fn single_match_know_enum() { fn if_suggestion() { let x = "test"; if x == "test" { println!() } + //~^^^^ single_match #[derive(PartialEq, Eq)] enum Foo { @@ -87,14 +93,18 @@ fn if_suggestion() { let x = Foo::A; if x == Foo::A { println!() } + //~^^^^ single_match const FOO_C: Foo = Foo::C(0); if x == FOO_C { println!() } + //~^^^^ single_match if x == Foo::A { println!() } + //~^^^^ single_match let x = &x; if x == &Foo::A { println!() } + //~^^^^ single_match enum Bar { A, @@ -109,11 +119,13 @@ fn if_suggestion() { let x = Bar::A; if let Bar::A = x { println!() } + //~^^^^ single_match // issue #7038 struct X; let x = Some(X); if let None = x { println!() }; + //~^^^^ single_match } // See: issue #8282 @@ -133,12 +145,15 @@ fn ranges() { // lint if let (Some(_), _) = x {} + //~^^^^ single_match // lint if let (Some(E::V), _) = x { todo!() } + //~^^^^ single_match // lint if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {} + //~^^^^ single_match // Don't lint, see above. match (Some(E::V), Some(E::V), Some(E::V)) { @@ -211,6 +226,7 @@ fn issue_10808(bar: Option) { let r = &v as *const i32; println!("{}", *r); } } + //~^^^^^^^ single_match if let Some(v) = bar { unsafe { @@ -218,6 +234,7 @@ fn issue_10808(bar: Option) { println!("{}", *r); } } + //~^^^^^^^^^^ single_match } mod issue8634 { @@ -289,6 +306,7 @@ fn issue11365() { } if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() } + //~^^^^ single_match match &Some(A) { Some(A | B | C) => println!(), @@ -301,10 +319,12 @@ fn issue11365() { } if let Some(A | B) = &Some(A) { println!() } + //~^^^^ single_match } fn issue12758(s: &[u8]) { if &s[0..3] == b"foo" { println!() } + //~^^^^ single_match } #[derive(Eq, PartialEq)] @@ -315,20 +335,26 @@ const CONST_I32: i32 = 1; fn irrefutable_match() { println!(); + //~^^^^ single_match println!(); + //~^^^^ single_match let i = 0; { let a = 1; let b = 2; } + //~^^^^^^^ single_match + //~^^^^ single_match + //~^^^^ single_match println!(); + //~^^^^ single_match let mut x = vec![1i8]; diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs index 2f3547c50639d..dc758fa4281c8 100644 --- a/src/tools/clippy/tests/ui/single_match.rs +++ b/src/tools/clippy/tests/ui/single_match.rs @@ -18,6 +18,7 @@ fn single_match() { }, _ => (), }; + //~^^^^^^ single_match let x = Some(1u8); match x { @@ -33,6 +34,7 @@ fn single_match() { (2..=3, 7..=9) => dummy(), _ => {}, }; + //~^^^^ single_match // Not linted (pattern guards used) match x { @@ -62,11 +64,13 @@ fn single_match_know_enum() { Some(y) => dummy(), None => (), }; + //~^^^^ single_match match y { Ok(y) => dummy(), Err(..) => (), }; + //~^^^^ single_match let c = Cow::Borrowed(""); @@ -74,6 +78,7 @@ fn single_match_know_enum() { Cow::Borrowed(..) => dummy(), Cow::Owned(..) => (), }; + //~^^^^ single_match let z = Foo::Bar; // no warning @@ -95,6 +100,7 @@ fn if_suggestion() { "test" => println!(), _ => (), } + //~^^^^ single_match #[derive(PartialEq, Eq)] enum Foo { @@ -108,23 +114,27 @@ fn if_suggestion() { Foo::A => println!(), _ => (), } + //~^^^^ single_match const FOO_C: Foo = Foo::C(0); match x { FOO_C => println!(), _ => (), } + //~^^^^ single_match match &&x { Foo::A => println!(), _ => (), } + //~^^^^ single_match let x = &x; match &x { Foo::A => println!(), _ => (), } + //~^^^^ single_match enum Bar { A, @@ -142,6 +152,7 @@ fn if_suggestion() { Bar::A => println!(), _ => (), } + //~^^^^ single_match // issue #7038 struct X; @@ -150,6 +161,7 @@ fn if_suggestion() { None => println!(), _ => (), }; + //~^^^^ single_match } // See: issue #8282 @@ -172,18 +184,21 @@ fn ranges() { (Some(_), _) => {}, (None, _) => {}, } + //~^^^^ single_match // lint match x { (Some(E::V), _) => todo!(), (_, _) => {}, } + //~^^^^ single_match // lint match (Some(42), Some(E::V), Some(42)) { (.., Some(E::V), _) => {}, (..) => {}, } + //~^^^^ single_match // Don't lint, see above. match (Some(E::V), Some(E::V), Some(E::V)) { @@ -259,6 +274,7 @@ fn issue_10808(bar: Option) { }, _ => {}, } + //~^^^^^^^ single_match match bar { #[rustfmt::skip] @@ -270,6 +286,7 @@ fn issue_10808(bar: Option) { }, _ => {}, } + //~^^^^^^^^^^ single_match } mod issue8634 { @@ -344,6 +361,7 @@ fn issue11365() { Ok(Some(A)) => println!(), Err(_) | Ok(None | Some(_)) => {}, } + //~^^^^ single_match match &Some(A) { Some(A | B | C) => println!(), @@ -359,6 +377,7 @@ fn issue11365() { Some(A | B) => println!(), None | Some(_) => {}, } + //~^^^^ single_match } fn issue12758(s: &[u8]) { @@ -366,6 +385,7 @@ fn issue12758(s: &[u8]) { b"foo" => println!(), _ => {}, } + //~^^^^ single_match } #[derive(Eq, PartialEq)] @@ -379,11 +399,13 @@ fn irrefutable_match() { DATA => println!(), _ => {}, } + //~^^^^ single_match match CONST_I32 { CONST_I32 => println!(), _ => {}, } + //~^^^^ single_match let i = 0; match i { @@ -393,21 +415,25 @@ fn irrefutable_match() { }, _ => {}, } + //~^^^^^^^ single_match match i { i => {}, _ => {}, } + //~^^^^ single_match match i { i => (), _ => (), } + //~^^^^ single_match match CONST_I32 { CONST_I32 => println!(), _ => {}, } + //~^^^^ single_match let mut x = vec![1i8]; diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr index 54bbfbac093c2..c882969594892 100644 --- a/src/tools/clippy/tests/ui/single_match.stderr +++ b/src/tools/clippy/tests/ui/single_match.stderr @@ -19,7 +19,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:32:5 + --> tests/ui/single_match.rs:33:5 | LL | / match z { LL | | (2..=3, 7..=9) => dummy(), @@ -28,7 +28,7 @@ LL | | }; | |_____^ help: try: `if let (2..=3, 7..=9) = z { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:61:5 + --> tests/ui/single_match.rs:63:5 | LL | / match x { LL | | Some(y) => dummy(), @@ -37,7 +37,7 @@ LL | | }; | |_____^ help: try: `if let Some(y) = x { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:66:5 + --> tests/ui/single_match.rs:69:5 | LL | / match y { LL | | Ok(y) => dummy(), @@ -46,7 +46,7 @@ LL | | }; | |_____^ help: try: `if let Ok(y) = y { dummy() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:73:5 + --> tests/ui/single_match.rs:77:5 | LL | / match c { LL | | Cow::Borrowed(..) => dummy(), @@ -55,7 +55,7 @@ LL | | }; | |_____^ help: try: `if let Cow::Borrowed(..) = c { dummy() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:94:5 + --> tests/ui/single_match.rs:99:5 | LL | / match x { LL | | "test" => println!(), @@ -64,7 +64,7 @@ LL | | } | |_____^ help: try: `if x == "test" { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:107:5 + --> tests/ui/single_match.rs:113:5 | LL | / match x { LL | | Foo::A => println!(), @@ -73,7 +73,7 @@ LL | | } | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:113:5 + --> tests/ui/single_match.rs:120:5 | LL | / match x { LL | | FOO_C => println!(), @@ -82,7 +82,7 @@ LL | | } | |_____^ help: try: `if x == FOO_C { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:118:5 + --> tests/ui/single_match.rs:126:5 | LL | / match &&x { LL | | Foo::A => println!(), @@ -91,7 +91,7 @@ LL | | } | |_____^ help: try: `if x == Foo::A { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:124:5 + --> tests/ui/single_match.rs:133:5 | LL | / match &x { LL | | Foo::A => println!(), @@ -100,7 +100,7 @@ LL | | } | |_____^ help: try: `if x == &Foo::A { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:141:5 + --> tests/ui/single_match.rs:151:5 | LL | / match x { LL | | Bar::A => println!(), @@ -109,7 +109,7 @@ LL | | } | |_____^ help: try: `if let Bar::A = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:149:5 + --> tests/ui/single_match.rs:160:5 | LL | / match x { LL | | None => println!(), @@ -118,7 +118,7 @@ LL | | }; | |_____^ help: try: `if let None = x { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:171:5 + --> tests/ui/single_match.rs:183:5 | LL | / match x { LL | | (Some(_), _) => {}, @@ -127,7 +127,7 @@ LL | | } | |_____^ help: try: `if let (Some(_), _) = x {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:177:5 + --> tests/ui/single_match.rs:190:5 | LL | / match x { LL | | (Some(E::V), _) => todo!(), @@ -136,7 +136,7 @@ LL | | } | |_____^ help: try: `if let (Some(E::V), _) = x { todo!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:183:5 + --> tests/ui/single_match.rs:197:5 | LL | / match (Some(42), Some(E::V), Some(42)) { LL | | (.., Some(E::V), _) => {}, @@ -145,7 +145,7 @@ LL | | } | |_____^ help: try: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:255:5 + --> tests/ui/single_match.rs:270:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -165,7 +165,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:263:5 + --> tests/ui/single_match.rs:279:5 | LL | / match bar { LL | | #[rustfmt::skip] @@ -187,7 +187,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:343:5 + --> tests/ui/single_match.rs:360:5 | LL | / match Ok::<_, u32>(Some(A)) { LL | | Ok(Some(A)) => println!(), @@ -196,7 +196,7 @@ LL | | } | |_____^ help: try: `if let Ok(Some(A)) = Ok::<_, u32>(Some(A)) { println!() }` error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match.rs:358:5 + --> tests/ui/single_match.rs:376:5 | LL | / match &Some(A) { LL | | Some(A | B) => println!(), @@ -205,7 +205,7 @@ LL | | } | |_____^ help: try: `if let Some(A | B) = &Some(A) { println!() }` error: you seem to be trying to use `match` for an equality check. Consider using `if` - --> tests/ui/single_match.rs:365:5 + --> tests/ui/single_match.rs:384:5 | LL | / match &s[0..3] { LL | | b"foo" => println!(), @@ -214,7 +214,7 @@ LL | | } | |_____^ help: try: `if &s[0..3] == b"foo" { println!() }` error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:378:5 + --> tests/ui/single_match.rs:398:5 | LL | / match DATA { LL | | DATA => println!(), @@ -223,7 +223,7 @@ LL | | } | |_____^ help: try: `println!();` error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:383:5 + --> tests/ui/single_match.rs:404:5 | LL | / match CONST_I32 { LL | | CONST_I32 => println!(), @@ -232,7 +232,7 @@ LL | | } | |_____^ help: try: `println!();` error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:389:5 + --> tests/ui/single_match.rs:411:5 | LL | / match i { LL | | i => { @@ -252,7 +252,7 @@ LL + } | error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:397:5 + --> tests/ui/single_match.rs:420:5 | LL | / match i { LL | | i => {}, @@ -261,7 +261,7 @@ LL | | } | |_____^ help: `match` expression can be removed error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:402:5 + --> tests/ui/single_match.rs:426:5 | LL | / match i { LL | | i => (), @@ -270,7 +270,7 @@ LL | | } | |_____^ help: `match` expression can be removed error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match.rs:407:5 + --> tests/ui/single_match.rs:432:5 | LL | / match CONST_I32 { LL | | CONST_I32 => println!(), diff --git a/src/tools/clippy/tests/ui/single_match_else.fixed b/src/tools/clippy/tests/ui/single_match_else.fixed index c2ca746976bd1..64782bf62a782 100644 --- a/src/tools/clippy/tests/ui/single_match_else.fixed +++ b/src/tools/clippy/tests/ui/single_match_else.fixed @@ -18,6 +18,7 @@ fn unwrap_addr() -> Option<&'static ExprNode> { let x = 5; None }; + //~^^^^^^^ single_match_else // Don't lint with_span!(span match ExprNode::Butterflies { @@ -80,12 +81,14 @@ fn main() { println!("else block"); return } + //~^^^^^^^ single_match_else // lint here if let Some(a) = Some(1) { println!("${:?}", a) } else { println!("else block"); return; } + //~^^^^^^^ single_match_else // lint here use std::convert::Infallible; @@ -93,12 +96,14 @@ fn main() { println!("else block"); return; } + //~^^^^^^^ single_match_else use std::borrow::Cow; if let Cow::Owned(a) = Cow::from("moo") { println!("${:?}", a) } else { println!("else block"); return; } + //~^^^^^^^ single_match_else } fn issue_10808(bar: Option) { @@ -109,6 +114,7 @@ fn issue_10808(bar: Option) { println!("None1"); println!("None2"); } + //~^^^^^^^^^^ single_match_else if let Some(v) = bar { println!("Some"); @@ -118,6 +124,7 @@ fn issue_10808(bar: Option) { let r = &v as *const i32; println!("{}", *r); } } + //~^^^^^^^^^^^ single_match_else if let Some(v) = bar { unsafe { let r = &v as *const i32; @@ -127,6 +134,7 @@ fn issue_10808(bar: Option) { let r = &v as *const i32; println!("{}", *r); } } + //~^^^^^^^^^^^ single_match_else if let Some(v) = bar { unsafe { @@ -137,6 +145,7 @@ fn issue_10808(bar: Option) { println!("None"); println!("None"); } + //~^^^^^^^^^^^^^ single_match_else match bar { Some(v) => { @@ -174,4 +183,5 @@ fn issue_10808(bar: Option) { fn irrefutable_match() -> Option<&'static ExprNode> { Some(&NODE) + //~^^^^^^^ single_match_else } diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs index 2d9e877ee0fee..3f86f4d51803f 100644 --- a/src/tools/clippy/tests/ui/single_match_else.rs +++ b/src/tools/clippy/tests/ui/single_match_else.rs @@ -21,6 +21,7 @@ fn unwrap_addr() -> Option<&'static ExprNode> { None }, }; + //~^^^^^^^ single_match_else // Don't lint with_span!(span match ExprNode::Butterflies { @@ -86,6 +87,7 @@ fn main() { return }, } + //~^^^^^^^ single_match_else // lint here match Some(1) { @@ -95,6 +97,7 @@ fn main() { return; }, } + //~^^^^^^^ single_match_else // lint here use std::convert::Infallible; @@ -105,6 +108,7 @@ fn main() { return; } } + //~^^^^^^^ single_match_else use std::borrow::Cow; match Cow::from("moo") { @@ -114,6 +118,7 @@ fn main() { return; } } + //~^^^^^^^ single_match_else } fn issue_10808(bar: Option) { @@ -127,6 +132,7 @@ fn issue_10808(bar: Option) { println!("None2"); }, } + //~^^^^^^^^^^ single_match_else match bar { Some(v) => { @@ -139,6 +145,7 @@ fn issue_10808(bar: Option) { println!("{}", *r); }, } + //~^^^^^^^^^^^ single_match_else match bar { Some(v) => unsafe { @@ -151,6 +158,7 @@ fn issue_10808(bar: Option) { println!("{}", *r); }, } + //~^^^^^^^^^^^ single_match_else match bar { #[rustfmt::skip] @@ -165,6 +173,7 @@ fn issue_10808(bar: Option) { println!("None"); }, } + //~^^^^^^^^^^^^^ single_match_else match bar { Some(v) => { @@ -208,4 +217,5 @@ fn irrefutable_match() -> Option<&'static ExprNode> { None }, } + //~^^^^^^^ single_match_else } diff --git a/src/tools/clippy/tests/ui/single_match_else.stderr b/src/tools/clippy/tests/ui/single_match_else.stderr index aa494520b8419..7d4ba5fb75ef8 100644 --- a/src/tools/clippy/tests/ui/single_match_else.stderr +++ b/src/tools/clippy/tests/ui/single_match_else.stderr @@ -22,7 +22,7 @@ LL ~ }; | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:82:5 + --> tests/ui/single_match_else.rs:83:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -42,7 +42,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:91:5 + --> tests/ui/single_match_else.rs:93:5 | LL | / match Some(1) { LL | | Some(a) => println!("${:?}", a), @@ -62,7 +62,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:101:5 + --> tests/ui/single_match_else.rs:104:5 | LL | / match Result::::Ok(1) { LL | | Ok(a) => println!("${:?}", a), @@ -81,7 +81,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:110:5 + --> tests/ui/single_match_else.rs:114:5 | LL | / match Cow::from("moo") { LL | | Cow::Owned(a) => println!("${:?}", a), @@ -100,7 +100,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:120:5 + --> tests/ui/single_match_else.rs:125:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -123,7 +123,7 @@ LL + } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:131:5 + --> tests/ui/single_match_else.rs:137:5 | LL | / match bar { LL | | Some(v) => { @@ -147,7 +147,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:143:5 + --> tests/ui/single_match_else.rs:150:5 | LL | / match bar { LL | | Some(v) => unsafe { @@ -171,7 +171,7 @@ LL + } } | error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let` - --> tests/ui/single_match_else.rs:155:5 + --> tests/ui/single_match_else.rs:163:5 | LL | / match bar { LL | | #[rustfmt::skip] @@ -196,7 +196,7 @@ LL + } | error: this pattern is irrefutable, `match` is useless - --> tests/ui/single_match_else.rs:204:5 + --> tests/ui/single_match_else.rs:213:5 | LL | / match ExprNode::Butterflies { LL | | ExprNode::Butterflies => Some(&NODE), diff --git a/src/tools/clippy/tests/ui/single_option_map.rs b/src/tools/clippy/tests/ui/single_option_map.rs new file mode 100644 index 0000000000000..6126582f4635a --- /dev/null +++ b/src/tools/clippy/tests/ui/single_option_map.rs @@ -0,0 +1,72 @@ +#![warn(clippy::single_option_map)] + +use std::sync::atomic::{AtomicUsize, Ordering}; + +static ATOM: AtomicUsize = AtomicUsize::new(42); +static MAYBE_ATOMIC: Option<&AtomicUsize> = Some(&ATOM); + +fn h(arg: Option) -> Option { + //~^ single_option_map + + arg.map(|x| x * 2) +} + +fn j(arg: Option) -> Option { + //~^ single_option_map + + arg.map(|x| x * 2) +} + +fn mul_args(a: String, b: u64) -> String { + a +} + +fn mul_args_opt(a: Option, b: u64) -> Option { + //~^ single_option_map + + a.map(|val| mul_args(val, b + 1)) +} + +// No lint: no `Option` argument argument +fn maps_static_option() -> Option { + MAYBE_ATOMIC.map(|a| a.load(Ordering::Relaxed)) +} + +// No lint: wrapped by another function +fn manipulate(i: i32) -> i32 { + i + 1 +} +// No lint: wraps another function to do the optional thing +fn manipulate_opt(opt_i: Option) -> Option { + opt_i.map(manipulate) +} + +// No lint: maps other than the receiver +fn map_not_arg(arg: Option) -> Option { + maps_static_option().map(|_| arg.unwrap()) +} + +// No lint: wrapper function with η-expanded form +#[allow(clippy::redundant_closure)] +fn manipulate_opt_explicit(opt_i: Option) -> Option { + opt_i.map(|x| manipulate(x)) +} + +// No lint +fn multi_args(a: String, b: bool, c: u64) -> String { + a +} + +// No lint: contains only map of a closure that binds other arguments +fn multi_args_opt(a: Option, b: bool, c: u64) -> Option { + a.map(|a| multi_args(a, b, c)) +} + +fn main() { + let answer = Some(42u32); + let h_result = h(answer); + + let answer = Some(42u64); + let j_result = j(answer); + maps_static_option(); +} diff --git a/src/tools/clippy/tests/ui/single_option_map.stderr b/src/tools/clippy/tests/ui/single_option_map.stderr new file mode 100644 index 0000000000000..11865c5b569fe --- /dev/null +++ b/src/tools/clippy/tests/ui/single_option_map.stderr @@ -0,0 +1,40 @@ +error: `fn` that only maps over argument + --> tests/ui/single_option_map.rs:8:1 + | +LL | / fn h(arg: Option) -> Option { +LL | | +LL | | +LL | | arg.map(|x| x * 2) +LL | | } + | |_^ + | + = help: move the `.map` to the caller or to an `_opt` function + = note: `-D clippy::single-option-map` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::single_option_map)]` + +error: `fn` that only maps over argument + --> tests/ui/single_option_map.rs:14:1 + | +LL | / fn j(arg: Option) -> Option { +LL | | +LL | | +LL | | arg.map(|x| x * 2) +LL | | } + | |_^ + | + = help: move the `.map` to the caller or to an `_opt` function + +error: `fn` that only maps over argument + --> tests/ui/single_option_map.rs:24:1 + | +LL | / fn mul_args_opt(a: Option, b: u64) -> Option { +LL | | +LL | | +LL | | a.map(|val| mul_args(val, b + 1)) +LL | | } + | |_^ + | + = help: move the `.map` to the caller or to an `_opt` function + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/single_range_in_vec_init.rs b/src/tools/clippy/tests/ui/single_range_in_vec_init.rs index 7887cfc61750f..c6c0cb347dc68 100644 --- a/src/tools/clippy/tests/ui/single_range_in_vec_init.rs +++ b/src/tools/clippy/tests/ui/single_range_in_vec_init.rs @@ -24,16 +24,26 @@ fn awa_vec(start: T, end: T) { fn main() { // Lint [0..200]; + //~^ single_range_in_vec_init vec![0..200]; + //~^ single_range_in_vec_init [0u8..200]; + //~^ single_range_in_vec_init [0usize..200]; + //~^ single_range_in_vec_init [0..200usize]; + //~^ single_range_in_vec_init vec![0u8..200]; + //~^ single_range_in_vec_init vec![0usize..200]; + //~^ single_range_in_vec_init vec![0..200usize]; + //~^ single_range_in_vec_init // Only suggest collect [0..200isize]; + //~^ single_range_in_vec_init vec![0..200isize]; + //~^ single_range_in_vec_init // Do not lint [0..200, 0..100]; vec![0..200, 0..100]; diff --git a/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr b/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr index b3bc8dd4aca19..a99127a7606fb 100644 --- a/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr +++ b/src/tools/clippy/tests/ui/single_range_in_vec_init.stderr @@ -18,7 +18,7 @@ LL + [0; 200]; | error: a `Vec` of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:27:5 + --> tests/ui/single_range_in_vec_init.rs:28:5 | LL | vec![0..200]; | ^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL + vec![0; 200]; | error: an array of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:28:5 + --> tests/ui/single_range_in_vec_init.rs:30:5 | LL | [0u8..200]; | ^^^^^^^^^^ @@ -52,7 +52,7 @@ LL + [0u8; 200]; | error: an array of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:29:5 + --> tests/ui/single_range_in_vec_init.rs:32:5 | LL | [0usize..200]; | ^^^^^^^^^^^^^ @@ -69,7 +69,7 @@ LL + [0usize; 200]; | error: an array of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:30:5 + --> tests/ui/single_range_in_vec_init.rs:34:5 | LL | [0..200usize]; | ^^^^^^^^^^^^^ @@ -86,7 +86,7 @@ LL + [0; 200usize]; | error: a `Vec` of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:31:5 + --> tests/ui/single_range_in_vec_init.rs:36:5 | LL | vec![0u8..200]; | ^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL + vec![0u8; 200]; | error: a `Vec` of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:32:5 + --> tests/ui/single_range_in_vec_init.rs:38:5 | LL | vec![0usize..200]; | ^^^^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + vec![0usize; 200]; | error: a `Vec` of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:33:5 + --> tests/ui/single_range_in_vec_init.rs:40:5 | LL | vec![0..200usize]; | ^^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL + vec![0; 200usize]; | error: an array of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:35:5 + --> tests/ui/single_range_in_vec_init.rs:43:5 | LL | [0..200isize]; | ^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL + (0..200isize).collect::>(); | error: a `Vec` of `Range` that is only one element - --> tests/ui/single_range_in_vec_init.rs:36:5 + --> tests/ui/single_range_in_vec_init.rs:45:5 | LL | vec![0..200isize]; | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs index f405ba200acdf..3fe4d923441dd 100644 --- a/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs +++ b/src/tools/clippy/tests/ui/size_of_in_element_count/expressions.rs @@ -13,15 +13,15 @@ fn main() { // Count expression involving multiplication of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of::() * SIZE) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count // Count expression involving nested multiplications of size_of (Should trigger the lint) unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), HALF_SIZE * size_of_val(&x[0]) * 2) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count // Count expression involving divisions of size_of (Should trigger the lint) unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE * size_of::() / 2) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count // Count expression involving divisions by size_of (Should not trigger the lint) unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / size_of::()) }; @@ -31,7 +31,7 @@ fn main() { // Count expression involving recursive divisions by size_of (Should trigger the lint) unsafe { copy(x.as_ptr(), y.as_mut_ptr(), DOUBLE_SIZE / (2 / size_of::())) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count // No size_of calls (Should not trigger the lint) unsafe { copy(x.as_ptr(), y.as_mut_ptr(), SIZE) }; diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs index af18136a1dbe1..afd12edec1edb 100644 --- a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs +++ b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.rs @@ -16,47 +16,59 @@ fn main() { // Count is size_of (Should trigger the lint) unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count unsafe { y.as_mut_ptr().sub(size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + y.as_ptr().wrapping_sub(size_of::()); - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { y.as_ptr().add(size_of::()) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + y.as_mut_ptr().wrapping_add(size_of::()); - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + unsafe { y.as_ptr().offset(size_of::() as isize) }; - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count + y.as_mut_ptr().wrapping_offset(size_of::() as isize); - //~^ ERROR: found a count of bytes instead of a count of elements of `T` + //~^ size_of_in_element_count } diff --git a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr index de54789b22518..f11c331676691 100644 --- a/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr +++ b/src/tools/clippy/tests/ui/size_of_in_element_count/functions.stderr @@ -9,7 +9,7 @@ LL | unsafe { copy_nonoverlapping::(x.as_ptr(), y.as_mut_ptr(), size_of = help: to override `-D warnings` add `#[allow(clippy::size_of_in_element_count)]` error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:20:62 + --> tests/ui/size_of_in_element_count/functions.rs:21:62 | LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | unsafe { copy_nonoverlapping(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:23:49 + --> tests/ui/size_of_in_element_count/functions.rs:24:49 | LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | unsafe { x.as_ptr().copy_to(y.as_mut_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:25:64 + --> tests/ui/size_of_in_element_count/functions.rs:27:64 | LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^ @@ -33,7 +33,7 @@ LL | unsafe { x.as_ptr().copy_to_nonoverlapping(y.as_mut_ptr(), size_of:: tests/ui/size_of_in_element_count/functions.rs:27:51 + --> tests/ui/size_of_in_element_count/functions.rs:30:51 | LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | unsafe { y.as_mut_ptr().copy_from(x.as_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:29:66 + --> tests/ui/size_of_in_element_count/functions.rs:33:66 | LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | unsafe { y.as_mut_ptr().copy_from_nonoverlapping(x.as_ptr(), size_of::< = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:32:47 + --> tests/ui/size_of_in_element_count/functions.rs:36:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; | ^^^^^^^^^^^^^^^^ @@ -57,7 +57,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:34:47 + --> tests/ui/size_of_in_element_count/functions.rs:39:47 | LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; | ^^^^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | unsafe { copy(x.as_ptr(), y.as_mut_ptr(), size_of_val(&x[0])) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:37:66 + --> tests/ui/size_of_in_element_count/functions.rs:42:66 | LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | unsafe { swap_nonoverlapping(y.as_mut_ptr(), x.as_mut_ptr(), size_of::< = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:40:46 + --> tests/ui/size_of_in_element_count/functions.rs:45:46 | LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | slice_from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:42:38 + --> tests/ui/size_of_in_element_count/functions.rs:48:38 | LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -89,7 +89,7 @@ LL | slice_from_raw_parts(y.as_ptr(), size_of::() * SIZE); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:45:49 + --> tests/ui/size_of_in_element_count/functions.rs:51:49 | LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | unsafe { from_raw_parts_mut(y.as_mut_ptr(), size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:47:41 + --> tests/ui/size_of_in_element_count/functions.rs:54:41 | LL | unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | unsafe { from_raw_parts(y.as_ptr(), size_of::() * SIZE) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:50:33 + --> tests/ui/size_of_in_element_count/functions.rs:57:33 | LL | unsafe { y.as_mut_ptr().sub(size_of::()) }; | ^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | unsafe { y.as_mut_ptr().sub(size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:52:29 + --> tests/ui/size_of_in_element_count/functions.rs:60:29 | LL | y.as_ptr().wrapping_sub(size_of::()); | ^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL | y.as_ptr().wrapping_sub(size_of::()); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:54:29 + --> tests/ui/size_of_in_element_count/functions.rs:63:29 | LL | unsafe { y.as_ptr().add(size_of::()) }; | ^^^^^^^^^^^^^^^^ @@ -129,7 +129,7 @@ LL | unsafe { y.as_ptr().add(size_of::()) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:56:33 + --> tests/ui/size_of_in_element_count/functions.rs:66:33 | LL | y.as_mut_ptr().wrapping_add(size_of::()); | ^^^^^^^^^^^^^^^^ @@ -137,7 +137,7 @@ LL | y.as_mut_ptr().wrapping_add(size_of::()); = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:58:32 + --> tests/ui/size_of_in_element_count/functions.rs:69:32 | LL | unsafe { y.as_ptr().offset(size_of::() as isize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | unsafe { y.as_ptr().offset(size_of::() as isize) }; = help: use a count of elements instead of a count of bytes, it already gets multiplied by the size of the type error: found a count of bytes instead of a count of elements of `T` - --> tests/ui/size_of_in_element_count/functions.rs:60:36 + --> tests/ui/size_of_in_element_count/functions.rs:72:36 | LL | y.as_mut_ptr().wrapping_offset(size_of::() as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/size_of_ref.rs b/src/tools/clippy/tests/ui/size_of_ref.rs index 670c6c080eca6..9a6a9419f681e 100644 --- a/src/tools/clippy/tests/ui/size_of_ref.rs +++ b/src/tools/clippy/tests/ui/size_of_ref.rs @@ -11,9 +11,10 @@ fn main() { size_of_val(y); // no lint size_of_val(&&x); - //~^ ERROR: argument to `std::mem::size_of_val()` is a reference to a reference + //~^ size_of_ref + size_of_val(&y); - //~^ ERROR: argument to `std::mem::size_of_val()` is a reference to a reference + //~^ size_of_ref } struct S { @@ -25,6 +26,6 @@ impl S { /// Get size of object including `self`, in bytes. pub fn size(&self) -> usize { std::mem::size_of_val(&self) + (std::mem::size_of::() * self.data.capacity()) - //~^ ERROR: argument to `std::mem::size_of_val()` is a reference to a reference + //~^ size_of_ref } } diff --git a/src/tools/clippy/tests/ui/size_of_ref.stderr b/src/tools/clippy/tests/ui/size_of_ref.stderr index bb8f08de531cf..6ac0b0dd2f065 100644 --- a/src/tools/clippy/tests/ui/size_of_ref.stderr +++ b/src/tools/clippy/tests/ui/size_of_ref.stderr @@ -9,7 +9,7 @@ LL | size_of_val(&&x); = help: to override `-D warnings` add `#[allow(clippy::size_of_ref)]` error: argument to `std::mem::size_of_val()` is a reference to a reference - --> tests/ui/size_of_ref.rs:15:5 + --> tests/ui/size_of_ref.rs:16:5 | LL | size_of_val(&y); | ^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | size_of_val(&y); = help: dereference the argument to `std::mem::size_of_val()` to get the size of the value instead of the size of the reference-type error: argument to `std::mem::size_of_val()` is a reference to a reference - --> tests/ui/size_of_ref.rs:27:9 + --> tests/ui/size_of_ref.rs:28:9 | LL | std::mem::size_of_val(&self) + (std::mem::size_of::() * self.data.capacity()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/skip_while_next.rs b/src/tools/clippy/tests/ui/skip_while_next.rs index 8e4cd82cec306..96f4604ad42dd 100644 --- a/src/tools/clippy/tests/ui/skip_while_next.rs +++ b/src/tools/clippy/tests/ui/skip_while_next.rs @@ -12,9 +12,11 @@ fn skip_while_next() { // Single-line case. let _ = v.iter().skip_while(|&x| *x < 0).next(); + //~^ skip_while_next // Multi-line case. let _ = v.iter().skip_while(|&x| { + //~^ skip_while_next *x < 0 } ).next(); diff --git a/src/tools/clippy/tests/ui/skip_while_next.stderr b/src/tools/clippy/tests/ui/skip_while_next.stderr index 2c1b9eeba3b6e..5db8b4bcb5227 100644 --- a/src/tools/clippy/tests/ui/skip_while_next.stderr +++ b/src/tools/clippy/tests/ui/skip_while_next.stderr @@ -9,10 +9,11 @@ LL | let _ = v.iter().skip_while(|&x| *x < 0).next(); = help: to override `-D warnings` add `#[allow(clippy::skip_while_next)]` error: called `skip_while(

).next()` on an `Iterator` - --> tests/ui/skip_while_next.rs:17:13 + --> tests/ui/skip_while_next.rs:18:13 | LL | let _ = v.iter().skip_while(|&x| { | _____________^ +LL | | LL | | *x < 0 LL | | } LL | | ).next(); diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed b/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed index 469ad27a99b9f..16c0daff78fdc 100644 --- a/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.fixed @@ -26,8 +26,11 @@ fn main() { let string: String = "dolor sit amet".to_owned(); let bytes = &s.as_bytes()[1..5]; + //~^ sliced_string_as_bytes let bytes = &string.as_bytes()[1..]; + //~^ sliced_string_as_bytes let bytes = &"consectetur adipiscing".as_bytes()[..=5]; + //~^ sliced_string_as_bytes let f = Foo; let bytes = f[0..4].as_bytes(); diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs b/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs index 4a4605e5a1aea..67985ae5b9842 100644 --- a/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.rs @@ -26,8 +26,11 @@ fn main() { let string: String = "dolor sit amet".to_owned(); let bytes = s[1..5].as_bytes(); + //~^ sliced_string_as_bytes let bytes = string[1..].as_bytes(); + //~^ sliced_string_as_bytes let bytes = "consectetur adipiscing"[..=5].as_bytes(); + //~^ sliced_string_as_bytes let f = Foo; let bytes = f[0..4].as_bytes(); diff --git a/src/tools/clippy/tests/ui/sliced_string_as_bytes.stderr b/src/tools/clippy/tests/ui/sliced_string_as_bytes.stderr index 1342f4c01a484..ae7f02781f4bb 100644 --- a/src/tools/clippy/tests/ui/sliced_string_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/sliced_string_as_bytes.stderr @@ -8,13 +8,13 @@ LL | let bytes = s[1..5].as_bytes(); = help: to override `-D warnings` add `#[allow(clippy::sliced_string_as_bytes)]` error: calling `as_bytes` after slicing a string - --> tests/ui/sliced_string_as_bytes.rs:29:17 + --> tests/ui/sliced_string_as_bytes.rs:30:17 | LL | let bytes = string[1..].as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&string.as_bytes()[1..]` error: calling `as_bytes` after slicing a string - --> tests/ui/sliced_string_as_bytes.rs:30:17 + --> tests/ui/sliced_string_as_bytes.rs:32:17 | LL | let bytes = "consectetur adipiscing"[..=5].as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&"consectetur adipiscing".as_bytes()[..=5]` diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs index 4b30fad409e3a..52f2a52fbbb86 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs @@ -12,13 +12,14 @@ fn extend_vector() { // Extend with constant expression let len = 300; let mut vec1 = Vec::with_capacity(len); - //~^ ERROR: slow zero-filling initialization - //~| NOTE: `-D clippy::slow-vector-initialization` implied by `-D warnings` + //~^ slow_vector_initialization + vec1.extend(repeat(0).take(len)); // Extend with len expression let mut vec2 = Vec::with_capacity(len - 10); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec2.extend(repeat(0).take(len - 10)); // Extend with mismatching expression should not be warned @@ -26,7 +27,8 @@ fn extend_vector() { vec3.extend(repeat(0).take(2)); let mut vec4 = Vec::with_capacity(len); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec4.extend(repeat(0).take(vec4.capacity())); } @@ -37,11 +39,13 @@ fn mixed_extend_resize_vector() { // Slow initialization let mut resized_vec = Vec::with_capacity(30); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + resized_vec.resize(30, 0); let mut extend_vec = Vec::with_capacity(30); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + extend_vec.extend(repeat(0).take(30)); } @@ -49,7 +53,8 @@ fn resize_vector() { // Resize with constant expression let len = 300; let mut vec1 = Vec::with_capacity(len); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec1.resize(len, 0); // Resize mismatch len @@ -58,16 +63,19 @@ fn resize_vector() { // Resize with len expression let mut vec3 = Vec::with_capacity(len - 10); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec3.resize(len - 10, 0); let mut vec4 = Vec::with_capacity(len); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec4.resize(vec4.capacity(), 0); // Reinitialization should be warned vec1 = Vec::with_capacity(10); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec1.resize(10, 0); } @@ -75,21 +83,25 @@ fn from_empty_vec() { // Resize with constant expression let len = 300; let mut vec1 = Vec::new(); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec1.resize(len, 0); // Resize with len expression let mut vec3 = Vec::new(); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec3.resize(len - 10, 0); // Reinitialization should be warned vec1 = Vec::new(); - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec1.resize(10, 0); vec1 = vec![]; - //~^ ERROR: slow zero-filling initialization + //~^ slow_vector_initialization + vec1.resize(10, 0); macro_rules! x { diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr index 4a25cafcddf26..e83eef8264724 100644 --- a/src/tools/clippy/tests/ui/slow_vector_initialization.stderr +++ b/src/tools/clippy/tests/ui/slow_vector_initialization.stderr @@ -15,106 +15,106 @@ error: slow zero-filling initialization | LL | let mut vec2 = Vec::with_capacity(len - 10); | ____________________^ -LL | | +... | LL | | vec2.extend(repeat(0).take(len - 10)); | |_________________________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:28:20 + --> tests/ui/slow_vector_initialization.rs:29:20 | LL | let mut vec4 = Vec::with_capacity(len); | ____________________^ -LL | | +... | LL | | vec4.extend(repeat(0).take(vec4.capacity())); | |________________________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:39:27 + --> tests/ui/slow_vector_initialization.rs:41:27 | LL | let mut resized_vec = Vec::with_capacity(30); | ___________________________^ -LL | | +... | LL | | resized_vec.resize(30, 0); | |_____________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:43:26 + --> tests/ui/slow_vector_initialization.rs:46:26 | LL | let mut extend_vec = Vec::with_capacity(30); | __________________________^ -LL | | +... | LL | | extend_vec.extend(repeat(0).take(30)); | |_________________________________________^ help: consider replacing this with: `vec![0; 30]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:51:20 + --> tests/ui/slow_vector_initialization.rs:55:20 | LL | let mut vec1 = Vec::with_capacity(len); | ____________________^ -LL | | +... | LL | | vec1.resize(len, 0); | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:60:20 + --> tests/ui/slow_vector_initialization.rs:65:20 | LL | let mut vec3 = Vec::with_capacity(len - 10); | ____________________^ -LL | | +... | LL | | vec3.resize(len - 10, 0); | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:64:20 + --> tests/ui/slow_vector_initialization.rs:70:20 | LL | let mut vec4 = Vec::with_capacity(len); | ____________________^ -LL | | +... | LL | | vec4.resize(vec4.capacity(), 0); | |___________________________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:69:12 + --> tests/ui/slow_vector_initialization.rs:76:12 | LL | vec1 = Vec::with_capacity(10); | ____________^ -LL | | +... | LL | | vec1.resize(10, 0); | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:77:20 + --> tests/ui/slow_vector_initialization.rs:85:20 | LL | let mut vec1 = Vec::new(); | ____________________^ -LL | | +... | LL | | vec1.resize(len, 0); | |_______________________^ help: consider replacing this with: `vec![0; len]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:82:20 + --> tests/ui/slow_vector_initialization.rs:91:20 | LL | let mut vec3 = Vec::new(); | ____________________^ -LL | | +... | LL | | vec3.resize(len - 10, 0); | |____________________________^ help: consider replacing this with: `vec![0; len - 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:87:12 + --> tests/ui/slow_vector_initialization.rs:97:12 | LL | vec1 = Vec::new(); | ____________^ -LL | | +... | LL | | vec1.resize(10, 0); | |______________________^ help: consider replacing this with: `vec![0; 10]` error: slow zero-filling initialization - --> tests/ui/slow_vector_initialization.rs:91:12 + --> tests/ui/slow_vector_initialization.rs:102:12 | LL | vec1 = vec![]; | ____________^ -LL | | +... | LL | | vec1.resize(10, 0); | |______________________^ help: consider replacing this with: `vec![0; 10]` diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.fixed b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed index 97f3a92238d20..b4870ebad2b36 100644 --- a/src/tools/clippy/tests/ui/stable_sort_primitive.fixed +++ b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed @@ -5,18 +5,25 @@ fn main() { // positive examples let mut vec = vec![1, 3, 2]; vec.sort_unstable(); + //~^ stable_sort_primitive let mut vec = vec![false, false, true]; vec.sort_unstable(); + //~^ stable_sort_primitive let mut vec = vec!['a', 'A', 'c']; vec.sort_unstable(); + //~^ stable_sort_primitive let mut vec = vec!["ab", "cd", "ab", "bc"]; vec.sort_unstable(); + //~^ stable_sort_primitive let mut vec = vec![(2, 1), (1, 2), (2, 5)]; vec.sort_unstable(); + //~^ stable_sort_primitive let mut vec = vec![[2, 1], [1, 2], [2, 5]]; vec.sort_unstable(); + //~^ stable_sort_primitive let mut arr = [1, 3, 2]; arr.sort_unstable(); + //~^ stable_sort_primitive // Negative examples: behavior changes if made unstable let mut vec = vec![1, 3, 2]; vec.sort_by_key(|i| i / 2); diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.rs b/src/tools/clippy/tests/ui/stable_sort_primitive.rs index 26e3d8e74f715..b3fe64efd6201 100644 --- a/src/tools/clippy/tests/ui/stable_sort_primitive.rs +++ b/src/tools/clippy/tests/ui/stable_sort_primitive.rs @@ -5,18 +5,25 @@ fn main() { // positive examples let mut vec = vec![1, 3, 2]; vec.sort(); + //~^ stable_sort_primitive let mut vec = vec![false, false, true]; vec.sort(); + //~^ stable_sort_primitive let mut vec = vec!['a', 'A', 'c']; vec.sort(); + //~^ stable_sort_primitive let mut vec = vec!["ab", "cd", "ab", "bc"]; vec.sort(); + //~^ stable_sort_primitive let mut vec = vec![(2, 1), (1, 2), (2, 5)]; vec.sort(); + //~^ stable_sort_primitive let mut vec = vec![[2, 1], [1, 2], [2, 5]]; vec.sort(); + //~^ stable_sort_primitive let mut arr = [1, 3, 2]; arr.sort(); + //~^ stable_sort_primitive // Negative examples: behavior changes if made unstable let mut vec = vec![1, 3, 2]; vec.sort_by_key(|i| i / 2); diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.stderr b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr index 66bd4c79bb286..00b45030139a5 100644 --- a/src/tools/clippy/tests/ui/stable_sort_primitive.stderr +++ b/src/tools/clippy/tests/ui/stable_sort_primitive.stderr @@ -9,7 +9,7 @@ LL | vec.sort(); = help: to override `-D warnings` add `#[allow(clippy::stable_sort_primitive)]` error: used `sort` on primitive type `bool` - --> tests/ui/stable_sort_primitive.rs:9:5 + --> tests/ui/stable_sort_primitive.rs:10:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -17,7 +17,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `char` - --> tests/ui/stable_sort_primitive.rs:11:5 + --> tests/ui/stable_sort_primitive.rs:13:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -25,7 +25,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `str` - --> tests/ui/stable_sort_primitive.rs:13:5 + --> tests/ui/stable_sort_primitive.rs:16:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -33,7 +33,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `tuple` - --> tests/ui/stable_sort_primitive.rs:15:5 + --> tests/ui/stable_sort_primitive.rs:19:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -41,7 +41,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `array` - --> tests/ui/stable_sort_primitive.rs:17:5 + --> tests/ui/stable_sort_primitive.rs:22:5 | LL | vec.sort(); | ^^^^^^^^^^ help: try: `vec.sort_unstable()` @@ -49,7 +49,7 @@ LL | vec.sort(); = note: an unstable sort typically performs faster without any observable difference for this data type error: used `sort` on primitive type `i32` - --> tests/ui/stable_sort_primitive.rs:19:5 + --> tests/ui/stable_sort_primitive.rs:25:5 | LL | arr.sort(); | ^^^^^^^^^^ help: try: `arr.sort_unstable()` diff --git a/src/tools/clippy/tests/ui/starts_ends_with.fixed b/src/tools/clippy/tests/ui/starts_ends_with.fixed index 252b6e5a98c09..b4f9d5867703a 100644 --- a/src/tools/clippy/tests/ui/starts_ends_with.fixed +++ b/src/tools/clippy/tests/ui/starts_ends_with.fixed @@ -5,36 +5,46 @@ fn main() {} #[allow(clippy::unnecessary_operation)] fn starts_with() { "".starts_with(' '); + //~^ chars_next_cmp !"".starts_with(' '); + //~^ chars_next_cmp // Ensure that suggestion is escaped correctly "".starts_with('\n'); + //~^ chars_next_cmp !"".starts_with('\n'); + //~^ chars_next_cmp } fn chars_cmp_with_unwrap() { let s = String::from("foo"); if s.starts_with('f') { + //~^ chars_next_cmp // s.starts_with('f') // Nothing here } if s.ends_with('o') { + //~^ chars_last_cmp // s.ends_with('o') // Nothing here } if s.ends_with('o') { + //~^ chars_last_cmp // s.ends_with('o') // Nothing here } if !s.starts_with('f') { + //~^ chars_next_cmp // !s.starts_with('f') // Nothing here } if !s.ends_with('o') { + //~^ chars_last_cmp // !s.ends_with('o') // Nothing here } if !s.ends_with('\n') { + //~^ chars_last_cmp // !s.ends_with('o') // Nothing here } @@ -43,11 +53,17 @@ fn chars_cmp_with_unwrap() { #[allow(clippy::unnecessary_operation)] fn ends_with() { "".ends_with(' '); + //~^ chars_last_cmp !"".ends_with(' '); + //~^ chars_last_cmp "".ends_with(' '); + //~^ chars_last_cmp !"".ends_with(' '); + //~^ chars_last_cmp // Ensure that suggestion is escaped correctly "".ends_with('\n'); + //~^ chars_last_cmp !"".ends_with('\n'); + //~^ chars_last_cmp } diff --git a/src/tools/clippy/tests/ui/starts_ends_with.rs b/src/tools/clippy/tests/ui/starts_ends_with.rs index 6c5655f31782d..dae04ac4a62d5 100644 --- a/src/tools/clippy/tests/ui/starts_ends_with.rs +++ b/src/tools/clippy/tests/ui/starts_ends_with.rs @@ -5,36 +5,46 @@ fn main() {} #[allow(clippy::unnecessary_operation)] fn starts_with() { "".chars().next() == Some(' '); + //~^ chars_next_cmp Some(' ') != "".chars().next(); + //~^ chars_next_cmp // Ensure that suggestion is escaped correctly "".chars().next() == Some('\n'); + //~^ chars_next_cmp Some('\n') != "".chars().next(); + //~^ chars_next_cmp } fn chars_cmp_with_unwrap() { let s = String::from("foo"); if s.chars().next().unwrap() == 'f' { + //~^ chars_next_cmp // s.starts_with('f') // Nothing here } if s.chars().next_back().unwrap() == 'o' { + //~^ chars_last_cmp // s.ends_with('o') // Nothing here } if s.chars().last().unwrap() == 'o' { + //~^ chars_last_cmp // s.ends_with('o') // Nothing here } if s.chars().next().unwrap() != 'f' { + //~^ chars_next_cmp // !s.starts_with('f') // Nothing here } if s.chars().next_back().unwrap() != 'o' { + //~^ chars_last_cmp // !s.ends_with('o') // Nothing here } if s.chars().last().unwrap() != '\n' { + //~^ chars_last_cmp // !s.ends_with('o') // Nothing here } @@ -43,11 +53,17 @@ fn chars_cmp_with_unwrap() { #[allow(clippy::unnecessary_operation)] fn ends_with() { "".chars().last() == Some(' '); + //~^ chars_last_cmp Some(' ') != "".chars().last(); + //~^ chars_last_cmp "".chars().next_back() == Some(' '); + //~^ chars_last_cmp Some(' ') != "".chars().next_back(); + //~^ chars_last_cmp // Ensure that suggestion is escaped correctly "".chars().last() == Some('\n'); + //~^ chars_last_cmp Some('\n') != "".chars().last(); + //~^ chars_last_cmp } diff --git a/src/tools/clippy/tests/ui/starts_ends_with.stderr b/src/tools/clippy/tests/ui/starts_ends_with.stderr index cee31f1e4cdd3..bcb38f2beb7b3 100644 --- a/src/tools/clippy/tests/ui/starts_ends_with.stderr +++ b/src/tools/clippy/tests/ui/starts_ends_with.stderr @@ -8,31 +8,31 @@ LL | "".chars().next() == Some(' '); = help: to override `-D warnings` add `#[allow(clippy::chars_next_cmp)]` error: you should use the `starts_with` method - --> tests/ui/starts_ends_with.rs:8:5 + --> tests/ui/starts_ends_with.rs:9:5 | LL | Some(' ') != "".chars().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')` error: you should use the `starts_with` method - --> tests/ui/starts_ends_with.rs:11:5 + --> tests/ui/starts_ends_with.rs:13:5 | LL | "".chars().next() == Some('\n'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with('\n')` error: you should use the `starts_with` method - --> tests/ui/starts_ends_with.rs:12:5 + --> tests/ui/starts_ends_with.rs:15:5 | LL | Some('\n') != "".chars().next(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with('\n')` error: you should use the `starts_with` method - --> tests/ui/starts_ends_with.rs:17:8 + --> tests/ui/starts_ends_with.rs:21:8 | LL | if s.chars().next().unwrap() == 'f' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.starts_with('f')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:21:8 + --> tests/ui/starts_ends_with.rs:26:8 | LL | if s.chars().next_back().unwrap() == 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` @@ -41,61 +41,61 @@ LL | if s.chars().next_back().unwrap() == 'o' { = help: to override `-D warnings` add `#[allow(clippy::chars_last_cmp)]` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:25:8 + --> tests/ui/starts_ends_with.rs:31:8 | LL | if s.chars().last().unwrap() == 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')` error: you should use the `starts_with` method - --> tests/ui/starts_ends_with.rs:29:8 + --> tests/ui/starts_ends_with.rs:36:8 | LL | if s.chars().next().unwrap() != 'f' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.starts_with('f')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:33:8 + --> tests/ui/starts_ends_with.rs:41:8 | LL | if s.chars().next_back().unwrap() != 'o' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:37:8 + --> tests/ui/starts_ends_with.rs:46:8 | LL | if s.chars().last().unwrap() != '\n' { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('\n')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:45:5 + --> tests/ui/starts_ends_with.rs:55:5 | LL | "".chars().last() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:46:5 + --> tests/ui/starts_ends_with.rs:57:5 | LL | Some(' ') != "".chars().last(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:47:5 + --> tests/ui/starts_ends_with.rs:59:5 | LL | "".chars().next_back() == Some(' '); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:48:5 + --> tests/ui/starts_ends_with.rs:61:5 | LL | Some(' ') != "".chars().next_back(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:51:5 + --> tests/ui/starts_ends_with.rs:65:5 | LL | "".chars().last() == Some('\n'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with('\n')` error: you should use the `ends_with` method - --> tests/ui/starts_ends_with.rs:52:5 + --> tests/ui/starts_ends_with.rs:67:5 | LL | Some('\n') != "".chars().last(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with('\n')` diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed index ec158ee02de89..ab2e801eee25f 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed +++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed @@ -89,3 +89,4 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: core::net::IpAddr) {} +//~^ std_instead_of_core diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs index 9c3c1658d8fec..f760b3561aed7 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs @@ -89,3 +89,4 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: std::net::IpAddr) {} +//~^ std_instead_of_core diff --git a/src/tools/clippy/tests/ui/str_split.fixed b/src/tools/clippy/tests/ui/str_split.fixed index 57a3c315a8779..6aca5051c5701 100644 --- a/src/tools/clippy/tests/ui/str_split.fixed +++ b/src/tools/clippy/tests/ui/str_split.fixed @@ -58,25 +58,35 @@ fn main() { // Splitting a `str` variable at "\n" or "\r\n" after trimming should warn let _ = s1.lines(); + //~^ str_split_at_newline #[allow(clippy::single_char_pattern)] let _ = s1.lines(); + //~^ str_split_at_newline let _ = s1.lines(); + //~^ str_split_at_newline // Splitting a `String` variable at "\n" or "\r\n" after trimming should warn let _ = s2.lines(); + //~^ str_split_at_newline #[allow(clippy::single_char_pattern)] let _ = s2.lines(); + //~^ str_split_at_newline let _ = s2.lines(); + //~^ str_split_at_newline // Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn. let s3 = DerefsIntoStr { s: s1 }; let _ = s3.lines(); + //~^ str_split_at_newline #[allow(clippy::single_char_pattern)] let _ = s3.lines(); + //~^ str_split_at_newline let _ = s3.lines(); + //~^ str_split_at_newline // If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix. let _ = make_str!(s1).lines(); + //~^ str_split_at_newline // CASES THAT SHOULD NOT EMIT A LINT diff --git a/src/tools/clippy/tests/ui/str_split.rs b/src/tools/clippy/tests/ui/str_split.rs index fcff036f2649a..11e9862da14ba 100644 --- a/src/tools/clippy/tests/ui/str_split.rs +++ b/src/tools/clippy/tests/ui/str_split.rs @@ -58,25 +58,35 @@ fn main() { // Splitting a `str` variable at "\n" or "\r\n" after trimming should warn let _ = s1.trim().split('\n'); + //~^ str_split_at_newline #[allow(clippy::single_char_pattern)] let _ = s1.trim().split("\n"); + //~^ str_split_at_newline let _ = s1.trim().split("\r\n"); + //~^ str_split_at_newline // Splitting a `String` variable at "\n" or "\r\n" after trimming should warn let _ = s2.trim().split('\n'); + //~^ str_split_at_newline #[allow(clippy::single_char_pattern)] let _ = s2.trim().split("\n"); + //~^ str_split_at_newline let _ = s2.trim().split("\r\n"); + //~^ str_split_at_newline // Splitting a variable that derefs into `str` at "\n" or "\r\n" after trimming should warn. let s3 = DerefsIntoStr { s: s1 }; let _ = s3.trim().split('\n'); + //~^ str_split_at_newline #[allow(clippy::single_char_pattern)] let _ = s3.trim().split("\n"); + //~^ str_split_at_newline let _ = s3.trim().split("\r\n"); + //~^ str_split_at_newline // If the `&str` is generated by a macro then the macro should not be expanded in the suggested fix. let _ = make_str!(s1).trim().split('\n'); + //~^ str_split_at_newline // CASES THAT SHOULD NOT EMIT A LINT diff --git a/src/tools/clippy/tests/ui/str_split.stderr b/src/tools/clippy/tests/ui/str_split.stderr index 7b560468f1269..c4eca81004c58 100644 --- a/src/tools/clippy/tests/ui/str_split.stderr +++ b/src/tools/clippy/tests/ui/str_split.stderr @@ -8,55 +8,55 @@ LL | let _ = s1.trim().split('\n'); = help: to override `-D warnings` add `#[allow(clippy::str_split_at_newline)]` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:62:13 + --> tests/ui/str_split.rs:63:13 | LL | let _ = s1.trim().split("\n"); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:63:13 + --> tests/ui/str_split.rs:65:13 | LL | let _ = s1.trim().split("\r\n"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s1.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:66:13 + --> tests/ui/str_split.rs:69:13 | LL | let _ = s2.trim().split('\n'); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:68:13 + --> tests/ui/str_split.rs:72:13 | LL | let _ = s2.trim().split("\n"); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:69:13 + --> tests/ui/str_split.rs:74:13 | LL | let _ = s2.trim().split("\r\n"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s2.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:73:13 + --> tests/ui/str_split.rs:79:13 | LL | let _ = s3.trim().split('\n'); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:75:13 + --> tests/ui/str_split.rs:82:13 | LL | let _ = s3.trim().split("\n"); | ^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:76:13 + --> tests/ui/str_split.rs:84:13 | LL | let _ = s3.trim().split("\r\n"); | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `s3.lines()` error: using `str.trim().split()` with hard-coded newlines - --> tests/ui/str_split.rs:79:13 + --> tests/ui/str_split.rs:88:13 | LL | let _ = make_str!(s1).trim().split('\n'); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `str.lines()` instead: `make_str!(s1).lines()` diff --git a/src/tools/clippy/tests/ui/str_to_string.fixed b/src/tools/clippy/tests/ui/str_to_string.fixed index 52e40b45a8bdd..2941c4dbd33d9 100644 --- a/src/tools/clippy/tests/ui/str_to_string.fixed +++ b/src/tools/clippy/tests/ui/str_to_string.fixed @@ -2,8 +2,9 @@ fn main() { let hello = "hello world".to_owned(); - //~^ ERROR: `to_string()` called on a `&str` + //~^ str_to_string + let msg = &hello[..]; msg.to_owned(); - //~^ ERROR: `to_string()` called on a `&str` + //~^ str_to_string } diff --git a/src/tools/clippy/tests/ui/str_to_string.rs b/src/tools/clippy/tests/ui/str_to_string.rs index f93b289c29ab3..4c4d2bb180625 100644 --- a/src/tools/clippy/tests/ui/str_to_string.rs +++ b/src/tools/clippy/tests/ui/str_to_string.rs @@ -2,8 +2,9 @@ fn main() { let hello = "hello world".to_string(); - //~^ ERROR: `to_string()` called on a `&str` + //~^ str_to_string + let msg = &hello[..]; msg.to_string(); - //~^ ERROR: `to_string()` called on a `&str` + //~^ str_to_string } diff --git a/src/tools/clippy/tests/ui/str_to_string.stderr b/src/tools/clippy/tests/ui/str_to_string.stderr index a761d96cd6b12..cb7b6b48843a5 100644 --- a/src/tools/clippy/tests/ui/str_to_string.stderr +++ b/src/tools/clippy/tests/ui/str_to_string.stderr @@ -8,7 +8,7 @@ LL | let hello = "hello world".to_string(); = help: to override `-D warnings` add `#[allow(clippy::str_to_string)]` error: `to_string()` called on a `&str` - --> tests/ui/str_to_string.rs:7:5 + --> tests/ui/str_to_string.rs:8:5 | LL | msg.to_string(); | ^^^^^^^^^^^^^^^ help: try: `msg.to_owned()` diff --git a/src/tools/clippy/tests/ui/string_add.rs b/src/tools/clippy/tests/ui/string_add.rs index c535f2ebbfcbe..5c7d13ebcd58b 100644 --- a/src/tools/clippy/tests/ui/string_add.rs +++ b/src/tools/clippy/tests/ui/string_add.rs @@ -4,17 +4,19 @@ extern crate proc_macros; use proc_macros::external; #[warn(clippy::string_add)] -#[allow(clippy::string_add_assign, unused)] +#[allow(clippy::assign_op_pattern, clippy::string_add_assign, unused)] fn main() { // ignores assignment distinction let mut x = String::new(); for _ in 1..3 { x = x + "."; + //~^ string_add } let y = String::new(); let z = y + "..."; + //~^ string_add assert_eq!(&x, &z); diff --git a/src/tools/clippy/tests/ui/string_add.stderr b/src/tools/clippy/tests/ui/string_add.stderr index fe6849b894b53..084a439410f83 100644 --- a/src/tools/clippy/tests/ui/string_add.stderr +++ b/src/tools/clippy/tests/ui/string_add.stderr @@ -1,12 +1,3 @@ -error: manual implementation of an assign operation - --> tests/ui/string_add.rs:13:9 - | -LL | x = x + "."; - | ^^^^^^^^^^^ help: replace it with: `x += "."` - | - = note: `-D clippy::assign-op-pattern` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` - error: you added something to a string. Consider using `String::push_str()` instead --> tests/ui/string_add.rs:13:13 | @@ -17,16 +8,10 @@ LL | x = x + "."; = help: to override `-D warnings` add `#[allow(clippy::string_add)]` error: you added something to a string. Consider using `String::push_str()` instead - --> tests/ui/string_add.rs:17:13 + --> tests/ui/string_add.rs:18:13 | LL | let z = y + "..."; | ^^^^^^^^^ -error: manual implementation of an assign operation - --> tests/ui/string_add.rs:22:5 - | -LL | x = x + 1; - | ^^^^^^^^^ help: replace it with: `x += 1` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/string_add_assign.fixed b/src/tools/clippy/tests/ui/string_add_assign.fixed index 31d84831d09ab..a86a304684f28 100644 --- a/src/tools/clippy/tests/ui/string_add_assign.fixed +++ b/src/tools/clippy/tests/ui/string_add_assign.fixed @@ -6,6 +6,8 @@ fn main() { for _ in 1..3 { x += "."; + //~^ string_add_assign + //~| assign_op_pattern } let y = String::new(); @@ -15,5 +17,6 @@ fn main() { let mut x = 1; x += 1; + //~^ assign_op_pattern assert_eq!(2, x); } diff --git a/src/tools/clippy/tests/ui/string_add_assign.rs b/src/tools/clippy/tests/ui/string_add_assign.rs index cdea91573cc75..042e33cf8413d 100644 --- a/src/tools/clippy/tests/ui/string_add_assign.rs +++ b/src/tools/clippy/tests/ui/string_add_assign.rs @@ -6,6 +6,8 @@ fn main() { for _ in 1..3 { x = x + "."; + //~^ string_add_assign + //~| assign_op_pattern } let y = String::new(); @@ -15,5 +17,6 @@ fn main() { let mut x = 1; x = x + 1; + //~^ assign_op_pattern assert_eq!(2, x); } diff --git a/src/tools/clippy/tests/ui/string_add_assign.stderr b/src/tools/clippy/tests/ui/string_add_assign.stderr index 50f970084e6b2..1987727479270 100644 --- a/src/tools/clippy/tests/ui/string_add_assign.stderr +++ b/src/tools/clippy/tests/ui/string_add_assign.stderr @@ -17,7 +17,7 @@ LL | x = x + "."; = help: to override `-D warnings` add `#[allow(clippy::assign_op_pattern)]` error: manual implementation of an assign operation - --> tests/ui/string_add_assign.rs:17:5 + --> tests/ui/string_add_assign.rs:19:5 | LL | x = x + 1; | ^^^^^^^^^ help: replace it with: `x += 1` diff --git a/src/tools/clippy/tests/ui/string_extend.fixed b/src/tools/clippy/tests/ui/string_extend.fixed index 142cb6a349804..17d3d927830f7 100644 --- a/src/tools/clippy/tests/ui/string_extend.fixed +++ b/src/tools/clippy/tests/ui/string_extend.fixed @@ -14,12 +14,15 @@ fn main() { s.push_str(abc); s.push_str(abc); + //~^ string_extend_chars s.push_str("abc"); s.push_str("abc"); + //~^ string_extend_chars s.push_str(&def); s.push_str(&def); + //~^ string_extend_chars s.extend(abc.chars().skip(1)); s.extend("abc".chars().skip(1)); @@ -30,4 +33,5 @@ fn main() { // issue #9735 s.push_str(&abc[0..2]); + //~^ string_extend_chars } diff --git a/src/tools/clippy/tests/ui/string_extend.rs b/src/tools/clippy/tests/ui/string_extend.rs index 41c0d29fae9ca..e2d54f4794394 100644 --- a/src/tools/clippy/tests/ui/string_extend.rs +++ b/src/tools/clippy/tests/ui/string_extend.rs @@ -14,12 +14,15 @@ fn main() { s.push_str(abc); s.extend(abc.chars()); + //~^ string_extend_chars s.push_str("abc"); s.extend("abc".chars()); + //~^ string_extend_chars s.push_str(&def); s.extend(def.chars()); + //~^ string_extend_chars s.extend(abc.chars().skip(1)); s.extend("abc".chars().skip(1)); @@ -30,4 +33,5 @@ fn main() { // issue #9735 s.extend(abc[0..2].chars()); + //~^ string_extend_chars } diff --git a/src/tools/clippy/tests/ui/string_extend.stderr b/src/tools/clippy/tests/ui/string_extend.stderr index fadda786aacb6..52aad5a02f6d8 100644 --- a/src/tools/clippy/tests/ui/string_extend.stderr +++ b/src/tools/clippy/tests/ui/string_extend.stderr @@ -8,19 +8,19 @@ LL | s.extend(abc.chars()); = help: to override `-D warnings` add `#[allow(clippy::string_extend_chars)]` error: calling `.extend(_.chars())` - --> tests/ui/string_extend.rs:19:5 + --> tests/ui/string_extend.rs:20:5 | LL | s.extend("abc".chars()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str("abc")` error: calling `.extend(_.chars())` - --> tests/ui/string_extend.rs:22:5 + --> tests/ui/string_extend.rs:24:5 | LL | s.extend(def.chars()); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&def)` error: calling `.extend(_.chars())` - --> tests/ui/string_extend.rs:32:5 + --> tests/ui/string_extend.rs:35:5 | LL | s.extend(abc[0..2].chars()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.push_str(&abc[0..2])` diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed index 6aa5a95c6f40f..193217114d882 100644 --- a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed @@ -2,4 +2,5 @@ fn main() { let _ = Some(&"Hello World!"[6..11]); + //~^ string_from_utf8_as_bytes } diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs index c8717f7950bd8..49beb19ee40fc 100644 --- a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs @@ -2,4 +2,5 @@ fn main() { let _ = std::str::from_utf8(&"Hello World!".as_bytes()[6..11]); + //~^ string_from_utf8_as_bytes } diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed index 225d4e90c4e2c..2a86dffbc7627 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed @@ -9,16 +9,21 @@ extern crate macro_rules; macro_rules! b { ($b:literal) => { const B: &[u8] = b"warning"; + //~^ string_lit_as_bytes }; } fn str_lit_as_bytes() { let bs = b"hello there"; + //~^ string_lit_as_bytes let bs = br###"raw string with 3# plus " ""###; + //~^ string_lit_as_bytes let bs = b"lit to string".to_vec(); + //~^ string_lit_as_bytes let bs = b"lit to owned".to_vec(); + //~^ string_lit_as_bytes b!("warning"); @@ -36,8 +41,10 @@ fn str_lit_as_bytes() { let current_version = env!("CARGO_PKG_VERSION").as_bytes(); let includestr = include_bytes!("string_lit_as_bytes.rs"); + //~^ string_lit_as_bytes let _ = b"string with newline\t\n"; + //~^ string_lit_as_bytes let _ = match "x".as_bytes() { b"xx" => 0, diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs index 3d116214ca424..785d8f1e0f6ba 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs @@ -9,16 +9,21 @@ extern crate macro_rules; macro_rules! b { ($b:literal) => { const B: &[u8] = $b.as_bytes(); + //~^ string_lit_as_bytes }; } fn str_lit_as_bytes() { let bs = "hello there".as_bytes(); + //~^ string_lit_as_bytes let bs = r###"raw string with 3# plus " ""###.as_bytes(); + //~^ string_lit_as_bytes let bs = "lit to string".to_string().into_bytes(); + //~^ string_lit_as_bytes let bs = "lit to owned".to_owned().into_bytes(); + //~^ string_lit_as_bytes b!("warning"); @@ -36,8 +41,10 @@ fn str_lit_as_bytes() { let current_version = env!("CARGO_PKG_VERSION").as_bytes(); let includestr = include_str!("string_lit_as_bytes.rs").as_bytes(); + //~^ string_lit_as_bytes let _ = "string with newline\t\n".as_bytes(); + //~^ string_lit_as_bytes let _ = match "x".as_bytes() { b"xx" => 0, diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr index 66b3e6f9462db..9388fbdc775d3 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr @@ -1,5 +1,5 @@ error: calling `as_bytes()` on a string literal - --> tests/ui/string_lit_as_bytes.rs:16:14 + --> tests/ui/string_lit_as_bytes.rs:17:14 | LL | let bs = "hello there".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"` @@ -8,19 +8,19 @@ LL | let bs = "hello there".as_bytes(); = help: to override `-D warnings` add `#[allow(clippy::string_lit_as_bytes)]` error: calling `as_bytes()` on a string literal - --> tests/ui/string_lit_as_bytes.rs:18:14 + --> tests/ui/string_lit_as_bytes.rs:20:14 | LL | let bs = r###"raw string with 3# plus " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###` error: calling `into_bytes()` on a string literal - --> tests/ui/string_lit_as_bytes.rs:20:14 + --> tests/ui/string_lit_as_bytes.rs:23:14 | LL | let bs = "lit to string".to_string().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()` error: calling `into_bytes()` on a string literal - --> tests/ui/string_lit_as_bytes.rs:21:14 + --> tests/ui/string_lit_as_bytes.rs:25:14 | LL | let bs = "lit to owned".to_owned().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()` @@ -37,13 +37,13 @@ LL | b!("warning"); = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) error: calling `as_bytes()` on `include_str!(..)` - --> tests/ui/string_lit_as_bytes.rs:38:22 + --> tests/ui/string_lit_as_bytes.rs:43:22 | LL | let includestr = include_str!("string_lit_as_bytes.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")` error: calling `as_bytes()` on a string literal - --> tests/ui/string_lit_as_bytes.rs:40:13 + --> tests/ui/string_lit_as_bytes.rs:46:13 | LL | let _ = "string with newline\t\n".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline\t\n"` diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.fixed b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed index 03e20c16ee63c..cf05a2c2e8356 100644 --- a/src/tools/clippy/tests/ui/string_lit_chars_any.fixed +++ b/src/tools/clippy/tests/ui/string_lit_chars_any.fixed @@ -16,11 +16,16 @@ impl NotStringLit { fn main() { let c = 'c'; matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + //~^ string_lit_chars_any matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + //~^ string_lit_chars_any matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + //~^ string_lit_chars_any matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + //~^ string_lit_chars_any #[rustfmt::skip] matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~'); + //~^ string_lit_chars_any // Do not lint NotStringLit.chars().any(|x| x == c); "\\.+*?()|[]{}^$#&-~".chars().any(|x| { diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.rs b/src/tools/clippy/tests/ui/string_lit_chars_any.rs index 12e6ffb6a9c47..22cfb784ed7d0 100644 --- a/src/tools/clippy/tests/ui/string_lit_chars_any.rs +++ b/src/tools/clippy/tests/ui/string_lit_chars_any.rs @@ -16,11 +16,16 @@ impl NotStringLit { fn main() { let c = 'c'; "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c); + //~^ string_lit_chars_any r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c); + //~^ string_lit_chars_any "\\.+*?()|[]{}^$#&-~".chars().any(|x| c == x); + //~^ string_lit_chars_any r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x); + //~^ string_lit_chars_any #[rustfmt::skip] "\\.+*?()|[]{}^$#&-~".chars().any(|x| { x == c }); + //~^ string_lit_chars_any // Do not lint NotStringLit.chars().any(|x| x == c); "\\.+*?()|[]{}^$#&-~".chars().any(|x| { diff --git a/src/tools/clippy/tests/ui/string_lit_chars_any.stderr b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr index 1e28ae7b163e6..3ba447b3c36ba 100644 --- a/src/tools/clippy/tests/ui/string_lit_chars_any.stderr +++ b/src/tools/clippy/tests/ui/string_lit_chars_any.stderr @@ -13,7 +13,7 @@ LL + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | error: usage of `.chars().any(...)` to check if a char matches any from a string literal - --> tests/ui/string_lit_chars_any.rs:19:5 + --> tests/ui/string_lit_chars_any.rs:20:5 | LL | r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| x == c); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | error: usage of `.chars().any(...)` to check if a char matches any from a string literal - --> tests/ui/string_lit_chars_any.rs:20:5 + --> tests/ui/string_lit_chars_any.rs:22:5 | LL | "\\.+*?()|[]{}^$#&-~".chars().any(|x| c == x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | error: usage of `.chars().any(...)` to check if a char matches any from a string literal - --> tests/ui/string_lit_chars_any.rs:21:5 + --> tests/ui/string_lit_chars_any.rs:24:5 | LL | r#"\.+*?()|[]{}^$#&-~"#.chars().any(|x| c == x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + matches!(c, '\\' | '.' | '+' | '*' | '?' | '(' | ')' | '|' | '[' | ']' | error: usage of `.chars().any(...)` to check if a char matches any from a string literal - --> tests/ui/string_lit_chars_any.rs:23:5 + --> tests/ui/string_lit_chars_any.rs:27:5 | LL | "\\.+*?()|[]{}^$#&-~".chars().any(|x| { x == c }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/string_slice.rs b/src/tools/clippy/tests/ui/string_slice.rs index dc519493a4dd3..0acc48c1f4121 100644 --- a/src/tools/clippy/tests/ui/string_slice.rs +++ b/src/tools/clippy/tests/ui/string_slice.rs @@ -5,15 +5,17 @@ use std::borrow::Cow; fn main() { &"Ölkanne"[1..]; - //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character - //~| NOTE: `-D clippy::string-slice` implied by `-D warnings` + //~^ string_slice + let m = "Mötörhead"; &m[2..5]; - //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character + //~^ string_slice + let s = String::from(m); &s[0..2]; - //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character + //~^ string_slice + let a = Cow::Borrowed("foo"); &a[0..3]; - //~^ ERROR: indexing into a string may panic if the index is within a UTF-8 character + //~^ string_slice } diff --git a/src/tools/clippy/tests/ui/string_slice.stderr b/src/tools/clippy/tests/ui/string_slice.stderr index bc0fcde34b826..f99413c6dfc6f 100644 --- a/src/tools/clippy/tests/ui/string_slice.stderr +++ b/src/tools/clippy/tests/ui/string_slice.stderr @@ -14,13 +14,13 @@ LL | &m[2..5]; | ^^^^^^^ error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:14:6 + --> tests/ui/string_slice.rs:15:6 | LL | &s[0..2]; | ^^^^^^^ error: indexing into a string may panic if the index is within a UTF-8 character - --> tests/ui/string_slice.rs:17:6 + --> tests/ui/string_slice.rs:19:6 | LL | &a[0..3]; | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/string_to_string.rs b/src/tools/clippy/tests/ui/string_to_string.rs index 007685b601797..94174e1253b8c 100644 --- a/src/tools/clippy/tests/ui/string_to_string.rs +++ b/src/tools/clippy/tests/ui/string_to_string.rs @@ -4,5 +4,5 @@ fn main() { let mut message = String::from("Hello"); let mut v = message.to_string(); - //~^ ERROR: `to_string()` called on a `String` + //~^ string_to_string } diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed index 1e7d04ffb9df9..31ed1cf03a2d2 100644 --- a/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed +++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed @@ -11,22 +11,29 @@ fn main() { // CString let cstring = CString::new("foo").expect("CString::new failed"); let _ = cstring.as_bytes().len(); + //~^ strlen_on_c_strings // CStr let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); let _ = cstr.to_bytes().len(); + //~^ strlen_on_c_strings let _ = cstr.to_bytes().len(); + //~^ strlen_on_c_strings let pcstr: *const &CStr = &cstr; let _ = unsafe { (*pcstr).to_bytes().len() }; + //~^ strlen_on_c_strings unsafe fn unsafe_identity(x: T) -> T { x } let _ = unsafe { unsafe_identity(cstr).to_bytes().len() }; + //~^ strlen_on_c_strings let _ = unsafe { unsafe_identity(cstr) }.to_bytes().len(); + //~^ strlen_on_c_strings let f: unsafe fn(_) -> _ = unsafe_identity; let _ = unsafe { f(cstr).to_bytes().len() }; + //~^ strlen_on_c_strings } diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs index c3ad03591d4ec..0f3798c9fd8a4 100644 --- a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs +++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs @@ -11,22 +11,29 @@ fn main() { // CString let cstring = CString::new("foo").expect("CString::new failed"); let _ = unsafe { libc::strlen(cstring.as_ptr()) }; + //~^ strlen_on_c_strings // CStr let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); let _ = unsafe { libc::strlen(cstr.as_ptr()) }; + //~^ strlen_on_c_strings let _ = unsafe { strlen(cstr.as_ptr()) }; + //~^ strlen_on_c_strings let pcstr: *const &CStr = &cstr; let _ = unsafe { strlen((*pcstr).as_ptr()) }; + //~^ strlen_on_c_strings unsafe fn unsafe_identity(x: T) -> T { x } let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; + //~^ strlen_on_c_strings let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; + //~^ strlen_on_c_strings let f: unsafe fn(_) -> _ = unsafe_identity; let _ = unsafe { strlen(f(cstr).as_ptr()) }; + //~^ strlen_on_c_strings } diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr index 8c2a7692659c4..b8619fa2df303 100644 --- a/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr +++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.stderr @@ -8,37 +8,37 @@ LL | let _ = unsafe { libc::strlen(cstring.as_ptr()) }; = help: to override `-D warnings` add `#[allow(clippy::strlen_on_c_strings)]` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:17:13 + --> tests/ui/strlen_on_c_strings.rs:18:13 | LL | let _ = unsafe { libc::strlen(cstr.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:19:13 + --> tests/ui/strlen_on_c_strings.rs:21:13 | LL | let _ = unsafe { strlen(cstr.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cstr.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:22:22 + --> tests/ui/strlen_on_c_strings.rs:25:22 | LL | let _ = unsafe { strlen((*pcstr).as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*pcstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:27:22 + --> tests/ui/strlen_on_c_strings.rs:31:22 | LL | let _ = unsafe { strlen(unsafe_identity(cstr).as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe_identity(cstr).to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:28:13 + --> tests/ui/strlen_on_c_strings.rs:33:13 | LL | let _ = unsafe { strlen(unsafe { unsafe_identity(cstr) }.as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unsafe { unsafe_identity(cstr) }.to_bytes().len()` error: using `libc::strlen` on a `CString` or `CStr` value - --> tests/ui/strlen_on_c_strings.rs:31:22 + --> tests/ui/strlen_on_c_strings.rs:37:22 | LL | let _ = unsafe { strlen(f(cstr).as_ptr()) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `f(cstr).to_bytes().len()` diff --git a/src/tools/clippy/tests/ui/struct_excessive_bools.rs b/src/tools/clippy/tests/ui/struct_excessive_bools.rs index 8137ce7a81c51..36cbc62780302 100644 --- a/src/tools/clippy/tests/ui/struct_excessive_bools.rs +++ b/src/tools/clippy/tests/ui/struct_excessive_bools.rs @@ -20,7 +20,7 @@ struct Foo { } struct BadFoo { - //~^ ERROR: more than 3 bools in a struct + //~^ struct_excessive_bools a: bool, b: bool, c: bool, @@ -37,7 +37,7 @@ struct Bar { fn main() { struct FooFoo { - //~^ ERROR: more than 3 bools in a struct + //~^ struct_excessive_bools a: bool, b: bool, c: bool, diff --git a/src/tools/clippy/tests/ui/struct_fields.rs b/src/tools/clippy/tests/ui/struct_fields.rs index 7c8867bd0fa3b..3dce530efffaa 100644 --- a/src/tools/clippy/tests/ui/struct_fields.rs +++ b/src/tools/clippy/tests/ui/struct_fields.rs @@ -339,7 +339,9 @@ struct Use { use_foo: bool, //~^ ERROR: field name starts with the struct's name use_bar: bool, + //~^ struct_field_names use_baz: bool, + //~^ struct_field_names } fn main() {} diff --git a/src/tools/clippy/tests/ui/struct_fields.stderr b/src/tools/clippy/tests/ui/struct_fields.stderr index cfda18c708c0f..79186cc1cfd8f 100644 --- a/src/tools/clippy/tests/ui/struct_fields.stderr +++ b/src/tools/clippy/tests/ui/struct_fields.stderr @@ -276,7 +276,7 @@ LL | use_bar: bool, | ^^^^^^^^^^^^^ error: field name starts with the struct's name - --> tests/ui/struct_fields.rs:342:5 + --> tests/ui/struct_fields.rs:343:5 | LL | use_baz: bool, | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs index 07280351e76ca..9798d2049c624 100644 --- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs +++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.rs @@ -12,16 +12,14 @@ impl Add for Foo { fn add(self, other: Self) -> Self { Foo(self.0 - other.0) - //~^ ERROR: suspicious use of `-` in `Add` impl - //~| NOTE: `-D clippy::suspicious-arithmetic-impl` implied by `-D warnings` + //~^ suspicious_arithmetic_impl } } impl AddAssign for Foo { fn add_assign(&mut self, other: Foo) { *self = *self - other; - //~^ ERROR: suspicious use of `-` in `AddAssign` impl - //~| NOTE: `-D clippy::suspicious-op-assign-impl` implied by `-D warnings` + //~^ suspicious_op_assign_impl } } @@ -35,7 +33,7 @@ impl BitOrAssign for Foo { impl MulAssign for Foo { fn mul_assign(&mut self, other: Foo) { self.0 /= other.0; - //~^ ERROR: suspicious use of `/` in `MulAssign` impl + //~^ suspicious_op_assign_impl } } @@ -74,7 +72,7 @@ impl Rem for Foo { fn rem(self, other: Self) -> Self { Foo(self.0 / other.0) - //~^ ERROR: suspicious use of `/` in `Rem` impl + //~^ suspicious_arithmetic_impl } } @@ -83,7 +81,7 @@ impl BitAnd for Foo { fn bitand(self, other: Self) -> Self { Foo(self.0 | other.0) - //~^ ERROR: suspicious use of `|` in `BitAnd` impl + //~^ suspicious_arithmetic_impl } } @@ -92,7 +90,7 @@ impl BitOr for Foo { fn bitor(self, other: Self) -> Self { Foo(self.0 ^ other.0) - //~^ ERROR: suspicious use of `^` in `BitOr` impl + //~^ suspicious_arithmetic_impl } } @@ -101,7 +99,7 @@ impl BitXor for Foo { fn bitxor(self, other: Self) -> Self { Foo(self.0 & other.0) - //~^ ERROR: suspicious use of `&` in `BitXor` impl + //~^ suspicious_arithmetic_impl } } @@ -110,7 +108,7 @@ impl Shl for Foo { fn shl(self, other: Self) -> Self { Foo(self.0 >> other.0) - //~^ ERROR: suspicious use of `>>` in `Shl` impl + //~^ suspicious_arithmetic_impl } } @@ -119,7 +117,7 @@ impl Shr for Foo { fn shr(self, other: Self) -> Self { Foo(self.0 << other.0) - //~^ ERROR: suspicious use of `<<` in `Shr` impl + //~^ suspicious_arithmetic_impl } } diff --git a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr index 1bfca49a635d4..2d8aac4db2a7e 100644 --- a/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr +++ b/src/tools/clippy/tests/ui/suspicious_arithmetic_impl.stderr @@ -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:22:23 + --> tests/ui/suspicious_arithmetic_impl.rs:21: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:37:16 + --> tests/ui/suspicious_arithmetic_impl.rs:35:16 | LL | self.0 /= other.0; | ^^ error: suspicious use of `/` in `Rem` impl - --> tests/ui/suspicious_arithmetic_impl.rs:76:20 + --> tests/ui/suspicious_arithmetic_impl.rs:74:20 | LL | Foo(self.0 / other.0) | ^ error: suspicious use of `|` in `BitAnd` impl - --> tests/ui/suspicious_arithmetic_impl.rs:85:20 + --> tests/ui/suspicious_arithmetic_impl.rs:83:20 | LL | Foo(self.0 | other.0) | ^ error: suspicious use of `^` in `BitOr` impl - --> tests/ui/suspicious_arithmetic_impl.rs:94:20 + --> tests/ui/suspicious_arithmetic_impl.rs:92:20 | LL | Foo(self.0 ^ other.0) | ^ error: suspicious use of `&` in `BitXor` impl - --> tests/ui/suspicious_arithmetic_impl.rs:103:20 + --> tests/ui/suspicious_arithmetic_impl.rs:101:20 | LL | Foo(self.0 & other.0) | ^ error: suspicious use of `>>` in `Shl` impl - --> tests/ui/suspicious_arithmetic_impl.rs:112:20 + --> tests/ui/suspicious_arithmetic_impl.rs:110:20 | LL | Foo(self.0 >> other.0) | ^^ error: suspicious use of `<<` in `Shr` impl - --> tests/ui/suspicious_arithmetic_impl.rs:121:20 + --> tests/ui/suspicious_arithmetic_impl.rs:119:20 | LL | Foo(self.0 << other.0) | ^^ diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed b/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed index 704d6ea1bb837..0a0d90f75e573 100644 --- a/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed +++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.fixed @@ -2,10 +2,10 @@ fn main() { // Things it should warn about: std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); - //~^ ERROR: single argument that looks like it should be multiple arguments - //~| NOTE: `-D clippy::suspicious-command-arg-space` implied by `-D warnings` + //~^ suspicious_command_arg_space + std::process::Command::new("cat").args(["--number", "file"]).spawn().unwrap(); - //~^ ERROR: single argument that looks like it should be multiple arguments + //~^ suspicious_command_arg_space // Things it should not warn about: std::process::Command::new("echo").arg("hello world").spawn().unwrap(); diff --git a/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs index 2a2a7557381c4..78bdfbdf0cb6b 100644 --- a/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs +++ b/src/tools/clippy/tests/ui/suspicious_command_arg_space.rs @@ -2,10 +2,10 @@ fn main() { // Things it should warn about: std::process::Command::new("echo").arg("-n hello").spawn().unwrap(); - //~^ ERROR: single argument that looks like it should be multiple arguments - //~| NOTE: `-D clippy::suspicious-command-arg-space` implied by `-D warnings` + //~^ suspicious_command_arg_space + std::process::Command::new("cat").arg("--number file").spawn().unwrap(); - //~^ ERROR: single argument that looks like it should be multiple arguments + //~^ suspicious_command_arg_space // Things it should not warn about: std::process::Command::new("echo").arg("hello world").spawn().unwrap(); diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed index d3df6a41cb12a..3696b0e066d28 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed @@ -4,10 +4,12 @@ //! Real module documentation. //! Fake module documentation. +//~^ suspicious_doc_comments fn baz() {} pub mod singleline_outer_doc { //! This module contains useful functions. + //~^ suspicious_doc_comments pub fn bar() {} } @@ -21,6 +23,7 @@ pub mod singleline_inner_doc { pub mod multiline_outer_doc { /*! This module contains useful functions. */ + //~^^ suspicious_doc_comments pub fn bar() {} } @@ -34,6 +37,7 @@ pub mod multiline_inner_doc { pub mod multiline_outer_doc2 { //! This module + //~^ suspicious_doc_comments //! contains //! useful functions. @@ -42,6 +46,7 @@ pub mod multiline_outer_doc2 { pub mod multiline_outer_doc3 { //! a + //~^ suspicious_doc_comments //! b /// c @@ -50,12 +55,14 @@ pub mod multiline_outer_doc3 { pub mod multiline_outer_doc4 { //! a + //~^ suspicious_doc_comments /// b pub fn bar() {} } pub mod multiline_outer_doc_gap { //! a + //~^ suspicious_doc_comments //! b pub fn bar() {} @@ -68,6 +75,7 @@ pub mod multiline_outer_doc_commented { pub mod outer_doc_macro { //! Very cool macro + //~^ suspicious_doc_comments macro_rules! x { () => {}; } @@ -75,6 +83,7 @@ pub mod outer_doc_macro { pub mod useless_outer_doc { //! Huh. + //~^ suspicious_doc_comments use std::mem; } diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs index 04db2b199c097..4107f5526d132 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs @@ -4,10 +4,12 @@ //! Real module documentation. ///! Fake module documentation. +//~^ suspicious_doc_comments fn baz() {} pub mod singleline_outer_doc { ///! This module contains useful functions. + //~^ suspicious_doc_comments pub fn bar() {} } @@ -21,6 +23,7 @@ pub mod singleline_inner_doc { pub mod multiline_outer_doc { /**! This module contains useful functions. */ + //~^^ suspicious_doc_comments pub fn bar() {} } @@ -34,6 +37,7 @@ pub mod multiline_inner_doc { pub mod multiline_outer_doc2 { ///! This module + //~^ suspicious_doc_comments ///! contains ///! useful functions. @@ -42,6 +46,7 @@ pub mod multiline_outer_doc2 { pub mod multiline_outer_doc3 { ///! a + //~^ suspicious_doc_comments ///! b /// c @@ -50,12 +55,14 @@ pub mod multiline_outer_doc3 { pub mod multiline_outer_doc4 { ///! a + //~^ suspicious_doc_comments /// b pub fn bar() {} } pub mod multiline_outer_doc_gap { ///! a + //~^ suspicious_doc_comments ///! b pub fn bar() {} @@ -68,6 +75,7 @@ pub mod multiline_outer_doc_commented { pub mod outer_doc_macro { ///! Very cool macro + //~^ suspicious_doc_comments macro_rules! x { () => {}; } @@ -75,6 +83,7 @@ pub mod outer_doc_macro { pub mod useless_outer_doc { ///! Huh. + //~^ suspicious_doc_comments use std::mem; } diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr index 7e5933df23760..df04d08537c91 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.stderr @@ -13,7 +13,7 @@ LL + //! Fake module documentation. | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:10:5 + --> tests/ui/suspicious_doc_comments.rs:11:5 | LL | ///! This module contains useful functions. | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + //! This module contains useful functions. | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:22:5 + --> tests/ui/suspicious_doc_comments.rs:24:5 | LL | / /**! This module contains useful functions. LL | | */ @@ -38,9 +38,10 @@ LL + */ | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:36:5 + --> tests/ui/suspicious_doc_comments.rs:39:5 | LL | / ///! This module +LL | | LL | | ///! contains LL | | ///! useful functions. | |__________________________^ @@ -48,25 +49,28 @@ LL | | ///! useful functions. help: use an inner doc comment to document the parent module or crate | LL ~ //! This module +LL | LL ~ //! contains LL ~ //! useful functions. | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:44:5 + --> tests/ui/suspicious_doc_comments.rs:48:5 | LL | / ///! a +LL | | LL | | ///! b | |__________^ | help: use an inner doc comment to document the parent module or crate | LL ~ //! a +LL | LL ~ //! b | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:52:5 + --> tests/ui/suspicious_doc_comments.rs:57:5 | LL | ///! a | ^^^^^^ @@ -78,10 +82,10 @@ LL + //! a | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:58:5 + --> tests/ui/suspicious_doc_comments.rs:64:5 | LL | / ///! a -LL | | +... | LL | | ///! b | |__________^ | @@ -89,11 +93,12 @@ help: use an inner doc comment to document the parent module or crate | LL ~ //! a LL | +LL | LL ~ //! b | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:70:5 + --> tests/ui/suspicious_doc_comments.rs:77:5 | LL | ///! Very cool macro | ^^^^^^^^^^^^^^^^^^^^ @@ -105,7 +110,7 @@ LL + //! Very cool macro | error: this is an outer doc comment and does not apply to the parent module or crate - --> tests/ui/suspicious_doc_comments.rs:77:5 + --> tests/ui/suspicious_doc_comments.rs:85:5 | LL | ///! Huh. | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.rs b/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.rs index 9e9c4775748ca..17c7cc15b170a 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.rs +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.rs @@ -1,16 +1,17 @@ -#![allow(unused)] +#![allow(unused, clippy::empty_line_after_doc_comments)] #![warn(clippy::suspicious_doc_comments)] //@no-rustfix ///! a -//~^ ERROR: this is an outer doc comment and does not apply to the parent module or crate -//~| NOTE: `-D clippy::suspicious-doc-comments` implied by `-D warnings` +//~^ suspicious_doc_comments + ///! b /// c ///! d pub fn foo() {} ///! a -//~^ ERROR: this is an outer doc comment and does not apply to the parent module or crate +//~^ suspicious_doc_comments + ///! b /// c ///! d diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr b/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr index d15f16f7c5032..234a22021df39 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments_unfixable.stderr @@ -26,6 +26,7 @@ error: this is an outer doc comment and does not apply to the parent module or c | LL | / ///! a LL | | +LL | | LL | | ///! b LL | | /// c LL | | ///! d @@ -35,6 +36,7 @@ help: use an inner doc comment to document the parent module or crate | LL + //! a LL | +LL | LL + //! b LL | /// c LL + //! d diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs index 3d5c892eb606e..28a3b551116d2 100644 --- a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs +++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs @@ -20,10 +20,12 @@ fn main() { // weird `else` formatting: if foo() { } { + //~^ suspicious_else_formatting } if foo() { } if foo() { + //~^ suspicious_else_formatting } let _ = { // if as the last expression @@ -31,6 +33,7 @@ fn main() { if foo() { } if foo() { + //~^ suspicious_else_formatting } else { } @@ -39,6 +42,7 @@ fn main() { let _ = { // if in the middle of a block if foo() { } if foo() { + //~^ suspicious_else_formatting } else { } @@ -50,6 +54,7 @@ fn main() { } else { } + //~^^^ suspicious_else_formatting // This is fine, though weird. Allman style braces on the else. if foo() { @@ -62,12 +67,14 @@ fn main() { } else if foo() { // the span of the above error should continue here } + //~^^^ suspicious_else_formatting if foo() { } else if foo() { // the span of the above error should continue here } + //~^^^^ suspicious_else_formatting // those are ok: if foo() { @@ -95,8 +102,8 @@ fn main() { else { - } + //~^^^^^ suspicious_else_formatting if foo() { } @@ -105,6 +112,7 @@ fn main() { { } + //~^^^^^^ suspicious_else_formatting // #3864 - Allman style braces if foo() diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr b/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr index 28c5a2d904ce2..affd20b22d9c1 100644 --- a/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr +++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.stderr @@ -9,7 +9,7 @@ LL | } { = help: to override `-D warnings` add `#[allow(clippy::suspicious_else_formatting)]` error: this looks like an `else if` but the `else` is missing - --> tests/ui/suspicious_else_formatting.rs:26:6 + --> tests/ui/suspicious_else_formatting.rs:27:6 | LL | } if foo() { | ^ @@ -17,7 +17,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> tests/ui/suspicious_else_formatting.rs:33:10 + --> tests/ui/suspicious_else_formatting.rs:35:10 | LL | } if foo() { | ^ @@ -25,7 +25,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this looks like an `else if` but the `else` is missing - --> tests/ui/suspicious_else_formatting.rs:41:10 + --> tests/ui/suspicious_else_formatting.rs:44:10 | LL | } if foo() { | ^ @@ -33,7 +33,7 @@ LL | } if foo() { = note: to remove this lint, add the missing `else` or add a new line before the second `if` error: this is an `else {..}` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:50:6 + --> tests/ui/suspicious_else_formatting.rs:54:6 | LL | } else | ______^ @@ -43,7 +43,7 @@ LL | | { = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else if` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:62:6 + --> tests/ui/suspicious_else_formatting.rs:67:6 | LL | } else | ______^ @@ -53,7 +53,7 @@ LL | | if foo() { // the span of the above error should continue here = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else if` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:67:6 + --> tests/ui/suspicious_else_formatting.rs:73:6 | LL | } | ______^ @@ -64,7 +64,7 @@ LL | | if foo() { // the span of the above error should continue here = note: to remove this lint, remove the `else` or remove the new line between `else` and `if` error: this is an `else {..}` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:94:6 + --> tests/ui/suspicious_else_formatting.rs:101:6 | LL | } | ______^ @@ -76,7 +76,7 @@ LL | | { = note: to remove this lint, remove the `else` or remove the new line between `else` and `{..}` error: this is an `else {..}` but the formatting might hide it - --> tests/ui/suspicious_else_formatting.rs:102:6 + --> tests/ui/suspicious_else_formatting.rs:109:6 | LL | } | ______^ diff --git a/src/tools/clippy/tests/ui/suspicious_map.rs b/src/tools/clippy/tests/ui/suspicious_map.rs index d4a52cb110fb1..86e48e29bb9e5 100644 --- a/src/tools/clippy/tests/ui/suspicious_map.rs +++ b/src/tools/clippy/tests/ui/suspicious_map.rs @@ -3,11 +3,11 @@ fn main() { let _ = (0..3).map(|x| x + 2).count(); - //~^ ERROR: this call to `map()` won't have an effect on the call to `count()` + //~^ suspicious_map let f = |x| x + 1; let _ = (0..3).map(f).count(); - //~^ ERROR: this call to `map()` won't have an effect on the call to `count()` + //~^ suspicious_map } fn negative() { diff --git a/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed b/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed index 60fde6e22cb68..fa680e537d305 100644 --- a/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed +++ b/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed @@ -1,7 +1,7 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::suspicious_operation_groupings)] -#![allow(dead_code, unused_parens, clippy::eq_op)] +#![allow(dead_code, unused_parens, clippy::eq_op, clippy::manual_midpoint)] struct Vec3 { x: f64, @@ -15,6 +15,7 @@ impl PartialEq for Vec3 { fn eq(&self, other: &Self) -> bool { // This should trigger the lint because `self.x` is compared to `other.y` self.x == other.x && self.y == other.y && self.z == other.z + //~^ suspicious_operation_groupings } } @@ -28,6 +29,7 @@ struct S { fn buggy_ab_cmp(s1: &S, s2: &S) -> bool { // There's no `s1.b` s1.a < s2.a && s1.b < s2.b + //~^ suspicious_operation_groupings } struct SaOnly { @@ -76,31 +78,38 @@ fn permissable(s1: &S, s2: &S) -> bool { fn non_boolean_operators(s1: &S, s2: &S) -> i32 { // There's no `s2.c` s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + s1.d * s2.d + //~^ suspicious_operation_groupings } fn odd_number_of_pairs(s1: &S, s2: &S) -> i32 { // There's no `s2.b` s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + //~^ suspicious_operation_groupings + //~| suspicious_operation_groupings } fn not_caught_by_eq_op_middle_change_left(s1: &S, s2: &S) -> i32 { // There's no `s1.b` s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + //~^ suspicious_operation_groupings } fn not_caught_by_eq_op_middle_change_right(s1: &S, s2: &S) -> i32 { // There's no `s2.b` s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + //~^ suspicious_operation_groupings } fn not_caught_by_eq_op_start(s1: &S, s2: &S) -> i32 { // There's no `s2.a` s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + //~^ suspicious_operation_groupings } fn not_caught_by_eq_op_end(s1: &S, s2: &S) -> i32 { // There's no `s2.c` s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + //~^ suspicious_operation_groupings } fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) { @@ -114,56 +123,68 @@ fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) { fn outer_parens_simple(s1: &S, s2: &S) -> i32 { // There's no `s2.b` (s1.a * s2.a + s1.b * s2.b) + //~^ suspicious_operation_groupings } fn outer_parens(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (s1.a * s2.a + s1.b * s2.b + s1.c * s2.c + s1.d * s2.d) + //~^ suspicious_operation_groupings } fn inner_parens(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d) + //~^ suspicious_operation_groupings } fn outer_and_some_inner_parens(s1: &S, s2: &S) -> i32 { // There's no `s2.c` ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d)) + //~^ suspicious_operation_groupings } fn all_parens_balanced_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.c) + (s1.d * s2.d))) + //~^ suspicious_operation_groupings + //~| suspicious_operation_groupings } fn all_parens_left_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.c)) + (s1.d * s2.d)) + //~^ suspicious_operation_groupings } fn all_parens_right_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.c) + (s1.d * s2.d))) + //~^ suspicious_operation_groupings } fn inside_other_binop_expression(s1: &S, s2: &S) -> i32 { // There's no `s1.b` (s1.a * s2.a + s1.b * s2.b) / 2 + //~^ suspicious_operation_groupings } fn inside_function_call(s1: &S, s2: &S) -> i32 { // There's no `s1.b` i32::swap_bytes(s1.a * s2.a + s1.b * s2.b) + //~^ suspicious_operation_groupings } fn inside_larger_boolean_expression(s1: &S, s2: &S) -> bool { // There's no `s1.c` s1.a > 0 && s1.b > 0 && s1.c == s2.c && s1.d == s2.d + //~^ suspicious_operation_groupings } fn inside_larger_boolean_expression_with_unsorted_ops(s1: &S, s2: &S) -> bool { // There's no `s1.c` s1.a > 0 && s1.c == s2.c && s1.b > 0 && s1.d == s2.d + //~^ suspicious_operation_groupings } struct Nested { @@ -173,6 +194,7 @@ struct Nested { fn changed_middle_ident(n1: &Nested, n2: &Nested) -> bool { // There's no `n2.inner.2.0` (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0 + //~^ suspicious_operation_groupings } // `eq_op` should catch this one. @@ -187,12 +209,14 @@ fn inside_fn_with_similar_expression(s1: &S, s2: &S, strict: bool) -> bool { } else { // There's no `s1.b` in this subexpression s1.a <= s2.a && s1.b <= s2.b + //~^ suspicious_operation_groupings } } fn inside_an_if_statement(s1: &mut S, s2: &S) { // There's no `s1.b` if s1.a < s2.a && s1.b < s2.b { + //~^ suspicious_operation_groupings s1.c = s2.c; } } @@ -200,11 +224,13 @@ fn inside_an_if_statement(s1: &mut S, s2: &S) { fn maximum_unary_minus_right_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.c) + -(-s1.d * -s2.d))) + //~^ suspicious_operation_groupings } fn unary_minus_and_an_if_expression(s1: &S, s2: &S) -> i32 { // There's no `s1.b` -(if -s1.a < -s2.a && -s1.b < -s2.b { s1.c } else { s2.a }) + //~^ suspicious_operation_groupings } fn main() {} diff --git a/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs b/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs index ce37148a853b0..4ffee640e8bda 100644 --- a/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs +++ b/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs @@ -1,7 +1,7 @@ //@compile-flags: -Zdeduplicate-diagnostics=yes #![warn(clippy::suspicious_operation_groupings)] -#![allow(dead_code, unused_parens, clippy::eq_op)] +#![allow(dead_code, unused_parens, clippy::eq_op, clippy::manual_midpoint)] struct Vec3 { x: f64, @@ -15,6 +15,7 @@ impl PartialEq for Vec3 { fn eq(&self, other: &Self) -> bool { // This should trigger the lint because `self.x` is compared to `other.y` self.x == other.y && self.y == other.y && self.z == other.z + //~^ suspicious_operation_groupings } } @@ -28,6 +29,7 @@ struct S { fn buggy_ab_cmp(s1: &S, s2: &S) -> bool { // There's no `s1.b` s1.a < s2.a && s1.a < s2.b + //~^ suspicious_operation_groupings } struct SaOnly { @@ -76,31 +78,38 @@ fn permissable(s1: &S, s2: &S) -> bool { fn non_boolean_operators(s1: &S, s2: &S) -> i32 { // There's no `s2.c` s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d + //~^ suspicious_operation_groupings } fn odd_number_of_pairs(s1: &S, s2: &S) -> i32 { // There's no `s2.b` s1.a * s2.a + s1.b * s2.c + s1.c * s2.c + //~^ suspicious_operation_groupings + //~| suspicious_operation_groupings } fn not_caught_by_eq_op_middle_change_left(s1: &S, s2: &S) -> i32 { // There's no `s1.b` s1.a * s2.a + s2.b * s2.b + s1.c * s2.c + //~^ suspicious_operation_groupings } fn not_caught_by_eq_op_middle_change_right(s1: &S, s2: &S) -> i32 { // There's no `s2.b` s1.a * s2.a + s1.b * s1.b + s1.c * s2.c + //~^ suspicious_operation_groupings } fn not_caught_by_eq_op_start(s1: &S, s2: &S) -> i32 { // There's no `s2.a` s1.a * s1.a + s1.b * s2.b + s1.c * s2.c + //~^ suspicious_operation_groupings } fn not_caught_by_eq_op_end(s1: &S, s2: &S) -> i32 { // There's no `s2.c` s1.a * s2.a + s1.b * s2.b + s1.c * s1.c + //~^ suspicious_operation_groupings } fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) { @@ -114,56 +123,68 @@ fn the_cross_product_should_not_lint(s1: &S, s2: &S) -> (i32, i32, i32) { fn outer_parens_simple(s1: &S, s2: &S) -> i32 { // There's no `s2.b` (s1.a * s2.a + s1.b * s1.b) + //~^ suspicious_operation_groupings } fn outer_parens(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) + //~^ suspicious_operation_groupings } fn inner_parens(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) + //~^ suspicious_operation_groupings } fn outer_and_some_inner_parens(s1: &S, s2: &S) -> i32 { // There's no `s2.c` ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) + //~^ suspicious_operation_groupings } fn all_parens_balanced_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) + //~^ suspicious_operation_groupings + //~| suspicious_operation_groupings } fn all_parens_left_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) + //~^ suspicious_operation_groupings } fn all_parens_right_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) + //~^ suspicious_operation_groupings } fn inside_other_binop_expression(s1: &S, s2: &S) -> i32 { // There's no `s1.b` (s1.a * s2.a + s2.b * s2.b) / 2 + //~^ suspicious_operation_groupings } fn inside_function_call(s1: &S, s2: &S) -> i32 { // There's no `s1.b` i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) + //~^ suspicious_operation_groupings } fn inside_larger_boolean_expression(s1: &S, s2: &S) -> bool { // There's no `s1.c` s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d + //~^ suspicious_operation_groupings } fn inside_larger_boolean_expression_with_unsorted_ops(s1: &S, s2: &S) -> bool { // There's no `s1.c` s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d + //~^ suspicious_operation_groupings } struct Nested { @@ -173,6 +194,7 @@ struct Nested { fn changed_middle_ident(n1: &Nested, n2: &Nested) -> bool { // There's no `n2.inner.2.0` (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 + //~^ suspicious_operation_groupings } // `eq_op` should catch this one. @@ -187,12 +209,14 @@ fn inside_fn_with_similar_expression(s1: &S, s2: &S, strict: bool) -> bool { } else { // There's no `s1.b` in this subexpression s1.a <= s2.a && s1.a <= s2.b + //~^ suspicious_operation_groupings } } fn inside_an_if_statement(s1: &mut S, s2: &S) { // There's no `s1.b` if s1.a < s2.a && s1.a < s2.b { + //~^ suspicious_operation_groupings s1.c = s2.c; } } @@ -200,11 +224,13 @@ fn inside_an_if_statement(s1: &mut S, s2: &S) { fn maximum_unary_minus_right_tree(s1: &S, s2: &S) -> i32 { // There's no `s2.c` -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) + //~^ suspicious_operation_groupings } fn unary_minus_and_an_if_expression(s1: &S, s2: &S) -> i32 { // There's no `s1.b` -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) + //~^ suspicious_operation_groupings } fn main() {} diff --git a/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr b/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr index 7cb066d57e75f..b640b2041cd3b 100644 --- a/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr +++ b/src/tools/clippy/tests/ui/suspicious_operation_groupings.stderr @@ -8,151 +8,151 @@ LL | self.x == other.y && self.y == other.y && self.z == other.z = help: to override `-D warnings` add `#[allow(clippy::suspicious_operation_groupings)]` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:30:20 + --> tests/ui/suspicious_operation_groupings.rs:31:20 | LL | s1.a < s2.a && s1.a < s2.b | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:78:33 + --> tests/ui/suspicious_operation_groupings.rs:80:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:83:19 + --> tests/ui/suspicious_operation_groupings.rs:86:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:83:19 + --> tests/ui/suspicious_operation_groupings.rs:86:19 | LL | s1.a * s2.a + s1.b * s2.c + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:88:19 + --> tests/ui/suspicious_operation_groupings.rs:93:19 | LL | s1.a * s2.a + s2.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:93:19 + --> tests/ui/suspicious_operation_groupings.rs:99:19 | LL | s1.a * s2.a + s1.b * s1.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:98:5 + --> tests/ui/suspicious_operation_groupings.rs:105:5 | LL | s1.a * s1.a + s1.b * s2.b + s1.c * s2.c | ^^^^^^^^^^^ help: did you mean: `s1.a * s2.a` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:103:33 + --> tests/ui/suspicious_operation_groupings.rs:111:33 | LL | s1.a * s2.a + s1.b * s2.b + s1.c * s1.c | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:116:20 + --> tests/ui/suspicious_operation_groupings.rs:125:20 | LL | (s1.a * s2.a + s1.b * s1.b) | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:121:34 + --> tests/ui/suspicious_operation_groupings.rs:131:34 | LL | (s1.a * s2.a + s1.b * s2.b + s1.c * s2.b + s1.d * s2.d) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:126:38 + --> tests/ui/suspicious_operation_groupings.rs:137:38 | LL | (s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:131:39 + --> tests/ui/suspicious_operation_groupings.rs:143:39 | LL | ((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:136:42 + --> tests/ui/suspicious_operation_groupings.rs:149:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:136:42 + --> tests/ui/suspicious_operation_groupings.rs:149:42 | LL | (((s1.a * s2.a) + (s1.b * s2.b)) + ((s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:141:40 + --> tests/ui/suspicious_operation_groupings.rs:156:40 | LL | (((s1.a * s2.a) + (s1.b * s2.b) + (s1.c * s2.b)) + (s1.d * s2.d)) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:146:40 + --> tests/ui/suspicious_operation_groupings.rs:162:40 | LL | ((s1.a * s2.a) + ((s1.b * s2.b) + (s1.c * s2.b) + (s1.d * s2.d))) | ^^^^^^^^^^^ help: did you mean: `s1.c * s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:151:20 + --> tests/ui/suspicious_operation_groupings.rs:168:20 | LL | (s1.a * s2.a + s2.b * s2.b) / 2 | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:156:35 + --> tests/ui/suspicious_operation_groupings.rs:174:35 | LL | i32::swap_bytes(s1.a * s2.a + s2.b * s2.b) | ^^^^^^^^^^^ help: did you mean: `s1.b * s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:161:29 + --> tests/ui/suspicious_operation_groupings.rs:180:29 | LL | s1.a > 0 && s1.b > 0 && s1.d == s2.c && s1.d == s2.d | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:166:17 + --> tests/ui/suspicious_operation_groupings.rs:186:17 | LL | s1.a > 0 && s1.d == s2.c && s1.b > 0 && s1.d == s2.d | ^^^^^^^^^^^^ help: did you mean: `s1.c == s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:175:77 + --> tests/ui/suspicious_operation_groupings.rs:196:77 | LL | (n1.inner.0).0 == (n2.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.1).0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `(n1.inner.2).0 == (n2.inner.2).0` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:189:25 + --> tests/ui/suspicious_operation_groupings.rs:211:25 | LL | s1.a <= s2.a && s1.a <= s2.b | ^^^^^^^^^^^^ help: did you mean: `s1.b <= s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:195:23 + --> tests/ui/suspicious_operation_groupings.rs:218:23 | LL | if s1.a < s2.a && s1.a < s2.b { | ^^^^^^^^^^^ help: did you mean: `s1.b < s2.b` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:202:48 + --> tests/ui/suspicious_operation_groupings.rs:226:48 | LL | -(-(-s1.a * -s2.a) + (-(-s1.b * -s2.b) + -(-s1.c * -s2.b) + -(-s1.d * -s2.d))) | ^^^^^^^^^^^^^ help: did you mean: `-s1.c * -s2.c` error: this sequence of operators looks suspiciously like a bug - --> tests/ui/suspicious_operation_groupings.rs:207:27 + --> tests/ui/suspicious_operation_groupings.rs:232:27 | LL | -(if -s1.a < -s2.a && -s1.a < -s2.b { s1.c } else { s2.a }) | ^^^^^^^^^^^^^ help: did you mean: `-s1.b < -s2.b` diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.rs b/src/tools/clippy/tests/ui/suspicious_splitn.rs index 7aa6097062201..535f62c6bedee 100644 --- a/src/tools/clippy/tests/ui/suspicious_splitn.rs +++ b/src/tools/clippy/tests/ui/suspicious_splitn.rs @@ -8,32 +8,30 @@ fn main() { let _ = [].splitn(0, |&x: &u32| x == 1); let _ = "a,b".splitn(0, ','); - //~^ ERROR: `splitn` called with `0` splits - //~| NOTE: the resulting iterator will always return `None` + //~^ suspicious_splitn + let _ = "a,b".rsplitn(0, ','); - //~^ ERROR: `rsplitn` called with `0` splits - //~| NOTE: the resulting iterator will always return `None` + //~^ suspicious_splitn + let _ = "a,b".splitn(1, ','); - //~^ ERROR: `splitn` called with `1` split - //~| NOTE: the resulting iterator will always return the entire string followed by `No + //~^ suspicious_splitn + let _ = [0, 1, 2].splitn(0, |&x| x == 1); - //~^ ERROR: `splitn` called with `0` splits - //~| NOTE: the resulting iterator will always return `None` + //~^ suspicious_splitn + let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); - //~^ ERROR: `splitn_mut` called with `0` splits - //~| NOTE: the resulting iterator will always return `None` + //~^ suspicious_splitn + let _ = [0, 1, 2].splitn(1, |&x| x == 1); - //~^ ERROR: `splitn` called with `1` split - //~| NOTE: the resulting iterator will always return the entire slice followed by `Non + //~^ suspicious_splitn + let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); - //~^ ERROR: `rsplitn_mut` called with `1` split - //~| NOTE: the resulting iterator will always return the entire slice followed by `Non + //~^ suspicious_splitn const X: usize = 0; let _ = "a,b".splitn(X + 1, ','); - //~^ ERROR: `splitn` called with `1` split - //~| NOTE: the resulting iterator will always return the entire string followed by `No + //~^ suspicious_splitn + let _ = "a,b".splitn(X, ','); - //~^ ERROR: `splitn` called with `0` splits - //~| NOTE: the resulting iterator will always return `None` + //~^ suspicious_splitn } diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr index 6e05bc28d130e..910c905bc990e 100644 --- a/src/tools/clippy/tests/ui/suspicious_splitn.stderr +++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr @@ -57,7 +57,7 @@ LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); = note: the resulting iterator will always return the entire slice followed by `None` error: `splitn` called with `1` split - --> tests/ui/suspicious_splitn.rs:33:13 + --> tests/ui/suspicious_splitn.rs:32:13 | LL | let _ = "a,b".splitn(X + 1, ','); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | let _ = "a,b".splitn(X + 1, ','); = note: the resulting iterator will always return the entire string followed by `None` error: `splitn` called with `0` splits - --> tests/ui/suspicious_splitn.rs:36:13 + --> tests/ui/suspicious_splitn.rs:35:13 | LL | let _ = "a,b".splitn(X, ','); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.rs b/src/tools/clippy/tests/ui/suspicious_to_owned.rs index 794c2e7174afe..2eec05ccaf4cb 100644 --- a/src/tools/clippy/tests/ui/suspicious_to_owned.rs +++ b/src/tools/clippy/tests/ui/suspicious_to_owned.rs @@ -15,8 +15,8 @@ fn main() { // we expect this to be linted let cow = Cow::Borrowed(moo); let _ = cow.to_owned(); - //~^ ERROR: this `to_owned` call clones the Cow<'_, str> itself and does not cause the - //~| NOTE: `-D clippy::suspicious-to-owned` implied by `-D warnings` + //~^ suspicious_to_owned + // we expect no lints for this let cow = Cow::Borrowed(moo); let _ = cow.into_owned(); @@ -27,7 +27,8 @@ fn main() { // we expect this to be linted let cow = Cow::Borrowed(&moos); let _ = cow.to_owned(); - //~^ ERROR: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cau + //~^ suspicious_to_owned + // we expect no lints for this let cow = Cow::Borrowed(&moos); let _ = cow.into_owned(); @@ -38,7 +39,8 @@ fn main() { // we expect this to be linted let cow = Cow::Borrowed(&moos_vec); let _ = cow.to_owned(); - //~^ ERROR: this `to_owned` call clones the Cow<'_, Vec> itself and does not cau + //~^ suspicious_to_owned + // we expect no lints for this let cow = Cow::Borrowed(&moos_vec); let _ = cow.into_owned(); @@ -49,7 +51,8 @@ fn main() { // we expect this to be linted let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); let _ = cow.to_owned(); - //~^ ERROR: this `to_owned` call clones the Cow<'_, str> itself and does not cause the + //~^ suspicious_to_owned + // we expect no lints for this let cow = unsafe { CStr::from_ptr(c_moo_ptr) }.to_string_lossy(); let _ = cow.into_owned(); @@ -64,8 +67,8 @@ fn main() { // we expect implicit_clone lints for these let _ = String::from(moo).to_owned(); - //~^ ERROR: implicitly cloning a `String` by calling `to_owned` on its dereferenced ty - //~| NOTE: `-D clippy::implicit-clone` implied by `-D warnings` + //~^ implicit_clone + let _ = moos_vec.to_owned(); - //~^ ERROR: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type + //~^ implicit_clone } diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr index 2c26565d5ef14..f90bea5fb8ff6 100644 --- a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr +++ b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr @@ -33,7 +33,7 @@ LL + let _ = cow.clone(); | error: this `to_owned` call clones the Cow<'_, Vec> itself and does not cause the Cow<'_, Vec> contents to become owned - --> tests/ui/suspicious_to_owned.rs:40:13 + --> tests/ui/suspicious_to_owned.rs:41:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + let _ = cow.clone(); | error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned - --> tests/ui/suspicious_to_owned.rs:51:13 + --> tests/ui/suspicious_to_owned.rs:53:13 | LL | let _ = cow.to_owned(); | ^^^^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL + let _ = cow.clone(); | error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type - --> tests/ui/suspicious_to_owned.rs:66:13 + --> tests/ui/suspicious_to_owned.rs:69:13 | LL | let _ = String::from(moo).to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::from(moo).clone()` @@ -74,7 +74,7 @@ LL | let _ = String::from(moo).to_owned(); = help: to override `-D warnings` add `#[allow(clippy::implicit_clone)]` error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type - --> tests/ui/suspicious_to_owned.rs:69:13 + --> tests/ui/suspicious_to_owned.rs:72:13 | LL | let _ = moos_vec.to_owned(); | ^^^^^^^^^^^^^^^^^^^ help: consider using: `moos_vec.clone()` diff --git a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs index a7a62154ee0f2..ab9bdde6cf902 100644 --- a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs +++ b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.rs @@ -7,18 +7,22 @@ fn main() { let a = 42; if a >- 30 {} - //~^ ERROR: by not having a space between `>` and `-` it looks like `>-` is a single o + //~^ suspicious_unary_op_formatting + if a >=- 30 {} - //~^ ERROR: by not having a space between `>=` and `-` it looks like `>=-` is a single + //~^ suspicious_unary_op_formatting + let b = true; let c = false; if b &&! c {} - //~^ ERROR: by not having a space between `&&` and `!` it looks like `&&!` is a single + //~^ suspicious_unary_op_formatting + if a >- 30 {} - //~^ ERROR: by not having a space between `>` and `-` it looks like `>-` is a single o + //~^ suspicious_unary_op_formatting + // those are ok: if a >-30 {} diff --git a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr index 379fb17266a96..5fe18aa82435b 100644 --- a/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr +++ b/src/tools/clippy/tests/ui/suspicious_unary_op_formatting.stderr @@ -9,7 +9,7 @@ LL | if a >- 30 {} = help: to override `-D warnings` add `#[allow(clippy::suspicious_unary_op_formatting)]` error: by not having a space between `>=` and `-` it looks like `>=-` is a single operator - --> tests/ui/suspicious_unary_op_formatting.rs:11:9 + --> tests/ui/suspicious_unary_op_formatting.rs:12:9 | LL | if a >=- 30 {} | ^^^^^ @@ -17,7 +17,7 @@ LL | if a >=- 30 {} = help: put a space between `>=` and `-` and remove the space after `-` error: by not having a space between `&&` and `!` it looks like `&&!` is a single operator - --> tests/ui/suspicious_unary_op_formatting.rs:17:9 + --> tests/ui/suspicious_unary_op_formatting.rs:19:9 | LL | if b &&! c {} | ^^^^^ @@ -25,7 +25,7 @@ LL | if b &&! c {} = help: put a space between `&&` and `!` and remove the space after `!` error: by not having a space between `>` and `-` it looks like `>-` is a single operator - --> tests/ui/suspicious_unary_op_formatting.rs:20:9 + --> tests/ui/suspicious_unary_op_formatting.rs:23:9 | LL | if a >- 30 {} | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.rs b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.rs index a5319e1b2308e..40a8d8c366bac 100644 --- a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.rs +++ b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.rs @@ -11,24 +11,31 @@ macro_rules! macro_test { macro_rules! macro_test_inside { () => { 1 ^ 2 // should warn even if inside macro + // + //~^^ suspicious_xor_used_as_pow }; } fn main() { // Should warn: let _ = 2 ^ 5; - //~^ ERROR: `^` is not the exponentiation operator - //~| NOTE: `-D clippy::suspicious-xor-used-as-pow` implied by `-D warnings` + //~^ suspicious_xor_used_as_pow + let _ = 2i32 ^ 9i32; - //~^ ERROR: `^` is not the exponentiation operator + //~^ suspicious_xor_used_as_pow + let _ = 2i32 ^ 2i32; - //~^ ERROR: `^` is not the exponentiation operator + //~^ suspicious_xor_used_as_pow + let _ = 50i32 ^ 3i32; - //~^ ERROR: `^` is not the exponentiation operator + //~^ suspicious_xor_used_as_pow + let _ = 5i32 ^ 8i32; - //~^ ERROR: `^` is not the exponentiation operator + //~^ suspicious_xor_used_as_pow + let _ = 2i32 ^ 32i32; - //~^ ERROR: `^` is not the exponentiation operator + //~^ suspicious_xor_used_as_pow + macro_test_inside!(); // Should not warn: diff --git a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr index 2a153169bd347..efeafdb94acb8 100644 --- a/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr +++ b/src/tools/clippy/tests/ui/suspicious_xor_used_as_pow.stderr @@ -1,5 +1,5 @@ error: `^` is not the exponentiation operator - --> tests/ui/suspicious_xor_used_as_pow.rs:19:13 + --> tests/ui/suspicious_xor_used_as_pow.rs:21:13 | LL | let _ = 2 ^ 5; | ^^^^^ @@ -13,7 +13,7 @@ LL + let _ = 2.pow(5); | error: `^` is not the exponentiation operator - --> tests/ui/suspicious_xor_used_as_pow.rs:22:13 + --> tests/ui/suspicious_xor_used_as_pow.rs:24:13 | LL | let _ = 2i32 ^ 9i32; | ^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let _ = 2i32.pow(9i32); | error: `^` is not the exponentiation operator - --> tests/ui/suspicious_xor_used_as_pow.rs:24:13 + --> tests/ui/suspicious_xor_used_as_pow.rs:27:13 | LL | let _ = 2i32 ^ 2i32; | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let _ = 2i32.pow(2i32); | error: `^` is not the exponentiation operator - --> tests/ui/suspicious_xor_used_as_pow.rs:26:13 + --> tests/ui/suspicious_xor_used_as_pow.rs:30:13 | LL | let _ = 50i32 ^ 3i32; | ^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + let _ = 50i32.pow(3i32); | error: `^` is not the exponentiation operator - --> tests/ui/suspicious_xor_used_as_pow.rs:28:13 + --> tests/ui/suspicious_xor_used_as_pow.rs:33:13 | LL | let _ = 5i32 ^ 8i32; | ^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let _ = 5i32.pow(8i32); | error: `^` is not the exponentiation operator - --> tests/ui/suspicious_xor_used_as_pow.rs:30:13 + --> tests/ui/suspicious_xor_used_as_pow.rs:36:13 | LL | let _ = 2i32 ^ 32i32; | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs index c9ad776292907..51af55ecd27c8 100644 --- a/src/tools/clippy/tests/ui/swap.rs +++ b/src/tools/clippy/tests/ui/swap.rs @@ -26,6 +26,7 @@ fn field() { let mut bar = Bar { a: 1, b: 2 }; let temp = bar.a; + //~^ manual_swap bar.a = bar.b; bar.b = temp; @@ -38,6 +39,7 @@ fn field() { fn array() { let mut foo = [1, 2]; let temp = foo[0]; + //~^ manual_swap foo[0] = foo[1]; foo[1] = temp; @@ -47,6 +49,7 @@ fn array() { fn slice() { let foo = &mut [1, 2]; let temp = foo[0]; + //~^ manual_swap foo[0] = foo[1]; foo[1] = temp; @@ -66,6 +69,7 @@ fn unswappable_slice() { fn vec() { let mut foo = vec![1, 2]; let temp = foo[0]; + //~^ manual_swap foo[0] = foo[1]; foo[1] = temp; @@ -77,6 +81,7 @@ fn xor_swap_locals() { let mut a = 0; let mut b = 1; a ^= b; + //~^ manual_swap b ^= a; a ^= b; } @@ -85,6 +90,7 @@ fn xor_field_swap() { // This is an xor-based swap of fields in a struct. let mut bar = Bar { a: 0, b: 1 }; bar.a ^= bar.b; + //~^ manual_swap bar.b ^= bar.a; bar.a ^= bar.b; } @@ -93,6 +99,7 @@ fn xor_slice_swap() { // This is an xor-based swap of a slice let foo = &mut [1, 2]; foo[0] ^= foo[1]; + //~^ manual_swap foo[1] ^= foo[0]; foo[0] ^= foo[1]; } @@ -122,6 +129,7 @@ fn distinct_slice() { let foo = &mut [vec![1, 2], vec![3, 4]]; let bar = &mut [vec![1, 2], vec![3, 4]]; let temp = foo[0][1]; + //~^ manual_swap foo[0][1] = bar[1][0]; bar[1][0] = temp; } @@ -133,31 +141,38 @@ fn main() { let mut b = 1337; a = b; + //~^ almost_swapped b = a; ; let t = a; + //~^ manual_swap a = b; b = t; let mut c = Foo(42); c.0 = a; + //~^ almost_swapped a = c.0; ; let t = c.0; + //~^ manual_swap c.0 = a; a = t; let a = b; + //~^ almost_swapped let b = a; let mut c = 1; let mut d = 2; d = c; + //~^ almost_swapped c = d; let mut b = 1; let a = b; + //~^ almost_swapped b = a; let b = 1; @@ -171,6 +186,7 @@ fn main() { let mut a = 2; let t = b; + //~^ manual_swap b = a; a = t; } @@ -206,6 +222,7 @@ fn issue_8154() { let mut s = &mut s; let s = S3(&mut s); let t = s.0.x; + //~^ manual_swap s.0.x = s.0.y; s.0.y = t; } diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr index fad356782479b..15f7566d58960 100644 --- a/src/tools/clippy/tests/ui/swap.stderr +++ b/src/tools/clippy/tests/ui/swap.stderr @@ -2,6 +2,7 @@ error: this looks like you are swapping `bar.a` and `bar.b` manually --> tests/ui/swap.rs:28:5 | LL | / let temp = bar.a; +LL | | LL | | bar.a = bar.b; LL | | bar.b = temp; | |_________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` @@ -11,57 +12,64 @@ LL | | bar.b = temp; = help: to override `-D warnings` add `#[allow(clippy::manual_swap)]` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:40:5 + --> tests/ui/swap.rs:41:5 | LL | / let temp = foo[0]; +LL | | LL | | foo[0] = foo[1]; LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:49:5 + --> tests/ui/swap.rs:51:5 | LL | / let temp = foo[0]; +LL | | LL | | foo[0] = foo[1]; LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:68:5 + --> tests/ui/swap.rs:71:5 | LL | / let temp = foo[0]; +LL | | LL | | foo[0] = foo[1]; LL | | foo[1] = temp; | |__________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `a` and `b` manually - --> tests/ui/swap.rs:79:5 + --> tests/ui/swap.rs:83:5 | LL | / a ^= b; +LL | | LL | | b ^= a; LL | | a ^= b; | |___________^ help: try: `std::mem::swap(&mut a, &mut b);` error: this looks like you are swapping `bar.a` and `bar.b` manually - --> tests/ui/swap.rs:87:5 + --> tests/ui/swap.rs:92:5 | LL | / bar.a ^= bar.b; +LL | | LL | | bar.b ^= bar.a; LL | | bar.a ^= bar.b; | |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);` error: this looks like you are swapping elements of `foo` manually - --> tests/ui/swap.rs:95:5 + --> tests/ui/swap.rs:101:5 | LL | / foo[0] ^= foo[1]; +LL | | LL | | foo[1] ^= foo[0]; LL | | foo[0] ^= foo[1]; | |_____________________^ help: try: `foo.swap(0, 1);` error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually - --> tests/ui/swap.rs:124:5 + --> tests/ui/swap.rs:131:5 | LL | / let temp = foo[0][1]; +LL | | LL | | foo[0][1] = bar[1][0]; LL | | bar[1][0] = temp; | |_____________________^ help: try: `std::mem::swap(&mut foo[0][1], &mut bar[1][0]);` @@ -69,10 +77,11 @@ LL | | bar[1][0] = temp; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `a` and `b` manually - --> tests/ui/swap.rs:138:7 + --> tests/ui/swap.rs:147:7 | LL | ; let t = a; | _______^ +LL | | LL | | a = b; LL | | b = t; | |__________^ help: try: `std::mem::swap(&mut a, &mut b);` @@ -80,10 +89,11 @@ LL | | b = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `c.0` and `a` manually - --> tests/ui/swap.rs:147:7 + --> tests/ui/swap.rs:158:7 | LL | ; let t = c.0; | _______^ +LL | | LL | | c.0 = a; LL | | a = t; | |__________^ help: try: `std::mem::swap(&mut c.0, &mut a);` @@ -91,9 +101,10 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `b` and `a` manually - --> tests/ui/swap.rs:173:5 + --> tests/ui/swap.rs:188:5 | LL | / let t = b; +LL | | LL | | b = a; LL | | a = t; | |__________^ help: try: `std::mem::swap(&mut b, &mut a);` @@ -101,9 +112,10 @@ LL | | a = t; = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> tests/ui/swap.rs:135:5 + --> tests/ui/swap.rs:143:5 | LL | / a = b; +LL | | LL | | b = a; | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` | @@ -112,45 +124,50 @@ LL | | b = a; = help: to override `-D warnings` add `#[allow(clippy::almost_swapped)]` error: this looks like you are trying to swap `c.0` and `a` - --> tests/ui/swap.rs:144:5 + --> tests/ui/swap.rs:154:5 | LL | / c.0 = a; +LL | | LL | | a = c.0; | |___________^ help: try: `std::mem::swap(&mut c.0, &mut a)` | = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> tests/ui/swap.rs:151:5 + --> tests/ui/swap.rs:163:5 | LL | / let a = b; +LL | | LL | | let b = a; | |_____________^ help: try: `std::mem::swap(&mut a, &mut b)` | = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `d` and `c` - --> tests/ui/swap.rs:156:5 + --> tests/ui/swap.rs:169:5 | LL | / d = c; +LL | | LL | | c = d; | |_________^ help: try: `std::mem::swap(&mut d, &mut c)` | = note: or maybe you should use `std::mem::replace`? error: this looks like you are trying to swap `a` and `b` - --> tests/ui/swap.rs:160:5 + --> tests/ui/swap.rs:174:5 | LL | / let a = b; +LL | | LL | | b = a; | |_________^ help: try: `std::mem::swap(&mut a, &mut b)` | = note: or maybe you should use `std::mem::replace`? error: this looks like you are swapping `s.0.x` and `s.0.y` manually - --> tests/ui/swap.rs:208:5 + --> tests/ui/swap.rs:224:5 | LL | / let t = s.0.x; +LL | | LL | | s.0.x = s.0.y; LL | | s.0.y = t; | |______________^ help: try: `std::mem::swap(&mut s.0.x, &mut s.0.y);` diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed index 599bb0e804430..ec46368a95aed 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed @@ -9,9 +9,13 @@ fn main() { unsafe { core::ptr::swap(y, z); + //~^ swap_ptr_to_ref core::ptr::swap(y, &mut x); + //~^ swap_ptr_to_ref core::ptr::swap(&mut x, y); + //~^ swap_ptr_to_ref core::ptr::swap(addr_of_mut!(x), addr_of_mut!(x)); + //~^ swap_ptr_to_ref } let y = &mut x; diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs b/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs index 3a8a8daefddc7..6a903ddb006d2 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs @@ -9,9 +9,13 @@ fn main() { unsafe { core::mem::swap(&mut *y, &mut *z); + //~^ swap_ptr_to_ref core::mem::swap(&mut *y, &mut x); + //~^ swap_ptr_to_ref core::mem::swap(&mut x, &mut *y); + //~^ swap_ptr_to_ref core::mem::swap(&mut *addr_of_mut!(x), &mut *addr_of_mut!(x)); + //~^ swap_ptr_to_ref } let y = &mut x; diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr index 019c2f91f0e9e..6b851901f82e5 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref.stderr @@ -8,19 +8,19 @@ LL | core::mem::swap(&mut *y, &mut *z); = help: to override `-D warnings` add `#[allow(clippy::swap_ptr_to_ref)]` error: call to `core::mem::swap` with a parameter derived from a raw pointer - --> tests/ui/swap_ptr_to_ref.rs:12:9 + --> tests/ui/swap_ptr_to_ref.rs:13:9 | LL | core::mem::swap(&mut *y, &mut x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(y, &mut x)` error: call to `core::mem::swap` with a parameter derived from a raw pointer - --> tests/ui/swap_ptr_to_ref.rs:13:9 + --> tests/ui/swap_ptr_to_ref.rs:15:9 | LL | core::mem::swap(&mut x, &mut *y); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(&mut x, y)` error: call to `core::mem::swap` with a parameter derived from a raw pointer - --> tests/ui/swap_ptr_to_ref.rs:14:9 + --> tests/ui/swap_ptr_to_ref.rs:17:9 | LL | core::mem::swap(&mut *addr_of_mut!(x), &mut *addr_of_mut!(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use ptr::swap: `core::ptr::swap(addr_of_mut!(x), addr_of_mut!(x))` diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.rs b/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.rs index 08e56a5d01b22..9c7cf27096ccf 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.rs +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.rs @@ -12,11 +12,12 @@ fn main() { unsafe { core::mem::swap(addr_of_mut_to_ref!(x), &mut *y); - //~^ ERROR: call to `core::mem::swap` with a parameter derived from a raw pointer - //~| NOTE: `-D clippy::swap-ptr-to-ref` implied by `-D warnings` + //~^ swap_ptr_to_ref + core::mem::swap(&mut *y, addr_of_mut_to_ref!(x)); - //~^ ERROR: call to `core::mem::swap` with a parameter derived from a raw pointer + //~^ swap_ptr_to_ref + core::mem::swap(addr_of_mut_to_ref!(x), addr_of_mut_to_ref!(x)); - //~^ ERROR: call to `core::mem::swap` with a parameter derived from a raw pointer + //~^ swap_ptr_to_ref } } diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr b/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr index 8a0352049483e..3bb9d87b70a57 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref_unfixable.stderr @@ -14,7 +14,7 @@ LL | core::mem::swap(&mut *y, addr_of_mut_to_ref!(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: call to `core::mem::swap` with a parameter derived from a raw pointer - --> tests/ui/swap_ptr_to_ref_unfixable.rs:19:9 + --> tests/ui/swap_ptr_to_ref_unfixable.rs:20:9 | LL | core::mem::swap(addr_of_mut_to_ref!(x), addr_of_mut_to_ref!(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed b/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed new file mode 100644 index 0000000000000..c96a53ba2cd18 --- /dev/null +++ b/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.fixed @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust-clippy/issues/12302 +use std::marker::PhantomData; + +pub struct Aa(PhantomData); + +fn aa(a: Aa) { +//~^ ERROR: expected one of + +} diff --git a/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs b/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs new file mode 100644 index 0000000000000..a3a35eb26d10a --- /dev/null +++ b/src/tools/clippy/tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs @@ -0,0 +1,9 @@ +// https://github.com/rust-lang/rust-clippy/issues/12302 +use std::marker::PhantomData; + +pub struct Aa(PhantomData); + +fn aa(a: Aa`, found `)` + --> tests/ui/syntax-error-recovery/non_expressive_names_error_recovery.rs:6:19 + | +LL | fn aa(a: Aa) { + | + + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed index 3536c1746df36..ed96cbaa6d3c8 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed @@ -3,15 +3,23 @@ /// /// Struct to hold two strings: /// - first one +//~^ tabs_in_doc_comments +//~| tabs_in_doc_comments /// - second one +//~^ tabs_in_doc_comments +//~| tabs_in_doc_comments pub struct DoubleString { /// /// - First String: + //~^ tabs_in_doc_comments /// - needs to be inside here + //~^ tabs_in_doc_comments first_string: String, /// /// - Second String: + //~^ tabs_in_doc_comments /// - needs to be inside here + //~^ tabs_in_doc_comments second_string: String, } diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs index 033a685066e1a..73d4d92a862e1 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs @@ -3,15 +3,23 @@ /// /// Struct to hold two strings: /// - first one +//~^ tabs_in_doc_comments +//~| tabs_in_doc_comments /// - second one +//~^ tabs_in_doc_comments +//~| tabs_in_doc_comments pub struct DoubleString { /// /// - First String: + //~^ tabs_in_doc_comments /// - needs to be inside here + //~^ tabs_in_doc_comments first_string: String, /// /// - Second String: + //~^ tabs_in_doc_comments /// - needs to be inside here + //~^ tabs_in_doc_comments second_string: String, } diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr index f8d30b728e58c..331bccaca92d2 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.stderr @@ -14,37 +14,37 @@ LL | /// - first one | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:5 + --> tests/ui/tabs_in_doc_comments.rs:8:5 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:6:14 + --> tests/ui/tabs_in_doc_comments.rs:8:14 | LL | /// - second one | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:9:9 + --> tests/ui/tabs_in_doc_comments.rs:13:9 | LL | /// - First String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:10:9 + --> tests/ui/tabs_in_doc_comments.rs:15:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:13:9 + --> tests/ui/tabs_in_doc_comments.rs:19:9 | LL | /// - Second String: | ^^^^ help: consider using four spaces per tab error: using tabs in doc comments is not recommended - --> tests/ui/tabs_in_doc_comments.rs:14:9 + --> tests/ui/tabs_in_doc_comments.rs:21:9 | LL | /// - needs to be inside here | ^^^^^^^^ help: consider using four spaces per tab diff --git a/src/tools/clippy/tests/ui/temporary_assignment.rs b/src/tools/clippy/tests/ui/temporary_assignment.rs index d269f91b9fa82..ac9ed5d05f8fd 100644 --- a/src/tools/clippy/tests/ui/temporary_assignment.rs +++ b/src/tools/clippy/tests/ui/temporary_assignment.rs @@ -46,18 +46,19 @@ fn main() { let mut t = (0, 0); Struct { field: 0 }.field = 1; - //~^ ERROR: assignment to temporary - //~| NOTE: `-D clippy::temporary-assignment` implied by `-D warnings` + //~^ temporary_assignment + MultiStruct { - //~^ ERROR: assignment to temporary + //~^ temporary_assignment structure: Struct { field: 0 }, } .structure .field = 1; ArrayStruct { array: [0] }.array[0] = 1; - //~^ ERROR: assignment to temporary + //~^ temporary_assignment + (0, 0).0 = 1; - //~^ ERROR: assignment to temporary + //~^ temporary_assignment // no error s.field = 1; diff --git a/src/tools/clippy/tests/ui/temporary_assignment.stderr b/src/tools/clippy/tests/ui/temporary_assignment.stderr index 7e6529cb21344..5f6a540036302 100644 --- a/src/tools/clippy/tests/ui/temporary_assignment.stderr +++ b/src/tools/clippy/tests/ui/temporary_assignment.stderr @@ -24,7 +24,7 @@ LL | ArrayStruct { array: [0] }.array[0] = 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: assignment to temporary - --> tests/ui/temporary_assignment.rs:59:5 + --> tests/ui/temporary_assignment.rs:60:5 | LL | (0, 0).0 = 1; | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/test_attr_in_doctest.rs b/src/tools/clippy/tests/ui/test_attr_in_doctest.rs index 4c904f7a09acc..6cffd813b8358 100644 --- a/src/tools/clippy/tests/ui/test_attr_in_doctest.rs +++ b/src/tools/clippy/tests/ui/test_attr_in_doctest.rs @@ -4,46 +4,44 @@ /// /// ``` /// #[test] +//~^ test_attr_in_doctest /// fn should_be_linted() { /// assert_eq!(1, 1); /// } /// ``` -/// +/// /// Make sure we catch multiple tests in one example, /// and show that we really parse the attr: -/// /// ``` /// #[test] +//~^ test_attr_in_doctest /// fn should_also_be_linted() { /// #[cfg(test)] /// assert!(true); /// } /// /// #[test] +//~^ test_attr_in_doctest /// fn should_be_linted_too() { /// assert_eq!("#[test]", " /// #[test] /// "); /// } /// ``` -/// +/// /// We don't catch examples that aren't run: -/// /// ```ignore /// #[test] /// fn ignored() { todo!() } /// ``` -/// /// ```no_run /// #[test] /// fn ignored() { todo!() } /// ``` -/// /// ```compile_fail /// #[test] /// fn ignored() { Err(()) } /// ``` -/// /// ```txt /// #[test] /// fn not_even_rust() { panic!("Ouch") } diff --git a/src/tools/clippy/tests/ui/test_attr_in_doctest.stderr b/src/tools/clippy/tests/ui/test_attr_in_doctest.stderr index f950455f2908d..166b9b417b626 100644 --- a/src/tools/clippy/tests/ui/test_attr_in_doctest.stderr +++ b/src/tools/clippy/tests/ui/test_attr_in_doctest.stderr @@ -3,6 +3,7 @@ error: unit tests in doctest are not executed | LL | /// #[test] | _____^ +LL | | LL | | /// fn should_be_linted() { | |_______________________^ | @@ -14,14 +15,16 @@ error: unit tests in doctest are not executed | LL | /// #[test] | _____^ +LL | | LL | | /// fn should_also_be_linted() { | |____________________________^ error: unit tests in doctest are not executed - --> tests/ui/test_attr_in_doctest.rs:22:5 + --> tests/ui/test_attr_in_doctest.rs:23:5 | LL | /// #[test] | _____^ +LL | | LL | | /// fn should_be_linted_too() { | |___________________________^ diff --git a/src/tools/clippy/tests/ui/tests_outside_test_module.rs b/src/tools/clippy/tests/ui/tests_outside_test_module.rs index 0abde4a57bf77..35126c46af083 100644 --- a/src/tools/clippy/tests/ui/tests_outside_test_module.rs +++ b/src/tools/clippy/tests/ui/tests_outside_test_module.rs @@ -1,3 +1,4 @@ +//@require-annotations-for-level: WARN #![allow(unused)] #![warn(clippy::tests_outside_test_module)] diff --git a/src/tools/clippy/tests/ui/tests_outside_test_module.stderr b/src/tools/clippy/tests/ui/tests_outside_test_module.stderr index 09feae6bf2aa7..8602a63cc7a41 100644 --- a/src/tools/clippy/tests/ui/tests_outside_test_module.stderr +++ b/src/tools/clippy/tests/ui/tests_outside_test_module.stderr @@ -1,5 +1,5 @@ error: this function marked with #[test] is outside a #[cfg(test)] module - --> tests/ui/tests_outside_test_module.rs:10:1 + --> tests/ui/tests_outside_test_module.rs:11:1 | LL | fn my_test() {} | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.fixed b/src/tools/clippy/tests/ui/to_digit_is_some.fixed index 2ef4c05289fdd..627d54c5f7384 100644 --- a/src/tools/clippy/tests/ui/to_digit_is_some.fixed +++ b/src/tools/clippy/tests/ui/to_digit_is_some.fixed @@ -5,5 +5,7 @@ fn main() { let d = &c; let _ = d.is_digit(8); + //~^ to_digit_is_some let _ = char::is_digit(c, 8); + //~^ to_digit_is_some } diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.rs b/src/tools/clippy/tests/ui/to_digit_is_some.rs index 54d9545809c52..d4eccc9931f17 100644 --- a/src/tools/clippy/tests/ui/to_digit_is_some.rs +++ b/src/tools/clippy/tests/ui/to_digit_is_some.rs @@ -5,5 +5,7 @@ fn main() { let d = &c; let _ = d.to_digit(8).is_some(); + //~^ to_digit_is_some let _ = char::to_digit(c, 8).is_some(); + //~^ to_digit_is_some } diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.stderr b/src/tools/clippy/tests/ui/to_digit_is_some.stderr index e44106b2e188b..f41382a60d53f 100644 --- a/src/tools/clippy/tests/ui/to_digit_is_some.stderr +++ b/src/tools/clippy/tests/ui/to_digit_is_some.stderr @@ -8,7 +8,7 @@ LL | let _ = d.to_digit(8).is_some(); = help: to override `-D warnings` add `#[allow(clippy::to_digit_is_some)]` error: use of `.to_digit(..).is_some()` - --> tests/ui/to_digit_is_some.rs:8:13 + --> tests/ui/to_digit_is_some.rs:9:13 | LL | let _ = char::to_digit(c, 8).is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `char::is_digit(c, 8)` diff --git a/src/tools/clippy/tests/ui/to_string_trait_impl.rs b/src/tools/clippy/tests/ui/to_string_trait_impl.rs index 7be9f7994f08a..646ec4db1f110 100644 --- a/src/tools/clippy/tests/ui/to_string_trait_impl.rs +++ b/src/tools/clippy/tests/ui/to_string_trait_impl.rs @@ -9,6 +9,7 @@ struct Point { } impl ToString for Point { + //~^ to_string_trait_impl fn to_string(&self) -> String { format!("({}, {})", self.x, self.y) } diff --git a/src/tools/clippy/tests/ui/to_string_trait_impl.stderr b/src/tools/clippy/tests/ui/to_string_trait_impl.stderr index fe8afc215f0c8..b24dfa39e011f 100644 --- a/src/tools/clippy/tests/ui/to_string_trait_impl.stderr +++ b/src/tools/clippy/tests/ui/to_string_trait_impl.stderr @@ -2,6 +2,7 @@ error: direct implementation of `ToString` --> tests/ui/to_string_trait_impl.rs:11:1 | LL | / impl ToString for Point { +LL | | LL | | fn to_string(&self) -> String { LL | | format!("({}, {})", self.x, self.y) LL | | } diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.fixed b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.fixed index d4a0cdf3447f1..7075aefd50b67 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.fixed +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.fixed @@ -1,7 +1,9 @@ #![warn(clippy::too_long_first_doc_paragraph)] /// A very short summary. +//~^ too_long_first_doc_paragraph /// +//~^ too_long_first_doc_paragraph /// A much longer explanation that goes into a lot more detail about /// how the thing works, possibly with doclinks and so one, /// and probably spanning a many rows. Blablabla, it needs to be over diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.rs b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.rs index 5a3b6c42a328b..844417d741ef8 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.rs +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.rs @@ -1,6 +1,7 @@ #![warn(clippy::too_long_first_doc_paragraph)] /// A very short summary. +//~^ too_long_first_doc_paragraph /// A much longer explanation that goes into a lot more detail about /// how the thing works, possibly with doclinks and so one, /// and probably spanning a many rows. Blablabla, it needs to be over diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr index 84a574017a9b7..bc2fbc2d14df6 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr @@ -2,6 +2,7 @@ error: first doc comment paragraph is too long --> tests/ui/too_long_first_doc_paragraph-fix.rs:3:1 | LL | / /// A very short summary. +LL | | LL | | /// A much longer explanation that goes into a lot more detail about LL | | /// how the thing works, possibly with doclinks and so one, LL | | /// and probably spanning a many rows. Blablabla, it needs to be over @@ -13,7 +14,9 @@ LL | | /// 200 characters so I needed to write something longeeeeeeer. help: add an empty line | LL | /// A very short summary. +LL | LL + /// +LL + | error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs index 7d0a37cde46db..49420841c88c7 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.rs @@ -6,6 +6,7 @@ pub mod foo { // in foo.rs //! A very short summary. + //~^ too_long_first_doc_paragraph //! A much longer explanation that goes into a lot more detail about //! how the thing works, possibly with doclinks and so one, //! and probably spanning a many rows. Blablabla, it needs to be over @@ -13,6 +14,7 @@ pub mod foo { } /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +//~^ too_long_first_doc_paragraph /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, /// gravida non lacinia at, rhoncus eu lacus. pub struct Bar; @@ -34,6 +36,7 @@ pub enum Enum { } /// Lorem +//~^ too_long_first_doc_paragraph /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, /// gravida non lacinia at, rhoncus eu lacus. @@ -58,6 +61,13 @@ pub union Union2 { /// gravida non lacinia at, rhoncus eu lacus. fn f() {} +#[rustfmt::skip] +/// Some function. This doc-string paragraph is too long. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. +//~^ too_long_first_doc_paragraph +/// +/// Here's a second paragraph. It would be preferable to put the details here. +pub fn issue_14274() {} + fn main() { // test code goes here } diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr index 8bc853132ec0b..f3f182aa54222 100644 --- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr +++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr @@ -2,6 +2,7 @@ error: first doc comment paragraph is too long --> tests/ui/too_long_first_doc_paragraph.rs:8:5 | LL | / //! A very short summary. +LL | | LL | | //! A much longer explanation that goes into a lot more detail about LL | | //! how the thing works, possibly with doclinks and so one, LL | | //! and probably spanning a many rows. Blablabla, it needs to be over @@ -13,26 +14,39 @@ LL | | //! 200 characters so I needed to write something longeeeeeeer. help: add an empty line | LL | //! A very short summary. +LL | LL ~ //! +LL + LL ~ //! A much longer explanation that goes into a lot more detail about | error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:15:1 + --> tests/ui/too_long_first_doc_paragraph.rs:16:1 | LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia +LL | | LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_^ error: first doc comment paragraph is too long - --> tests/ui/too_long_first_doc_paragraph.rs:36:1 + --> tests/ui/too_long_first_doc_paragraph.rs:38:1 | LL | / /// Lorem +LL | | LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero, LL | | /// gravida non lacinia at, rhoncus eu lacus. | |_^ -error: aborting due to 3 previous errors +error: first doc comment paragraph is too long + --> tests/ui/too_long_first_doc_paragraph.rs:65:1 + | +LL | / /// Some function. This doc-string paragraph is too long. Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lore... +LL | | +LL | | /// +LL | | /// Here's a second paragraph. It would be preferable to put the details here. + | |_^ + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed index 3eb47a5b5fd65..11d4eaaefda02 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed @@ -12,17 +12,22 @@ fn main() { y(1u8); let _x = &1; + //~^ toplevel_ref_arg let _y: &(&_, u8) = &(&1, 2); + //~^ toplevel_ref_arg let _z = &(1 + 2); + //~^ toplevel_ref_arg let _z = &mut (1 + 2); + //~^ toplevel_ref_arg let (ref x, _) = (1, 2); // ok, not top level println!("The answer is {}.", x); let _x = &vec![1, 2, 3]; + //~^ toplevel_ref_arg // Make sure that allowing the lint works #[allow(clippy::toplevel_ref_arg)] @@ -33,6 +38,7 @@ fn main() { // lint in macro inline!(let _y = &42;); + //~^ toplevel_ref_arg // do not lint in external macro external!(let ref _y = 42;); diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs index cd731387de976..957dd542f5a99 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs @@ -12,17 +12,22 @@ fn main() { y(1u8); let ref _x = 1; + //~^ toplevel_ref_arg let ref _y: (&_, u8) = (&1, 2); + //~^ toplevel_ref_arg let ref _z = 1 + 2; + //~^ toplevel_ref_arg let ref mut _z = 1 + 2; + //~^ toplevel_ref_arg let (ref x, _) = (1, 2); // ok, not top level println!("The answer is {}.", x); let ref _x = vec![1, 2, 3]; + //~^ toplevel_ref_arg // Make sure that allowing the lint works #[allow(clippy::toplevel_ref_arg)] @@ -33,6 +38,7 @@ fn main() { // lint in macro inline!(let ref _y = 42;); + //~^ toplevel_ref_arg // do not lint in external macro external!(let ref _y = 42;); diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr index 61f0fd4a6cd20..42e77f01495be 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.stderr @@ -8,31 +8,31 @@ LL | let ref _x = 1; = help: to override `-D warnings` add `#[allow(clippy::toplevel_ref_arg)]` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> tests/ui/toplevel_ref_arg.rs:16:9 + --> tests/ui/toplevel_ref_arg.rs:17:9 | LL | let ref _y: (&_, u8) = (&1, 2); | ----^^^^^^--------------------- help: try: `let _y: &(&_, u8) = &(&1, 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> tests/ui/toplevel_ref_arg.rs:18:9 + --> tests/ui/toplevel_ref_arg.rs:20:9 | LL | let ref _z = 1 + 2; | ----^^^^^^--------- help: try: `let _z = &(1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> tests/ui/toplevel_ref_arg.rs:20:9 + --> tests/ui/toplevel_ref_arg.rs:23:9 | LL | let ref mut _z = 1 + 2; | ----^^^^^^^^^^--------- help: try: `let _z = &mut (1 + 2);` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> tests/ui/toplevel_ref_arg.rs:25:9 + --> tests/ui/toplevel_ref_arg.rs:29:9 | LL | let ref _x = vec![1, 2, 3]; | ----^^^^^^----------------- help: try: `let _x = &vec![1, 2, 3];` error: `ref` on an entire `let` pattern is discouraged, take a reference with `&` instead - --> tests/ui/toplevel_ref_arg.rs:35:17 + --> tests/ui/toplevel_ref_arg.rs:40:17 | LL | inline!(let ref _y = 42;); | ----^^^^^^------ help: try: `let _y = &42;` diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs index 8aaf47b1bd0c5..87c84a7ee14ab 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -7,6 +7,7 @@ extern crate proc_macros; use proc_macros::{external, inline_macros}; fn the_answer(ref mut x: u8) { + //~^ toplevel_ref_arg *x = 42; } @@ -18,6 +19,7 @@ fn main() { // lint in macro inline! { fn fun_example(ref _x: usize) {} + //~^ toplevel_ref_arg } // do not lint in external macro diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr index 26166e2fc8dac..e17b2536874e0 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.stderr @@ -8,7 +8,7 @@ LL | fn the_answer(ref mut x: u8) { = help: to override `-D warnings` add `#[allow(clippy::toplevel_ref_arg)]` error: `ref` directly on a function parameter does not prevent taking ownership of the passed argument. Consider using a reference type instead - --> tests/ui/toplevel_ref_arg_non_rustfix.rs:20:24 + --> tests/ui/toplevel_ref_arg_non_rustfix.rs:21:24 | LL | fn fun_example(ref _x: usize) {} | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/track-diagnostics.rs b/src/tools/clippy/tests/ui/track-diagnostics.rs index 6ab0bce770e2f..723ea23e9a63b 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics.rs +++ b/src/tools/clippy/tests/ui/track-diagnostics.rs @@ -7,5 +7,6 @@ struct A; struct B; const S: A = B; +//~^ ERROR: mismatched types fn main() {} diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs index ea3b8ff01afa6..a8c3ffdb0dab3 100644 --- a/src/tools/clippy/tests/ui/trailing_empty_array.rs +++ b/src/tools/clippy/tests/ui/trailing_empty_array.rs @@ -4,39 +4,39 @@ // Do lint: struct RarelyUseful { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array field: i32, last: [usize; 0], } struct OnlyField { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array first_and_last: [usize; 0], } struct GenericArrayType { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array field: i32, last: [T; 0], } #[must_use] struct OnlyAnotherAttribute { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array field: i32, last: [usize; 0], } #[derive(Debug)] struct OnlyADeriveAttribute { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array field: i32, last: [usize; 0], } const ZERO: usize = 0; struct ZeroSizedWithConst { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array field: i32, last: [usize; ZERO], } @@ -46,7 +46,7 @@ const fn compute_zero() -> usize { (4 + 6) - (2 * 5) } struct ZeroSizedWithConstFunction { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array field: i32, last: [usize; compute_zero()], } @@ -55,19 +55,19 @@ const fn compute_zero_from_arg(x: usize) -> usize { x - 1 } struct ZeroSizedWithConstFunction2 { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array field: i32, last: [usize; compute_zero_from_arg(1)], } struct ZeroSizedArrayWrapper([usize; 0]); -//~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib +//~^ trailing_empty_array struct TupleStruct(i32, [usize; 0]); -//~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib +//~^ trailing_empty_array struct LotsOfFields { - //~^ ERROR: trailing zero-sized array in a struct which is not marked with a `repr` attrib + //~^ trailing_empty_array f1: u32, f2: u32, f3: u32, diff --git a/src/tools/clippy/tests/ui/trailing_zeros.fixed b/src/tools/clippy/tests/ui/trailing_zeros.fixed index f7de976f1e00e..8c30b062fb183 100644 --- a/src/tools/clippy/tests/ui/trailing_zeros.fixed +++ b/src/tools/clippy/tests/ui/trailing_zeros.fixed @@ -4,10 +4,11 @@ fn main() { let x: i32 = 42; let _ = x.trailing_zeros() >= 4; - //~^ ERROR: bit mask could be simplified with a call to `trailing_zeros` - //~| NOTE: `-D clippy::verbose-bit-mask` implied by `-D warnings` + //~^ verbose_bit_mask + let _ = x.trailing_zeros() >= 5; - //~^ ERROR: bit mask could be simplified with a call to `trailing_zeros` + //~^ verbose_bit_mask + let _ = x & 0b1_1010 == 0; // do not lint let _ = x & 1 == 0; // do not lint } diff --git a/src/tools/clippy/tests/ui/trailing_zeros.rs b/src/tools/clippy/tests/ui/trailing_zeros.rs index a05b09233e212..369a31557392c 100644 --- a/src/tools/clippy/tests/ui/trailing_zeros.rs +++ b/src/tools/clippy/tests/ui/trailing_zeros.rs @@ -4,10 +4,11 @@ fn main() { let x: i32 = 42; let _ = (x & 0b1111 == 0); - //~^ ERROR: bit mask could be simplified with a call to `trailing_zeros` - //~| NOTE: `-D clippy::verbose-bit-mask` implied by `-D warnings` + //~^ verbose_bit_mask + let _ = x & 0b1_1111 == 0; - //~^ ERROR: bit mask could be simplified with a call to `trailing_zeros` + //~^ verbose_bit_mask + let _ = x & 0b1_1010 == 0; // do not lint let _ = x & 1 == 0; // do not lint } diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index 708512793d50a..666ff78b21897 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -5,12 +5,14 @@ use std::any::Any; fn bad_foo(arg0: T, argo1: U) { + //~^ trait_duplication_in_bounds unimplemented!(); } fn bad_bar(arg0: T, arg1: U) where T: Clone + Copy, + //~^ trait_duplication_in_bounds U: Clone + Copy, { unimplemented!(); @@ -39,6 +41,7 @@ trait GoodSelfWhereClause { } trait BadSelfTraitBound: Clone { + //~^ trait_duplication_in_bounds fn f(); } @@ -46,6 +49,7 @@ trait BadSelfWhereClause { fn f() where Self: Clone; + //~^ trait_duplication_in_bounds } trait GoodTraitBound { @@ -60,6 +64,7 @@ trait GoodWhereClause { } trait BadTraitBound { + //~^ trait_duplication_in_bounds fn f(); } @@ -67,6 +72,7 @@ trait BadWhereClause { fn f() where T: Clone + Copy, + //~^ trait_duplication_in_bounds U: Clone + Copy; } @@ -100,6 +106,7 @@ fn good_generic + GenericTrait>(arg0: T) { } fn bad_generic + GenericTrait>(arg0: T) { + //~^ trait_duplication_in_bounds unimplemented!(); } @@ -108,6 +115,7 @@ mod foo { } fn qualified_path(arg0: T) { + //~^ trait_duplication_in_bounds unimplemented!(); } @@ -116,6 +124,7 @@ fn good_trait_object(arg0: &(dyn Any + Send)) { } fn bad_trait_object(arg0: &(dyn Any + Send)) { + //~^ trait_duplication_in_bounds unimplemented!(); } diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index 12db6b65a7aed..a1a86fe058e63 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -5,12 +5,14 @@ use std::any::Any; fn bad_foo(arg0: T, argo1: U) { + //~^ trait_duplication_in_bounds unimplemented!(); } fn bad_bar(arg0: T, arg1: U) where T: Clone + Clone + Clone + Copy, + //~^ trait_duplication_in_bounds U: Clone + Copy, { unimplemented!(); @@ -39,6 +41,7 @@ trait GoodSelfWhereClause { } trait BadSelfTraitBound: Clone + Clone + Clone { + //~^ trait_duplication_in_bounds fn f(); } @@ -46,6 +49,7 @@ trait BadSelfWhereClause { fn f() where Self: Clone + Clone + Clone; + //~^ trait_duplication_in_bounds } trait GoodTraitBound { @@ -60,6 +64,7 @@ trait GoodWhereClause { } trait BadTraitBound { + //~^ trait_duplication_in_bounds fn f(); } @@ -67,6 +72,7 @@ trait BadWhereClause { fn f() where T: Clone + Clone + Clone + Copy, + //~^ trait_duplication_in_bounds U: Clone + Copy; } @@ -100,6 +106,7 @@ fn good_generic + GenericTrait>(arg0: T) { } fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { + //~^ trait_duplication_in_bounds unimplemented!(); } @@ -108,6 +115,7 @@ mod foo { } fn qualified_path(arg0: T) { + //~^ trait_duplication_in_bounds unimplemented!(); } @@ -116,6 +124,7 @@ fn good_trait_object(arg0: &(dyn Any + Send)) { } fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { + //~^ trait_duplication_in_bounds unimplemented!(); } diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index 83c06eaccd4e8..d76b4e458480f 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -11,67 +11,67 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:13:8 + --> tests/ui/trait_duplication_in_bounds.rs:14:8 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:41:26 + --> tests/ui/trait_duplication_in_bounds.rs:43:26 | LL | trait BadSelfTraitBound: Clone + Clone + Clone { | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:48:15 + --> tests/ui/trait_duplication_in_bounds.rs:51:15 | LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:62:24 + --> tests/ui/trait_duplication_in_bounds.rs:66:24 | LL | trait BadTraitBound { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:69:12 + --> tests/ui/trait_duplication_in_bounds.rs:74:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:102:19 + --> tests/ui/trait_duplication_in_bounds.rs:108:19 | LL | fn bad_generic + GenericTrait + GenericTrait>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait + GenericTrait` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:110:22 + --> tests/ui/trait_duplication_in_bounds.rs:117:22 | LL | fn qualified_path(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` error: this trait bound is already specified in trait declaration - --> tests/ui/trait_duplication_in_bounds.rs:118:33 + --> tests/ui/trait_duplication_in_bounds.rs:126:33 | LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` error: these bounds contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:165:36 + --> tests/ui/trait_duplication_in_bounds.rs:174:36 | LL | const fn const_trait_bounds_bad() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `~const ConstTrait` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:172:8 + --> tests/ui/trait_duplication_in_bounds.rs:181:8 | LL | T: IntoIterator + IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `IntoIterator` error: these where clauses contain repeated elements - --> tests/ui/trait_duplication_in_bounds.rs:194:8 + --> tests/ui/trait_duplication_in_bounds.rs:203:8 | LL | T: AssocConstTrait + AssocConstTrait, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `AssocConstTrait` diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs index b0095bb77b5a0..cf72ed844a78c 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.rs @@ -5,8 +5,8 @@ use std::collections::BTreeMap; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign}; fn bad_foo(arg0: T, arg1: Z) -//~^ ERROR: this trait bound is already specified in the where clause -//~| ERROR: this trait bound is already specified in the where clause +//~^ trait_duplication_in_bounds +//~| trait_duplication_in_bounds where T: Clone, T: Default, @@ -36,7 +36,7 @@ trait T: Default { fn f() where Self: Default; - //~^ ERROR: this trait bound is already specified in trait declaration + //~^ trait_duplication_in_bounds } trait U: Default { @@ -51,19 +51,21 @@ trait ZZ: Default { fn f() where Self: Default + Clone; - //~^ ERROR: this trait bound is already specified in trait declaration + //~^ trait_duplication_in_bounds } trait BadTrait: Default + Clone { fn f() where Self: Default + Clone; - //~^ ERROR: this trait bound is already specified in trait declaration - //~| ERROR: this trait bound is already specified in trait declaration + //~^ trait_duplication_in_bounds + //~| trait_duplication_in_bounds + fn g() where Self: Default; - //~^ ERROR: this trait bound is already specified in trait declaration + //~^ trait_duplication_in_bounds + fn h() where Self: Copy; @@ -99,7 +101,7 @@ trait FooIter: Iterator { fn bar() where Self: Iterator, - //~^ ERROR: this trait bound is already specified in trait declaration + //~^ trait_duplication_in_bounds { } } diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr index 41029007a98ee..546d39518e1fa 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds_unfixable.stderr @@ -52,7 +52,7 @@ LL | Self: Default + Clone; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> tests/ui/trait_duplication_in_bounds_unfixable.rs:65:15 + --> tests/ui/trait_duplication_in_bounds_unfixable.rs:66:15 | LL | Self: Default; | ^^^^^^^ @@ -60,7 +60,7 @@ LL | Self: Default; = help: consider removing this trait bound error: this trait bound is already specified in trait declaration - --> tests/ui/trait_duplication_in_bounds_unfixable.rs:101:15 + --> tests/ui/trait_duplication_in_bounds_unfixable.rs:103:15 | LL | Self: Iterator, | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs index 7f5bdea4acf3c..3aecde398dc3f 100644 --- a/src/tools/clippy/tests/ui/transmute.rs +++ b/src/tools/clippy/tests/ui/transmute.rs @@ -29,41 +29,40 @@ unsafe fn _generic<'a, T, U: 'a>(t: &'a T) { let _: &'a U = core::mem::transmute(t); let _: *const T = core::mem::transmute(t); - //~^ ERROR: transmute from a reference to a pointer - //~| NOTE: `-D clippy::useless-transmute` implied by `-D warnings` + //~^ useless_transmute let _: *mut T = core::mem::transmute(t); - //~^ ERROR: transmute from a reference to a pointer + //~^ useless_transmute let _: *const U = core::mem::transmute(t); - //~^ ERROR: transmute from a reference to a pointer + //~^ useless_transmute } #[warn(clippy::useless_transmute)] fn useless() { unsafe { let _: Vec = core::mem::transmute(my_vec()); - //~^ ERROR: transmute from a type (`std::vec::Vec`) to itself + //~^ useless_transmute let _: Vec = core::mem::transmute(my_vec()); - //~^ ERROR: transmute from a type (`std::vec::Vec`) to itself + //~^ useless_transmute let _: Vec = std::mem::transmute(my_vec()); - //~^ ERROR: transmute from a type (`std::vec::Vec`) to itself + //~^ useless_transmute let _: Vec = std::mem::transmute(my_vec()); - //~^ ERROR: transmute from a type (`std::vec::Vec`) to itself + //~^ useless_transmute let _: Vec = my_transmute(my_vec()); - //~^ ERROR: transmute from a type (`std::vec::Vec`) to itself + //~^ useless_transmute let _: *const usize = std::mem::transmute(5_isize); - //~^ ERROR: transmute from an integer to a pointer + //~^ useless_transmute let _ = 5_isize as *const usize; let _: *const usize = std::mem::transmute(1 + 1usize); - //~^ ERROR: transmute from an integer to a pointer + //~^ useless_transmute let _ = (1 + 1_usize) as *const usize; } @@ -95,77 +94,84 @@ fn crosspointer() { unsafe { let _: Usize = core::mem::transmute(int_const_ptr); - //~^ ERROR: transmute from a type (`*const Usize`) to the type that it points to ( - //~| NOTE: `-D clippy::crosspointer-transmute` implied by `-D warnings` + //~^ crosspointer_transmute let _: Usize = core::mem::transmute(int_mut_ptr); - //~^ ERROR: transmute from a type (`*mut Usize`) to the type that it points to (`U + //~^ crosspointer_transmute let _: *const Usize = core::mem::transmute(my_int()); - //~^ ERROR: transmute from a type (`Usize`) to a pointer to that type (`*const Usi + //~^ crosspointer_transmute let _: *mut Usize = core::mem::transmute(my_int()); - //~^ ERROR: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize + //~^ crosspointer_transmute } } #[warn(clippy::transmute_int_to_bool)] fn int_to_bool() { let _: bool = unsafe { std::mem::transmute(0_u8) }; - //~^ ERROR: transmute from a `u8` to a `bool` - //~| NOTE: `-D clippy::transmute-int-to-bool` implied by `-D warnings` + //~^ transmute_int_to_bool } #[warn(clippy::transmute_int_to_float)] mod int_to_float { fn test() { let _: f16 = unsafe { std::mem::transmute(0_u16) }; - //~^ ERROR: transmute from a `u16` to a `f16` - //~| NOTE: `-D clippy::transmute-int-to-float` implied by `-D warnings` + //~^ transmute_int_to_float + let _: f16 = unsafe { std::mem::transmute(0_i16) }; - //~^ ERROR: transmute from a `i16` to a `f16` + //~^ transmute_int_to_float + let _: f32 = unsafe { std::mem::transmute(0_u32) }; - //~^ ERROR: transmute from a `u32` to a `f32` + //~^ transmute_int_to_float + let _: f32 = unsafe { std::mem::transmute(0_i32) }; - //~^ ERROR: transmute from a `i32` to a `f32` + //~^ transmute_int_to_float + let _: f64 = unsafe { std::mem::transmute(0_u64) }; - //~^ ERROR: transmute from a `u64` to a `f64` + //~^ transmute_int_to_float + let _: f64 = unsafe { std::mem::transmute(0_i64) }; - //~^ ERROR: transmute from a `i64` to a `f64` + //~^ transmute_int_to_float + let _: f128 = unsafe { std::mem::transmute(0_u128) }; - //~^ ERROR: transmute from a `u128` to a `f128` + //~^ transmute_int_to_float + let _: f128 = unsafe { std::mem::transmute(0_i128) }; - //~^ ERROR: transmute from a `i128` to a `f128` + //~^ transmute_int_to_float } mod issue_5747 { const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; - //~^ ERROR: transmute from a `u16` to a `f16` + //~^ transmute_int_to_float + const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; - //~^ ERROR: transmute from a `u32` to a `f32` + //~^ transmute_int_to_float + const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; - //~^ ERROR: transmute from a `i64` to a `f64` + //~^ transmute_int_to_float + const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; - //~^ ERROR: transmute from a `i128` to a `f128` + //~^ transmute_int_to_float const fn from_bits_16(v: i16) -> f16 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `i16` to a `f16` + //~^ transmute_int_to_float } const fn from_bits_32(v: i32) -> f32 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `i32` to a `f32` + //~^ transmute_int_to_float } const fn from_bits_64(v: u64) -> f64 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `u64` to a `f64` + //~^ transmute_int_to_float } const fn from_bits_128(v: u128) -> f128 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `u128` to a `f128` + //~^ transmute_int_to_float } } } @@ -174,52 +180,67 @@ mod num_to_bytes { fn test() { unsafe { let _: [u8; 1] = std::mem::transmute(0u8); - //~^ ERROR: transmute from a `u8` to a `[u8; 1]` - //~| NOTE: `-D clippy::transmute-num-to-bytes` implied by `-D warnings` + //~^ transmute_num_to_bytes + let _: [u8; 4] = std::mem::transmute(0u32); - //~^ ERROR: transmute from a `u32` to a `[u8; 4]` + //~^ transmute_num_to_bytes + let _: [u8; 16] = std::mem::transmute(0u128); - //~^ ERROR: transmute from a `u128` to a `[u8; 16]` + //~^ transmute_num_to_bytes + let _: [u8; 1] = std::mem::transmute(0i8); - //~^ ERROR: transmute from a `i8` to a `[u8; 1]` + //~^ transmute_num_to_bytes + let _: [u8; 4] = std::mem::transmute(0i32); - //~^ ERROR: transmute from a `i32` to a `[u8; 4]` + //~^ transmute_num_to_bytes + let _: [u8; 16] = std::mem::transmute(0i128); - //~^ ERROR: transmute from a `i128` to a `[u8; 16]` + //~^ transmute_num_to_bytes let _: [u8; 2] = std::mem::transmute(0.0f16); - //~^ ERROR: transmute from a `f16` to a `[u8; 2]` + //~^ transmute_num_to_bytes + let _: [u8; 4] = std::mem::transmute(0.0f32); - //~^ ERROR: transmute from a `f32` to a `[u8; 4]` + //~^ transmute_num_to_bytes + let _: [u8; 8] = std::mem::transmute(0.0f64); - //~^ ERROR: transmute from a `f64` to a `[u8; 8]` + //~^ transmute_num_to_bytes + let _: [u8; 16] = std::mem::transmute(0.0f128); - //~^ ERROR: transmute from a `f128` to a `[u8; 16]` + //~^ transmute_num_to_bytes } } const fn test_const() { unsafe { let _: [u8; 1] = std::mem::transmute(0u8); - //~^ ERROR: transmute from a `u8` to a `[u8; 1]` + //~^ transmute_num_to_bytes + let _: [u8; 4] = std::mem::transmute(0u32); - //~^ ERROR: transmute from a `u32` to a `[u8; 4]` + //~^ transmute_num_to_bytes + let _: [u8; 16] = std::mem::transmute(0u128); - //~^ ERROR: transmute from a `u128` to a `[u8; 16]` + //~^ transmute_num_to_bytes + let _: [u8; 1] = std::mem::transmute(0i8); - //~^ ERROR: transmute from a `i8` to a `[u8; 1]` + //~^ transmute_num_to_bytes + let _: [u8; 4] = std::mem::transmute(0i32); - //~^ ERROR: transmute from a `i32` to a `[u8; 4]` + //~^ transmute_num_to_bytes + let _: [u8; 16] = std::mem::transmute(0i128); - //~^ ERROR: transmute from a `i128` to a `[u8; 16]` + //~^ transmute_num_to_bytes let _: [u8; 2] = std::mem::transmute(0.0f16); - //~^ ERROR: transmute from a `f16` to a `[u8; 2]` + //~^ transmute_num_to_bytes + let _: [u8; 4] = std::mem::transmute(0.0f32); - //~^ ERROR: transmute from a `f32` to a `[u8; 4]` + //~^ transmute_num_to_bytes + let _: [u8; 8] = std::mem::transmute(0.0f64); - //~^ ERROR: transmute from a `f64` to a `[u8; 8]` + //~^ transmute_num_to_bytes + let _: [u8; 16] = std::mem::transmute(0.0f128); - //~^ ERROR: transmute from a `f128` to a `[u8; 16]` + //~^ transmute_num_to_bytes } } } @@ -228,12 +249,13 @@ fn bytes_to_str(mb: &mut [u8]) { const B: &[u8] = b""; let _: &str = unsafe { std::mem::transmute(B) }; - //~^ ERROR: transmute from a `&[u8]` to a `&str` - //~| NOTE: `-D clippy::transmute-bytes-to-str` implied by `-D warnings` + //~^ transmute_bytes_to_str + let _: &mut str = unsafe { std::mem::transmute(mb) }; - //~^ ERROR: transmute from a `&mut [u8]` to a `&mut str` + //~^ transmute_bytes_to_str + const _: &str = unsafe { std::mem::transmute(B) }; - //~^ ERROR: transmute from a `&[u8]` to a `&str` + //~^ transmute_bytes_to_str } fn main() {} diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr index b5032772856ee..e0d28437aafc8 100644 --- a/src/tools/clippy/tests/ui/transmute.stderr +++ b/src/tools/clippy/tests/ui/transmute.stderr @@ -8,61 +8,61 @@ LL | let _: *const T = core::mem::transmute(t); = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:35:21 + --> tests/ui/transmute.rs:34:21 | LL | let _: *mut T = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T` error: transmute from a reference to a pointer - --> tests/ui/transmute.rs:38:23 + --> tests/ui/transmute.rs:37:23 | LL | let _: *const U = core::mem::transmute(t); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U` error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:45:27 + --> tests/ui/transmute.rs:44:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:48:27 + --> tests/ui/transmute.rs:47:27 | LL | let _: Vec = core::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:51:27 + --> tests/ui/transmute.rs:50:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:54:27 + --> tests/ui/transmute.rs:53:27 | LL | let _: Vec = std::mem::transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`std::vec::Vec`) to itself - --> tests/ui/transmute.rs:57:27 + --> tests/ui/transmute.rs:56:27 | LL | let _: Vec = my_transmute(my_vec()); | ^^^^^^^^^^^^^^^^^^^^^^ error: transmute from an integer to a pointer - --> tests/ui/transmute.rs:60:31 + --> tests/ui/transmute.rs:59: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:65:31 + --> tests/ui/transmute.rs:64: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:97:24 + --> tests/ui/transmute.rs:96:24 | LL | let _: Usize = core::mem::transmute(int_const_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,25 +71,25 @@ LL | let _: Usize = core::mem::transmute(int_const_ptr); = help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]` error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`) - --> tests/ui/transmute.rs:101:24 + --> tests/ui/transmute.rs:99:24 | LL | let _: Usize = core::mem::transmute(int_mut_ptr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`) - --> tests/ui/transmute.rs:104:31 + --> tests/ui/transmute.rs:102:31 | LL | let _: *const Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`) - --> tests/ui/transmute.rs:107:29 + --> tests/ui/transmute.rs:105:29 | LL | let _: *mut Usize = core::mem::transmute(my_int()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a `u8` to a `bool` - --> tests/ui/transmute.rs:114: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 `u16` to a `f16` - --> tests/ui/transmute.rs:122:31 + --> tests/ui/transmute.rs:119:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` @@ -107,19 +107,19 @@ LL | let _: f16 = unsafe { std::mem::transmute(0_u16) }; = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:125:31 + --> tests/ui/transmute.rs:122:31 | LL | let _: f16 = unsafe { std::mem::transmute(0_i16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:127:31 + --> tests/ui/transmute.rs:125:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:129:31 + --> tests/ui/transmute.rs:128:31 | LL | let _: f32 = unsafe { std::mem::transmute(0_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)` @@ -131,73 +131,73 @@ 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:133:31 + --> tests/ui/transmute.rs:134:31 | LL | let _: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:135:32 + --> tests/ui/transmute.rs:137:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_u128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:137:32 + --> tests/ui/transmute.rs:140:32 | LL | let _: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `u16` to a `f16` - --> tests/ui/transmute.rs:142:39 + --> tests/ui/transmute.rs:145:39 | LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)` error: transmute from a `u32` to a `f32` - --> tests/ui/transmute.rs:144:39 + --> tests/ui/transmute.rs:148:39 | LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)` error: transmute from a `i64` to a `f64` - --> tests/ui/transmute.rs:146:39 + --> tests/ui/transmute.rs:151:39 | LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)` error: transmute from a `i128` to a `f128` - --> tests/ui/transmute.rs:148:41 + --> tests/ui/transmute.rs:154:41 | LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)` error: transmute from a `i16` to a `f16` - --> tests/ui/transmute.rs:152:22 + --> tests/ui/transmute.rs:158:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)` error: transmute from a `i32` to a `f32` - --> tests/ui/transmute.rs:157:22 + --> tests/ui/transmute.rs:163:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)` error: transmute from a `u64` to a `f64` - --> tests/ui/transmute.rs:162:22 + --> tests/ui/transmute.rs:168:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)` error: transmute from a `u128` to a `f128` - --> tests/ui/transmute.rs:167:22 + --> tests/ui/transmute.rs:173:22 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:176:30 + --> tests/ui/transmute.rs:182:30 | LL | let _: [u8; 1] = std::mem::transmute(0u8); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()` @@ -206,121 +206,121 @@ 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:179:30 + --> tests/ui/transmute.rs:185: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:181:31 + --> tests/ui/transmute.rs:188: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:183:30 + --> tests/ui/transmute.rs:191: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:185:30 + --> tests/ui/transmute.rs:194: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:187:31 + --> tests/ui/transmute.rs:197:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:190:30 + --> tests/ui/transmute.rs:200:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:192:30 + --> tests/ui/transmute.rs:203: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:194:30 + --> tests/ui/transmute.rs:206: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 `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:196:31 + --> tests/ui/transmute.rs:209:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `u8` to a `[u8; 1]` - --> tests/ui/transmute.rs:202:30 + --> tests/ui/transmute.rs:215: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:204:30 + --> tests/ui/transmute.rs:218: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:206:31 + --> tests/ui/transmute.rs:221: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:208:30 + --> tests/ui/transmute.rs:224: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:210:30 + --> tests/ui/transmute.rs:227: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:212:31 + --> tests/ui/transmute.rs:230:31 | LL | let _: [u8; 16] = std::mem::transmute(0i128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()` error: transmute from a `f16` to a `[u8; 2]` - --> tests/ui/transmute.rs:215:30 + --> tests/ui/transmute.rs:233:30 | LL | let _: [u8; 2] = std::mem::transmute(0.0f16); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()` error: transmute from a `f32` to a `[u8; 4]` - --> tests/ui/transmute.rs:217:30 + --> tests/ui/transmute.rs:236: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:219:30 + --> tests/ui/transmute.rs:239: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 `f128` to a `[u8; 16]` - --> tests/ui/transmute.rs:221:31 + --> tests/ui/transmute.rs:242:31 | LL | let _: [u8; 16] = std::mem::transmute(0.0f128); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()` error: transmute from a `&[u8]` to a `&str` - --> tests/ui/transmute.rs:230:28 + --> tests/ui/transmute.rs:251:28 | LL | let _: &str = unsafe { std::mem::transmute(B) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()` @@ -329,13 +329,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:233:32 + --> tests/ui/transmute.rs:254: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:235:30 + --> tests/ui/transmute.rs:257: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_32bit.rs b/src/tools/clippy/tests/ui/transmute_32bit.rs index e162bbb2d9296..997f43ab12b5c 100644 --- a/src/tools/clippy/tests/ui/transmute_32bit.rs +++ b/src/tools/clippy/tests/ui/transmute_32bit.rs @@ -3,12 +3,12 @@ #[warn(clippy::wrong_transmute)] fn main() { unsafe { - let _: *const usize = std::mem::transmute(6.0f32); + let _: *const usize = std::mem::transmute(6.0f32); //~ wrong_transmute - let _: *mut usize = std::mem::transmute(6.0f32); + let _: *mut usize = std::mem::transmute(6.0f32); //~ wrong_transmute - let _: *const usize = std::mem::transmute('x'); + let _: *const usize = std::mem::transmute('x'); //~ wrong_transmute - let _: *mut usize = std::mem::transmute('x'); + let _: *mut usize = std::mem::transmute('x'); //~ wrong_transmute } } diff --git a/src/tools/clippy/tests/ui/transmute_64bit.rs b/src/tools/clippy/tests/ui/transmute_64bit.rs index fd0ad74bcfa0a..1a4bfffdc3226 100644 --- a/src/tools/clippy/tests/ui/transmute_64bit.rs +++ b/src/tools/clippy/tests/ui/transmute_64bit.rs @@ -4,10 +4,9 @@ fn main() { unsafe { let _: *const usize = std::mem::transmute(6.0f64); - //~^ ERROR: transmute from a `f64` to a pointer - //~| NOTE: `-D clippy::wrong-transmute` implied by `-D warnings` + //~^ wrong_transmute let _: *mut usize = std::mem::transmute(6.0f64); - //~^ ERROR: transmute from a `f64` to a pointer + //~^ wrong_transmute } } diff --git a/src/tools/clippy/tests/ui/transmute_64bit.stderr b/src/tools/clippy/tests/ui/transmute_64bit.stderr index 65fff17f59fa9..e75b81671e093 100644 --- a/src/tools/clippy/tests/ui/transmute_64bit.stderr +++ b/src/tools/clippy/tests/ui/transmute_64bit.stderr @@ -8,7 +8,7 @@ LL | let _: *const usize = std::mem::transmute(6.0f64); = help: to override `-D warnings` add `#[allow(clippy::wrong_transmute)]` error: transmute from a `f64` to a pointer - --> tests/ui/transmute_64bit.rs:10:29 + --> tests/ui/transmute_64bit.rs:9:29 | LL | let _: *mut usize = std::mem::transmute(6.0f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/transmute_collection.rs b/src/tools/clippy/tests/ui/transmute_collection.rs index 6748b66e0eb6c..74d7f5e38bf8d 100644 --- a/src/tools/clippy/tests/ui/transmute_collection.rs +++ b/src/tools/clippy/tests/ui/transmute_collection.rs @@ -8,61 +8,71 @@ fn main() { unsafe { // wrong size let _ = transmute::<_, Vec>(vec![0u8]); - //~^ ERROR: transmute from `std::vec::Vec` to `std::vec::Vec` with mismat - //~| NOTE: `-D clippy::unsound-collection-transmute` implied by `-D warnings` + //~^ unsound_collection_transmute + // wrong layout let _ = transmute::<_, Vec<[u8; 4]>>(vec![1234u32]); - //~^ ERROR: transmute from `std::vec::Vec` to `std::vec::Vec<[u8; 4]>` with m + //~^ unsound_collection_transmute // wrong size let _ = transmute::<_, VecDeque>(VecDeque::::new()); - //~^ ERROR: transmute from `std::collections::VecDeque` to `std::collections:: + //~^ unsound_collection_transmute + // wrong layout let _ = transmute::<_, VecDeque>(VecDeque::<[u8; 4]>::new()); - //~^ ERROR: transmute from `std::collections::VecDeque<[u8; 4]>` to `std::collecti + //~^ unsound_collection_transmute // wrong size let _ = transmute::<_, BinaryHeap>(BinaryHeap::::new()); - //~^ ERROR: transmute from `std::collections::BinaryHeap` to `std::collections + //~^ unsound_collection_transmute + // wrong layout let _ = transmute::<_, BinaryHeap>(BinaryHeap::<[u8; 4]>::new()); - //~^ ERROR: transmute from `std::collections::BinaryHeap<[u8; 4]>` to `std::collec + //~^ unsound_collection_transmute // wrong size let _ = transmute::<_, BTreeSet>(BTreeSet::::new()); - //~^ ERROR: transmute from `std::collections::BTreeSet` to `std::collections:: + //~^ unsound_collection_transmute + // wrong layout let _ = transmute::<_, BTreeSet>(BTreeSet::<[u8; 4]>::new()); - //~^ ERROR: transmute from `std::collections::BTreeSet<[u8; 4]>` to `std::collecti + //~^ unsound_collection_transmute // wrong size let _ = transmute::<_, HashSet>(HashSet::::new()); - //~^ ERROR: transmute from `std::collections::HashSet` to `std::collections::H + //~^ unsound_collection_transmute + // wrong layout let _ = transmute::<_, HashSet>(HashSet::<[u8; 4]>::new()); - //~^ ERROR: transmute from `std::collections::HashSet<[u8; 4]>` to `std::collectio + //~^ unsound_collection_transmute // wrong size let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); - //~^ ERROR: transmute from `std::collections::BTreeMap` to `std::collectio + //~^ unsound_collection_transmute + let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); - //~^ ERROR: transmute from `std::collections::BTreeMap` to `std::collect + //~^ unsound_collection_transmute + // wrong layout let _ = transmute::<_, BTreeMap>(BTreeMap::::new()); - //~^ ERROR: transmute from `std::collections::BTreeMap` to `std::coll + //~^ unsound_collection_transmute + let _ = transmute::<_, BTreeMap>(BTreeMap::<[u8; 4], u32>::new()); - //~^ ERROR: transmute from `std::collections::BTreeMap<[u8; 4], u32>` to `std::col + //~^ unsound_collection_transmute // wrong size let _ = transmute::<_, HashMap>(HashMap::::new()); - //~^ ERROR: transmute from `std::collections::HashMap` to `std::collection + //~^ unsound_collection_transmute + let _ = transmute::<_, HashMap>(HashMap::::new()); - //~^ ERROR: transmute from `std::collections::HashMap` to `std::collecti + //~^ unsound_collection_transmute + // wrong layout let _ = transmute::<_, HashMap>(HashMap::::new()); - //~^ ERROR: transmute from `std::collections::HashMap` to `std::colle + //~^ unsound_collection_transmute + let _ = transmute::<_, HashMap>(HashMap::<[u8; 4], u32>::new()); - //~^ ERROR: transmute from `std::collections::HashMap<[u8; 4], u32>` to `std::coll + //~^ unsound_collection_transmute let _ = transmute::<_, Vec>(Vec::>::new()); let _ = transmute::<_, Vec<*mut u32>>(Vec::>::new()); diff --git a/src/tools/clippy/tests/ui/transmute_collection.stderr b/src/tools/clippy/tests/ui/transmute_collection.stderr index 06db9321064b4..ac2de07f6bf27 100644 --- a/src/tools/clippy/tests/ui/transmute_collection.stderr +++ b/src/tools/clippy/tests/ui/transmute_collection.stderr @@ -20,91 +20,91 @@ 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:21:17 + --> tests/ui/transmute_collection.rs:22: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:25:17 + --> tests/ui/transmute_collection.rs:26: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:28:17 + --> tests/ui/transmute_collection.rs:30: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:32:17 + --> tests/ui/transmute_collection.rs:34: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:35:17 + --> tests/ui/transmute_collection.rs:38: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:39:17 + --> tests/ui/transmute_collection.rs:42: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:42:17 + --> tests/ui/transmute_collection.rs:46: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:46:17 + --> tests/ui/transmute_collection.rs:50: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:48:17 + --> tests/ui/transmute_collection.rs:53: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:51:17 + --> tests/ui/transmute_collection.rs:57: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:53:17 + --> tests/ui/transmute_collection.rs:60: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:57:17 + --> tests/ui/transmute_collection.rs:64: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:59:17 + --> tests/ui/transmute_collection.rs:67: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:62:17 + --> tests/ui/transmute_collection.rs:71: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:64:17 + --> tests/ui/transmute_collection.rs:74: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 075a198918a0d..1f97b997eaa0e 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.fixed +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.fixed @@ -5,48 +5,55 @@ fn float_to_int() { let _: u32 = unsafe { 1f32.to_bits() }; - //~^ ERROR: transmute from a `f32` to a `u32` - //~| NOTE: `-D clippy::transmute-float-to-int` implied by `-D warnings` + //~^ transmute_float_to_int + let _: i32 = unsafe { 1f32.to_bits() as i32 }; - //~^ ERROR: transmute from a `f32` to a `i32` + //~^ transmute_float_to_int + let _: u64 = unsafe { 1f64.to_bits() }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int + let _: i64 = unsafe { 1f64.to_bits() as i64 }; - //~^ ERROR: transmute from a `f64` to a `i64` + //~^ transmute_float_to_int + let _: u64 = unsafe { 1.0f64.to_bits() }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int + let _: u64 = unsafe { (-1.0f64).to_bits() }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int } mod issue_5747 { const VALUE16: i16 = unsafe { 1f16.to_bits() as i16 }; - //~^ ERROR: transmute from a `f16` to a `i16` + //~^ transmute_float_to_int + const VALUE32: i32 = unsafe { 1f32.to_bits() as i32 }; - //~^ ERROR: transmute from a `f32` to a `i32` + //~^ transmute_float_to_int + const VALUE64: u64 = unsafe { 1f64.to_bits() }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int + const VALUE128: u128 = unsafe { 1f128.to_bits() }; - //~^ ERROR: transmute from a `f128` to a `u128` + //~^ transmute_float_to_int const fn to_bits_16(v: f16) -> u16 { unsafe { v.to_bits() } - //~^ ERROR: transmute from a `f16` to a `u16` + //~^ transmute_float_to_int } const fn to_bits_32(v: f32) -> u32 { unsafe { v.to_bits() } - //~^ ERROR: transmute from a `f32` to a `u32` + //~^ transmute_float_to_int } const fn to_bits_64(v: f64) -> i64 { unsafe { v.to_bits() as i64 } - //~^ ERROR: transmute from a `f64` to a `i64` + //~^ transmute_float_to_int } const fn to_bits_128(v: f128) -> i128 { unsafe { v.to_bits() as i128 } - //~^ ERROR: transmute from a `f128` to a `i128` + //~^ transmute_float_to_int } } 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 12541b2f7cf32..788a7e1026c67 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.rs +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.rs @@ -5,48 +5,55 @@ fn float_to_int() { let _: u32 = unsafe { std::mem::transmute(1f32) }; - //~^ ERROR: transmute from a `f32` to a `u32` - //~| NOTE: `-D clippy::transmute-float-to-int` implied by `-D warnings` + //~^ transmute_float_to_int + let _: i32 = unsafe { std::mem::transmute(1f32) }; - //~^ ERROR: transmute from a `f32` to a `i32` + //~^ transmute_float_to_int + let _: u64 = unsafe { std::mem::transmute(1f64) }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int + let _: i64 = unsafe { std::mem::transmute(1f64) }; - //~^ ERROR: transmute from a `f64` to a `i64` + //~^ transmute_float_to_int + let _: u64 = unsafe { std::mem::transmute(1.0) }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int + let _: u64 = unsafe { std::mem::transmute(-1.0) }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int } mod issue_5747 { const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; - //~^ ERROR: transmute from a `f16` to a `i16` + //~^ transmute_float_to_int + const VALUE32: i32 = unsafe { std::mem::transmute(1f32) }; - //~^ ERROR: transmute from a `f32` to a `i32` + //~^ transmute_float_to_int + const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; - //~^ ERROR: transmute from a `f64` to a `u64` + //~^ transmute_float_to_int + const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; - //~^ ERROR: transmute from a `f128` to a `u128` + //~^ transmute_float_to_int const fn to_bits_16(v: f16) -> u16 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `f16` to a `u16` + //~^ transmute_float_to_int } const fn to_bits_32(v: f32) -> u32 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `f32` to a `u32` + //~^ transmute_float_to_int } const fn to_bits_64(v: f64) -> i64 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `f64` to a `i64` + //~^ transmute_float_to_int } const fn to_bits_128(v: f128) -> i128 { unsafe { std::mem::transmute(v) } - //~^ ERROR: transmute from a `f128` to a `i128` + //~^ transmute_float_to_int } } 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 0cabab58ab08c..223cbc4e90c07 100644 --- a/src/tools/clippy/tests/ui/transmute_float_to_int.stderr +++ b/src/tools/clippy/tests/ui/transmute_float_to_int.stderr @@ -14,73 +14,73 @@ 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:12:27 + --> tests/ui/transmute_float_to_int.rs:13: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:14:27 + --> tests/ui/transmute_float_to_int.rs:16: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:16:27 + --> tests/ui/transmute_float_to_int.rs:19: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:18:27 + --> tests/ui/transmute_float_to_int.rs:22:27 | LL | let _: u64 = unsafe { std::mem::transmute(-1.0) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-1.0f64).to_bits()` error: transmute from a `f16` to a `i16` - --> tests/ui/transmute_float_to_int.rs:23:35 + --> tests/ui/transmute_float_to_int.rs:27:35 | LL | const VALUE16: i16 = unsafe { std::mem::transmute(1f16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f16.to_bits() as i16` error: transmute from a `f32` to a `i32` - --> tests/ui/transmute_float_to_int.rs:25:35 + --> tests/ui/transmute_float_to_int.rs:30:35 | LL | const VALUE32: 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:27:35 + --> tests/ui/transmute_float_to_int.rs:33:35 | LL | const VALUE64: u64 = unsafe { std::mem::transmute(1f64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f64.to_bits()` error: transmute from a `f128` to a `u128` - --> tests/ui/transmute_float_to_int.rs:29:37 + --> tests/ui/transmute_float_to_int.rs:36:37 | LL | const VALUE128: u128 = unsafe { std::mem::transmute(1f128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `1f128.to_bits()` error: transmute from a `f16` to a `u16` - --> tests/ui/transmute_float_to_int.rs:33:18 + --> tests/ui/transmute_float_to_int.rs:40:18 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` error: transmute from a `f32` to a `u32` - --> tests/ui/transmute_float_to_int.rs:38:18 + --> tests/ui/transmute_float_to_int.rs:45:18 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits()` error: transmute from a `f64` to a `i64` - --> tests/ui/transmute_float_to_int.rs:43:18 + --> tests/ui/transmute_float_to_int.rs:50:18 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i64` error: transmute from a `f128` to a `i128` - --> tests/ui/transmute_float_to_int.rs:48:18 + --> tests/ui/transmute_float_to_int.rs:55:18 | LL | unsafe { std::mem::transmute(v) } | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `v.to_bits() as i128` 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 d3277d1b8c732..b5425a2e9e854 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char.fixed +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.fixed @@ -3,10 +3,10 @@ fn int_to_char() { let _: char = unsafe { std::char::from_u32(0_u32).unwrap() }; - //~^ ERROR: transmute from a `u32` to a `char` - //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + //~^ transmute_int_to_char + let _: char = unsafe { std::char::from_u32(0_i32 as u32).unwrap() }; - //~^ ERROR: transmute from a `i32` to a `char` + //~^ transmute_int_to_char // These shouldn't warn const _: char = unsafe { std::mem::transmute(0_u32) }; 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 d21c4fd6fea34..b24bb177c9fc0 100644 --- a/src/tools/clippy/tests/ui/transmute_int_to_char.rs +++ b/src/tools/clippy/tests/ui/transmute_int_to_char.rs @@ -3,10 +3,10 @@ fn int_to_char() { let _: char = unsafe { std::mem::transmute(0_u32) }; - //~^ ERROR: transmute from a `u32` to a `char` - //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + //~^ transmute_int_to_char + let _: char = unsafe { std::mem::transmute(0_i32) }; - //~^ ERROR: transmute from a `i32` to a `char` + //~^ transmute_int_to_char // These shouldn't warn const _: char = unsafe { std::mem::transmute(0_u32) }; 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 32a57645b46f1..e525751e306ea 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 @@ -15,10 +15,10 @@ fn panic(info: &PanicInfo) -> ! { fn int_to_char() { let _: char = unsafe { core::char::from_u32(0_u32).unwrap() }; - //~^ ERROR: transmute from a `u32` to a `char` - //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + //~^ transmute_int_to_char + let _: char = unsafe { core::char::from_u32(0_i32 as u32).unwrap() }; - //~^ ERROR: transmute from a `i32` to a `char` + //~^ transmute_int_to_char // These shouldn't warn const _: char = unsafe { core::mem::transmute(0_u32) }; 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 942794c32f810..7cb508ceaf3bc 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 @@ -15,10 +15,10 @@ fn panic(info: &PanicInfo) -> ! { fn int_to_char() { let _: char = unsafe { core::mem::transmute(0_u32) }; - //~^ ERROR: transmute from a `u32` to a `char` - //~| NOTE: `-D clippy::transmute-int-to-char` implied by `-D warnings` + //~^ transmute_int_to_char + let _: char = unsafe { core::mem::transmute(0_i32) }; - //~^ ERROR: transmute from a `i32` to a `char` + //~^ transmute_int_to_char // These shouldn't warn const _: char = unsafe { core::mem::transmute(0_u32) }; 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 1a48051ec8c4d..273090fef3876 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 @@ -17,27 +17,34 @@ fn main() { let int_i128: i128 = 1; let _: NonZero = unsafe { NonZero::new_unchecked(int_u8) }; - //~^ ERROR: transmute from a `u8` to a `NonZero` - //~| NOTE: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_u16) }; - //~^ ERROR: transmute from a `u16` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_u32) }; - //~^ ERROR: transmute from a `u32` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_u64) }; - //~^ ERROR: transmute from a `u64` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_u128) }; - //~^ ERROR: transmute from a `u128` to a `NonZero` + //~^ transmute_int_to_non_zero let _: NonZero = unsafe { NonZero::new_unchecked(int_i8) }; - //~^ ERROR: transmute from a `i8` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_i16) }; - //~^ ERROR: transmute from a `i16` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_i32) }; - //~^ ERROR: transmute from a `i32` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_i64) }; - //~^ ERROR: transmute from a `i64` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { NonZero::new_unchecked(int_i128) }; - //~^ ERROR: transmute from a `i128` to a `NonZero` + //~^ transmute_int_to_non_zero let _: NonZero = unsafe { NonZero::new_unchecked(int_u8) }; let _: NonZero = unsafe { NonZero::new_unchecked(int_u16) }; 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 d8e842fb99ceb..f27bc9b42d426 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 @@ -17,27 +17,34 @@ fn main() { let int_i128: i128 = 1; let _: NonZero = unsafe { std::mem::transmute(int_u8) }; - //~^ ERROR: transmute from a `u8` to a `NonZero` - //~| NOTE: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_u16) }; - //~^ ERROR: transmute from a `u16` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_u32) }; - //~^ ERROR: transmute from a `u32` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_u64) }; - //~^ ERROR: transmute from a `u64` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_u128) }; - //~^ ERROR: transmute from a `u128` to a `NonZero` + //~^ transmute_int_to_non_zero let _: NonZero = unsafe { std::mem::transmute(int_i8) }; - //~^ ERROR: transmute from a `i8` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_i16) }; - //~^ ERROR: transmute from a `i16` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_i32) }; - //~^ ERROR: transmute from a `i32` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_i64) }; - //~^ ERROR: transmute from a `i64` to a `NonZero` + //~^ transmute_int_to_non_zero + let _: NonZero = unsafe { std::mem::transmute(int_i128) }; - //~^ ERROR: transmute from a `i128` to a `NonZero` + //~^ transmute_int_to_non_zero let _: NonZero = unsafe { NonZero::new_unchecked(int_u8) }; let _: NonZero = unsafe { NonZero::new_unchecked(int_u16) }; 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 199b8ec59d092..995ab11a5bc96 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 @@ -14,49 +14,49 @@ LL | let _: NonZero = unsafe { std::mem::transmute(int_u16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u16)` error: transmute from a `u32` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:24:36 + --> tests/ui/transmute_int_to_non_zero.rs:25:36 | LL | let _: NonZero = unsafe { std::mem::transmute(int_u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u32)` error: transmute from a `u64` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:26:36 + --> tests/ui/transmute_int_to_non_zero.rs:28:36 | LL | let _: NonZero = unsafe { std::mem::transmute(int_u64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u64)` error: transmute from a `u128` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:28:37 + --> tests/ui/transmute_int_to_non_zero.rs:31:37 | LL | let _: NonZero = unsafe { std::mem::transmute(int_u128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u128)` error: transmute from a `i8` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:31:35 + --> tests/ui/transmute_int_to_non_zero.rs:34:35 | LL | let _: NonZero = unsafe { std::mem::transmute(int_i8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i8)` error: transmute from a `i16` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:33:36 + --> tests/ui/transmute_int_to_non_zero.rs:37:36 | LL | let _: NonZero = unsafe { std::mem::transmute(int_i16) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i16)` error: transmute from a `i32` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:35:36 + --> tests/ui/transmute_int_to_non_zero.rs:40:36 | LL | let _: NonZero = unsafe { std::mem::transmute(int_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i32)` error: transmute from a `i64` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:37:36 + --> tests/ui/transmute_int_to_non_zero.rs:43:36 | LL | let _: NonZero = unsafe { std::mem::transmute(int_i64) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i64)` error: transmute from a `i128` to a `NonZero` - --> tests/ui/transmute_int_to_non_zero.rs:39:37 + --> tests/ui/transmute_int_to_non_zero.rs:46:37 | LL | let _: NonZero = unsafe { std::mem::transmute(int_i128) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::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 c0196ad52d437..e88f05bb662e2 100644 --- a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs +++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs @@ -6,9 +6,10 @@ fn one_liners() { unsafe { let _: fn() = std::mem::transmute(0 as *const ()); - //~^ ERROR: transmuting a known null pointer into a function pointer + //~^ transmute_null_to_fn + let _: fn() = std::mem::transmute(std::ptr::null::<()>()); - //~^ ERROR: transmuting a known null pointer into a function pointer + //~^ transmute_null_to_fn } } @@ -19,7 +20,8 @@ fn transmute_const() { unsafe { // Should raise a lint. let _: fn() = std::mem::transmute(ZPTR); - //~^ ERROR: transmuting a known null pointer into a function pointer + //~^ transmute_null_to_fn + // Should NOT raise a lint. let _: fn() = std::mem::transmute(NOT_ZPTR); } @@ -28,11 +30,13 @@ fn transmute_const() { fn issue_11485() { unsafe { let _: fn() = std::mem::transmute(0 as *const u8 as *const ()); - //~^ ERROR: transmuting a known null pointer into a function pointer + //~^ transmute_null_to_fn + let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); - //~^ ERROR: transmuting a known null pointer into a function pointer + //~^ transmute_null_to_fn + let _: fn() = std::mem::transmute(ZPTR as *const u8); - //~^ ERROR: transmuting a known null pointer into a function pointer + //~^ transmute_null_to_fn } } diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr index cea7b42cb801c..f7d80147445d8 100644 --- a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr +++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr @@ -9,7 +9,7 @@ LL | let _: fn() = std::mem::transmute(0 as *const ()); = help: to override `-D warnings` add `#[allow(clippy::transmute_null_to_fn)]` error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:10:23 + --> tests/ui/transmute_null_to_fn.rs:11:23 | LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -17,7 +17,7 @@ LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>()); = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:21:23 + --> tests/ui/transmute_null_to_fn.rs:22:23 | LL | let _: fn() = std::mem::transmute(ZPTR); | ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -25,7 +25,7 @@ LL | let _: fn() = std::mem::transmute(ZPTR); = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:30:23 + --> tests/ui/transmute_null_to_fn.rs:32:23 | LL | let _: fn() = std::mem::transmute(0 as *const u8 as *const ()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -33,7 +33,7 @@ LL | let _: fn() = std::mem::transmute(0 as *const u8 as *const ()); = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:32:23 + --> tests/ui/transmute_null_to_fn.rs:35:23 | LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior @@ -41,7 +41,7 @@ LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const = help: try wrapping your function pointer type in `Option` instead, and using `None` as a null pointer value error: transmuting a known null pointer into a function pointer - --> tests/ui/transmute_null_to_fn.rs:34:23 + --> tests/ui/transmute_null_to_fn.rs:38:23 | LL | let _: fn() = std::mem::transmute(ZPTR as *const u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior 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 39e67b2505266..3a67be5f45d0b 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed @@ -31,24 +31,32 @@ fn transmute_ptr_to_ptr() { // pointer-to-pointer transmutes; bad let _: *const f32 = ptr.cast::(); //~^ transmute_ptr_to_ptr + let _: *mut f32 = mut_ptr.cast::(); //~^ transmute_ptr_to_ptr + // ref-ref transmutes; bad let _: &f32 = &*(&1u32 as *const u32 as *const f32); //~^ transmute_ptr_to_ptr + let _: &f32 = &*(&1f64 as *const f64 as *const f32); //~^ transmute_ptr_to_ptr + //:^ this test is here because both f32 and f64 are the same TypeVariant, but they are not // the same type let _: &mut f32 = &mut *(&mut 1u32 as *mut u32 as *mut f32); //~^ transmute_ptr_to_ptr + let _: &GenericParam = &*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam); //~^ transmute_ptr_to_ptr + let u64_ref: &u64 = &0u64; let u8_ref: &u8 = &*(u64_ref as *const u64 as *const u8); //~^ transmute_ptr_to_ptr + let _: *const u32 = mut_ptr.cast_const(); //~^ transmute_ptr_to_ptr + let _: *mut u32 = ptr.cast_mut(); //~^ transmute_ptr_to_ptr } @@ -77,6 +85,7 @@ const _: &() = { fn msrv_1_37(ptr: *const u8) { unsafe { let _: *const i8 = ptr as *const i8; + //~^ transmute_ptr_to_ptr } } @@ -84,6 +93,7 @@ fn msrv_1_37(ptr: *const u8) { fn msrv_1_38(ptr: *const u8) { unsafe { let _: *const i8 = ptr.cast::(); + //~^ transmute_ptr_to_ptr } } @@ -91,7 +101,9 @@ fn msrv_1_38(ptr: *const u8) { fn msrv_1_64(ptr: *const u8, mut_ptr: *mut u8) { unsafe { let _: *mut u8 = ptr as *mut u8; + //~^ transmute_ptr_to_ptr let _: *const u8 = mut_ptr as *const u8; + //~^ transmute_ptr_to_ptr } } @@ -99,7 +111,9 @@ fn msrv_1_64(ptr: *const u8, mut_ptr: *mut u8) { fn msrv_1_65(ptr: *const u8, mut_ptr: *mut u8) { unsafe { let _: *mut u8 = ptr.cast_mut(); + //~^ transmute_ptr_to_ptr let _: *const u8 = mut_ptr.cast_const(); + //~^ transmute_ptr_to_ptr } } 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 580b285517344..01ad3a3296b17 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs @@ -31,24 +31,32 @@ fn transmute_ptr_to_ptr() { // pointer-to-pointer transmutes; bad let _: *const f32 = transmute(ptr); //~^ transmute_ptr_to_ptr + let _: *mut f32 = transmute(mut_ptr); //~^ transmute_ptr_to_ptr + // ref-ref transmutes; bad let _: &f32 = transmute(&1u32); //~^ transmute_ptr_to_ptr + let _: &f32 = transmute(&1f64); //~^ transmute_ptr_to_ptr + //:^ this test is here because both f32 and f64 are the same TypeVariant, but they are not // the same type let _: &mut f32 = transmute(&mut 1u32); //~^ transmute_ptr_to_ptr + let _: &GenericParam = transmute(&GenericParam { t: 1u32 }); //~^ transmute_ptr_to_ptr + let u64_ref: &u64 = &0u64; let u8_ref: &u8 = transmute(u64_ref); //~^ transmute_ptr_to_ptr + let _: *const u32 = transmute(mut_ptr); //~^ transmute_ptr_to_ptr + let _: *mut u32 = transmute(ptr); //~^ transmute_ptr_to_ptr } @@ -77,6 +85,7 @@ const _: &() = { fn msrv_1_37(ptr: *const u8) { unsafe { let _: *const i8 = transmute(ptr); + //~^ transmute_ptr_to_ptr } } @@ -84,6 +93,7 @@ fn msrv_1_37(ptr: *const u8) { fn msrv_1_38(ptr: *const u8) { unsafe { let _: *const i8 = transmute(ptr); + //~^ transmute_ptr_to_ptr } } @@ -91,7 +101,9 @@ fn msrv_1_38(ptr: *const u8) { fn msrv_1_64(ptr: *const u8, mut_ptr: *mut u8) { unsafe { let _: *mut u8 = transmute(ptr); + //~^ transmute_ptr_to_ptr let _: *const u8 = transmute(mut_ptr); + //~^ transmute_ptr_to_ptr } } @@ -99,7 +111,9 @@ fn msrv_1_64(ptr: *const u8, mut_ptr: *mut u8) { fn msrv_1_65(ptr: *const u8, mut_ptr: *mut u8) { unsafe { let _: *mut u8 = transmute(ptr); + //~^ transmute_ptr_to_ptr let _: *const u8 = transmute(mut_ptr); + //~^ transmute_ptr_to_ptr } } diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr index f4f83cd7ac6a7..c8db4fe214fdb 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr @@ -13,7 +13,7 @@ LL + let _: *const f32 = ptr.cast::(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:34:27 + --> tests/ui/transmute_ptr_to_ptr.rs:35:27 | LL | let _: *mut f32 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -25,37 +25,37 @@ LL + let _: *mut f32 = mut_ptr.cast::(); | error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:37:23 + --> tests/ui/transmute_ptr_to_ptr.rs:39:23 | LL | let _: &f32 = transmute(&1u32); | ^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:39:23 + --> tests/ui/transmute_ptr_to_ptr.rs:42:23 | LL | let _: &f32 = transmute(&1f64); | ^^^^^^^^^^^^^^^^ help: try: `&*(&1f64 as *const f64 as *const f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:43:27 + --> tests/ui/transmute_ptr_to_ptr.rs:47:27 | LL | let _: &mut f32 = transmute(&mut 1u32); | ^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:45:37 + --> tests/ui/transmute_ptr_to_ptr.rs:50:37 | LL | let _: &GenericParam = transmute(&GenericParam { t: 1u32 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam as *const GenericParam)` error: transmute from a reference to a reference - --> tests/ui/transmute_ptr_to_ptr.rs:48:27 + --> tests/ui/transmute_ptr_to_ptr.rs:54:27 | LL | let u8_ref: &u8 = transmute(u64_ref); | ^^^^^^^^^^^^^^^^^^ help: try: `&*(u64_ref as *const u64 as *const u8)` error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:50:29 + --> tests/ui/transmute_ptr_to_ptr.rs:57:29 | LL | let _: *const u32 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -67,7 +67,7 @@ LL + let _: *const u32 = mut_ptr.cast_const(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:52:27 + --> tests/ui/transmute_ptr_to_ptr.rs:60:27 | LL | let _: *mut u32 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -79,7 +79,7 @@ LL + let _: *mut u32 = ptr.cast_mut(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:64:14 + --> tests/ui/transmute_ptr_to_ptr.rs:72:14 | LL | unsafe { transmute(v) } | ^^^^^^^^^^^^ @@ -91,7 +91,7 @@ LL + unsafe { v as *const &() } | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:79:28 + --> tests/ui/transmute_ptr_to_ptr.rs:87:28 | LL | let _: *const i8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -103,7 +103,7 @@ LL + let _: *const i8 = ptr as *const i8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:86:28 + --> tests/ui/transmute_ptr_to_ptr.rs:95:28 | LL | let _: *const i8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -115,7 +115,7 @@ LL + let _: *const i8 = ptr.cast::(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:93:26 + --> tests/ui/transmute_ptr_to_ptr.rs:103:26 | LL | let _: *mut u8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -127,7 +127,7 @@ LL + let _: *mut u8 = ptr as *mut u8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:94:28 + --> tests/ui/transmute_ptr_to_ptr.rs:105:28 | LL | let _: *const u8 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ @@ -139,7 +139,7 @@ LL + let _: *const u8 = mut_ptr as *const u8; | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:101:26 + --> tests/ui/transmute_ptr_to_ptr.rs:113:26 | LL | let _: *mut u8 = transmute(ptr); | ^^^^^^^^^^^^^^ @@ -151,7 +151,7 @@ LL + let _: *mut u8 = ptr.cast_mut(); | error: transmute from a pointer to a pointer - --> tests/ui/transmute_ptr_to_ptr.rs:102:28 + --> tests/ui/transmute_ptr_to_ptr.rs:115:28 | LL | let _: *const u8 = transmute(mut_ptr); | ^^^^^^^^^^^^^^^^^^ 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 56330d7193898..1bd45bc10a39b 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed @@ -7,24 +7,31 @@ unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = &*p; + //~^ transmute_ptr_to_ref let _: &T = &*p; let _: &mut T = &mut *m; + //~^ transmute_ptr_to_ref let _: &mut T = &mut *m; let _: &T = &*m; + //~^ transmute_ptr_to_ref let _: &T = &*m; let _: &mut T = &mut *(p as *mut T); + //~^ transmute_ptr_to_ref let _ = &mut *(p as *mut T); let _: &T = &*(o as *const T); + //~^ transmute_ptr_to_ref let _: &T = &*(o as *const T); let _: &mut T = &mut *(om as *mut T); + //~^ transmute_ptr_to_ref let _: &mut T = &mut *(om as *mut T); let _: &T = &*(om as *const T); + //~^ transmute_ptr_to_ref let _: &T = &*(om as *const T); } @@ -35,20 +42,27 @@ fn _issue1231() { let raw = 42 as *const i32; let _: &Foo = unsafe { &*raw.cast::>() }; + //~^ transmute_ptr_to_ref let _: &Foo<&u8> = unsafe { &*raw.cast::>() }; + //~^ transmute_ptr_to_ref type Bar<'a> = &'a u8; let raw = 42 as *const i32; unsafe { &*(raw as *const u8) }; + //~^ transmute_ptr_to_ref } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { match 0 { 0 => &*x.cast::<&u32>(), + //~^ transmute_ptr_to_ref 1 => &*y.cast::<&u32>(), + //~^ transmute_ptr_to_ref 2 => &*x.cast::<&'b u32>(), + //~^ transmute_ptr_to_ref _ => &*y.cast::<&'b u32>(), + //~^ transmute_ptr_to_ref } } @@ -57,10 +71,14 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { let a = 0u32; let a = &a as *const u32; let _: &u32 = &*a; + //~^ transmute_ptr_to_ref let _: &u32 = &*a.cast::(); + //~^ transmute_ptr_to_ref match 0 { 0 => &*x.cast::<&u32>(), + //~^ transmute_ptr_to_ref _ => &*x.cast::<&'b u32>(), + //~^ transmute_ptr_to_ref } } @@ -69,10 +87,14 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { let a = 0u32; let a = &a as *const u32; let _: &u32 = &*a; + //~^ transmute_ptr_to_ref let _: &u32 = &*(a as *const u32); + //~^ transmute_ptr_to_ref match 0 { 0 => &*(x as *const () as *const &u32), + //~^ transmute_ptr_to_ref _ => &*(x as *const () as *const &'b u32), + //~^ transmute_ptr_to_ref } } 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 ce1ee8bfbfaee..cbe64bf1ea6bc 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs @@ -7,24 +7,31 @@ unsafe fn _ptr_to_ref(p: *const T, m: *mut T, o: *const U, om: *mut U) { let _: &T = std::mem::transmute(p); + //~^ transmute_ptr_to_ref let _: &T = &*p; let _: &mut T = std::mem::transmute(m); + //~^ transmute_ptr_to_ref let _: &mut T = &mut *m; let _: &T = std::mem::transmute(m); + //~^ transmute_ptr_to_ref let _: &T = &*m; let _: &mut T = std::mem::transmute(p as *mut T); + //~^ transmute_ptr_to_ref let _ = &mut *(p as *mut T); let _: &T = std::mem::transmute(o); + //~^ transmute_ptr_to_ref let _: &T = &*(o as *const T); let _: &mut T = std::mem::transmute(om); + //~^ transmute_ptr_to_ref let _: &mut T = &mut *(om as *mut T); let _: &T = std::mem::transmute(om); + //~^ transmute_ptr_to_ref let _: &T = &*(om as *const T); } @@ -35,20 +42,27 @@ fn _issue1231() { let raw = 42 as *const i32; let _: &Foo = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) }; + //~^ transmute_ptr_to_ref let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) }; + //~^ transmute_ptr_to_ref type Bar<'a> = &'a u8; let raw = 42 as *const i32; unsafe { std::mem::transmute::<_, Bar>(raw) }; + //~^ transmute_ptr_to_ref } unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 { match 0 { 0 => std::mem::transmute(x), + //~^ transmute_ptr_to_ref 1 => std::mem::transmute(y), + //~^ transmute_ptr_to_ref 2 => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref _ => std::mem::transmute::<_, &&'b u32>(y), + //~^ transmute_ptr_to_ref } } @@ -57,10 +71,14 @@ unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { let a = 0u32; let a = &a as *const u32; let _: &u32 = std::mem::transmute(a); + //~^ transmute_ptr_to_ref let _: &u32 = std::mem::transmute::<_, &u32>(a); + //~^ transmute_ptr_to_ref match 0 { 0 => std::mem::transmute(x), + //~^ transmute_ptr_to_ref _ => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref } } @@ -69,10 +87,14 @@ unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 { let a = 0u32; let a = &a as *const u32; let _: &u32 = std::mem::transmute(a); + //~^ transmute_ptr_to_ref let _: &u32 = std::mem::transmute::<_, &u32>(a); + //~^ transmute_ptr_to_ref match 0 { 0 => std::mem::transmute(x), + //~^ transmute_ptr_to_ref _ => std::mem::transmute::<_, &&'b u32>(x), + //~^ transmute_ptr_to_ref } } 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 44cda254c3f7b..7fad9b4065a56 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr @@ -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:12:21 + --> tests/ui/transmute_ptr_to_ref.rs:13: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:15:17 + --> tests/ui/transmute_ptr_to_ref.rs:17: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:18:21 + --> tests/ui/transmute_ptr_to_ref.rs:21: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:21:17 + --> tests/ui/transmute_ptr_to_ref.rs:25: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:24:21 + --> tests/ui/transmute_ptr_to_ref.rs:29: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:27:17 + --> tests/ui/transmute_ptr_to_ref.rs:33: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:37:32 + --> tests/ui/transmute_ptr_to_ref.rs:44: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:39:33 + --> tests/ui/transmute_ptr_to_ref.rs:47: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:43:14 + --> tests/ui/transmute_ptr_to_ref.rs:52: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:48:14 + --> tests/ui/transmute_ptr_to_ref.rs:58: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:49:14 + --> tests/ui/transmute_ptr_to_ref.rs:60: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:50:14 + --> tests/ui/transmute_ptr_to_ref.rs:62: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:51:14 + --> tests/ui/transmute_ptr_to_ref.rs:64: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:59:19 + --> tests/ui/transmute_ptr_to_ref.rs:73: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:60:19 + --> tests/ui/transmute_ptr_to_ref.rs:75: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:62:14 + --> tests/ui/transmute_ptr_to_ref.rs:78: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:63:14 + --> tests/ui/transmute_ptr_to_ref.rs:80: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:71:19 + --> tests/ui/transmute_ptr_to_ref.rs:89: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:72:19 + --> tests/ui/transmute_ptr_to_ref.rs:91: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:74:14 + --> tests/ui/transmute_ptr_to_ref.rs:94: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:75:14 + --> tests/ui/transmute_ptr_to_ref.rs:96: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 44d7af44a8053..8bdf07b4a428b 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.rs @@ -7,12 +7,14 @@ fn main() { unsafe { let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; let bools: &[bool] = unsafe { std::mem::transmute(single_u64) }; - //~^ ERROR: transmute from a reference to a reference + //~^ transmute_ptr_to_ptr + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; let b: &[u8] = unsafe { std::mem::transmute(a) }; - //~^ ERROR: transmute from a reference to a reference + //~^ transmute_ptr_to_ptr + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; - //~^ ERROR: transmute from a reference to a reference + //~^ transmute_ptr_to_ptr } } diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr index e2d04cea8959f..e8d659f9c5d8d 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref.stderr @@ -11,13 +11,13 @@ LL | #![deny(clippy::transmute_ptr_to_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref.rs:12:33 + --> tests/ui/transmute_ref_to_ref.rs:13:33 | LL | let b: &[u8] = unsafe { std::mem::transmute(a) }; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref.rs:15:42 + --> tests/ui/transmute_ref_to_ref.rs:17:42 | LL | let alt_slice: &[u32] = unsafe { std::mem::transmute(bytes) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` 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 5917705875496..faa776f2afcec 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 @@ -19,12 +19,14 @@ fn main() { unsafe { let single_u64: &[u64] = &[0xDEAD_BEEF_DEAD_BEEF]; let bools: &[bool] = unsafe { core::mem::transmute(single_u64) }; - //~^ ERROR: transmute from a reference to a reference + //~^ transmute_ptr_to_ptr + let a: &[u32] = &[0x12345678, 0x90ABCDEF, 0xFEDCBA09, 0x87654321]; let b: &[u8] = unsafe { core::mem::transmute(a) }; - //~^ ERROR: transmute from a reference to a reference + //~^ transmute_ptr_to_ptr + let bytes = &[1u8, 2u8, 3u8, 4u8] as &[u8]; let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; - //~^ ERROR: transmute from a reference to a reference + //~^ transmute_ptr_to_ptr } } diff --git a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr index 6a76d6729d05b..9aa9ed928a4d5 100644 --- a/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr +++ b/src/tools/clippy/tests/ui/transmute_ref_to_ref_no_std.stderr @@ -11,13 +11,13 @@ LL | #![deny(clippy::transmute_ptr_to_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref_no_std.rs:24:33 + --> tests/ui/transmute_ref_to_ref_no_std.rs:25:33 | LL | let b: &[u8] = unsafe { core::mem::transmute(a) }; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const [u32] as *const [u8])` error: transmute from a reference to a reference - --> tests/ui/transmute_ref_to_ref_no_std.rs:27:42 + --> tests/ui/transmute_ref_to_ref_no_std.rs:29:42 | LL | let alt_slice: &[u32] = unsafe { core::mem::transmute(bytes) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(bytes as *const [u8] as *const [u32])` diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs index 5b16d71f1142a..a449d6a4302f8 100644 --- a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs +++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs @@ -32,11 +32,11 @@ fn main() { // Lint, Ty2 is unordered let _: Ty2C = transmute(value::>()); - //~^ ERROR: transmute from `Ty2` which has an undefined layout - //~| NOTE: `-D clippy::transmute-undefined-repr` implied by `-D warnings` + //~^ transmute_undefined_repr + // Lint, Ty2 is unordered let _: Ty2 = transmute(value::>()); - //~^ ERROR: transmute into `Ty2` which has an undefined layout + //~^ transmute_undefined_repr // Ok, Ty2 types are the same let _: Ty2 = transmute(value::>>()); @@ -45,24 +45,22 @@ fn main() { // Lint, different Ty2 instances let _: Ty2 = transmute(value::>>()); - //~^ ERROR: transmute from `Ty>` to `Ty2`, both of which h - //~| NOTE: two instances of the same generic type (`Ty2`) may have different layou + //~^ transmute_undefined_repr + // Lint, different Ty2 instances let _: Ty> = transmute(value::>()); - //~^ ERROR: transmute from `Ty2` to `Ty>`, both of which h - //~| NOTE: two instances of the same generic type (`Ty2`) may have different layou + //~^ transmute_undefined_repr let _: Ty<&()> = transmute(value::<&()>()); let _: &() = transmute(value::>()); // Lint, different Ty2 instances let _: &Ty2 = transmute(value::>>()); - //~^ ERROR: transmute from `Ty<&Ty2>` to `&Ty2`, both of which - //~| NOTE: two instances of the same generic type (`Ty2`) may have different layou + //~^ transmute_undefined_repr + // Lint, different Ty2 instances let _: Ty<&Ty2> = transmute(value::<&Ty2>()); - //~^ ERROR: transmute from `&Ty2` to `Ty<&Ty2>`, both of which - //~| NOTE: two instances of the same generic type (`Ty2`) may have different layou + //~^ transmute_undefined_repr // Ok, pointer to usize conversion let _: Ty = transmute(value::<&Ty2>()); @@ -91,12 +89,11 @@ fn main() { // Lint, different Ty2 instances let _: &'static mut Ty2 = transmute(value::>>()); - //~^ ERROR: transmute from `std::boxed::Box>` to `&mut Ty2 - //~| NOTE: two instances of the same generic type (`Ty2`) may have different layou + //~^ transmute_undefined_repr + // Lint, different Ty2 instances let _: Box> = transmute(value::<&'static mut Ty2>()); - //~^ ERROR: transmute from `&mut Ty2` to `std::boxed::Box> - //~| NOTE: two instances of the same generic type (`Ty2`) may have different layou + //~^ transmute_undefined_repr // Ok, type erasure let _: *const () = transmute(value::>>()); @@ -192,12 +189,11 @@ fn main() { // Err let _: *const Ty2 = transmute(value::<*const Ty2C>>()); - //~^ ERROR: transmute into `*const Ty2` which has an undefined layout - //~| NOTE: the contained type `Ty2` has an undefined layout + //~^ transmute_undefined_repr + // Err let _: *const Ty2C> = transmute(value::<*const Ty2>()); - //~^ ERROR: transmute from `*const Ty2` which has an undefined layout - //~| NOTE: the contained type `Ty2` has an undefined layout + //~^ transmute_undefined_repr // Ok let _: NonNull = transmute(value::>()); @@ -243,12 +239,11 @@ fn _with_generics() { // Err let _: Vec> = transmute(value::>>()); - //~^ ERROR: transmute from `std::vec::Vec>` to `std::vec::Vec> = transmute(value::>>()); - //~^ ERROR: transmute from `std::vec::Vec>` to `std::vec::Vec>()); diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr index b41d37a5cd132..a259ef784c782 100644 --- a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr +++ b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr @@ -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:59:33 + --> tests/ui/transmute_undefined_repr.rs:58: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:63:37 + --> tests/ui/transmute_undefined_repr.rs:62: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:93:45 + --> tests/ui/transmute_undefined_repr.rs:91: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:97:37 + --> tests/ui/transmute_undefined_repr.rs:95: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:194:39 + --> tests/ui/transmute_undefined_repr.rs:191: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:198:50 + --> tests/ui/transmute_undefined_repr.rs:195: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:245:35 + --> tests/ui/transmute_undefined_repr.rs:241: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:249:35 + --> tests/ui/transmute_undefined_repr.rs:245: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 a4a3ca82e76cd..e7ad2a1cbbcb1 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 @@ -15,28 +15,33 @@ fn main() { // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast let _ptr_i32_transmute = unsafe { usize::MAX as *const i32 }; + //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... let _ptr_i8_transmute = unsafe { ptr_i32.cast::() }; + //~^ transmute_ptr_to_ptr let _ptr_i8 = ptr_i32 as *const i8; let slice_ptr = &[0, 1, 2, 3] as *const [i32]; // ... or pointer_kind(T) = pointer_kind(U_0); ptr-ptr-cast let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u32] }; + //~^ transmute_ptr_to_ptr let _ptr_to_unsized = slice_ptr as *const [u32]; // TODO: We could try testing vtable casts here too, but maybe // we should wait until std::raw::TraitObject is stabilized? // e has type *T and U is a numeric type, while T: Sized; ptr-addr-cast let _usize_from_int_ptr_transmute = unsafe { ptr_i32 as usize }; + //~^ transmutes_expressible_as_ptr_casts let _usize_from_int_ptr = ptr_i32 as usize; let array_ref: &[i32; 4] = &[1, 2, 3, 4]; // e has type &[T; n] and U is *const T; array-ptr-cast let _array_ptr_transmute = unsafe { array_ref as *const [i32; 4] }; + //~^ useless_transmute let _array_ptr = array_ref as *const [i32; 4]; fn foo(_: usize) -> u8 { @@ -45,13 +50,16 @@ fn main() { // e is a function pointer type and U has type *T, while T: Sized; fptr-ptr-cast let _usize_ptr_transmute = unsafe { foo as *const usize }; + //~^ transmutes_expressible_as_ptr_casts let _usize_ptr_transmute = foo as *const usize; // e is a function pointer type and U is an integer; fptr-addr-cast let _usize_from_fn_ptr_transmute = unsafe { foo as usize }; + //~^ transmutes_expressible_as_ptr_casts let _usize_from_fn_ptr = foo as *const usize; let _usize_from_ref = unsafe { &1u32 as *const u32 as usize }; + //~^ transmutes_expressible_as_ptr_casts } // If a ref-to-ptr cast of this form where the pointer type points to a type other @@ -63,6 +71,7 @@ fn main() { // fall through into `do_check`. fn trigger_do_check_to_emit_error(in_param: &[i32; 1]) -> *const u8 { unsafe { in_param as *const [i32; 1] as *const u8 } + //~^ useless_transmute } #[repr(C)] @@ -81,6 +90,7 @@ fn issue_10449() { fn f() {} let _x: u8 = unsafe { *(f as *const u8) }; + //~^ transmutes_expressible_as_ptr_casts } // Pointers cannot be cast to integers in const contexts 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 6aa8e384e268c..42a81777a8267 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 @@ -15,28 +15,33 @@ fn main() { // e is an integer and U is *U_0, while U_0: Sized; addr-ptr-cast let _ptr_i32_transmute = unsafe { transmute::(usize::MAX) }; + //~^ useless_transmute let ptr_i32 = usize::MAX as *const i32; // e has type *T, U is *U_0, and either U_0: Sized ... let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) }; + //~^ transmute_ptr_to_ptr let _ptr_i8 = ptr_i32 as *const i8; let slice_ptr = &[0, 1, 2, 3] as *const [i32]; // ... or pointer_kind(T) = pointer_kind(U_0); ptr-ptr-cast let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u32]>(slice_ptr) }; + //~^ transmute_ptr_to_ptr let _ptr_to_unsized = slice_ptr as *const [u32]; // TODO: We could try testing vtable casts here too, but maybe // we should wait until std::raw::TraitObject is stabilized? // e has type *T and U is a numeric type, while T: Sized; ptr-addr-cast let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) }; + //~^ transmutes_expressible_as_ptr_casts let _usize_from_int_ptr = ptr_i32 as usize; let array_ref: &[i32; 4] = &[1, 2, 3, 4]; // e has type &[T; n] and U is *const T; array-ptr-cast let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) }; + //~^ useless_transmute let _array_ptr = array_ref as *const [i32; 4]; fn foo(_: usize) -> u8 { @@ -45,13 +50,16 @@ fn main() { // e is a function pointer type and U has type *T, while T: Sized; fptr-ptr-cast let _usize_ptr_transmute = unsafe { transmute:: u8, *const usize>(foo) }; + //~^ transmutes_expressible_as_ptr_casts let _usize_ptr_transmute = foo as *const usize; // e is a function pointer type and U is an integer; fptr-addr-cast let _usize_from_fn_ptr_transmute = unsafe { transmute:: u8, usize>(foo) }; + //~^ transmutes_expressible_as_ptr_casts let _usize_from_fn_ptr = foo as *const usize; let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; + //~^ transmutes_expressible_as_ptr_casts } // If a ref-to-ptr cast of this form where the pointer type points to a type other @@ -63,6 +71,7 @@ fn main() { // fall through into `do_check`. fn trigger_do_check_to_emit_error(in_param: &[i32; 1]) -> *const u8 { unsafe { transmute::<&[i32; 1], *const u8>(in_param) } + //~^ useless_transmute } #[repr(C)] @@ -81,6 +90,7 @@ fn issue_10449() { fn f() {} let _x: u8 = unsafe { *std::mem::transmute::(f) }; + //~^ transmutes_expressible_as_ptr_casts } // Pointers cannot be cast to integers in const contexts diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr index 21edd39e7ad65..7746f087cc714 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr @@ -8,7 +8,7 @@ LL | let _ptr_i32_transmute = unsafe { transmute::(usize: = help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]` error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:21:38 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:22:38 | LL | let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL + let _ptr_i8_transmute = unsafe { ptr_i32.cast::() }; | error: transmute from a pointer to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:27:46 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:29:46 | LL | let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u32]>(slice_ptr) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL + let _ptr_to_unsized_transmute = unsafe { slice_ptr as *const [u32] }; | error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:33:50 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:36:50 | LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize` @@ -43,37 +43,37 @@ LL | let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us = help: to override `-D warnings` add `#[allow(clippy::transmutes_expressible_as_ptr_casts)]` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:39:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:43:41 | LL | let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]` error: transmute from `fn(usize) -> u8` to `*const usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:47:41 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:52:41 | LL | let _usize_ptr_transmute = unsafe { transmute:: u8, *const usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize` error: transmute from `fn(usize) -> u8` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:51:49 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:57:49 | LL | let _usize_from_fn_ptr_transmute = unsafe { transmute:: u8, usize>(foo) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize` error: transmute from `*const u32` to `usize` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:54:36 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:61:36 | LL | let _usize_from_ref = unsafe { transmute::<*const u32, usize>(&1u32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&1u32 as *const u32 as usize` error: transmute from a reference to a pointer - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:65:14 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:73:14 | LL | unsafe { transmute::<&[i32; 1], *const u8>(in_param) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8` error: transmute from `fn()` to `*const u8` which could be expressed as a pointer cast instead - --> tests/ui/transmutes_expressible_as_ptr_casts.rs:83:28 + --> tests/ui/transmutes_expressible_as_ptr_casts.rs:92:28 | LL | let _x: u8 = unsafe { *std::mem::transmute::(f) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(f as *const u8)` diff --git a/src/tools/clippy/tests/ui/transmuting_null.rs b/src/tools/clippy/tests/ui/transmuting_null.rs index c2deb6b6c460c..bcd35bbd4e72a 100644 --- a/src/tools/clippy/tests/ui/transmuting_null.rs +++ b/src/tools/clippy/tests/ui/transmuting_null.rs @@ -8,10 +8,10 @@ fn one_liners() { unsafe { let _: &u64 = std::mem::transmute(0 as *const u64); - //~^ ERROR: transmuting a known null pointer into a reference - //~| NOTE: `-D clippy::transmuting-null` implied by `-D warnings` + //~^ transmuting_null + let _: &u64 = std::mem::transmute(std::ptr::null::()); - //~^ ERROR: transmuting a known null pointer into a reference + //~^ transmuting_null } } @@ -22,7 +22,8 @@ fn transmute_const() { unsafe { // Should raise a lint. let _: &u64 = std::mem::transmute(ZPTR); - //~^ ERROR: transmuting a known null pointer into a reference + //~^ transmuting_null + // Should NOT raise a lint. let _: &u64 = std::mem::transmute(NOT_ZPTR); } diff --git a/src/tools/clippy/tests/ui/trim_split_whitespace.fixed b/src/tools/clippy/tests/ui/trim_split_whitespace.fixed index 6d3daf798a675..434e91b7d9530 100644 --- a/src/tools/clippy/tests/ui/trim_split_whitespace.fixed +++ b/src/tools/clippy/tests/ui/trim_split_whitespace.fixed @@ -59,13 +59,25 @@ impl DerefStrAndCustomTrim { fn main() { // &str let _ = " A B C ".split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = " A B C ".split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = " A B C ".split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // String let _ = (" A B C ").to_string().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = (" A B C ").to_string().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = (" A B C ").to_string().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // Custom let _ = Custom.trim().split_whitespace(); // should not trigger lint @@ -73,6 +85,8 @@ fn main() { // Deref let s = DerefStr(" A B C "); let _ = s.split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // Deref + custom impl let s = DerefStrAndCustom(" A B C "); @@ -81,6 +95,8 @@ fn main() { // Deref + only custom split_ws() impl let s = DerefStrAndCustomSplit(" A B C "); let _ = s.split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // Expl: trim() is called on str (deref) and returns &str. // Thus split_ws() is called on str as well and the custom impl on S is unused diff --git a/src/tools/clippy/tests/ui/trim_split_whitespace.rs b/src/tools/clippy/tests/ui/trim_split_whitespace.rs index b49d9e8b3fab8..b939ecdfba854 100644 --- a/src/tools/clippy/tests/ui/trim_split_whitespace.rs +++ b/src/tools/clippy/tests/ui/trim_split_whitespace.rs @@ -59,13 +59,25 @@ impl DerefStrAndCustomTrim { fn main() { // &str let _ = " A B C ".trim().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = " A B C ".trim_start().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = " A B C ".trim_end().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // String let _ = (" A B C ").to_string().trim().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = (" A B C ").to_string().trim_start().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace let _ = (" A B C ").to_string().trim_end().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // Custom let _ = Custom.trim().split_whitespace(); // should not trigger lint @@ -73,6 +85,8 @@ fn main() { // Deref let s = DerefStr(" A B C "); let _ = s.trim().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // Deref + custom impl let s = DerefStrAndCustom(" A B C "); @@ -81,6 +95,8 @@ fn main() { // Deref + only custom split_ws() impl let s = DerefStrAndCustomSplit(" A B C "); let _ = s.trim().split_whitespace(); // should trigger lint + // + //~^^ trim_split_whitespace // Expl: trim() is called on str (deref) and returns &str. // Thus split_ws() is called on str as well and the custom impl on S is unused diff --git a/src/tools/clippy/tests/ui/trim_split_whitespace.stderr b/src/tools/clippy/tests/ui/trim_split_whitespace.stderr index 6119d21a8e9ae..f242dd8021156 100644 --- a/src/tools/clippy/tests/ui/trim_split_whitespace.stderr +++ b/src/tools/clippy/tests/ui/trim_split_whitespace.stderr @@ -8,43 +8,43 @@ LL | let _ = " A B C ".trim().split_whitespace(); // should trigger lint = help: to override `-D warnings` add `#[allow(clippy::trim_split_whitespace)]` error: found call to `str::trim_start` before `str::split_whitespace` - --> tests/ui/trim_split_whitespace.rs:62:23 + --> tests/ui/trim_split_whitespace.rs:64:23 | LL | let _ = " A B C ".trim_start().split_whitespace(); // should trigger lint | ^^^^^^^^^^^^^ help: remove `trim_start()` error: found call to `str::trim_end` before `str::split_whitespace` - --> tests/ui/trim_split_whitespace.rs:63:23 + --> tests/ui/trim_split_whitespace.rs:67:23 | LL | let _ = " A B C ".trim_end().split_whitespace(); // should trigger lint | ^^^^^^^^^^^ help: remove `trim_end()` error: found call to `str::trim` before `str::split_whitespace` - --> tests/ui/trim_split_whitespace.rs:66:37 + --> tests/ui/trim_split_whitespace.rs:72:37 | LL | let _ = (" A B C ").to_string().trim().split_whitespace(); // should trigger lint | ^^^^^^^ help: remove `trim()` error: found call to `str::trim_start` before `str::split_whitespace` - --> tests/ui/trim_split_whitespace.rs:67:37 + --> tests/ui/trim_split_whitespace.rs:75:37 | LL | let _ = (" A B C ").to_string().trim_start().split_whitespace(); // should trigger lint | ^^^^^^^^^^^^^ help: remove `trim_start()` error: found call to `str::trim_end` before `str::split_whitespace` - --> tests/ui/trim_split_whitespace.rs:68:37 + --> tests/ui/trim_split_whitespace.rs:78:37 | LL | let _ = (" A B C ").to_string().trim_end().split_whitespace(); // should trigger lint | ^^^^^^^^^^^ help: remove `trim_end()` error: found call to `str::trim` before `str::split_whitespace` - --> tests/ui/trim_split_whitespace.rs:75:15 + --> tests/ui/trim_split_whitespace.rs:87:15 | LL | let _ = s.trim().split_whitespace(); // should trigger lint | ^^^^^^^ help: remove `trim()` error: found call to `str::trim` before `str::split_whitespace` - --> tests/ui/trim_split_whitespace.rs:83:15 + --> tests/ui/trim_split_whitespace.rs:97:15 | LL | let _ = s.trim().split_whitespace(); // should trigger lint | ^^^^^^^ help: remove `trim()` diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs index 043a7b63af3cc..37bc6f89a20af 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs @@ -52,6 +52,7 @@ fn good_return_explicit_lt_struct<'a>(foo: &'a Foo) -> FooRef<'a> { fn bad(x: &u32, y: &Foo, z: &Baz) {} //~^ ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by //~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by +//~| ERROR: this argument (4 byte) is passed by reference, but would be more efficient if passed by impl Foo { fn good(self, a: &mut u32, b: u32, c: &Bar) {} diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr index 4887fb00e7425..e813fecf653ac 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr @@ -23,91 +23,91 @@ LL | fn bad(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:61:12 + --> tests/ui/trivially_copy_pass_by_ref.rs:62:12 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^^ help: consider passing by value instead: `self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:61:22 + --> tests/ui/trivially_copy_pass_by_ref.rs:62:22 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:61:31 + --> tests/ui/trivially_copy_pass_by_ref.rs:62:31 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:61:40 + --> tests/ui/trivially_copy_pass_by_ref.rs:62:40 | LL | fn bad(&self, x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:67:16 + --> tests/ui/trivially_copy_pass_by_ref.rs:68:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:67:25 + --> tests/ui/trivially_copy_pass_by_ref.rs:68:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:67:34 + --> tests/ui/trivially_copy_pass_by_ref.rs:68:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:72:35 + --> tests/ui/trivially_copy_pass_by_ref.rs:73:35 | LL | fn bad_issue7518(self, other: &Self) {} | ^^^^^ help: consider passing by value instead: `Self` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:85:16 + --> tests/ui/trivially_copy_pass_by_ref.rs:86:16 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `u32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:85:25 + --> tests/ui/trivially_copy_pass_by_ref.rs:86:25 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:85:34 + --> tests/ui/trivially_copy_pass_by_ref.rs:86:34 | LL | fn bad2(x: &u32, y: &Foo, z: &Baz) {} | ^^^^ help: consider passing by value instead: `Baz` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:92:34 + --> tests/ui/trivially_copy_pass_by_ref.rs:93:34 | LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:125:21 + --> tests/ui/trivially_copy_pass_by_ref.rs:126:21 | LL | fn foo_never(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:131:15 + --> tests/ui/trivially_copy_pass_by_ref.rs:132:15 | LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: 8 byte) - --> tests/ui/trivially_copy_pass_by_ref.rs:159:37 + --> tests/ui/trivially_copy_pass_by_ref.rs:160:37 | LL | fn _unrelated_lifetimes<'a, 'b>(_x: &'a u32, y: &'b u32) -> &'b u32 { | ^^^^^^^ help: consider passing by value instead: `u32` diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed index f149bfb77740c..ea509f9a2da87 100644 --- a/src/tools/clippy/tests/ui/try_err.fixed +++ b/src/tools/clippy/tests/ui/try_err.fixed @@ -20,6 +20,7 @@ pub fn basic_test() -> Result { // To avoid warnings during rustfix if true { return Err(err); + //~^ try_err } Ok(0) } @@ -30,6 +31,7 @@ pub fn into_test() -> Result { // To avoid warnings during rustfix if true { return Err(err.into()); + //~^ try_err } Ok(0) } @@ -50,6 +52,7 @@ pub fn closure_matches_test() -> Result { // To avoid warnings during rustfix if true { return Err(err); + //~^ try_err } Ok(i) }) @@ -69,6 +72,7 @@ pub fn closure_into_test() -> Result { // To avoid warnings during rustfix if true { return Err(err.into()); + //~^ try_err } Ok(i) }) @@ -89,6 +93,7 @@ fn calling_macro() -> Result { match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => return Err(1), + //~^ try_err } ); // `Err` arg is another macro @@ -96,6 +101,7 @@ fn calling_macro() -> Result { match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => return Err(inline!(1)), + //~^ try_err } ); Ok(5) @@ -123,6 +129,7 @@ fn main() { pub fn macro_inside(fail: bool) -> Result { if fail { return Err(inline!(inline!(String::from("aasdfasdfasdfa")))); + //~^ try_err } Ok(0) } @@ -130,8 +137,10 @@ pub fn macro_inside(fail: bool) -> Result { pub fn poll_write(n: usize) -> Poll> { if n == 0 { return Poll::Ready(Err(io::ErrorKind::WriteZero.into())) + //~^ try_err } else if n == 1 { return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))) + //~^ try_err }; Poll::Ready(Ok(n)) @@ -140,6 +149,7 @@ pub fn poll_write(n: usize) -> Poll> { pub fn poll_next(ready: bool) -> Poll>> { if !ready { return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into()))) + //~^ try_err } Poll::Ready(None) @@ -149,6 +159,7 @@ pub fn poll_next(ready: bool) -> Poll>> { pub fn try_return(x: bool) -> Result { if x { return Err(42); + //~^ try_err } Ok(0) } diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs index 841ec6b5d5c77..295f7bd7089b9 100644 --- a/src/tools/clippy/tests/ui/try_err.rs +++ b/src/tools/clippy/tests/ui/try_err.rs @@ -20,6 +20,7 @@ pub fn basic_test() -> Result { // To avoid warnings during rustfix if true { Err(err)?; + //~^ try_err } Ok(0) } @@ -30,6 +31,7 @@ pub fn into_test() -> Result { // To avoid warnings during rustfix if true { Err(err)?; + //~^ try_err } Ok(0) } @@ -50,6 +52,7 @@ pub fn closure_matches_test() -> Result { // To avoid warnings during rustfix if true { Err(err)?; + //~^ try_err } Ok(i) }) @@ -69,6 +72,7 @@ pub fn closure_into_test() -> Result { // To avoid warnings during rustfix if true { Err(err)?; + //~^ try_err } Ok(i) }) @@ -89,6 +93,7 @@ fn calling_macro() -> Result { match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => Err(1)?, + //~^ try_err } ); // `Err` arg is another macro @@ -96,6 +101,7 @@ fn calling_macro() -> Result { match $(Ok::<_, i32>(5)) { Ok(_) => 0, Err(_) => Err(inline!(1))?, + //~^ try_err } ); Ok(5) @@ -123,6 +129,7 @@ fn main() { pub fn macro_inside(fail: bool) -> Result { if fail { Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; + //~^ try_err } Ok(0) } @@ -130,8 +137,10 @@ pub fn macro_inside(fail: bool) -> Result { pub fn poll_write(n: usize) -> Poll> { if n == 0 { Err(io::ErrorKind::WriteZero)? + //~^ try_err } else if n == 1 { Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? + //~^ try_err }; Poll::Ready(Ok(n)) @@ -140,6 +149,7 @@ pub fn poll_write(n: usize) -> Poll> { pub fn poll_next(ready: bool) -> Poll>> { if !ready { Err(io::ErrorKind::NotFound)? + //~^ try_err } Poll::Ready(None) @@ -149,6 +159,7 @@ pub fn poll_next(ready: bool) -> Poll>> { pub fn try_return(x: bool) -> Result { if x { return Err(42)?; + //~^ try_err } Ok(0) } diff --git a/src/tools/clippy/tests/ui/try_err.stderr b/src/tools/clippy/tests/ui/try_err.stderr index fb563d4078660..50c2b092d6c87 100644 --- a/src/tools/clippy/tests/ui/try_err.stderr +++ b/src/tools/clippy/tests/ui/try_err.stderr @@ -11,25 +11,25 @@ LL | #![deny(clippy::try_err)] | ^^^^^^^^^^^^^^^ error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:32:9 + --> tests/ui/try_err.rs:33:9 | LL | Err(err)?; | ^^^^^^^^^ help: try: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:52:17 + --> tests/ui/try_err.rs:54:17 | LL | Err(err)?; | ^^^^^^^^^ help: try: `return Err(err)` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:71:17 + --> tests/ui/try_err.rs:74:17 | LL | Err(err)?; | ^^^^^^^^^ help: try: `return Err(err.into())` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:91:23 + --> tests/ui/try_err.rs:95:23 | LL | Err(_) => Err(1)?, | ^^^^^^^ help: try: `return Err(1)` @@ -37,7 +37,7 @@ LL | Err(_) => Err(1)?, = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:98:23 + --> tests/ui/try_err.rs:103:23 | LL | Err(_) => Err(inline!(1))?, | ^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(1))` @@ -45,31 +45,31 @@ LL | Err(_) => Err(inline!(1))?, = note: this error originates in the macro `__inline_mac_fn_calling_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:125:9 + --> tests/ui/try_err.rs:131:9 | LL | Err(inline!(inline!(String::from("aasdfasdfasdfa"))))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Err(inline!(inline!(String::from("aasdfasdfasdfa"))))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:132:9 + --> tests/ui/try_err.rs:139:9 | LL | Err(io::ErrorKind::WriteZero)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::ErrorKind::WriteZero.into()))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:134:9 + --> tests/ui/try_err.rs:142:9 | LL | Err(io::Error::new(io::ErrorKind::InvalidInput, "error"))? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Err(io::Error::new(io::ErrorKind::InvalidInput, "error")))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:142:9 + --> tests/ui/try_err.rs:151:9 | LL | Err(io::ErrorKind::NotFound)? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `return Poll::Ready(Some(Err(io::ErrorKind::NotFound.into())))` error: returning an `Err(_)` with the `?` operator - --> tests/ui/try_err.rs:151:16 + --> tests/ui/try_err.rs:161:16 | LL | return Err(42)?; | ^^^^^^^^ help: try: `Err(42)` diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.rs b/src/tools/clippy/tests/ui/tuple_array_conversions.rs index ca79cc104f223..772c41df090e5 100644 --- a/src/tools/clippy/tests/ui/tuple_array_conversions.rs +++ b/src/tools/clippy/tests/ui/tuple_array_conversions.rs @@ -8,15 +8,21 @@ extern crate proc_macros; fn main() { let x = [1, 2]; let x = (x[0], x[1]); + //~^ tuple_array_conversions let x = [x.0, x.1]; + //~^ tuple_array_conversions let x = &[1, 2]; let x = (x[0], x[1]); let t1: &[(u32, u32)] = &[(1, 2), (3, 4)]; let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); + //~^ tuple_array_conversions t1.iter().for_each(|&(a, b)| _ = [a, b]); + //~^ tuple_array_conversions let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect(); + //~^ tuple_array_conversions t1.iter().for_each(|&(a, b)| _ = [a, b]); + //~^ tuple_array_conversions // Do not lint let v2: Vec<[u32; 2]> = t1.iter().map(|&t| t.into()).collect(); let t3: Vec<(u32, u32)> = v2.iter().map(|&v| v.into()).collect(); @@ -55,9 +61,11 @@ fn main() { // FP #11082; needs discussion let (a, b) = (1.0f64, 2.0f64); let _: &[f64] = &[a, b]; + //~^ tuple_array_conversions // FP #11085; impossible to fix let [src, dest]: [_; 2] = [1, 2]; (src, dest); + //~^ tuple_array_conversions // FP #11100 fn issue_11100_array_to_tuple(this: [&mut i32; 2]) -> (&i32, &mut i32) { let [input, output] = this; @@ -102,7 +110,9 @@ fn msrv_too_low() { fn msrv_juust_right() { let x = [1, 2]; let x = (x[0], x[1]); + //~^ tuple_array_conversions let x = [x.0, x.1]; + //~^ tuple_array_conversions let x = &[1, 2]; let x = (x[0], x[1]); } diff --git a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr index 9e022b3cfb254..6dafb8d285d4d 100644 --- a/src/tools/clippy/tests/ui/tuple_array_conversions.stderr +++ b/src/tools/clippy/tests/ui/tuple_array_conversions.stderr @@ -9,7 +9,7 @@ LL | let x = (x[0], x[1]); = help: to override `-D warnings` add `#[allow(clippy::tuple_array_conversions)]` error: it looks like you're trying to convert a tuple to an array - --> tests/ui/tuple_array_conversions.rs:11:13 + --> tests/ui/tuple_array_conversions.rs:12:13 | LL | let x = [x.0, x.1]; | ^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let x = [x.0, x.1]; = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed error: it looks like you're trying to convert a tuple to an array - --> tests/ui/tuple_array_conversions.rs:16:53 + --> tests/ui/tuple_array_conversions.rs:18:53 | LL | let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); | ^^^^^^ @@ -25,7 +25,7 @@ LL | let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect(); = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed error: it looks like you're trying to convert a tuple to an array - --> tests/ui/tuple_array_conversions.rs:17:38 + --> tests/ui/tuple_array_conversions.rs:20:38 | LL | t1.iter().for_each(|&(a, b)| _ = [a, b]); | ^^^^^^ @@ -33,7 +33,7 @@ LL | t1.iter().for_each(|&(a, b)| _ = [a, b]); = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed error: it looks like you're trying to convert an array to a tuple - --> tests/ui/tuple_array_conversions.rs:18:55 + --> tests/ui/tuple_array_conversions.rs:22:55 | LL | let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect(); | ^^^^^^ @@ -41,7 +41,7 @@ LL | let t2: Vec<(u32, u32)> = v1.iter().map(|&[a, b]| (a, b)).collect(); = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed error: it looks like you're trying to convert a tuple to an array - --> tests/ui/tuple_array_conversions.rs:19:38 + --> tests/ui/tuple_array_conversions.rs:24:38 | LL | t1.iter().for_each(|&(a, b)| _ = [a, b]); | ^^^^^^ @@ -49,7 +49,7 @@ LL | t1.iter().for_each(|&(a, b)| _ = [a, b]); = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed error: it looks like you're trying to convert a tuple to an array - --> tests/ui/tuple_array_conversions.rs:57:22 + --> tests/ui/tuple_array_conversions.rs:63:22 | LL | let _: &[f64] = &[a, b]; | ^^^^^^ @@ -57,7 +57,7 @@ LL | let _: &[f64] = &[a, b]; = help: use `.into()` instead, or `<[T; N]>::from` if type annotations are needed error: it looks like you're trying to convert an array to a tuple - --> tests/ui/tuple_array_conversions.rs:60:5 + --> tests/ui/tuple_array_conversions.rs:67:5 | LL | (src, dest); | ^^^^^^^^^^^ @@ -65,7 +65,7 @@ LL | (src, dest); = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed error: it looks like you're trying to convert an array to a tuple - --> tests/ui/tuple_array_conversions.rs:104:13 + --> tests/ui/tuple_array_conversions.rs:112:13 | LL | let x = (x[0], x[1]); | ^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | let x = (x[0], x[1]); = help: use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed error: it looks like you're trying to convert a tuple to an array - --> tests/ui/tuple_array_conversions.rs:105:13 + --> tests/ui/tuple_array_conversions.rs:114:13 | LL | let x = [x.0, x.1]; | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/ty_fn_sig.rs b/src/tools/clippy/tests/ui/ty_fn_sig.rs index 9e2753dcb18d6..60767bfad135c 100644 --- a/src/tools/clippy/tests/ui/ty_fn_sig.rs +++ b/src/tools/clippy/tests/ui/ty_fn_sig.rs @@ -1,3 +1,4 @@ +//@ check-pass // Regression test pub fn retry(f: F) { diff --git a/src/tools/clippy/tests/ui/type_complexity.rs b/src/tools/clippy/tests/ui/type_complexity.rs index be28ee2da0cd4..89c4955c9f6f0 100644 --- a/src/tools/clippy/tests/ui/type_complexity.rs +++ b/src/tools/clippy/tests/ui/type_complexity.rs @@ -5,42 +5,46 @@ type Alias = Vec>>; // no warning here const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); -//~^ ERROR: very complex type used. Consider factoring parts into `type` definitions -//~| NOTE: `-D clippy::type-complexity` implied by `-D warnings` +//~^ type_complexity + static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); -//~^ ERROR: very complex type used. Consider factoring parts into `type` definitions +//~^ type_complexity struct S { f: Vec>>, - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity } struct Ts(Vec>>); -//~^ ERROR: very complex type used. Consider factoring parts into `type` definitions +//~^ type_complexity enum E { Tuple(Vec>>), - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity Struct { f: Vec>> }, - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity } impl S { const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity + fn impl_method(&self, p: Vec>>) {} - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity } trait T { const A: Vec>>; - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity + type B = Vec>>; - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity + fn method(&self, p: Vec>>); - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity + fn def_method(&self, p: Vec>>) {} - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity } // Should not warn since there is likely no way to simplify this (#1013) @@ -53,16 +57,17 @@ impl T for () { } fn test1() -> Vec>> { - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity + vec![] } fn test2(_x: Vec>>) {} -//~^ ERROR: very complex type used. Consider factoring parts into `type` definitions +//~^ type_complexity fn test3() { let _y: Vec>> = vec![]; - //~^ ERROR: very complex type used. Consider factoring parts into `type` definitions + //~^ type_complexity } #[repr(C)] diff --git a/src/tools/clippy/tests/ui/type_complexity.stderr b/src/tools/clippy/tests/ui/type_complexity.stderr index 9e27899e4f904..181e04d38e9a4 100644 --- a/src/tools/clippy/tests/ui/type_complexity.stderr +++ b/src/tools/clippy/tests/ui/type_complexity.stderr @@ -44,49 +44,49 @@ LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0)))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:31:30 + --> tests/ui/type_complexity.rs:32:30 | LL | fn impl_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:36:14 + --> tests/ui/type_complexity.rs:37:14 | LL | const A: Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:38:14 + --> tests/ui/type_complexity.rs:40:14 | LL | type B = Vec>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:40:25 + --> tests/ui/type_complexity.rs:43:25 | LL | fn method(&self, p: Vec>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:42:29 + --> tests/ui/type_complexity.rs:46:29 | LL | fn def_method(&self, p: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:55:15 + --> tests/ui/type_complexity.rs:59:15 | LL | fn test1() -> Vec>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:60:14 + --> tests/ui/type_complexity.rs:65:14 | LL | fn test2(_x: Vec>>) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: very complex type used. Consider factoring parts into `type` definitions - --> tests/ui/type_complexity.rs:64:13 + --> tests/ui/type_complexity.rs:69:13 | LL | let _y: Vec>> = vec![]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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 3656043700fa9..2e241c36b34a1 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box.fixed +++ b/src/tools/clippy/tests/ui/type_id_on_box.fixed @@ -29,7 +29,7 @@ fn main() { let any_box: Box = Box::new(0usize); let _ = (*any_box).type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box // Don't lint. We explicitly say "do this instead" if this is intentional let _ = TypeId::of::>(); @@ -38,18 +38,18 @@ fn main() { // 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(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box let b = existential(); let _ = b.type_id(); // Don't let b: Box = Box::new(1); let _ = (*b).type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box let b: SomeBox = Box::new(0usize); let _ = (*b).type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box 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 4bd9e73f2da02..46fac632894c3 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box.rs +++ b/src/tools/clippy/tests/ui/type_id_on_box.rs @@ -29,7 +29,7 @@ fn main() { let any_box: Box = Box::new(0usize); let _ = any_box.type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box // Don't lint. We explicitly say "do this instead" if this is intentional let _ = TypeId::of::>(); @@ -38,18 +38,18 @@ fn main() { // 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(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box let b = existential(); let _ = b.type_id(); // Don't let b: Box = Box::new(1); let _ = b.type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box let b: SomeBox = Box::new(0usize); let _ = b.type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box 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_unfixable.rs b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs index 67e398e604b4b..58d245d56aa59 100644 --- a/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs +++ b/src/tools/clippy/tests/ui/type_id_on_box_unfixable.rs @@ -23,9 +23,9 @@ fn main() { // could) let b: Box = Box::new(1); let _ = b.type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box let b: Box = Box::new(1); let _ = b.type_id(); - //~^ ERROR: calling `.type_id()` on + //~^ type_id_on_box } diff --git a/src/tools/clippy/tests/ui/unbuffered_bytes.rs b/src/tools/clippy/tests/ui/unbuffered_bytes.rs new file mode 100644 index 0000000000000..87199c7e335df --- /dev/null +++ b/src/tools/clippy/tests/ui/unbuffered_bytes.rs @@ -0,0 +1,41 @@ +#![warn(clippy::unbuffered_bytes)] + +use std::fs::File; +use std::io::{BufReader, Cursor, Read, Stdin, stdin}; +use std::net::TcpStream; + +fn main() { + // File is not buffered, should complain + let file = File::open("./bytes.txt").unwrap(); + file.bytes(); + //~^ unbuffered_bytes + + // TcpStream is not buffered, should complain + let tcp_stream: TcpStream = TcpStream::connect("127.0.0.1:80").unwrap(); + tcp_stream.bytes(); + //~^ unbuffered_bytes + + // BufReader is buffered, should not complain + let file = BufReader::new(File::open("./bytes.txt").unwrap()); + file.bytes(); + + // Cursor is buffered, should not complain + let cursor = Cursor::new(Vec::new()); + cursor.bytes(); + + // Stdio would acquire the lock for every byte, should complain + let s: Stdin = stdin(); + s.bytes(); + //~^ unbuffered_bytes + + // But when locking stdin, this is fine so should not complain + let s: Stdin = stdin(); + let s = s.lock(); + s.bytes(); +} + +fn use_read(r: R) { + // Callers of `use_read` may choose a `R` that is not buffered + r.bytes(); + //~^ unbuffered_bytes +} diff --git a/src/tools/clippy/tests/ui/unbuffered_bytes.stderr b/src/tools/clippy/tests/ui/unbuffered_bytes.stderr new file mode 100644 index 0000000000000..7505eb9e363a5 --- /dev/null +++ b/src/tools/clippy/tests/ui/unbuffered_bytes.stderr @@ -0,0 +1,36 @@ +error: calling .bytes() is very inefficient when data is not in memory + --> tests/ui/unbuffered_bytes.rs:10:5 + | +LL | file.bytes(); + | ^^^^^^^^^^^^ + | + = help: consider using `BufReader` + = note: `-D clippy::unbuffered-bytes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unbuffered_bytes)]` + +error: calling .bytes() is very inefficient when data is not in memory + --> tests/ui/unbuffered_bytes.rs:15:5 + | +LL | tcp_stream.bytes(); + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider using `BufReader` + +error: calling .bytes() is very inefficient when data is not in memory + --> tests/ui/unbuffered_bytes.rs:28:5 + | +LL | s.bytes(); + | ^^^^^^^^^ + | + = help: consider using `BufReader` + +error: calling .bytes() is very inefficient when data is not in memory + --> tests/ui/unbuffered_bytes.rs:39:5 + | +LL | r.bytes(); + | ^^^^^^^^^ + | + = help: consider using `BufReader` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed index a0c3330d1777a..bddffe44ac4d0 100644 --- a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed +++ b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed @@ -7,10 +7,14 @@ fn main() { let second = Duration::from_secs(3); let _ = _first.checked_sub(second).unwrap(); + //~^ unchecked_duration_subtraction let _ = Instant::now().checked_sub(Duration::from_secs(5)).unwrap(); + //~^ unchecked_duration_subtraction let _ = _first.checked_sub(Duration::from_secs(5)).unwrap(); + //~^ unchecked_duration_subtraction let _ = Instant::now().checked_sub(second).unwrap(); + //~^ unchecked_duration_subtraction } diff --git a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs index fff1d13720d98..bb0f712396424 100644 --- a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs +++ b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs @@ -7,10 +7,14 @@ fn main() { let second = Duration::from_secs(3); let _ = _first - second; + //~^ unchecked_duration_subtraction let _ = Instant::now() - Duration::from_secs(5); + //~^ unchecked_duration_subtraction let _ = _first - Duration::from_secs(5); + //~^ unchecked_duration_subtraction let _ = Instant::now() - second; + //~^ unchecked_duration_subtraction } diff --git a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr index b5e9bab86b478..be291c320e689 100644 --- a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr +++ b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.stderr @@ -8,19 +8,19 @@ LL | let _ = _first - second; = help: to override `-D warnings` add `#[allow(clippy::unchecked_duration_subtraction)]` error: unchecked subtraction of a 'Duration' from an 'Instant' - --> tests/ui/unchecked_duration_subtraction.rs:11:13 + --> tests/ui/unchecked_duration_subtraction.rs:12:13 | LL | let _ = Instant::now() - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(Duration::from_secs(5)).unwrap()` error: unchecked subtraction of a 'Duration' from an 'Instant' - --> tests/ui/unchecked_duration_subtraction.rs:13:13 + --> tests/ui/unchecked_duration_subtraction.rs:15:13 | LL | let _ = _first - Duration::from_secs(5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `_first.checked_sub(Duration::from_secs(5)).unwrap()` error: unchecked subtraction of a 'Duration' from an 'Instant' - --> tests/ui/unchecked_duration_subtraction.rs:15:13 + --> tests/ui/unchecked_duration_subtraction.rs:18:13 | LL | let _ = Instant::now() - second; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Instant::now().checked_sub(second).unwrap()` diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.rs b/src/tools/clippy/tests/ui/unconditional_recursion.rs index b8476a7088a10..d9f4c07dc9025 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.rs +++ b/src/tools/clippy/tests/ui/unconditional_recursion.rs @@ -15,11 +15,13 @@ enum Foo { impl PartialEq for Foo { fn ne(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + self != other } fn eq(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + self == other } } @@ -31,9 +33,11 @@ enum Foo2 { impl PartialEq for Foo2 { fn ne(&self, other: &Self) -> bool { + //~^ unconditional_recursion self != &Foo2::B // no error here } fn eq(&self, other: &Self) -> bool { + //~^ unconditional_recursion self == &Foo2::B // no error here } } @@ -45,11 +49,14 @@ enum Foo3 { impl PartialEq for Foo3 { fn ne(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + //~| ERROR: function cannot return without recursing self.ne(other) } fn eq(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + //~| ERROR: function cannot return without recursing + self.eq(other) } } @@ -93,11 +100,13 @@ struct S; // Check the order doesn't matter. impl PartialEq for S { fn ne(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + other != self } fn eq(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + other == self } } @@ -107,12 +116,16 @@ struct S2; // Check that if the same element is compared, it's also triggering the lint. impl PartialEq for S2 { fn ne(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + other != other + //~^ eq_op } fn eq(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + other == other + //~^ eq_op } } @@ -120,12 +133,16 @@ struct S3; impl PartialEq for S3 { fn ne(&self, _other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + self != self + //~^ eq_op } fn eq(&self, _other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + self == self + //~^ eq_op } } @@ -152,7 +169,8 @@ macro_rules! impl_partial_eq { ($ty:ident) => { impl PartialEq for $ty { fn eq(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + self == other } } @@ -181,7 +199,8 @@ struct S7<'a> { impl<'a> PartialEq for S7<'a> { fn eq(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + let mine = &self.field; let theirs = &other.field; mine == theirs @@ -250,7 +269,8 @@ impl std::default::Default for S12 { impl S12 { fn new() -> Self { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + Self::default() } @@ -289,7 +309,8 @@ struct S15<'a> { impl PartialEq for S15<'_> { fn eq(&self, other: &Self) -> bool { - //~^ ERROR: function cannot return without recursing + //~^ unconditional_recursion + let mine = &self.field; let theirs = &other.field; mine.eq(theirs) @@ -360,6 +381,7 @@ struct BadFromTy1<'a>(&'a ()); struct BadIntoTy1<'b>(&'b ()); impl<'a> From> for BadIntoTy1<'static> { fn from(f: BadFromTy1<'a>) -> Self { + //~^ unconditional_recursion f.into() } } @@ -369,6 +391,7 @@ struct BadFromTy2<'a>(&'a ()); struct BadIntoTy2<'b>(&'b ()); impl<'a> From> for BadIntoTy2<'static> { fn from(f: BadFromTy2<'a>) -> Self { + //~^ unconditional_recursion Into::into(f) } } diff --git a/src/tools/clippy/tests/ui/unconditional_recursion.stderr b/src/tools/clippy/tests/ui/unconditional_recursion.stderr index 6a0078ee09068..c6eaa6a0775c1 100644 --- a/src/tools/clippy/tests/ui/unconditional_recursion.stderr +++ b/src/tools/clippy/tests/ui/unconditional_recursion.stderr @@ -1,9 +1,9 @@ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:47:5 + --> tests/ui/unconditional_recursion.rs:51:5 | LL | fn ne(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | +... LL | self.ne(other) | -------------- recursive call site | @@ -12,18 +12,18 @@ LL | self.ne(other) = help: to override `-D warnings` add `#[allow(unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:51:5 + --> tests/ui/unconditional_recursion.rs:56:5 | LL | fn eq(&self, other: &Self) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing -LL | +... LL | self.eq(other) | -------------- recursive call site | = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:216:5 + --> tests/ui/unconditional_recursion.rs:235:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -34,7 +34,7 @@ LL | self.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:226:5 + --> tests/ui/unconditional_recursion.rs:245:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -45,7 +45,7 @@ LL | x.to_string() = help: a `loop` may express intention better if this is on purpose error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:237:5 + --> tests/ui/unconditional_recursion.rs:256:5 | LL | fn to_string(&self) -> String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -60,12 +60,13 @@ error: function cannot return without recursing | LL | / fn ne(&self, other: &Self) -> bool { LL | | +LL | | LL | | self != other LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:19:9 + --> tests/ui/unconditional_recursion.rs:20:9 | LL | self != other | ^^^^^^^^^^^^^ @@ -73,125 +74,132 @@ LL | self != other = help: to override `-D warnings` add `#[allow(clippy::unconditional_recursion)]` error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:21:5 + --> tests/ui/unconditional_recursion.rs:22:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | +LL | | LL | | self == other LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:23:9 + --> tests/ui/unconditional_recursion.rs:25:9 | LL | self == other | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:33:5 + --> tests/ui/unconditional_recursion.rs:35:5 | LL | / fn ne(&self, other: &Self) -> bool { +LL | | LL | | self != &Foo2::B // no error here LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:34:9 + --> tests/ui/unconditional_recursion.rs:37:9 | LL | self != &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:36:5 + --> tests/ui/unconditional_recursion.rs:39:5 | LL | / fn eq(&self, other: &Self) -> bool { +LL | | LL | | self == &Foo2::B // no error here LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:37:9 + --> tests/ui/unconditional_recursion.rs:41:9 | LL | self == &Foo2::B // no error here | ^^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:47:5 + --> tests/ui/unconditional_recursion.rs:51:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | +LL | | LL | | self.ne(other) LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:49:9 + --> tests/ui/unconditional_recursion.rs:54:9 | LL | self.ne(other) | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:51:5 + --> tests/ui/unconditional_recursion.rs:56:5 | LL | / fn eq(&self, other: &Self) -> bool { -LL | | -LL | | self.eq(other) +... | LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:53:9 + --> tests/ui/unconditional_recursion.rs:60:9 | LL | self.eq(other) | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:95:5 + --> tests/ui/unconditional_recursion.rs:102:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | +LL | | LL | | other != self LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:97:9 + --> tests/ui/unconditional_recursion.rs:105:9 | LL | other != self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:99:5 + --> tests/ui/unconditional_recursion.rs:107:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | +LL | | LL | | other == self LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:101:9 + --> tests/ui/unconditional_recursion.rs:110:9 | LL | other == self | ^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:109:5 + --> tests/ui/unconditional_recursion.rs:118:5 | LL | / fn ne(&self, other: &Self) -> bool { LL | | +LL | | LL | | other != other +LL | | LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:111:9 + --> tests/ui/unconditional_recursion.rs:121:9 | LL | other != other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:111:9 + --> tests/ui/unconditional_recursion.rs:121:9 | LL | other != other | ^^^^^^^^^^^^^^ @@ -199,73 +207,80 @@ LL | other != other = note: `#[deny(clippy::eq_op)]` on by default error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:113:5 + --> tests/ui/unconditional_recursion.rs:124:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | +LL | | LL | | other == other +LL | | LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:115:9 + --> tests/ui/unconditional_recursion.rs:127:9 | LL | other == other | ^^^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:115:9 + --> tests/ui/unconditional_recursion.rs:127:9 | LL | other == other | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:122:5 + --> tests/ui/unconditional_recursion.rs:135:5 | LL | / fn ne(&self, _other: &Self) -> bool { LL | | +LL | | LL | | self != self +LL | | LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:124:9 + --> tests/ui/unconditional_recursion.rs:138:9 | LL | self != self | ^^^^^^^^^^^^ error: equal expressions as operands to `!=` - --> tests/ui/unconditional_recursion.rs:124:9 + --> tests/ui/unconditional_recursion.rs:138:9 | LL | self != self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:126:5 + --> tests/ui/unconditional_recursion.rs:141:5 | LL | / fn eq(&self, _other: &Self) -> bool { LL | | +LL | | LL | | self == self +LL | | LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:128:9 + --> tests/ui/unconditional_recursion.rs:144:9 | LL | self == self | ^^^^^^^^^^^^ error: equal expressions as operands to `==` - --> tests/ui/unconditional_recursion.rs:128:9 + --> tests/ui/unconditional_recursion.rs:144:9 | LL | self == self | ^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:154:13 + --> tests/ui/unconditional_recursion.rs:171:13 | LL | / fn eq(&self, other: &Self) -> bool { LL | | +LL | | LL | | self == other LL | | } | |_____________^ @@ -274,7 +289,7 @@ LL | impl_partial_eq!(S5); | -------------------- in this macro invocation | note: recursive call site - --> tests/ui/unconditional_recursion.rs:156:17 + --> tests/ui/unconditional_recursion.rs:174:17 | LL | self == other | ^^^^^^^^^^^^^ @@ -284,10 +299,11 @@ LL | impl_partial_eq!(S5); = note: this error originates in the macro `impl_partial_eq` (in Nightly builds, run with -Z macro-backtrace for more info) error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:183:5 + --> tests/ui/unconditional_recursion.rs:201:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | +LL | | LL | | let mine = &self.field; LL | | let theirs = &other.field; LL | | mine == theirs @@ -295,31 +311,33 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:187:9 + --> tests/ui/unconditional_recursion.rs:206:9 | LL | mine == theirs | ^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:252:5 + --> tests/ui/unconditional_recursion.rs:271:5 | LL | / fn new() -> Self { LL | | +LL | | LL | | Self::default() LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:254:9 + --> tests/ui/unconditional_recursion.rs:274:9 | LL | Self::default() | ^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:291:5 + --> tests/ui/unconditional_recursion.rs:311:5 | LL | / fn eq(&self, other: &Self) -> bool { LL | | +LL | | LL | | let mine = &self.field; LL | | let theirs = &other.field; LL | | mine.eq(theirs) @@ -327,35 +345,37 @@ LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:295:9 + --> tests/ui/unconditional_recursion.rs:316:9 | LL | mine.eq(theirs) | ^^^^^^^^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:362:5 + --> tests/ui/unconditional_recursion.rs:383:5 | LL | / fn from(f: BadFromTy1<'a>) -> Self { +LL | | LL | | f.into() LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:363:9 + --> tests/ui/unconditional_recursion.rs:385:9 | LL | f.into() | ^^^^^^^^ error: function cannot return without recursing - --> tests/ui/unconditional_recursion.rs:371:5 + --> tests/ui/unconditional_recursion.rs:393:5 | LL | / fn from(f: BadFromTy2<'a>) -> Self { +LL | | LL | | Into::into(f) LL | | } | |_____^ | note: recursive call site - --> tests/ui/unconditional_recursion.rs:372:9 + --> tests/ui/unconditional_recursion.rs:395:9 | LL | Into::into(f) | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unicode.fixed b/src/tools/clippy/tests/ui/unicode.fixed index f9efb4ec34c6c..9234b440d9648 100644 --- a/src/tools/clippy/tests/ui/unicode.fixed +++ b/src/tools/clippy/tests/ui/unicode.fixed @@ -3,16 +3,20 @@ #[warn(clippy::invisible_characters)] fn zero() { print!("Here >\u{200B}< is a ZWS, and \u{200B}another"); + //~^ invisible_characters print!("This\u{200B}is\u{200B}fine"); print!("Here >\u{AD}< is a SHY, and \u{AD}another"); + //~^ invisible_characters print!("This\u{ad}is\u{ad}fine"); print!("Here >\u{2060}< is a WJ, and \u{2060}another"); + //~^ invisible_characters print!("This\u{2060}is\u{2060}fine"); } #[warn(clippy::unicode_not_nfc)] fn canon() { print!("̀àh?"); + //~^ unicode_not_nfc print!("a\u{0300}h?"); // also ok } @@ -21,13 +25,16 @@ mod non_ascii_literal { fn uni() { print!("\u{dc}ben!"); + //~^ non_ascii_literal print!("\u{DC}ben!"); // this is ok } // issue 8013 fn single_quote() { const _EMPTY_BLOCK: char = '\u{25b1}'; + //~^ non_ascii_literal const _FULL_BLOCK: char = '\u{25b0}'; + //~^ non_ascii_literal } #[test] @@ -48,6 +55,7 @@ mod non_ascii_literal { #[test] fn denied() { let _ = "\u{60b2}\u{3057}\u{3044}\u{304b}\u{306a}\u{3001}\u{3053}\u{3053}\u{306b}\u{65e5}\u{672c}\u{8a9e}\u{3092}\u{66f8}\u{304f}\u{3053}\u{3068}\u{306f}\u{3067}\u{304d}\u{306a}\u{3044}\u{3002}"; + //~^ non_ascii_literal } } } diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs index bba613e228ed7..ada8bac8e0492 100644 --- a/src/tools/clippy/tests/ui/unicode.rs +++ b/src/tools/clippy/tests/ui/unicode.rs @@ -3,16 +3,20 @@ #[warn(clippy::invisible_characters)] fn zero() { print!("Here >​< is a ZWS, and ​another"); + //~^ invisible_characters print!("This\u{200B}is\u{200B}fine"); print!("Here >­< is a SHY, and ­another"); + //~^ invisible_characters print!("This\u{ad}is\u{ad}fine"); print!("Here >⁠< is a WJ, and ⁠another"); + //~^ invisible_characters print!("This\u{2060}is\u{2060}fine"); } #[warn(clippy::unicode_not_nfc)] fn canon() { print!("̀àh?"); + //~^ unicode_not_nfc print!("a\u{0300}h?"); // also ok } @@ -21,13 +25,16 @@ mod non_ascii_literal { fn uni() { print!("Üben!"); + //~^ non_ascii_literal print!("\u{DC}ben!"); // this is ok } // issue 8013 fn single_quote() { const _EMPTY_BLOCK: char = '▱'; + //~^ non_ascii_literal const _FULL_BLOCK: char = '▰'; + //~^ non_ascii_literal } #[test] @@ -48,6 +55,7 @@ mod non_ascii_literal { #[test] fn denied() { let _ = "悲しいかな、ここに日本語を書くことはできない。"; + //~^ non_ascii_literal } } } diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr index b004493300eed..c761ec89602fc 100644 --- a/src/tools/clippy/tests/ui/unicode.stderr +++ b/src/tools/clippy/tests/ui/unicode.stderr @@ -8,19 +8,19 @@ LL | print!("Here >​< is a ZWS, and ​another"); = help: to override `-D warnings` add `#[allow(clippy::invisible_characters)]` error: invisible character detected - --> tests/ui/unicode.rs:7:12 + --> tests/ui/unicode.rs:8:12 | LL | print!("Here >­< is a SHY, and ­another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{AD}< is a SHY, and \u{AD}another"` error: invisible character detected - --> tests/ui/unicode.rs:9:12 + --> tests/ui/unicode.rs:11:12 | LL | print!("Here >⁠< is a WJ, and ⁠another"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{2060}< is a WJ, and \u{2060}another"` error: non-NFC Unicode sequence detected - --> tests/ui/unicode.rs:15:12 + --> tests/ui/unicode.rs:18:12 | LL | print!("̀àh?"); | ^^^^^ help: consider replacing the string with: `"̀àh?"` @@ -29,37 +29,37 @@ LL | print!("̀àh?"); = help: to override `-D warnings` add `#[allow(clippy::unicode_not_nfc)]` error: literal non-ASCII character detected - --> tests/ui/unicode.rs:23:16 + --> tests/ui/unicode.rs:27:16 | LL | print!("Üben!"); | ^^^^^^^ help: consider replacing the string with: `"\u{dc}ben!"` | note: the lint level is defined here - --> tests/ui/unicode.rs:20:13 + --> tests/ui/unicode.rs:24:13 | LL | #![deny(clippy::non_ascii_literal)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: literal non-ASCII character detected - --> tests/ui/unicode.rs:29:36 + --> tests/ui/unicode.rs:34:36 | LL | const _EMPTY_BLOCK: char = '▱'; | ^^^ help: consider replacing the string with: `'\u{25b1}'` error: literal non-ASCII character detected - --> tests/ui/unicode.rs:30:35 + --> tests/ui/unicode.rs:36:35 | LL | const _FULL_BLOCK: char = '▰'; | ^^^ help: consider replacing the string with: `'\u{25b0}'` error: literal non-ASCII character detected - --> tests/ui/unicode.rs:50:21 + --> tests/ui/unicode.rs:57:21 | LL | let _ = "悲しいかな、ここに日本語を書くことはできない。"; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"\u{60b2}\u{3057}\u{3044}\u{304b}\u{306a}\u{3001}\u{3053}\u{3053}\u{306b}\u{65e5}\u{672c}\u{8a9e}\u{3092}\u{66f8}\u{304f}\u{3053}\u{3068}\u{306f}\u{3067}\u{304d}\u{306a}\u{3044}\u{3002}"` | note: the lint level is defined here - --> tests/ui/unicode.rs:39:17 + --> tests/ui/unicode.rs:46:17 | LL | #![deny(clippy::non_ascii_literal)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/uninhabited_references.rs b/src/tools/clippy/tests/ui/uninhabited_references.rs index 3569366ed0560..9b3616ad51871 100644 --- a/src/tools/clippy/tests/ui/uninhabited_references.rs +++ b/src/tools/clippy/tests/ui/uninhabited_references.rs @@ -3,13 +3,16 @@ #![feature(never_type)] fn ret_uninh_ref() -> &'static std::convert::Infallible { + //~^ uninhabited_references unsafe { std::mem::transmute(&()) } } macro_rules! ret_something { ($name:ident, $ty:ty) => { fn $name(x: &$ty) -> &$ty { + //~^ uninhabited_references &*x + //~^ uninhabited_references } }; } @@ -20,4 +23,5 @@ ret_something!(id_never, !); fn main() { let x = ret_uninh_ref(); let _ = *x; + //~^ uninhabited_references } diff --git a/src/tools/clippy/tests/ui/uninhabited_references.stderr b/src/tools/clippy/tests/ui/uninhabited_references.stderr index 8c9b206f42967..ac05ab5bb4d40 100644 --- a/src/tools/clippy/tests/ui/uninhabited_references.stderr +++ b/src/tools/clippy/tests/ui/uninhabited_references.stderr @@ -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:11:30 + --> tests/ui/uninhabited_references.rs:12: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:12:14 + --> tests/ui/uninhabited_references.rs:14: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:22:13 + --> tests/ui/uninhabited_references.rs:25:13 | LL | let _ = *x; | ^^ diff --git a/src/tools/clippy/tests/ui/uninit.rs b/src/tools/clippy/tests/ui/uninit.rs index 10a4c22b5b91c..f74248c8aea80 100644 --- a/src/tools/clippy/tests/ui/uninit.rs +++ b/src/tools/clippy/tests/ui/uninit.rs @@ -10,8 +10,7 @@ union MyOwnMaybeUninit { fn main() { let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; - //~^ ERROR: this call for this type may be undefined behavior - //~| NOTE: `#[deny(clippy::uninit_assumed_init)]` on by default + //~^ uninit_assumed_init // This is OK, because ZSTs do not contain data. let _: () = unsafe { MaybeUninit::uninit().assume_init() }; @@ -33,7 +32,7 @@ fn main() { // Was a false negative. let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; - //~^ ERROR: this call for this type may be undefined behavior + //~^ uninit_assumed_init polymorphic::<()>(); polymorphic_maybe_uninit_array::<10>(); @@ -42,7 +41,7 @@ fn main() { fn polymorphic() { // We are conservative around polymorphic types. let _: T = unsafe { MaybeUninit::uninit().assume_init() }; - //~^ ERROR: this call for this type may be undefined behavior + //~^ uninit_assumed_init } fn polymorphic_maybe_uninit_array() { diff --git a/src/tools/clippy/tests/ui/uninit.stderr b/src/tools/clippy/tests/ui/uninit.stderr index 81577fe3fd477..d6f54dd61ca0e 100644 --- a/src/tools/clippy/tests/ui/uninit.stderr +++ b/src/tools/clippy/tests/ui/uninit.stderr @@ -7,13 +7,13 @@ LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; = note: `#[deny(clippy::uninit_assumed_init)]` on by default error: this call for this type may be undefined behavior - --> tests/ui/uninit.rs:35:29 + --> tests/ui/uninit.rs:34:29 | LL | let _: usize = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this call for this type may be undefined behavior - --> tests/ui/uninit.rs:44:29 + --> tests/ui/uninit.rs:43:29 | LL | let _: T = unsafe { MaybeUninit::uninit().assume_init() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs index 464f88140bdba..a48397137992f 100644 --- a/src/tools/clippy/tests/ui/uninit_vec.rs +++ b/src/tools/clippy/tests/ui/uninit_vec.rs @@ -16,40 +16,46 @@ union MyOwnMaybeUninit { // https://github.com/rust-lang/rust/issues/119620 unsafe fn requires_paramenv() { let mut vec = Vec::>::with_capacity(1); + //~^ uninit_vec vec.set_len(1); } fn main() { // with_capacity() -> set_len() should be detected let mut vec: Vec = Vec::with_capacity(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates uninitial + //~^ uninit_vec + unsafe { vec.set_len(200); } // reserve() -> set_len() should be detected vec.reserve(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates uninitial + //~^ uninit_vec + unsafe { vec.set_len(200); } // new() -> set_len() should be detected let mut vec: Vec = Vec::new(); - //~^ ERROR: calling `set_len()` on empty `Vec` creates out-of-bound values + //~^ uninit_vec + unsafe { vec.set_len(200); } // default() -> set_len() should be detected let mut vec: Vec = Default::default(); - //~^ ERROR: calling `set_len()` on empty `Vec` creates out-of-bound values + //~^ uninit_vec + unsafe { vec.set_len(200); } let mut vec: Vec = Vec::default(); - //~^ ERROR: calling `set_len()` on empty `Vec` creates out-of-bound values + //~^ uninit_vec + unsafe { vec.set_len(200); } @@ -57,16 +63,19 @@ fn main() { // test when both calls are enclosed in the same unsafe block unsafe { let mut vec: Vec = Vec::with_capacity(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates unini + //~^ uninit_vec + vec.set_len(200); vec.reserve(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates unini + //~^ uninit_vec + vec.set_len(200); } let mut vec: Vec = Vec::with_capacity(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates uninitial + //~^ uninit_vec + unsafe { // test the case where there are other statements in the following unsafe block vec.set_len(200); @@ -76,13 +85,15 @@ fn main() { // handle vec stored in the field of a struct let mut my_vec = MyVec::default(); my_vec.vec.reserve(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates uninitial + //~^ uninit_vec + unsafe { my_vec.vec.set_len(200); } my_vec.vec = Vec::with_capacity(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates uninitial + //~^ uninit_vec + unsafe { my_vec.vec.set_len(200); } @@ -137,7 +148,8 @@ fn main() { fn polymorphic() { // We are conservative around polymorphic types. let mut vec: Vec = Vec::with_capacity(1000); - //~^ ERROR: calling `set_len()` immediately after reserving a buffer creates unini + //~^ uninit_vec + unsafe { vec.set_len(10); } @@ -165,6 +177,7 @@ fn main() { let mut vec: Vec> = Vec::with_capacity(1); //~^ uninit_vec + unsafe { vec.set_len(1); } @@ -178,6 +191,7 @@ fn main() { // Enums can have a discriminant that can't be uninit, so this should still warn let mut vec: Vec> = Vec::with_capacity(1); //~^ uninit_vec + unsafe { vec.set_len(1); } diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr index e7c81cf792f23..7ff6140a2c3ec 100644 --- a/src/tools/clippy/tests/ui/uninit_vec.stderr +++ b/src/tools/clippy/tests/ui/uninit_vec.stderr @@ -3,6 +3,7 @@ error: calling `set_len()` immediately after reserving a buffer creates uninitia | LL | let mut vec = Vec::>::with_capacity(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | LL | vec.set_len(1); | ^^^^^^^^^^^^^^ | @@ -11,7 +12,7 @@ LL | vec.set_len(1); = help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:24:5 + --> tests/ui/uninit_vec.rs:25:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -22,7 +23,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:31:5 + --> tests/ui/uninit_vec.rs:33:5 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ @@ -33,7 +34,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> tests/ui/uninit_vec.rs:38:5 + --> tests/ui/uninit_vec.rs:41:5 | LL | let mut vec: Vec = Vec::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -42,7 +43,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> tests/ui/uninit_vec.rs:45:5 + --> tests/ui/uninit_vec.rs:49:5 | LL | let mut vec: Vec = Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -51,7 +52,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` on empty `Vec` creates out-of-bound values - --> tests/ui/uninit_vec.rs:51:5 + --> tests/ui/uninit_vec.rs:56:5 | LL | let mut vec: Vec = Vec::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +61,7 @@ LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:68:5 + --> tests/ui/uninit_vec.rs:76:5 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -71,7 +72,7 @@ LL | vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:78:5 + --> tests/ui/uninit_vec.rs:87:5 | LL | my_vec.vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -82,7 +83,7 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:84:5 + --> tests/ui/uninit_vec.rs:94:5 | LL | my_vec.vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,29 +94,29 @@ LL | my_vec.vec.set_len(200); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:59:9 + --> tests/ui/uninit_vec.rs:65:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | +... LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ | = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:63:9 + --> tests/ui/uninit_vec.rs:70:9 | LL | vec.reserve(1000); | ^^^^^^^^^^^^^^^^^^ -LL | +... LL | vec.set_len(200); | ^^^^^^^^^^^^^^^^ | = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:139:9 + --> tests/ui/uninit_vec.rs:150:9 | LL | let mut vec: Vec = Vec::with_capacity(1000); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -126,7 +127,7 @@ LL | vec.set_len(10); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:166:9 + --> tests/ui/uninit_vec.rs:178:9 | LL | let mut vec: Vec> = Vec::with_capacity(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -137,7 +138,7 @@ LL | vec.set_len(1); = help: initialize the buffer or wrap the content in `MaybeUninit` error: calling `set_len()` immediately after reserving a buffer creates uninitialized values - --> tests/ui/uninit_vec.rs:179:9 + --> tests/ui/uninit_vec.rs:192:9 | LL | let mut vec: Vec> = Vec::with_capacity(1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed index 111a2e1987c83..7b609d9163a9c 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed @@ -43,75 +43,141 @@ fn tester(fn_arg: i32) { let _: &[u8; 3] = b" "; // <- println!("val='{local_i32}'"); + //~^ uninlined_format_args println!("val='{local_i32}'"); // 3 spaces + // + //~^^ uninlined_format_args println!("val='{local_i32}'"); // tab + // + //~^^ uninlined_format_args println!("val='{local_i32}'"); // space+tab + // + //~^^ uninlined_format_args println!("val='{local_i32}'"); // tab+space + // + //~^^ uninlined_format_args println!( + //~^ uninlined_format_args "val='{local_i32}'" ); println!("{local_i32}"); + //~^ uninlined_format_args println!("{fn_arg}"); + //~^ uninlined_format_args println!("{local_i32:?}"); + //~^ uninlined_format_args println!("{local_i32:#?}"); + //~^ uninlined_format_args println!("{local_i32:4}"); + //~^ uninlined_format_args println!("{local_i32:04}"); + //~^ uninlined_format_args println!("{local_i32:<3}"); + //~^ uninlined_format_args println!("{local_i32:#010x}"); + //~^ uninlined_format_args println!("{local_f64:.1}"); + //~^ uninlined_format_args println!("Hello {} is {:.*}", "x", local_i32, local_f64); println!("Hello {} is {:.*}", local_i32, 5, local_f64); println!("Hello {} is {2:.*}", local_i32, 5, local_f64); println!("{local_i32} {local_f64}"); + //~^ uninlined_format_args println!("{}, {}", local_i32, local_opt.unwrap()); println!("{val}"); + //~^ uninlined_format_args println!("{val}"); + //~^ uninlined_format_args println!("{} {1}", local_i32, 42); println!("val='{local_i32}'"); + //~^ uninlined_format_args println!("val='{local_i32}'"); + //~^ uninlined_format_args println!("val='{local_i32}'"); + //~^ uninlined_format_args println!("val='{fn_arg}'"); + //~^ uninlined_format_args println!("{local_i32}"); + //~^ uninlined_format_args println!("{local_i32:?}"); + //~^ uninlined_format_args println!("{local_i32:#?}"); + //~^ uninlined_format_args println!("{local_i32:04}"); + //~^ uninlined_format_args println!("{local_i32:<3}"); + //~^ uninlined_format_args println!("{local_i32:#010x}"); + //~^ uninlined_format_args println!("{local_f64:.1}"); + //~^ uninlined_format_args println!("{local_i32} {local_i32}"); + //~^ uninlined_format_args println!("{local_f64} {local_i32} {local_i32} {local_f64}"); + //~^ uninlined_format_args println!("{local_i32} {local_f64}"); + //~^ uninlined_format_args println!("{local_f64} {local_i32}"); + //~^ uninlined_format_args println!("{local_f64} {local_i32} {local_f64} {local_i32}"); + //~^ uninlined_format_args println!("{1} {0}", "str", local_i32); println!("{local_i32}"); + //~^ uninlined_format_args println!("{local_i32:width$}"); + //~^ uninlined_format_args println!("{local_i32:width$}"); + //~^ uninlined_format_args println!("{local_i32:.prec$}"); + //~^ uninlined_format_args println!("{local_i32:.prec$}"); + //~^ uninlined_format_args println!("{val:val$}"); + //~^ uninlined_format_args println!("{val:val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{val:val$.val$}"); + //~^ uninlined_format_args println!("{width:width$}"); + //~^ uninlined_format_args println!("{local_i32:width$}"); + //~^ uninlined_format_args println!("{width:width$}"); + //~^ uninlined_format_args println!("{local_i32:width$}"); + //~^ uninlined_format_args println!("{prec:.prec$}"); + //~^ uninlined_format_args println!("{local_i32:.prec$}"); + //~^ uninlined_format_args println!("{prec:.prec$}"); + //~^ uninlined_format_args println!("{local_i32:.prec$}"); + //~^ uninlined_format_args println!("{width:width$.prec$}"); + //~^ uninlined_format_args println!("{width:width$.prec$}"); + //~^ uninlined_format_args println!("{local_f64:width$.prec$}"); + //~^ uninlined_format_args println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); + //~^ uninlined_format_args println!( + //~^ uninlined_format_args "{local_i32:width$.prec$} {local_i32:prec$.width$} {width:local_i32$.prec$} {width:prec$.local_i32$} {prec:local_i32$.width$} {prec:width$.local_i32$}", ); println!( @@ -122,8 +188,11 @@ fn tester(fn_arg: i32) { 1 + 2 ); println!("Width = {local_i32}, value with width = {local_f64:local_i32$}"); + //~^ uninlined_format_args println!("{local_i32:width$.prec$}"); + //~^ uninlined_format_args println!("{width:width$.prec$}"); + //~^ uninlined_format_args println!("{}", format!("{}", local_i32)); my_println!("{}", local_i32); my_println_args!("{}", local_i32); @@ -143,21 +212,26 @@ fn tester(fn_arg: i32) { println!(no_param_str!(), local_i32); println!( + //~^ uninlined_format_args "{val}", ); println!("{val}"); + //~^ uninlined_format_args println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64); println!("{}", with_span!(span val)); if local_i32 > 0 { panic!("p1 {local_i32}"); + //~^ uninlined_format_args } if local_i32 > 0 { panic!("p2 {local_i32}"); + //~^ uninlined_format_args } if local_i32 > 0 { panic!("p3 {local_i32}"); + //~^ uninlined_format_args } if local_i32 > 0 { panic!("p4 {local_i32}"); @@ -178,6 +252,7 @@ fn _under_msrv() { fn _meets_msrv() { let local_i32 = 1; println!("expand='{local_i32}'"); + //~^ uninlined_format_args } fn _do_not_fire() { @@ -280,7 +355,11 @@ fn user_format() { let local_f64 = 2.0; usr_println!(true, "val='{local_i32}'"); + //~^ uninlined_format_args usr_println!(true, "{local_i32}"); + //~^ uninlined_format_args usr_println!(true, "{local_i32:#010x}"); + //~^ uninlined_format_args usr_println!(true, "{local_f64:.1}"); + //~^ uninlined_format_args } diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs index 81fe24765674b..14e0b6caabc0e 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.rs +++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs @@ -43,77 +43,143 @@ fn tester(fn_arg: i32) { let _: &[u8; 3] = b" "; // <- println!("val='{}'", local_i32); + //~^ uninlined_format_args println!("val='{ }'", local_i32); // 3 spaces + // + //~^^ uninlined_format_args println!("val='{ }'", local_i32); // tab + // + //~^^ uninlined_format_args println!("val='{ }'", local_i32); // space+tab + // + //~^^ uninlined_format_args println!("val='{ }'", local_i32); // tab+space + // + //~^^ uninlined_format_args println!( + //~^ uninlined_format_args "val='{ }'", local_i32 ); println!("{}", local_i32); + //~^ uninlined_format_args println!("{}", fn_arg); + //~^ uninlined_format_args println!("{:?}", local_i32); + //~^ uninlined_format_args println!("{:#?}", local_i32); + //~^ uninlined_format_args println!("{:4}", local_i32); + //~^ uninlined_format_args println!("{:04}", local_i32); + //~^ uninlined_format_args println!("{:<3}", local_i32); + //~^ uninlined_format_args println!("{:#010x}", local_i32); + //~^ uninlined_format_args println!("{:.1}", local_f64); + //~^ uninlined_format_args println!("Hello {} is {:.*}", "x", local_i32, local_f64); println!("Hello {} is {:.*}", local_i32, 5, local_f64); println!("Hello {} is {2:.*}", local_i32, 5, local_f64); println!("{} {}", local_i32, local_f64); + //~^ uninlined_format_args println!("{}, {}", local_i32, local_opt.unwrap()); println!("{}", val); + //~^ uninlined_format_args println!("{}", v = val); + //~^ uninlined_format_args println!("{} {1}", local_i32, 42); println!("val='{\t }'", local_i32); + //~^ uninlined_format_args println!("val='{\n }'", local_i32); + //~^ uninlined_format_args println!("val='{local_i32}'", local_i32 = local_i32); + //~^ uninlined_format_args println!("val='{local_i32}'", local_i32 = fn_arg); + //~^ uninlined_format_args println!("{0}", local_i32); + //~^ uninlined_format_args println!("{0:?}", local_i32); + //~^ uninlined_format_args println!("{0:#?}", local_i32); + //~^ uninlined_format_args println!("{0:04}", local_i32); + //~^ uninlined_format_args println!("{0:<3}", local_i32); + //~^ uninlined_format_args println!("{0:#010x}", local_i32); + //~^ uninlined_format_args println!("{0:.1}", local_f64); + //~^ uninlined_format_args println!("{0} {0}", local_i32); + //~^ uninlined_format_args println!("{1} {} {0} {}", local_i32, local_f64); + //~^ uninlined_format_args println!("{0} {1}", local_i32, local_f64); + //~^ uninlined_format_args println!("{1} {0}", local_i32, local_f64); + //~^ uninlined_format_args println!("{1} {0} {1} {0}", local_i32, local_f64); + //~^ uninlined_format_args println!("{1} {0}", "str", local_i32); println!("{v}", v = local_i32); + //~^ uninlined_format_args println!("{local_i32:0$}", width); + //~^ uninlined_format_args println!("{local_i32:w$}", w = width); + //~^ uninlined_format_args println!("{local_i32:.0$}", prec); + //~^ uninlined_format_args println!("{local_i32:.p$}", p = prec); + //~^ uninlined_format_args println!("{:0$}", v = val); + //~^ uninlined_format_args println!("{0:0$}", v = val); + //~^ uninlined_format_args println!("{:0$.0$}", v = val); + //~^ uninlined_format_args println!("{0:0$.0$}", v = val); + //~^ uninlined_format_args println!("{0:0$.v$}", v = val); + //~^ uninlined_format_args println!("{0:v$.0$}", v = val); + //~^ uninlined_format_args println!("{v:0$.0$}", v = val); + //~^ uninlined_format_args println!("{v:v$.0$}", v = val); + //~^ uninlined_format_args println!("{v:0$.v$}", v = val); + //~^ uninlined_format_args println!("{v:v$.v$}", v = val); + //~^ uninlined_format_args println!("{:0$}", width); + //~^ uninlined_format_args println!("{:1$}", local_i32, width); + //~^ uninlined_format_args println!("{:w$}", w = width); + //~^ uninlined_format_args println!("{:w$}", local_i32, w = width); + //~^ uninlined_format_args println!("{:.0$}", prec); + //~^ uninlined_format_args println!("{:.1$}", local_i32, prec); + //~^ uninlined_format_args println!("{:.p$}", p = prec); + //~^ uninlined_format_args println!("{:.p$}", local_i32, p = prec); + //~^ uninlined_format_args println!("{:0$.1$}", width, prec); + //~^ uninlined_format_args println!("{:0$.w$}", width, w = prec); + //~^ uninlined_format_args println!("{:1$.2$}", local_f64, width, prec); + //~^ uninlined_format_args println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); + //~^ uninlined_format_args println!( + //~^ uninlined_format_args "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", local_i32, width, prec, ); @@ -125,8 +191,11 @@ fn tester(fn_arg: i32) { 1 + 2 ); println!("Width = {}, value with width = {:0$}", local_i32, local_f64); + //~^ uninlined_format_args println!("{:w$.p$}", local_i32, w = width, p = prec); + //~^ uninlined_format_args println!("{:w$.p$}", w = width, p = prec); + //~^ uninlined_format_args println!("{}", format!("{}", local_i32)); my_println!("{}", local_i32); my_println_args!("{}", local_i32); @@ -146,23 +215,28 @@ fn tester(fn_arg: i32) { println!(no_param_str!(), local_i32); println!( + //~^ uninlined_format_args "{}", // comment with a comma , in it val, ); println!("{}", /* comment with a comma , in it */ val); + //~^ uninlined_format_args println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64); println!("{}", with_span!(span val)); if local_i32 > 0 { panic!("p1 {}", local_i32); + //~^ uninlined_format_args } if local_i32 > 0 { panic!("p2 {0}", local_i32); + //~^ uninlined_format_args } if local_i32 > 0 { panic!("p3 {local_i32}", local_i32 = local_i32); + //~^ uninlined_format_args } if local_i32 > 0 { panic!("p4 {local_i32}"); @@ -183,6 +257,7 @@ fn _under_msrv() { fn _meets_msrv() { let local_i32 = 1; println!("expand='{}'", local_i32); + //~^ uninlined_format_args } fn _do_not_fire() { @@ -285,7 +360,11 @@ fn user_format() { let local_f64 = 2.0; usr_println!(true, "val='{}'", local_i32); + //~^ uninlined_format_args usr_println!(true, "{}", local_i32); + //~^ uninlined_format_args usr_println!(true, "{:#010x}", local_i32); + //~^ uninlined_format_args usr_println!(true, "{:.1}", local_f64); + //~^ uninlined_format_args } diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.stderr b/src/tools/clippy/tests/ui/uninlined_format_args.stderr index 77961fea2c534..7e62a095eadf7 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.stderr +++ b/src/tools/clippy/tests/ui/uninlined_format_args.stderr @@ -13,7 +13,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:46:5 + --> tests/ui/uninlined_format_args.rs:47:5 | LL | println!("val='{ }'", local_i32); // 3 spaces | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + println!("val='{local_i32}'"); // 3 spaces | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:47:5 + --> tests/ui/uninlined_format_args.rs:50:5 | LL | println!("val='{ }'", local_i32); // tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + println!("val='{local_i32}'"); // tab | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:48:5 + --> tests/ui/uninlined_format_args.rs:53:5 | LL | println!("val='{ }'", local_i32); // space+tab | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + println!("val='{local_i32}'"); // space+tab | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:49:5 + --> tests/ui/uninlined_format_args.rs:56:5 | LL | println!("val='{ }'", local_i32); // tab+space | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,9 +61,10 @@ LL + println!("val='{local_i32}'"); // tab+space | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:50:5 + --> tests/ui/uninlined_format_args.rs:59:5 | LL | / println!( +LL | | LL | | "val='{ LL | | }'", LL | | local_i32 @@ -71,7 +72,7 @@ LL | | ); | |_____^ error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:55:5 + --> tests/ui/uninlined_format_args.rs:65:5 | LL | println!("{}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +84,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:56:5 + --> tests/ui/uninlined_format_args.rs:67:5 | LL | println!("{}", fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +96,7 @@ LL + println!("{fn_arg}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:57:5 + --> tests/ui/uninlined_format_args.rs:69:5 | LL | println!("{:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -107,7 +108,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:58:5 + --> tests/ui/uninlined_format_args.rs:71:5 | LL | println!("{:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +120,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:59:5 + --> tests/ui/uninlined_format_args.rs:73:5 | LL | println!("{:4}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +132,7 @@ LL + println!("{local_i32:4}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:60:5 + --> tests/ui/uninlined_format_args.rs:75:5 | LL | println!("{:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,7 +144,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:61:5 + --> tests/ui/uninlined_format_args.rs:77:5 | LL | println!("{:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -155,7 +156,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:62:5 + --> tests/ui/uninlined_format_args.rs:79:5 | LL | println!("{:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +168,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:63:5 + --> tests/ui/uninlined_format_args.rs:81:5 | LL | println!("{:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -179,7 +180,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:67:5 + --> tests/ui/uninlined_format_args.rs:86:5 | LL | println!("{} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -191,7 +192,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:69:5 + --> tests/ui/uninlined_format_args.rs:89:5 | LL | println!("{}", val); | ^^^^^^^^^^^^^^^^^^^ @@ -203,7 +204,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:70:5 + --> tests/ui/uninlined_format_args.rs:91:5 | LL | println!("{}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -215,7 +216,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:72:5 + --> tests/ui/uninlined_format_args.rs:94:5 | LL | println!("val='{\t }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -227,7 +228,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:73:5 + --> tests/ui/uninlined_format_args.rs:96:5 | LL | println!("val='{\n }'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -239,7 +240,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:74:5 + --> tests/ui/uninlined_format_args.rs:98:5 | LL | println!("val='{local_i32}'", local_i32 = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -251,7 +252,7 @@ LL + println!("val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:75:5 + --> tests/ui/uninlined_format_args.rs:100:5 | LL | println!("val='{local_i32}'", local_i32 = fn_arg); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -263,7 +264,7 @@ LL + println!("val='{fn_arg}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:76:5 + --> tests/ui/uninlined_format_args.rs:102:5 | LL | println!("{0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -275,7 +276,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:77:5 + --> tests/ui/uninlined_format_args.rs:104:5 | LL | println!("{0:?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -287,7 +288,7 @@ LL + println!("{local_i32:?}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:78:5 + --> tests/ui/uninlined_format_args.rs:106:5 | LL | println!("{0:#?}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -299,7 +300,7 @@ LL + println!("{local_i32:#?}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:79:5 + --> tests/ui/uninlined_format_args.rs:108:5 | LL | println!("{0:04}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -311,7 +312,7 @@ LL + println!("{local_i32:04}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:80:5 + --> tests/ui/uninlined_format_args.rs:110:5 | LL | println!("{0:<3}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -323,7 +324,7 @@ LL + println!("{local_i32:<3}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:81:5 + --> tests/ui/uninlined_format_args.rs:112:5 | LL | println!("{0:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -335,7 +336,7 @@ LL + println!("{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:82:5 + --> tests/ui/uninlined_format_args.rs:114:5 | LL | println!("{0:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -347,7 +348,7 @@ LL + println!("{local_f64:.1}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:83:5 + --> tests/ui/uninlined_format_args.rs:116:5 | LL | println!("{0} {0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -359,7 +360,7 @@ LL + println!("{local_i32} {local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:84:5 + --> tests/ui/uninlined_format_args.rs:118:5 | LL | println!("{1} {} {0} {}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -371,7 +372,7 @@ LL + println!("{local_f64} {local_i32} {local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:85:5 + --> tests/ui/uninlined_format_args.rs:120:5 | LL | println!("{0} {1}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +384,7 @@ LL + println!("{local_i32} {local_f64}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:86:5 + --> tests/ui/uninlined_format_args.rs:122:5 | LL | println!("{1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -395,7 +396,7 @@ LL + println!("{local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:87:5 + --> tests/ui/uninlined_format_args.rs:124:5 | LL | println!("{1} {0} {1} {0}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -407,7 +408,7 @@ LL + println!("{local_f64} {local_i32} {local_f64} {local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:89:5 + --> tests/ui/uninlined_format_args.rs:127:5 | LL | println!("{v}", v = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -419,7 +420,7 @@ LL + println!("{local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:90:5 + --> tests/ui/uninlined_format_args.rs:129:5 | LL | println!("{local_i32:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -431,7 +432,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:91:5 + --> tests/ui/uninlined_format_args.rs:131:5 | LL | println!("{local_i32:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -443,7 +444,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:92:5 + --> tests/ui/uninlined_format_args.rs:133:5 | LL | println!("{local_i32:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -455,7 +456,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:93:5 + --> tests/ui/uninlined_format_args.rs:135:5 | LL | println!("{local_i32:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -467,7 +468,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:94:5 + --> tests/ui/uninlined_format_args.rs:137:5 | LL | println!("{:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -479,7 +480,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:95:5 + --> tests/ui/uninlined_format_args.rs:139:5 | LL | println!("{0:0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -491,7 +492,7 @@ LL + println!("{val:val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:96:5 + --> tests/ui/uninlined_format_args.rs:141:5 | LL | println!("{:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -503,7 +504,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:97:5 + --> tests/ui/uninlined_format_args.rs:143:5 | LL | println!("{0:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -515,7 +516,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:98:5 + --> tests/ui/uninlined_format_args.rs:145:5 | LL | println!("{0:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -527,7 +528,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:99:5 + --> tests/ui/uninlined_format_args.rs:147:5 | LL | println!("{0:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -539,7 +540,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:100:5 + --> tests/ui/uninlined_format_args.rs:149:5 | LL | println!("{v:0$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -551,7 +552,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:101:5 + --> tests/ui/uninlined_format_args.rs:151:5 | LL | println!("{v:v$.0$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -563,7 +564,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:102:5 + --> tests/ui/uninlined_format_args.rs:153:5 | LL | println!("{v:0$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -575,7 +576,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:103:5 + --> tests/ui/uninlined_format_args.rs:155:5 | LL | println!("{v:v$.v$}", v = val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -587,7 +588,7 @@ LL + println!("{val:val$.val$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:104:5 + --> tests/ui/uninlined_format_args.rs:157:5 | LL | println!("{:0$}", width); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -599,7 +600,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:105:5 + --> tests/ui/uninlined_format_args.rs:159:5 | LL | println!("{:1$}", local_i32, width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -611,7 +612,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:106:5 + --> tests/ui/uninlined_format_args.rs:161:5 | LL | println!("{:w$}", w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -623,7 +624,7 @@ LL + println!("{width:width$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:107:5 + --> tests/ui/uninlined_format_args.rs:163:5 | LL | println!("{:w$}", local_i32, w = width); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -635,7 +636,7 @@ LL + println!("{local_i32:width$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:108:5 + --> tests/ui/uninlined_format_args.rs:165:5 | LL | println!("{:.0$}", prec); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -647,7 +648,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:109:5 + --> tests/ui/uninlined_format_args.rs:167:5 | LL | println!("{:.1$}", local_i32, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -659,7 +660,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:110:5 + --> tests/ui/uninlined_format_args.rs:169:5 | LL | println!("{:.p$}", p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -671,7 +672,7 @@ LL + println!("{prec:.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:111:5 + --> tests/ui/uninlined_format_args.rs:171:5 | LL | println!("{:.p$}", local_i32, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -683,7 +684,7 @@ LL + println!("{local_i32:.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:112:5 + --> tests/ui/uninlined_format_args.rs:173:5 | LL | println!("{:0$.1$}", width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -695,7 +696,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:113:5 + --> tests/ui/uninlined_format_args.rs:175:5 | LL | println!("{:0$.w$}", width, w = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -707,7 +708,7 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:114:5 + --> tests/ui/uninlined_format_args.rs:177:5 | LL | println!("{:1$.2$}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -719,7 +720,7 @@ LL + println!("{local_f64:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:115:5 + --> tests/ui/uninlined_format_args.rs:179:5 | LL | println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -731,16 +732,17 @@ LL + println!("{local_f64:width$.prec$} {local_f64} {width} {prec}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:116:5 + --> tests/ui/uninlined_format_args.rs:181:5 | LL | / println!( +LL | | LL | | "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}", LL | | local_i32, width, prec, LL | | ); | |_____^ error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:127:5 + --> tests/ui/uninlined_format_args.rs:193:5 | LL | println!("Width = {}, value with width = {:0$}", local_i32, local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -752,7 +754,7 @@ LL + println!("Width = {local_i32}, value with width = {local_f64:local_i32$ | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:128:5 + --> tests/ui/uninlined_format_args.rs:195:5 | LL | println!("{:w$.p$}", local_i32, w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -764,7 +766,7 @@ LL + println!("{local_i32:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:129:5 + --> tests/ui/uninlined_format_args.rs:197:5 | LL | println!("{:w$.p$}", w = width, p = prec); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -776,17 +778,17 @@ LL + println!("{width:width$.prec$}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:148:5 + --> tests/ui/uninlined_format_args.rs:217:5 | LL | / println!( +LL | | LL | | "{}", -LL | | // comment with a comma , in it -LL | | val, +... | LL | | ); | |_____^ error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:153:5 + --> tests/ui/uninlined_format_args.rs:223:5 | LL | println!("{}", /* comment with a comma , in it */ val); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -798,7 +800,7 @@ LL + println!("{val}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:159:9 + --> tests/ui/uninlined_format_args.rs:230:9 | LL | panic!("p1 {}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -810,7 +812,7 @@ LL + panic!("p1 {local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:162:9 + --> tests/ui/uninlined_format_args.rs:234:9 | LL | panic!("p2 {0}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -822,7 +824,7 @@ LL + panic!("p2 {local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:165:9 + --> tests/ui/uninlined_format_args.rs:238:9 | LL | panic!("p3 {local_i32}", local_i32 = local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -834,7 +836,7 @@ LL + panic!("p3 {local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:185:5 + --> tests/ui/uninlined_format_args.rs:259:5 | LL | println!("expand='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -846,7 +848,7 @@ LL + println!("expand='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:287:5 + --> tests/ui/uninlined_format_args.rs:362:5 | LL | usr_println!(true, "val='{}'", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -858,7 +860,7 @@ LL + usr_println!(true, "val='{local_i32}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:288:5 + --> tests/ui/uninlined_format_args.rs:364:5 | LL | usr_println!(true, "{}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -870,7 +872,7 @@ LL + usr_println!(true, "{local_i32}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:289:5 + --> tests/ui/uninlined_format_args.rs:366:5 | LL | usr_println!(true, "{:#010x}", local_i32); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -882,7 +884,7 @@ LL + usr_println!(true, "{local_i32:#010x}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args.rs:290:5 + --> tests/ui/uninlined_format_args.rs:368:5 | LL | usr_println!(true, "{:.1}", local_f64); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed index 9911d1317070a..3710036c05890 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -9,15 +9,19 @@ fn main() { let var = 1; println!("val='{var}'"); + //~^ uninlined_format_args if var > 0 { panic!("p1 {}", var); + //~[edition2021]^ uninlined_format_args } if var > 0 { panic!("p2 {0}", var); + //~[edition2021]^ uninlined_format_args } if var > 0 { panic!("p3 {var}", var = var); + //~[edition2021]^ uninlined_format_args } #[allow(non_fmt_panics)] @@ -28,5 +32,7 @@ fn main() { } assert!(var == 1, "p5 {}", var); + //~[edition2021]^ uninlined_format_args debug_assert!(var == 1, "p6 {}", var); + //~[edition2021]^ uninlined_format_args } diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed index 87b74670565f4..8a754d313806c 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -9,15 +9,19 @@ fn main() { let var = 1; println!("val='{var}'"); + //~^ uninlined_format_args if var > 0 { panic!("p1 {var}"); + //~[edition2021]^ uninlined_format_args } if var > 0 { panic!("p2 {var}"); + //~[edition2021]^ uninlined_format_args } if var > 0 { panic!("p3 {var}"); + //~[edition2021]^ uninlined_format_args } #[allow(non_fmt_panics)] @@ -28,5 +32,7 @@ fn main() { } assert!(var == 1, "p5 {var}"); + //~[edition2021]^ uninlined_format_args debug_assert!(var == 1, "p6 {var}"); + //~[edition2021]^ uninlined_format_args } diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr index 7638d3f8bbadc..4db6e6a993123 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.stderr @@ -13,7 +13,7 @@ LL + println!("val='{var}'"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:14:9 + --> tests/ui/uninlined_format_args_panic.rs:15:9 | LL | panic!("p1 {}", var); | ^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + panic!("p1 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:17:9 + --> tests/ui/uninlined_format_args_panic.rs:19:9 | LL | panic!("p2 {0}", var); | ^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + panic!("p2 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:20:9 + --> tests/ui/uninlined_format_args_panic.rs:23:9 | LL | panic!("p3 {var}", var = var); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + panic!("p3 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:30:5 + --> tests/ui/uninlined_format_args_panic.rs:34:5 | LL | assert!(var == 1, "p5 {}", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + assert!(var == 1, "p5 {var}"); | error: variables can be used directly in the `format!` string - --> tests/ui/uninlined_format_args_panic.rs:31:5 + --> tests/ui/uninlined_format_args_panic.rs:36:5 | LL | debug_assert!(var == 1, "p6 {}", var); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs index 647c69bc5c410..94de4f057e99e 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs @@ -9,15 +9,19 @@ fn main() { let var = 1; println!("val='{}'", var); + //~^ uninlined_format_args if var > 0 { panic!("p1 {}", var); + //~[edition2021]^ uninlined_format_args } if var > 0 { panic!("p2 {0}", var); + //~[edition2021]^ uninlined_format_args } if var > 0 { panic!("p3 {var}", var = var); + //~[edition2021]^ uninlined_format_args } #[allow(non_fmt_panics)] @@ -28,5 +32,7 @@ fn main() { } assert!(var == 1, "p5 {}", var); + //~[edition2021]^ uninlined_format_args debug_assert!(var == 1, "p6 {}", var); + //~[edition2021]^ uninlined_format_args } diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 2e1390621a6cd..22a6a26dab626 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -61,23 +61,30 @@ impl Tr for B { fn bad() { foo({ + //~^ unit_arg 1; }); foo(foo(1)); + //~^ unit_arg foo({ + //~^ unit_arg foo(1); foo(2); }); let b = Bar; b.bar({ + //~^ unit_arg 1; }); taking_multiple_units(foo(0), foo(1)); + //~^ unit_arg taking_multiple_units(foo(0), { + //~^ unit_arg foo(1); foo(2); }); taking_multiple_units( + //~^ unit_arg { foo(0); foo(1); @@ -89,9 +96,11 @@ fn bad() { ); // here Some(foo(2)) isn't the top level statement expression, wrap the suggestion in a block None.or(Some(foo(2))); + //~^ unit_arg // in this case, the suggestion can be inlined, no need for a surrounding block // foo(()); foo(()) instead of { foo(()); foo(()) } foo(foo(())); + //~^ unit_arg } fn ok() { @@ -129,6 +138,7 @@ mod issue_2945 { #[allow(dead_code)] fn returning_expr() -> Option<()> { Some(foo(1)) + //~^ unit_arg } fn taking_multiple_units(a: (), b: ()) {} diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index bf79e93e44405..6c333d9792d4d 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -2,6 +2,7 @@ error: passing a unit value to a function --> tests/ui/unit_arg.rs:63:5 | LL | / foo({ +LL | | LL | | 1; LL | | }); | |______^ @@ -16,13 +17,14 @@ LL + 1 help: or move the expression in front of the call and replace it with the unit literal `()` | LL ~ { +LL + LL + 1; LL + }; LL ~ foo(()); | error: passing a unit value to a function - --> tests/ui/unit_arg.rs:66:5 + --> tests/ui/unit_arg.rs:67:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -34,9 +36,10 @@ LL ~ foo(()); | error: passing a unit value to a function - --> tests/ui/unit_arg.rs:67:5 + --> tests/ui/unit_arg.rs:69:5 | LL | / foo({ +LL | | LL | | foo(1); LL | | foo(2); LL | | }); @@ -50,6 +53,7 @@ LL + foo(2) help: or move the expression in front of the call and replace it with the unit literal `()` | LL ~ { +LL + LL + foo(1); LL + foo(2); LL + }; @@ -57,9 +61,10 @@ LL ~ foo(()); | error: passing a unit value to a function - --> tests/ui/unit_arg.rs:72:5 + --> tests/ui/unit_arg.rs:75:5 | LL | / b.bar({ +LL | | LL | | 1; LL | | }); | |______^ @@ -72,13 +77,14 @@ LL + 1 help: or move the expression in front of the call and replace it with the unit literal `()` | LL ~ { +LL + LL + 1; LL + }; LL ~ b.bar(()); | error: passing unit values to a function - --> tests/ui/unit_arg.rs:75:5 + --> tests/ui/unit_arg.rs:79:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -91,9 +97,10 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> tests/ui/unit_arg.rs:76:5 + --> tests/ui/unit_arg.rs:81:5 | LL | / taking_multiple_units(foo(0), { +LL | | LL | | foo(1); LL | | foo(2); LL | | }); @@ -108,6 +115,7 @@ help: or move the expressions in front of the call and replace them with the uni | LL ~ foo(0); LL + { +LL + LL + foo(1); LL + foo(2); LL + }; @@ -115,12 +123,12 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> tests/ui/unit_arg.rs:80:5 + --> tests/ui/unit_arg.rs:86:5 | LL | / taking_multiple_units( +LL | | LL | | { LL | | foo(0); -LL | | foo(1); ... | LL | | }, LL | | ); @@ -147,13 +155,14 @@ LL + foo(2); LL + foo(3); LL + }; LL + taking_multiple_units( +LL + LL + (), LL + (), LL ~ ); | error: passing a unit value to a function - --> tests/ui/unit_arg.rs:91:13 + --> tests/ui/unit_arg.rs:98:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -167,7 +176,7 @@ LL ~ }); | error: passing a unit value to a function - --> tests/ui/unit_arg.rs:94:5 + --> tests/ui/unit_arg.rs:102:5 | LL | foo(foo(())); | ^^^^^^^^^^^^ @@ -179,7 +188,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> tests/ui/unit_arg.rs:131:5 + --> tests/ui/unit_arg.rs:140:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed index a947ded7b1e72..b045a33608d7c 100644 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed @@ -14,12 +14,16 @@ fn foo3(t1: T1, t2: T2, t3: T3) { fn bad() { foo(()); + //~^ unit_arg foo3((), 2, 2); + //~^ unit_arg foo(0); taking_two_units((), ()); + //~^ unit_arg foo(0); foo(1); taking_three_units((), (), ()); + //~^ unit_arg } fn taking_two_units(a: (), b: ()) {} diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs index 058c4f84a9e87..ab305913f3f69 100644 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs @@ -14,9 +14,13 @@ fn foo3(t1: T1, t2: T2, t3: T3) { fn bad() { foo({}); + //~^ unit_arg foo3({}, 2, 2); + //~^ unit_arg taking_two_units({}, foo(0)); + //~^ unit_arg taking_three_units({}, foo(0), foo(1)); + //~^ unit_arg } fn taking_two_units(a: (), b: ()) {} diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr index d971195dda265..2c686d58ecc1a 100644 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr @@ -10,7 +10,7 @@ LL | foo({}); = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` error: passing a unit value to a function - --> tests/ui/unit_arg_empty_blocks.rs:17:5 + --> tests/ui/unit_arg_empty_blocks.rs:18:5 | LL | foo3({}, 2, 2); | ^^^^^--^^^^^^^ @@ -18,7 +18,7 @@ LL | foo3({}, 2, 2); | help: use a unit literal instead: `()` error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:18:5 + --> tests/ui/unit_arg_empty_blocks.rs:20:5 | LL | taking_two_units({}, foo(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -30,7 +30,7 @@ LL ~ taking_two_units((), ()); | error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:19:5 + --> tests/ui/unit_arg_empty_blocks.rs:22:5 | LL | taking_three_units({}, foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unit_cmp.rs b/src/tools/clippy/tests/ui/unit_cmp.rs index cea89026da6f1..93f5b87c3d2a7 100644 --- a/src/tools/clippy/tests/ui/unit_cmp.rs +++ b/src/tools/clippy/tests/ui/unit_cmp.rs @@ -15,22 +15,23 @@ fn main() { // this warns if { - //~^ ERROR: ==-comparison of unit values detected. This will always be true - //~| NOTE: `-D clippy::unit-cmp` implied by `-D warnings` + //~^ unit_cmp + true; } == { false; } {} if { - //~^ ERROR: >-comparison of unit values detected. This will always be false + //~^ unit_cmp + true; } > { false; } {} assert_eq!( - //~^ ERROR: `assert_eq` of unit values detected. This will always succeed + //~^ unit_cmp { true; }, @@ -39,7 +40,7 @@ fn main() { } ); debug_assert_eq!( - //~^ ERROR: `debug_assert_eq` of unit values detected. This will always succeed + //~^ unit_cmp { true; }, @@ -49,7 +50,7 @@ fn main() { ); assert_ne!( - //~^ ERROR: `assert_ne` of unit values detected. This will always fail + //~^ unit_cmp { true; }, @@ -58,7 +59,7 @@ fn main() { } ); debug_assert_ne!( - //~^ ERROR: `debug_assert_ne` of unit values detected. This will always fail + //~^ unit_cmp { true; }, diff --git a/src/tools/clippy/tests/ui/unit_cmp.stderr b/src/tools/clippy/tests/ui/unit_cmp.stderr index 9e067edb84679..8f26749fd8605 100644 --- a/src/tools/clippy/tests/ui/unit_cmp.stderr +++ b/src/tools/clippy/tests/ui/unit_cmp.stderr @@ -20,6 +20,7 @@ error: >-comparison of unit values detected. This will always be false LL | if { | ________^ LL | | +LL | | LL | | true; LL | | } > { LL | | false; @@ -27,7 +28,7 @@ LL | | } {} | |_____^ error: `assert_eq` of unit values detected. This will always succeed - --> tests/ui/unit_cmp.rs:32:5 + --> tests/ui/unit_cmp.rs:33:5 | LL | / assert_eq!( LL | | @@ -38,7 +39,7 @@ LL | | ); | |_____^ error: `debug_assert_eq` of unit values detected. This will always succeed - --> tests/ui/unit_cmp.rs:41:5 + --> tests/ui/unit_cmp.rs:42:5 | LL | / debug_assert_eq!( LL | | @@ -49,7 +50,7 @@ LL | | ); | |_____^ error: `assert_ne` of unit values detected. This will always fail - --> tests/ui/unit_cmp.rs:51:5 + --> tests/ui/unit_cmp.rs:52:5 | LL | / assert_ne!( LL | | @@ -60,7 +61,7 @@ LL | | ); | |_____^ error: `debug_assert_ne` of unit values detected. This will always fail - --> tests/ui/unit_cmp.rs:60:5 + --> tests/ui/unit_cmp.rs:61:5 | LL | / debug_assert_ne!( LL | | diff --git a/src/tools/clippy/tests/ui/unit_hash.fixed b/src/tools/clippy/tests/ui/unit_hash.fixed index ed0facf1b9635..25c90e6ddc4c2 100644 --- a/src/tools/clippy/tests/ui/unit_hash.fixed +++ b/src/tools/clippy/tests/ui/unit_hash.fixed @@ -17,18 +17,15 @@ fn main() { match my_enum { Foo::Empty => 0_u8.hash(&mut state), - //~^ ERROR: this call to `hash` on the unit type will do nothing - //~| NOTE: the implementation of `Hash` for `()` is a no-op + //~^ unit_hash Foo::WithValue(x) => x.hash(&mut state), } let res = (); 0_u8.hash(&mut state); - //~^ ERROR: this call to `hash` on the unit type will do nothing - //~| NOTE: the implementation of `Hash` for `()` is a no-op + //~^ unit_hash #[allow(clippy::unit_arg)] 0_u8.hash(&mut state); - //~^ ERROR: this call to `hash` on the unit type will do nothing - //~| NOTE: the implementation of `Hash` for `()` is a no-op + //~^ unit_hash } diff --git a/src/tools/clippy/tests/ui/unit_hash.rs b/src/tools/clippy/tests/ui/unit_hash.rs index f3636d1644da9..b04cca6adf2a5 100644 --- a/src/tools/clippy/tests/ui/unit_hash.rs +++ b/src/tools/clippy/tests/ui/unit_hash.rs @@ -17,18 +17,15 @@ fn main() { match my_enum { Foo::Empty => ().hash(&mut state), - //~^ ERROR: this call to `hash` on the unit type will do nothing - //~| NOTE: the implementation of `Hash` for `()` is a no-op + //~^ unit_hash Foo::WithValue(x) => x.hash(&mut state), } let res = (); res.hash(&mut state); - //~^ ERROR: this call to `hash` on the unit type will do nothing - //~| NOTE: the implementation of `Hash` for `()` is a no-op + //~^ unit_hash #[allow(clippy::unit_arg)] do_nothing().hash(&mut state); - //~^ ERROR: this call to `hash` on the unit type will do nothing - //~| NOTE: the implementation of `Hash` for `()` is a no-op + //~^ unit_hash } diff --git a/src/tools/clippy/tests/ui/unit_hash.stderr b/src/tools/clippy/tests/ui/unit_hash.stderr index b48f3a543b763..d1cabf89f8e71 100644 --- a/src/tools/clippy/tests/ui/unit_hash.stderr +++ b/src/tools/clippy/tests/ui/unit_hash.stderr @@ -9,7 +9,7 @@ LL | Foo::Empty => ().hash(&mut state), = help: to override `-D warnings` add `#[allow(clippy::unit_hash)]` error: this call to `hash` on the unit type will do nothing - --> tests/ui/unit_hash.rs:26:5 + --> tests/ui/unit_hash.rs:25:5 | LL | res.hash(&mut state); | ^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` @@ -17,7 +17,7 @@ LL | res.hash(&mut state); = note: the implementation of `Hash` for `()` is a no-op error: this call to `hash` on the unit type will do nothing - --> tests/ui/unit_hash.rs:31:5 + --> tests/ui/unit_hash.rs:29:5 | LL | do_nothing().hash(&mut state); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `hash` or consider using: `0_u8.hash(&mut state)` diff --git a/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs b/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs index 5f62157dd6d55..74cd304726842 100644 --- a/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs +++ b/src/tools/clippy/tests/ui/unit_return_expecting_ord.rs @@ -16,16 +16,19 @@ fn unit(_i: isize) {} fn main() { let mut structs = vec![Struct { field: 2 }, Struct { field: 1 }]; structs.sort_by_key(|s| { - //~^ ERROR: this closure returns the unit type which also implements Ord + //~^ unit_return_expecting_ord + double(s.field); }); structs.sort_by_key(|s| double(s.field)); structs.is_sorted_by_key(|s| { - //~^ ERROR: this closure returns the unit type which also implements PartialOrd + //~^ unit_return_expecting_ord + double(s.field); }); structs.is_sorted_by_key(|s| { - //~^ ERROR: this closure returns the unit type which also implements PartialOrd + //~^ unit_return_expecting_ord + if s.field > 0 { () } else { @@ -36,5 +39,5 @@ fn main() { return double(s.field); }); structs.sort_by_key(|s| unit(s.field)); - //~^ ERROR: this closure returns the unit type which also implements Ord + //~^ unit_return_expecting_ord } diff --git a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr index 329832048e88a..d5ce2fb0b51d9 100644 --- a/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr +++ b/src/tools/clippy/tests/ui/unit_return_expecting_ord.stderr @@ -5,7 +5,7 @@ LL | structs.sort_by_key(|s| { | ^^^ | help: probably caused by this trailing semicolon - --> tests/ui/unit_return_expecting_ord.rs:20:24 + --> tests/ui/unit_return_expecting_ord.rs:21:24 | LL | double(s.field); | ^ @@ -13,25 +13,25 @@ LL | double(s.field); = help: to override `-D warnings` add `#[allow(clippy::unit_return_expecting_ord)]` error: this closure returns the unit type which also implements PartialOrd - --> tests/ui/unit_return_expecting_ord.rs:23:30 + --> tests/ui/unit_return_expecting_ord.rs:24:30 | LL | structs.is_sorted_by_key(|s| { | ^^^ | help: probably caused by this trailing semicolon - --> tests/ui/unit_return_expecting_ord.rs:25:24 + --> tests/ui/unit_return_expecting_ord.rs:27:24 | LL | double(s.field); | ^ error: this closure returns the unit type which also implements PartialOrd - --> tests/ui/unit_return_expecting_ord.rs:27:30 + --> tests/ui/unit_return_expecting_ord.rs:29:30 | LL | structs.is_sorted_by_key(|s| { | ^^^ error: this closure returns the unit type which also implements Ord - --> tests/ui/unit_return_expecting_ord.rs:38:25 + --> tests/ui/unit_return_expecting_ord.rs:41:25 | LL | structs.sort_by_key(|s| unit(s.field)); | ^^^ diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed index c0ccd41c19ab6..f97452c34eb5a 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed @@ -1,18 +1,27 @@ #![warn(clippy::pedantic)] // Should suggest lowercase #![allow(clippy::all)] +//~^ ERROR: unknown lint #![warn(clippy::cmp_owned)] +//~^ ERROR: unknown lint // Should suggest similar clippy lint name #[warn(clippy::if_not_else)] +//~^ ERROR: unknown lint #[warn(clippy::unnecessary_cast)] +//~^ ERROR: unknown lint #[warn(clippy::useless_transmute)] +//~^ ERROR: unknown lint // Should suggest rustc lint name(`dead_code`) #[warn(dead_code)] +//~^ ERROR: unknown lint // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`) #[warn(clippy::unused_self)] +//~^ ERROR: unknown lint // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`) #[warn(clippy::redundant_static_lifetimes)] +//~^ ERROR: unknown lint // issue #118183, should report `missing_docs` from rustc lint #[warn(missing_docs)] +//~^ ERROR: unknown lint fn main() {} diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.rs b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs index 7a59ad364aa7f..2ff4dd80bddcb 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.rs +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs @@ -1,18 +1,27 @@ #![warn(clippy::pedantic)] // Should suggest lowercase #![allow(clippy::All)] +//~^ ERROR: unknown lint #![warn(clippy::CMP_OWNED)] +//~^ ERROR: unknown lint // Should suggest similar clippy lint name #[warn(clippy::if_not_els)] +//~^ ERROR: unknown lint #[warn(clippy::UNNecsaRy_cAst)] +//~^ ERROR: unknown lint #[warn(clippy::useles_transute)] +//~^ ERROR: unknown lint // Should suggest rustc lint name(`dead_code`) #[warn(clippy::dead_cod)] +//~^ ERROR: unknown lint // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`) #[warn(clippy::unused_colle)] +//~^ ERROR: unknown lint // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`) #[warn(clippy::const_static_lifetim)] +//~^ ERROR: unknown lint // issue #118183, should report `missing_docs` from rustc lint #[warn(clippy::missing_docs)] +//~^ ERROR: unknown lint fn main() {} diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr index ea925cd3a9fc4..592fdfbebd43a 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr @@ -8,31 +8,31 @@ LL | #![allow(clippy::All)] = help: to override `-D warnings` add `#[allow(unknown_lints)]` error: unknown lint: `clippy::CMP_OWNED` - --> tests/ui/unknown_clippy_lints.rs:4:9 + --> tests/ui/unknown_clippy_lints.rs:5:9 | LL | #![warn(clippy::CMP_OWNED)] | ^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::cmp_owned` error: unknown lint: `clippy::if_not_els` - --> tests/ui/unknown_clippy_lints.rs:7:8 + --> tests/ui/unknown_clippy_lints.rs:9:8 | LL | #[warn(clippy::if_not_els)] | ^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::if_not_else` error: unknown lint: `clippy::UNNecsaRy_cAst` - --> tests/ui/unknown_clippy_lints.rs:8:8 + --> tests/ui/unknown_clippy_lints.rs:11:8 | LL | #[warn(clippy::UNNecsaRy_cAst)] | ^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unnecessary_cast` error: unknown lint: `clippy::useles_transute` - --> tests/ui/unknown_clippy_lints.rs:9:8 + --> tests/ui/unknown_clippy_lints.rs:13:8 | LL | #[warn(clippy::useles_transute)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::useless_transmute` error: unknown lint: `clippy::dead_cod` - --> tests/ui/unknown_clippy_lints.rs:11:8 + --> tests/ui/unknown_clippy_lints.rs:16:8 | LL | #[warn(clippy::dead_cod)] | ^^^^^^^^^^^^^^^^ @@ -44,19 +44,19 @@ LL + #[warn(dead_code)] | error: unknown lint: `clippy::unused_colle` - --> tests/ui/unknown_clippy_lints.rs:13:8 + --> tests/ui/unknown_clippy_lints.rs:19:8 | LL | #[warn(clippy::unused_colle)] | ^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::unused_self` error: unknown lint: `clippy::const_static_lifetim` - --> tests/ui/unknown_clippy_lints.rs:15:8 + --> tests/ui/unknown_clippy_lints.rs:22:8 | LL | #[warn(clippy::const_static_lifetim)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean: `clippy::redundant_static_lifetimes` error: unknown lint: `clippy::missing_docs` - --> tests/ui/unknown_clippy_lints.rs:17:8 + --> tests/ui/unknown_clippy_lints.rs:25:8 | LL | #[warn(clippy::missing_docs)] | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_box_returns.rs b/src/tools/clippy/tests/ui/unnecessary_box_returns.rs index bcdaca33b6449..a7ab7e90be06b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_box_returns.rs +++ b/src/tools/clippy/tests/ui/unnecessary_box_returns.rs @@ -3,7 +3,7 @@ trait Bar { // lint fn baz(&self) -> Box; - //~^ ERROR: boxed return of the sized type `usize` + //~^ unnecessary_box_returns } pub struct Foo {} @@ -17,7 +17,8 @@ impl Bar for Foo { impl Foo { fn baz(&self) -> Box { - //~^ ERROR: boxed return of the sized type `usize` + //~^ unnecessary_box_returns + // lint Box::new(13) } @@ -25,13 +26,15 @@ impl Foo { // lint fn bxed_usize() -> Box { - //~^ ERROR: boxed return of the sized type `usize` + //~^ unnecessary_box_returns + Box::new(5) } // lint fn _bxed_foo() -> Box { - //~^ ERROR: boxed return of the sized type `Foo` + //~^ unnecessary_box_returns + Box::new(Foo {}) } diff --git a/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr b/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr index cb88ba1b0016d..ab1d90f13b922 100644 --- a/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_box_returns.stderr @@ -17,7 +17,7 @@ LL | fn baz(&self) -> Box { = help: changing this also requires a change to the return expressions in this function error: boxed return of the sized type `usize` - --> tests/ui/unnecessary_box_returns.rs:27:20 + --> tests/ui/unnecessary_box_returns.rs:28:20 | LL | fn bxed_usize() -> Box { | ^^^^^^^^^^ help: try: `usize` @@ -25,7 +25,7 @@ LL | fn bxed_usize() -> Box { = help: changing this also requires a change to the return expressions in this function error: boxed return of the sized type `Foo` - --> tests/ui/unnecessary_box_returns.rs:33:19 + --> tests/ui/unnecessary_box_returns.rs:35:19 | LL | fn _bxed_foo() -> Box { | ^^^^^^^^ help: try: `Foo` diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed index c43e50761bd52..ba167e79a308b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed @@ -17,6 +17,7 @@ type PtrMutU8 = *mut u8; fn owo(ptr: *const T) -> *const T { ptr + //~^ unnecessary_cast } fn uwu(ptr: *const T) -> *const U { @@ -52,21 +53,32 @@ fn bbb() -> UnsignedThirtyTwoBitInteger { fn main() { // Test cast_unnecessary 1_i32; + //~^ unnecessary_cast 1_f32; + //~^ unnecessary_cast false; + //~^ unnecessary_cast &1i32 as &i32; -1_i32; + //~^ unnecessary_cast - 1_i32; + //~^ unnecessary_cast -1_f32; + //~^ unnecessary_cast 1_i32; + //~^ unnecessary_cast 1_f32; + //~^ unnecessary_cast let _: *mut u8 = [1u8, 2].as_ptr() as *mut u8; + //~^ unnecessary_cast [1u8, 2].as_ptr(); + //~^ unnecessary_cast [1u8, 2].as_ptr() as *mut u8; [1u8, 2].as_mut_ptr(); + //~^ unnecessary_cast [1u8, 2].as_mut_ptr() as *const u8; [1u8, 2].as_ptr() as PtrConstU8; [1u8, 2].as_ptr() as PtrMutU8; @@ -78,9 +90,12 @@ fn main() { let _: *mut u8 = [1u8, 2].as_mut_ptr() as *mut _; owo::([1u32].as_ptr()); + //~^ unnecessary_cast uwu::([1u32].as_ptr()); + //~^ unnecessary_cast // this will not lint in the function body even though they have the same type, instead here uwu::([1u32].as_ptr()); + //~^ unnecessary_cast // macro version macro_rules! foo { @@ -116,8 +131,10 @@ fn main() { let pid = unsafe { fake_libc::getpid() }; pid as i32; aaa(); + //~^ unnecessary_cast let x = aaa(); aaa(); + //~^ unnecessary_cast // Will not lint currently. bbb() as u32; let x = bbb(); @@ -154,13 +171,21 @@ mod fixable { fn main() { // casting integer literal to float is unnecessary 100_f32; + //~^ unnecessary_cast 100_f64; + //~^ unnecessary_cast 100_f64; + //~^ unnecessary_cast let _ = -100_f32; + //~^ unnecessary_cast let _ = -100_f64; + //~^ unnecessary_cast let _ = -100_f64; + //~^ unnecessary_cast 100_f32; + //~^ unnecessary_cast 100_f64; + //~^ unnecessary_cast // Should not trigger #[rustfmt::skip] let v = vec!(1); @@ -173,32 +198,44 @@ mod fixable { 0b11 as f64; 1_u32; + //~^ unnecessary_cast 0x10_i32; + //~^ unnecessary_cast 0b10_usize; + //~^ unnecessary_cast 0o73_u16; + //~^ unnecessary_cast 1_000_000_000_u32; + //~^ unnecessary_cast 1.0_f64; + //~^ unnecessary_cast 0.5_f32; + //~^ unnecessary_cast 1.0 as u16; let _ = -1_i32; + //~^ unnecessary_cast let _ = -1.0_f32; + //~^ unnecessary_cast let _ = 1 as I32Alias; let _ = &1 as &I32Alias; let x = 1i32; let _ = &{ x }; + //~^ unnecessary_cast } type I32Alias = i32; fn issue_9380() { let _: i32 = -1_i32; + //~^ unnecessary_cast let _: f32 = -(1) as f32; let _: i64 = -1_i64; + //~^ unnecessary_cast let _: i64 = -(1.0) as i64; let _ = -(1 + 1) as i64; @@ -206,8 +243,11 @@ mod fixable { fn issue_9563() { let _: f64 = (-8.0_f64).exp(); + //~^ unnecessary_cast #[allow(ambiguous_negative_literals)] let _: f64 = -8.0_f64.exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior + // + //~^^ unnecessary_cast } fn issue_9562_non_literal() { @@ -216,6 +256,7 @@ mod fixable { } let _num = foo(); + //~^ unnecessary_cast } fn issue_9603() { @@ -226,5 +267,6 @@ mod fixable { // `*x.pow(2)` which tries to dereference the return value rather than `x`. fn issue_11968(x: &usize) -> usize { { *x }.pow(2) + //~^ unnecessary_cast } } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs index 4a5ca231315eb..0f90a8b05965a 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs @@ -17,6 +17,7 @@ type PtrMutU8 = *mut u8; fn owo(ptr: *const T) -> *const T { ptr as *const T + //~^ unnecessary_cast } fn uwu(ptr: *const T) -> *const U { @@ -52,21 +53,32 @@ fn bbb() -> UnsignedThirtyTwoBitInteger { fn main() { // Test cast_unnecessary 1i32 as i32; + //~^ unnecessary_cast 1f32 as f32; + //~^ unnecessary_cast false as bool; + //~^ unnecessary_cast &1i32 as &i32; -1_i32 as i32; + //~^ unnecessary_cast - 1_i32 as i32; + //~^ unnecessary_cast -1f32 as f32; + //~^ unnecessary_cast 1_i32 as i32; + //~^ unnecessary_cast 1_f32 as f32; + //~^ unnecessary_cast let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8; + //~^ unnecessary_cast [1u8, 2].as_ptr() as *const u8; + //~^ unnecessary_cast [1u8, 2].as_ptr() as *mut u8; [1u8, 2].as_mut_ptr() as *mut u8; + //~^ unnecessary_cast [1u8, 2].as_mut_ptr() as *const u8; [1u8, 2].as_ptr() as PtrConstU8; [1u8, 2].as_ptr() as PtrMutU8; @@ -78,9 +90,12 @@ fn main() { let _: *mut u8 = [1u8, 2].as_mut_ptr() as *mut _; owo::([1u32].as_ptr()) as *const u32; + //~^ unnecessary_cast uwu::([1u32].as_ptr()) as *const u8; + //~^ unnecessary_cast // this will not lint in the function body even though they have the same type, instead here uwu::([1u32].as_ptr()) as *const u32; + //~^ unnecessary_cast // macro version macro_rules! foo { @@ -116,8 +131,10 @@ fn main() { let pid = unsafe { fake_libc::getpid() }; pid as i32; aaa() as u32; + //~^ unnecessary_cast let x = aaa(); aaa() as u32; + //~^ unnecessary_cast // Will not lint currently. bbb() as u32; let x = bbb(); @@ -154,13 +171,21 @@ mod fixable { fn main() { // casting integer literal to float is unnecessary 100 as f32; + //~^ unnecessary_cast 100 as f64; + //~^ unnecessary_cast 100_i32 as f64; + //~^ unnecessary_cast let _ = -100 as f32; + //~^ unnecessary_cast let _ = -100 as f64; + //~^ unnecessary_cast let _ = -100_i32 as f64; + //~^ unnecessary_cast 100. as f32; + //~^ unnecessary_cast 100. as f64; + //~^ unnecessary_cast // Should not trigger #[rustfmt::skip] let v = vec!(1); @@ -173,32 +198,44 @@ mod fixable { 0b11 as f64; 1 as u32; + //~^ unnecessary_cast 0x10 as i32; + //~^ unnecessary_cast 0b10 as usize; + //~^ unnecessary_cast 0o73 as u16; + //~^ unnecessary_cast 1_000_000_000 as u32; + //~^ unnecessary_cast 1.0 as f64; + //~^ unnecessary_cast 0.5 as f32; + //~^ unnecessary_cast 1.0 as u16; let _ = -1 as i32; + //~^ unnecessary_cast let _ = -1.0 as f32; + //~^ unnecessary_cast let _ = 1 as I32Alias; let _ = &1 as &I32Alias; let x = 1i32; let _ = &(x as i32); + //~^ unnecessary_cast } type I32Alias = i32; fn issue_9380() { let _: i32 = -(1) as i32; + //~^ unnecessary_cast let _: f32 = -(1) as f32; let _: i64 = -(1) as i64; + //~^ unnecessary_cast let _: i64 = -(1.0) as i64; let _ = -(1 + 1) as i64; @@ -206,8 +243,11 @@ mod fixable { fn issue_9563() { let _: f64 = (-8.0 as f64).exp(); + //~^ unnecessary_cast #[allow(ambiguous_negative_literals)] let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior + // + //~^^ unnecessary_cast } fn issue_9562_non_literal() { @@ -216,6 +256,7 @@ mod fixable { } let _num = foo() as f32; + //~^ unnecessary_cast } fn issue_9603() { @@ -226,5 +267,6 @@ mod fixable { // `*x.pow(2)` which tries to dereference the return value rather than `x`. fn issue_11968(x: &usize) -> usize { (*x as usize).pow(2) + //~^ unnecessary_cast } } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index 80fd5c13d8185..c83770c1a2992 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -8,241 +8,241 @@ LL | ptr as *const T = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:54:5 + --> tests/ui/unnecessary_cast.rs:55:5 | LL | 1i32 as i32; | ^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:55:5 + --> tests/ui/unnecessary_cast.rs:57:5 | LL | 1f32 as f32; | ^^^^^^^^^^^ help: try: `1_f32` error: casting to the same type is unnecessary (`bool` -> `bool`) - --> tests/ui/unnecessary_cast.rs:56:5 + --> tests/ui/unnecessary_cast.rs:59:5 | LL | false as bool; | ^^^^^^^^^^^^^ help: try: `false` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:59:5 + --> tests/ui/unnecessary_cast.rs:63:5 | LL | -1_i32 as i32; | ^^^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:60:5 + --> tests/ui/unnecessary_cast.rs:65:5 | LL | - 1_i32 as i32; | ^^^^^^^^^^^^^^ help: try: `- 1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:61:5 + --> tests/ui/unnecessary_cast.rs:67:5 | LL | -1f32 as f32; | ^^^^^^^^^^^^ help: try: `-1_f32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:62:5 + --> tests/ui/unnecessary_cast.rs:69:5 | LL | 1_i32 as i32; | ^^^^^^^^^^^^ help: try: `1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:63:5 + --> tests/ui/unnecessary_cast.rs:71:5 | LL | 1_f32 as f32; | ^^^^^^^^^^^^ help: try: `1_f32` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:65:22 + --> tests/ui/unnecessary_cast.rs:74:22 | LL | let _: *mut u8 = [1u8, 2].as_ptr() as *const u8 as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:67:5 + --> tests/ui/unnecessary_cast.rs:77:5 | LL | [1u8, 2].as_ptr() as *const u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*mut u8` -> `*mut u8`) - --> tests/ui/unnecessary_cast.rs:69:5 + --> tests/ui/unnecessary_cast.rs:80:5 | LL | [1u8, 2].as_mut_ptr() as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `[1u8, 2].as_mut_ptr()` error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) - --> tests/ui/unnecessary_cast.rs:80:5 + --> tests/ui/unnecessary_cast.rs:92:5 | LL | owo::([1u32].as_ptr()) as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `owo::([1u32].as_ptr())` error: casting raw pointers to the same type and constness is unnecessary (`*const u8` -> `*const u8`) - --> tests/ui/unnecessary_cast.rs:81:5 + --> tests/ui/unnecessary_cast.rs:94:5 | LL | uwu::([1u32].as_ptr()) as *const u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` error: casting raw pointers to the same type and constness is unnecessary (`*const u32` -> `*const u32`) - --> tests/ui/unnecessary_cast.rs:83:5 + --> tests/ui/unnecessary_cast.rs:97:5 | LL | uwu::([1u32].as_ptr()) as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `uwu::([1u32].as_ptr())` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:118:5 + --> tests/ui/unnecessary_cast.rs:133:5 | LL | aaa() as u32; | ^^^^^^^^^^^^ help: try: `aaa()` error: casting to the same type is unnecessary (`u32` -> `u32`) - --> tests/ui/unnecessary_cast.rs:120:5 + --> tests/ui/unnecessary_cast.rs:136:5 | LL | aaa() as u32; | ^^^^^^^^^^^^ help: try: `aaa()` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:156:9 + --> tests/ui/unnecessary_cast.rs:173:9 | LL | 100 as f32; | ^^^^^^^^^^ help: try: `100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:157:9 + --> tests/ui/unnecessary_cast.rs:175:9 | LL | 100 as f64; | ^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:158:9 + --> tests/ui/unnecessary_cast.rs:177:9 | LL | 100_i32 as f64; | ^^^^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:159:17 + --> tests/ui/unnecessary_cast.rs:179:17 | LL | let _ = -100 as f32; | ^^^^^^^^^^^ help: try: `-100_f32` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:160:17 + --> tests/ui/unnecessary_cast.rs:181:17 | LL | let _ = -100 as f64; | ^^^^^^^^^^^ help: try: `-100_f64` error: casting integer literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:161:17 + --> tests/ui/unnecessary_cast.rs:183:17 | LL | let _ = -100_i32 as f64; | ^^^^^^^^^^^^^^^ help: try: `-100_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:162:9 + --> tests/ui/unnecessary_cast.rs:185:9 | LL | 100. as f32; | ^^^^^^^^^^^ help: try: `100_f32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:163:9 + --> tests/ui/unnecessary_cast.rs:187:9 | LL | 100. as f64; | ^^^^^^^^^^^ help: try: `100_f64` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:175:9 + --> tests/ui/unnecessary_cast.rs:200:9 | LL | 1 as u32; | ^^^^^^^^ help: try: `1_u32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:176:9 + --> tests/ui/unnecessary_cast.rs:202:9 | LL | 0x10 as i32; | ^^^^^^^^^^^ help: try: `0x10_i32` error: casting integer literal to `usize` is unnecessary - --> tests/ui/unnecessary_cast.rs:177:9 + --> tests/ui/unnecessary_cast.rs:204:9 | LL | 0b10 as usize; | ^^^^^^^^^^^^^ help: try: `0b10_usize` error: casting integer literal to `u16` is unnecessary - --> tests/ui/unnecessary_cast.rs:178:9 + --> tests/ui/unnecessary_cast.rs:206:9 | LL | 0o73 as u16; | ^^^^^^^^^^^ help: try: `0o73_u16` error: casting integer literal to `u32` is unnecessary - --> tests/ui/unnecessary_cast.rs:179:9 + --> tests/ui/unnecessary_cast.rs:208:9 | LL | 1_000_000_000 as u32; | ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:181:9 + --> tests/ui/unnecessary_cast.rs:211:9 | LL | 1.0 as f64; | ^^^^^^^^^^ help: try: `1.0_f64` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:182:9 + --> tests/ui/unnecessary_cast.rs:213:9 | LL | 0.5 as f32; | ^^^^^^^^^^ help: try: `0.5_f32` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:186:17 + --> tests/ui/unnecessary_cast.rs:218:17 | LL | let _ = -1 as i32; | ^^^^^^^^^ help: try: `-1_i32` error: casting float literal to `f32` is unnecessary - --> tests/ui/unnecessary_cast.rs:187:17 + --> tests/ui/unnecessary_cast.rs:220:17 | LL | let _ = -1.0 as f32; | ^^^^^^^^^^^ help: try: `-1.0_f32` error: casting to the same type is unnecessary (`i32` -> `i32`) - --> tests/ui/unnecessary_cast.rs:193:18 + --> tests/ui/unnecessary_cast.rs:227:18 | LL | let _ = &(x as i32); | ^^^^^^^^^^ help: try: `{ x }` error: casting integer literal to `i32` is unnecessary - --> tests/ui/unnecessary_cast.rs:199:22 + --> tests/ui/unnecessary_cast.rs:234:22 | LL | let _: i32 = -(1) as i32; | ^^^^^^^^^^^ help: try: `-1_i32` error: casting integer literal to `i64` is unnecessary - --> tests/ui/unnecessary_cast.rs:201:22 + --> tests/ui/unnecessary_cast.rs:237:22 | LL | let _: i64 = -(1) as i64; | ^^^^^^^^^^^ help: try: `-1_i64` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:208:22 + --> tests/ui/unnecessary_cast.rs:245:22 | LL | let _: f64 = (-8.0 as f64).exp(); | ^^^^^^^^^^^^^ help: try: `(-8.0_f64)` error: casting float literal to `f64` is unnecessary - --> tests/ui/unnecessary_cast.rs:210:23 + --> tests/ui/unnecessary_cast.rs:248:23 | LL | let _: f64 = -(8.0 as f64).exp(); // should suggest `-8.0_f64.exp()` here not to change code behavior | ^^^^^^^^^^^^ help: try: `8.0_f64` error: casting to the same type is unnecessary (`f32` -> `f32`) - --> tests/ui/unnecessary_cast.rs:218:20 + --> tests/ui/unnecessary_cast.rs:258:20 | LL | let _num = foo() as f32; | ^^^^^^^^^^^^ help: try: `foo()` error: casting to the same type is unnecessary (`usize` -> `usize`) - --> tests/ui/unnecessary_cast.rs:228:9 + --> tests/ui/unnecessary_cast.rs:269:9 | LL | (*x as usize).pow(2) | ^^^^^^^^^^^^^ help: try: `{ *x }` diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs index 36adf19c91ca7..2bb64c3e80e34 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs @@ -2,8 +2,7 @@ //@no-rustfix fn main() { let _ = std::ptr::null() as *const u8; - //~^ ERROR: casting raw pointers to the same type and constness is unnecessary (`*cons - //~| NOTE: `-D clippy::unnecessary-cast` implied by `-D warnings` + //~^ unnecessary_cast } mod issue11113 { @@ -19,7 +18,7 @@ mod issue11113 { impl TearOff { unsafe fn query(&self) { ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)() - //~^ ERROR: casting raw pointers to the same type and constness is unnecessary + //~^ unnecessary_cast } } } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr index cafaffeae6c36..6ba1c78730667 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr @@ -8,7 +8,7 @@ LL | let _ = std::ptr::null() as *const u8; = help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]` error: casting raw pointers to the same type and constness is unnecessary (`*mut issue11113::Vtbl` -> `*mut issue11113::Vtbl`) - --> tests/ui/unnecessary_cast_unfixable.rs:21:16 + --> tests/ui/unnecessary_cast_unfixable.rs:20:16 | LL | ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*(self.object as *mut *mut _)` diff --git a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs index 9915f8b843efd..e7e01248dfbed 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.rs @@ -2,22 +2,25 @@ #![warn(clippy::unnecessary_clippy_cfg)] #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg +//~| duplicated_attributes #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg +//~| duplicated_attributes #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] -//~^ ERROR: no need to put clippy lints behind a `clippy` cfg +//~^ unnecessary_clippy_cfg + pub struct Bar; fn main() {} diff --git a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr index 01f842a657de5..f66c68949548b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clippy_cfg.stderr @@ -24,19 +24,19 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] = note: write instead: `#![deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg - --> tests/ui/unnecessary_clippy_cfg.rs:10:1 + --> tests/ui/unnecessary_clippy_cfg.rs:11:1 | LL | #![cfg_attr(clippy, deny(clippy::non_minimal_cfg))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#![deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg - --> tests/ui/unnecessary_clippy_cfg.rs:13:1 + --> tests/ui/unnecessary_clippy_cfg.rs:14:1 | LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg - --> tests/ui/unnecessary_clippy_cfg.rs:15:36 + --> tests/ui/unnecessary_clippy_cfg.rs:16:36 | LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] = note: write instead: `#[deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg - --> tests/ui/unnecessary_clippy_cfg.rs:17:36 + --> tests/ui/unnecessary_clippy_cfg.rs:18:36 | LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] = note: write instead: `#[deny(clippy::non_minimal_cfg)]` error: no need to put clippy lints behind a `clippy` cfg - --> tests/ui/unnecessary_clippy_cfg.rs:19:1 + --> tests/ui/unnecessary_clippy_cfg.rs:21:1 | LL | #[cfg_attr(clippy, deny(clippy::non_minimal_cfg))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `#[deny(clippy::non_minimal_cfg)]` @@ -77,18 +77,18 @@ LL | #![cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] = help: to override `-D warnings` add `#[allow(clippy::duplicated_attributes)]` error: duplicated attribute - --> tests/ui/unnecessary_clippy_cfg.rs:17:25 + --> tests/ui/unnecessary_clippy_cfg.rs:18:25 | LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ | note: first defined here - --> tests/ui/unnecessary_clippy_cfg.rs:15:25 + --> tests/ui/unnecessary_clippy_cfg.rs:16:25 | LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ help: remove this attribute - --> tests/ui/unnecessary_clippy_cfg.rs:17:25 + --> tests/ui/unnecessary_clippy_cfg.rs:18:25 | LL | #[cfg_attr(clippy, deny(dead_code, clippy::non_minimal_cfg))] | ^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs index 12ac96aa64caa..7335b6f9f0390 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs @@ -21,34 +21,36 @@ fn clone_on_ref_ptr() { let arc_weak = Arc::downgrade(&arc); rc.clone(); - //~^ ERROR: using `.clone()` on a ref-counted pointer - //~| NOTE: `-D clippy::clone-on-ref-ptr` implied by `-D warnings` + //~^ clone_on_ref_ptr + Rc::clone(&rc); arc.clone(); - //~^ ERROR: using `.clone()` on a ref-counted pointer + //~^ clone_on_ref_ptr + Arc::clone(&arc); rcweak.clone(); - //~^ ERROR: using `.clone()` on a ref-counted pointer + //~^ clone_on_ref_ptr + rc::Weak::clone(&rcweak); arc_weak.clone(); - //~^ ERROR: using `.clone()` on a ref-counted pointer + //~^ clone_on_ref_ptr + sync::Weak::clone(&arc_weak); let x = Arc::new(SomeImpl); let _: Arc = x.clone(); - //~^ ERROR: using `.clone()` on a ref-counted pointer + //~^ clone_on_ref_ptr } fn clone_on_copy_generic(t: T) { t.clone(); - //~^ ERROR: using `clone` on type `T` which implements the `Copy` trait - //~| NOTE: `-D clippy::clone-on-copy` implied by `-D warnings` + //~^ clone_on_copy Some(t).clone(); - //~^ ERROR: using `clone` on type `Option` which implements the `Copy` trait + //~^ clone_on_copy } mod many_derefs { @@ -83,7 +85,8 @@ mod many_derefs { fn go1() { let a = A; let _: E = a.clone(); - //~^ ERROR: using `clone` on type `E` which implements the `Copy` trait + //~^ clone_on_copy + let _: E = *****a; } } @@ -103,6 +106,6 @@ mod issue2076 { fn func() -> Option> { let rc = Rc::new(42); Some(try_opt!(Some(rc)).clone()) - //~^ ERROR: using `.clone()` on a ref-counted pointer + //~^ clone_on_ref_ptr } } diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr index e34a387c77e2e..a4fdf09cd5dcb 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr @@ -14,25 +14,25 @@ LL | arc.clone(); | ^^^^^^^^^^^ help: try: `Arc::::clone(&arc)` error: using `.clone()` on a ref-counted pointer - --> tests/ui/unnecessary_clone.rs:32:5 + --> tests/ui/unnecessary_clone.rs:33:5 | LL | rcweak.clone(); | ^^^^^^^^^^^^^^ help: try: `Weak::::clone(&rcweak)` error: using `.clone()` on a ref-counted pointer - --> tests/ui/unnecessary_clone.rs:36:5 + --> tests/ui/unnecessary_clone.rs:38:5 | LL | arc_weak.clone(); | ^^^^^^^^^^^^^^^^ help: try: `Weak::::clone(&arc_weak)` error: using `.clone()` on a ref-counted pointer - --> tests/ui/unnecessary_clone.rs:41:33 + --> tests/ui/unnecessary_clone.rs:44:33 | LL | let _: Arc = x.clone(); | ^^^^^^^^^ help: try: `Arc::::clone(&x)` error: using `clone` on type `T` which implements the `Copy` trait - --> tests/ui/unnecessary_clone.rs:46:5 + --> tests/ui/unnecessary_clone.rs:49:5 | LL | t.clone(); | ^^^^^^^^^ help: try removing the `clone` call: `t` @@ -41,19 +41,19 @@ LL | t.clone(); = help: to override `-D warnings` add `#[allow(clippy::clone_on_copy)]` error: using `clone` on type `Option` which implements the `Copy` trait - --> tests/ui/unnecessary_clone.rs:50:5 + --> tests/ui/unnecessary_clone.rs:52:5 | LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` error: using `clone` on type `E` which implements the `Copy` trait - --> tests/ui/unnecessary_clone.rs:85:20 + --> tests/ui/unnecessary_clone.rs:87:20 | LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` error: using `.clone()` on a ref-counted pointer - --> tests/ui/unnecessary_clone.rs:105:14 + --> tests/ui/unnecessary_clone.rs:108:14 | LL | Some(try_opt!(Some(rc)).clone()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Rc::::clone(&try_opt!(Some(rc)))` diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed index b6dd1f2677435..bae8f066cf12e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed @@ -4,40 +4,40 @@ fn main() { // --- TryFromMethod `T::try_from(u)` --- let _: i64 = 0i32.into(); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _: i64 = 0i32.into(); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryFromFunction `T::try_from(U)` --- let _ = i64::from(0i32); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _ = i64::from(0i32); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryIntoFunction `U::try_into(t)` --- let _: i64 = i32::into(0); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _: i64 = i32::into(0i32); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryFromFunction `>::try_from(U)` --- let _ = >::from(0); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _ = >::from(0); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryIntoFunction `>::try_into(U)` --- let _: i64 = >::into(0); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _: i64 = >::into(0); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions } diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs index 6f8df7365e897..04c9826f3765e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs +++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs @@ -4,40 +4,40 @@ fn main() { // --- TryFromMethod `T::try_from(u)` --- let _: i64 = 0i32.try_into().unwrap(); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _: i64 = 0i32.try_into().expect("can't happen"); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryFromFunction `T::try_from(U)` --- let _ = i64::try_from(0i32).unwrap(); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _ = i64::try_from(0i32).expect("can't happen"); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryIntoFunction `U::try_into(t)` --- let _: i64 = i32::try_into(0).unwrap(); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _: i64 = i32::try_into(0i32).expect("can't happen"); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryFromFunction `>::try_from(U)` --- let _ = >::try_from(0).unwrap(); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _ = >::try_from(0).expect("can't happen"); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions // --- TryIntoFunction `>::try_into(U)` --- let _: i64 = >::try_into(0).unwrap(); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions let _: i64 = >::try_into(0).expect("can't happen"); - //~^ ERROR: use of a fallible conversion when an infallible one could be used + //~^ unnecessary_fallible_conversions } diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs index 8cf102ab0a557..c4f1b6bc7e3d7 100644 --- a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs +++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs @@ -3,29 +3,33 @@ fn main() { let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None }); - //~^ ERROR: this `.filter_map` can be written more simply - //~| NOTE: `-D clippy::unnecessary-filter-map` implied by `-D warnings` + //~^ unnecessary_filter_map + let _ = (0..4).filter_map(|x| { - //~^ ERROR: this `.filter_map` can be written more simply + //~^ unnecessary_filter_map + if x > 1 { return Some(x); }; None }); let _ = (0..4).filter_map(|x| match x { - //~^ ERROR: this `.filter_map` can be written more simply + //~^ unnecessary_filter_map 0 | 1 => None, _ => Some(x), }); let _ = (0..4).filter_map(|x| Some(x + 1)); - //~^ ERROR: this `.filter_map` can be written more simply + //~^ unnecessary_filter_map let _ = (0..4).filter_map(i32::checked_abs); let _ = (0..4).filter_map(Some); let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); + //~^ redundant_closure + //~| unnecessary_filter_map + //~| unnecessary_filter_map } fn filter_map_none_changes_item_type() -> impl Iterator { @@ -163,4 +167,5 @@ fn issue11260() { // #11260 is about unnecessary_find_map, but the fix also kind of applies to // unnecessary_filter_map let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n)); + //~^ unnecessary_filter_map } diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr index b21589c5f8445..6683444b72730 100644 --- a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr @@ -13,15 +13,15 @@ error: this `.filter_map` can be written more simply LL | let _ = (0..4).filter_map(|x| { | _____________^ LL | | +LL | | LL | | if x > 1 { -LL | | return Some(x); -LL | | }; +... | LL | | None LL | | }); | |______^ help: try instead: `filter` error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:15:13 + --> tests/ui/unnecessary_filter_map.rs:16:13 | LL | let _ = (0..4).filter_map(|x| match x { | _____________^ @@ -32,13 +32,13 @@ LL | | }); | |______^ help: try instead: `filter` error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:21:13 + --> tests/ui/unnecessary_filter_map.rs:22:13 | LL | let _ = (0..4).filter_map(|x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map` error: redundant closure - --> tests/ui/unnecessary_filter_map.rs:28:57 + --> tests/ui/unnecessary_filter_map.rs:29:57 | LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); | ^^^^^^^^^^^ help: replace the closure with the function itself: `Some` @@ -47,19 +47,19 @@ LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: filter_map is unnecessary - --> tests/ui/unnecessary_filter_map.rs:28:61 + --> tests/ui/unnecessary_filter_map.rs:29:61 | LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); | ^^^^ help: try removing the filter_map error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:28:13 + --> tests/ui/unnecessary_filter_map.rs:29:13 | LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map` error: this `.filter_map` can be written more simply - --> tests/ui/unnecessary_filter_map.rs:165:14 + --> tests/ui/unnecessary_filter_map.rs:169:14 | LL | let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `filter` diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.rs b/src/tools/clippy/tests/ui/unnecessary_find_map.rs index c357d85324819..8c8a3799f0216 100644 --- a/src/tools/clippy/tests/ui/unnecessary_find_map.rs +++ b/src/tools/clippy/tests/ui/unnecessary_find_map.rs @@ -3,23 +3,24 @@ fn main() { let _ = (0..4).find_map(|x| if x > 1 { Some(x) } else { None }); - //~^ ERROR: this `.find_map` can be written more simply - //~| NOTE: `-D clippy::unnecessary-find-map` implied by `-D warnings` + //~^ unnecessary_find_map + let _ = (0..4).find_map(|x| { - //~^ ERROR: this `.find_map` can be written more simply + //~^ unnecessary_find_map + if x > 1 { return Some(x); }; None }); let _ = (0..4).find_map(|x| match x { - //~^ ERROR: this `.find_map` can be written more simply + //~^ unnecessary_find_map 0 | 1 => None, _ => Some(x), }); let _ = (0..4).find_map(|x| Some(x + 1)); - //~^ ERROR: this `.find_map` can be written more simply + //~^ unnecessary_find_map let _ = (0..4).find_map(i32::checked_abs); } @@ -31,5 +32,6 @@ fn find_map_none_changes_item_type() -> Option { fn issue11260() { let y = Some(1); let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n)); + //~^ unnecessary_find_map let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(y)); // different option, so can't be just `.find()` } diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr index 98a6c3d164a63..94e320773a6fe 100644 --- a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr @@ -13,15 +13,15 @@ error: this `.find_map` can be written more simply LL | let _ = (0..4).find_map(|x| { | _____________^ LL | | +LL | | LL | | if x > 1 { -LL | | return Some(x); -LL | | }; +... | LL | | None LL | | }); | |______^ help: try instead: `find` error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:15:13 + --> tests/ui/unnecessary_find_map.rs:16:13 | LL | let _ = (0..4).find_map(|x| match x { | _____________^ @@ -32,13 +32,13 @@ LL | | }); | |______^ help: try instead: `find` error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:21:13 + --> tests/ui/unnecessary_find_map.rs:22:13 | LL | let _ = (0..4).find_map(|x| Some(x + 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map(..).next()` error: this `.find_map` can be written more simply - --> tests/ui/unnecessary_find_map.rs:33:14 + --> tests/ui/unnecessary_find_map.rs:34:14 | LL | let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `find` diff --git a/src/tools/clippy/tests/ui/unnecessary_first_then_check.fixed b/src/tools/clippy/tests/ui/unnecessary_first_then_check.fixed index 7202e1bbd179c..aa049eb33751b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_first_then_check.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_first_then_check.fixed @@ -4,19 +4,26 @@ fn main() { let s = [1, 2, 3]; let _: bool = !s.is_empty(); + //~^ unnecessary_first_then_check let _: bool = s.is_empty(); + //~^ unnecessary_first_then_check let v = vec![1, 2, 3]; let _: bool = !v.is_empty(); + //~^ unnecessary_first_then_check let n = [[1, 2, 3], [4, 5, 6]]; let _: bool = !n[0].is_empty(); + //~^ unnecessary_first_then_check let _: bool = n[0].is_empty(); + //~^ unnecessary_first_then_check struct Foo { bar: &'static [i32], } let f = [Foo { bar: &[] }]; let _: bool = !f[0].bar.is_empty(); + //~^ unnecessary_first_then_check let _: bool = f[0].bar.is_empty(); + //~^ unnecessary_first_then_check } diff --git a/src/tools/clippy/tests/ui/unnecessary_first_then_check.rs b/src/tools/clippy/tests/ui/unnecessary_first_then_check.rs index 762b959992883..4c2ac3ba40a21 100644 --- a/src/tools/clippy/tests/ui/unnecessary_first_then_check.rs +++ b/src/tools/clippy/tests/ui/unnecessary_first_then_check.rs @@ -4,19 +4,26 @@ fn main() { let s = [1, 2, 3]; let _: bool = s.first().is_some(); + //~^ unnecessary_first_then_check let _: bool = s.first().is_none(); + //~^ unnecessary_first_then_check let v = vec![1, 2, 3]; let _: bool = v.first().is_some(); + //~^ unnecessary_first_then_check let n = [[1, 2, 3], [4, 5, 6]]; let _: bool = n[0].first().is_some(); + //~^ unnecessary_first_then_check let _: bool = n[0].first().is_none(); + //~^ unnecessary_first_then_check struct Foo { bar: &'static [i32], } let f = [Foo { bar: &[] }]; let _: bool = f[0].bar.first().is_some(); + //~^ unnecessary_first_then_check let _: bool = f[0].bar.first().is_none(); + //~^ unnecessary_first_then_check } diff --git a/src/tools/clippy/tests/ui/unnecessary_first_then_check.stderr b/src/tools/clippy/tests/ui/unnecessary_first_then_check.stderr index bbaf7e68edabb..408b388ecf71a 100644 --- a/src/tools/clippy/tests/ui/unnecessary_first_then_check.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_first_then_check.stderr @@ -8,37 +8,37 @@ LL | let _: bool = s.first().is_some(); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_first_then_check)]` error: unnecessary use of `first().is_none()` to check if slice is empty - --> tests/ui/unnecessary_first_then_check.rs:7:21 + --> tests/ui/unnecessary_first_then_check.rs:8:21 | LL | let _: bool = s.first().is_none(); | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` error: unnecessary use of `first().is_some()` to check if slice is not empty - --> tests/ui/unnecessary_first_then_check.rs:10:19 + --> tests/ui/unnecessary_first_then_check.rs:12:19 | LL | let _: bool = v.first().is_some(); | ^^^^^^^^^^^^^^^^^^^ help: replace this with: `!v.is_empty()` error: unnecessary use of `first().is_some()` to check if slice is not empty - --> tests/ui/unnecessary_first_then_check.rs:13:19 + --> tests/ui/unnecessary_first_then_check.rs:16:19 | LL | let _: bool = n[0].first().is_some(); | ^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!n[0].is_empty()` error: unnecessary use of `first().is_none()` to check if slice is empty - --> tests/ui/unnecessary_first_then_check.rs:14:24 + --> tests/ui/unnecessary_first_then_check.rs:18:24 | LL | let _: bool = n[0].first().is_none(); | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` error: unnecessary use of `first().is_some()` to check if slice is not empty - --> tests/ui/unnecessary_first_then_check.rs:20:19 + --> tests/ui/unnecessary_first_then_check.rs:25:19 | LL | let _: bool = f[0].bar.first().is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this with: `!f[0].bar.is_empty()` error: unnecessary use of `first().is_none()` to check if slice is empty - --> tests/ui/unnecessary_first_then_check.rs:21:28 + --> tests/ui/unnecessary_first_then_check.rs:27:28 | LL | let _: bool = f[0].bar.first().is_none(); | ^^^^^^^^^^^^^^^^^ help: replace this with: `is_empty()` diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.fixed b/src/tools/clippy/tests/ui/unnecessary_fold.fixed index c5bc11b55ab5c..1c331be75094d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_fold.fixed @@ -8,19 +8,25 @@ fn is_any(acc: bool, x: usize) -> bool { fn unnecessary_fold() { // Can be replaced by .any let _ = (0..3).any(|x| x > 2); + //~^ unnecessary_fold // Can be replaced by .any (checking suggestion) let _ = (0..3).fold(false, is_any); + //~^ redundant_closure // Can be replaced by .all let _ = (0..3).all(|x| x > 2); + //~^ unnecessary_fold // Can be replaced by .sum let _: i32 = (0..3).sum(); + //~^ unnecessary_fold // Can be replaced by .product let _: i32 = (0..3).product(); + //~^ unnecessary_fold } /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)` fn unnecessary_fold_span_for_multi_element_chain() { let _: bool = (0..3).map(|x| 2 * x).any(|x| x > 2); + //~^ unnecessary_fold } /// Calls which should not trigger the `UNNECESSARY_FOLD` lint @@ -51,6 +57,7 @@ fn unnecessary_fold_over_multiple_lines() { .map(|x| x + 1) .filter(|x| x % 2 == 0) .any(|x| x > 2); + //~^ unnecessary_fold } fn issue10000() { @@ -62,16 +69,25 @@ fn issue10000() { fn smoketest_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().sum::(), 0); + //~^ unnecessary_fold // more cases: let _ = map.values().sum::(); + //~^ unnecessary_fold let _ = map.values().product::(); + //~^ unnecessary_fold let _: i32 = map.values().sum(); + //~^ unnecessary_fold let _: i32 = map.values().product(); + //~^ unnecessary_fold anything(map.values().sum::()); + //~^ unnecessary_fold anything(map.values().product::()); + //~^ unnecessary_fold num(map.values().sum()); + //~^ unnecessary_fold num(map.values().product()); + //~^ unnecessary_fold } smoketest_map(HashMap::new()); diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.rs b/src/tools/clippy/tests/ui/unnecessary_fold.rs index 3a5136eeeaeb7..e2050e37e3b1c 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.rs +++ b/src/tools/clippy/tests/ui/unnecessary_fold.rs @@ -8,19 +8,25 @@ fn is_any(acc: bool, x: usize) -> bool { fn unnecessary_fold() { // Can be replaced by .any let _ = (0..3).fold(false, |acc, x| acc || x > 2); + //~^ unnecessary_fold // Can be replaced by .any (checking suggestion) let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); + //~^ redundant_closure // Can be replaced by .all let _ = (0..3).fold(true, |acc, x| acc && x > 2); + //~^ unnecessary_fold // Can be replaced by .sum let _: i32 = (0..3).fold(0, |acc, x| acc + x); + //~^ unnecessary_fold // Can be replaced by .product let _: i32 = (0..3).fold(1, |acc, x| acc * x); + //~^ unnecessary_fold } /// Should trigger the `UNNECESSARY_FOLD` lint, with an error span including exactly `.fold(...)` fn unnecessary_fold_span_for_multi_element_chain() { let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); + //~^ unnecessary_fold } /// Calls which should not trigger the `UNNECESSARY_FOLD` lint @@ -51,6 +57,7 @@ fn unnecessary_fold_over_multiple_lines() { .map(|x| x + 1) .filter(|x| x % 2 == 0) .fold(false, |acc, x| acc || x > 2); + //~^ unnecessary_fold } fn issue10000() { @@ -62,16 +69,25 @@ fn issue10000() { fn smoketest_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x + y), 0); + //~^ unnecessary_fold // more cases: let _ = map.values().fold(0, |x, y| x + y); + //~^ unnecessary_fold let _ = map.values().fold(1, |x, y| x * y); + //~^ unnecessary_fold let _: i32 = map.values().fold(0, |x, y| x + y); + //~^ unnecessary_fold let _: i32 = map.values().fold(1, |x, y| x * y); + //~^ unnecessary_fold anything(map.values().fold(0, |x, y| x + y)); + //~^ unnecessary_fold anything(map.values().fold(1, |x, y| x * y)); + //~^ unnecessary_fold num(map.values().fold(0, |x, y| x + y)); + //~^ unnecessary_fold num(map.values().fold(1, |x, y| x * y)); + //~^ unnecessary_fold } smoketest_map(HashMap::new()); diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.stderr b/src/tools/clippy/tests/ui/unnecessary_fold.stderr index 31abab62f4c60..d82b1f39b48bb 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_fold.stderr @@ -8,7 +8,7 @@ LL | let _ = (0..3).fold(false, |acc, x| acc || x > 2); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fold)]` error: redundant closure - --> tests/ui/unnecessary_fold.rs:12:32 + --> tests/ui/unnecessary_fold.rs:13:32 | LL | let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `is_any` @@ -17,85 +17,85 @@ LL | let _ = (0..3).fold(false, |acc, x| is_any(acc, x)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:14:20 + --> tests/ui/unnecessary_fold.rs:16:20 | LL | let _ = (0..3).fold(true, |acc, x| acc && x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `all(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:16:25 + --> tests/ui/unnecessary_fold.rs:19:25 | LL | let _: i32 = (0..3).fold(0, |acc, x| acc + x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:18:25 + --> tests/ui/unnecessary_fold.rs:22:25 | LL | let _: i32 = (0..3).fold(1, |acc, x| acc * x); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:23:41 + --> tests/ui/unnecessary_fold.rs:28:41 | LL | let _: bool = (0..3).map(|x| 2 * x).fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:53:10 + --> tests/ui/unnecessary_fold.rs:59:10 | LL | .fold(false, |acc, x| acc || x > 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `any(|x| x > 2)` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:64:33 + --> tests/ui/unnecessary_fold.rs:71:33 | LL | assert_eq!(map.values().fold(0, |x, y| x + y), 0); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:67:30 + --> tests/ui/unnecessary_fold.rs:75:30 | LL | let _ = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:68:30 + --> tests/ui/unnecessary_fold.rs:77:30 | LL | let _ = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:69:35 + --> tests/ui/unnecessary_fold.rs:79:35 | LL | let _: i32 = map.values().fold(0, |x, y| x + y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:70:35 + --> tests/ui/unnecessary_fold.rs:81:35 | LL | let _: i32 = map.values().fold(1, |x, y| x * y); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:71:31 + --> tests/ui/unnecessary_fold.rs:83:31 | LL | anything(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:72:31 + --> tests/ui/unnecessary_fold.rs:85:31 | LL | anything(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product::()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:73:26 + --> tests/ui/unnecessary_fold.rs:87:26 | LL | num(map.values().fold(0, |x, y| x + y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `sum()` error: this `.fold` can be written more succinctly using another method - --> tests/ui/unnecessary_fold.rs:74:26 + --> tests/ui/unnecessary_fold.rs:89:26 | LL | num(map.values().fold(1, |x, y| x * y)); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `product()` diff --git a/src/tools/clippy/tests/ui/unnecessary_get_then_check.fixed b/src/tools/clippy/tests/ui/unnecessary_get_then_check.fixed index 178a3300c3460..c6da769544e0d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_get_then_check.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_get_then_check.fixed @@ -4,23 +4,33 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; fn main() { let s: HashSet = HashSet::new(); - let _ = s.contains("a"); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = !s.contains("a"); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.contains("a"); + //~^ unnecessary_get_then_check + let _ = !s.contains("a"); + //~^ unnecessary_get_then_check let s: HashMap = HashMap::new(); - let _ = s.contains_key("a"); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = !s.contains_key("a"); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.contains_key("a"); + //~^ unnecessary_get_then_check + let _ = !s.contains_key("a"); + //~^ unnecessary_get_then_check let s: BTreeSet = BTreeSet::new(); - let _ = s.contains("a"); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = !s.contains("a"); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.contains("a"); + //~^ unnecessary_get_then_check + let _ = !s.contains("a"); + //~^ unnecessary_get_then_check let s: BTreeMap = BTreeMap::new(); - let _ = s.contains_key("a"); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = !s.contains_key("a"); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.contains_key("a"); + //~^ unnecessary_get_then_check + let _ = !s.contains_key("a"); + //~^ unnecessary_get_then_check // Import to check that the generic annotations are kept! let s: HashSet = HashSet::new(); - let _ = s.contains::("a"); //~ ERROR: unnecessary use of `get::("a").is_some()` - let _ = !s.contains::("a"); //~ ERROR: unnecessary use of `get::("a").is_none()` + let _ = s.contains::("a"); + //~^ unnecessary_get_then_check + let _ = !s.contains::("a"); + //~^ unnecessary_get_then_check } diff --git a/src/tools/clippy/tests/ui/unnecessary_get_then_check.rs b/src/tools/clippy/tests/ui/unnecessary_get_then_check.rs index c197bdef47eaf..323ccc2136ce9 100644 --- a/src/tools/clippy/tests/ui/unnecessary_get_then_check.rs +++ b/src/tools/clippy/tests/ui/unnecessary_get_then_check.rs @@ -4,23 +4,33 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; fn main() { let s: HashSet = HashSet::new(); - let _ = s.get("a").is_some(); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = s.get("a").is_none(); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.get("a").is_some(); + //~^ unnecessary_get_then_check + let _ = s.get("a").is_none(); + //~^ unnecessary_get_then_check let s: HashMap = HashMap::new(); - let _ = s.get("a").is_some(); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = s.get("a").is_none(); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.get("a").is_some(); + //~^ unnecessary_get_then_check + let _ = s.get("a").is_none(); + //~^ unnecessary_get_then_check let s: BTreeSet = BTreeSet::new(); - let _ = s.get("a").is_some(); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = s.get("a").is_none(); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.get("a").is_some(); + //~^ unnecessary_get_then_check + let _ = s.get("a").is_none(); + //~^ unnecessary_get_then_check let s: BTreeMap = BTreeMap::new(); - let _ = s.get("a").is_some(); //~ ERROR: unnecessary use of `get("a").is_some()` - let _ = s.get("a").is_none(); //~ ERROR: unnecessary use of `get("a").is_none()` + let _ = s.get("a").is_some(); + //~^ unnecessary_get_then_check + let _ = s.get("a").is_none(); + //~^ unnecessary_get_then_check // Import to check that the generic annotations are kept! let s: HashSet = HashSet::new(); - let _ = s.get::("a").is_some(); //~ ERROR: unnecessary use of `get::("a").is_some()` - let _ = s.get::("a").is_none(); //~ ERROR: unnecessary use of `get::("a").is_none()` + let _ = s.get::("a").is_some(); + //~^ unnecessary_get_then_check + let _ = s.get::("a").is_none(); + //~^ unnecessary_get_then_check } diff --git a/src/tools/clippy/tests/ui/unnecessary_get_then_check.stderr b/src/tools/clippy/tests/ui/unnecessary_get_then_check.stderr index 0477c03d16dd9..5ecb3d4e29dd2 100644 --- a/src/tools/clippy/tests/ui/unnecessary_get_then_check.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_get_then_check.stderr @@ -8,7 +8,7 @@ LL | let _ = s.get("a").is_some(); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_get_then_check)]` error: unnecessary use of `get("a").is_none()` - --> tests/ui/unnecessary_get_then_check.rs:8:15 + --> tests/ui/unnecessary_get_then_check.rs:9:15 | LL | let _ = s.get("a").is_none(); | --^^^^^^^^^^^^^^^^^^ @@ -16,13 +16,13 @@ LL | let _ = s.get("a").is_none(); | help: replace it with: `!s.contains("a")` error: unnecessary use of `get("a").is_some()` - --> tests/ui/unnecessary_get_then_check.rs:11:15 + --> tests/ui/unnecessary_get_then_check.rs:13:15 | LL | let _ = s.get("a").is_some(); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `contains_key("a")` error: unnecessary use of `get("a").is_none()` - --> tests/ui/unnecessary_get_then_check.rs:12:15 + --> tests/ui/unnecessary_get_then_check.rs:15:15 | LL | let _ = s.get("a").is_none(); | --^^^^^^^^^^^^^^^^^^ @@ -30,13 +30,13 @@ LL | let _ = s.get("a").is_none(); | help: replace it with: `!s.contains_key("a")` error: unnecessary use of `get("a").is_some()` - --> tests/ui/unnecessary_get_then_check.rs:15:15 + --> tests/ui/unnecessary_get_then_check.rs:19:15 | LL | let _ = s.get("a").is_some(); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `contains("a")` error: unnecessary use of `get("a").is_none()` - --> tests/ui/unnecessary_get_then_check.rs:16:15 + --> tests/ui/unnecessary_get_then_check.rs:21:15 | LL | let _ = s.get("a").is_none(); | --^^^^^^^^^^^^^^^^^^ @@ -44,13 +44,13 @@ LL | let _ = s.get("a").is_none(); | help: replace it with: `!s.contains("a")` error: unnecessary use of `get("a").is_some()` - --> tests/ui/unnecessary_get_then_check.rs:19:15 + --> tests/ui/unnecessary_get_then_check.rs:25:15 | LL | let _ = s.get("a").is_some(); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `contains_key("a")` error: unnecessary use of `get("a").is_none()` - --> tests/ui/unnecessary_get_then_check.rs:20:15 + --> tests/ui/unnecessary_get_then_check.rs:27:15 | LL | let _ = s.get("a").is_none(); | --^^^^^^^^^^^^^^^^^^ @@ -58,13 +58,13 @@ LL | let _ = s.get("a").is_none(); | help: replace it with: `!s.contains_key("a")` error: unnecessary use of `get::("a").is_some()` - --> tests/ui/unnecessary_get_then_check.rs:24:15 + --> tests/ui/unnecessary_get_then_check.rs:32:15 | LL | let _ = s.get::("a").is_some(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `contains::("a")` error: unnecessary use of `get::("a").is_none()` - --> tests/ui/unnecessary_get_then_check.rs:25:15 + --> tests/ui/unnecessary_get_then_check.rs:34:15 | LL | let _ = s.get::("a").is_none(); | --^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed index dc5e163ff04e4..aed2dbe1f1ce4 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed @@ -29,6 +29,7 @@ fn main() { // https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { for (t, path) in files { + //~^ unnecessary_to_owned let other = match get_file_path(t) { Ok(p) => p, Err(_) => { @@ -44,6 +45,7 @@ fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool { for (t, path) in files.iter() { + //~^ unnecessary_to_owned let other = match get_file_path(t) { Ok(p) => p, Err(_) => { @@ -175,7 +177,8 @@ mod issue_12821 { fn foo() { let v: Vec<_> = "hello".chars().collect(); for c in v.iter() { - //~^ ERROR: unnecessary use of `cloned` + //~^ unnecessary_to_owned + println!("{c}"); // should not suggest to remove `&` } } @@ -183,8 +186,9 @@ mod issue_12821 { fn bar() { let v: Vec<_> = "hello".chars().collect(); for c in v.iter() { - //~^ ERROR: unnecessary use of `cloned` - let ref_c = c; //~ HELP: remove any references to the binding + //~^ unnecessary_to_owned + + let ref_c = c; println!("{ref_c}"); } } @@ -192,8 +196,9 @@ mod issue_12821 { fn baz() { let v: Vec<_> = "hello".chars().enumerate().collect(); for (i, c) in v.iter() { - //~^ ERROR: unnecessary use of `cloned` - let ref_c = c; //~ HELP: remove any references to the binding + //~^ unnecessary_to_owned + + let ref_c = c; let ref_i = i; println!("{i} {ref_c}"); // should not suggest to remove `&` from `i` } diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs index 8f797ac717fb6..12fdd150e4233 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs @@ -29,6 +29,7 @@ fn main() { // https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { for (t, path) in files.iter().copied() { + //~^ unnecessary_to_owned let other = match get_file_path(&t) { Ok(p) => p, Err(_) => { @@ -44,6 +45,7 @@ fn check_files(files: &[(FileType, &std::path::Path)]) -> bool { fn check_files_vec(files: Vec<(FileType, &std::path::Path)>) -> bool { for (t, path) in files.iter().copied() { + //~^ unnecessary_to_owned let other = match get_file_path(&t) { Ok(p) => p, Err(_) => { @@ -175,7 +177,8 @@ mod issue_12821 { fn foo() { let v: Vec<_> = "hello".chars().collect(); for c in v.iter().cloned() { - //~^ ERROR: unnecessary use of `cloned` + //~^ unnecessary_to_owned + println!("{c}"); // should not suggest to remove `&` } } @@ -183,8 +186,9 @@ mod issue_12821 { fn bar() { let v: Vec<_> = "hello".chars().collect(); for c in v.iter().cloned() { - //~^ ERROR: unnecessary use of `cloned` - let ref_c = &c; //~ HELP: remove any references to the binding + //~^ unnecessary_to_owned + + let ref_c = &c; println!("{ref_c}"); } } @@ -192,8 +196,9 @@ mod issue_12821 { fn baz() { let v: Vec<_> = "hello".chars().enumerate().collect(); for (i, c) in v.iter().cloned() { - //~^ ERROR: unnecessary use of `cloned` - let ref_c = &c; //~ HELP: remove any references to the binding + //~^ unnecessary_to_owned + + let ref_c = &c; let ref_i = &i; println!("{i} {ref_c}"); // should not suggest to remove `&` from `i` } diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr index 6f2ae0ab1f35a..632c8f3711068 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr @@ -9,11 +9,12 @@ LL | for (t, path) in files.iter().copied() { help: remove any references to the binding | LL ~ for (t, path) in files { +LL | LL ~ let other = match get_file_path(t) { | error: unnecessary use of `copied` - --> tests/ui/unnecessary_iter_cloned.rs:46:22 + --> tests/ui/unnecessary_iter_cloned.rs:47:22 | LL | for (t, path) in files.iter().copied() { | ^^^^^^^^^^^^^^^^^^^^^ @@ -21,17 +22,18 @@ LL | for (t, path) in files.iter().copied() { help: remove any references to the binding | LL ~ for (t, path) in files.iter() { +LL | LL ~ let other = match get_file_path(t) { | error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:177:18 + --> tests/ui/unnecessary_iter_cloned.rs:179:18 | LL | for c in v.iter().cloned() { | ^^^^^^^^^^^^^^^^^ help: remove any references to the binding: `v.iter()` error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:185:18 + --> tests/ui/unnecessary_iter_cloned.rs:188:18 | LL | for c in v.iter().cloned() { | ^^^^^^^^^^^^^^^^^ @@ -40,11 +42,12 @@ help: remove any references to the binding | LL ~ for c in v.iter() { LL | +LL | LL ~ let ref_c = c; | error: unnecessary use of `cloned` - --> tests/ui/unnecessary_iter_cloned.rs:194:23 + --> tests/ui/unnecessary_iter_cloned.rs:198:23 | LL | for (i, c) in v.iter().cloned() { | ^^^^^^^^^^^^^^^^^ @@ -53,6 +56,7 @@ help: remove any references to the binding | LL ~ for (i, c) in v.iter() { LL | +LL | LL ~ let ref_c = c; LL ~ let ref_i = i; | diff --git a/src/tools/clippy/tests/ui/unnecessary_join.rs b/src/tools/clippy/tests/ui/unnecessary_join.rs index d042d9e5c2128..e58b2696645a9 100644 --- a/src/tools/clippy/tests/ui/unnecessary_join.rs +++ b/src/tools/clippy/tests/ui/unnecessary_join.rs @@ -8,6 +8,7 @@ fn main() { .iter() .map(|item| item.to_uppercase()) .collect::>() + //~^ unnecessary_join .join(""); println!("{}", output); @@ -17,6 +18,7 @@ fn main() { .iter() .map(|item| item.to_uppercase()) .collect::>() + //~^ unnecessary_join .join(""); println!("{}", output); diff --git a/src/tools/clippy/tests/ui/unnecessary_join.stderr b/src/tools/clippy/tests/ui/unnecessary_join.stderr index a06a1059033b7..a7677fe2f9eb6 100644 --- a/src/tools/clippy/tests/ui/unnecessary_join.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_join.stderr @@ -3,6 +3,7 @@ error: called `.collect::>().join("")` on an iterator | LL | .collect::>() | __________^ +LL | | LL | | .join(""); | |_________________^ help: consider using: `collect::()` | @@ -10,10 +11,11 @@ LL | | .join(""); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_join)]` error: called `.collect::>().join("")` on an iterator - --> tests/ui/unnecessary_join.rs:19:10 + --> tests/ui/unnecessary_join.rs:20:10 | LL | .collect::>() | __________^ +LL | | LL | | .join(""); | |_________________^ help: consider using: `collect::()` diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed index d8031c484e5e1..9a32908163897 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed @@ -81,42 +81,69 @@ fn main() { // Should lint - Option let _ = opt.unwrap_or(2); + //~^ unnecessary_lazy_evaluations let _ = opt.unwrap_or(astronomers_pi); + //~^ unnecessary_lazy_evaluations let _ = opt.unwrap_or(ext_str.some_field); + //~^ unnecessary_lazy_evaluations let _ = opt.unwrap_or_else(|| ext_arr[0]); let _ = opt.and(ext_opt); + //~^ unnecessary_lazy_evaluations let _ = opt.or(ext_opt); + //~^ unnecessary_lazy_evaluations let _ = opt.or(None); + //~^ unnecessary_lazy_evaluations let _ = opt.get_or_insert(2); + //~^ unnecessary_lazy_evaluations let _ = opt.ok_or(2); + //~^ unnecessary_lazy_evaluations let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); + //~^ unnecessary_lazy_evaluations let _ = cond.then_some(astronomers_pi); + //~^ unnecessary_lazy_evaluations let _ = true.then_some({}); + //~^ unnecessary_lazy_evaluations let _ = true.then_some({}); + //~^ unnecessary_lazy_evaluations // Should lint - Builtin deref let r = &1; let _ = Some(1).unwrap_or(*r); + //~^ unnecessary_lazy_evaluations let b = Box::new(1); let _ = Some(1).unwrap_or(*b); + //~^ unnecessary_lazy_evaluations // Should lint - Builtin deref through autoderef let _ = Some(1).as_ref().unwrap_or(&r); + //~^ unnecessary_lazy_evaluations let _ = Some(1).as_ref().unwrap_or(&b); + //~^ unnecessary_lazy_evaluations // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or(2); + //~^ unnecessary_lazy_evaluations let _ = Some(10).and(ext_opt); + //~^ unnecessary_lazy_evaluations let _: Option = None.or(ext_opt); + //~^ unnecessary_lazy_evaluations let _ = None.get_or_insert(2); + //~^ unnecessary_lazy_evaluations let _: Result = None.ok_or(2); + //~^ unnecessary_lazy_evaluations let _: Option = None.or(None); + //~^ unnecessary_lazy_evaluations let mut deep = Deep(Some(42)); let _ = deep.0.unwrap_or(2); + //~^ unnecessary_lazy_evaluations let _ = deep.0.and(ext_opt); + //~^ unnecessary_lazy_evaluations let _ = deep.0.or(None); + //~^ unnecessary_lazy_evaluations let _ = deep.0.get_or_insert(2); + //~^ unnecessary_lazy_evaluations let _ = deep.0.ok_or(2); + //~^ unnecessary_lazy_evaluations // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); @@ -148,16 +175,22 @@ fn main() { // should lint, bind_instead_of_map doesn't apply let _: Option = None.or(Some(3)); + //~^ unnecessary_lazy_evaluations let _ = deep.0.or(Some(3)); + //~^ unnecessary_lazy_evaluations let _ = opt.or(Some(3)); + //~^ unnecessary_lazy_evaluations // Should lint - Result let res: Result = Err(5); let res2: Result = Err(SomeStruct { some_field: 5 }); let _ = res2.unwrap_or(2); + //~^ unnecessary_lazy_evaluations let _ = res2.unwrap_or(astronomers_pi); + //~^ unnecessary_lazy_evaluations let _ = res2.unwrap_or(ext_str.some_field); + //~^ unnecessary_lazy_evaluations // Should not lint - Result let _ = res.unwrap_or_else(|err| err); @@ -180,13 +213,20 @@ fn main() { // should lint, bind_instead_of_map doesn't apply let _: Result = res.and(Err(2)); + //~^ unnecessary_lazy_evaluations let _: Result = res.and(Err(astronomers_pi)); + //~^ unnecessary_lazy_evaluations let _: Result = res.and(Err(ext_str.some_field)); + //~^ unnecessary_lazy_evaluations let _: Result = res.or(Ok(2)); + //~^ unnecessary_lazy_evaluations let _: Result = res.or(Ok(astronomers_pi)); + //~^ unnecessary_lazy_evaluations let _: Result = res.or(Ok(ext_str.some_field)); + //~^ unnecessary_lazy_evaluations let _: Result = res. + //~^ unnecessary_lazy_evaluations // some lines // some lines // some lines @@ -217,39 +257,39 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { // See comments in `eager_or_lazy.rs` for the rules that this is meant to follow let _x = false.then_some(i32::MAX + 1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(i32::MAX * 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(i32::MAX - 1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(i32::MIN - 1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(255u8 << 7); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(255u8 << 8); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(255u8 >> 8); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 255u8 >> x); let _x = false.then_some(i32::MAX + -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(-i32::MAX); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(-i32::MIN); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| -y); let _x = false.then_some(255 >> -7); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(255 << -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(1 / 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(x << -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(x << 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| x + x); let _x = false.then(|| x * x); let _x = false.then(|| x - x); @@ -259,19 +299,19 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { let _x = false.then(|| 1 + x); let _x = false.then_some(x / 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(x % 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| y / -1); let _x = false.then_some(1 / -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(i32::MIN / -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| i32::MIN / x as i32); let _x = false.then_some(i32::MIN / 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then_some(4 / 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 1 / x); // const eval doesn't read variables, but floating point math never panics, so we can still emit a @@ -279,5 +319,5 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { let f1 = 1.0; let f2 = 2.0; let _x = false.then_some(f1 + f2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations } diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs index ea55b1d9a905f..2d05ef5c29175 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs @@ -81,42 +81,69 @@ fn main() { // Should lint - Option let _ = opt.unwrap_or_else(|| 2); + //~^ unnecessary_lazy_evaluations let _ = opt.unwrap_or_else(|| astronomers_pi); + //~^ unnecessary_lazy_evaluations let _ = opt.unwrap_or_else(|| ext_str.some_field); + //~^ unnecessary_lazy_evaluations let _ = opt.unwrap_or_else(|| ext_arr[0]); let _ = opt.and_then(|_| ext_opt); + //~^ unnecessary_lazy_evaluations let _ = opt.or_else(|| ext_opt); + //~^ unnecessary_lazy_evaluations let _ = opt.or_else(|| None); + //~^ unnecessary_lazy_evaluations let _ = opt.get_or_insert_with(|| 2); + //~^ unnecessary_lazy_evaluations let _ = opt.ok_or_else(|| 2); + //~^ unnecessary_lazy_evaluations let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); + //~^ unnecessary_lazy_evaluations let _ = cond.then(|| astronomers_pi); + //~^ unnecessary_lazy_evaluations let _ = true.then(|| -> _ {}); + //~^ unnecessary_lazy_evaluations let _ = true.then(|| {}); + //~^ unnecessary_lazy_evaluations // Should lint - Builtin deref let r = &1; let _ = Some(1).unwrap_or_else(|| *r); + //~^ unnecessary_lazy_evaluations let b = Box::new(1); let _ = Some(1).unwrap_or_else(|| *b); + //~^ unnecessary_lazy_evaluations // Should lint - Builtin deref through autoderef let _ = Some(1).as_ref().unwrap_or_else(|| &r); + //~^ unnecessary_lazy_evaluations let _ = Some(1).as_ref().unwrap_or_else(|| &b); + //~^ unnecessary_lazy_evaluations // Cases when unwrap is not called on a simple variable let _ = Some(10).unwrap_or_else(|| 2); + //~^ unnecessary_lazy_evaluations let _ = Some(10).and_then(|_| ext_opt); + //~^ unnecessary_lazy_evaluations let _: Option = None.or_else(|| ext_opt); + //~^ unnecessary_lazy_evaluations let _ = None.get_or_insert_with(|| 2); + //~^ unnecessary_lazy_evaluations let _: Result = None.ok_or_else(|| 2); + //~^ unnecessary_lazy_evaluations let _: Option = None.or_else(|| None); + //~^ unnecessary_lazy_evaluations let mut deep = Deep(Some(42)); let _ = deep.0.unwrap_or_else(|| 2); + //~^ unnecessary_lazy_evaluations let _ = deep.0.and_then(|_| ext_opt); + //~^ unnecessary_lazy_evaluations let _ = deep.0.or_else(|| None); + //~^ unnecessary_lazy_evaluations let _ = deep.0.get_or_insert_with(|| 2); + //~^ unnecessary_lazy_evaluations let _ = deep.0.ok_or_else(|| 2); + //~^ unnecessary_lazy_evaluations // Should not lint - Option let _ = opt.unwrap_or_else(|| ext_str.return_some_field()); @@ -148,16 +175,22 @@ fn main() { // should lint, bind_instead_of_map doesn't apply let _: Option = None.or_else(|| Some(3)); + //~^ unnecessary_lazy_evaluations let _ = deep.0.or_else(|| Some(3)); + //~^ unnecessary_lazy_evaluations let _ = opt.or_else(|| Some(3)); + //~^ unnecessary_lazy_evaluations // Should lint - Result let res: Result = Err(5); let res2: Result = Err(SomeStruct { some_field: 5 }); let _ = res2.unwrap_or_else(|_| 2); + //~^ unnecessary_lazy_evaluations let _ = res2.unwrap_or_else(|_| astronomers_pi); + //~^ unnecessary_lazy_evaluations let _ = res2.unwrap_or_else(|_| ext_str.some_field); + //~^ unnecessary_lazy_evaluations // Should not lint - Result let _ = res.unwrap_or_else(|err| err); @@ -180,13 +213,20 @@ fn main() { // should lint, bind_instead_of_map doesn't apply let _: Result = res.and_then(|_| Err(2)); + //~^ unnecessary_lazy_evaluations let _: Result = res.and_then(|_| Err(astronomers_pi)); + //~^ unnecessary_lazy_evaluations let _: Result = res.and_then(|_| Err(ext_str.some_field)); + //~^ unnecessary_lazy_evaluations let _: Result = res.or_else(|_| Ok(2)); + //~^ unnecessary_lazy_evaluations let _: Result = res.or_else(|_| Ok(astronomers_pi)); + //~^ unnecessary_lazy_evaluations let _: Result = res.or_else(|_| Ok(ext_str.some_field)); + //~^ unnecessary_lazy_evaluations let _: Result = res. + //~^ unnecessary_lazy_evaluations // some lines // some lines // some lines @@ -217,39 +257,39 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { // See comments in `eager_or_lazy.rs` for the rules that this is meant to follow let _x = false.then(|| i32::MAX + 1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| i32::MAX * 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| i32::MAX - 1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| i32::MIN - 1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 255u8 << 7); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 255u8 << 8); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 255u8 >> 8); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 255u8 >> x); let _x = false.then(|| i32::MAX + -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| -i32::MAX); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| -i32::MIN); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| -y); let _x = false.then(|| 255 >> -7); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 255 << -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 1 / 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| x << -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| x << 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| x + x); let _x = false.then(|| x * x); let _x = false.then(|| x - x); @@ -259,19 +299,19 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { let _x = false.then(|| 1 + x); let _x = false.then(|| x / 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| x % 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| y / -1); let _x = false.then(|| 1 / -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| i32::MIN / -1); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| i32::MIN / x as i32); let _x = false.then(|| i32::MIN / 0); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 4 / 2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations let _x = false.then(|| 1 / x); // const eval doesn't read variables, but floating point math never panics, so we can still emit a @@ -279,5 +319,5 @@ fn panicky_arithmetic_ops(x: usize, y: isize) { let f1 = 1.0; let f2 = 2.0; let _x = false.then(|| f1 + f2); - //~^ ERROR: unnecessary closure used with `bool::then` + //~^ unnecessary_lazy_evaluations } diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr index 9bb1b71f0ed56..75a06a419c71b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr @@ -13,7 +13,7 @@ LL + let _ = opt.unwrap_or(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:84:13 + --> tests/ui/unnecessary_lazy_eval.rs:85:13 | LL | let _ = opt.unwrap_or_else(|| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let _ = opt.unwrap_or(astronomers_pi); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:85:13 + --> tests/ui/unnecessary_lazy_eval.rs:87:13 | LL | let _ = opt.unwrap_or_else(|| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let _ = opt.unwrap_or(ext_str.some_field); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:87:13 + --> tests/ui/unnecessary_lazy_eval.rs:90:13 | LL | let _ = opt.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + let _ = opt.and(ext_opt); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:88:13 + --> tests/ui/unnecessary_lazy_eval.rs:92:13 | LL | let _ = opt.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + let _ = opt.or(ext_opt); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:89:13 + --> tests/ui/unnecessary_lazy_eval.rs:94:13 | LL | let _ = opt.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + let _ = opt.or(None); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:90:13 + --> tests/ui/unnecessary_lazy_eval.rs:96:13 | LL | let _ = opt.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + let _ = opt.get_or_insert(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:91:13 + --> tests/ui/unnecessary_lazy_eval.rs:98:13 | LL | let _ = opt.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + let _ = opt.ok_or(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:92:13 + --> tests/ui/unnecessary_lazy_eval.rs:100:13 | LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + let _ = nested_tuple_opt.unwrap_or(Some((1, 2))); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:93:13 + --> tests/ui/unnecessary_lazy_eval.rs:102:13 | LL | let _ = cond.then(|| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + let _ = cond.then_some(astronomers_pi); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:94:13 + --> tests/ui/unnecessary_lazy_eval.rs:104:13 | LL | let _ = true.then(|| -> _ {}); | ^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + let _ = true.then_some({}); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:95:13 + --> tests/ui/unnecessary_lazy_eval.rs:106:13 | LL | let _ = true.then(|| {}); | ^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + let _ = true.then_some({}); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:99:13 + --> tests/ui/unnecessary_lazy_eval.rs:111:13 | LL | let _ = Some(1).unwrap_or_else(|| *r); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + let _ = Some(1).unwrap_or(*r); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:101:13 + --> tests/ui/unnecessary_lazy_eval.rs:114:13 | LL | let _ = Some(1).unwrap_or_else(|| *b); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + let _ = Some(1).unwrap_or(*b); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:103:13 + --> tests/ui/unnecessary_lazy_eval.rs:117:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + let _ = Some(1).as_ref().unwrap_or(&r); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:104:13 + --> tests/ui/unnecessary_lazy_eval.rs:119:13 | LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + let _ = Some(1).as_ref().unwrap_or(&b); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:107:13 + --> tests/ui/unnecessary_lazy_eval.rs:123:13 | LL | let _ = Some(10).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + let _ = Some(10).unwrap_or(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:108:13 + --> tests/ui/unnecessary_lazy_eval.rs:125:13 | LL | let _ = Some(10).and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + let _ = Some(10).and(ext_opt); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:109:28 + --> tests/ui/unnecessary_lazy_eval.rs:127:28 | LL | let _: Option = None.or_else(|| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + let _: Option = None.or(ext_opt); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:110:13 + --> tests/ui/unnecessary_lazy_eval.rs:129:13 | LL | let _ = None.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + let _ = None.get_or_insert(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:111:35 + --> tests/ui/unnecessary_lazy_eval.rs:131:35 | LL | let _: Result = None.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL + let _: Result = None.ok_or(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:112:28 + --> tests/ui/unnecessary_lazy_eval.rs:133:28 | LL | let _: Option = None.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL + let _: Option = None.or(None); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:115:13 + --> tests/ui/unnecessary_lazy_eval.rs:137:13 | LL | let _ = deep.0.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + let _ = deep.0.unwrap_or(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:116:13 + --> tests/ui/unnecessary_lazy_eval.rs:139:13 | LL | let _ = deep.0.and_then(|_| ext_opt); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -289,7 +289,7 @@ LL + let _ = deep.0.and(ext_opt); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:117:13 + --> tests/ui/unnecessary_lazy_eval.rs:141:13 | LL | let _ = deep.0.or_else(|| None); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL + let _ = deep.0.or(None); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:118:13 + --> tests/ui/unnecessary_lazy_eval.rs:143:13 | LL | let _ = deep.0.get_or_insert_with(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + let _ = deep.0.get_or_insert(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:119:13 + --> tests/ui/unnecessary_lazy_eval.rs:145:13 | LL | let _ = deep.0.ok_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + let _ = deep.0.ok_or(2); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:150:28 + --> tests/ui/unnecessary_lazy_eval.rs:177:28 | LL | let _: Option = None.or_else(|| Some(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + let _: Option = None.or(Some(3)); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:151:13 + --> tests/ui/unnecessary_lazy_eval.rs:179:13 | LL | let _ = deep.0.or_else(|| Some(3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + let _ = deep.0.or(Some(3)); | error: unnecessary closure used to substitute value for `Option::None` - --> tests/ui/unnecessary_lazy_eval.rs:152:13 + --> tests/ui/unnecessary_lazy_eval.rs:181:13 | LL | let _ = opt.or_else(|| Some(3)); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,7 +361,7 @@ LL + let _ = opt.or(Some(3)); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:158:13 + --> tests/ui/unnecessary_lazy_eval.rs:188:13 | LL | let _ = res2.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL + let _ = res2.unwrap_or(2); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:159:13 + --> tests/ui/unnecessary_lazy_eval.rs:190:13 | LL | let _ = res2.unwrap_or_else(|_| astronomers_pi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -385,7 +385,7 @@ LL + let _ = res2.unwrap_or(astronomers_pi); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:160:13 + --> tests/ui/unnecessary_lazy_eval.rs:192:13 | LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL + let _ = res2.unwrap_or(ext_str.some_field); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:182:35 + --> tests/ui/unnecessary_lazy_eval.rs:215:35 | LL | let _: Result = res.and_then(|_| Err(2)); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -409,7 +409,7 @@ LL + let _: Result = res.and(Err(2)); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:183:35 + --> tests/ui/unnecessary_lazy_eval.rs:217:35 | LL | let _: Result = res.and_then(|_| Err(astronomers_pi)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -421,7 +421,7 @@ LL + let _: Result = res.and(Err(astronomers_pi)); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:184:35 + --> tests/ui/unnecessary_lazy_eval.rs:219:35 | LL | let _: Result = res.and_then(|_| Err(ext_str.some_field)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -433,7 +433,7 @@ LL + let _: Result = res.and(Err(ext_str.some_field)); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:186:35 + --> tests/ui/unnecessary_lazy_eval.rs:222:35 | LL | let _: Result = res.or_else(|_| Ok(2)); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -445,7 +445,7 @@ LL + let _: Result = res.or(Ok(2)); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:187:35 + --> tests/ui/unnecessary_lazy_eval.rs:224:35 | LL | let _: Result = res.or_else(|_| Ok(astronomers_pi)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -457,7 +457,7 @@ LL + let _: Result = res.or(Ok(astronomers_pi)); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:188:35 + --> tests/ui/unnecessary_lazy_eval.rs:226:35 | LL | let _: Result = res.or_else(|_| Ok(ext_str.some_field)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -469,7 +469,7 @@ LL + let _: Result = res.or(Ok(ext_str.some_field)); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval.rs:189:35 + --> tests/ui/unnecessary_lazy_eval.rs:228:35 | LL | let _: Result = res. | ___________________________________^ @@ -484,7 +484,7 @@ LL + or(Ok(ext_str.some_field)); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:219:14 + --> tests/ui/unnecessary_lazy_eval.rs:259:14 | LL | let _x = false.then(|| i32::MAX + 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -496,7 +496,7 @@ LL + let _x = false.then_some(i32::MAX + 1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:221:14 + --> tests/ui/unnecessary_lazy_eval.rs:261:14 | LL | let _x = false.then(|| i32::MAX * 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -508,7 +508,7 @@ LL + let _x = false.then_some(i32::MAX * 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:223:14 + --> tests/ui/unnecessary_lazy_eval.rs:263:14 | LL | let _x = false.then(|| i32::MAX - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -520,7 +520,7 @@ LL + let _x = false.then_some(i32::MAX - 1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:225:14 + --> tests/ui/unnecessary_lazy_eval.rs:265:14 | LL | let _x = false.then(|| i32::MIN - 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -532,7 +532,7 @@ LL + let _x = false.then_some(i32::MIN - 1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:227:14 + --> tests/ui/unnecessary_lazy_eval.rs:267:14 | LL | let _x = false.then(|| (1 + 2 * 3 - 2 / 3 + 9) << 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -544,7 +544,7 @@ LL + let _x = false.then_some((1 + 2 * 3 - 2 / 3 + 9) << 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:229:14 + --> tests/ui/unnecessary_lazy_eval.rs:269:14 | LL | let _x = false.then(|| 255u8 << 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -556,7 +556,7 @@ LL + let _x = false.then_some(255u8 << 7); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:231:14 + --> tests/ui/unnecessary_lazy_eval.rs:271:14 | LL | let _x = false.then(|| 255u8 << 8); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -568,7 +568,7 @@ LL + let _x = false.then_some(255u8 << 8); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:233:14 + --> tests/ui/unnecessary_lazy_eval.rs:273:14 | LL | let _x = false.then(|| 255u8 >> 8); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -580,7 +580,7 @@ LL + let _x = false.then_some(255u8 >> 8); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:236:14 + --> tests/ui/unnecessary_lazy_eval.rs:276:14 | LL | let _x = false.then(|| i32::MAX + -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -592,7 +592,7 @@ LL + let _x = false.then_some(i32::MAX + -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:238:14 + --> tests/ui/unnecessary_lazy_eval.rs:278:14 | LL | let _x = false.then(|| -i32::MAX); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -604,7 +604,7 @@ LL + let _x = false.then_some(-i32::MAX); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:240:14 + --> tests/ui/unnecessary_lazy_eval.rs:280:14 | LL | let _x = false.then(|| -i32::MIN); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,7 +616,7 @@ LL + let _x = false.then_some(-i32::MIN); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:243:14 + --> tests/ui/unnecessary_lazy_eval.rs:283:14 | LL | let _x = false.then(|| 255 >> -7); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -628,7 +628,7 @@ LL + let _x = false.then_some(255 >> -7); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:245:14 + --> tests/ui/unnecessary_lazy_eval.rs:285:14 | LL | let _x = false.then(|| 255 << -1); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -640,7 +640,7 @@ LL + let _x = false.then_some(255 << -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:247:14 + --> tests/ui/unnecessary_lazy_eval.rs:287:14 | LL | let _x = false.then(|| 1 / 0); | ^^^^^^^^^^^^^^^^^^^^ @@ -652,7 +652,7 @@ LL + let _x = false.then_some(1 / 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:249:14 + --> tests/ui/unnecessary_lazy_eval.rs:289:14 | LL | let _x = false.then(|| x << -1); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -664,7 +664,7 @@ LL + let _x = false.then_some(x << -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:251:14 + --> tests/ui/unnecessary_lazy_eval.rs:291:14 | LL | let _x = false.then(|| x << 2); | ^^^^^^^^^^^^^^^^^^^^^ @@ -676,7 +676,7 @@ LL + let _x = false.then_some(x << 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:261:14 + --> tests/ui/unnecessary_lazy_eval.rs:301:14 | LL | let _x = false.then(|| x / 0); | ^^^^^^^^^^^^^^^^^^^^ @@ -688,7 +688,7 @@ LL + let _x = false.then_some(x / 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:263:14 + --> tests/ui/unnecessary_lazy_eval.rs:303:14 | LL | let _x = false.then(|| x % 0); | ^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +700,7 @@ LL + let _x = false.then_some(x % 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:266:14 + --> tests/ui/unnecessary_lazy_eval.rs:306:14 | LL | let _x = false.then(|| 1 / -1); | ^^^^^^^^^^^^^^^^^^^^^ @@ -712,7 +712,7 @@ LL + let _x = false.then_some(1 / -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:268:14 + --> tests/ui/unnecessary_lazy_eval.rs:308:14 | LL | let _x = false.then(|| i32::MIN / -1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -724,7 +724,7 @@ LL + let _x = false.then_some(i32::MIN / -1); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:271:14 + --> tests/ui/unnecessary_lazy_eval.rs:311:14 | LL | let _x = false.then(|| i32::MIN / 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -736,7 +736,7 @@ LL + let _x = false.then_some(i32::MIN / 0); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:273:14 + --> tests/ui/unnecessary_lazy_eval.rs:313:14 | LL | let _x = false.then(|| 4 / 2); | ^^^^^^^^^^^^^^^^^^^^ @@ -748,7 +748,7 @@ LL + let _x = false.then_some(4 / 2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval.rs:281:14 + --> tests/ui/unnecessary_lazy_eval.rs:321:14 | LL | let _x = false.then(|| f1 + f2); | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs index 412d4aaafb4a1..6d28d544dfe0b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs @@ -11,15 +11,16 @@ struct SomeStruct { fn main() { // fix will break type inference let _ = Ok(1).unwrap_or_else(|()| 2); - //~^ ERROR: unnecessary closure used to substitute value for `Result::Err` - //~| NOTE: `-D clippy::unnecessary-lazy-evaluations` implied by `-D warnings` + //~^ unnecessary_lazy_evaluations + mod e { pub struct E; } let _ = Ok(1).unwrap_or_else(|e::E| 2); - //~^ ERROR: unnecessary closure used to substitute value for `Result::Err` + //~^ unnecessary_lazy_evaluations + let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); - //~^ ERROR: unnecessary closure used to substitute value for `Result::Err` + //~^ unnecessary_lazy_evaluations // Fix #6343 let arr = [(Some(1),)]; @@ -29,4 +30,5 @@ fn main() { fn issue11672() { // Return type annotation helps type inference and removing it can break code let _ = true.then(|| -> &[u8] { &[] }); + //~^ unnecessary_lazy_evaluations } diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr index 9688c44c9145e..5174acc1e9f95 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr @@ -25,7 +25,7 @@ LL + let _ = Ok(1).unwrap_or(2); | error: unnecessary closure used to substitute value for `Result::Err` - --> tests/ui/unnecessary_lazy_eval_unfixable.rs:21:13 + --> tests/ui/unnecessary_lazy_eval_unfixable.rs:22:13 | LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let _ = Ok(1).unwrap_or(2); | error: unnecessary closure used with `bool::then` - --> tests/ui/unnecessary_lazy_eval_unfixable.rs:31:13 + --> tests/ui/unnecessary_lazy_eval_unfixable.rs:32:13 | LL | let _ = true.then(|| -> &[u8] { &[] }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_bound.fixed b/src/tools/clippy/tests/ui/unnecessary_literal_bound.fixed index 107e397466d00..ec0d2db154cea 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_bound.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_literal_bound.fixed @@ -7,6 +7,7 @@ struct Struct<'a> { impl Struct<'_> { // Should warn fn returns_lit(&self) -> &'static str { + //~^ unnecessary_literal_bound "Hello" } @@ -27,6 +28,7 @@ impl Struct<'_> { // Should warn fn contionally_returns_literals_explicit(&self, cond: bool) -> &'static str { + //~^ unnecessary_literal_bound if cond { return "Literal"; } @@ -51,6 +53,7 @@ trait ReturnsStr { impl ReturnsStr for u8 { // Should warn, even though not useful without trait refinement fn trait_method(&self) -> &'static str { + //~^ unnecessary_literal_bound "Literal" } } diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_bound.rs b/src/tools/clippy/tests/ui/unnecessary_literal_bound.rs index b371ff9d3a2e3..713dee4d30a60 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_bound.rs +++ b/src/tools/clippy/tests/ui/unnecessary_literal_bound.rs @@ -7,6 +7,7 @@ struct Struct<'a> { impl Struct<'_> { // Should warn fn returns_lit(&self) -> &str { + //~^ unnecessary_literal_bound "Hello" } @@ -27,6 +28,7 @@ impl Struct<'_> { // Should warn fn contionally_returns_literals_explicit(&self, cond: bool) -> &str { + //~^ unnecessary_literal_bound if cond { return "Literal"; } @@ -51,6 +53,7 @@ trait ReturnsStr { impl ReturnsStr for u8 { // Should warn, even though not useful without trait refinement fn trait_method(&self) -> &str { + //~^ unnecessary_literal_bound "Literal" } } diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_bound.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_bound.stderr index 512b2f9a0afad..e510d86622d63 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_bound.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_literal_bound.stderr @@ -8,13 +8,13 @@ LL | fn returns_lit(&self) -> &str { = help: to override `-D warnings` add `#[allow(clippy::unnecessary_literal_bound)]` error: returning a `str` unnecessarily tied to the lifetime of arguments - --> tests/ui/unnecessary_literal_bound.rs:29:68 + --> tests/ui/unnecessary_literal_bound.rs:30:68 | LL | fn contionally_returns_literals_explicit(&self, cond: bool) -> &str { | ^^^^ help: try: `&'static str` error: returning a `str` unnecessarily tied to the lifetime of arguments - --> tests/ui/unnecessary_literal_bound.rs:53:31 + --> tests/ui/unnecessary_literal_bound.rs:55:31 | LL | fn trait_method(&self) -> &str { | ^^^^ help: try: `&'static str` diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed index b17343aa9ba5a..877f4ad41c7ef 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed @@ -9,73 +9,119 @@ fn unwrap_option_some() { let _val = 1; + //~^ unnecessary_literal_unwrap let _val = 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap } #[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }` fn unwrap_option_none() { let _val = panic!(); + //~^ unnecessary_literal_unwrap let _val = panic!("this always happens"); + //~^ unnecessary_literal_unwrap let _val: String = String::default(); + //~^ unnecessary_literal_unwrap let _val: u16 = 234; + //~^ unnecessary_literal_unwrap let _val: u16 = 234; + //~^ unnecessary_literal_unwrap let _val: u16 = { 234 }; + //~^ unnecessary_literal_unwrap let _val: u16 = { 234 }; + //~^ unnecessary_literal_unwrap panic!(); + //~^ unnecessary_literal_unwrap panic!("this always happens"); + //~^ unnecessary_literal_unwrap String::default(); + //~^ unnecessary_literal_unwrap 234; + //~^ unnecessary_literal_unwrap 234; + //~^ unnecessary_literal_unwrap { 234 }; + //~^ unnecessary_literal_unwrap { 234 }; + //~^ unnecessary_literal_unwrap } fn unwrap_result_ok() { let _val = 1; + //~^ unnecessary_literal_unwrap let _val = 1; + //~^ unnecessary_literal_unwrap let _val = panic!("{:?}", 1); + //~^ unnecessary_literal_unwrap let _val = panic!("{1}: {:?}", 1, "this always happens"); + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap panic!("{:?}", 1); + //~^ unnecessary_literal_unwrap panic!("{1}: {:?}", 1, "this always happens"); + //~^ unnecessary_literal_unwrap } fn unwrap_result_err() { let _val = 1; + //~^ unnecessary_literal_unwrap let _val = 1; + //~^ unnecessary_literal_unwrap let _val = panic!("{:?}", 1); + //~^ unnecessary_literal_unwrap let _val = panic!("{1}: {:?}", 1, "this always happens"); + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap panic!("{:?}", 1); + //~^ unnecessary_literal_unwrap panic!("{1}: {:?}", 1, "this always happens"); + //~^ unnecessary_literal_unwrap } fn unwrap_methods_option() { let _val = 1; + //~^ unnecessary_literal_unwrap let _val = 1; + //~^ unnecessary_literal_unwrap let _val = 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap } fn unwrap_methods_result() { let _val = 1; + //~^ unnecessary_literal_unwrap let _val = 1; + //~^ unnecessary_literal_unwrap let _val = 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap 1; + //~^ unnecessary_literal_unwrap } fn unwrap_from_binding() { @@ -90,12 +136,20 @@ fn unwrap_from_binding() { fn unwrap_unchecked() { let _ = 1; + //~^ unnecessary_literal_unwrap let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe block + // + //~^^ unnecessary_literal_unwrap let _ = 1 + 1; + //~^ unnecessary_literal_unwrap let _ = 1; + //~^ unnecessary_literal_unwrap let _ = unsafe { 1 + *(&1 as *const i32) }; + //~^ unnecessary_literal_unwrap let _ = 1 + 1; + //~^ unnecessary_literal_unwrap let _ = 123; + //~^ unnecessary_literal_unwrap } fn main() { diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs index 7bd8deea4d1b3..c0a35ae78a71d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.rs @@ -9,73 +9,119 @@ fn unwrap_option_some() { let _val = Some(1).unwrap(); + //~^ unnecessary_literal_unwrap let _val = Some(1).expect("this never happens"); + //~^ unnecessary_literal_unwrap Some(1).unwrap(); + //~^ unnecessary_literal_unwrap Some(1).expect("this never happens"); + //~^ unnecessary_literal_unwrap } #[rustfmt::skip] // force rustfmt not to remove braces in `|| { 234 }` fn unwrap_option_none() { let _val = None::<()>.unwrap(); + //~^ unnecessary_literal_unwrap let _val = None::<()>.expect("this always happens"); + //~^ unnecessary_literal_unwrap let _val: String = None.unwrap_or_default(); + //~^ unnecessary_literal_unwrap let _val: u16 = None.unwrap_or(234); + //~^ unnecessary_literal_unwrap let _val: u16 = None.unwrap_or_else(|| 234); + //~^ unnecessary_literal_unwrap let _val: u16 = None.unwrap_or_else(|| { 234 }); + //~^ unnecessary_literal_unwrap let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 }); + //~^ unnecessary_literal_unwrap None::<()>.unwrap(); + //~^ unnecessary_literal_unwrap None::<()>.expect("this always happens"); + //~^ unnecessary_literal_unwrap None::.unwrap_or_default(); + //~^ unnecessary_literal_unwrap None::.unwrap_or(234); + //~^ unnecessary_literal_unwrap None::.unwrap_or_else(|| 234); + //~^ unnecessary_literal_unwrap None::.unwrap_or_else(|| { 234 }); + //~^ unnecessary_literal_unwrap None::.unwrap_or_else(|| -> u16 { 234 }); + //~^ unnecessary_literal_unwrap } fn unwrap_result_ok() { let _val = Ok::<_, ()>(1).unwrap(); + //~^ unnecessary_literal_unwrap let _val = Ok::<_, ()>(1).expect("this never happens"); + //~^ unnecessary_literal_unwrap let _val = Ok::<_, ()>(1).unwrap_err(); + //~^ unnecessary_literal_unwrap let _val = Ok::<_, ()>(1).expect_err("this always happens"); + //~^ unnecessary_literal_unwrap Ok::<_, ()>(1).unwrap(); + //~^ unnecessary_literal_unwrap Ok::<_, ()>(1).expect("this never happens"); + //~^ unnecessary_literal_unwrap Ok::<_, ()>(1).unwrap_err(); + //~^ unnecessary_literal_unwrap Ok::<_, ()>(1).expect_err("this always happens"); + //~^ unnecessary_literal_unwrap } fn unwrap_result_err() { let _val = Err::<(), _>(1).unwrap_err(); + //~^ unnecessary_literal_unwrap let _val = Err::<(), _>(1).expect_err("this never happens"); + //~^ unnecessary_literal_unwrap let _val = Err::<(), _>(1).unwrap(); + //~^ unnecessary_literal_unwrap let _val = Err::<(), _>(1).expect("this always happens"); + //~^ unnecessary_literal_unwrap Err::<(), _>(1).unwrap_err(); + //~^ unnecessary_literal_unwrap Err::<(), _>(1).expect_err("this never happens"); + //~^ unnecessary_literal_unwrap Err::<(), _>(1).unwrap(); + //~^ unnecessary_literal_unwrap Err::<(), _>(1).expect("this always happens"); + //~^ unnecessary_literal_unwrap } fn unwrap_methods_option() { let _val = Some(1).unwrap_or(2); + //~^ unnecessary_literal_unwrap let _val = Some(1).unwrap_or_default(); + //~^ unnecessary_literal_unwrap let _val = Some(1).unwrap_or_else(|| 2); + //~^ unnecessary_literal_unwrap Some(1).unwrap_or(2); + //~^ unnecessary_literal_unwrap Some(1).unwrap_or_default(); + //~^ unnecessary_literal_unwrap Some(1).unwrap_or_else(|| 2); + //~^ unnecessary_literal_unwrap } fn unwrap_methods_result() { let _val = Ok::<_, ()>(1).unwrap_or(2); + //~^ unnecessary_literal_unwrap let _val = Ok::<_, ()>(1).unwrap_or_default(); + //~^ unnecessary_literal_unwrap let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); + //~^ unnecessary_literal_unwrap Ok::<_, ()>(1).unwrap_or(2); + //~^ unnecessary_literal_unwrap Ok::<_, ()>(1).unwrap_or_default(); + //~^ unnecessary_literal_unwrap Ok::<_, ()>(1).unwrap_or_else(|_| 2); + //~^ unnecessary_literal_unwrap } fn unwrap_from_binding() { @@ -90,12 +136,20 @@ fn unwrap_from_binding() { fn unwrap_unchecked() { let _ = unsafe { Some(1).unwrap_unchecked() }; + //~^ unnecessary_literal_unwrap let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block + // + //~^^ unnecessary_literal_unwrap let _ = unsafe { Some(1).unwrap_unchecked() } + 1; + //~^ unnecessary_literal_unwrap let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; + //~^ unnecessary_literal_unwrap let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; + //~^ unnecessary_literal_unwrap let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; + //~^ unnecessary_literal_unwrap let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; + //~^ unnecessary_literal_unwrap } fn main() { diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr index 631bf08372666..cd90763263e9d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr @@ -13,7 +13,7 @@ LL + let _val = 1; | error: used `expect()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:12:16 + --> tests/ui/unnecessary_literal_unwrap.rs:13:16 | LL | let _val = Some(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let _val = 1; | error: used `unwrap()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:14:5 + --> tests/ui/unnecessary_literal_unwrap.rs:16:5 | LL | Some(1).unwrap(); | ^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + 1; | error: used `expect()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:15:5 + --> tests/ui/unnecessary_literal_unwrap.rs:18:5 | LL | Some(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,13 +49,13 @@ LL + 1; | error: used `unwrap()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:20:16 + --> tests/ui/unnecessary_literal_unwrap.rs:24:16 | LL | let _val = None::<()>.unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` error: used `expect()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:21:16 + --> tests/ui/unnecessary_literal_unwrap.rs:26:16 | LL | let _val = None::<()>.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,13 +67,13 @@ LL + let _val = panic!("this always happens"); | error: used `unwrap_or_default()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:22:24 + --> tests/ui/unnecessary_literal_unwrap.rs:28:24 | LL | let _val: String = None.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` error: used `unwrap_or()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:23:21 + --> tests/ui/unnecessary_literal_unwrap.rs:30:21 | LL | let _val: u16 = None.unwrap_or(234); | ^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + let _val: u16 = 234; | error: used `unwrap_or_else()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:24:21 + --> tests/ui/unnecessary_literal_unwrap.rs:32:21 | LL | let _val: u16 = None.unwrap_or_else(|| 234); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + let _val: u16 = 234; | error: used `unwrap_or_else()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:25:21 + --> tests/ui/unnecessary_literal_unwrap.rs:34:21 | LL | let _val: u16 = None.unwrap_or_else(|| { 234 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + let _val: u16 = { 234 }; | error: used `unwrap_or_else()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:26:21 + --> tests/ui/unnecessary_literal_unwrap.rs:36:21 | LL | let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -121,13 +121,13 @@ LL + let _val: u16 = { 234 }; | error: used `unwrap()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:28:5 + --> tests/ui/unnecessary_literal_unwrap.rs:39:5 | LL | None::<()>.unwrap(); | ^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap()`: `panic!()` error: used `expect()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:29:5 + --> tests/ui/unnecessary_literal_unwrap.rs:41:5 | LL | None::<()>.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -139,13 +139,13 @@ LL + panic!("this always happens"); | error: used `unwrap_or_default()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:30:5 + --> tests/ui/unnecessary_literal_unwrap.rs:43:5 | LL | None::.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `String::default()` error: used `unwrap_or()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:31:5 + --> tests/ui/unnecessary_literal_unwrap.rs:45:5 | LL | None::.unwrap_or(234); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + 234; | error: used `unwrap_or_else()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:32:5 + --> tests/ui/unnecessary_literal_unwrap.rs:47:5 | LL | None::.unwrap_or_else(|| 234); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + 234; | error: used `unwrap_or_else()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:33:5 + --> tests/ui/unnecessary_literal_unwrap.rs:49:5 | LL | None::.unwrap_or_else(|| { 234 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + { 234 }; | error: used `unwrap_or_else()` on `None` value - --> tests/ui/unnecessary_literal_unwrap.rs:34:5 + --> tests/ui/unnecessary_literal_unwrap.rs:51:5 | LL | None::.unwrap_or_else(|| -> u16 { 234 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + { 234 }; | error: used `unwrap()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:38:16 + --> tests/ui/unnecessary_literal_unwrap.rs:56:16 | LL | let _val = Ok::<_, ()>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -205,7 +205,7 @@ LL + let _val = 1; | error: used `expect()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:39:16 + --> tests/ui/unnecessary_literal_unwrap.rs:58:16 | LL | let _val = Ok::<_, ()>(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -217,7 +217,7 @@ LL + let _val = 1; | error: used `unwrap_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:40:16 + --> tests/ui/unnecessary_literal_unwrap.rs:60:16 | LL | let _val = Ok::<_, ()>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +229,7 @@ LL + let _val = panic!("{:?}", 1); | error: used `expect_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:41:16 + --> tests/ui/unnecessary_literal_unwrap.rs:62:16 | LL | let _val = Ok::<_, ()>(1).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -241,7 +241,7 @@ LL + let _val = panic!("{1}: {:?}", 1, "this always happens"); | error: used `unwrap()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:43:5 + --> tests/ui/unnecessary_literal_unwrap.rs:65:5 | LL | Ok::<_, ()>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -253,7 +253,7 @@ LL + 1; | error: used `expect()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:44:5 + --> tests/ui/unnecessary_literal_unwrap.rs:67:5 | LL | Ok::<_, ()>(1).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,7 +265,7 @@ LL + 1; | error: used `unwrap_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:45:5 + --> tests/ui/unnecessary_literal_unwrap.rs:69:5 | LL | Ok::<_, ()>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -277,7 +277,7 @@ LL + panic!("{:?}", 1); | error: used `expect_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:46:5 + --> tests/ui/unnecessary_literal_unwrap.rs:71:5 | LL | Ok::<_, ()>(1).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -289,7 +289,7 @@ LL + panic!("{1}: {:?}", 1, "this always happens"); | error: used `unwrap_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:50:16 + --> tests/ui/unnecessary_literal_unwrap.rs:76:16 | LL | let _val = Err::<(), _>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -301,7 +301,7 @@ LL + let _val = 1; | error: used `expect_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:51:16 + --> tests/ui/unnecessary_literal_unwrap.rs:78:16 | LL | let _val = Err::<(), _>(1).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -313,7 +313,7 @@ LL + let _val = 1; | error: used `unwrap()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:52:16 + --> tests/ui/unnecessary_literal_unwrap.rs:80:16 | LL | let _val = Err::<(), _>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -325,7 +325,7 @@ LL + let _val = panic!("{:?}", 1); | error: used `expect()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:53:16 + --> tests/ui/unnecessary_literal_unwrap.rs:82:16 | LL | let _val = Err::<(), _>(1).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +337,7 @@ LL + let _val = panic!("{1}: {:?}", 1, "this always happens"); | error: used `unwrap_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:55:5 + --> tests/ui/unnecessary_literal_unwrap.rs:85:5 | LL | Err::<(), _>(1).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -349,7 +349,7 @@ LL + 1; | error: used `expect_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:56:5 + --> tests/ui/unnecessary_literal_unwrap.rs:87:5 | LL | Err::<(), _>(1).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,7 +361,7 @@ LL + 1; | error: used `unwrap()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:57:5 + --> tests/ui/unnecessary_literal_unwrap.rs:89:5 | LL | Err::<(), _>(1).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +373,7 @@ LL + panic!("{:?}", 1); | error: used `expect()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:58:5 + --> tests/ui/unnecessary_literal_unwrap.rs:91:5 | LL | Err::<(), _>(1).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -385,7 +385,7 @@ LL + panic!("{1}: {:?}", 1, "this always happens"); | error: used `unwrap_or()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:62:16 + --> tests/ui/unnecessary_literal_unwrap.rs:96:16 | LL | let _val = Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -397,7 +397,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:63:16 + --> tests/ui/unnecessary_literal_unwrap.rs:98:16 | LL | let _val = Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -409,7 +409,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:64:16 + --> tests/ui/unnecessary_literal_unwrap.rs:100:16 | LL | let _val = Some(1).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -421,7 +421,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:66:5 + --> tests/ui/unnecessary_literal_unwrap.rs:103:5 | LL | Some(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^ @@ -433,7 +433,7 @@ LL + 1; | error: used `unwrap_or_default()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:67:5 + --> tests/ui/unnecessary_literal_unwrap.rs:105:5 | LL | Some(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -445,7 +445,7 @@ LL + 1; | error: used `unwrap_or_else()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:68:5 + --> tests/ui/unnecessary_literal_unwrap.rs:107:5 | LL | Some(1).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -457,7 +457,7 @@ LL + 1; | error: used `unwrap_or()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:72:16 + --> tests/ui/unnecessary_literal_unwrap.rs:112:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -469,7 +469,7 @@ LL + let _val = 1; | error: used `unwrap_or_default()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:73:16 + --> tests/ui/unnecessary_literal_unwrap.rs:114:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -481,7 +481,7 @@ LL + let _val = 1; | error: used `unwrap_or_else()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:74:16 + --> tests/ui/unnecessary_literal_unwrap.rs:116:16 | LL | let _val = Ok::<_, ()>(1).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -493,7 +493,7 @@ LL + let _val = 1; | error: used `unwrap_or()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:76:5 + --> tests/ui/unnecessary_literal_unwrap.rs:119:5 | LL | Ok::<_, ()>(1).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -505,7 +505,7 @@ LL + 1; | error: used `unwrap_or_default()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:77:5 + --> tests/ui/unnecessary_literal_unwrap.rs:121:5 | LL | Ok::<_, ()>(1).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -517,7 +517,7 @@ LL + 1; | error: used `unwrap_or_else()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:78:5 + --> tests/ui/unnecessary_literal_unwrap.rs:123:5 | LL | Ok::<_, ()>(1).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -529,7 +529,7 @@ LL + 1; | error: used `unwrap_unchecked()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:92:22 + --> tests/ui/unnecessary_literal_unwrap.rs:138:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -541,7 +541,7 @@ LL + let _ = 1; | error: used `unwrap_unchecked()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:93:22 + --> tests/ui/unnecessary_literal_unwrap.rs:140:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() + *(&1 as *const i32) }; // needs to keep the unsafe block | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -553,7 +553,7 @@ LL + let _ = unsafe { 1 + *(&1 as *const i32) }; // needs to keep the unsafe | error: used `unwrap_unchecked()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap.rs:94:22 + --> tests/ui/unnecessary_literal_unwrap.rs:143:22 | LL | let _ = unsafe { Some(1).unwrap_unchecked() } + 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -565,7 +565,7 @@ LL + let _ = 1 + 1; | error: used `unwrap_unchecked()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:95:22 + --> tests/ui/unnecessary_literal_unwrap.rs:145:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -577,7 +577,7 @@ LL + let _ = 1; | error: used `unwrap_unchecked()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:96:22 + --> tests/ui/unnecessary_literal_unwrap.rs:147:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() + *(&1 as *const i32) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -589,7 +589,7 @@ LL + let _ = unsafe { 1 + *(&1 as *const i32) }; | error: used `unwrap_unchecked()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap.rs:97:22 + --> tests/ui/unnecessary_literal_unwrap.rs:149:22 | LL | let _ = unsafe { Ok::<_, ()>(1).unwrap_unchecked() } + 1; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -601,7 +601,7 @@ LL + let _ = 1 + 1; | error: used `unwrap_err_unchecked()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap.rs:98:22 + --> tests/ui/unnecessary_literal_unwrap.rs:151:22 | LL | let _ = unsafe { Err::<(), i32>(123).unwrap_err_unchecked() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs index 61058b7988a2d..b6cba4e6a5685 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.rs @@ -5,154 +5,190 @@ fn unwrap_option_some() { let val = Some(1); let _val2 = val.unwrap(); - //~^ ERROR: used `unwrap()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect("this never happens"); - //~^ ERROR: used `expect()` on `Some` value + //~^ unnecessary_literal_unwrap } fn unwrap_option_some_context() { let _val = Some::([1, 2, 3].iter().sum()).unwrap(); - //~^ ERROR: used `unwrap()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); - //~^ ERROR: used `expect()` on `Some` value + //~^ unnecessary_literal_unwrap let val = Some::([1, 2, 3].iter().sum()); let _val2 = val.unwrap(); - //~^ ERROR: used `unwrap()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect("this never happens"); - //~^ ERROR: used `expect()` on `Some` value + //~^ unnecessary_literal_unwrap } fn unwrap_option_none() { let val = None::<()>; let _val2 = val.unwrap(); - //~^ ERROR: used `unwrap()` on `None` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect("this always happens"); - //~^ ERROR: used `expect()` on `None` value + //~^ unnecessary_literal_unwrap + let _val3: u8 = None.unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `None` value + //~^ unnecessary_literal_unwrap + None::<()>.unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `None` value + //~^ unnecessary_literal_unwrap } fn unwrap_result_ok() { let val = Ok::<_, ()>(1); let _val2 = val.unwrap(); - //~^ ERROR: used `unwrap()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect("this never happens"); - //~^ ERROR: used `expect()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_err(); - //~^ ERROR: used `unwrap_err()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect_err("this always happens"); - //~^ ERROR: used `expect_err()` on `Ok` value + //~^ unnecessary_literal_unwrap } fn unwrap_result_ok_context() { let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); - //~^ ERROR: used `unwrap()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); - //~^ ERROR: used `expect()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); - //~^ ERROR: used `unwrap_err()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); - //~^ ERROR: used `expect_err()` on `Ok` value + //~^ unnecessary_literal_unwrap let val = Ok::([1, 2, 3].iter().sum()); let _val2 = val.unwrap(); - //~^ ERROR: used `unwrap()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect("this never happens"); - //~^ ERROR: used `expect()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_err(); - //~^ ERROR: used `unwrap_err()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect_err("this always happens"); - //~^ ERROR: used `expect_err()` on `Ok` value + //~^ unnecessary_literal_unwrap } fn unwrap_result_err() { let val = Err::<(), _>(1); let _val2 = val.unwrap_err(); - //~^ ERROR: used `unwrap_err()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect_err("this never happens"); - //~^ ERROR: used `expect_err()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap(); - //~^ ERROR: used `unwrap()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect("this always happens"); - //~^ ERROR: used `expect()` on `Err` value + //~^ unnecessary_literal_unwrap } fn unwrap_result_err_context() { let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); - //~^ ERROR: used `unwrap_err()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); - //~^ ERROR: used `expect_err()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); - //~^ ERROR: used `unwrap()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); - //~^ ERROR: used `expect()` on `Err` value + //~^ unnecessary_literal_unwrap let val = Err::<(), usize>([1, 2, 3].iter().sum()); let _val2 = val.unwrap_err(); - //~^ ERROR: used `unwrap_err()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect_err("this never happens"); - //~^ ERROR: used `expect_err()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap(); - //~^ ERROR: used `unwrap()` on `Err` value + //~^ unnecessary_literal_unwrap + let _val2 = val.expect("this always happens"); - //~^ ERROR: used `expect()` on `Err` value + //~^ unnecessary_literal_unwrap } fn unwrap_methods_option() { let val = Some(1); let _val2 = val.unwrap_or(2); - //~^ ERROR: used `unwrap_or()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_else(|| 2); - //~^ ERROR: used `unwrap_or_else()` on `Some` value + //~^ unnecessary_literal_unwrap } fn unwrap_methods_option_context() { let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); - //~^ ERROR: used `unwrap_or()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); - //~^ ERROR: used `unwrap_or_else()` on `Some` value + //~^ unnecessary_literal_unwrap let val = Some::([1, 2, 3].iter().sum()); let _val2 = val.unwrap_or(2); - //~^ ERROR: used `unwrap_or()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `Some` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_else(|| 2); - //~^ ERROR: used `unwrap_or_else()` on `Some` value + //~^ unnecessary_literal_unwrap } fn unwrap_methods_result() { let val = Ok::<_, ()>(1); let _val2 = val.unwrap_or(2); - //~^ ERROR: used `unwrap_or()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_else(|_| 2); - //~^ ERROR: used `unwrap_or_else()` on `Ok` value + //~^ unnecessary_literal_unwrap } fn unwrap_methods_result_context() { let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); - //~^ ERROR: used `unwrap_or()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); - //~^ ERROR: used `unwrap_or_else()` on `Ok` value + //~^ unnecessary_literal_unwrap let val = Ok::([1, 2, 3].iter().sum()); let _val2 = val.unwrap_or(2); - //~^ ERROR: used `unwrap_or()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_default(); - //~^ ERROR: used `unwrap_or_default()` on `Ok` value + //~^ unnecessary_literal_unwrap + let _val2 = val.unwrap_or_else(|_| 2); - //~^ ERROR: used `unwrap_or_else()` on `Ok` value + //~^ unnecessary_literal_unwrap } fn main() { diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr index b7dd7ae729fd9..4994eeded776e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap_unfixable.stderr @@ -13,7 +13,7 @@ LL | let val = Some(1); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_literal_unwrap)]` error: used `expect()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:9:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:10:17 | LL | let _val2 = val.expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,589 +25,589 @@ LL | let val = Some(1); | ^^^^^^^ error: used `unwrap()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:14:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:15:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:14:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:15:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:16:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:18:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:16:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:18:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:20:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:22:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Some` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:19:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:21:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:22:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:25:17 | LL | let _val2 = val.expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:19:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:21:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `None` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:28:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:31:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `None` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:27:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:30:15 | LL | let val = None::<()>; | ^^^^^^^^^^ error: used `expect()` on `None` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:30:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:34:17 | LL | let _val2 = val.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `None` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:27:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:30:15 | LL | let val = None::<()>; | ^^^^^^^^^^ error: used `unwrap_or_default()` on `None` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:32:21 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:37:21 | LL | let _val3: u8 = None.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()` error: used `unwrap_or_default()` on `None` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:34:5 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:40:5 | LL | None::<()>.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the `None` and `unwrap_or_default()`: `Default::default()` error: used `unwrap()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:40:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:46:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:39:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:45:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `expect()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:42:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:49:17 | LL | let _val2 = val.expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:39:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:45:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:44:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:52:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:39:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:45:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `expect_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:46:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:55:17 | LL | let _val2 = val.expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:39:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:45:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:51:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:60:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:51:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:60:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:53:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:63:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:53:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:63:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:55:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:66:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:55:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:66:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:57:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:69:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:57:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:69:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:61:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:73:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:60:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:63:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:76:17 | LL | let _val2 = val.expect("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:60:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:65:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:79:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:60:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:67:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:82:17 | LL | let _val2 = val.expect_err("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `expect_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:60:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:73:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:88:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:87:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `expect_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:75:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:91:17 | LL | let _val2 = val.expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:87:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `unwrap()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:77:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:94:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Err` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:87:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `expect()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:79:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:97:17 | LL | let _val2 = val.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:72:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:87:15 | LL | let val = Err::<(), _>(1); | ^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:84:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:102:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:84:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:102:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:86:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:105:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:86:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:105:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:88:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:108:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:88:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:108:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:90:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:111:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:90:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:111:16 | LL | let _val = Err::<(), usize>([1, 2, 3].iter().sum()).expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:94:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:115:17 | LL | let _val2 = val.unwrap_err(); | ^^^^^^^^^^^^^^^^ | help: remove the `Err` and `unwrap_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:93:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:114:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect_err()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:96:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:118:17 | LL | let _val2 = val.expect_err("this never happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect_err()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:93:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:114:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:98:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:121:17 | LL | let _val2 = val.unwrap(); | ^^^^^^^^^^^^ | help: remove the `Err` and `unwrap()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:93:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:114:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `expect()` on `Err` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:100:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:124:17 | LL | let _val2 = val.expect("this always happens"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Err` and `expect()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:93:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:114:15 | LL | let val = Err::<(), usize>([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:106:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:130:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:105:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:129:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or_default()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:108:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:133:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_default()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:105:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:129:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or_else()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:110:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:136:17 | LL | let _val2 = val.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_else()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:105:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:129:15 | LL | let val = Some(1); | ^^^^^^^ error: used `unwrap_or()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:115:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:141:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:115:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:141:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:117:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:144:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_default()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:117:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:144:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:119:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:147:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_else()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:119:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:147:16 | LL | let _val = Some::([1, 2, 3].iter().sum()).unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:123:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:151:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:122:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:150:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:125:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:154:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_default()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:122:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:150:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Some` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:127:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:157:17 | LL | let _val2 = val.unwrap_or_else(|| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Some` and `unwrap_or_else()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:122:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:150:15 | LL | let val = Some::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:133:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:163:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:132:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:162:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:135:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:166:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:132:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:162:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:137:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:169:17 | LL | let _val2 = val.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:132:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:162:15 | LL | let val = Ok::<_, ()>(1); | ^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:142:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:174:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:142:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:174:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or(2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:144:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:177:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:144:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:177:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:146:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:180:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:146:16 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:180:16 | LL | let _val = Ok::([1, 2, 3].iter().sum()).unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:150:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:184:17 | LL | let _val2 = val.unwrap_or(2); | ^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:149:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:183:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_default()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:152:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:187:17 | LL | let _val2 = val.unwrap_or_default(); | ^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_default()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:149:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:183:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used `unwrap_or_else()` on `Ok` value - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:154:17 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:190:17 | LL | let _val2 = val.unwrap_or_else(|_| 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | help: remove the `Ok` and `unwrap_or_else()` - --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:149:15 + --> tests/ui/unnecessary_literal_unwrap_unfixable.rs:183:15 | LL | let val = Ok::([1, 2, 3].iter().sum()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.fixed b/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.fixed index d0ba7ed749e4b..4452fda38c406 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.fixed @@ -30,14 +30,22 @@ fn main() { let c: SimpleResult = Err(err); let a = Some(fun(x)); + //~^ unnecessary_map_on_constructor let b: SimpleResult = Ok(fun(x)); + //~^ unnecessary_map_on_constructor let c: SimpleResult = Err(notfun(err)); + //~^ unnecessary_map_on_constructor let a = Option::Some(fun(x)); + //~^ unnecessary_map_on_constructor let b: SimpleResult = SimpleResult::Ok(fun(x)); + //~^ unnecessary_map_on_constructor let c: SimpleResult = SimpleResult::Err(notfun(err)); + //~^ unnecessary_map_on_constructor let b: std::result::Result = Ok(fun(x)); + //~^ unnecessary_map_on_constructor let c: std::result::Result = Err(notfun(err)); + //~^ unnecessary_map_on_constructor let a = Some(fun(x)); let b: SimpleResult = Ok(fun(x)); diff --git a/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.rs b/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.rs index e89e7aad4c40e..0cd41f2b363ac 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.rs +++ b/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.rs @@ -30,14 +30,22 @@ fn main() { let c: SimpleResult = Err(err); let a = Some(x).map(fun); + //~^ unnecessary_map_on_constructor let b: SimpleResult = Ok(x).map(fun); + //~^ unnecessary_map_on_constructor let c: SimpleResult = Err(err).map_err(notfun); + //~^ unnecessary_map_on_constructor let a = Option::Some(x).map(fun); + //~^ unnecessary_map_on_constructor let b: SimpleResult = SimpleResult::Ok(x).map(fun); + //~^ unnecessary_map_on_constructor let c: SimpleResult = SimpleResult::Err(err).map_err(notfun); + //~^ unnecessary_map_on_constructor let b: std::result::Result = Ok(x).map(fun); + //~^ unnecessary_map_on_constructor let c: std::result::Result = Err(err).map_err(notfun); + //~^ unnecessary_map_on_constructor let a = Some(fun(x)); let b: SimpleResult = Ok(fun(x)); diff --git a/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.stderr b/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.stderr index ecbf652441549..f29bfec60f726 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_map_on_constructor.stderr @@ -8,43 +8,43 @@ LL | let a = Some(x).map(fun); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_on_constructor)]` error: unnecessary map on constructor Ok(_) - --> tests/ui/unnecessary_map_on_constructor.rs:33:27 + --> tests/ui/unnecessary_map_on_constructor.rs:34:27 | LL | let b: SimpleResult = Ok(x).map(fun); | ^^^^^^^^^^^^^^ help: try: `Ok(fun(x))` error: unnecessary map_err on constructor Err(_) - --> tests/ui/unnecessary_map_on_constructor.rs:34:27 + --> tests/ui/unnecessary_map_on_constructor.rs:36:27 | LL | let c: SimpleResult = Err(err).map_err(notfun); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Err(notfun(err))` error: unnecessary map on constructor Option::Some(_) - --> tests/ui/unnecessary_map_on_constructor.rs:36:13 + --> tests/ui/unnecessary_map_on_constructor.rs:39:13 | LL | let a = Option::Some(x).map(fun); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Option::Some(fun(x))` error: unnecessary map on constructor SimpleResult::Ok(_) - --> tests/ui/unnecessary_map_on_constructor.rs:37:27 + --> tests/ui/unnecessary_map_on_constructor.rs:41:27 | LL | let b: SimpleResult = SimpleResult::Ok(x).map(fun); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `SimpleResult::Ok(fun(x))` error: unnecessary map_err on constructor SimpleResult::Err(_) - --> tests/ui/unnecessary_map_on_constructor.rs:38:27 + --> tests/ui/unnecessary_map_on_constructor.rs:43:27 | LL | let c: SimpleResult = SimpleResult::Err(err).map_err(notfun); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `SimpleResult::Err(notfun(err))` error: unnecessary map on constructor Ok(_) - --> tests/ui/unnecessary_map_on_constructor.rs:39:52 + --> tests/ui/unnecessary_map_on_constructor.rs:45:52 | LL | let b: std::result::Result = Ok(x).map(fun); | ^^^^^^^^^^^^^^ help: try: `Ok(fun(x))` error: unnecessary map_err on constructor Err(_) - --> tests/ui/unnecessary_map_on_constructor.rs:40:52 + --> tests/ui/unnecessary_map_on_constructor.rs:47:52 | LL | let c: std::result::Result = Err(err).map_err(notfun); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Err(notfun(err))` diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed index 5a6e77a06b8f5..3c7243972845f 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed @@ -11,24 +11,39 @@ extern crate proc_macros; fn main() { // should trigger let _ = Some(5) == Some(5); + //~^ unnecessary_map_or let _ = Some(5) != Some(5); + //~^ unnecessary_map_or let _ = Some(5) == Some(5); let _ = Some(5).is_some_and(|n| { + //~^ unnecessary_map_or let _ = n; 6 >= 5 }); let _ = Some(vec![5]).is_some_and(|n| n == [5]); + //~^ unnecessary_map_or let _ = Some(vec![1]).is_some_and(|n| vec![2] == n); + //~^ unnecessary_map_or let _ = Some(5).is_some_and(|n| n == n); + //~^ unnecessary_map_or let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 }); + //~^ unnecessary_map_or let _ = Ok::, i32>(vec![5]).is_ok_and(|n| n == [5]); + //~^ unnecessary_map_or let _ = Ok::(5) == Ok(5); + //~^ unnecessary_map_or let _ = (Some(5) == Some(5)).then(|| 1); + //~^ unnecessary_map_or let _ = Some(5).is_none_or(|n| n == 5); + //~^ unnecessary_map_or let _ = Some(5).is_none_or(|n| 5 == n); + //~^ unnecessary_map_or let _ = !(Some(5) == Some(5)); + //~^ unnecessary_map_or let _ = (Some(5) == Some(5)) || false; + //~^ unnecessary_map_or let _ = (Some(5) == Some(5)) as usize; + //~^ unnecessary_map_or macro_rules! x { () => { @@ -53,18 +68,23 @@ fn main() { struct S; let r: Result = Ok(3); let _ = r.is_ok_and(|x| x == 7); + //~^ unnecessary_map_or // lint constructs that are not comparaisons as well let func = |_x| true; let r: Result = Ok(3); let _ = r.is_ok_and(func); + //~^ unnecessary_map_or let _ = Some(5).is_some_and(func); + //~^ unnecessary_map_or let _ = Some(5).is_none_or(func); + //~^ unnecessary_map_or #[derive(PartialEq)] struct S2; let r: Result = Ok(4); let _ = r == Ok(8); + //~^ unnecessary_map_or // do not lint `Result::map_or(true, …)` let r: Result = Ok(4); @@ -85,6 +105,8 @@ fn msrv_1_81() { fn with_refs(o: &mut Option) -> bool { o.is_none_or(|n| n > 5) || (o as &Option).is_none_or(|n| n < 5) + //~^ unnecessary_map_or + //~| unnecessary_map_or } struct S; @@ -98,4 +120,13 @@ impl std::ops::Deref for S { fn with_deref(o: &S) -> bool { o.is_none_or(|n| n > 5) + //~^ unnecessary_map_or +} + +fn issue14201(a: Option, b: Option, s: &String) -> bool { + let x = a.is_some_and(|a| a == *s); + //~^ unnecessary_map_or + let y = b.is_none_or(|b| b == *s); + //~^ unnecessary_map_or + x && y } diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.rs b/src/tools/clippy/tests/ui/unnecessary_map_or.rs index 5ba63121659fc..e734a27badabd 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.rs +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.rs @@ -11,27 +11,43 @@ extern crate proc_macros; fn main() { // should trigger let _ = Some(5).map_or(false, |n| n == 5); + //~^ unnecessary_map_or let _ = Some(5).map_or(true, |n| n != 5); + //~^ unnecessary_map_or let _ = Some(5).map_or(false, |n| { + //~^ unnecessary_map_or let _ = 1; n == 5 }); let _ = Some(5).map_or(false, |n| { + //~^ unnecessary_map_or let _ = n; 6 >= 5 }); let _ = Some(vec![5]).map_or(false, |n| n == [5]); + //~^ unnecessary_map_or let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); + //~^ unnecessary_map_or let _ = Some(5).map_or(false, |n| n == n); + //~^ unnecessary_map_or let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); + //~^ unnecessary_map_or let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); + //~^ unnecessary_map_or let _ = Ok::(5).map_or(false, |n| n == 5); + //~^ unnecessary_map_or let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); + //~^ unnecessary_map_or let _ = Some(5).map_or(true, |n| n == 5); + //~^ unnecessary_map_or let _ = Some(5).map_or(true, |n| 5 == n); + //~^ unnecessary_map_or let _ = !Some(5).map_or(false, |n| n == 5); + //~^ unnecessary_map_or let _ = Some(5).map_or(false, |n| n == 5) || false; + //~^ unnecessary_map_or let _ = Some(5).map_or(false, |n| n == 5) as usize; + //~^ unnecessary_map_or macro_rules! x { () => { @@ -56,18 +72,23 @@ fn main() { struct S; let r: Result = Ok(3); let _ = r.map_or(false, |x| x == 7); + //~^ unnecessary_map_or // lint constructs that are not comparaisons as well let func = |_x| true; let r: Result = Ok(3); let _ = r.map_or(false, func); + //~^ unnecessary_map_or let _ = Some(5).map_or(false, func); + //~^ unnecessary_map_or let _ = Some(5).map_or(true, func); + //~^ unnecessary_map_or #[derive(PartialEq)] struct S2; let r: Result = Ok(4); let _ = r.map_or(false, |x| x == 8); + //~^ unnecessary_map_or // do not lint `Result::map_or(true, …)` let r: Result = Ok(4); @@ -88,6 +109,8 @@ fn msrv_1_81() { fn with_refs(o: &mut Option) -> bool { o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) + //~^ unnecessary_map_or + //~| unnecessary_map_or } struct S; @@ -101,4 +124,13 @@ impl std::ops::Deref for S { fn with_deref(o: &S) -> bool { o.map_or(true, |n| n > 5) + //~^ unnecessary_map_or +} + +fn issue14201(a: Option, b: Option, s: &String) -> bool { + let x = a.map_or(false, |a| a == *s); + //~^ unnecessary_map_or + let y = b.map_or(true, |b| b == *s); + //~^ unnecessary_map_or + x && y } diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr index 9f38b8c8d93ad..0f9466a6a6b30 100644 --- a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr @@ -13,7 +13,7 @@ LL + let _ = Some(5) == Some(5); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:14:13 + --> tests/ui/unnecessary_map_or.rs:15:13 | LL | let _ = Some(5).map_or(true, |n| n != 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,10 +25,11 @@ LL + let _ = Some(5) != Some(5); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:15:13 + --> tests/ui/unnecessary_map_or.rs:17:13 | LL | let _ = Some(5).map_or(false, |n| { | _____________^ +LL | | LL | | let _ = 1; LL | | n == 5 LL | | }); @@ -37,6 +38,7 @@ LL | | }); help: use a standard comparison instead | LL - let _ = Some(5).map_or(false, |n| { +LL - LL - let _ = 1; LL - n == 5 LL - }); @@ -44,10 +46,11 @@ LL + let _ = Some(5) == Some(5); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:19:13 + --> tests/ui/unnecessary_map_or.rs:22:13 | LL | let _ = Some(5).map_or(false, |n| { | _____________^ +LL | | LL | | let _ = n; LL | | 6 >= 5 LL | | }); @@ -60,7 +63,7 @@ LL + let _ = Some(5).is_some_and(|n| { | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:23:13 + --> tests/ui/unnecessary_map_or.rs:27:13 | LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +75,7 @@ LL + let _ = Some(vec![5]).is_some_and(|n| n == [5]); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:24:13 + --> tests/ui/unnecessary_map_or.rs:29:13 | LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +87,7 @@ LL + let _ = Some(vec![1]).is_some_and(|n| vec![2] == n); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:25:13 + --> tests/ui/unnecessary_map_or.rs:31:13 | LL | let _ = Some(5).map_or(false, |n| n == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -96,7 +99,7 @@ LL + let _ = Some(5).is_some_and(|n| n == n); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:26:13 + --> tests/ui/unnecessary_map_or.rs:33:13 | LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -108,7 +111,7 @@ LL + let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 }); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:27:13 + --> tests/ui/unnecessary_map_or.rs:35:13 | LL | let _ = Ok::, i32>(vec![5]).map_or(false, |n| n == [5]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -120,7 +123,7 @@ LL + let _ = Ok::, i32>(vec![5]).is_ok_and(|n| n == [5]); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:28:13 + --> tests/ui/unnecessary_map_or.rs:37:13 | LL | let _ = Ok::(5).map_or(false, |n| n == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -132,7 +135,7 @@ LL + let _ = Ok::(5) == Ok(5); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:29:13 + --> tests/ui/unnecessary_map_or.rs:39:13 | LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -144,7 +147,7 @@ LL + let _ = (Some(5) == Some(5)).then(|| 1); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:30:13 + --> tests/ui/unnecessary_map_or.rs:41:13 | LL | let _ = Some(5).map_or(true, |n| n == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -156,7 +159,7 @@ LL + let _ = Some(5).is_none_or(|n| n == 5); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:31:13 + --> tests/ui/unnecessary_map_or.rs:43:13 | LL | let _ = Some(5).map_or(true, |n| 5 == n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,7 +171,7 @@ LL + let _ = Some(5).is_none_or(|n| 5 == n); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:32:14 + --> tests/ui/unnecessary_map_or.rs:45:14 | LL | let _ = !Some(5).map_or(false, |n| n == 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -180,7 +183,7 @@ LL + let _ = !(Some(5) == Some(5)); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:33:13 + --> tests/ui/unnecessary_map_or.rs:47:13 | LL | let _ = Some(5).map_or(false, |n| n == 5) || false; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -192,7 +195,7 @@ LL + let _ = (Some(5) == Some(5)) || false; | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:34:13 + --> tests/ui/unnecessary_map_or.rs:49:13 | LL | let _ = Some(5).map_or(false, |n| n == 5) as usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +207,7 @@ LL + let _ = (Some(5) == Some(5)) as usize; | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:58:13 + --> tests/ui/unnecessary_map_or.rs:74:13 | LL | let _ = r.map_or(false, |x| x == 7); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -216,7 +219,7 @@ LL + let _ = r.is_ok_and(|x| x == 7); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:63:13 + --> tests/ui/unnecessary_map_or.rs:80:13 | LL | let _ = r.map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^ @@ -228,7 +231,7 @@ LL + let _ = r.is_ok_and(func); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:64:13 + --> tests/ui/unnecessary_map_or.rs:82:13 | LL | let _ = Some(5).map_or(false, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -240,7 +243,7 @@ LL + let _ = Some(5).is_some_and(func); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:65:13 + --> tests/ui/unnecessary_map_or.rs:84:13 | LL | let _ = Some(5).map_or(true, func); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -252,7 +255,7 @@ LL + let _ = Some(5).is_none_or(func); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:70:13 + --> tests/ui/unnecessary_map_or.rs:90:13 | LL | let _ = r.map_or(false, |x| x == 8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -264,7 +267,7 @@ LL + let _ = r == Ok(8); | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:90:5 + --> tests/ui/unnecessary_map_or.rs:111:5 | LL | o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -276,7 +279,7 @@ LL + o.is_none_or(|n| n > 5) || (o as &Option).map_or(true, |n| n < 5) | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:90:34 + --> tests/ui/unnecessary_map_or.rs:111:34 | LL | o.map_or(true, |n| n > 5) || (o as &Option).map_or(true, |n| n < 5) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -288,7 +291,7 @@ LL + o.map_or(true, |n| n > 5) || (o as &Option).is_none_or(|n| n < 5) | error: this `map_or` can be simplified - --> tests/ui/unnecessary_map_or.rs:103:5 + --> tests/ui/unnecessary_map_or.rs:126:5 | LL | o.map_or(true, |n| n > 5) | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -299,5 +302,29 @@ LL - o.map_or(true, |n| n > 5) LL + o.is_none_or(|n| n > 5) | -error: aborting due to 24 previous errors +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:131:13 + | +LL | let x = a.map_or(false, |a| a == *s); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_some_and instead + | +LL - let x = a.map_or(false, |a| a == *s); +LL + let x = a.is_some_and(|a| a == *s); + | + +error: this `map_or` can be simplified + --> tests/ui/unnecessary_map_or.rs:133:13 + | +LL | let y = b.map_or(true, |b| b == *s); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use is_none_or instead + | +LL - let y = b.map_or(true, |b| b == *s); +LL + let y = b.is_none_or(|b| b == *s); + | + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed index 1f3e131516ce6..2650cae5baf46 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.fixed @@ -11,30 +11,47 @@ const X: i32 = 1; fn main() { // Both are Literals let _ = (-6_i32); + //~^ unnecessary_min_or_max let _ = 9; + //~^ unnecessary_min_or_max let _ = 6; + //~^ unnecessary_min_or_max let _ = 9_u32; + //~^ unnecessary_min_or_max let _ = 6; + //~^ unnecessary_min_or_max let _ = 7_u8; + //~^ unnecessary_min_or_max let x: u32 = 42; // unsigned with zero let _ = 0; + //~^ unnecessary_min_or_max let _ = x; + //~^ unnecessary_min_or_max let _ = 0_u32; + //~^ unnecessary_min_or_max let _ = x; + //~^ unnecessary_min_or_max let x: i32 = 42; // signed MIN let _ = i32::MIN; + //~^ unnecessary_min_or_max let _ = x; + //~^ unnecessary_min_or_max let _ = i32::MIN; + //~^ unnecessary_min_or_max let _ = x; + //~^ unnecessary_min_or_max let _ = i32::MIN - 0; + //~^ unnecessary_min_or_max let _ = x; + //~^ unnecessary_min_or_max let _ = i32::MIN - 0; + //~^ unnecessary_min_or_max // The below cases shouldn't be lint let mut min = u32::MAX; diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs index 58356b9d49e77..2f3c480b3d150 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.rs @@ -11,30 +11,47 @@ const X: i32 = 1; fn main() { // Both are Literals let _ = (-6_i32).min(9); + //~^ unnecessary_min_or_max let _ = (-6_i32).max(9); + //~^ unnecessary_min_or_max let _ = 9_u32.min(6); + //~^ unnecessary_min_or_max let _ = 9_u32.max(6); + //~^ unnecessary_min_or_max let _ = 6.min(7_u8); + //~^ unnecessary_min_or_max let _ = 6.max(7_u8); + //~^ unnecessary_min_or_max let x: u32 = 42; // unsigned with zero let _ = 0.min(x); + //~^ unnecessary_min_or_max let _ = 0.max(x); + //~^ unnecessary_min_or_max let _ = x.min(0_u32); + //~^ unnecessary_min_or_max let _ = x.max(0_u32); + //~^ unnecessary_min_or_max let x: i32 = 42; // signed MIN let _ = i32::MIN.min(x); + //~^ unnecessary_min_or_max let _ = i32::MIN.max(x); + //~^ unnecessary_min_or_max let _ = x.min(i32::MIN); + //~^ unnecessary_min_or_max let _ = x.max(i32::MIN); + //~^ unnecessary_min_or_max let _ = x.min(i32::MIN - 0); + //~^ unnecessary_min_or_max let _ = x.max(i32::MIN); + //~^ unnecessary_min_or_max let _ = x.min(i32::MIN - 0); + //~^ unnecessary_min_or_max // The below cases shouldn't be lint let mut min = u32::MAX; diff --git a/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr index f5cd31fbaf24b..dfe6910dfa5cb 100644 --- a/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_min_or_max.stderr @@ -8,97 +8,97 @@ LL | let _ = (-6_i32).min(9); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_min_or_max)]` error: `(-6_i32)` is never greater than `9` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:14:13 + --> tests/ui/unnecessary_min_or_max.rs:15:13 | LL | let _ = (-6_i32).max(9); | ^^^^^^^^^^^^^^^ help: try: `9` error: `9_u32` is never smaller than `6` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:15:13 + --> tests/ui/unnecessary_min_or_max.rs:17:13 | LL | let _ = 9_u32.min(6); | ^^^^^^^^^^^^ help: try: `6` error: `9_u32` is never smaller than `6` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:16:13 + --> tests/ui/unnecessary_min_or_max.rs:19:13 | LL | let _ = 9_u32.max(6); | ^^^^^^^^^^^^ help: try: `9_u32` error: `6` is never greater than `7_u8` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:17:13 + --> tests/ui/unnecessary_min_or_max.rs:21:13 | LL | let _ = 6.min(7_u8); | ^^^^^^^^^^^ help: try: `6` error: `6` is never greater than `7_u8` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:18:13 + --> tests/ui/unnecessary_min_or_max.rs:23:13 | LL | let _ = 6.max(7_u8); | ^^^^^^^^^^^ help: try: `7_u8` error: `0` is never greater than `x` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:22:13 + --> tests/ui/unnecessary_min_or_max.rs:28:13 | LL | let _ = 0.min(x); | ^^^^^^^^ help: try: `0` error: `0` is never greater than `x` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:23:13 + --> tests/ui/unnecessary_min_or_max.rs:30:13 | LL | let _ = 0.max(x); | ^^^^^^^^ help: try: `x` error: `x` is never smaller than `0_u32` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:24:13 + --> tests/ui/unnecessary_min_or_max.rs:32:13 | LL | let _ = x.min(0_u32); | ^^^^^^^^^^^^ help: try: `0_u32` error: `x` is never smaller than `0_u32` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:25:13 + --> tests/ui/unnecessary_min_or_max.rs:34:13 | LL | let _ = x.max(0_u32); | ^^^^^^^^^^^^ help: try: `x` error: `i32::MIN` is never greater than `x` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:29:13 + --> tests/ui/unnecessary_min_or_max.rs:39:13 | LL | let _ = i32::MIN.min(x); | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` error: `i32::MIN` is never greater than `x` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:30:13 + --> tests/ui/unnecessary_min_or_max.rs:41:13 | LL | let _ = i32::MIN.max(x); | ^^^^^^^^^^^^^^^ help: try: `x` error: `x` is never smaller than `i32::MIN` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:31:13 + --> tests/ui/unnecessary_min_or_max.rs:43:13 | LL | let _ = x.min(i32::MIN); | ^^^^^^^^^^^^^^^ help: try: `i32::MIN` error: `x` is never smaller than `i32::MIN` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:32:13 + --> tests/ui/unnecessary_min_or_max.rs:45:13 | LL | let _ = x.max(i32::MIN); | ^^^^^^^^^^^^^^^ help: try: `x` error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:34:13 + --> tests/ui/unnecessary_min_or_max.rs:48:13 | LL | let _ = x.min(i32::MIN - 0); | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` error: `x` is never smaller than `i32::MIN` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:35:13 + --> tests/ui/unnecessary_min_or_max.rs:50:13 | LL | let _ = x.max(i32::MIN); | ^^^^^^^^^^^^^^^ help: try: `x` error: `x` is never smaller than `i32::MIN - 0` and has therefore no effect - --> tests/ui/unnecessary_min_or_max.rs:37:13 + --> tests/ui/unnecessary_min_or_max.rs:53:13 | LL | let _ = x.min(i32::MIN - 0); | ^^^^^^^^^^^^^^^^^^^ help: try: `i32::MIN - 0` diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index 006f123cbcdfc..05dfb72f48d2d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -68,22 +68,39 @@ where fn main() { get_number(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation get_struct(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation 5;get_number(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation 5;6;get_number(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation 5;get_number(); + //~^ unnecessary_operation 42;get_number(); + //~^ unnecessary_operation assert!([42, 55].len() > get_usize()); + //~^ unnecessary_operation 42;get_number(); + //~^ unnecessary_operation get_number(); + //~^ unnecessary_operation assert!([42; 55].len() > get_usize()); + //~^ unnecessary_operation get_number(); String::from("blah"); @@ -124,5 +141,5 @@ const _: () = { const fn foo() { assert!([42, 55].len() > get_usize()); - //~^ ERROR: unnecessary operation + //~^ unnecessary_operation } diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs index b4067c7407415..6ef74c3eb1c1e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.rs +++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs @@ -68,26 +68,45 @@ where fn main() { Tuple(get_number()); + //~^ unnecessary_operation Struct { field: get_number() }; + //~^ unnecessary_operation Struct { ..get_struct() }; + //~^ unnecessary_operation Enum::Tuple(get_number()); + //~^ unnecessary_operation Enum::Struct { field: get_number() }; + //~^ unnecessary_operation 5 + get_number(); + //~^ unnecessary_operation *&get_number(); + //~^ unnecessary_operation &get_number(); + //~^ unnecessary_operation (5, 6, get_number()); + //~^ unnecessary_operation get_number()..; + //~^ unnecessary_operation ..get_number(); + //~^ unnecessary_operation 5..get_number(); + //~^ unnecessary_operation [42, get_number()]; + //~^ unnecessary_operation [42, 55][get_usize()]; + //~^ unnecessary_operation (42, get_number()).1; + //~^ unnecessary_operation [get_number(); 55]; + //~^ unnecessary_operation [42; 55][get_usize()]; + //~^ unnecessary_operation { + //~^ unnecessary_operation get_number() }; FooString { + //~^ unnecessary_operation s: String::from("blah"), }; @@ -128,5 +147,5 @@ const _: () = { const fn foo() { [42, 55][get_usize()]; - //~^ ERROR: unnecessary operation + //~^ unnecessary_operation } diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr index 036a9a44bbad0..eb98af09e7a3d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr @@ -8,119 +8,121 @@ LL | Tuple(get_number()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_operation)]` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:71:5 + --> tests/ui/unnecessary_operation.rs:72:5 | LL | Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:72:5 + --> tests/ui/unnecessary_operation.rs:74:5 | LL | Struct { ..get_struct() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:73:5 + --> tests/ui/unnecessary_operation.rs:76:5 | LL | Enum::Tuple(get_number()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:74:5 + --> tests/ui/unnecessary_operation.rs:78:5 | LL | Enum::Struct { field: get_number() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:75:5 + --> tests/ui/unnecessary_operation.rs:80:5 | LL | 5 + get_number(); | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:76:5 + --> tests/ui/unnecessary_operation.rs:82:5 | LL | *&get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:77:5 + --> tests/ui/unnecessary_operation.rs:84:5 | LL | &get_number(); | ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:78:5 + --> tests/ui/unnecessary_operation.rs:86:5 | LL | (5, 6, get_number()); | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:79:5 + --> tests/ui/unnecessary_operation.rs:88:5 | LL | get_number()..; | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:80:5 + --> tests/ui/unnecessary_operation.rs:90:5 | LL | ..get_number(); | ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:81:5 + --> tests/ui/unnecessary_operation.rs:92:5 | LL | 5..get_number(); | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:82:5 + --> tests/ui/unnecessary_operation.rs:94:5 | LL | [42, get_number()]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:83:5 + --> tests/ui/unnecessary_operation.rs:96:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:84:5 + --> tests/ui/unnecessary_operation.rs:98:5 | LL | (42, get_number()).1; | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:85:5 + --> tests/ui/unnecessary_operation.rs:100:5 | LL | [get_number(); 55]; | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:86:5 + --> tests/ui/unnecessary_operation.rs:102:5 | LL | [42; 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:87:5 + --> tests/ui/unnecessary_operation.rs:104:5 | LL | / { +LL | | LL | | get_number() LL | | }; | |______^ help: statement can be reduced to: `get_number();` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:90:5 + --> tests/ui/unnecessary_operation.rs:108:5 | LL | / FooString { +LL | | LL | | s: String::from("blah"), LL | | }; | |______^ help: statement can be reduced to: `String::from("blah");` error: unnecessary operation - --> tests/ui/unnecessary_operation.rs:130:5 + --> tests/ui/unnecessary_operation.rs:149:5 | LL | [42, 55][get_usize()]; | ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());` diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs new file mode 100644 index 0000000000000..12663ec9a528f --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs @@ -0,0 +1,22 @@ +#![warn(clippy::unnecessary_debug_formatting)] + +use std::ffi::{OsStr, OsString}; + +fn main() { + let os_str = OsStr::new("abc"); + let os_string = os_str.to_os_string(); + + // negative tests + println!("{}", os_str.display()); + println!("{}", os_string.display()); + + // positive tests + println!("{:?}", os_str); //~ unnecessary_debug_formatting + println!("{:?}", os_string); //~ unnecessary_debug_formatting + + println!("{os_str:?}"); //~ unnecessary_debug_formatting + println!("{os_string:?}"); //~ unnecessary_debug_formatting + + let _: String = format!("{:?}", os_str); //~ unnecessary_debug_formatting + let _: String = format!("{:?}", os_string); //~ unnecessary_debug_formatting +} diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr new file mode 100644 index 0000000000000..001309ab817a1 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr @@ -0,0 +1,58 @@ +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_os_str_debug_formatting.rs:14:22 + | +LL | println!("{:?}", os_str); + | ^^^^^^ + | + = help: use `Display` formatting and change this to `os_str.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + = note: `-D clippy::unnecessary-debug-formatting` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_debug_formatting)]` + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_os_str_debug_formatting.rs:15:22 + | +LL | println!("{:?}", os_string); + | ^^^^^^^^^ + | + = help: use `Display` formatting and change this to `os_string.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_os_str_debug_formatting.rs:17:16 + | +LL | println!("{os_str:?}"); + | ^^^^^^ + | + = help: use `Display` formatting and change this to `os_str.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_os_str_debug_formatting.rs:18:16 + | +LL | println!("{os_string:?}"); + | ^^^^^^^^^ + | + = help: use `Display` formatting and change this to `os_string.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `format!` args + --> tests/ui/unnecessary_os_str_debug_formatting.rs:20:37 + | +LL | let _: String = format!("{:?}", os_str); + | ^^^^^^ + | + = help: use `Display` formatting and change this to `os_str.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `format!` args + --> tests/ui/unnecessary_os_str_debug_formatting.rs:21:37 + | +LL | let _: String = format!("{:?}", os_string); + | ^^^^^^^^^ + | + = help: use `Display` formatting and change this to `os_string.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed index 75cd63db8a1ac..dc0e495be30f8 100644 --- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed @@ -8,10 +8,12 @@ fn ref_string_argument(_value: &String) {} fn main() { // should be linted ref_str_argument(""); + //~^ unnecessary_owned_empty_strings // should be linted #[allow(clippy::manual_string_new)] ref_str_argument(""); + //~^ unnecessary_owned_empty_strings // should not be linted ref_str_argument(""); diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs index 2edc0bd86d383..e2c5de447444b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs +++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs @@ -8,10 +8,12 @@ fn ref_string_argument(_value: &String) {} fn main() { // should be linted ref_str_argument(&String::new()); + //~^ unnecessary_owned_empty_strings // should be linted #[allow(clippy::manual_string_new)] ref_str_argument(&String::from("")); + //~^ unnecessary_owned_empty_strings // should not be linted ref_str_argument(""); diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr index 1820ea4ef5d85..8bcf3ee88765f 100644 --- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.stderr @@ -8,7 +8,7 @@ LL | ref_str_argument(&String::new()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_owned_empty_strings)]` error: usage of `&String::from("")` for a function expecting a `&str` argument - --> tests/ui/unnecessary_owned_empty_strings.rs:14:22 + --> tests/ui/unnecessary_owned_empty_strings.rs:15:22 | LL | ref_str_argument(&String::from("")); | ^^^^^^^^^^^^^^^^^ help: try: `""` diff --git a/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.rs b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.rs new file mode 100644 index 0000000000000..02adeece2809b --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.rs @@ -0,0 +1,43 @@ +#![warn(clippy::unnecessary_debug_formatting)] + +use std::ffi::{OsStr, OsString}; +use std::ops::Deref; +use std::path::{Path, PathBuf}; + +struct DerefPath<'a> { + path: &'a Path, +} + +impl Deref for DerefPath<'_> { + type Target = Path; + fn deref(&self) -> &Self::Target { + self.path + } +} + +fn main() { + let path = Path::new("/a/b/c"); + let path_buf = path.to_path_buf(); + let os_str = OsStr::new("abc"); + let os_string = os_str.to_os_string(); + + // negative tests + println!("{}", path.display()); + println!("{}", path_buf.display()); + + // positive tests + println!("{:?}", os_str); //~ unnecessary_debug_formatting + println!("{:?}", os_string); //~ unnecessary_debug_formatting + + println!("{:?}", path); //~ unnecessary_debug_formatting + println!("{:?}", path_buf); //~ unnecessary_debug_formatting + + println!("{path:?}"); //~ unnecessary_debug_formatting + println!("{path_buf:?}"); //~ unnecessary_debug_formatting + + let _: String = format!("{:?}", path); //~ unnecessary_debug_formatting + let _: String = format!("{:?}", path_buf); //~ unnecessary_debug_formatting + + let deref_path = DerefPath { path }; + println!("{:?}", &*deref_path); //~ unnecessary_debug_formatting +} diff --git a/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.stderr b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.stderr new file mode 100644 index 0000000000000..f12fa72c84b35 --- /dev/null +++ b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.stderr @@ -0,0 +1,85 @@ +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:29:22 + | +LL | println!("{:?}", os_str); + | ^^^^^^ + | + = help: use `Display` formatting and change this to `os_str.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + = note: `-D clippy::unnecessary-debug-formatting` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unnecessary_debug_formatting)]` + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:30:22 + | +LL | println!("{:?}", os_string); + | ^^^^^^^^^ + | + = help: use `Display` formatting and change this to `os_string.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:32:22 + | +LL | println!("{:?}", path); + | ^^^^ + | + = help: use `Display` formatting and change this to `path.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:33:22 + | +LL | println!("{:?}", path_buf); + | ^^^^^^^^ + | + = help: use `Display` formatting and change this to `path_buf.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:35:16 + | +LL | println!("{path:?}"); + | ^^^^ + | + = help: use `Display` formatting and change this to `path.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:36:16 + | +LL | println!("{path_buf:?}"); + | ^^^^^^^^ + | + = help: use `Display` formatting and change this to `path_buf.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `format!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:38:37 + | +LL | let _: String = format!("{:?}", path); + | ^^^^ + | + = help: use `Display` formatting and change this to `path.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `format!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:39:37 + | +LL | let _: String = format!("{:?}", path_buf); + | ^^^^^^^^ + | + = help: use `Display` formatting and change this to `path_buf.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: unnecessary `Debug` formatting in `println!` args + --> tests/ui/unnecessary_path_debug_formatting.rs:42:22 + | +LL | println!("{:?}", &*deref_path); + | ^^^^^^^^^^^^ + | + = help: use `Display` formatting and change this to `&*deref_path.display()` + = note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed index 224e0b52d75df..5d7e3fa355fd0 100644 --- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.fixed @@ -3,16 +3,19 @@ fn main() { let x: Result<(), ()> = Ok(()); - x.unwrap_or_else(|err| err); //~ ERROR: unused "map closure" when calling + x.unwrap_or_else(|err| err); + //~^ unnecessary_result_map_or_else // Type ascribtion. let x: Result<(), ()> = Ok(()); - x.unwrap_or_else(|err: ()| err); //~ ERROR: unused "map closure" when calling + x.unwrap_or_else(|err: ()| err); + //~^ unnecessary_result_map_or_else // Auto-deref. let y = String::new(); let x: Result<&String, &String> = Ok(&y); - let y: &str = x.unwrap_or_else(|err| err); //~ ERROR: unused "map closure" when calling + let y: &str = x.unwrap_or_else(|err| err); + //~^ unnecessary_result_map_or_else // Temporary variable. let x: Result<(), ()> = Ok(()); diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs index 4fe950a4cfa6b..d2bab0f9d9c1b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs +++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.rs @@ -3,21 +3,24 @@ fn main() { let x: Result<(), ()> = Ok(()); - x.map_or_else(|err| err, |n| n); //~ ERROR: unused "map closure" when calling + x.map_or_else(|err| err, |n| n); + //~^ unnecessary_result_map_or_else // Type ascribtion. let x: Result<(), ()> = Ok(()); - x.map_or_else(|err: ()| err, |n: ()| n); //~ ERROR: unused "map closure" when calling + x.map_or_else(|err: ()| err, |n: ()| n); + //~^ unnecessary_result_map_or_else // Auto-deref. let y = String::new(); let x: Result<&String, &String> = Ok(&y); - let y: &str = x.map_or_else(|err| err, |n| n); //~ ERROR: unused "map closure" when calling + let y: &str = x.map_or_else(|err| err, |n| n); + //~^ unnecessary_result_map_or_else // Temporary variable. let x: Result<(), ()> = Ok(()); x.map_or_else( - //~^ ERROR: unused "map closure" when calling + //~^ unnecessary_result_map_or_else |err| err, |n| { let tmp = n; diff --git a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr index e3a6dbf8ecd8b..e6afa50217cc9 100644 --- a/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_result_map_or_else.stderr @@ -8,19 +8,19 @@ LL | x.map_or_else(|err| err, |n| n); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_result_map_or_else)]` error: unused "map closure" when calling `Result::map_or_else` value - --> tests/ui/unnecessary_result_map_or_else.rs:10:5 + --> tests/ui/unnecessary_result_map_or_else.rs:11:5 | LL | x.map_or_else(|err: ()| err, |n: ()| n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err: ()| err)` error: unused "map closure" when calling `Result::map_or_else` value - --> tests/ui/unnecessary_result_map_or_else.rs:15:19 + --> tests/ui/unnecessary_result_map_or_else.rs:17:19 | LL | let y: &str = x.map_or_else(|err| err, |n| n); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `unwrap_or_else`: `x.unwrap_or_else(|err| err)` error: unused "map closure" when calling `Result::map_or_else` value - --> tests/ui/unnecessary_result_map_or_else.rs:19:5 + --> tests/ui/unnecessary_result_map_or_else.rs:22:5 | LL | / x.map_or_else( LL | | diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs index bdc6fa0f46bbe..4440089b3633b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs +++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.rs @@ -4,19 +4,23 @@ mod unsafe_items_invalid_comment { // SAFETY: const CONST: u32 = 0; - //~^ ERROR: constant item has unnecessary safety comment + //~^ unnecessary_safety_comment + // SAFETY: static STATIC: u32 = 0; - //~^ ERROR: static item has unnecessary safety comment + //~^ unnecessary_safety_comment + // SAFETY: struct Struct; - //~^ ERROR: struct has unnecessary safety comment + //~^ unnecessary_safety_comment + // SAFETY: enum Enum {} - //~^ ERROR: enum has unnecessary safety comment + //~^ unnecessary_safety_comment + // SAFETY: mod module {} - //~^ ERROR: module has unnecessary safety comment + //~^ unnecessary_safety_comment } mod unnecessary_from_macro { @@ -36,6 +40,7 @@ mod unnecessary_from_macro { ($t:ty) => { // Safety: unnecessary impl T for $t {} + //~^ unnecessary_safety_comment }; } @@ -45,15 +50,15 @@ mod unnecessary_from_macro { fn unnecessary_on_stmt_and_expr() -> u32 { // SAFETY: unnecessary let num = 42; - //~^ ERROR: statement has unnecessary safety comment + //~^ unnecessary_safety_comment // SAFETY: unnecessary if num > 24 {} - //~^ ERROR: statement has unnecessary safety comment + //~^ unnecessary_safety_comment // SAFETY: unnecessary 24 - //~^ ERROR: expression has unnecessary safety comment + //~^ unnecessary_safety_comment } mod issue_10084 { diff --git a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr index 139ed769975b3..b56e8b354931c 100644 --- a/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_safety_comment.stderr @@ -13,55 +13,55 @@ LL | // SAFETY: = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_comment)]` error: static item has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:9:5 + --> tests/ui/unnecessary_safety_comment.rs:10:5 | LL | static STATIC: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:8:5 + --> tests/ui/unnecessary_safety_comment.rs:9:5 | LL | // SAFETY: | ^^^^^^^^^^ error: struct has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:12:5 + --> tests/ui/unnecessary_safety_comment.rs:14:5 | LL | struct Struct; | ^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:11:5 + --> tests/ui/unnecessary_safety_comment.rs:13:5 | LL | // SAFETY: | ^^^^^^^^^^ error: enum has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:15:5 + --> tests/ui/unnecessary_safety_comment.rs:18:5 | LL | enum Enum {} | ^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:14:5 + --> tests/ui/unnecessary_safety_comment.rs:17:5 | LL | // SAFETY: | ^^^^^^^^^^ error: module has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:18:5 + --> tests/ui/unnecessary_safety_comment.rs:22:5 | LL | mod module {} | ^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:17:5 + --> tests/ui/unnecessary_safety_comment.rs:21:5 | LL | // SAFETY: | ^^^^^^^^^^ error: impl has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:38:13 + --> tests/ui/unnecessary_safety_comment.rs:42:13 | LL | impl T for $t {} | ^^^^^^^^^^^^^^^^ @@ -70,44 +70,44 @@ LL | with_safety_comment!(i32); | ------------------------- in this macro invocation | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:37:13 + --> tests/ui/unnecessary_safety_comment.rs:41:13 | LL | // Safety: unnecessary | ^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `with_safety_comment` (in Nightly builds, run with -Z macro-backtrace for more info) error: expression has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:55:5 + --> tests/ui/unnecessary_safety_comment.rs:60:5 | LL | 24 | ^^ | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:54:5 + --> tests/ui/unnecessary_safety_comment.rs:59:5 | LL | // SAFETY: unnecessary | ^^^^^^^^^^^^^^^^^^^^^^ error: statement has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:47:5 + --> tests/ui/unnecessary_safety_comment.rs:52:5 | LL | let num = 42; | ^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:46:5 + --> tests/ui/unnecessary_safety_comment.rs:51:5 | LL | // SAFETY: unnecessary | ^^^^^^^^^^^^^^^^^^^^^^ error: statement has unnecessary safety comment - --> tests/ui/unnecessary_safety_comment.rs:51:5 + --> tests/ui/unnecessary_safety_comment.rs:56:5 | LL | if num > 24 {} | ^^^^^^^^^^^^^^ | help: consider removing the safety comment - --> tests/ui/unnecessary_safety_comment.rs:50:5 + --> tests/ui/unnecessary_safety_comment.rs:55:5 | LL | // SAFETY: unnecessary | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed b/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed index c265dcd2414fa..0fd74705bde02 100644 --- a/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed @@ -3,7 +3,9 @@ use std::collections::hash_map::{self, *}; use std::fs as alias; +//~^ unnecessary_self_imports use std::io::{self, Read}; use std::rc; +//~^ unnecessary_self_imports fn main() {} diff --git a/src/tools/clippy/tests/ui/unnecessary_self_imports.rs b/src/tools/clippy/tests/ui/unnecessary_self_imports.rs index c3fcf7c951a17..d09c5fcb8caa6 100644 --- a/src/tools/clippy/tests/ui/unnecessary_self_imports.rs +++ b/src/tools/clippy/tests/ui/unnecessary_self_imports.rs @@ -3,7 +3,9 @@ use std::collections::hash_map::{self, *}; use std::fs::{self as alias}; +//~^ unnecessary_self_imports use std::io::{self, Read}; use std::rc::{self}; +//~^ unnecessary_self_imports fn main() {} diff --git a/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr b/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr index 9b143b48c9a6e..1bb22c46a6c11 100644 --- a/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_self_imports.stderr @@ -11,7 +11,7 @@ LL | use std::fs::{self as alias}; = help: to override `-D warnings` add `#[allow(clippy::unnecessary_self_imports)]` error: import ending with `::{self}` - --> tests/ui/unnecessary_self_imports.rs:7:1 + --> tests/ui/unnecessary_self_imports.rs:8:1 | LL | use std::rc::{self}; | ^^^^^^^^^----------- diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed index 343c88b98155a..f10d804c8ccc4 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed @@ -27,13 +27,13 @@ fn main() { if a == 2 { println!("This is weird"); } - //~^ ERROR: unnecessary semicolon + //~^ unnecessary_semicolon a.match { 3 => println!("three"), _ => println!("not three"), } - //~^ ERROR: unnecessary semicolon + //~^ unnecessary_semicolon } // This is a problem in edition 2021 and below @@ -45,6 +45,7 @@ fn borrow_issue() { }, None => {}, }; + //~[edition2024]^ unnecessary_semicolon } fn no_borrow_issue(a: u32, b: u32) { @@ -54,6 +55,7 @@ fn no_borrow_issue(a: u32, b: u32) { }, None => {}, } + //~^ unnecessary_semicolon } fn issue14100() -> bool { diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.stderr b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.stderr index ccff33084172e..a3b139f73805d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.stderr @@ -14,7 +14,7 @@ LL | }; | ^ help: remove error: unnecessary semicolon - --> tests/ui/unnecessary_semicolon.rs:56:6 + --> tests/ui/unnecessary_semicolon.rs:57:6 | LL | }; | ^ help: remove diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed index 1cba5760eb0a0..32a3bb9b40819 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed @@ -27,13 +27,13 @@ fn main() { if a == 2 { println!("This is weird"); } - //~^ ERROR: unnecessary semicolon + //~^ unnecessary_semicolon a.match { 3 => println!("three"), _ => println!("not three"), } - //~^ ERROR: unnecessary semicolon + //~^ unnecessary_semicolon } // This is a problem in edition 2021 and below @@ -45,6 +45,7 @@ fn borrow_issue() { }, None => {}, } + //~[edition2024]^ unnecessary_semicolon } fn no_borrow_issue(a: u32, b: u32) { @@ -54,6 +55,7 @@ fn no_borrow_issue(a: u32, b: u32) { }, None => {}, } + //~^ unnecessary_semicolon } fn issue14100() -> bool { diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.stderr b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.stderr index 4e526af2147db..d5ccae7fdf580 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.stderr @@ -20,7 +20,7 @@ LL | }; | ^ help: remove error: unnecessary semicolon - --> tests/ui/unnecessary_semicolon.rs:56:6 + --> tests/ui/unnecessary_semicolon.rs:57:6 | LL | }; | ^ help: remove diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs index 6abbbd79aaf20..91b2821802249 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs @@ -27,13 +27,13 @@ fn main() { if a == 2 { println!("This is weird"); }; - //~^ ERROR: unnecessary semicolon + //~^ unnecessary_semicolon a.match { 3 => println!("three"), _ => println!("not three"), }; - //~^ ERROR: unnecessary semicolon + //~^ unnecessary_semicolon } // This is a problem in edition 2021 and below @@ -45,6 +45,7 @@ fn borrow_issue() { }, None => {}, }; + //~[edition2024]^ unnecessary_semicolon } fn no_borrow_issue(a: u32, b: u32) { @@ -54,6 +55,7 @@ fn no_borrow_issue(a: u32, b: u32) { }, None => {}, }; + //~^ unnecessary_semicolon } fn issue14100() -> bool { diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed index 6b667e00c9781..5255ab173efb9 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed @@ -10,13 +10,19 @@ fn unnecessary_sort_by() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort(); + //~^ unnecessary_sort_by vec.sort_unstable(); + //~^ unnecessary_sort_by vec.sort_by_key(|a| (a + 5).abs()); + //~^ unnecessary_sort_by vec.sort_unstable_by_key(|a| id(-a)); + //~^ unnecessary_sort_by // Reverse examples vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs())); + //~^ unnecessary_sort_by vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b))); + //~^ unnecessary_sort_by // Negative examples (shouldn't be changed) let c = &7; vec.sort_by(|a, b| (b - a).cmp(&(a - b))); @@ -27,7 +33,9 @@ fn unnecessary_sort_by() { // Vectors of references are fine as long as the resulting key does not borrow let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; vec.sort_by_key(|a| (***a).abs()); + //~^ unnecessary_sort_by vec.sort_unstable_by_key(|a| (***a).abs()); + //~^ unnecessary_sort_by // `Reverse(b)` would borrow in the following cases, don't lint vec.sort_by(|a, b| b.cmp(a)); vec.sort_unstable_by(|a, b| b.cmp(a)); @@ -87,10 +95,14 @@ mod issue_6001 { // Forward args.sort_by_key(|a| a.name()); + //~^ unnecessary_sort_by args.sort_unstable_by_key(|a| a.name()); + //~^ unnecessary_sort_by // Reverse args.sort_by_key(|b| std::cmp::Reverse(b.name())); + //~^ unnecessary_sort_by args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name())); + //~^ unnecessary_sort_by } } diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs index 0ff20fb9ef289..65db7ca3f1375 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs @@ -10,13 +10,19 @@ fn unnecessary_sort_by() { let mut vec: Vec = vec![3, 6, 1, 2, 5]; // Forward examples vec.sort_by(|a, b| a.cmp(b)); + //~^ unnecessary_sort_by vec.sort_unstable_by(|a, b| a.cmp(b)); + //~^ unnecessary_sort_by vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); + //~^ unnecessary_sort_by vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); + //~^ unnecessary_sort_by // Reverse examples vec.sort_by(|a, b| b.cmp(a)); // not linted to avoid suggesting `Reverse(b)` which would borrow vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); + //~^ unnecessary_sort_by vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); + //~^ unnecessary_sort_by // Negative examples (shouldn't be changed) let c = &7; vec.sort_by(|a, b| (b - a).cmp(&(a - b))); @@ -27,7 +33,9 @@ fn unnecessary_sort_by() { // Vectors of references are fine as long as the resulting key does not borrow let mut vec: Vec<&&&isize> = vec![&&&3, &&&6, &&&1, &&&2, &&&5]; vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); + //~^ unnecessary_sort_by vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); + //~^ unnecessary_sort_by // `Reverse(b)` would borrow in the following cases, don't lint vec.sort_by(|a, b| b.cmp(a)); vec.sort_unstable_by(|a, b| b.cmp(a)); @@ -87,10 +95,14 @@ mod issue_6001 { // Forward args.sort_by(|a, b| a.name().cmp(&b.name())); + //~^ unnecessary_sort_by args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); + //~^ unnecessary_sort_by // Reverse args.sort_by(|a, b| b.name().cmp(&a.name())); + //~^ unnecessary_sort_by args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); + //~^ unnecessary_sort_by } } diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr index e2013a4e6f9d2..9a38d3746da81 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.stderr @@ -8,67 +8,67 @@ LL | vec.sort_by(|a, b| a.cmp(b)); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` error: consider using `sort` - --> tests/ui/unnecessary_sort_by.rs:13:5 + --> tests/ui/unnecessary_sort_by.rs:14:5 | LL | vec.sort_unstable_by(|a, b| a.cmp(b)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable()` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:14:5 + --> tests/ui/unnecessary_sort_by.rs:16:5 | LL | vec.sort_by(|a, b| (a + 5).abs().cmp(&(b + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (a + 5).abs())` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:15:5 + --> tests/ui/unnecessary_sort_by.rs:18:5 | LL | vec.sort_unstable_by(|a, b| id(-a).cmp(&id(-b))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| id(-a))` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:18:5 + --> tests/ui/unnecessary_sort_by.rs:22:5 | LL | vec.sort_by(|a, b| (b + 5).abs().cmp(&(a + 5).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| std::cmp::Reverse((b + 5).abs()))` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:19:5 + --> tests/ui/unnecessary_sort_by.rs:24:5 | LL | vec.sort_unstable_by(|a, b| id(-b).cmp(&id(-a))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|b| std::cmp::Reverse(id(-b)))` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:29:5 + --> tests/ui/unnecessary_sort_by.rs:35:5 | LL | vec.sort_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|a| (***a).abs())` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:30:5 + --> tests/ui/unnecessary_sort_by.rs:37:5 | LL | vec.sort_unstable_by(|a, b| (***a).abs().cmp(&(***b).abs())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_unstable_by_key(|a| (***a).abs())` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:89:9 + --> tests/ui/unnecessary_sort_by.rs:97:9 | LL | args.sort_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|a| a.name())` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:90:9 + --> tests/ui/unnecessary_sort_by.rs:99:9 | LL | args.sort_unstable_by(|a, b| a.name().cmp(&b.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|a| a.name())` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:92:9 + --> tests/ui/unnecessary_sort_by.rs:102:9 | LL | args.sort_by(|a, b| b.name().cmp(&a.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_by_key(|b| std::cmp::Reverse(b.name()))` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by.rs:93:9 + --> tests/ui/unnecessary_sort_by.rs:104:9 | LL | args.sort_unstable_by(|a, b| b.name().cmp(&a.name())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `args.sort_unstable_by_key(|b| std::cmp::Reverse(b.name()))` diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.fixed index c7be000b820cf..40e6aecd1b6d0 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.fixed @@ -8,6 +8,7 @@ fn issue_11524() -> Vec { // Should lint and suggest `vec.sort_by_key(|a| a + 1);` vec.sort_by_key(|a| a + 1); + //~^ unnecessary_sort_by vec } @@ -16,5 +17,6 @@ fn issue_11524_2() -> Vec { // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` vec.sort_by_key(|b| core::cmp::Reverse(b + 1)); + //~^ unnecessary_sort_by vec } diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.rs index 5f44be97c61f5..184c90d959eb5 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.rs +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.rs @@ -8,6 +8,7 @@ fn issue_11524() -> Vec { // Should lint and suggest `vec.sort_by_key(|a| a + 1);` vec.sort_by(|a, b| (a + 1).cmp(&(b + 1))); + //~^ unnecessary_sort_by vec } @@ -16,5 +17,6 @@ fn issue_11524_2() -> Vec { // Should lint and suggest `vec.sort_by_key(|b| core::cmp::Reverse(b + 1));` vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); + //~^ unnecessary_sort_by vec } diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.stderr b/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.stderr index a57fbc7a6328c..de3ef4123514d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by_no_std.stderr @@ -8,7 +8,7 @@ LL | vec.sort_by(|a, b| (a + 1).cmp(&(b + 1))); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_sort_by)]` error: consider using `sort_by_key` - --> tests/ui/unnecessary_sort_by_no_std.rs:18:5 + --> tests/ui/unnecessary_sort_by_no_std.rs:19:5 | LL | vec.sort_by(|a, b| (b + 1).cmp(&(a + 1))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `vec.sort_by_key(|b| core::cmp::Reverse(b + 1))` diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed index b0e8f45463539..07dc90acfa308 100644 --- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed @@ -35,6 +35,7 @@ impl Clone for V { fn clone(&self) -> Self { // Lint: `Self` implements `Copy` *self + //~^ unnecessary_struct_initialization } } @@ -42,9 +43,11 @@ fn main() { // Should lint: `a` would be consumed anyway let a = S { f: String::from("foo") }; let mut b = a; + //~^ unnecessary_struct_initialization // Should lint: `b` would be consumed, and is mutable let c = &mut b; + //~^ unnecessary_struct_initialization // Should not lint as `d` is not mutable let d = S { f: String::from("foo") }; @@ -53,6 +56,7 @@ fn main() { // Should lint as `f` would be consumed anyway let f = S { f: String::from("foo") }; let g = &f; + //~^ unnecessary_struct_initialization // Should lint: the result of an expression is mutable let h = &mut *Box::new(S { f: String::from("foo") }); @@ -77,6 +81,7 @@ fn main() { // Should lint: all fields of `q` would be consumed anyway let q = W { f1: 42, f2: 1337 }; let r = q; + //~^ unnecessary_struct_initialization // Should not lint: not all fields of `t` from same source let s = W { f1: 1337, f2: 42 }; @@ -88,6 +93,7 @@ fn main() { // Should lint: all fields of `v` would be consumed anyway let v = W { f1: 42, f2: 1337 }; let w = v; + //~^ unnecessary_struct_initialization // Should not lint: source differs between fields and base let x = W { f1: 42, f2: 1337 }; @@ -96,6 +102,7 @@ fn main() { // Should lint: range desugars to struct let r1 = 0..5; let r2 = r1; + //~^ unnecessary_struct_initialization references(); shorthand(); @@ -109,6 +116,7 @@ fn references() { // Should lint as `d` is a shared reference let c = W { f1: 42, f2: 1337 }; let d = &c; + //~^ unnecessary_struct_initialization // Should not lint as `e` is not mutable let e = W { f1: 42, f2: 1337 }; @@ -117,6 +125,7 @@ fn references() { // Should lint as `h` is a shared reference let g = W { f1: 42, f2: 1337 }; let h = &g; + //~^ unnecessary_struct_initialization // Should not lint as `j` is copy let i = V { f: 0x1701d }; diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs index b0db71af4d4c2..12a444fc878b9 100644 --- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs @@ -35,6 +35,7 @@ impl Clone for V { fn clone(&self) -> Self { // Lint: `Self` implements `Copy` Self { ..*self } + //~^ unnecessary_struct_initialization } } @@ -42,9 +43,11 @@ fn main() { // Should lint: `a` would be consumed anyway let a = S { f: String::from("foo") }; let mut b = S { ..a }; + //~^ unnecessary_struct_initialization // Should lint: `b` would be consumed, and is mutable let c = &mut S { ..b }; + //~^ unnecessary_struct_initialization // Should not lint as `d` is not mutable let d = S { f: String::from("foo") }; @@ -53,9 +56,11 @@ fn main() { // Should lint as `f` would be consumed anyway let f = S { f: String::from("foo") }; let g = &S { ..f }; + //~^ unnecessary_struct_initialization // Should lint: the result of an expression is mutable let h = &mut S { + //~^ unnecessary_struct_initialization ..*Box::new(S { f: String::from("foo") }) }; @@ -75,12 +80,14 @@ fn main() { // Should lint: the result of an expression is mutable and temporary let p = &mut T { + //~^ unnecessary_struct_initialization ..*Box::new(T { f: 5 }) }; // Should lint: all fields of `q` would be consumed anyway let q = W { f1: 42, f2: 1337 }; let r = W { f1: q.f1, f2: q.f2 }; + //~^ unnecessary_struct_initialization // Should not lint: not all fields of `t` from same source let s = W { f1: 1337, f2: 42 }; @@ -92,6 +99,7 @@ fn main() { // Should lint: all fields of `v` would be consumed anyway let v = W { f1: 42, f2: 1337 }; let w = W { f1: v.f1, ..v }; + //~^ unnecessary_struct_initialization // Should not lint: source differs between fields and base let x = W { f1: 42, f2: 1337 }; @@ -100,6 +108,7 @@ fn main() { // Should lint: range desugars to struct let r1 = 0..5; let r2 = r1.start..r1.end; + //~^ unnecessary_struct_initialization references(); shorthand(); @@ -113,6 +122,7 @@ fn references() { // Should lint as `d` is a shared reference let c = W { f1: 42, f2: 1337 }; let d = &W { f1: c.f1, f2: c.f2 }; + //~^ unnecessary_struct_initialization // Should not lint as `e` is not mutable let e = W { f1: 42, f2: 1337 }; @@ -121,6 +131,7 @@ fn references() { // Should lint as `h` is a shared reference let g = W { f1: 42, f2: 1337 }; let h = &W { f1: g.f1, ..g }; + //~^ unnecessary_struct_initialization // Should not lint as `j` is copy let i = V { f: 0x1701d }; diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr index 56982cc0a39f9..5177b3252547b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.stderr @@ -8,67 +8,69 @@ LL | Self { ..*self } = help: to override `-D warnings` add `#[allow(clippy::unnecessary_struct_initialization)]` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:44:17 + --> tests/ui/unnecessary_struct_initialization.rs:45:17 | LL | let mut b = S { ..a }; | ^^^^^^^^^ help: replace with: `a` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:47:18 + --> tests/ui/unnecessary_struct_initialization.rs:49:18 | LL | let c = &mut S { ..b }; | ^^^^^^^^^ help: replace with: `b` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:55:14 + --> tests/ui/unnecessary_struct_initialization.rs:58:14 | LL | let g = &S { ..f }; | ^^^^^^^^^ help: replace with: `f` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:58:18 + --> tests/ui/unnecessary_struct_initialization.rs:62:18 | LL | let h = &mut S { | __________________^ +LL | | LL | | ..*Box::new(S { f: String::from("foo") }) LL | | }; | |_____^ help: replace with: `*Box::new(S { f: String::from("foo") })` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:77:18 + --> tests/ui/unnecessary_struct_initialization.rs:82:18 | LL | let p = &mut T { | __________________^ +LL | | LL | | ..*Box::new(T { f: 5 }) LL | | }; | |_____^ help: replace with: `*Box::new(T { f: 5 })` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:83:13 + --> tests/ui/unnecessary_struct_initialization.rs:89:13 | LL | let r = W { f1: q.f1, f2: q.f2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `q` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:94:13 + --> tests/ui/unnecessary_struct_initialization.rs:101:13 | LL | let w = W { f1: v.f1, ..v }; | ^^^^^^^^^^^^^^^^^^^ help: replace with: `v` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:102:14 + --> tests/ui/unnecessary_struct_initialization.rs:110:14 | LL | let r2 = r1.start..r1.end; | ^^^^^^^^^^^^^^^^ help: replace with: `r1` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:115:14 + --> tests/ui/unnecessary_struct_initialization.rs:124:14 | LL | let d = &W { f1: c.f1, f2: c.f2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `c` error: unnecessary struct building - --> tests/ui/unnecessary_struct_initialization.rs:123:14 + --> tests/ui/unnecessary_struct_initialization.rs:133:14 | LL | let h = &W { f1: g.f1, ..g }; | ^^^^^^^^^^^^^^^^^^^ help: replace with: `g` diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed index 027dac419375b..bf271aef763bb 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed @@ -3,7 +3,8 @@ clippy::needless_borrows_for_generic_args, clippy::ptr_arg, clippy::manual_async_fn, - clippy::needless_lifetimes + clippy::needless_lifetimes, + clippy::owned_cow )] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] @@ -62,82 +63,151 @@ fn main() { let x_ref = &x; require_c_str(&Cow::from(c_str)); + //~^ unnecessary_to_owned require_c_str(c_str); + //~^ unnecessary_to_owned require_os_str(os_str); + //~^ unnecessary_to_owned require_os_str(&Cow::from(os_str)); + //~^ unnecessary_to_owned require_os_str(os_str); + //~^ unnecessary_to_owned require_path(path); + //~^ unnecessary_to_owned require_path(&Cow::from(path)); + //~^ unnecessary_to_owned require_path(path); + //~^ unnecessary_to_owned require_str(s); + //~^ unnecessary_to_owned require_str(&Cow::from(s)); + //~^ unnecessary_to_owned require_str(s); + //~^ unnecessary_to_owned require_str(x_ref.as_ref()); + //~^ unnecessary_to_owned require_slice(slice); + //~^ unnecessary_to_owned require_slice(&Cow::from(slice)); + //~^ unnecessary_to_owned require_slice(array.as_ref()); + //~^ unnecessary_to_owned require_slice(array_ref.as_ref()); + //~^ unnecessary_to_owned require_slice(slice); + //~^ unnecessary_to_owned require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. require_x(&Cow::::Owned(x.clone())); + //~^ unnecessary_to_owned require_x(&x_ref.to_owned()); // No longer flagged because of #8759. require_deref_c_str(c_str); + //~^ unnecessary_to_owned require_deref_os_str(os_str); + //~^ unnecessary_to_owned require_deref_path(path); + //~^ unnecessary_to_owned require_deref_str(s); + //~^ unnecessary_to_owned require_deref_slice(slice); + //~^ unnecessary_to_owned require_impl_deref_c_str(c_str); + //~^ unnecessary_to_owned require_impl_deref_os_str(os_str); + //~^ unnecessary_to_owned require_impl_deref_path(path); + //~^ unnecessary_to_owned require_impl_deref_str(s); + //~^ unnecessary_to_owned require_impl_deref_slice(slice); + //~^ unnecessary_to_owned require_deref_str_slice(s, slice); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_deref_slice_str(slice, s); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_c_str(c_str); + //~^ unnecessary_to_owned require_as_ref_os_str(os_str); + //~^ unnecessary_to_owned require_as_ref_path(path); + //~^ unnecessary_to_owned require_as_ref_str(s); + //~^ unnecessary_to_owned require_as_ref_str(&x); + //~^ unnecessary_to_owned require_as_ref_slice(array); + //~^ unnecessary_to_owned require_as_ref_slice(array_ref); + //~^ unnecessary_to_owned require_as_ref_slice(slice); + //~^ unnecessary_to_owned require_impl_as_ref_c_str(c_str); + //~^ unnecessary_to_owned require_impl_as_ref_os_str(os_str); + //~^ unnecessary_to_owned require_impl_as_ref_path(path); + //~^ unnecessary_to_owned require_impl_as_ref_str(s); + //~^ unnecessary_to_owned require_impl_as_ref_str(&x); + //~^ unnecessary_to_owned require_impl_as_ref_slice(array); + //~^ unnecessary_to_owned require_impl_as_ref_slice(array_ref); + //~^ unnecessary_to_owned require_impl_as_ref_slice(slice); + //~^ unnecessary_to_owned require_as_ref_str_slice(s, array); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_str_slice(s, array_ref); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_str_slice(s, slice); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_slice_str(array, s); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_slice_str(array_ref, s); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_slice_str(slice, s); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned let _ = x.join(x_ref); + //~^ unnecessary_to_owned let _ = slice.iter().copied(); + //~^ unnecessary_to_owned let _ = slice.iter().copied(); + //~^ unnecessary_to_owned let _ = [std::path::PathBuf::new()][..].iter().cloned(); + //~^ unnecessary_to_owned let _ = [std::path::PathBuf::new()][..].iter().cloned(); + //~^ unnecessary_to_owned let _ = slice.iter().copied(); + //~^ unnecessary_to_owned let _ = slice.iter().copied(); + //~^ unnecessary_to_owned let _ = [std::path::PathBuf::new()][..].iter().cloned(); + //~^ unnecessary_to_owned let _ = [std::path::PathBuf::new()][..].iter().cloned(); + //~^ unnecessary_to_owned let _ = check_files(&[FileType::Account]); @@ -153,15 +223,23 @@ fn main() { // The following should be flagged by `redundant_clone`, but not by this lint. require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap()); + //~^ redundant_clone require_os_str(&OsString::from("x")); + //~^ redundant_clone require_path(&std::path::PathBuf::from("x")); + //~^ redundant_clone require_str(&String::from("x")); + //~^ redundant_clone require_slice(&[String::from("x")]); + //~^ redundant_clone let slice = [0u8; 1024]; let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); + //~^ unnecessary_to_owned let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); + //~^ unnecessary_to_owned let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); + //~^ unnecessary_to_owned // Expression is of type `&String`, can't suggest `str::from_utf8` here let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); macro_rules! arg_from_macro { @@ -219,6 +297,7 @@ fn require_as_ref_slice_str, V: AsRef>(_: U, _: V) {} // https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 fn check_files(file_types: &[FileType]) -> bool { for t in file_types { + //~^ unnecessary_to_owned let path = match get_file_path(t) { Ok(p) => p, Err(_) => { @@ -242,11 +321,13 @@ fn require_string(_: &String) {} fn _msrv_1_35() { // `copied` was stabilized in 1.36, so clippy should use `cloned`. let _ = &["x"][..].iter().cloned(); + //~^ unnecessary_to_owned } #[clippy::msrv = "1.36"] fn _msrv_1_36() { let _ = &["x"][..].iter().copied(); + //~^ unnecessary_to_owned } // https://github.com/rust-lang/rust-clippy/issues/8507 @@ -295,6 +376,7 @@ mod issue_8507 { // Should lint because Y is copy. fn test_y(y: Y) -> Box { Box::new(build(y)) + //~^ unnecessary_to_owned } } @@ -404,6 +486,7 @@ mod issue_9351 { // Should lint fn single_return() -> impl AsRef { id("abc") + //~^ unnecessary_to_owned } // Should not lint @@ -547,6 +630,7 @@ mod issue_11952 { fn bar() { IntoFuture::into_future(foo([], &0)); + //~^ unnecessary_to_owned } } @@ -556,18 +640,23 @@ fn borrow_checks() { fn inner(a: &[&str]) { let mut s = HashSet::from([vec!["a"]]); - s.remove(a); //~ ERROR: unnecessary use of `to_vec` + s.remove(a); + //~^ unnecessary_to_owned } let mut s = HashSet::from(["a".to_string()]); - s.remove("b"); //~ ERROR: unnecessary use of `to_owned` - s.remove("b"); //~ ERROR: unnecessary use of `to_string` + s.remove("b"); + //~^ unnecessary_to_owned + s.remove("b"); + //~^ unnecessary_to_owned // Should not warn. s.remove("b"); let mut s = HashSet::from([vec!["a"]]); - s.remove(["b"].as_slice()); //~ ERROR: unnecessary use of `to_vec` - s.remove((&["b"]).as_slice()); //~ ERROR: unnecessary use of `to_vec` + s.remove(["b"].as_slice()); + //~^ unnecessary_to_owned + s.remove((&["b"]).as_slice()); + //~^ unnecessary_to_owned // Should not warn. s.remove(&["b"].to_vec().clone()); diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs index b89f3d552f84d..95b95ab6bd222 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs @@ -3,7 +3,8 @@ clippy::needless_borrows_for_generic_args, clippy::ptr_arg, clippy::manual_async_fn, - clippy::needless_lifetimes + clippy::needless_lifetimes, + clippy::owned_cow )] #![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] @@ -62,82 +63,151 @@ fn main() { let x_ref = &x; require_c_str(&Cow::from(c_str).into_owned()); + //~^ unnecessary_to_owned require_c_str(&c_str.to_owned()); + //~^ unnecessary_to_owned require_os_str(&os_str.to_os_string()); + //~^ unnecessary_to_owned require_os_str(&Cow::from(os_str).into_owned()); + //~^ unnecessary_to_owned require_os_str(&os_str.to_owned()); + //~^ unnecessary_to_owned require_path(&path.to_path_buf()); + //~^ unnecessary_to_owned require_path(&Cow::from(path).into_owned()); + //~^ unnecessary_to_owned require_path(&path.to_owned()); + //~^ unnecessary_to_owned require_str(&s.to_string()); + //~^ unnecessary_to_owned require_str(&Cow::from(s).into_owned()); + //~^ unnecessary_to_owned require_str(&s.to_owned()); + //~^ unnecessary_to_owned require_str(&x_ref.to_string()); + //~^ unnecessary_to_owned require_slice(&slice.to_vec()); + //~^ unnecessary_to_owned require_slice(&Cow::from(slice).into_owned()); + //~^ unnecessary_to_owned require_slice(&array.to_owned()); + //~^ unnecessary_to_owned require_slice(&array_ref.to_owned()); + //~^ unnecessary_to_owned require_slice(&slice.to_owned()); + //~^ unnecessary_to_owned require_slice(&x_ref.to_owned()); // No longer flagged because of #8759. require_x(&Cow::::Owned(x.clone()).into_owned()); + //~^ unnecessary_to_owned require_x(&x_ref.to_owned()); // No longer flagged because of #8759. require_deref_c_str(c_str.to_owned()); + //~^ unnecessary_to_owned require_deref_os_str(os_str.to_owned()); + //~^ unnecessary_to_owned require_deref_path(path.to_owned()); + //~^ unnecessary_to_owned require_deref_str(s.to_owned()); + //~^ unnecessary_to_owned require_deref_slice(slice.to_owned()); + //~^ unnecessary_to_owned require_impl_deref_c_str(c_str.to_owned()); + //~^ unnecessary_to_owned require_impl_deref_os_str(os_str.to_owned()); + //~^ unnecessary_to_owned require_impl_deref_path(path.to_owned()); + //~^ unnecessary_to_owned require_impl_deref_str(s.to_owned()); + //~^ unnecessary_to_owned require_impl_deref_slice(slice.to_owned()); + //~^ unnecessary_to_owned require_deref_str_slice(s.to_owned(), slice.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_deref_slice_str(slice.to_owned(), s.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_c_str(c_str.to_owned()); + //~^ unnecessary_to_owned require_as_ref_os_str(os_str.to_owned()); + //~^ unnecessary_to_owned require_as_ref_path(path.to_owned()); + //~^ unnecessary_to_owned require_as_ref_str(s.to_owned()); + //~^ unnecessary_to_owned require_as_ref_str(x.to_owned()); + //~^ unnecessary_to_owned require_as_ref_slice(array.to_owned()); + //~^ unnecessary_to_owned require_as_ref_slice(array_ref.to_owned()); + //~^ unnecessary_to_owned require_as_ref_slice(slice.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_c_str(c_str.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_os_str(os_str.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_path(path.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_str(s.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_str(x.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_slice(array.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_slice(array_ref.to_owned()); + //~^ unnecessary_to_owned require_impl_as_ref_slice(slice.to_owned()); + //~^ unnecessary_to_owned require_as_ref_str_slice(s.to_owned(), array.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_str_slice(s.to_owned(), slice.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_slice_str(array.to_owned(), s.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned require_as_ref_slice_str(slice.to_owned(), s.to_owned()); + //~^ unnecessary_to_owned + //~| unnecessary_to_owned let _ = x.join(&x_ref.to_string()); + //~^ unnecessary_to_owned let _ = slice.to_vec().into_iter(); + //~^ unnecessary_to_owned let _ = slice.to_owned().into_iter(); + //~^ unnecessary_to_owned let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); + //~^ unnecessary_to_owned let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); + //~^ unnecessary_to_owned let _ = IntoIterator::into_iter(slice.to_vec()); + //~^ unnecessary_to_owned let _ = IntoIterator::into_iter(slice.to_owned()); + //~^ unnecessary_to_owned let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); + //~^ unnecessary_to_owned let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); + //~^ unnecessary_to_owned let _ = check_files(&[FileType::Account]); @@ -153,15 +223,23 @@ fn main() { // The following should be flagged by `redundant_clone`, but not by this lint. require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); + //~^ redundant_clone require_os_str(&OsString::from("x").to_os_string()); + //~^ redundant_clone require_path(&std::path::PathBuf::from("x").to_path_buf()); + //~^ redundant_clone require_str(&String::from("x").to_string()); + //~^ redundant_clone require_slice(&[String::from("x")].to_owned()); + //~^ redundant_clone let slice = [0u8; 1024]; let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); + //~^ unnecessary_to_owned let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); + //~^ unnecessary_to_owned let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); + //~^ unnecessary_to_owned // Expression is of type `&String`, can't suggest `str::from_utf8` here let _ref_string = &String::from_utf8(b"foo".to_vec()).unwrap(); macro_rules! arg_from_macro { @@ -219,6 +297,7 @@ fn require_as_ref_slice_str, V: AsRef>(_: U, _: V) {} // https://github.com/breard-r/acmed/blob/1f0dcc32aadbc5e52de6d23b9703554c0f925113/acmed/src/storage.rs#L262 fn check_files(file_types: &[FileType]) -> bool { for t in file_types.to_vec() { + //~^ unnecessary_to_owned let path = match get_file_path(&t) { Ok(p) => p, Err(_) => { @@ -242,11 +321,13 @@ fn require_string(_: &String) {} fn _msrv_1_35() { // `copied` was stabilized in 1.36, so clippy should use `cloned`. let _ = &["x"][..].to_vec().into_iter(); + //~^ unnecessary_to_owned } #[clippy::msrv = "1.36"] fn _msrv_1_36() { let _ = &["x"][..].to_vec().into_iter(); + //~^ unnecessary_to_owned } // https://github.com/rust-lang/rust-clippy/issues/8507 @@ -295,6 +376,7 @@ mod issue_8507 { // Should lint because Y is copy. fn test_y(y: Y) -> Box { Box::new(build(y.to_string())) + //~^ unnecessary_to_owned } } @@ -404,6 +486,7 @@ mod issue_9351 { // Should lint fn single_return() -> impl AsRef { id("abc".to_string()) + //~^ unnecessary_to_owned } // Should not lint @@ -547,6 +630,7 @@ mod issue_11952 { fn bar() { IntoFuture::into_future(foo([].to_vec(), &0)); + //~^ unnecessary_to_owned } } @@ -556,18 +640,23 @@ fn borrow_checks() { fn inner(a: &[&str]) { let mut s = HashSet::from([vec!["a"]]); - s.remove(&a.to_vec()); //~ ERROR: unnecessary use of `to_vec` + s.remove(&a.to_vec()); + //~^ unnecessary_to_owned } let mut s = HashSet::from(["a".to_string()]); - s.remove(&"b".to_owned()); //~ ERROR: unnecessary use of `to_owned` - s.remove(&"b".to_string()); //~ ERROR: unnecessary use of `to_string` + s.remove(&"b".to_owned()); + //~^ unnecessary_to_owned + s.remove(&"b".to_string()); + //~^ unnecessary_to_owned // Should not warn. s.remove("b"); let mut s = HashSet::from([vec!["a"]]); - s.remove(&["b"].to_vec()); //~ ERROR: unnecessary use of `to_vec` - s.remove(&(&["b"]).to_vec()); //~ ERROR: unnecessary use of `to_vec` + s.remove(&["b"].to_vec()); + //~^ unnecessary_to_owned + s.remove(&(&["b"]).to_vec()); + //~^ unnecessary_to_owned // Should not warn. s.remove(&["b"].to_vec().clone()); diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr index 498ac68cdaa0f..4daa3876e60eb 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr @@ -1,11 +1,11 @@ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:155:64 + --> tests/ui/unnecessary_to_owned.rs:225:64 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:155:20 + --> tests/ui/unnecessary_to_owned.rs:225:20 | LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -13,55 +13,55 @@ LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned()) = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]` error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:156:40 + --> tests/ui/unnecessary_to_owned.rs:227:40 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:156:21 + --> tests/ui/unnecessary_to_owned.rs:227:21 | LL | require_os_str(&OsString::from("x").to_os_string()); | ^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:157:48 + --> tests/ui/unnecessary_to_owned.rs:229:48 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:157:19 + --> tests/ui/unnecessary_to_owned.rs:229:19 | LL | require_path(&std::path::PathBuf::from("x").to_path_buf()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:158:35 + --> tests/ui/unnecessary_to_owned.rs:231:35 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:158:18 + --> tests/ui/unnecessary_to_owned.rs:231:18 | LL | require_str(&String::from("x").to_string()); | ^^^^^^^^^^^^^^^^^ error: redundant clone - --> tests/ui/unnecessary_to_owned.rs:159:39 + --> tests/ui/unnecessary_to_owned.rs:233:39 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> tests/ui/unnecessary_to_owned.rs:159:20 + --> tests/ui/unnecessary_to_owned.rs:233:20 | LL | require_slice(&[String::from("x")].to_owned()); | ^^^^^^^^^^^^^^^^^^^ error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:64:36 + --> tests/ui/unnecessary_to_owned.rs:65:36 | LL | require_c_str(&Cow::from(c_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this @@ -70,415 +70,415 @@ LL | require_c_str(&Cow::from(c_str).into_owned()); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:65:19 + --> tests/ui/unnecessary_to_owned.rs:67:19 | LL | require_c_str(&c_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_os_string` - --> tests/ui/unnecessary_to_owned.rs:67:20 + --> tests/ui/unnecessary_to_owned.rs:70:20 | LL | require_os_str(&os_str.to_os_string()); | ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:68:38 + --> tests/ui/unnecessary_to_owned.rs:72:38 | LL | require_os_str(&Cow::from(os_str).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:69:20 + --> tests/ui/unnecessary_to_owned.rs:74:20 | LL | require_os_str(&os_str.to_owned()); | ^^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_path_buf` - --> tests/ui/unnecessary_to_owned.rs:71:18 + --> tests/ui/unnecessary_to_owned.rs:77:18 | LL | require_path(&path.to_path_buf()); | ^^^^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:72:34 + --> tests/ui/unnecessary_to_owned.rs:79:34 | LL | require_path(&Cow::from(path).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:73:18 + --> tests/ui/unnecessary_to_owned.rs:81:18 | LL | require_path(&path.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:75:17 + --> tests/ui/unnecessary_to_owned.rs:84:17 | LL | require_str(&s.to_string()); | ^^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:76:30 + --> tests/ui/unnecessary_to_owned.rs:86:30 | LL | require_str(&Cow::from(s).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:77:17 + --> tests/ui/unnecessary_to_owned.rs:88:17 | LL | require_str(&s.to_owned()); | ^^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:78:17 + --> tests/ui/unnecessary_to_owned.rs:90:17 | LL | require_str(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:80:19 + --> tests/ui/unnecessary_to_owned.rs:93:19 | LL | require_slice(&slice.to_vec()); | ^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:81:36 + --> tests/ui/unnecessary_to_owned.rs:95:36 | LL | require_slice(&Cow::from(slice).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:82:19 + --> tests/ui/unnecessary_to_owned.rs:97:19 | LL | require_slice(&array.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:83:19 + --> tests/ui/unnecessary_to_owned.rs:99:19 | LL | require_slice(&array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:84:19 + --> tests/ui/unnecessary_to_owned.rs:101:19 | LL | require_slice(&slice.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `into_owned` - --> tests/ui/unnecessary_to_owned.rs:87:42 + --> tests/ui/unnecessary_to_owned.rs:105:42 | LL | require_x(&Cow::::Owned(x.clone()).into_owned()); | ^^^^^^^^^^^^^ help: remove this error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:90:25 + --> tests/ui/unnecessary_to_owned.rs:109:25 | LL | require_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:91:26 + --> tests/ui/unnecessary_to_owned.rs:111:26 | LL | require_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:92:24 + --> tests/ui/unnecessary_to_owned.rs:113:24 | LL | require_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:93:23 + --> tests/ui/unnecessary_to_owned.rs:115:23 | LL | require_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:94:25 + --> tests/ui/unnecessary_to_owned.rs:117:25 | LL | require_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:96:30 + --> tests/ui/unnecessary_to_owned.rs:120:30 | LL | require_impl_deref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:97:31 + --> tests/ui/unnecessary_to_owned.rs:122:31 | LL | require_impl_deref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:98:29 + --> tests/ui/unnecessary_to_owned.rs:124:29 | LL | require_impl_deref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:99:28 + --> tests/ui/unnecessary_to_owned.rs:126:28 | LL | require_impl_deref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:100:30 + --> tests/ui/unnecessary_to_owned.rs:128:30 | LL | require_impl_deref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:102:29 + --> tests/ui/unnecessary_to_owned.rs:131:29 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:102:43 + --> tests/ui/unnecessary_to_owned.rs:131:43 | LL | require_deref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:103:29 + --> tests/ui/unnecessary_to_owned.rs:134:29 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:103:47 + --> tests/ui/unnecessary_to_owned.rs:134:47 | LL | require_deref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:105:26 + --> tests/ui/unnecessary_to_owned.rs:138:26 | LL | require_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:106:27 + --> tests/ui/unnecessary_to_owned.rs:140:27 | LL | require_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:107:25 + --> tests/ui/unnecessary_to_owned.rs:142:25 | LL | require_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:108:24 + --> tests/ui/unnecessary_to_owned.rs:144:24 | LL | require_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:109:24 + --> tests/ui/unnecessary_to_owned.rs:146:24 | LL | require_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:110:26 + --> tests/ui/unnecessary_to_owned.rs:148:26 | LL | require_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:111:26 + --> tests/ui/unnecessary_to_owned.rs:150:26 | LL | require_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:112:26 + --> tests/ui/unnecessary_to_owned.rs:152:26 | LL | require_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:114:31 + --> tests/ui/unnecessary_to_owned.rs:155:31 | LL | require_impl_as_ref_c_str(c_str.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `c_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:115:32 + --> tests/ui/unnecessary_to_owned.rs:157:32 | LL | require_impl_as_ref_os_str(os_str.to_owned()); | ^^^^^^^^^^^^^^^^^ help: use: `os_str` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:116:30 + --> tests/ui/unnecessary_to_owned.rs:159:30 | LL | require_impl_as_ref_path(path.to_owned()); | ^^^^^^^^^^^^^^^ help: use: `path` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:117:29 + --> tests/ui/unnecessary_to_owned.rs:161:29 | LL | require_impl_as_ref_str(s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:118:29 + --> tests/ui/unnecessary_to_owned.rs:163:29 | LL | require_impl_as_ref_str(x.to_owned()); | ^^^^^^^^^^^^ help: use: `&x` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:119:31 + --> tests/ui/unnecessary_to_owned.rs:165:31 | LL | require_impl_as_ref_slice(array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:120:31 + --> tests/ui/unnecessary_to_owned.rs:167:31 | LL | require_impl_as_ref_slice(array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:121:31 + --> tests/ui/unnecessary_to_owned.rs:169:31 | LL | require_impl_as_ref_slice(slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:123:30 + --> tests/ui/unnecessary_to_owned.rs:172:30 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:123:44 + --> tests/ui/unnecessary_to_owned.rs:172:44 | LL | require_as_ref_str_slice(s.to_owned(), array.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:124:30 + --> tests/ui/unnecessary_to_owned.rs:175:30 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:124:44 + --> tests/ui/unnecessary_to_owned.rs:175:44 | LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:125:30 + --> tests/ui/unnecessary_to_owned.rs:178:30 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:125:44 + --> tests/ui/unnecessary_to_owned.rs:178:44 | LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:126:30 + --> tests/ui/unnecessary_to_owned.rs:181:30 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `array` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:126:48 + --> tests/ui/unnecessary_to_owned.rs:181:48 | LL | require_as_ref_slice_str(array.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:127:30 + --> tests/ui/unnecessary_to_owned.rs:184:30 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:127:52 + --> tests/ui/unnecessary_to_owned.rs:184:52 | LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:128:30 + --> tests/ui/unnecessary_to_owned.rs:187:30 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^^^^^ help: use: `slice` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:128:48 + --> tests/ui/unnecessary_to_owned.rs:187:48 | LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned()); | ^^^^^^^^^^^^ help: use: `s` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:130:20 + --> tests/ui/unnecessary_to_owned.rs:191:20 | LL | let _ = x.join(&x_ref.to_string()); | ^^^^^^^^^^^^^^^^^^ help: use: `x_ref` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:132:13 + --> tests/ui/unnecessary_to_owned.rs:194:13 | LL | let _ = slice.to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:133:13 + --> tests/ui/unnecessary_to_owned.rs:196:13 | LL | let _ = slice.to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:134:13 + --> tests/ui/unnecessary_to_owned.rs:198:13 | LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:135:13 + --> tests/ui/unnecessary_to_owned.rs:200:13 | LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:137:13 + --> tests/ui/unnecessary_to_owned.rs:203:13 | LL | let _ = IntoIterator::into_iter(slice.to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:138:13 + --> tests/ui/unnecessary_to_owned.rs:205:13 | LL | let _ = IntoIterator::into_iter(slice.to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:139:13 + --> tests/ui/unnecessary_to_owned.rs:207:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:140:13 + --> tests/ui/unnecessary_to_owned.rs:209:13 | LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()` error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:162:26 + --> tests/ui/unnecessary_to_owned.rs:237:26 | LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -490,7 +490,7 @@ LL + let _ref_str: &str = core::str::from_utf8(&slice).expect("not UTF-8"); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:163:26 + --> tests/ui/unnecessary_to_owned.rs:239:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -502,7 +502,7 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo").unwrap(); | error: allocating a new `String` only to create a temporary `&str` from it - --> tests/ui/unnecessary_to_owned.rs:164:26 + --> tests/ui/unnecessary_to_owned.rs:241:26 | LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -514,7 +514,7 @@ LL + let _ref_str: &str = core::str::from_utf8(b"foo".as_slice()).unwrap(); | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:221:14 + --> tests/ui/unnecessary_to_owned.rs:299:14 | LL | for t in file_types.to_vec() { | ^^^^^^^^^^^^^^^^^^^ @@ -522,65 +522,66 @@ LL | for t in file_types.to_vec() { help: remove any references to the binding | LL ~ for t in file_types { +LL | LL ~ let path = match get_file_path(t) { | error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:244:14 + --> tests/ui/unnecessary_to_owned.rs:323:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:249:14 + --> tests/ui/unnecessary_to_owned.rs:329:14 | LL | let _ = &["x"][..].to_vec().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:297:24 + --> tests/ui/unnecessary_to_owned.rs:378:24 | LL | Box::new(build(y.to_string())) | ^^^^^^^^^^^^^ help: use: `y` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:406:12 + --> tests/ui/unnecessary_to_owned.rs:488:12 | LL | id("abc".to_string()) | ^^^^^^^^^^^^^^^^^ help: use: `"abc"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:549:37 + --> tests/ui/unnecessary_to_owned.rs:632:37 | LL | IntoFuture::into_future(foo([].to_vec(), &0)); | ^^^^^^^^^^^ help: use: `[]` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:559:18 + --> tests/ui/unnecessary_to_owned.rs:643:18 | LL | s.remove(&a.to_vec()); | ^^^^^^^^^^^ help: replace it with: `a` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned.rs:563:14 + --> tests/ui/unnecessary_to_owned.rs:648:14 | LL | s.remove(&"b".to_owned()); | ^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned.rs:564:14 + --> tests/ui/unnecessary_to_owned.rs:650:14 | LL | s.remove(&"b".to_string()); | ^^^^^^^^^^^^^^^^ help: replace it with: `"b"` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:569:14 + --> tests/ui/unnecessary_to_owned.rs:656:14 | LL | s.remove(&["b"].to_vec()); | ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned.rs:570:14 + --> tests/ui/unnecessary_to_owned.rs:658:14 | LL | s.remove(&(&["b"]).to_vec()); | ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()` diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed index e0ba216f41bfc..f43d92a2d9bab 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.fixed @@ -17,22 +17,29 @@ impl ToString for Issue12068 { fn main() { let _ = "a".split('a').next().unwrap(); - //~^ ERROR: unnecessary use of `to_string` + //~^ unnecessary_to_owned + let _ = "a".split("a").next().unwrap(); - //~^ ERROR: unnecessary use of `to_string` + //~^ unnecessary_to_owned + let _ = "a".split('a').next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned + let _ = "a".split("a").next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned + let _ = Issue12068.as_ref().split('a').next().unwrap(); - //~^ ERROR: unnecessary use of `to_string` + //~^ unnecessary_to_owned let _ = [1].split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_vec` + //~^ unnecessary_to_owned + let _ = [1].split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_vec` + //~^ unnecessary_to_owned + let _ = [1].split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned + let _ = [1].split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned } diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs index 70efc6ebba5da..bdf5f98bf61e3 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.rs @@ -17,22 +17,29 @@ impl ToString for Issue12068 { fn main() { let _ = "a".to_string().split('a').next().unwrap(); - //~^ ERROR: unnecessary use of `to_string` + //~^ unnecessary_to_owned + let _ = "a".to_string().split("a").next().unwrap(); - //~^ ERROR: unnecessary use of `to_string` + //~^ unnecessary_to_owned + let _ = "a".to_owned().split('a').next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned + let _ = "a".to_owned().split("a").next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned + let _ = Issue12068.to_string().split('a').next().unwrap(); - //~^ ERROR: unnecessary use of `to_string` + //~^ unnecessary_to_owned let _ = [1].to_vec().split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_vec` + //~^ unnecessary_to_owned + let _ = [1].to_vec().split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_vec` + //~^ unnecessary_to_owned + let _ = [1].to_owned().split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned + let _ = [1].to_owned().split(|x| *x == 2).next().unwrap(); - //~^ ERROR: unnecessary use of `to_owned` + //~^ unnecessary_to_owned } diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr index cf5c964bcf3cd..5e4fbb1035d69 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned_on_split.stderr @@ -8,49 +8,49 @@ LL | let _ = "a".to_string().split('a').next().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned_on_split.rs:21:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:22:13 | LL | let _ = "a".to_string().split("a").next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned_on_split.rs:23:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:25:13 | LL | let _ = "a".to_owned().split('a').next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split('a')` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned_on_split.rs:25:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:28:13 | LL | let _ = "a".to_owned().split("a").next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `"a".split("a")` error: unnecessary use of `to_string` - --> tests/ui/unnecessary_to_owned_on_split.rs:27:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:31:13 | LL | let _ = Issue12068.to_string().split('a').next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `Issue12068.as_ref().split('a')` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned_on_split.rs:30:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:34:13 | LL | let _ = [1].to_vec().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` error: unnecessary use of `to_vec` - --> tests/ui/unnecessary_to_owned_on_split.rs:32:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:37:13 | LL | let _ = [1].to_vec().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned_on_split.rs:34:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:40:13 | LL | let _ = [1].to_owned().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` error: unnecessary use of `to_owned` - --> tests/ui/unnecessary_to_owned_on_split.rs:36:13 + --> tests/ui/unnecessary_to_owned_on_split.rs:43:13 | LL | let _ = [1].to_owned().split(|x| *x == 2).next().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[1].split(|x| *x == 2)` diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs index 5ad117eb8db6e..7a847d2e3b501 100644 --- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs +++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs @@ -17,6 +17,7 @@ pub fn destroy_the_planet() { /// /// This function shouldn't be called unless the horsemen are ready pub fn apocalypse(universe: &mut ()) { + //~^ unnecessary_safety_doc unimplemented!(); } @@ -43,6 +44,7 @@ mod private_mod { /// /// Unnecessary safety! pub fn republished() { + //~^ unnecessary_safety_doc unimplemented!(); } } @@ -56,6 +58,7 @@ pub trait SafeTraitSafeMethods { /// /// Unnecessary! fn documented(self); + //~^ unnecessary_safety_doc } pub trait SafeTrait { @@ -66,6 +69,7 @@ pub trait SafeTrait { /// /// Unnecessary! pub trait DocumentedSafeTrait { + //~^ unnecessary_safety_doc fn method2(); } @@ -94,6 +98,7 @@ impl Struct { /// /// Unnecessary! pub fn documented() -> Self { + //~^ unnecessary_safety_doc unimplemented!(); } @@ -121,6 +126,7 @@ macro_rules! very_safe { /// /// Driving is very safe already! pub fn drive() { + //~^ unnecessary_safety_doc whee() } }; @@ -149,5 +155,6 @@ pub mod __macro { /// # Implementation safety pub trait DocumentedSafeTraitWithImplementationHeader { + //~^ unnecessary_safety_doc fn method(); } diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr index d8a9f0aa38c33..dd9d8b65f75e8 100644 --- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.stderr @@ -8,31 +8,31 @@ LL | pub fn apocalypse(universe: &mut ()) { = help: to override `-D warnings` add `#[allow(clippy::unnecessary_safety_doc)]` error: safe function's docs have unnecessary `# Safety` section - --> tests/ui/unnecessary_unsafety_doc.rs:45:5 + --> tests/ui/unnecessary_unsafety_doc.rs:46:5 | LL | pub fn republished() { | ^^^^^^^^^^^^^^^^^^^^ error: safe function's docs have unnecessary `# Safety` section - --> tests/ui/unnecessary_unsafety_doc.rs:58:5 + --> tests/ui/unnecessary_unsafety_doc.rs:60:5 | LL | fn documented(self); | ^^^^^^^^^^^^^^^^^^^^ error: docs for safe trait have unnecessary `# Safety` section - --> tests/ui/unnecessary_unsafety_doc.rs:68:1 + --> tests/ui/unnecessary_unsafety_doc.rs:71:1 | LL | pub trait DocumentedSafeTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: safe function's docs have unnecessary `# Safety` section - --> tests/ui/unnecessary_unsafety_doc.rs:96:5 + --> tests/ui/unnecessary_unsafety_doc.rs:100:5 | LL | pub fn documented() -> Self { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: safe function's docs have unnecessary `# Safety` section - --> tests/ui/unnecessary_unsafety_doc.rs:123:9 + --> tests/ui/unnecessary_unsafety_doc.rs:128:9 | LL | pub fn drive() { | ^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | very_safe!(); = note: this error originates in the macro `very_safe` (in Nightly builds, run with -Z macro-backtrace for more info) error: docs for safe trait have unnecessary `# Safety` section - --> tests/ui/unnecessary_unsafety_doc.rs:151:1 + --> tests/ui/unnecessary_unsafety_doc.rs:157:1 | LL | pub trait DocumentedSafeTraitWithImplementationHeader { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.rs b/src/tools/clippy/tests/ui/unnecessary_wraps.rs index 200aefff1bbf4..4770ef3b48300 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.rs +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.rs @@ -7,8 +7,8 @@ // should be linted fn func1(a: bool, b: bool) -> Option { - //~^ ERROR: this function's return value is unnecessarily wrapped by `Option` - //~| NOTE: `-D clippy::unnecessary-wraps` implied by `-D warnings` + //~^ unnecessary_wraps + if a && b { return Some(42); } @@ -22,7 +22,8 @@ fn func1(a: bool, b: bool) -> Option { // should be linted fn func2(a: bool, b: bool) -> Option { - //~^ ERROR: this function's return value is unnecessarily wrapped by `Option` + //~^ unnecessary_wraps + if a && b { return Some(10); } @@ -41,7 +42,8 @@ fn func4(a: bool) -> Option { // should be linted fn func5() -> Option { - //~^ ERROR: this function's return value is unnecessarily wrapped by `Option` + //~^ unnecessary_wraps + Some(1) } @@ -52,7 +54,8 @@ fn func6() -> Option { // should be linted fn func7() -> Result { - //~^ ERROR: this function's return value is unnecessarily wrapped by `Result` + //~^ unnecessary_wraps + Ok(1) } @@ -81,7 +84,8 @@ impl A { // should be linted fn func12() -> Option { - //~^ ERROR: this function's return value is unnecessarily wrapped by `Option` + //~^ unnecessary_wraps + Some(1) } } @@ -109,7 +113,8 @@ fn issue_6384(s: &str) -> Option<&str> { // should be linted fn issue_6640_1(a: bool, b: bool) -> Option<()> { - //~^ ERROR: this function's return value is unnecessary + //~^ unnecessary_wraps + if a && b { return Some(()); } @@ -123,7 +128,8 @@ fn issue_6640_1(a: bool, b: bool) -> Option<()> { // should be linted fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { - //~^ ERROR: this function's return value is unnecessary + //~^ unnecessary_wraps + if a && b { return Ok(()); } diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr index b06ab91dc8de0..ba562f5a50bec 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.stderr @@ -32,9 +32,9 @@ error: this function's return value is unnecessarily wrapped by `Option` | LL | / fn func2(a: bool, b: bool) -> Option { LL | | +LL | | LL | | if a && b { -LL | | return Some(10); -LL | | } +... | LL | | if a { Some(20) } else { Some(30) } LL | | } | |_^ @@ -52,10 +52,11 @@ LL ~ if a { 20 } else { 30 } | error: this function's return value is unnecessarily wrapped by `Option` - --> tests/ui/unnecessary_wraps.rs:43:1 + --> tests/ui/unnecessary_wraps.rs:44:1 | LL | / fn func5() -> Option { LL | | +LL | | LL | | Some(1) LL | | } | |_^ @@ -72,10 +73,11 @@ LL + 1 | error: this function's return value is unnecessarily wrapped by `Result` - --> tests/ui/unnecessary_wraps.rs:54:1 + --> tests/ui/unnecessary_wraps.rs:56:1 | LL | / fn func7() -> Result { LL | | +LL | | LL | | Ok(1) LL | | } | |_^ @@ -92,10 +94,11 @@ LL + 1 | error: this function's return value is unnecessarily wrapped by `Option` - --> tests/ui/unnecessary_wraps.rs:83:5 + --> tests/ui/unnecessary_wraps.rs:86:5 | LL | / fn func12() -> Option { LL | | +LL | | LL | | Some(1) LL | | } | |_____^ @@ -112,12 +115,12 @@ LL + 1 | error: this function's return value is unnecessary - --> tests/ui/unnecessary_wraps.rs:111:1 + --> tests/ui/unnecessary_wraps.rs:115:1 | LL | / fn issue_6640_1(a: bool, b: bool) -> Option<()> { LL | | +LL | | LL | | if a && b { -LL | | return Some(()); ... | LL | | } | |_^ @@ -139,12 +142,12 @@ LL ~ return ; | error: this function's return value is unnecessary - --> tests/ui/unnecessary_wraps.rs:125:1 + --> tests/ui/unnecessary_wraps.rs:130:1 | LL | / fn issue_6640_2(a: bool, b: bool) -> Result<(), i32> { LL | | +LL | | LL | | if a && b { -LL | | return Ok(()); ... | LL | | } | |_^ diff --git a/src/tools/clippy/tests/ui/unneeded_field_pattern.rs b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs index 1d42f81711bd6..327b64e7c4aab 100644 --- a/src/tools/clippy/tests/ui/unneeded_field_pattern.rs +++ b/src/tools/clippy/tests/ui/unneeded_field_pattern.rs @@ -16,8 +16,9 @@ fn main() { match f { Foo { a: _, b: 0, .. } => {}, - + //~^ unneeded_field_pattern Foo { a: _, b: _, c: _ } => {}, + //~^ unneeded_field_pattern } match f { Foo { b: 0, .. } => {}, // should be OK diff --git a/src/tools/clippy/tests/ui/unneeded_struct_pattern.fixed b/src/tools/clippy/tests/ui/unneeded_struct_pattern.fixed index 5bd269896a6b1..665ab98913be3 100644 --- a/src/tools/clippy/tests/ui/unneeded_struct_pattern.fixed +++ b/src/tools/clippy/tests/ui/unneeded_struct_pattern.fixed @@ -15,11 +15,13 @@ fn main() { match Some(114514) { Some(v) => v, None => 0, + //~^ unneeded_struct_pattern }; match Some(1919810) { Some(v) => v, None => 0, + //~^ unneeded_struct_pattern }; match Some(123456) { @@ -30,15 +32,23 @@ fn main() { match Some(Some(123456)) { Some(Some(v)) => v, Some(None) => 0, + //~^ unneeded_struct_pattern None => 0, + //~^ unneeded_struct_pattern }; if let None = Some(0) {} + //~^ unneeded_struct_pattern if let None = Some(0) {} + //~^ unneeded_struct_pattern if let Some(None) = Some(Some(0)) {} + //~^ unneeded_struct_pattern let None = Some(0) else { panic!() }; + //~^ unneeded_struct_pattern let None = Some(0) else { panic!() }; + //~^ unneeded_struct_pattern let Some(None) = Some(Some(0)) else { panic!() }; + //~^ unneeded_struct_pattern enum Custom { HasFields { @@ -54,26 +64,28 @@ fn main() { match Custom::Init { Custom::HasFields { field: value } => value, Custom::HasBracketsNoFields {} => 0, - Custom::NoBrackets => 0, //~ ERROR: struct pattern is not needed for a unit variant - Custom::NoBracketsNonExhaustive => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets => 0, //~ unneeded_struct_pattern + Custom::NoBracketsNonExhaustive => 0, //~ unneeded_struct_pattern _ => 0, }; match Custom::Init { Custom::HasFields { field: value } => value, Custom::HasBracketsNoFields { .. } => 0, - Custom::NoBrackets => 0, //~ ERROR: struct pattern is not needed for a unit variant - Custom::NoBracketsNonExhaustive => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets => 0, //~ unneeded_struct_pattern + Custom::NoBracketsNonExhaustive => 0, //~ unneeded_struct_pattern _ => 0, }; match Custom::Init { - Custom::NoBrackets if true => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets if true => 0, //~ unneeded_struct_pattern _ => 0, }; match Custom::Init { - Custom::NoBrackets | Custom::NoBracketsNonExhaustive => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets | Custom::NoBracketsNonExhaustive => 0, + //~^ unneeded_struct_pattern + //~| unneeded_struct_pattern _ => 0, }; @@ -87,23 +99,24 @@ fn main() { noop(); } if let Custom::NoBrackets = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } if let Custom::NoBrackets = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } if let Custom::NoBrackets | Custom::NoBracketsNonExhaustive = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern + //~| unneeded_struct_pattern noop(); } if let Custom::NoBracketsNonExhaustive = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } if let Custom::NoBracketsNonExhaustive = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } @@ -118,18 +131,18 @@ fn main() { let Custom::HasBracketsNoFields { .. } = Custom::Init else { panic!() }; - let Custom::NoBrackets = Custom::Init else { panic!() }; //~ ERROR: struct pattern is not needed for a unit variant + let Custom::NoBrackets = Custom::Init else { panic!() }; //~ unneeded_struct_pattern let Custom::NoBrackets = Custom::Init else { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern panic!() }; let Custom::NoBracketsNonExhaustive = Custom::Init else { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern panic!() }; let Custom::NoBracketsNonExhaustive = Custom::Init else { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern panic!() }; @@ -137,11 +150,11 @@ fn main() { Variant, } - fn pat_in_fn_param_1(Refutable::Variant: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant - fn pat_in_fn_param_2(Refutable::Variant: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant + fn pat_in_fn_param_1(Refutable::Variant: Refutable) {} //~ unneeded_struct_pattern + fn pat_in_fn_param_2(Refutable::Variant: Refutable) {} //~ unneeded_struct_pattern - for Refutable::Variant in [] {} //~ ERROR: struct pattern is not needed for a unit variant - for Refutable::Variant in [] {} //~ ERROR: struct pattern is not needed for a unit variant + for Refutable::Variant in [] {} //~ unneeded_struct_pattern + for Refutable::Variant in [] {} //~ unneeded_struct_pattern } fn external_crate() { @@ -155,13 +168,13 @@ fn external_crate() { match ExhaustiveUnit { // Exhaustive variant - ExhaustiveUnit => 0, //~ ERROR: struct pattern is not needed for a unit variant + ExhaustiveUnit => 0, //~ unneeded_struct_pattern _ => 0, }; match ExhaustiveUnit { // Exhaustive variant - ExhaustiveUnit => 0, //~ ERROR: struct pattern is not needed for a unit variant + ExhaustiveUnit => 0, //~ unneeded_struct_pattern _ => 0, }; diff --git a/src/tools/clippy/tests/ui/unneeded_struct_pattern.rs b/src/tools/clippy/tests/ui/unneeded_struct_pattern.rs index c7658617ad376..7cadb6c7fbb54 100644 --- a/src/tools/clippy/tests/ui/unneeded_struct_pattern.rs +++ b/src/tools/clippy/tests/ui/unneeded_struct_pattern.rs @@ -15,11 +15,13 @@ fn main() { match Some(114514) { Some(v) => v, None {} => 0, + //~^ unneeded_struct_pattern }; match Some(1919810) { Some(v) => v, None { .. } => 0, + //~^ unneeded_struct_pattern }; match Some(123456) { @@ -30,15 +32,23 @@ fn main() { match Some(Some(123456)) { Some(Some(v)) => v, Some(None {}) => 0, + //~^ unneeded_struct_pattern None {} => 0, + //~^ unneeded_struct_pattern }; if let None {} = Some(0) {} + //~^ unneeded_struct_pattern if let None { .. } = Some(0) {} + //~^ unneeded_struct_pattern if let Some(None {}) = Some(Some(0)) {} + //~^ unneeded_struct_pattern let None {} = Some(0) else { panic!() }; + //~^ unneeded_struct_pattern let None { .. } = Some(0) else { panic!() }; + //~^ unneeded_struct_pattern let Some(None {}) = Some(Some(0)) else { panic!() }; + //~^ unneeded_struct_pattern enum Custom { HasFields { @@ -54,26 +64,28 @@ fn main() { match Custom::Init { Custom::HasFields { field: value } => value, Custom::HasBracketsNoFields {} => 0, - Custom::NoBrackets {} => 0, //~ ERROR: struct pattern is not needed for a unit variant - Custom::NoBracketsNonExhaustive {} => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets {} => 0, //~ unneeded_struct_pattern + Custom::NoBracketsNonExhaustive {} => 0, //~ unneeded_struct_pattern _ => 0, }; match Custom::Init { Custom::HasFields { field: value } => value, Custom::HasBracketsNoFields { .. } => 0, - Custom::NoBrackets { .. } => 0, //~ ERROR: struct pattern is not needed for a unit variant - Custom::NoBracketsNonExhaustive { .. } => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets { .. } => 0, //~ unneeded_struct_pattern + Custom::NoBracketsNonExhaustive { .. } => 0, //~ unneeded_struct_pattern _ => 0, }; match Custom::Init { - Custom::NoBrackets {} if true => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets {} if true => 0, //~ unneeded_struct_pattern _ => 0, }; match Custom::Init { - Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} => 0, //~ ERROR: struct pattern is not needed for a unit variant + Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} => 0, + //~^ unneeded_struct_pattern + //~| unneeded_struct_pattern _ => 0, }; @@ -87,23 +99,24 @@ fn main() { noop(); } if let Custom::NoBrackets {} = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } if let Custom::NoBrackets { .. } = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } if let Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern + //~| unneeded_struct_pattern noop(); } if let Custom::NoBracketsNonExhaustive {} = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } if let Custom::NoBracketsNonExhaustive { .. } = Custom::Init { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern noop(); } @@ -118,18 +131,18 @@ fn main() { let Custom::HasBracketsNoFields { .. } = Custom::Init else { panic!() }; - let Custom::NoBrackets {} = Custom::Init else { panic!() }; //~ ERROR: struct pattern is not needed for a unit variant + let Custom::NoBrackets {} = Custom::Init else { panic!() }; //~ unneeded_struct_pattern let Custom::NoBrackets { .. } = Custom::Init else { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern panic!() }; let Custom::NoBracketsNonExhaustive {} = Custom::Init else { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern panic!() }; let Custom::NoBracketsNonExhaustive { .. } = Custom::Init else { - //~^ ERROR: struct pattern is not needed for a unit variant + //~^ unneeded_struct_pattern panic!() }; @@ -137,11 +150,11 @@ fn main() { Variant, } - fn pat_in_fn_param_1(Refutable::Variant {}: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant - fn pat_in_fn_param_2(Refutable::Variant { .. }: Refutable) {} //~ ERROR: struct pattern is not needed for a unit variant + fn pat_in_fn_param_1(Refutable::Variant {}: Refutable) {} //~ unneeded_struct_pattern + fn pat_in_fn_param_2(Refutable::Variant { .. }: Refutable) {} //~ unneeded_struct_pattern - for Refutable::Variant {} in [] {} //~ ERROR: struct pattern is not needed for a unit variant - for Refutable::Variant { .. } in [] {} //~ ERROR: struct pattern is not needed for a unit variant + for Refutable::Variant {} in [] {} //~ unneeded_struct_pattern + for Refutable::Variant { .. } in [] {} //~ unneeded_struct_pattern } fn external_crate() { @@ -155,13 +168,13 @@ fn external_crate() { match ExhaustiveUnit { // Exhaustive variant - ExhaustiveUnit { .. } => 0, //~ ERROR: struct pattern is not needed for a unit variant + ExhaustiveUnit { .. } => 0, //~ unneeded_struct_pattern _ => 0, }; match ExhaustiveUnit { // Exhaustive variant - ExhaustiveUnit {} => 0, //~ ERROR: struct pattern is not needed for a unit variant + ExhaustiveUnit {} => 0, //~ unneeded_struct_pattern _ => 0, }; diff --git a/src/tools/clippy/tests/ui/unneeded_struct_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_struct_pattern.stderr index 3a7f595838020..7c0c3c9e4462e 100644 --- a/src/tools/clippy/tests/ui/unneeded_struct_pattern.stderr +++ b/src/tools/clippy/tests/ui/unneeded_struct_pattern.stderr @@ -8,193 +8,193 @@ LL | None {} => 0, = help: to override `-D warnings` add `#[allow(clippy::unneeded_struct_pattern)]` error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:22:13 + --> tests/ui/unneeded_struct_pattern.rs:23:13 | LL | None { .. } => 0, | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:32:18 + --> tests/ui/unneeded_struct_pattern.rs:34:18 | LL | Some(None {}) => 0, | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:33:13 + --> tests/ui/unneeded_struct_pattern.rs:36:13 | LL | None {} => 0, | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:36:16 + --> tests/ui/unneeded_struct_pattern.rs:40:16 | LL | if let None {} = Some(0) {} | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:37:16 + --> tests/ui/unneeded_struct_pattern.rs:42:16 | LL | if let None { .. } = Some(0) {} | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:38:21 + --> tests/ui/unneeded_struct_pattern.rs:44:21 | LL | if let Some(None {}) = Some(Some(0)) {} | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:39:13 + --> tests/ui/unneeded_struct_pattern.rs:46:13 | LL | let None {} = Some(0) else { panic!() }; | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:40:13 + --> tests/ui/unneeded_struct_pattern.rs:48:13 | LL | let None { .. } = Some(0) else { panic!() }; | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:41:18 + --> tests/ui/unneeded_struct_pattern.rs:50:18 | LL | let Some(None {}) = Some(Some(0)) else { panic!() }; | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:57:27 + --> tests/ui/unneeded_struct_pattern.rs:67:27 | LL | Custom::NoBrackets {} => 0, | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:58:40 + --> tests/ui/unneeded_struct_pattern.rs:68:40 | LL | Custom::NoBracketsNonExhaustive {} => 0, | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:65:27 + --> tests/ui/unneeded_struct_pattern.rs:75:27 | LL | Custom::NoBrackets { .. } => 0, | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:66:40 + --> tests/ui/unneeded_struct_pattern.rs:76:40 | LL | Custom::NoBracketsNonExhaustive { .. } => 0, | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:71:27 + --> tests/ui/unneeded_struct_pattern.rs:81:27 | LL | Custom::NoBrackets {} if true => 0, | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:76:27 + --> tests/ui/unneeded_struct_pattern.rs:86:27 | LL | Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} => 0, | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:76:64 + --> tests/ui/unneeded_struct_pattern.rs:86:64 | LL | Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} => 0, | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:89:30 + --> tests/ui/unneeded_struct_pattern.rs:101:30 | LL | if let Custom::NoBrackets {} = Custom::Init { | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:93:30 + --> tests/ui/unneeded_struct_pattern.rs:105:30 | LL | if let Custom::NoBrackets { .. } = Custom::Init { | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:97:30 + --> tests/ui/unneeded_struct_pattern.rs:109:30 | LL | if let Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} = Custom::Init { | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:97:67 + --> tests/ui/unneeded_struct_pattern.rs:109:67 | LL | if let Custom::NoBrackets {} | Custom::NoBracketsNonExhaustive {} = Custom::Init { | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:101:43 + --> tests/ui/unneeded_struct_pattern.rs:114:43 | LL | if let Custom::NoBracketsNonExhaustive {} = Custom::Init { | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:105:43 + --> tests/ui/unneeded_struct_pattern.rs:118:43 | LL | if let Custom::NoBracketsNonExhaustive { .. } = Custom::Init { | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:121:27 + --> tests/ui/unneeded_struct_pattern.rs:134:27 | LL | let Custom::NoBrackets {} = Custom::Init else { panic!() }; | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:123:27 + --> tests/ui/unneeded_struct_pattern.rs:136:27 | LL | let Custom::NoBrackets { .. } = Custom::Init else { | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:127:40 + --> tests/ui/unneeded_struct_pattern.rs:140:40 | LL | let Custom::NoBracketsNonExhaustive {} = Custom::Init else { | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:131:40 + --> tests/ui/unneeded_struct_pattern.rs:144:40 | LL | let Custom::NoBracketsNonExhaustive { .. } = Custom::Init else { | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:140:44 + --> tests/ui/unneeded_struct_pattern.rs:153:44 | LL | fn pat_in_fn_param_1(Refutable::Variant {}: Refutable) {} | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:141:44 + --> tests/ui/unneeded_struct_pattern.rs:154:44 | LL | fn pat_in_fn_param_2(Refutable::Variant { .. }: Refutable) {} | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:143:27 + --> tests/ui/unneeded_struct_pattern.rs:156:27 | LL | for Refutable::Variant {} in [] {} | ^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:144:27 + --> tests/ui/unneeded_struct_pattern.rs:157:27 | LL | for Refutable::Variant { .. } in [] {} | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:158:23 + --> tests/ui/unneeded_struct_pattern.rs:171:23 | LL | ExhaustiveUnit { .. } => 0, | ^^^^^^^ help: remove the struct pattern error: struct pattern is not needed for a unit variant - --> tests/ui/unneeded_struct_pattern.rs:164:23 + --> tests/ui/unneeded_struct_pattern.rs:177:23 | LL | ExhaustiveUnit {} => 0, | ^^^ help: remove the struct pattern diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed index cbf91ed4910ac..7e6a493b86c12 100644 --- a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed +++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed @@ -10,11 +10,17 @@ fn main() { let t = (0, 1, 2, 3); if let (0, ..) = t {}; + //~^ unneeded_wildcard_pattern if let (0, ..) = t {}; + //~^ unneeded_wildcard_pattern if let (.., 0) = t {}; + //~^ unneeded_wildcard_pattern if let (.., 0) = t {}; + //~^ unneeded_wildcard_pattern if let (0, ..) = t {}; + //~^ unneeded_wildcard_pattern if let (0, ..) = t {}; + //~^ unneeded_wildcard_pattern if let (_, 0, ..) = t {}; if let (.., 0, _) = t {}; if let (0, _, _, _) = t {}; @@ -24,6 +30,7 @@ fn main() { #[rustfmt::skip] { if let (0, ..,) = t {}; + //~^ unneeded_wildcard_pattern } struct S(usize, usize, usize, usize); @@ -31,11 +38,17 @@ fn main() { let s = S(0, 1, 2, 3); if let S(0, ..) = s {}; + //~^ unneeded_wildcard_pattern if let S(0, ..) = s {}; + //~^ unneeded_wildcard_pattern if let S(.., 0) = s {}; + //~^ unneeded_wildcard_pattern if let S(.., 0) = s {}; + //~^ unneeded_wildcard_pattern if let S(0, ..) = s {}; + //~^ unneeded_wildcard_pattern if let S(0, ..) = s {}; + //~^ unneeded_wildcard_pattern if let S(_, 0, ..) = s {}; if let S(.., 0, _) = s {}; if let S(0, _, _, _) = s {}; @@ -45,6 +58,7 @@ fn main() { #[rustfmt::skip] { if let S(0, ..,) = s {}; + //~^ unneeded_wildcard_pattern } external! { let t = (0, 1, 2, 3); diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs index 10df2b93d5e07..c91383e2cca5f 100644 --- a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs +++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs @@ -10,11 +10,17 @@ fn main() { let t = (0, 1, 2, 3); if let (0, .., _) = t {}; + //~^ unneeded_wildcard_pattern if let (0, _, ..) = t {}; + //~^ unneeded_wildcard_pattern if let (_, .., 0) = t {}; + //~^ unneeded_wildcard_pattern if let (.., _, 0) = t {}; + //~^ unneeded_wildcard_pattern if let (0, _, _, ..) = t {}; + //~^ unneeded_wildcard_pattern if let (0, .., _, _) = t {}; + //~^ unneeded_wildcard_pattern if let (_, 0, ..) = t {}; if let (.., 0, _) = t {}; if let (0, _, _, _) = t {}; @@ -24,6 +30,7 @@ fn main() { #[rustfmt::skip] { if let (0, .., _, _,) = t {}; + //~^ unneeded_wildcard_pattern } struct S(usize, usize, usize, usize); @@ -31,11 +38,17 @@ fn main() { let s = S(0, 1, 2, 3); if let S(0, .., _) = s {}; + //~^ unneeded_wildcard_pattern if let S(0, _, ..) = s {}; + //~^ unneeded_wildcard_pattern if let S(_, .., 0) = s {}; + //~^ unneeded_wildcard_pattern if let S(.., _, 0) = s {}; + //~^ unneeded_wildcard_pattern if let S(0, _, _, ..) = s {}; + //~^ unneeded_wildcard_pattern if let S(0, .., _, _) = s {}; + //~^ unneeded_wildcard_pattern if let S(_, 0, ..) = s {}; if let S(.., 0, _) = s {}; if let S(0, _, _, _) = s {}; @@ -45,6 +58,7 @@ fn main() { #[rustfmt::skip] { if let S(0, .., _, _,) = s {}; + //~^ unneeded_wildcard_pattern } external! { let t = (0, 1, 2, 3); diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr index ceb7d7fe9e09f..20666268a8cab 100644 --- a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr +++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.stderr @@ -11,79 +11,79 @@ LL | #![deny(clippy::unneeded_wildcard_pattern)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this pattern is unneeded as the `..` pattern can match that element - --> tests/ui/unneeded_wildcard_pattern.rs:13:16 + --> tests/ui/unneeded_wildcard_pattern.rs:14:16 | LL | if let (0, _, ..) = t {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> tests/ui/unneeded_wildcard_pattern.rs:14:13 + --> tests/ui/unneeded_wildcard_pattern.rs:16:13 | LL | if let (_, .., 0) = t {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> tests/ui/unneeded_wildcard_pattern.rs:15:15 + --> tests/ui/unneeded_wildcard_pattern.rs:18:15 | LL | if let (.., _, 0) = t {}; | ^^^ help: remove it error: these patterns are unneeded as the `..` pattern can match those elements - --> tests/ui/unneeded_wildcard_pattern.rs:16:16 + --> tests/ui/unneeded_wildcard_pattern.rs:20:16 | LL | if let (0, _, _, ..) = t {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> tests/ui/unneeded_wildcard_pattern.rs:17:18 + --> tests/ui/unneeded_wildcard_pattern.rs:22:18 | LL | if let (0, .., _, _) = t {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> tests/ui/unneeded_wildcard_pattern.rs:26:22 + --> tests/ui/unneeded_wildcard_pattern.rs:32:22 | LL | if let (0, .., _, _,) = t {}; | ^^^^^^ help: remove them error: this pattern is unneeded as the `..` pattern can match that element - --> tests/ui/unneeded_wildcard_pattern.rs:33:19 + --> tests/ui/unneeded_wildcard_pattern.rs:40:19 | LL | if let S(0, .., _) = s {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> tests/ui/unneeded_wildcard_pattern.rs:34:17 + --> tests/ui/unneeded_wildcard_pattern.rs:42:17 | LL | if let S(0, _, ..) = s {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> tests/ui/unneeded_wildcard_pattern.rs:35:14 + --> tests/ui/unneeded_wildcard_pattern.rs:44:14 | LL | if let S(_, .., 0) = s {}; | ^^^ help: remove it error: this pattern is unneeded as the `..` pattern can match that element - --> tests/ui/unneeded_wildcard_pattern.rs:36:16 + --> tests/ui/unneeded_wildcard_pattern.rs:46:16 | LL | if let S(.., _, 0) = s {}; | ^^^ help: remove it error: these patterns are unneeded as the `..` pattern can match those elements - --> tests/ui/unneeded_wildcard_pattern.rs:37:17 + --> tests/ui/unneeded_wildcard_pattern.rs:48:17 | LL | if let S(0, _, _, ..) = s {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> tests/ui/unneeded_wildcard_pattern.rs:38:19 + --> tests/ui/unneeded_wildcard_pattern.rs:50:19 | LL | if let S(0, .., _, _) = s {}; | ^^^^^^ help: remove them error: these patterns are unneeded as the `..` pattern can match those elements - --> tests/ui/unneeded_wildcard_pattern.rs:47:23 + --> tests/ui/unneeded_wildcard_pattern.rs:60:23 | LL | if let S(0, .., _, _,) = s {}; | ^^^^^^ help: remove them diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed index 53ec556d1008b..791b2fa131f23 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed @@ -14,27 +14,43 @@ fn main() { if let &0 | &2 = &0 {} if let box (0 | 2) = Box::new(0) {} + //~^ unnested_or_patterns if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} + //~^ unnested_or_patterns const C0: Option = Some(1); if let Some(1 | 2) | C0 = None {} + //~^ unnested_or_patterns if let &mut (0 | 2) = &mut 0 {} + //~^ unnested_or_patterns if let x @ (0 | 2) = 0 {} + //~^ unnested_or_patterns if let (0, 1 | 2 | 3) = (0, 0) {} + //~^ unnested_or_patterns if let (1 | 2 | 3, 0) = (0, 0) {} + //~^ unnested_or_patterns if let (x, ..) | (x, 1 | 2) = (0, 1) {} + //~^ unnested_or_patterns if let [0 | 1] = [0] {} + //~^ unnested_or_patterns if let [x, 0 | 1] = [0, 1] {} + //~^ unnested_or_patterns if let [x, 0 | 1 | 2] = [0, 1] {} + //~^ unnested_or_patterns if let [x, ..] | [x, 1 | 2] = [0, 1] {} + //~^ unnested_or_patterns struct TS(u8, u8); if let TS(0 | 1, x) = TS(0, 0) {} + //~^ unnested_or_patterns if let TS(1 | 2 | 3, 0) = TS(0, 0) {} + //~^ unnested_or_patterns if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {} + //~^ unnested_or_patterns struct S { x: u8, y: u8, } if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {} + //~^ unnested_or_patterns if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} } @@ -46,4 +62,5 @@ fn msrv_1_52() { #[clippy::msrv = "1.53"] fn msrv_1_53() { if let [1 | 53] = [0] {} + //~^ unnested_or_patterns } diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs index e5e378e922af2..e7e7c7cd2e494 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.rs +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs @@ -14,27 +14,43 @@ fn main() { if let &0 | &2 = &0 {} if let box 0 | box 2 = Box::new(0) {} + //~^ unnested_or_patterns if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {} + //~^ unnested_or_patterns const C0: Option = Some(1); if let Some(1) | C0 | Some(2) = None {} + //~^ unnested_or_patterns if let &mut 0 | &mut 2 = &mut 0 {} + //~^ unnested_or_patterns if let x @ 0 | x @ 2 = 0 {} + //~^ unnested_or_patterns if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} + //~^ unnested_or_patterns if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {} + //~^ unnested_or_patterns if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {} + //~^ unnested_or_patterns if let [0] | [1] = [0] {} + //~^ unnested_or_patterns if let [x, 0] | [x, 1] = [0, 1] {} + //~^ unnested_or_patterns if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {} + //~^ unnested_or_patterns if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {} + //~^ unnested_or_patterns struct TS(u8, u8); if let TS(0, x) | TS(1, x) = TS(0, 0) {} + //~^ unnested_or_patterns if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {} + //~^ unnested_or_patterns if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {} + //~^ unnested_or_patterns struct S { x: u8, y: u8, } if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} + //~^ unnested_or_patterns if let S { x: 0, y, .. } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} } @@ -46,4 +62,5 @@ fn msrv_1_52() { #[clippy::msrv = "1.53"] fn msrv_1_53() { if let [1] | [53] = [0] {} + //~^ unnested_or_patterns } diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr index 4325df1430423..ec5eb983c5a01 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr @@ -13,7 +13,7 @@ LL + if let box (0 | 2) = Box::new(0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:17:12 + --> tests/ui/unnested_or_patterns.rs:18:12 | LL | if let box ((0 | 1)) | box (2 | 3) | box 4 = Box::new(0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:19:12 + --> tests/ui/unnested_or_patterns.rs:21:12 | LL | if let Some(1) | C0 | Some(2) = None {} | ^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + if let Some(1 | 2) | C0 = None {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:20:12 + --> tests/ui/unnested_or_patterns.rs:23:12 | LL | if let &mut 0 | &mut 2 = &mut 0 {} | ^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + if let &mut (0 | 2) = &mut 0 {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:21:12 + --> tests/ui/unnested_or_patterns.rs:25:12 | LL | if let x @ 0 | x @ 2 = 0 {} | ^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + if let x @ (0 | 2) = 0 {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:22:12 + --> tests/ui/unnested_or_patterns.rs:27:12 | LL | if let (0, 1) | (0, 2) | (0, 3) = (0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + if let (0, 1 | 2 | 3) = (0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:23:12 + --> tests/ui/unnested_or_patterns.rs:29:12 | LL | if let (1, 0) | (2, 0) | (3, 0) = (0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + if let (1 | 2 | 3, 0) = (0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:24:12 + --> tests/ui/unnested_or_patterns.rs:31:12 | LL | if let (x, ..) | (x, 1) | (x, 2) = (0, 1) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + if let (x, ..) | (x, 1 | 2) = (0, 1) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:25:12 + --> tests/ui/unnested_or_patterns.rs:33:12 | LL | if let [0] | [1] = [0] {} | ^^^^^^^^^ @@ -109,7 +109,7 @@ LL + if let [0 | 1] = [0] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:26:12 + --> tests/ui/unnested_or_patterns.rs:35:12 | LL | if let [x, 0] | [x, 1] = [0, 1] {} | ^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + if let [x, 0 | 1] = [0, 1] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:27:12 + --> tests/ui/unnested_or_patterns.rs:37:12 | LL | if let [x, 0] | [x, 1] | [x, 2] = [0, 1] {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -133,7 +133,7 @@ LL + if let [x, 0 | 1 | 2] = [0, 1] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:28:12 + --> tests/ui/unnested_or_patterns.rs:39:12 | LL | if let [x, ..] | [x, 1] | [x, 2] = [0, 1] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + if let [x, ..] | [x, 1 | 2] = [0, 1] {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:30:12 + --> tests/ui/unnested_or_patterns.rs:42:12 | LL | if let TS(0, x) | TS(1, x) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^ @@ -157,7 +157,7 @@ LL + if let TS(0 | 1, x) = TS(0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:31:12 + --> tests/ui/unnested_or_patterns.rs:44:12 | LL | if let TS(1, 0) | TS(2, 0) | TS(3, 0) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +169,7 @@ LL + if let TS(1 | 2 | 3, 0) = TS(0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:32:12 + --> tests/ui/unnested_or_patterns.rs:46:12 | LL | if let TS(x, ..) | TS(x, 1) | TS(x, 2) = TS(0, 0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -181,7 +181,7 @@ LL + if let TS(x, ..) | TS(x, 1 | 2) = TS(0, 0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:37:12 + --> tests/ui/unnested_or_patterns.rs:52:12 | LL | if let S { x: 0, y } | S { y, x: 1 } = (S { x: 0, y: 1 }) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +193,7 @@ LL + if let S { x: 0 | 1, y } = (S { x: 0, y: 1 }) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns.rs:48:12 + --> tests/ui/unnested_or_patterns.rs:64:12 | LL | if let [1] | [53] = [0] {} | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed index b2a4e83dadc33..6d601ea5e57fe 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed @@ -10,11 +10,19 @@ fn main() { if let Some(Some(0 | 1)) = None {} + //~^ unnested_or_patterns if let Some(Some(0 | 1 | 2)) = None {} + //~^ unnested_or_patterns if let Some(Some(0 | 1 | 2 | 3 | 4)) = None {} + //~^ unnested_or_patterns if let Some(Some(0 | 1 | 2)) = None {} + //~^ unnested_or_patterns if let ((0 | 1 | 2,),) = ((0,),) {} + //~^ unnested_or_patterns if let 0 | 1 | 2 = 0 {} + //~^ unnested_or_patterns if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} + //~^ unnested_or_patterns if let box box (0 | 2 | 4) = Box::new(Box::new(0)) {} + //~^ unnested_or_patterns } diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.rs b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs index 58435f8990d22..7e5ea0161bffd 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.rs +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs @@ -10,11 +10,19 @@ fn main() { if let Some(Some(0)) | Some(Some(1)) = None {} + //~^ unnested_or_patterns if let Some(Some(0)) | Some(Some(1) | Some(2)) = None {} + //~^ unnested_or_patterns if let Some(Some(0 | 1) | Some(2)) | Some(Some(3) | Some(4)) = None {} + //~^ unnested_or_patterns if let Some(Some(0) | Some(1 | 2)) = None {} + //~^ unnested_or_patterns if let ((0,),) | ((1,) | (2,),) = ((0,),) {} + //~^ unnested_or_patterns if let 0 | (1 | 2) = 0 {} + //~^ unnested_or_patterns if let box (0 | 1) | (box 2 | box (3 | 4)) = Box::new(0) {} + //~^ unnested_or_patterns if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {} + //~^ unnested_or_patterns } diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr index 3d8968551b969..3fc8fa174c939 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.stderr @@ -13,7 +13,7 @@ LL + if let Some(Some(0 | 1)) = None {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns2.rs:13:12 + --> tests/ui/unnested_or_patterns2.rs:14:12 | LL | if let Some(Some(0)) | Some(Some(1) | Some(2)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + if let Some(Some(0 | 1 | 2)) = None {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns2.rs:14:12 + --> tests/ui/unnested_or_patterns2.rs:16:12 | LL | if let Some(Some(0 | 1) | Some(2)) | Some(Some(3) | Some(4)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + if let Some(Some(0 | 1 | 2 | 3 | 4)) = None {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns2.rs:15:12 + --> tests/ui/unnested_or_patterns2.rs:18:12 | LL | if let Some(Some(0) | Some(1 | 2)) = None {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + if let Some(Some(0 | 1 | 2)) = None {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns2.rs:16:12 + --> tests/ui/unnested_or_patterns2.rs:20:12 | LL | if let ((0,),) | ((1,) | (2,),) = ((0,),) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + if let ((0 | 1 | 2,),) = ((0,),) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns2.rs:17:12 + --> tests/ui/unnested_or_patterns2.rs:22:12 | LL | if let 0 | (1 | 2) = 0 {} | ^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + if let 0 | 1 | 2 = 0 {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns2.rs:18:12 + --> tests/ui/unnested_or_patterns2.rs:24:12 | LL | if let box (0 | 1) | (box 2 | box (3 | 4)) = Box::new(0) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + if let box (0 | 1 | 2 | 3 | 4) = Box::new(0) {} | error: unnested or-patterns - --> tests/ui/unnested_or_patterns2.rs:19:12 + --> tests/ui/unnested_or_patterns2.rs:26:12 | LL | if let box box 0 | box (box 2 | box 4) = Box::new(Box::new(0)) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unreadable_literal.fixed b/src/tools/clippy/tests/ui/unreadable_literal.fixed index fb9c2672db829..646481ab040b4 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.fixed +++ b/src/tools/clippy/tests/ui/unreadable_literal.fixed @@ -29,14 +29,24 @@ fn main() { 1.123_4_f32, ); let _bad = (0b11_0110_i64, 0x1234_5678_usize, 123_456_f32, 1.234_567_f32); + //~^ unreadable_literal + //~| unreadable_literal + //~| unreadable_literal + //~| unreadable_literal let _good_sci = 1.1234e1; let _bad_sci = 1.123_456e1; + //~^ unreadable_literal let _fail1 = 0x00ab_cdef; + //~^ unreadable_literal let _fail2: u32 = 0xBAFE_BAFE; + //~^ unreadable_literal let _fail3 = 0x0abc_deff; + //~^ unreadable_literal let _fail4: i128 = 0x00ab_cabc_abca_bcab_cabc; + //~^ unreadable_literal let _fail5 = 1.100_300_400; + //~^ unreadable_literal let _ = foo!(); let _ = bar!(); diff --git a/src/tools/clippy/tests/ui/unreadable_literal.rs b/src/tools/clippy/tests/ui/unreadable_literal.rs index 0a24fa8525467..973d1a8e196ae 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.rs +++ b/src/tools/clippy/tests/ui/unreadable_literal.rs @@ -29,14 +29,24 @@ fn main() { 1.123_4_f32, ); let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); + //~^ unreadable_literal + //~| unreadable_literal + //~| unreadable_literal + //~| unreadable_literal let _good_sci = 1.1234e1; let _bad_sci = 1.123456e1; + //~^ unreadable_literal let _fail1 = 0xabcdef; + //~^ unreadable_literal let _fail2: u32 = 0xBAFEBAFE; + //~^ unreadable_literal let _fail3 = 0xabcdeff; + //~^ unreadable_literal let _fail4: i128 = 0xabcabcabcabcabcabc; + //~^ unreadable_literal let _fail5 = 1.100300400; + //~^ unreadable_literal let _ = foo!(); let _ = bar!(); diff --git a/src/tools/clippy/tests/ui/unreadable_literal.stderr b/src/tools/clippy/tests/ui/unreadable_literal.stderr index 5e350d760643a..d019bf1b1febf 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.stderr +++ b/src/tools/clippy/tests/ui/unreadable_literal.stderr @@ -26,37 +26,37 @@ LL | let _bad = (0b110110_i64, 0x12345678_usize, 123456_f32, 1.234567_f32); | ^^^^^^^^^^^^ help: consider: `1.234_567_f32` error: long literal lacking separators - --> tests/ui/unreadable_literal.rs:33:20 + --> tests/ui/unreadable_literal.rs:37:20 | LL | let _bad_sci = 1.123456e1; | ^^^^^^^^^^ help: consider: `1.123_456e1` error: long literal lacking separators - --> tests/ui/unreadable_literal.rs:35:18 + --> tests/ui/unreadable_literal.rs:40:18 | LL | let _fail1 = 0xabcdef; | ^^^^^^^^ help: consider: `0x00ab_cdef` error: long literal lacking separators - --> tests/ui/unreadable_literal.rs:36:23 + --> tests/ui/unreadable_literal.rs:42:23 | LL | let _fail2: u32 = 0xBAFEBAFE; | ^^^^^^^^^^ help: consider: `0xBAFE_BAFE` error: long literal lacking separators - --> tests/ui/unreadable_literal.rs:37:18 + --> tests/ui/unreadable_literal.rs:44:18 | LL | let _fail3 = 0xabcdeff; | ^^^^^^^^^ help: consider: `0x0abc_deff` error: long literal lacking separators - --> tests/ui/unreadable_literal.rs:38:24 + --> tests/ui/unreadable_literal.rs:46:24 | LL | let _fail4: i128 = 0xabcabcabcabcabcabc; | ^^^^^^^^^^^^^^^^^^^^ help: consider: `0x00ab_cabc_abca_bcab_cabc` error: long literal lacking separators - --> tests/ui/unreadable_literal.rs:39:18 + --> tests/ui/unreadable_literal.rs:48:18 | LL | let _fail5 = 1.100300400; | ^^^^^^^^^^^ help: consider: `1.100_300_400` diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs index e9e6c8312f5eb..2e1d8b60a0e2f 100644 --- a/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs +++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.rs @@ -3,11 +3,10 @@ #![warn(clippy::unsafe_removed_from_name)] use std::cell::UnsafeCell as TotallySafeCell; -//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCell` -//~| NOTE: `-D clippy::unsafe-removed-from-name` implied by `-D warnings` +//~^ unsafe_removed_from_name use std::cell::UnsafeCell as TotallySafeCellAgain; -//~^ ERROR: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain` +//~^ unsafe_removed_from_name // Shouldn't error use std::cell::RefCell as ProbablyNotUnsafe; @@ -26,12 +25,12 @@ mod mod_with_some_unsafe_things { } use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; -//~^ ERROR: removed `unsafe` from the name of `Unsafe` in use as `LieAboutModSafety` +//~^ unsafe_removed_from_name // merged imports use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B}; -//~^ ERROR: removed `unsafe` from the name of `Unsafe` in use as `A` -//~| ERROR: removed `unsafe` from the name of `Unsafe` in use as `B` +//~^ unsafe_removed_from_name +//~| unsafe_removed_from_name // Shouldn't error use mod_with_some_unsafe_things::Safe as IPromiseItsSafeThisTime; diff --git a/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr index 998cdbb579f65..5268c16ec9ba5 100644 --- a/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr +++ b/src/tools/clippy/tests/ui/unsafe_removed_from_name.stderr @@ -8,25 +8,25 @@ LL | use std::cell::UnsafeCell as TotallySafeCell; = help: to override `-D warnings` add `#[allow(clippy::unsafe_removed_from_name)]` error: removed `unsafe` from the name of `UnsafeCell` in use as `TotallySafeCellAgain` - --> tests/ui/unsafe_removed_from_name.rs:9:1 + --> tests/ui/unsafe_removed_from_name.rs:8:1 | LL | use std::cell::UnsafeCell as TotallySafeCellAgain; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: removed `unsafe` from the name of `Unsafe` in use as `LieAboutModSafety` - --> tests/ui/unsafe_removed_from_name.rs:28:1 + --> tests/ui/unsafe_removed_from_name.rs:27:1 | LL | use mod_with_some_unsafe_things::Unsafe as LieAboutModSafety; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: removed `unsafe` from the name of `Unsafe` in use as `A` - --> tests/ui/unsafe_removed_from_name.rs:32:1 + --> tests/ui/unsafe_removed_from_name.rs:31:1 | LL | use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: removed `unsafe` from the name of `Unsafe` in use as `B` - --> tests/ui/unsafe_removed_from_name.rs:32:1 + --> tests/ui/unsafe_removed_from_name.rs:31:1 | LL | use mod_with_some_unsafe_things::{Unsafe as A, Unsafe as B}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed index 93f7f747b7cd5..e13dd561d627a 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed @@ -13,6 +13,7 @@ struct Foo; macro_rules! lit_from_macro { () => { 42_usize + //~^ unseparated_literal_suffix }; } @@ -21,15 +22,22 @@ fn main() { let _ok2 = 1234_isize; let _ok3 = 0x123_isize; let _fail1 = 1234_i32; + //~^ unseparated_literal_suffix let _fail2 = 1234_u32; + //~^ unseparated_literal_suffix let _fail3 = 1234_isize; + //~^ unseparated_literal_suffix let _fail4 = 1234_usize; + //~^ unseparated_literal_suffix let _fail5 = 0x123_isize; + //~^ unseparated_literal_suffix let _okf1 = 1.5_f32; let _okf2 = 1_f32; let _failf1 = 1.5_f32; + //~^ unseparated_literal_suffix let _failf2 = 1_f32; + //~^ unseparated_literal_suffix // Test for macro let _ = lit_from_macro!(); @@ -38,4 +46,5 @@ fn main() { let _ = line!(); // Because `assert!` contains `line!()` macro. assert_eq!(4897_u32, 32223); + //~^ unseparated_literal_suffix } diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs index c960ff6b5dcce..6f7b16ccba54c 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs @@ -13,6 +13,7 @@ struct Foo; macro_rules! lit_from_macro { () => { 42usize + //~^ unseparated_literal_suffix }; } @@ -21,15 +22,22 @@ fn main() { let _ok2 = 1234_isize; let _ok3 = 0x123_isize; let _fail1 = 1234i32; + //~^ unseparated_literal_suffix let _fail2 = 1234u32; + //~^ unseparated_literal_suffix let _fail3 = 1234isize; + //~^ unseparated_literal_suffix let _fail4 = 1234usize; + //~^ unseparated_literal_suffix let _fail5 = 0x123isize; + //~^ unseparated_literal_suffix let _okf1 = 1.5_f32; let _okf2 = 1_f32; let _failf1 = 1.5f32; + //~^ unseparated_literal_suffix let _failf2 = 1f32; + //~^ unseparated_literal_suffix // Test for macro let _ = lit_from_macro!(); @@ -38,4 +46,5 @@ fn main() { let _ = line!(); // Because `assert!` contains `line!()` macro. assert_eq!(4897u32, 32223); + //~^ unseparated_literal_suffix } diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr index 1c51f7ada91f1..4cfbf5e4b74ea 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr @@ -1,5 +1,5 @@ error: integer type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:23:18 + --> tests/ui/unseparated_prefix_literals.rs:24:18 | LL | let _fail1 = 1234i32; | ^^^^^^^ help: add an underscore: `1234_i32` @@ -8,37 +8,37 @@ LL | let _fail1 = 1234i32; = help: to override `-D warnings` add `#[allow(clippy::unseparated_literal_suffix)]` error: integer type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:24:18 + --> tests/ui/unseparated_prefix_literals.rs:26:18 | LL | let _fail2 = 1234u32; | ^^^^^^^ help: add an underscore: `1234_u32` error: integer type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:25:18 + --> tests/ui/unseparated_prefix_literals.rs:28:18 | LL | let _fail3 = 1234isize; | ^^^^^^^^^ help: add an underscore: `1234_isize` error: integer type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:26:18 + --> tests/ui/unseparated_prefix_literals.rs:30:18 | LL | let _fail4 = 1234usize; | ^^^^^^^^^ help: add an underscore: `1234_usize` error: integer type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:27:18 + --> tests/ui/unseparated_prefix_literals.rs:32:18 | LL | let _fail5 = 0x123isize; | ^^^^^^^^^^ help: add an underscore: `0x123_isize` error: float type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:31:19 + --> tests/ui/unseparated_prefix_literals.rs:37:19 | LL | let _failf1 = 1.5f32; | ^^^^^^ help: add an underscore: `1.5_f32` error: float type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:32:19 + --> tests/ui/unseparated_prefix_literals.rs:39:19 | LL | let _failf2 = 1f32; | ^^^^ help: add an underscore: `1_f32` @@ -55,7 +55,7 @@ LL | let _ = lit_from_macro!(); = note: this error originates in the macro `lit_from_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: integer type suffix should be separated by an underscore - --> tests/ui/unseparated_prefix_literals.rs:40:16 + --> tests/ui/unseparated_prefix_literals.rs:48:16 | LL | assert_eq!(4897u32, 32223); | ^^^^^^^ help: add an underscore: `4897_u32` diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs index 838d6f0aa9711..5aaf7b9f5b598 100644 --- a/src/tools/clippy/tests/ui/unused_async.rs +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -10,7 +10,8 @@ mod issue10800 { use std::future::ready; async fn async_block_await() { - //~^ ERROR: unused `async` for function with no await statements + //~^ unused_async + async { ready(()).await; }; @@ -43,7 +44,7 @@ mod issue9695 { async fn f() {} async fn f2() {} async fn f3() {} - //~^ ERROR: unused `async` for function with no await statements + //~^ unused_async fn needs_async_fn>(_: fn() -> F) {} @@ -72,7 +73,8 @@ mod issue13466 { } async fn foo() -> i32 { - //~^ ERROR: unused `async` for function with no await statements + //~^ unused_async + 4 } @@ -84,7 +86,8 @@ struct S; impl S { async fn unused(&self) -> i32 { - //~^ ERROR: unused `async` for function with no await statements + //~^ unused_async + 1 } diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr index 4811df63658a9..f95fdd8653001 100644 --- a/src/tools/clippy/tests/ui/unused_async.stderr +++ b/src/tools/clippy/tests/ui/unused_async.stderr @@ -3,6 +3,7 @@ error: unused `async` for function with no await statements | LL | / async fn async_block_await() { LL | | +LL | | LL | | async { LL | | ready(()).await; LL | | }; @@ -11,7 +12,7 @@ LL | | } | = help: consider removing the `async` from this function note: `await` used in an async block, which does not require the enclosing function to be `async` - --> tests/ui/unused_async.rs:15:23 + --> tests/ui/unused_async.rs:16:23 | LL | ready(()).await; | ^^^^^ @@ -19,7 +20,7 @@ LL | ready(()).await; = help: to override `-D warnings` add `#[allow(clippy::unused_async)]` error: unused `async` for function with no await statements - --> tests/ui/unused_async.rs:45:5 + --> tests/ui/unused_async.rs:46:5 | LL | async fn f3() {} | ^^^^^^^^^^^^^^^^ @@ -27,10 +28,11 @@ LL | async fn f3() {} = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> tests/ui/unused_async.rs:74:1 + --> tests/ui/unused_async.rs:75:1 | LL | / async fn foo() -> i32 { LL | | +LL | | LL | | 4 LL | | } | |_^ @@ -38,10 +40,11 @@ LL | | } = help: consider removing the `async` from this function error: unused `async` for function with no await statements - --> tests/ui/unused_async.rs:86:5 + --> tests/ui/unused_async.rs:88:5 | LL | / async fn unused(&self) -> i32 { LL | | +LL | | LL | | 1 LL | | } | |_____^ diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.fixed b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed index cffd02b0acc8c..258e52971ceab 100644 --- a/src/tools/clippy/tests/ui/unused_enumerate_index.fixed +++ b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed @@ -10,6 +10,7 @@ fn get_enumerate() -> Enumerate> { fn main() { let v = [1, 2, 3]; for x in v.iter() { + //~^ unused_enumerate_index println!("{x}"); } @@ -57,12 +58,15 @@ fn main() { let dummy = Dummy3(vec![1, 2, 3].into_iter()); for x in dummy { + //~^ unused_enumerate_index println!("{x}"); } let _ = vec![1, 2, 3].into_iter().map(|x| println!("{x}")); + //~^ unused_enumerate_index let p = vec![1, 2, 3].into_iter(); + //~^ unused_enumerate_index p.map(|x| println!("{x}")); // This shouldn't trigger the lint. `get_enumerate` may come from an external library on which we @@ -84,6 +88,7 @@ fn main() { }; } _ = mac2!().map(|_v| {}); + //~^ unused_enumerate_index // This shouldn't trigger the lint because of the `allow`. #[allow(clippy::unused_enumerate_index)] @@ -92,15 +97,18 @@ fn main() { // This should keep the explicit type of `x`. let v = [1, 2, 3].iter().copied(); + //~^ unused_enumerate_index let x = v.map(|x: i32| x).sum::(); assert_eq!(x, 6); // This should keep the explicit type of `x`. let v = [1, 2, 3].iter().copied(); + //~^ unused_enumerate_index let x = v.map(|x: i32| x).sum::(); assert_eq!(x, 6); let v = [1, 2, 3].iter().copied(); + //~^ unused_enumerate_index let x = v.map(|x| x).sum::(); assert_eq!(x, 6); } diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.rs b/src/tools/clippy/tests/ui/unused_enumerate_index.rs index f2b5f8b912476..a17e3259a9b07 100644 --- a/src/tools/clippy/tests/ui/unused_enumerate_index.rs +++ b/src/tools/clippy/tests/ui/unused_enumerate_index.rs @@ -10,6 +10,7 @@ fn get_enumerate() -> Enumerate> { fn main() { let v = [1, 2, 3]; for (_, x) in v.iter().enumerate() { + //~^ unused_enumerate_index println!("{x}"); } @@ -57,12 +58,15 @@ fn main() { let dummy = Dummy3(vec![1, 2, 3].into_iter()); for (_, x) in dummy.enumerate() { + //~^ unused_enumerate_index println!("{x}"); } let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}")); + //~^ unused_enumerate_index let p = vec![1, 2, 3].into_iter().enumerate(); + //~^ unused_enumerate_index p.map(|(_, x)| println!("{x}")); // This shouldn't trigger the lint. `get_enumerate` may come from an external library on which we @@ -84,6 +88,7 @@ fn main() { }; } _ = mac2!().enumerate().map(|(_, _v)| {}); + //~^ unused_enumerate_index // This shouldn't trigger the lint because of the `allow`. #[allow(clippy::unused_enumerate_index)] @@ -92,15 +97,18 @@ fn main() { // This should keep the explicit type of `x`. let v = [1, 2, 3].iter().copied().enumerate(); + //~^ unused_enumerate_index let x = v.map(|(_, x): (usize, i32)| x).sum::(); assert_eq!(x, 6); // This should keep the explicit type of `x`. let v = [1, 2, 3].iter().copied().enumerate(); + //~^ unused_enumerate_index let x = v.map(|(_, x): (_, i32)| x).sum::(); assert_eq!(x, 6); let v = [1, 2, 3].iter().copied().enumerate(); + //~^ unused_enumerate_index let x = v.map(|(_, x)| x).sum::(); assert_eq!(x, 6); } diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.stderr b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr index 02d65f064308b..14d1d20a66e4b 100644 --- a/src/tools/clippy/tests/ui/unused_enumerate_index.stderr +++ b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr @@ -13,7 +13,7 @@ LL + for x in v.iter() { | error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:59:19 + --> tests/ui/unused_enumerate_index.rs:60:19 | LL | for (_, x) in dummy.enumerate() { | ^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + for x in dummy { | error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:63:39 + --> tests/ui/unused_enumerate_index.rs:65:39 | LL | let _ = vec![1, 2, 3].into_iter().enumerate().map(|(_, x)| println!("{x}")); | ^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let _ = vec![1, 2, 3].into_iter().map(|x| println!("{x}")); | error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:65:39 + --> tests/ui/unused_enumerate_index.rs:68:39 | LL | let p = vec![1, 2, 3].into_iter().enumerate(); | ^^^^^^^^^^^ @@ -45,11 +45,12 @@ LL | let p = vec![1, 2, 3].into_iter().enumerate(); help: remove the `.enumerate()` call | LL ~ let p = vec![1, 2, 3].into_iter(); +LL | LL ~ p.map(|x| println!("{x}")); | error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:86:17 + --> tests/ui/unused_enumerate_index.rs:90:17 | LL | _ = mac2!().enumerate().map(|(_, _v)| {}); | ^^^^^^^^^^^ @@ -61,7 +62,7 @@ LL + _ = mac2!().map(|_v| {}); | error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:94:39 + --> tests/ui/unused_enumerate_index.rs:99:39 | LL | let v = [1, 2, 3].iter().copied().enumerate(); | ^^^^^^^^^^^ @@ -69,11 +70,12 @@ LL | let v = [1, 2, 3].iter().copied().enumerate(); help: remove the `.enumerate()` call | LL ~ let v = [1, 2, 3].iter().copied(); +LL | LL ~ let x = v.map(|x: i32| x).sum::(); | error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:99:39 + --> tests/ui/unused_enumerate_index.rs:105:39 | LL | let v = [1, 2, 3].iter().copied().enumerate(); | ^^^^^^^^^^^ @@ -81,11 +83,12 @@ LL | let v = [1, 2, 3].iter().copied().enumerate(); help: remove the `.enumerate()` call | LL ~ let v = [1, 2, 3].iter().copied(); +LL | LL ~ let x = v.map(|x: i32| x).sum::(); | error: you seem to use `.enumerate()` and immediately discard the index - --> tests/ui/unused_enumerate_index.rs:103:39 + --> tests/ui/unused_enumerate_index.rs:110:39 | LL | let v = [1, 2, 3].iter().copied().enumerate(); | ^^^^^^^^^^^ @@ -93,6 +96,7 @@ LL | let v = [1, 2, 3].iter().copied().enumerate(); help: remove the `.enumerate()` call | LL ~ let v = [1, 2, 3].iter().copied(); +LL | LL ~ let x = v.map(|x| x).sum::(); | diff --git a/src/tools/clippy/tests/ui/unused_format_specs.1.fixed b/src/tools/clippy/tests/ui/unused_format_specs.1.fixed index 157c2b08d3cfa..05bd1df9a5236 100644 --- a/src/tools/clippy/tests/ui/unused_format_specs.1.fixed +++ b/src/tools/clippy/tests/ui/unused_format_specs.1.fixed @@ -10,18 +10,18 @@ macro_rules! format_args_from_macro { fn main() { // prints `.`, not ` .` println!("{:5}.", format!("")); - //~^ ERROR: format specifiers have no effect on `format_args!()` - //~| NOTE: `-D clippy::unused-format-specs` implied by `-D warnings` + //~^ unused_format_specs + //prints `abcde`, not `abc` println!("{:.3}", format!("abcde")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs println!("{}.", format_args_from_macro!()); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs let args = format_args!(""); println!("{args}"); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs } fn should_not_lint() { @@ -46,17 +46,18 @@ macro_rules! usr_println { fn should_lint_user() { // prints `.`, not ` .` usr_println!(true, "{:5}.", format!("")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs + //prints `abcde`, not `abc` usr_println!(true, "{:.3}", format!("abcde")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs usr_println!(true, "{}.", format_args_from_macro!()); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs let args = format_args!(""); usr_println!(true, "{args}"); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs } fn should_not_lint_user() { diff --git a/src/tools/clippy/tests/ui/unused_format_specs.2.fixed b/src/tools/clippy/tests/ui/unused_format_specs.2.fixed index 92c7b951f3caf..c1f3d4fa20c6f 100644 --- a/src/tools/clippy/tests/ui/unused_format_specs.2.fixed +++ b/src/tools/clippy/tests/ui/unused_format_specs.2.fixed @@ -10,18 +10,18 @@ macro_rules! format_args_from_macro { fn main() { // prints `.`, not ` .` println!("{}.", format_args!("")); - //~^ ERROR: format specifiers have no effect on `format_args!()` - //~| NOTE: `-D clippy::unused-format-specs` implied by `-D warnings` + //~^ unused_format_specs + //prints `abcde`, not `abc` println!("{}", format_args!("abcde")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs println!("{}.", format_args_from_macro!()); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs let args = format_args!(""); println!("{args}"); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs } fn should_not_lint() { @@ -46,17 +46,18 @@ macro_rules! usr_println { fn should_lint_user() { // prints `.`, not ` .` usr_println!(true, "{}.", format_args!("")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs + //prints `abcde`, not `abc` usr_println!(true, "{}", format_args!("abcde")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs usr_println!(true, "{}.", format_args_from_macro!()); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs let args = format_args!(""); usr_println!(true, "{args}"); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs } fn should_not_lint_user() { diff --git a/src/tools/clippy/tests/ui/unused_format_specs.rs b/src/tools/clippy/tests/ui/unused_format_specs.rs index a5df4d8a86683..b47047ba34e5f 100644 --- a/src/tools/clippy/tests/ui/unused_format_specs.rs +++ b/src/tools/clippy/tests/ui/unused_format_specs.rs @@ -10,18 +10,18 @@ macro_rules! format_args_from_macro { fn main() { // prints `.`, not ` .` println!("{:5}.", format_args!("")); - //~^ ERROR: format specifiers have no effect on `format_args!()` - //~| NOTE: `-D clippy::unused-format-specs` implied by `-D warnings` + //~^ unused_format_specs + //prints `abcde`, not `abc` println!("{:.3}", format_args!("abcde")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs println!("{:5}.", format_args_from_macro!()); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs let args = format_args!(""); println!("{args:5}"); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs } fn should_not_lint() { @@ -46,17 +46,18 @@ macro_rules! usr_println { fn should_lint_user() { // prints `.`, not ` .` usr_println!(true, "{:5}.", format_args!("")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs + //prints `abcde`, not `abc` usr_println!(true, "{:.3}", format_args!("abcde")); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs usr_println!(true, "{:5}.", format_args_from_macro!()); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs let args = format_args!(""); usr_println!(true, "{args:5}"); - //~^ ERROR: format specifiers have no effect on `format_args!()` + //~^ unused_format_specs } fn should_not_lint_user() { diff --git a/src/tools/clippy/tests/ui/unused_format_specs.stderr b/src/tools/clippy/tests/ui/unused_format_specs.stderr index d3c0530ced46d..b07058fd568da 100644 --- a/src/tools/clippy/tests/ui/unused_format_specs.stderr +++ b/src/tools/clippy/tests/ui/unused_format_specs.stderr @@ -78,7 +78,7 @@ LL + usr_println!(true, "{}.", format_args!("")); | error: format specifiers have no effect on `format_args!()` - --> tests/ui/unused_format_specs.rs:51:25 + --> tests/ui/unused_format_specs.rs:52:25 | LL | usr_println!(true, "{:.3}", format_args!("abcde")); | ^^^^^ @@ -95,7 +95,7 @@ LL + usr_println!(true, "{}", format_args!("abcde")); | error: format specifiers have no effect on `format_args!()` - --> tests/ui/unused_format_specs.rs:54:25 + --> tests/ui/unused_format_specs.rs:55:25 | LL | usr_println!(true, "{:5}.", format_args_from_macro!()); | ^^^^ @@ -108,7 +108,7 @@ LL + usr_println!(true, "{}.", format_args_from_macro!()); | error: format specifiers have no effect on `format_args!()` - --> tests/ui/unused_format_specs.rs:58:25 + --> tests/ui/unused_format_specs.rs:59:25 | LL | usr_println!(true, "{args:5}"); | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs index 175c4ca76895c..32a50375806a3 100644 --- a/src/tools/clippy/tests/ui/unused_io_amount.rs +++ b/src/tools/clippy/tests/ui/unused_io_amount.rs @@ -8,26 +8,26 @@ use std::io::{self, Read}; fn question_mark(s: &mut T) -> io::Result<()> { s.write(b"test")?; - //~^ ERROR: written amount is not handled + //~^ unused_io_amount let mut buf = [0u8; 4]; s.read(&mut buf)?; - //~^ ERROR: read amount is not handled + //~^ unused_io_amount Ok(()) } fn unwrap(s: &mut T) { s.write(b"test").unwrap(); - //~^ ERROR: written amount is not handled + //~^ unused_io_amount let mut buf = [0u8; 4]; s.read(&mut buf).unwrap(); - //~^ ERROR: read amount is not handled + //~^ unused_io_amount } fn vectored(s: &mut T) -> io::Result<()> { s.read_vectored(&mut [io::IoSliceMut::new(&mut [])])?; - //~^ ERROR: read amount is not handled + //~^ unused_io_amount s.write_vectored(&[io::IoSlice::new(&[])])?; - //~^ ERROR: written amount is not handled + //~^ unused_io_amount Ok(()) } @@ -35,7 +35,7 @@ fn ok(file: &str) -> Option<()> { let mut reader = std::fs::File::open(file).ok()?; let mut result = [0u8; 0]; reader.read(&mut result).ok()?; - //~^ ERROR: read amount is not handled + //~^ unused_io_amount Some(()) } @@ -45,7 +45,7 @@ fn or_else(file: &str) -> io::Result<()> { let mut reader = std::fs::File::open(file)?; let mut result = [0u8; 0]; reader.read(&mut result).or_else(|err| Err(err))?; - //~^ ERROR: read amount is not handled + //~^ unused_io_amount Ok(()) } @@ -58,7 +58,7 @@ fn or(file: &str) -> Result<(), Error> { let mut reader = std::fs::File::open(file).unwrap(); let mut result = [0u8; 0]; reader.read(&mut result).or(Err(Error::Kind))?; - //~^ ERROR: read amount is not handled + //~^ unused_io_amount Ok(()) } @@ -66,7 +66,7 @@ fn combine_or(file: &str) -> Result<(), Error> { let mut reader = std::fs::File::open(file).unwrap(); let mut result = [0u8; 0]; reader - //~^ ERROR: read amount is not handled + //~^ unused_io_amount .read(&mut result) .or(Err(Error::Kind)) .or(Err(Error::Kind)) @@ -76,25 +76,25 @@ fn combine_or(file: &str) -> Result<(), Error> { fn is_ok_err(s: &mut T) { s.write(b"ok").is_ok(); - //~^ ERROR: written amount is not handled + //~^ unused_io_amount s.write(b"err").is_err(); - //~^ ERROR: written amount is not handled + //~^ unused_io_amount let mut buf = [0u8; 0]; s.read(&mut buf).is_ok(); - //~^ ERROR: read amount is not handled + //~^ unused_io_amount s.read(&mut buf).is_err(); - //~^ ERROR: read amount is not handled + //~^ unused_io_amount } async fn bad_async_write(w: &mut W) { w.write(b"hello world").await.unwrap(); - //~^ ERROR: written amount is not handled + //~^ unused_io_amount } async fn bad_async_read(r: &mut R) { let mut buf = [0u8; 0]; r.read(&mut buf[..]).await.unwrap(); - //~^ ERROR: read amount is not handled + //~^ unused_io_amount } async fn io_not_ignored_async_write(mut w: W) { @@ -102,13 +102,14 @@ async fn io_not_ignored_async_write(mut w: W) { // warning about _that_ (or we would, if it were enabled), but we // won't get one about ignoring the return value. w.write(b"hello world"); + //~^ unused_io_amount } fn bad_async_write_closure(w: W) -> impl futures::Future> { let mut w = w; async move { w.write(b"hello world").await?; - //~^ ERROR: written amount is not handled + //~^ unused_io_amount Ok(()) } } @@ -117,7 +118,7 @@ async fn async_read_nested_or(r: &mut R, do_it: bool) -> R let mut buf = [0u8; 1]; if do_it { r.read(&mut buf[..]).await.or(Err(Error::Kind))?; - //~^ ERROR: read amount is not handled + //~^ unused_io_amount } Ok(buf) } @@ -126,13 +127,13 @@ use tokio::io::{AsyncRead as TokioAsyncRead, AsyncReadExt as _, AsyncWrite as To async fn bad_async_write_tokio(w: &mut W) { w.write(b"hello world").await.unwrap(); - //~^ ERROR: written amount is not handled + //~^ unused_io_amount } async fn bad_async_read_tokio(r: &mut R) { let mut buf = [0u8; 0]; r.read(&mut buf[..]).await.unwrap(); - //~^ ERROR: read amount is not handled + //~^ unused_io_amount } async fn undetected_bad_async_write(w: &mut W) { @@ -145,35 +146,31 @@ async fn undetected_bad_async_write(w: &mut W) { fn match_okay_underscore(s: &mut T) { match s.write(b"test") { - //~^ ERROR: written amount is not handled + //~^ unused_io_amount Ok(_) => todo!(), - //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled Err(_) => todo!(), }; let mut buf = [0u8; 4]; match s.read(&mut buf) { - //~^ ERROR: read amount is not handled + //~^ unused_io_amount Ok(_) => todo!(), - //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled Err(_) => todo!(), } } fn match_okay_underscore_read_expr(s: &mut T) { match s.read(&mut [0u8; 4]) { - //~^ ERROR: read amount is not handled + //~^ unused_io_amount Ok(_) => todo!(), - //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled Err(_) => todo!(), } } fn match_okay_underscore_write_expr(s: &mut T) { match s.write(b"test") { - //~^ ERROR: written amount is not handled + //~^ unused_io_amount Ok(_) => todo!(), - //~^ NOTE: the result is consumed here, but the amount of I/O bytes remains unhandled Err(_) => todo!(), } } @@ -184,21 +181,21 @@ fn returned_value_should_not_lint(s: &mut T) -> Result< fn if_okay_underscore_read_expr(s: &mut T) { if let Ok(_) = s.read(&mut [0u8; 4]) { - //~^ ERROR: read amount is not handled + //~^ unused_io_amount todo!() } } fn if_okay_underscore_write_expr(s: &mut T) { if let Ok(_) = s.write(b"test") { - //~^ ERROR: written amount is not handled + //~^ unused_io_amount todo!() } } fn if_okay_dots_write_expr(s: &mut T) { if let Ok(..) = s.write(b"test") { - //~^ ERROR: written amount is not handled + //~^ unused_io_amount todo!() } } diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr index 771e463ca010a..71bb4c40de840 100644 --- a/src/tools/clippy/tests/ui/unused_io_amount.stderr +++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr @@ -138,7 +138,7 @@ LL | w.write(b"hello world"); = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: written amount is not handled - --> tests/ui/unused_io_amount.rs:110:9 + --> tests/ui/unused_io_amount.rs:111:9 | LL | w.write(b"hello world").await?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -146,7 +146,7 @@ LL | w.write(b"hello world").await?; = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> tests/ui/unused_io_amount.rs:119:9 + --> tests/ui/unused_io_amount.rs:120:9 | LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +154,7 @@ LL | r.read(&mut buf[..]).await.or(Err(Error::Kind))?; = help: use `AsyncReadExt::read_exact` instead, or handle partial reads error: written amount is not handled - --> tests/ui/unused_io_amount.rs:128:5 + --> tests/ui/unused_io_amount.rs:129:5 | LL | w.write(b"hello world").await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | w.write(b"hello world").await.unwrap(); = help: use `AsyncWriteExt::write_all` instead, or handle partial writes error: read amount is not handled - --> tests/ui/unused_io_amount.rs:134:5 + --> tests/ui/unused_io_amount.rs:135:5 | LL | r.read(&mut buf[..]).await.unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -170,14 +170,14 @@ LL | r.read(&mut buf[..]).await.unwrap(); = help: use `AsyncReadExt::read_exact` instead, or handle partial reads error: written amount is not handled - --> tests/ui/unused_io_amount.rs:147:11 + --> tests/ui/unused_io_amount.rs:148:11 | LL | match s.write(b"test") { | ^^^^^^^^^^^^^^^^ | = help: use `Write::write_all` instead, or handle partial writes note: the result is consumed here, but the amount of I/O bytes remains unhandled - --> tests/ui/unused_io_amount.rs:149:9 + --> tests/ui/unused_io_amount.rs:150:9 | LL | Ok(_) => todo!(), | ^^^^^ @@ -196,66 +196,66 @@ LL | Ok(_) => todo!(), | ^^^^^ error: read amount is not handled - --> tests/ui/unused_io_amount.rs:164:11 + --> tests/ui/unused_io_amount.rs:163:11 | LL | match s.read(&mut [0u8; 4]) { | ^^^^^^^^^^^^^^^^^^^^^ | = help: use `Read::read_exact` instead, or handle partial reads note: the result is consumed here, but the amount of I/O bytes remains unhandled - --> tests/ui/unused_io_amount.rs:166:9 + --> tests/ui/unused_io_amount.rs:165:9 | LL | Ok(_) => todo!(), | ^^^^^ error: written amount is not handled - --> tests/ui/unused_io_amount.rs:173:11 + --> tests/ui/unused_io_amount.rs:171:11 | LL | match s.write(b"test") { | ^^^^^^^^^^^^^^^^ | = help: use `Write::write_all` instead, or handle partial writes note: the result is consumed here, but the amount of I/O bytes remains unhandled - --> tests/ui/unused_io_amount.rs:175:9 + --> tests/ui/unused_io_amount.rs:173:9 | LL | Ok(_) => todo!(), | ^^^^^ error: read amount is not handled - --> tests/ui/unused_io_amount.rs:186:8 + --> tests/ui/unused_io_amount.rs:183:8 | LL | if let Ok(_) = s.read(&mut [0u8; 4]) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `Read::read_exact` instead, or handle partial reads note: the result is consumed here, but the amount of I/O bytes remains unhandled - --> tests/ui/unused_io_amount.rs:186:12 + --> tests/ui/unused_io_amount.rs:183:12 | LL | if let Ok(_) = s.read(&mut [0u8; 4]) { | ^^^^^ error: written amount is not handled - --> tests/ui/unused_io_amount.rs:193:8 + --> tests/ui/unused_io_amount.rs:190:8 | LL | if let Ok(_) = s.write(b"test") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `Write::write_all` instead, or handle partial writes note: the result is consumed here, but the amount of I/O bytes remains unhandled - --> tests/ui/unused_io_amount.rs:193:12 + --> tests/ui/unused_io_amount.rs:190:12 | LL | if let Ok(_) = s.write(b"test") { | ^^^^^ error: written amount is not handled - --> tests/ui/unused_io_amount.rs:200:8 + --> tests/ui/unused_io_amount.rs:197:8 | LL | if let Ok(..) = s.write(b"test") { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: use `Write::write_all` instead, or handle partial writes note: the result is consumed here, but the amount of I/O bytes remains unhandled - --> tests/ui/unused_io_amount.rs:200:12 + --> tests/ui/unused_io_amount.rs:197:12 | LL | if let Ok(..) = s.write(b"test") { | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/unused_peekable.rs b/src/tools/clippy/tests/ui/unused_peekable.rs index 5865bba43508b..e7fe297764eb3 100644 --- a/src/tools/clippy/tests/ui/unused_peekable.rs +++ b/src/tools/clippy/tests/ui/unused_peekable.rs @@ -11,17 +11,17 @@ fn main() { #[allow(clippy::unused_unit)] fn invalid() { let peekable = std::iter::empty::().peekable(); - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable // Only lint `new_local` let old_local = std::iter::empty::().peekable(); let new_local = old_local; - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable // Behind mut ref let mut by_mut_ref_test = std::iter::empty::().peekable(); let by_mut_ref = &mut by_mut_ref_test; - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable // Explicitly returns `Peekable` fn returns_peekable() -> Peekable> { @@ -29,26 +29,29 @@ fn invalid() { } let peekable_from_fn = returns_peekable(); - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable // Using a method not exclusive to `Peekable` let mut peekable_using_iterator_method = std::iter::empty::().peekable(); - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable + peekable_using_iterator_method.next(); // Passed by ref to another function fn takes_ref(_peek: &Peekable>) {} let passed_along_ref = std::iter::empty::().peekable(); - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable + takes_ref(&passed_along_ref); // `by_ref` without `peek` let mut by_ref_test = std::iter::empty::().peekable(); let _by_ref = by_ref_test.by_ref(); - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable let mut peekable_in_for_loop = std::iter::empty::().peekable(); - //~^ ERROR: `peek` never called on `Peekable` iterator + //~^ unused_peekable + for x in peekable_in_for_loop {} } diff --git a/src/tools/clippy/tests/ui/unused_peekable.stderr b/src/tools/clippy/tests/ui/unused_peekable.stderr index 00c6a52bab336..9330d8c58001d 100644 --- a/src/tools/clippy/tests/ui/unused_peekable.stderr +++ b/src/tools/clippy/tests/ui/unused_peekable.stderr @@ -41,7 +41,7 @@ LL | let mut peekable_using_iterator_method = std::iter::empty::().peek = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:41:9 + --> tests/ui/unused_peekable.rs:42:9 | LL | let passed_along_ref = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | let passed_along_ref = std::iter::empty::().peekable(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:47:9 + --> tests/ui/unused_peekable.rs:49:9 | LL | let _by_ref = by_ref_test.by_ref(); | ^^^^^^^ @@ -57,7 +57,7 @@ LL | let _by_ref = by_ref_test.by_ref(); = help: consider removing the call to `peekable` error: `peek` never called on `Peekable` iterator - --> tests/ui/unused_peekable.rs:50:13 + --> tests/ui/unused_peekable.rs:52:13 | LL | let mut peekable_in_for_loop = std::iter::empty::().peekable(); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unused_result_ok.fixed b/src/tools/clippy/tests/ui/unused_result_ok.fixed index e78fde5c9e3cc..faedd96216c2e 100644 --- a/src/tools/clippy/tests/ui/unused_result_ok.fixed +++ b/src/tools/clippy/tests/ui/unused_result_ok.fixed @@ -7,6 +7,7 @@ extern crate proc_macros; fn bad_style(x: &str) { let _ = x.parse::(); + //~^ unused_result_ok } fn good_style(x: &str) -> Option { @@ -16,6 +17,7 @@ fn good_style(x: &str) -> Option { #[rustfmt::skip] fn strange_parse(x: &str) { let _ = x . parse::(); + //~^ unused_result_ok } macro_rules! v { @@ -27,11 +29,13 @@ macro_rules! v { macro_rules! w { () => { let _ = Ok::<(), ()>(()); + //~^ unused_result_ok }; } fn main() { let _ = v!(); + //~^ unused_result_ok w!(); external! { diff --git a/src/tools/clippy/tests/ui/unused_result_ok.rs b/src/tools/clippy/tests/ui/unused_result_ok.rs index 117d64c4cec60..6ab974861b636 100644 --- a/src/tools/clippy/tests/ui/unused_result_ok.rs +++ b/src/tools/clippy/tests/ui/unused_result_ok.rs @@ -7,6 +7,7 @@ extern crate proc_macros; fn bad_style(x: &str) { x.parse::().ok(); + //~^ unused_result_ok } fn good_style(x: &str) -> Option { @@ -16,6 +17,7 @@ fn good_style(x: &str) -> Option { #[rustfmt::skip] fn strange_parse(x: &str) { x . parse::() . ok (); + //~^ unused_result_ok } macro_rules! v { @@ -27,11 +29,13 @@ macro_rules! v { macro_rules! w { () => { Ok::<(), ()>(()).ok(); + //~^ unused_result_ok }; } fn main() { v!().ok(); + //~^ unused_result_ok w!(); external! { diff --git a/src/tools/clippy/tests/ui/unused_result_ok.stderr b/src/tools/clippy/tests/ui/unused_result_ok.stderr index 024aafa6bbb89..0e134ba3ccba2 100644 --- a/src/tools/clippy/tests/ui/unused_result_ok.stderr +++ b/src/tools/clippy/tests/ui/unused_result_ok.stderr @@ -13,7 +13,7 @@ LL + let _ = x.parse::(); | error: ignoring a result with `.ok()` is misleading - --> tests/ui/unused_result_ok.rs:18:5 + --> tests/ui/unused_result_ok.rs:19:5 | LL | x . parse::() . ok (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL + let _ = x . parse::(); | error: ignoring a result with `.ok()` is misleading - --> tests/ui/unused_result_ok.rs:34:5 + --> tests/ui/unused_result_ok.rs:37:5 | LL | v!().ok(); | ^^^^^^^^^ @@ -37,7 +37,7 @@ LL + let _ = v!(); | error: ignoring a result with `.ok()` is misleading - --> tests/ui/unused_result_ok.rs:29:9 + --> tests/ui/unused_result_ok.rs:31:9 | LL | Ok::<(), ()>(()).ok(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unused_rounding.fixed b/src/tools/clippy/tests/ui/unused_rounding.fixed index 7af2c8650a3dd..461d97c55531c 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.fixed +++ b/src/tools/clippy/tests/ui/unused_rounding.fixed @@ -4,15 +4,20 @@ fn main() { let _ = 1f32; + //~^ unused_rounding let _ = 1.0f64; + //~^ unused_rounding let _ = 1.00f32; + //~^ unused_rounding let _ = 2e-54f64.floor(); // issue9866 let _ = 3.3_f32.round(); let _ = 3.3_f64.round(); let _ = 3.0_f32; + //~^ unused_rounding let _ = 3_3.0_0_f32; + //~^ unused_rounding let _ = 3_3.0_1_f64.round(); } diff --git a/src/tools/clippy/tests/ui/unused_rounding.rs b/src/tools/clippy/tests/ui/unused_rounding.rs index 1b0b22a9b6854..0d5ebf941a5e3 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.rs +++ b/src/tools/clippy/tests/ui/unused_rounding.rs @@ -4,15 +4,20 @@ fn main() { let _ = 1f32.ceil(); + //~^ unused_rounding let _ = 1.0f64.floor(); + //~^ unused_rounding let _ = 1.00f32.round(); + //~^ unused_rounding let _ = 2e-54f64.floor(); // issue9866 let _ = 3.3_f32.round(); let _ = 3.3_f64.round(); let _ = 3.0_f32.round(); + //~^ unused_rounding let _ = 3_3.0_0_f32.round(); + //~^ unused_rounding let _ = 3_3.0_1_f64.round(); } diff --git a/src/tools/clippy/tests/ui/unused_rounding.stderr b/src/tools/clippy/tests/ui/unused_rounding.stderr index c5ae2da75f84e..494b0cc7352d2 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.stderr +++ b/src/tools/clippy/tests/ui/unused_rounding.stderr @@ -8,25 +8,25 @@ LL | let _ = 1f32.ceil(); = help: to override `-D warnings` add `#[allow(clippy::unused_rounding)]` error: used the `floor` method with a whole number float - --> tests/ui/unused_rounding.rs:7:13 + --> tests/ui/unused_rounding.rs:8:13 | LL | let _ = 1.0f64.floor(); | ^^^^^^^^^^^^^^ help: remove the `floor` method call: `1.0f64` error: used the `round` method with a whole number float - --> tests/ui/unused_rounding.rs:8:13 + --> tests/ui/unused_rounding.rs:10:13 | LL | let _ = 1.00f32.round(); | ^^^^^^^^^^^^^^^ help: remove the `round` method call: `1.00f32` error: used the `round` method with a whole number float - --> tests/ui/unused_rounding.rs:14:13 + --> tests/ui/unused_rounding.rs:17:13 | LL | let _ = 3.0_f32.round(); | ^^^^^^^^^^^^^^^ help: remove the `round` method call: `3.0_f32` error: used the `round` method with a whole number float - --> tests/ui/unused_rounding.rs:16:13 + --> tests/ui/unused_rounding.rs:20:13 | LL | let _ = 3_3.0_0_f32.round(); | ^^^^^^^^^^^^^^^^^^^ help: remove the `round` method call: `3_3.0_0_f32` diff --git a/src/tools/clippy/tests/ui/unused_self.rs b/src/tools/clippy/tests/ui/unused_self.rs index d3d06037cb494..cb80d946acedb 100644 --- a/src/tools/clippy/tests/ui/unused_self.rs +++ b/src/tools/clippy/tests/ui/unused_self.rs @@ -9,25 +9,34 @@ mod unused_self { impl A { fn unused_self_move(self) {} - //~^ ERROR: unused `self` argument + //~^ unused_self + fn unused_self_ref(&self) {} - //~^ ERROR: unused `self` argument + //~^ unused_self + fn unused_self_mut_ref(&mut self) {} - //~^ ERROR: unused `self` argument + //~^ unused_self + fn unused_self_pin_ref(self: Pin<&Self>) {} - //~^ ERROR: unused `self` argument + //~^ unused_self + fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {} - //~^ ERROR: unused `self` argument + //~^ unused_self + fn unused_self_pin_nested(self: Pin>) {} - //~^ ERROR: unused `self` argument + //~^ unused_self + fn unused_self_box(self: Box) {} - //~^ ERROR: unused `self` argument + //~^ unused_self + fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 { - //~^ ERROR: unused `self` argument + //~^ unused_self + x + y } fn unused_self_class_method(&self) { - //~^ ERROR: unused `self` argument + //~^ unused_self + Self::static_method(); } diff --git a/src/tools/clippy/tests/ui/unused_self.stderr b/src/tools/clippy/tests/ui/unused_self.stderr index 5d5f1b643a4a1..e29f5f96c886c 100644 --- a/src/tools/clippy/tests/ui/unused_self.stderr +++ b/src/tools/clippy/tests/ui/unused_self.stderr @@ -9,7 +9,7 @@ LL | fn unused_self_move(self) {} = help: to override `-D warnings` add `#[allow(clippy::unused_self)]` error: unused `self` argument - --> tests/ui/unused_self.rs:13:28 + --> tests/ui/unused_self.rs:14:28 | LL | fn unused_self_ref(&self) {} | ^^^^^ @@ -17,7 +17,7 @@ LL | fn unused_self_ref(&self) {} = help: consider refactoring to an associated function error: unused `self` argument - --> tests/ui/unused_self.rs:15:32 + --> tests/ui/unused_self.rs:17:32 | LL | fn unused_self_mut_ref(&mut self) {} | ^^^^^^^^^ @@ -25,7 +25,7 @@ LL | fn unused_self_mut_ref(&mut self) {} = help: consider refactoring to an associated function error: unused `self` argument - --> tests/ui/unused_self.rs:17:32 + --> tests/ui/unused_self.rs:20:32 | LL | fn unused_self_pin_ref(self: Pin<&Self>) {} | ^^^^ @@ -33,7 +33,7 @@ LL | fn unused_self_pin_ref(self: Pin<&Self>) {} = help: consider refactoring to an associated function error: unused `self` argument - --> tests/ui/unused_self.rs:19:36 + --> tests/ui/unused_self.rs:23:36 | LL | fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {} | ^^^^ @@ -41,7 +41,7 @@ LL | fn unused_self_pin_mut_ref(self: Pin<&mut Self>) {} = help: consider refactoring to an associated function error: unused `self` argument - --> tests/ui/unused_self.rs:21:35 + --> tests/ui/unused_self.rs:26:35 | LL | fn unused_self_pin_nested(self: Pin>) {} | ^^^^ @@ -49,7 +49,7 @@ LL | fn unused_self_pin_nested(self: Pin>) {} = help: consider refactoring to an associated function error: unused `self` argument - --> tests/ui/unused_self.rs:23:28 + --> tests/ui/unused_self.rs:29:28 | LL | fn unused_self_box(self: Box) {} | ^^^^ @@ -57,7 +57,7 @@ LL | fn unused_self_box(self: Box) {} = help: consider refactoring to an associated function error: unused `self` argument - --> tests/ui/unused_self.rs:25:40 + --> tests/ui/unused_self.rs:32:40 | LL | fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 { | ^^^^^ @@ -65,7 +65,7 @@ LL | fn unused_with_other_used_args(&self, x: u8, y: u8) -> u8 { = help: consider refactoring to an associated function error: unused `self` argument - --> tests/ui/unused_self.rs:29:37 + --> tests/ui/unused_self.rs:37:37 | LL | fn unused_self_class_method(&self) { | ^^^^^ diff --git a/src/tools/clippy/tests/ui/unused_trait_names.fixed b/src/tools/clippy/tests/ui/unused_trait_names.fixed index 7dfd0db65aa1b..17e32ddfd9d95 100644 --- a/src/tools/clippy/tests/ui/unused_trait_names.fixed +++ b/src/tools/clippy/tests/ui/unused_trait_names.fixed @@ -10,6 +10,7 @@ fn main() {} fn bad() { use std::any::Any as _; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -29,6 +30,7 @@ fn used_good() { fn multi_bad() { use std::any::{self, Any as _, TypeId}; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -41,12 +43,14 @@ fn multi_good() { fn renamed_bad() { use std::any::Any as _; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } fn multi_renamed_bad() { use std::any::{Any as _, TypeId as MyTypeId}; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -70,6 +74,7 @@ mod used_mod_good { mod mod_import_bad { fn mod_import_bad() { use std::any::Any as _; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -111,6 +116,7 @@ mod nested_mod_used_good3 { mod nested_mod_used_bad { use std::any::Any as _; + //~^ unused_trait_names fn bar() { println!("{:?}", "foo".type_id()); @@ -130,6 +136,7 @@ mod nested_mod_used_bad { // the code would still compile. mod nested_mod_used_bad1 { use std::any::Any as _; + //~^ unused_trait_names use std::any::Any as MyAny; @@ -189,6 +196,7 @@ fn msrv_1_32() { #[clippy::msrv = "1.33"] fn msrv_1_33() { use simple_trait::{MyStruct, MyTrait as _}; + //~^ unused_trait_names MyStruct.do_things(); } @@ -196,6 +204,7 @@ mod lint_inside_macro_expansion_bad { macro_rules! foo { () => { use std::any::Any as _; + //~^ unused_trait_names fn bar() { "bar".type_id(); } @@ -243,6 +252,7 @@ proc_macros::with_span!( #[warn(unused)] mod unused_import { + //~^ ERROR: unused import } #[allow(clippy::unused_trait_names)] diff --git a/src/tools/clippy/tests/ui/unused_trait_names.rs b/src/tools/clippy/tests/ui/unused_trait_names.rs index ce44eedbc79c2..3cf8597e53517 100644 --- a/src/tools/clippy/tests/ui/unused_trait_names.rs +++ b/src/tools/clippy/tests/ui/unused_trait_names.rs @@ -10,6 +10,7 @@ fn main() {} fn bad() { use std::any::Any; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -29,6 +30,7 @@ fn used_good() { fn multi_bad() { use std::any::{self, Any, TypeId}; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -41,12 +43,14 @@ fn multi_good() { fn renamed_bad() { use std::any::Any as MyAny; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } fn multi_renamed_bad() { use std::any::{Any as MyAny, TypeId as MyTypeId}; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -70,6 +74,7 @@ mod used_mod_good { mod mod_import_bad { fn mod_import_bad() { use std::any::Any; + //~^ unused_trait_names println!("{:?}", "foo".type_id()); } @@ -111,6 +116,7 @@ mod nested_mod_used_good3 { mod nested_mod_used_bad { use std::any::Any; + //~^ unused_trait_names fn bar() { println!("{:?}", "foo".type_id()); @@ -130,6 +136,7 @@ mod nested_mod_used_bad { // the code would still compile. mod nested_mod_used_bad1 { use std::any::Any; + //~^ unused_trait_names use std::any::Any as MyAny; @@ -189,6 +196,7 @@ fn msrv_1_32() { #[clippy::msrv = "1.33"] fn msrv_1_33() { use simple_trait::{MyStruct, MyTrait}; + //~^ unused_trait_names MyStruct.do_things(); } @@ -196,6 +204,7 @@ mod lint_inside_macro_expansion_bad { macro_rules! foo { () => { use std::any::Any; + //~^ unused_trait_names fn bar() { "bar".type_id(); } @@ -243,6 +252,7 @@ proc_macros::with_span!( #[warn(unused)] mod unused_import { use std::any::Any; + //~^ ERROR: unused import } #[allow(clippy::unused_trait_names)] diff --git a/src/tools/clippy/tests/ui/unused_trait_names.stderr b/src/tools/clippy/tests/ui/unused_trait_names.stderr index f59d8f58a170a..3183289d85337 100644 --- a/src/tools/clippy/tests/ui/unused_trait_names.stderr +++ b/src/tools/clippy/tests/ui/unused_trait_names.stderr @@ -1,5 +1,5 @@ error: unused import: `std::any::Any` - --> tests/ui/unused_trait_names.rs:245:9 + --> tests/ui/unused_trait_names.rs:254:9 | LL | use std::any::Any; | ^^^^^^^^^^^^^ @@ -17,49 +17,49 @@ LL | use std::any::Any; = help: to override `-D warnings` add `#[allow(clippy::unused_trait_names)]` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:31:26 + --> tests/ui/unused_trait_names.rs:32:26 | LL | use std::any::{self, Any, TypeId}; | ^^^ help: use: `Any as _` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:43:19 + --> tests/ui/unused_trait_names.rs:45:19 | LL | use std::any::Any as MyAny; | ^^^^^^^^^^^^ help: use: `Any as _` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:49:20 + --> tests/ui/unused_trait_names.rs:52:20 | LL | use std::any::{Any as MyAny, TypeId as MyTypeId}; | ^^^^^^^^^^^^ help: use: `Any as _` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:72:23 + --> tests/ui/unused_trait_names.rs:76:23 | LL | use std::any::Any; | ^^^ help: use: `Any as _` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:113:19 + --> tests/ui/unused_trait_names.rs:118:19 | LL | use std::any::Any; | ^^^ help: use: `Any as _` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:132:19 + --> tests/ui/unused_trait_names.rs:138:19 | LL | use std::any::Any; | ^^^ help: use: `Any as _` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:191:34 + --> tests/ui/unused_trait_names.rs:198:34 | LL | use simple_trait::{MyStruct, MyTrait}; | ^^^^^^^ help: use: `MyTrait as _` error: importing trait that is only used anonymously - --> tests/ui/unused_trait_names.rs:198:27 + --> tests/ui/unused_trait_names.rs:206:27 | LL | use std::any::Any; | ^^^ help: use: `Any as _` diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed index 04fe2d3b7af18..e3c02681c9fd7 100644 --- a/src/tools/clippy/tests/ui/unused_unit.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.fixed @@ -18,8 +18,12 @@ struct Unitter; impl Unitter { #[allow(clippy::no_effect)] pub fn get_unit(&self, f: F, _g: G) + //~^ unused_unit + //~| unused_unit where G: Fn() { + //~^ unused_unit let _y: &dyn Fn() = &f; + //~^ unused_unit (); // this should not lint, as it's not in return type position } } @@ -27,25 +31,35 @@ impl Unitter { impl Into<()> for Unitter { #[rustfmt::skip] fn into(self) { + //~^ unused_unit + //~^ unused_unit } } trait Trait { fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit where G: FnMut(), + //~^ unused_unit H: Fn(); + //~^ unused_unit } impl Trait for Unitter { fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit where G: FnMut(), + //~^ unused_unit H: Fn() {} + //~^ unused_unit } fn return_unit() { } +//~^ unused_unit +//~| unused_unit #[allow(clippy::needless_return)] #[allow(clippy::never_loop)] @@ -56,8 +70,10 @@ fn main() { return_unit(); loop { break; + //~^ unused_unit } return; + //~^ unused_unit } // https://github.com/rust-lang/rust-clippy/issues/4076 @@ -75,12 +91,15 @@ fn foo() { #[rustfmt::skip] fn test(){} +//~^ unused_unit #[rustfmt::skip] fn test2(){} +//~^ unused_unit #[rustfmt::skip] fn test3(){} +//~^ unused_unit fn macro_expr() { macro_rules! e { diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs index 25c2ed59873ac..4353026c594c1 100644 --- a/src/tools/clippy/tests/ui/unused_unit.rs +++ b/src/tools/clippy/tests/ui/unused_unit.rs @@ -18,8 +18,12 @@ struct Unitter; impl Unitter { #[allow(clippy::no_effect)] pub fn get_unit (), G>(&self, f: F, _g: G) -> () + //~^ unused_unit + //~| unused_unit where G: Fn() -> () { + //~^ unused_unit let _y: &dyn Fn() -> () = &f; + //~^ unused_unit (); // this should not lint, as it's not in return type position } } @@ -27,25 +31,35 @@ impl Unitter { impl Into<()> for Unitter { #[rustfmt::skip] fn into(self) -> () { + //~^ unused_unit () + //~^ unused_unit } } trait Trait { fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + //~^ unused_unit where G: FnMut() -> (), + //~^ unused_unit H: Fn() -> (); + //~^ unused_unit } impl Trait for Unitter { fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + //~^ unused_unit where G: FnMut() -> (), + //~^ unused_unit H: Fn() -> () {} + //~^ unused_unit } fn return_unit() -> () { () } +//~^ unused_unit +//~| unused_unit #[allow(clippy::needless_return)] #[allow(clippy::never_loop)] @@ -56,8 +70,10 @@ fn main() { return_unit(); loop { break(); + //~^ unused_unit } return(); + //~^ unused_unit } // https://github.com/rust-lang/rust-clippy/issues/4076 @@ -75,12 +91,15 @@ fn foo() { #[rustfmt::skip] fn test()->(){} +//~^ unused_unit #[rustfmt::skip] fn test2() ->(){} +//~^ unused_unit #[rustfmt::skip] fn test3()-> (){} +//~^ unused_unit fn macro_expr() { macro_rules! e { diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr index 104159ad5fc63..172fe06550281 100644 --- a/src/tools/clippy/tests/ui/unused_unit.stderr +++ b/src/tools/clippy/tests/ui/unused_unit.stderr @@ -17,103 +17,103 @@ LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:21:18 + --> tests/ui/unused_unit.rs:23:18 | LL | where G: Fn() -> () { | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:22:26 + --> tests/ui/unused_unit.rs:25:26 | LL | let _y: &dyn Fn() -> () = &f; | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:29:18 + --> tests/ui/unused_unit.rs:33:18 | LL | fn into(self) -> () { | ^^^^^^ help: remove the `-> ()` error: unneeded unit expression - --> tests/ui/unused_unit.rs:30:9 + --> tests/ui/unused_unit.rs:35:9 | LL | () | ^^ help: remove the final `()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:35:29 + --> tests/ui/unused_unit.rs:41:29 | LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:37:19 + --> tests/ui/unused_unit.rs:44:19 | LL | G: FnMut() -> (), | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:38:16 + --> tests/ui/unused_unit.rs:46:16 | LL | H: Fn() -> (); | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:42:29 + --> tests/ui/unused_unit.rs:51:29 | LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:44:19 + --> tests/ui/unused_unit.rs:54:19 | LL | G: FnMut() -> (), | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:45:16 + --> tests/ui/unused_unit.rs:56:16 | LL | H: Fn() -> () {} | ^^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:48:17 + --> tests/ui/unused_unit.rs:60:17 | LL | fn return_unit() -> () { () } | ^^^^^^ help: remove the `-> ()` error: unneeded unit expression - --> tests/ui/unused_unit.rs:48:26 + --> tests/ui/unused_unit.rs:60:26 | LL | fn return_unit() -> () { () } | ^^ help: remove the final `()` error: unneeded `()` - --> tests/ui/unused_unit.rs:58:14 + --> tests/ui/unused_unit.rs:72:14 | LL | break(); | ^^ help: remove the `()` error: unneeded `()` - --> tests/ui/unused_unit.rs:60:11 + --> tests/ui/unused_unit.rs:75:11 | LL | return(); | ^^ help: remove the `()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:77:10 + --> tests/ui/unused_unit.rs:93:10 | LL | fn test()->(){} | ^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:80:11 + --> tests/ui/unused_unit.rs:97:11 | LL | fn test2() ->(){} | ^^^^^ help: remove the `-> ()` error: unneeded unit return type - --> tests/ui/unused_unit.rs:83:11 + --> tests/ui/unused_unit.rs:101:11 | LL | fn test3()-> (){} | ^^^^^ help: remove the `-> ()` diff --git a/src/tools/clippy/tests/ui/unwrap.rs b/src/tools/clippy/tests/ui/unwrap.rs index 8ad7e98503bfc..3191b396f99bc 100644 --- a/src/tools/clippy/tests/ui/unwrap.rs +++ b/src/tools/clippy/tests/ui/unwrap.rs @@ -4,15 +4,16 @@ fn unwrap_option() { let opt = Some(0); let _ = opt.unwrap(); - //~^ ERROR: used `unwrap()` on an `Option` value + //~^ unwrap_used } fn unwrap_result() { let res: Result = Ok(0); let _ = res.unwrap(); - //~^ ERROR: used `unwrap()` on a `Result` value + //~^ unwrap_used + let _ = res.unwrap_err(); - //~^ ERROR: used `unwrap_err()` on a `Result` value + //~^ unwrap_used } fn main() { diff --git a/src/tools/clippy/tests/ui/unwrap.stderr b/src/tools/clippy/tests/ui/unwrap.stderr index 3c1b37bc3d9bf..c242541a6bd73 100644 --- a/src/tools/clippy/tests/ui/unwrap.stderr +++ b/src/tools/clippy/tests/ui/unwrap.stderr @@ -19,7 +19,7 @@ LL | let _ = res.unwrap(); = help: consider using `expect()` to provide a better panic message error: used `unwrap_err()` on a `Result` value - --> tests/ui/unwrap.rs:14:13 + --> tests/ui/unwrap.rs:15:13 | LL | let _ = res.unwrap_err(); | ^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs index a56bd0a8d0790..d0bb571273b5a 100644 --- a/src/tools/clippy/tests/ui/unwrap_expect_used.rs +++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs @@ -25,9 +25,10 @@ impl OptionExt for Option { fn main() { Some(3).unwrap(); - //~^ ERROR: used `unwrap()` on an `Option` value + //~^ unwrap_used + Some(3).expect("Hello world!"); - //~^ ERROR: used `expect()` on an `Option` value + //~^ expect_used // Don't trigger on unwrap_err on an option Some(3).unwrap_err(); @@ -43,11 +44,25 @@ fn main() { let a: Result = Ok(3); a.unwrap(); - //~^ ERROR: used `unwrap()` on a `Result` value + //~^ unwrap_used + a.expect("Hello world!"); - //~^ ERROR: used `expect()` on a `Result` value + //~^ expect_used + a.unwrap_err(); - //~^ ERROR: used `unwrap_err()` on a `Result` value + //~^ unwrap_used + a.expect_err("Hello error!"); - //~^ ERROR: used `expect_err()` on a `Result` value + //~^ expect_used + + // Don't trigger in compile time contexts by default + const SOME: Option = Some(3); + const UNWRAPPED: i32 = SOME.unwrap(); + const EXPECTED: i32 = SOME.expect("Not three?"); + const { + SOME.unwrap(); + } + const { + SOME.expect("Still not three?"); + } } diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr index 9069522a4df1a..79eac3f58ccb2 100644 --- a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr +++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr @@ -9,7 +9,7 @@ LL | Some(3).unwrap(); = help: to override `-D warnings` add `#[allow(clippy::unwrap_used)]` error: used `expect()` on an `Option` value - --> tests/ui/unwrap_expect_used.rs:29:5 + --> tests/ui/unwrap_expect_used.rs:30:5 | LL | Some(3).expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +19,7 @@ LL | Some(3).expect("Hello world!"); = help: to override `-D warnings` add `#[allow(clippy::expect_used)]` error: used `unwrap()` on a `Result` value - --> tests/ui/unwrap_expect_used.rs:45:5 + --> tests/ui/unwrap_expect_used.rs:46:5 | LL | a.unwrap(); | ^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | a.unwrap(); = note: if this value is an `Err`, it will panic error: used `expect()` on a `Result` value - --> tests/ui/unwrap_expect_used.rs:47:5 + --> tests/ui/unwrap_expect_used.rs:49:5 | LL | a.expect("Hello world!"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | a.expect("Hello world!"); = note: if this value is an `Err`, it will panic error: used `unwrap_err()` on a `Result` value - --> tests/ui/unwrap_expect_used.rs:49:5 + --> tests/ui/unwrap_expect_used.rs:52:5 | LL | a.unwrap_err(); | ^^^^^^^^^^^^^^ @@ -43,7 +43,7 @@ LL | a.unwrap_err(); = note: if this value is an `Ok`, it will panic error: used `expect_err()` on a `Result` value - --> tests/ui/unwrap_expect_used.rs:51:5 + --> tests/ui/unwrap_expect_used.rs:55:5 | LL | a.expect_err("Hello error!"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.rs b/src/tools/clippy/tests/ui/unwrap_in_result.rs index 62c6d959c84b6..4e872c67b423e 100644 --- a/src/tools/clippy/tests/ui/unwrap_in_result.rs +++ b/src/tools/clippy/tests/ui/unwrap_in_result.rs @@ -20,7 +20,8 @@ impl A { // should be detected fn bad_divisible_by_3(i_str: String) -> Result { - //~^ ERROR: used unwrap or expect in a function that returns result or option + //~^ unwrap_in_result + // checks whether a string represents a number divisible by 3 let i = i_str.parse::().unwrap(); if i % 3 == 0 { @@ -31,7 +32,8 @@ impl A { } fn example_option_expect(i_str: String) -> Option { - //~^ ERROR: used unwrap or expect in a function that returns result or option + //~^ unwrap_in_result + let i = i_str.parse::().expect("not a number"); if i % 3 == 0 { return Some(true); @@ -40,6 +42,7 @@ impl A { } fn in_closure(a: Option) -> Option { + //~^ unwrap_in_result let c = || a.unwrap(); Some(c()) } diff --git a/src/tools/clippy/tests/ui/unwrap_in_result.stderr b/src/tools/clippy/tests/ui/unwrap_in_result.stderr index 201d4ae36ae3d..5e3eab813e075 100644 --- a/src/tools/clippy/tests/ui/unwrap_in_result.stderr +++ b/src/tools/clippy/tests/ui/unwrap_in_result.stderr @@ -2,16 +2,13 @@ error: used unwrap or expect in a function that returns result or option --> tests/ui/unwrap_in_result.rs:22:5 | LL | / fn bad_divisible_by_3(i_str: String) -> Result { -LL | | -LL | | // checks whether a string represents a number divisible by 3 -LL | | let i = i_str.parse::().unwrap(); ... | LL | | } | |_____^ | = help: unwrap and expect should not be used in a function that returns result or option note: potential non-recoverable error(s) - --> tests/ui/unwrap_in_result.rs:25:17 + --> tests/ui/unwrap_in_result.rs:26:17 | LL | let i = i_str.parse::().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,12 +16,12 @@ LL | let i = i_str.parse::().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::unwrap_in_result)]` error: used unwrap or expect in a function that returns result or option - --> tests/ui/unwrap_in_result.rs:33:5 + --> tests/ui/unwrap_in_result.rs:34:5 | LL | / fn example_option_expect(i_str: String) -> Option { LL | | +LL | | LL | | let i = i_str.parse::().expect("not a number"); -LL | | if i % 3 == 0 { ... | LL | | None LL | | } @@ -32,15 +29,16 @@ LL | | } | = help: unwrap and expect should not be used in a function that returns result or option note: potential non-recoverable error(s) - --> tests/ui/unwrap_in_result.rs:35:17 + --> tests/ui/unwrap_in_result.rs:37:17 | LL | let i = i_str.parse::().expect("not a number"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: used unwrap or expect in a function that returns result or option - --> tests/ui/unwrap_in_result.rs:42:5 + --> tests/ui/unwrap_in_result.rs:44:5 | LL | / fn in_closure(a: Option) -> Option { +LL | | LL | | let c = || a.unwrap(); LL | | Some(c()) LL | | } @@ -48,7 +46,7 @@ LL | | } | = help: unwrap and expect should not be used in a function that returns result or option note: potential non-recoverable error(s) - --> tests/ui/unwrap_in_result.rs:43:20 + --> tests/ui/unwrap_in_result.rs:46:20 | LL | let c = || a.unwrap(); | ^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unwrap_or.fixed b/src/tools/clippy/tests/ui/unwrap_or.fixed index 62bc1966da6ff..c794ed577032d 100644 --- a/src/tools/clippy/tests/ui/unwrap_or.fixed +++ b/src/tools/clippy/tests/ui/unwrap_or.fixed @@ -3,11 +3,10 @@ fn main() { let s = Some(String::from("test string")).unwrap_or_else(|| "Fail".to_string()).len(); - //~^ ERROR: function call inside of `unwrap_or` - //~| NOTE: `-D clippy::or-fun-call` implied by `-D warnings` + //~^ or_fun_call } fn new_lines() { let s = Some(String::from("test string")).unwrap_or_else(|| "Fail".to_string()).len(); - //~^ ERROR: function call inside of `unwrap_or` + //~^ or_fun_call } diff --git a/src/tools/clippy/tests/ui/unwrap_or.rs b/src/tools/clippy/tests/ui/unwrap_or.rs index e8e4b6b7168f4..11a6883b7403f 100644 --- a/src/tools/clippy/tests/ui/unwrap_or.rs +++ b/src/tools/clippy/tests/ui/unwrap_or.rs @@ -3,11 +3,10 @@ fn main() { let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - //~^ ERROR: function call inside of `unwrap_or` - //~| NOTE: `-D clippy::or-fun-call` implied by `-D warnings` + //~^ or_fun_call } fn new_lines() { let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); - //~^ ERROR: function call inside of `unwrap_or` + //~^ or_fun_call } diff --git a/src/tools/clippy/tests/ui/unwrap_or.stderr b/src/tools/clippy/tests/ui/unwrap_or.stderr index b712f8cf693de..e95633680acc1 100644 --- a/src/tools/clippy/tests/ui/unwrap_or.stderr +++ b/src/tools/clippy/tests/ui/unwrap_or.stderr @@ -8,7 +8,7 @@ LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()) = help: to override `-D warnings` add `#[allow(clippy::or_fun_call)]` error: function call inside of `unwrap_or` - --> tests/ui/unwrap_or.rs:11:47 + --> tests/ui/unwrap_or.rs:10:47 | LL | let s = Some(String::from("test string")).unwrap_or("Fail".to_string()).len(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| "Fail".to_string())` diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed index 8d5d34175c525..561cbce473deb 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed @@ -44,6 +44,7 @@ fn unwrap_or_else_default() { let with_new = Some(vec![1]); with_new.unwrap_or_default(); + //~^ unwrap_or_default let with_err: Result<_, ()> = Ok(vec![1]); with_err.unwrap_or_else(make); @@ -58,43 +59,56 @@ fn unwrap_or_else_default() { let with_real_default = None::; with_real_default.unwrap_or_default(); + //~^ unwrap_or_default let with_default_trait = Some(1); with_default_trait.unwrap_or_default(); + //~^ unwrap_or_default let with_default_type = Some(1); with_default_type.unwrap_or_default(); + //~^ unwrap_or_default let with_default_type: Option> = None; with_default_type.unwrap_or_default(); + //~^ unwrap_or_default let empty_string = None::; empty_string.unwrap_or_default(); + //~^ unwrap_or_default } fn type_certainty(option: Option>) { option.unwrap_or_default().push(1); + //~^ unwrap_or_default let option: std::option::Option> = None; option.unwrap_or_default().push(1); + //~^ unwrap_or_default let option: Option> = None; option.unwrap_or_default().push(1); + //~^ unwrap_or_default let option = std::option::Option::>::None; option.unwrap_or_default().push(1); + //~^ unwrap_or_default let option = Option::>::None; option.unwrap_or_default().push(1); + //~^ unwrap_or_default let option = std::option::Option::None::>; option.unwrap_or_default().push(1); + //~^ unwrap_or_default let option = Option::None::>; option.unwrap_or_default().push(1); + //~^ unwrap_or_default let option = None::>; option.unwrap_or_default().push(1); + //~^ unwrap_or_default // should not be changed: type annotation with infer, unconcretized initializer let option: Option> = None; @@ -111,6 +125,7 @@ fn type_certainty(option: Option>) { type Alias = Option>; let option: Alias = Option::>::Some(Vec::new()); option.unwrap_or_default().push(1); + //~^ unwrap_or_default } fn method_call_with_deref() { @@ -128,6 +143,7 @@ fn method_call_with_deref() { let inner_map = outer_map.get_mut(&option.unwrap()).unwrap(); let _ = inner_map.entry(0).or_default(); + //~^ unwrap_or_default } fn missing_suggested_method() { diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs index adbcb4b446591..8389be964fe6d 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs @@ -44,6 +44,7 @@ fn unwrap_or_else_default() { let with_new = Some(vec![1]); with_new.unwrap_or_else(Vec::new); + //~^ unwrap_or_default let with_err: Result<_, ()> = Ok(vec![1]); with_err.unwrap_or_else(make); @@ -58,43 +59,56 @@ fn unwrap_or_else_default() { let with_real_default = None::; with_real_default.unwrap_or_else(::default); + //~^ unwrap_or_default let with_default_trait = Some(1); with_default_trait.unwrap_or_else(Default::default); + //~^ unwrap_or_default let with_default_type = Some(1); with_default_type.unwrap_or_else(u64::default); + //~^ unwrap_or_default let with_default_type: Option> = None; with_default_type.unwrap_or_else(Vec::new); + //~^ unwrap_or_default let empty_string = None::; empty_string.unwrap_or_else(|| "".to_string()); + //~^ unwrap_or_default } fn type_certainty(option: Option>) { option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default let option: std::option::Option> = None; option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default let option: Option> = None; option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default let option = std::option::Option::>::None; option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default let option = Option::>::None; option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default let option = std::option::Option::None::>; option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default let option = Option::None::>; option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default let option = None::>; option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default // should not be changed: type annotation with infer, unconcretized initializer let option: Option> = None; @@ -111,6 +125,7 @@ fn type_certainty(option: Option>) { type Alias = Option>; let option: Alias = Option::>::Some(Vec::new()); option.unwrap_or_else(Vec::new).push(1); + //~^ unwrap_or_default } fn method_call_with_deref() { @@ -128,6 +143,7 @@ fn method_call_with_deref() { let inner_map = outer_map.get_mut(&option.unwrap()).unwrap(); let _ = inner_map.entry(0).or_insert_with(Default::default); + //~^ unwrap_or_default } fn missing_suggested_method() { diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr index e4b4a0a1f6aa7..a001f7e46add9 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.stderr @@ -8,91 +8,91 @@ LL | with_new.unwrap_or_else(Vec::new); = help: to override `-D warnings` add `#[allow(clippy::unwrap_or_default)]` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:60:23 + --> tests/ui/unwrap_or_else_default.rs:61:23 | LL | with_real_default.unwrap_or_else(::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:63:24 + --> tests/ui/unwrap_or_else_default.rs:65:24 | LL | with_default_trait.unwrap_or_else(Default::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:66:23 + --> tests/ui/unwrap_or_else_default.rs:69:23 | LL | with_default_type.unwrap_or_else(u64::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:69:23 + --> tests/ui/unwrap_or_else_default.rs:73:23 | LL | with_default_type.unwrap_or_else(Vec::new); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:72:18 + --> tests/ui/unwrap_or_else_default.rs:77:18 | LL | empty_string.unwrap_or_else(|| "".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:76:12 + --> tests/ui/unwrap_or_else_default.rs:82:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:79:12 + --> tests/ui/unwrap_or_else_default.rs:86:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:82:12 + --> tests/ui/unwrap_or_else_default.rs:90:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:85:12 + --> tests/ui/unwrap_or_else_default.rs:94:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:88:12 + --> tests/ui/unwrap_or_else_default.rs:98:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:91:12 + --> tests/ui/unwrap_or_else_default.rs:102:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:94:12 + --> tests/ui/unwrap_or_else_default.rs:106:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:97:12 + --> tests/ui/unwrap_or_else_default.rs:110:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `unwrap_or_else` to construct default value - --> tests/ui/unwrap_or_else_default.rs:113:12 + --> tests/ui/unwrap_or_else_default.rs:127:12 | LL | option.unwrap_or_else(Vec::new).push(1); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()` error: use of `or_insert_with` to construct default value - --> tests/ui/unwrap_or_else_default.rs:130:32 + --> tests/ui/unwrap_or_else_default.rs:145:32 | LL | let _ = inner_map.entry(0).or_insert_with(Default::default); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()` diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.fixed b/src/tools/clippy/tests/ui/upper_case_acronyms.fixed index a8023ed00d213..da44c8e3026e2 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.fixed +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.fixed @@ -7,22 +7,21 @@ struct CString; // not linted enum Flags { NS, // not linted Cwr, - //~^ ERROR: name `CWR` contains a capitalized acronym - //~| NOTE: `-D clippy::upper-case-acronyms` implied by `-D warnings` + //~^ upper_case_acronyms Ece, - //~^ ERROR: name `ECE` contains a capitalized acronym + //~^ upper_case_acronyms Urg, - //~^ ERROR: name `URG` contains a capitalized acronym + //~^ upper_case_acronyms Ack, - //~^ ERROR: name `ACK` contains a capitalized acronym + //~^ upper_case_acronyms Psh, - //~^ ERROR: name `PSH` contains a capitalized acronym + //~^ upper_case_acronyms Rst, - //~^ ERROR: name `RST` contains a capitalized acronym + //~^ upper_case_acronyms Syn, - //~^ ERROR: name `SYN` contains a capitalized acronym + //~^ upper_case_acronyms Fin, - //~^ ERROR: name `FIN` contains a capitalized acronym + //~^ upper_case_acronyms } // linted with cfg option, beware that lint suggests `GccllvmSomething` instead of @@ -43,18 +42,18 @@ pub enum ParseError { // private, do lint here enum ParseErrorPrivate { Wasd(u8), - //~^ ERROR: name `WASD` contains a capitalized acronym + //~^ upper_case_acronyms Utf8(std::string::FromUtf8Error), Parse(T, String), } // do lint here struct Json; -//~^ ERROR: name `JSON` contains a capitalized acronym +//~^ upper_case_acronyms // do lint here enum Yaml { - //~^ ERROR: name `YAML` contains a capitalized acronym + //~^ upper_case_acronyms Num(u32), Str(String), } @@ -62,7 +61,7 @@ enum Yaml { // test for issue #7708 enum AllowOnField { Disallow, - //~^ ERROR: name `DISALLOW` contains a capitalized acronym + //~^ upper_case_acronyms #[allow(clippy::upper_case_acronyms)] ALLOW, } diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.rs b/src/tools/clippy/tests/ui/upper_case_acronyms.rs index c4711b87ec380..d223b02acda94 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.rs +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.rs @@ -7,22 +7,21 @@ struct CString; // not linted enum Flags { NS, // not linted CWR, - //~^ ERROR: name `CWR` contains a capitalized acronym - //~| NOTE: `-D clippy::upper-case-acronyms` implied by `-D warnings` + //~^ upper_case_acronyms ECE, - //~^ ERROR: name `ECE` contains a capitalized acronym + //~^ upper_case_acronyms URG, - //~^ ERROR: name `URG` contains a capitalized acronym + //~^ upper_case_acronyms ACK, - //~^ ERROR: name `ACK` contains a capitalized acronym + //~^ upper_case_acronyms PSH, - //~^ ERROR: name `PSH` contains a capitalized acronym + //~^ upper_case_acronyms RST, - //~^ ERROR: name `RST` contains a capitalized acronym + //~^ upper_case_acronyms SYN, - //~^ ERROR: name `SYN` contains a capitalized acronym + //~^ upper_case_acronyms FIN, - //~^ ERROR: name `FIN` contains a capitalized acronym + //~^ upper_case_acronyms } // linted with cfg option, beware that lint suggests `GccllvmSomething` instead of @@ -43,18 +42,18 @@ pub enum ParseError { // private, do lint here enum ParseErrorPrivate { WASD(u8), - //~^ ERROR: name `WASD` contains a capitalized acronym + //~^ upper_case_acronyms Utf8(std::string::FromUtf8Error), Parse(T, String), } // do lint here struct JSON; -//~^ ERROR: name `JSON` contains a capitalized acronym +//~^ upper_case_acronyms // do lint here enum YAML { - //~^ ERROR: name `YAML` contains a capitalized acronym + //~^ upper_case_acronyms Num(u32), Str(String), } @@ -62,7 +61,7 @@ enum YAML { // test for issue #7708 enum AllowOnField { DISALLOW, - //~^ ERROR: name `DISALLOW` contains a capitalized acronym + //~^ upper_case_acronyms #[allow(clippy::upper_case_acronyms)] ALLOW, } diff --git a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr index 1f8046c8e841f..dd548fc143e2c 100644 --- a/src/tools/clippy/tests/ui/upper_case_acronyms.stderr +++ b/src/tools/clippy/tests/ui/upper_case_acronyms.stderr @@ -8,67 +8,67 @@ LL | CWR, = help: to override `-D warnings` add `#[allow(clippy::upper_case_acronyms)]` error: name `ECE` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:12:5 + --> tests/ui/upper_case_acronyms.rs:11:5 | LL | ECE, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Ece` error: name `URG` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:14:5 + --> tests/ui/upper_case_acronyms.rs:13:5 | LL | URG, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Urg` error: name `ACK` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:16:5 + --> tests/ui/upper_case_acronyms.rs:15:5 | LL | ACK, | ^^^ help: consider making the acronym lowercase, except the initial letter (notice the capitalization): `Ack` error: name `PSH` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:18:5 + --> tests/ui/upper_case_acronyms.rs:17:5 | LL | PSH, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Psh` error: name `RST` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:20:5 + --> tests/ui/upper_case_acronyms.rs:19:5 | LL | RST, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Rst` error: name `SYN` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:22:5 + --> tests/ui/upper_case_acronyms.rs:21:5 | LL | SYN, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Syn` error: name `FIN` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:24:5 + --> tests/ui/upper_case_acronyms.rs:23:5 | LL | FIN, | ^^^ help: consider making the acronym lowercase, except the initial letter: `Fin` error: name `WASD` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:45:5 + --> tests/ui/upper_case_acronyms.rs:44:5 | LL | WASD(u8), | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Wasd` error: name `JSON` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:52:8 + --> tests/ui/upper_case_acronyms.rs:51:8 | LL | struct JSON; | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Json` error: name `YAML` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:56:6 + --> tests/ui/upper_case_acronyms.rs:55:6 | LL | enum YAML { | ^^^^ help: consider making the acronym lowercase, except the initial letter: `Yaml` error: name `DISALLOW` contains a capitalized acronym - --> tests/ui/upper_case_acronyms.rs:64:5 + --> tests/ui/upper_case_acronyms.rs:63:5 | LL | DISALLOW, | ^^^^^^^^ help: consider making the acronym lowercase, except the initial letter: `Disallow` diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index ffc5b74d7bd68..f15e5e0a5bb42 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -21,16 +21,22 @@ mod use_self { impl Foo { fn new() -> Self { + //~^ use_self Self {} + //~^ use_self } fn test() -> Self { + //~^ use_self Self::new() + //~^ use_self } } impl Default for Foo { fn default() -> Self { + //~^ use_self Self::new() + //~^ use_self } } } @@ -72,6 +78,7 @@ mod lifetimes { } fn clone(&self) -> Self { + //~^ use_self Foo { foo_str: self.foo_str } } @@ -105,6 +112,8 @@ mod existential { impl Foo { fn bad(foos: &[Self]) -> impl Iterator { + //~^ use_self + //~| use_self foos.iter() } @@ -120,6 +129,7 @@ mod tuple_structs { impl TS { pub fn ts() -> Self { Self(0) + //~^ use_self } } } @@ -155,7 +165,9 @@ mod nesting { impl Bar { fn bar() -> Self { + //~^ use_self Self { foo: Foo {} } + //~^ use_self } } @@ -167,7 +179,9 @@ mod nesting { // Should lint here fn baz() -> Self { + //~^ use_self Self {} + //~^ use_self } } @@ -185,8 +199,11 @@ mod nesting { fn method2() { let _ = Self::B(42); + //~^ use_self let _ = Self::C { field: true }; + //~^ use_self let _ = Self::A; + //~^ use_self } } } @@ -229,9 +246,12 @@ mod rustfix { fn fun_2() { Self::fun_1(); + //~^ use_self Self::A; + //~^ use_self Self {}; + //~^ use_self } } } @@ -251,6 +271,7 @@ mod issue3567 { impl Test for TestStruct { fn test() -> TestStruct { Self::from_something() + //~^ use_self } } } @@ -265,11 +286,15 @@ mod paths_created_by_lowering { const B: usize = 1; async fn g() -> Self { + //~^ use_self Self {} + //~^ use_self } fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] { &p[Self::A..Self::B] + //~^ use_self + //~| use_self } } @@ -293,7 +318,9 @@ mod generics { impl Foo { // `Self` is applicable here fn foo(value: T) -> Self { + //~^ use_self Self { value } + //~^ use_self } // `Cannot` use `Self` as a return type as the generic types are different @@ -466,6 +493,7 @@ mod nested_paths { impl A { fn test() -> Self { Self::new::(submod::B {}) + //~^ use_self } } } @@ -503,6 +531,7 @@ mod issue7206 { impl<'a> S2> { fn new_again() -> Self { Self::new() + //~^ use_self } } } @@ -540,13 +569,16 @@ mod use_self_in_pat { fn do_stuff(self) { match self { Self::Bar => unimplemented!(), + //~^ use_self Self::Baz => unimplemented!(), + //~^ use_self } match Some(1) { Some(_) => unimplemented!(), None => unimplemented!(), } if let Self::Bar = self { + //~^ use_self unimplemented!() } } @@ -571,16 +603,22 @@ mod issue8845 { fn get_value(&self) -> u8 { match self { Self::Num(n) => *n, + //~^ use_self Self::TupleNums(n, _m) => *n, + //~^ use_self Self::StructNums { one, two: _ } => *one, + //~^ use_self } } fn use_crate(&self) -> u8 { match self { Self::Num(n) => *n, + //~^ use_self Self::TupleNums(n, _m) => *n, + //~^ use_self Self::StructNums { one, two: _ } => *one, + //~^ use_self } } @@ -597,11 +635,13 @@ mod issue8845 { impl Foo { fn get_value(&self) -> u8 { let Self(x) = self; + //~^ use_self *x } fn use_crate(&self) -> u8 { let Self(x) = self; + //~^ use_self *x } } @@ -609,11 +649,13 @@ mod issue8845 { impl Bar { fn get_value(&self) -> u8 { let Self { x, .. } = self; + //~^ use_self *x } fn use_crate(&self) -> u8 { let Self { x, .. } = self; + //~^ use_self *x } } @@ -653,6 +695,7 @@ fn msrv_1_37() { fn foo(self) { match self { Self::A => {}, + //~^ use_self } } } @@ -667,3 +710,48 @@ mod issue_10371 { } } } + +mod issue_13092 { + use std::cell::RefCell; + macro_rules! macro_inner_item { + ($ty:ty) => { + fn foo(_: $ty) { + fn inner(_: $ty) {} + } + }; + } + + #[derive(Default)] + struct MyStruct; + + impl MyStruct { + macro_inner_item!(MyStruct); + } + + impl MyStruct { + thread_local! { + static SPECIAL: RefCell = RefCell::default(); + } + } +} + +mod crash_check_13128 { + struct A; + + impl A { + fn a() { + struct B; + + // pushes a NoCheck + impl Iterator for &B { + // Pops the NoCheck + type Item = A; + + // Lints A -> Self + fn next(&mut self) -> Option { + Some(A) + } + } + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index eb9d96168bcd1..b6376938611e7 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -21,16 +21,22 @@ mod use_self { impl Foo { fn new() -> Foo { + //~^ use_self Foo {} + //~^ use_self } fn test() -> Foo { + //~^ use_self Foo::new() + //~^ use_self } } impl Default for Foo { fn default() -> Foo { + //~^ use_self Foo::new() + //~^ use_self } } } @@ -72,6 +78,7 @@ mod lifetimes { } fn clone(&self) -> Foo<'a> { + //~^ use_self Foo { foo_str: self.foo_str } } @@ -105,6 +112,8 @@ mod existential { impl Foo { fn bad(foos: &[Foo]) -> impl Iterator { + //~^ use_self + //~| use_self foos.iter() } @@ -120,6 +129,7 @@ mod tuple_structs { impl TS { pub fn ts() -> Self { TS(0) + //~^ use_self } } } @@ -155,7 +165,9 @@ mod nesting { impl Bar { fn bar() -> Bar { + //~^ use_self Bar { foo: Foo {} } + //~^ use_self } } @@ -167,7 +179,9 @@ mod nesting { // Should lint here fn baz() -> Foo { + //~^ use_self Foo {} + //~^ use_self } } @@ -185,8 +199,11 @@ mod nesting { fn method2() { let _ = Enum::B(42); + //~^ use_self let _ = Enum::C { field: true }; + //~^ use_self let _ = Enum::A; + //~^ use_self } } } @@ -229,9 +246,12 @@ mod rustfix { fn fun_2() { nested::A::fun_1(); + //~^ use_self nested::A::A; + //~^ use_self nested::A {}; + //~^ use_self } } } @@ -251,6 +271,7 @@ mod issue3567 { impl Test for TestStruct { fn test() -> TestStruct { TestStruct::from_something() + //~^ use_self } } } @@ -265,11 +286,15 @@ mod paths_created_by_lowering { const B: usize = 1; async fn g() -> S { + //~^ use_self S {} + //~^ use_self } fn f<'a>(&self, p: &'a [u8]) -> &'a [u8] { &p[S::A..S::B] + //~^ use_self + //~| use_self } } @@ -293,7 +318,9 @@ mod generics { impl Foo { // `Self` is applicable here fn foo(value: T) -> Foo { + //~^ use_self Foo:: { value } + //~^ use_self } // `Cannot` use `Self` as a return type as the generic types are different @@ -466,6 +493,7 @@ mod nested_paths { impl A { fn test() -> Self { A::new::(submod::B {}) + //~^ use_self } } } @@ -503,6 +531,7 @@ mod issue7206 { impl<'a> S2> { fn new_again() -> Self { S2::new() + //~^ use_self } } } @@ -540,13 +569,16 @@ mod use_self_in_pat { fn do_stuff(self) { match self { Foo::Bar => unimplemented!(), + //~^ use_self Foo::Baz => unimplemented!(), + //~^ use_self } match Some(1) { Some(_) => unimplemented!(), None => unimplemented!(), } if let Foo::Bar = self { + //~^ use_self unimplemented!() } } @@ -571,16 +603,22 @@ mod issue8845 { fn get_value(&self) -> u8 { match self { Something::Num(n) => *n, + //~^ use_self Something::TupleNums(n, _m) => *n, + //~^ use_self Something::StructNums { one, two: _ } => *one, + //~^ use_self } } fn use_crate(&self) -> u8 { match self { crate::issue8845::Something::Num(n) => *n, + //~^ use_self crate::issue8845::Something::TupleNums(n, _m) => *n, + //~^ use_self crate::issue8845::Something::StructNums { one, two: _ } => *one, + //~^ use_self } } @@ -597,11 +635,13 @@ mod issue8845 { impl Foo { fn get_value(&self) -> u8 { let Foo(x) = self; + //~^ use_self *x } fn use_crate(&self) -> u8 { let crate::issue8845::Foo(x) = self; + //~^ use_self *x } } @@ -609,11 +649,13 @@ mod issue8845 { impl Bar { fn get_value(&self) -> u8 { let Bar { x, .. } = self; + //~^ use_self *x } fn use_crate(&self) -> u8 { let crate::issue8845::Bar { x, .. } = self; + //~^ use_self *x } } @@ -653,6 +695,7 @@ fn msrv_1_37() { fn foo(self) { match self { E::A => {}, + //~^ use_self } } } @@ -667,3 +710,48 @@ mod issue_10371 { } } } + +mod issue_13092 { + use std::cell::RefCell; + macro_rules! macro_inner_item { + ($ty:ty) => { + fn foo(_: $ty) { + fn inner(_: $ty) {} + } + }; + } + + #[derive(Default)] + struct MyStruct; + + impl MyStruct { + macro_inner_item!(MyStruct); + } + + impl MyStruct { + thread_local! { + static SPECIAL: RefCell = RefCell::default(); + } + } +} + +mod crash_check_13128 { + struct A; + + impl A { + fn a() { + struct B; + + // pushes a NoCheck + impl Iterator for &B { + // Pops the NoCheck + type Item = A; + + // Lints A -> Self + fn next(&mut self) -> Option { + Some(A) + } + } + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr index bd5b685b45d54..781327696ac19 100644 --- a/src/tools/clippy/tests/ui/use_self.stderr +++ b/src/tools/clippy/tests/ui/use_self.stderr @@ -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:24:13 + --> tests/ui/use_self.rs:25:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:26:22 + --> tests/ui/use_self.rs:28:22 | LL | fn test() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:27:13 + --> tests/ui/use_self.rs:30:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:32:25 + --> tests/ui/use_self.rs:36:25 | LL | fn default() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:33:13 + --> tests/ui/use_self.rs:38:13 | LL | Foo::new() | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:74:28 + --> tests/ui/use_self.rs:80:28 | LL | fn clone(&self) -> Foo<'a> { | ^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:107:24 + --> tests/ui/use_self.rs:114:24 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:107:55 + --> tests/ui/use_self.rs:114:55 | LL | fn bad(foos: &[Foo]) -> impl Iterator { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:122:13 + --> tests/ui/use_self.rs:131:13 | LL | TS(0) | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:157:29 + --> tests/ui/use_self.rs:167:29 | LL | fn bar() -> Bar { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:158:21 + --> tests/ui/use_self.rs:169:21 | LL | Bar { foo: Foo {} } | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:169:21 + --> tests/ui/use_self.rs:181:21 | LL | fn baz() -> Foo { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:170:13 + --> tests/ui/use_self.rs:183:13 | LL | Foo {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:187:21 + --> tests/ui/use_self.rs:201:21 | LL | let _ = Enum::B(42); | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:188:21 + --> tests/ui/use_self.rs:203:21 | LL | let _ = Enum::C { field: true }; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:189:21 + --> tests/ui/use_self.rs:205:21 | LL | let _ = Enum::A; | ^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:231:13 + --> tests/ui/use_self.rs:248:13 | LL | nested::A::fun_1(); | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:232:13 + --> tests/ui/use_self.rs:250:13 | LL | nested::A::A; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:234:13 + --> tests/ui/use_self.rs:253:13 | LL | nested::A {}; | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:253:13 + --> tests/ui/use_self.rs:273:13 | LL | TestStruct::from_something() | ^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:267:25 + --> tests/ui/use_self.rs:288:25 | LL | async fn g() -> S { | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:268:13 + --> tests/ui/use_self.rs:290:13 | LL | S {} | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:272:16 + --> tests/ui/use_self.rs:295:16 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:272:22 + --> tests/ui/use_self.rs:295:22 | LL | &p[S::A..S::B] | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:295:29 + --> tests/ui/use_self.rs:320:29 | LL | fn foo(value: T) -> Foo { | ^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:296:13 + --> tests/ui/use_self.rs:322:13 | LL | Foo:: { value } | ^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:468:13 + --> tests/ui/use_self.rs:495:13 | LL | A::new::(submod::B {}) | ^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:505:13 + --> tests/ui/use_self.rs:533:13 | LL | S2::new() | ^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:542:17 + --> tests/ui/use_self.rs:571:17 | LL | Foo::Bar => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:543:17 + --> tests/ui/use_self.rs:573:17 | LL | Foo::Baz => unimplemented!(), | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:549:20 + --> tests/ui/use_self.rs:580:20 | LL | if let Foo::Bar = self { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:573:17 + --> tests/ui/use_self.rs:605:17 | LL | Something::Num(n) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:574:17 + --> tests/ui/use_self.rs:607:17 | LL | Something::TupleNums(n, _m) => *n, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:575:17 + --> tests/ui/use_self.rs:609:17 | LL | Something::StructNums { one, two: _ } => *one, | ^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:581:17 + --> tests/ui/use_self.rs:616:17 | LL | crate::issue8845::Something::Num(n) => *n, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:582:17 + --> tests/ui/use_self.rs:618: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:583:17 + --> tests/ui/use_self.rs:620: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:599:17 + --> tests/ui/use_self.rs:637:17 | LL | let Foo(x) = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:604:17 + --> tests/ui/use_self.rs:643:17 | LL | let crate::issue8845::Foo(x) = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:611:17 + --> tests/ui/use_self.rs:651:17 | LL | let Bar { x, .. } = self; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:616:17 + --> tests/ui/use_self.rs:657:17 | LL | let crate::issue8845::Bar { x, .. } = self; | ^^^^^^^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self.rs:655:17 + --> tests/ui/use_self.rs:697:17 | LL | E::A => {}, | ^ help: use the applicable keyword: `Self` diff --git a/src/tools/clippy/tests/ui/use_self_trait.fixed b/src/tools/clippy/tests/ui/use_self_trait.fixed index 2758ec7aca1fd..c5d800dc94e18 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.fixed +++ b/src/tools/clippy/tests/ui/use_self_trait.fixed @@ -17,28 +17,42 @@ struct Bad; impl SelfTrait for Bad { fn refs(p1: &Self) -> &Self { + //~^ use_self + //~| use_self p1 } fn ref_refs<'a>(p1: &'a &'a Self) -> &'a &'a Self { + //~^ use_self + //~| use_self p1 } fn mut_refs(p1: &mut Self) -> &mut Self { + //~^ use_self + //~| use_self p1 } fn nested(_p1: Box, _p2: (&u8, &Self)) {} + //~^ use_self + //~| use_self fn vals(_: Self) -> Self { + //~^ use_self + //~| use_self Self + //~^ use_self } } impl Mul for Bad { type Output = Self; + //~^ use_self fn mul(self, rhs: Self) -> Self { + //~^ use_self + //~| use_self rhs } } @@ -46,6 +60,7 @@ impl Mul for Bad { impl Clone for Bad { fn clone(&self) -> Self { Self + //~^ use_self } } @@ -143,6 +158,8 @@ mod full_path_replacement { impl Error for std::fmt::Error { fn custom(_msg: T) -> Self { Self // Should lint + // + //~^^ use_self } } } diff --git a/src/tools/clippy/tests/ui/use_self_trait.rs b/src/tools/clippy/tests/ui/use_self_trait.rs index 31031e8f50b24..dcf5820afc26a 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.rs +++ b/src/tools/clippy/tests/ui/use_self_trait.rs @@ -17,28 +17,42 @@ struct Bad; impl SelfTrait for Bad { fn refs(p1: &Bad) -> &Bad { + //~^ use_self + //~| use_self p1 } fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { + //~^ use_self + //~| use_self p1 } fn mut_refs(p1: &mut Bad) -> &mut Bad { + //~^ use_self + //~| use_self p1 } fn nested(_p1: Box, _p2: (&u8, &Bad)) {} + //~^ use_self + //~| use_self fn vals(_: Bad) -> Bad { + //~^ use_self + //~| use_self Bad + //~^ use_self } } impl Mul for Bad { type Output = Bad; + //~^ use_self fn mul(self, rhs: Bad) -> Bad { + //~^ use_self + //~| use_self rhs } } @@ -46,6 +60,7 @@ impl Mul for Bad { impl Clone for Bad { fn clone(&self) -> Self { Bad + //~^ use_self } } @@ -143,6 +158,8 @@ mod full_path_replacement { impl Error for std::fmt::Error { fn custom(_msg: T) -> Self { std::fmt::Error // Should lint + // + //~^^ use_self } } } diff --git a/src/tools/clippy/tests/ui/use_self_trait.stderr b/src/tools/clippy/tests/ui/use_self_trait.stderr index 9cbb728ebe667..1b664b3b7a28f 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.stderr +++ b/src/tools/clippy/tests/ui/use_self_trait.stderr @@ -14,85 +14,85 @@ LL | fn refs(p1: &Bad) -> &Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:23:33 + --> tests/ui/use_self_trait.rs:25:33 | LL | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:23:49 + --> tests/ui/use_self_trait.rs:25:49 | LL | fn ref_refs<'a>(p1: &'a &'a Bad) -> &'a &'a Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:27:26 + --> tests/ui/use_self_trait.rs:31:26 | LL | fn mut_refs(p1: &mut Bad) -> &mut Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:27:39 + --> tests/ui/use_self_trait.rs:31:39 | LL | fn mut_refs(p1: &mut Bad) -> &mut Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:31:24 + --> tests/ui/use_self_trait.rs:37:24 | LL | fn nested(_p1: Box, _p2: (&u8, &Bad)) {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:31:42 + --> tests/ui/use_self_trait.rs:37:42 | LL | fn nested(_p1: Box, _p2: (&u8, &Bad)) {} | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:33:16 + --> tests/ui/use_self_trait.rs:41:16 | LL | fn vals(_: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:33:24 + --> tests/ui/use_self_trait.rs:41:24 | LL | fn vals(_: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:34:9 + --> tests/ui/use_self_trait.rs:44:9 | LL | Bad | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:39:19 + --> tests/ui/use_self_trait.rs:50:19 | LL | type Output = Bad; | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:41:23 + --> tests/ui/use_self_trait.rs:53:23 | LL | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:41:31 + --> tests/ui/use_self_trait.rs:53:31 | LL | fn mul(self, rhs: Bad) -> Bad { | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:48:9 + --> tests/ui/use_self_trait.rs:62:9 | LL | Bad | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition - --> tests/ui/use_self_trait.rs:145:13 + --> tests/ui/use_self_trait.rs:160:13 | LL | std::fmt::Error // Should lint | ^^^^^^^^^^^^^^^ help: use the applicable keyword: `Self` diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs index 84dccf28f3b22..3b063fd16be1e 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.rs +++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs @@ -21,12 +21,16 @@ macro_rules! test_macro { /// Tests that we lint if we use a binding with a single leading underscore fn prefix_underscore(_foo: u32) -> u32 { _foo + 1 + //~^ used_underscore_binding } /// Tests that we lint if we use a `_`-variable defined outside within a macro expansion fn in_macro_or_desugar(_foo: u32) { println!("{}", _foo); + //~^ used_underscore_binding assert_eq!(_foo, _foo); + //~^ used_underscore_binding + //~| used_underscore_binding test_macro!() + 1; } @@ -40,6 +44,7 @@ struct StructFieldTest { fn in_struct_field() { let mut s = StructFieldTest { _underscore_field: 0 }; s._underscore_field += 1; + //~^ used_underscore_binding } /// Tests that we do not lint if the struct field is used in code created with derive. @@ -101,6 +106,7 @@ async fn await_desugaring() { ({ let _i = 5; uses_i(_i); + //~^ used_underscore_binding foo() }) .await diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.stderr b/src/tools/clippy/tests/ui/used_underscore_binding.stderr index f9e8013d3ad57..7d94d79f9b3b5 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.stderr +++ b/src/tools/clippy/tests/ui/used_underscore_binding.stderr @@ -13,61 +13,61 @@ LL | fn prefix_underscore(_foo: u32) -> u32 { = help: to override `-D warnings` add `#[allow(clippy::used_underscore_binding)]` error: used underscore-prefixed binding - --> tests/ui/used_underscore_binding.rs:28:20 + --> tests/ui/used_underscore_binding.rs:29:20 | LL | println!("{}", _foo); | ^^^^ | note: binding is defined here - --> tests/ui/used_underscore_binding.rs:27:24 + --> tests/ui/used_underscore_binding.rs:28:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ error: used underscore-prefixed binding - --> tests/ui/used_underscore_binding.rs:29:16 + --> tests/ui/used_underscore_binding.rs:31:16 | LL | assert_eq!(_foo, _foo); | ^^^^ | note: binding is defined here - --> tests/ui/used_underscore_binding.rs:27:24 + --> tests/ui/used_underscore_binding.rs:28:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ error: used underscore-prefixed binding - --> tests/ui/used_underscore_binding.rs:29:22 + --> tests/ui/used_underscore_binding.rs:31:22 | LL | assert_eq!(_foo, _foo); | ^^^^ | note: binding is defined here - --> tests/ui/used_underscore_binding.rs:27:24 + --> tests/ui/used_underscore_binding.rs:28:24 | LL | fn in_macro_or_desugar(_foo: u32) { | ^^^^ error: used underscore-prefixed binding - --> tests/ui/used_underscore_binding.rs:42:5 + --> tests/ui/used_underscore_binding.rs:46:5 | LL | s._underscore_field += 1; | ^^^^^^^^^^^^^^^^^^^ | note: binding is defined here - --> tests/ui/used_underscore_binding.rs:36:5 + --> tests/ui/used_underscore_binding.rs:40:5 | LL | _underscore_field: u32, | ^^^^^^^^^^^^^^^^^^^^^^ error: used underscore-prefixed binding - --> tests/ui/used_underscore_binding.rs:103:16 + --> tests/ui/used_underscore_binding.rs:108:16 | LL | uses_i(_i); | ^^ | note: binding is defined here - --> tests/ui/used_underscore_binding.rs:102:13 + --> tests/ui/used_underscore_binding.rs:107:13 | LL | let _i = 5; | ^^ diff --git a/src/tools/clippy/tests/ui/used_underscore_items.rs b/src/tools/clippy/tests/ui/used_underscore_items.rs index 223016a5c9667..3401df6ae7438 100644 --- a/src/tools/clippy/tests/ui/used_underscore_items.rs +++ b/src/tools/clippy/tests/ui/used_underscore_items.rs @@ -41,16 +41,25 @@ mod a { fn main() { _foo1(); + //~^ used_underscore_items let _ = _foo2(); + //~^ used_underscore_items a::b::c::_foo3(); + //~^ used_underscore_items let _ = &_FooStruct {}; + //~^ used_underscore_items let _ = _FooStruct {}; + //~^ used_underscore_items let foo_struct = _FooStruct {}; + //~^ used_underscore_items foo_struct._method_call(); + //~^ used_underscore_items let foo_struct2 = a::b::c::_FooStruct2 {}; + //~^ used_underscore_items foo_struct2._method_call(); + //~^ used_underscore_items } // should not lint exteranl crate. @@ -61,3 +70,13 @@ fn external_item_call() { external_item::_exernal_foo(); } + +// should not lint foreign functions. +// issue #14156 +extern "C" { + pub fn _exit(code: i32) -> !; +} + +fn _f() { + unsafe { _exit(1) } +} diff --git a/src/tools/clippy/tests/ui/used_underscore_items.stderr b/src/tools/clippy/tests/ui/used_underscore_items.stderr index 93ac3a6fec6be..d6e23f1e726af 100644 --- a/src/tools/clippy/tests/ui/used_underscore_items.stderr +++ b/src/tools/clippy/tests/ui/used_underscore_items.stderr @@ -13,7 +13,7 @@ LL | fn _foo1() {} = help: to override `-D warnings` add `#[allow(clippy::used_underscore_items)]` error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:44:13 + --> tests/ui/used_underscore_items.rs:45:13 | LL | let _ = _foo2(); | ^^^^^^^ @@ -25,7 +25,7 @@ LL | fn _foo2() -> i32 { | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:45:5 + --> tests/ui/used_underscore_items.rs:47:5 | LL | a::b::c::_foo3(); | ^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | pub fn _foo3() {} | ^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:46:14 + --> tests/ui/used_underscore_items.rs:49:14 | LL | let _ = &_FooStruct {}; | ^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL | struct _FooStruct {} | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:47:13 + --> tests/ui/used_underscore_items.rs:51:13 | LL | let _ = _FooStruct {}; | ^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL | struct _FooStruct {} | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:49:22 + --> tests/ui/used_underscore_items.rs:54:22 | LL | let foo_struct = _FooStruct {}; | ^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | struct _FooStruct {} | ^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:50:5 + --> tests/ui/used_underscore_items.rs:56:5 | LL | foo_struct._method_call(); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | fn _method_call(self) {} | ^^^^^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:52:23 + --> tests/ui/used_underscore_items.rs:59:23 | LL | let foo_struct2 = a::b::c::_FooStruct2 {}; | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | pub struct _FooStruct2 {} | ^^^^^^^^^^^^^^^^^^^^^^ error: used underscore-prefixed item - --> tests/ui/used_underscore_items.rs:53:5 + --> tests/ui/used_underscore_items.rs:61:5 | LL | foo_struct2._method_call(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/useful_asref.rs b/src/tools/clippy/tests/ui/useful_asref.rs index d17db9371ee8d..a37c2785bde2a 100644 --- a/src/tools/clippy/tests/ui/useful_asref.rs +++ b/src/tools/clippy/tests/ui/useful_asref.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(clippy::useless_asref)] #![allow(clippy::needless_lifetimes)] diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index ddbb9255b4667..8c1f948fb5806 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -8,6 +8,7 @@ )] use std::fmt::Debug; +use std::ops::Deref; use std::rc::{Rc, Weak as RcWeak}; use std::sync::{Arc, Weak as ArcWeak}; @@ -48,14 +49,18 @@ fn not_ok() { { let rslice: &[i32] = &*mrslice; foo_rstr(rstr); + //~^ useless_asref foo_rstr(rstr); foo_rslice(rslice); + //~^ useless_asref foo_rslice(rslice); } { foo_mrslice(mrslice); + //~^ useless_asref foo_mrslice(mrslice); foo_rslice(mrslice); + //~^ useless_asref foo_rslice(mrslice); } @@ -63,19 +68,24 @@ fn not_ok() { let rrrrrstr = &&&&rstr; let rrrrrslice = &&&&&*mrslice; foo_rslice(rrrrrslice); + //~^ useless_asref foo_rslice(rrrrrslice); foo_rstr(rrrrrstr); + //~^ useless_asref foo_rstr(rrrrrstr); } { let mrrrrrslice = &mut &mut &mut &mut mrslice; foo_mrslice(mrrrrrslice); + //~^ useless_asref foo_mrslice(mrrrrrslice); foo_rslice(mrrrrrslice); + //~^ useless_asref foo_rslice(mrrrrrslice); } #[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)] foo_rrrrmr((&&&&MoreRef)); + //~^ useless_asref generic_not_ok(mrslice); generic_ok(mrslice); @@ -126,8 +136,10 @@ fn foo_rt(t: &T) { fn generic_not_ok + AsRef + Debug + ?Sized>(mrt: &mut T) { foo_mrt(mrt); + //~^ useless_asref foo_mrt(mrt); foo_rt(mrt); + //~^ useless_asref foo_rt(mrt); } @@ -139,11 +151,13 @@ fn generic_ok + AsRef + ?Sized, T: Debug + ?Sized>(mru: &mut U) { fn foo() { let x = Some(String::new()); let z = x.clone(); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + let z = x.clone(); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + let z = x.clone(); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref } mod issue12135 { @@ -167,16 +181,18 @@ mod issue12135 { pub fn f(x: &Struct) -> Option { x.field.clone(); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + x.field.clone(); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + x.field.clone(); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref // https://github.com/rust-lang/rust-clippy/pull/12136#discussion_r1451565223 #[allow(clippy::clone_on_copy)] Some(1).clone(); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref x.field.as_ref().map(|v| v.method().clone()) } @@ -198,6 +214,40 @@ fn issue_12528() { let _ = opt.as_ref().map(RcWeak::clone); } +fn issue_14088() { + let s = Some("foo"); + let _: Option<&str> = s.as_ref().map(|x| x.as_ref()); +} + +pub struct Wrap { + inner: T, +} + +impl Deref for Wrap { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +struct NonCloneableError; + +pub struct Issue12357 { + current: Option>>, +} + +impl Issue12357 { + fn f(&self) -> Option> { + self.current.as_ref().map(|p| Arc::clone(p)) + } + + fn g(&self) { + let result: Result = Ok("Hello".to_string()); + let cloned = result.as_ref().map(|s| s.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 b0405e930a259..d9db2d4f5596a 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -8,6 +8,7 @@ )] use std::fmt::Debug; +use std::ops::Deref; use std::rc::{Rc, Weak as RcWeak}; use std::sync::{Arc, Weak as ArcWeak}; @@ -48,14 +49,18 @@ fn not_ok() { { let rslice: &[i32] = &*mrslice; foo_rstr(rstr.as_ref()); + //~^ useless_asref foo_rstr(rstr); foo_rslice(rslice.as_ref()); + //~^ useless_asref foo_rslice(rslice); } { foo_mrslice(mrslice.as_mut()); + //~^ useless_asref foo_mrslice(mrslice); foo_rslice(mrslice.as_ref()); + //~^ useless_asref foo_rslice(mrslice); } @@ -63,19 +68,24 @@ fn not_ok() { let rrrrrstr = &&&&rstr; let rrrrrslice = &&&&&*mrslice; foo_rslice(rrrrrslice.as_ref()); + //~^ useless_asref foo_rslice(rrrrrslice); foo_rstr(rrrrrstr.as_ref()); + //~^ useless_asref foo_rstr(rrrrrstr); } { let mrrrrrslice = &mut &mut &mut &mut mrslice; foo_mrslice(mrrrrrslice.as_mut()); + //~^ useless_asref foo_mrslice(mrrrrrslice); foo_rslice(mrrrrrslice.as_ref()); + //~^ useless_asref foo_rslice(mrrrrrslice); } #[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)] foo_rrrrmr((&&&&MoreRef).as_ref()); + //~^ useless_asref generic_not_ok(mrslice); generic_ok(mrslice); @@ -126,8 +136,10 @@ fn foo_rt(t: &T) { fn generic_not_ok + AsRef + Debug + ?Sized>(mrt: &mut T) { foo_mrt(mrt.as_mut()); + //~^ useless_asref foo_mrt(mrt); foo_rt(mrt.as_ref()); + //~^ useless_asref foo_rt(mrt); } @@ -139,11 +151,13 @@ fn generic_ok + AsRef + ?Sized, T: Debug + ?Sized>(mru: &mut U) { fn foo() { let x = Some(String::new()); let z = x.as_ref().map(String::clone); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + let z = x.as_ref().map(|z| z.clone()); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + let z = x.as_ref().map(|z| String::clone(z)); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref } mod issue12135 { @@ -167,16 +181,18 @@ mod issue12135 { pub fn f(x: &Struct) -> Option { x.field.as_ref().map(|v| v.clone()); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + x.field.as_ref().map(Clone::clone); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref + x.field.as_ref().map(|v| Clone::clone(v)); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref // https://github.com/rust-lang/rust-clippy/pull/12136#discussion_r1451565223 #[allow(clippy::clone_on_copy)] Some(1).as_ref().map(|&x| x.clone()); - //~^ ERROR: this call to `as_ref.map(...)` does nothing + //~^ useless_asref x.field.as_ref().map(|v| v.method().clone()) } @@ -198,6 +214,40 @@ fn issue_12528() { let _ = opt.as_ref().map(RcWeak::clone); } +fn issue_14088() { + let s = Some("foo"); + let _: Option<&str> = s.as_ref().map(|x| x.as_ref()); +} + +pub struct Wrap { + inner: T, +} + +impl Deref for Wrap { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +struct NonCloneableError; + +pub struct Issue12357 { + current: Option>>, +} + +impl Issue12357 { + fn f(&self) -> Option> { + self.current.as_ref().map(|p| Arc::clone(p)) + } + + fn g(&self) { + let result: Result = Ok("Hello".to_string()); + let cloned = result.as_ref().map(|s| s.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 5f495c396705c..8255f5d9d2abe 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:50:18 + --> tests/ui/useless_asref.rs:51: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:52:20 + --> tests/ui/useless_asref.rs:54:20 | LL | foo_rslice(rslice.as_ref()); | ^^^^^^^^^^^^^^^ help: try: `rslice` error: this call to `as_mut` does nothing - --> tests/ui/useless_asref.rs:56:21 + --> tests/ui/useless_asref.rs:59:21 | LL | foo_mrslice(mrslice.as_mut()); | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:58:20 + --> tests/ui/useless_asref.rs:62:20 | LL | foo_rslice(mrslice.as_ref()); | ^^^^^^^^^^^^^^^^ help: try: `mrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:65:20 + --> tests/ui/useless_asref.rs:70:20 | LL | foo_rslice(rrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^ help: try: `rrrrrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:67:18 + --> tests/ui/useless_asref.rs:73:18 | LL | foo_rstr(rrrrrstr.as_ref()); | ^^^^^^^^^^^^^^^^^ help: try: `rrrrrstr` error: this call to `as_mut` does nothing - --> tests/ui/useless_asref.rs:72:21 + --> tests/ui/useless_asref.rs:79:21 | LL | foo_mrslice(mrrrrrslice.as_mut()); | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:74:20 + --> tests/ui/useless_asref.rs:82:20 | LL | foo_rslice(mrrrrrslice.as_ref()); | ^^^^^^^^^^^^^^^^^^^^ help: try: `mrrrrrslice` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:78:16 + --> tests/ui/useless_asref.rs:87:16 | LL | foo_rrrrmr((&&&&MoreRef).as_ref()); | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `(&&&&MoreRef)` error: this call to `as_mut` does nothing - --> tests/ui/useless_asref.rs:128:13 + --> tests/ui/useless_asref.rs:138:13 | LL | foo_mrt(mrt.as_mut()); | ^^^^^^^^^^^^ help: try: `mrt` error: this call to `as_ref` does nothing - --> tests/ui/useless_asref.rs:130:12 + --> tests/ui/useless_asref.rs:141:12 | LL | foo_rt(mrt.as_ref()); | ^^^^^^^^^^^^ help: try: `mrt` error: this call to `as_ref.map(...)` does nothing - --> tests/ui/useless_asref.rs:141:13 + --> tests/ui/useless_asref.rs:153: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:143:13 + --> tests/ui/useless_asref.rs:156: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:145:13 + --> tests/ui/useless_asref.rs:159: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:169:9 + --> tests/ui/useless_asref.rs:183: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:171:9 + --> tests/ui/useless_asref.rs:186: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:173:9 + --> tests/ui/useless_asref.rs:189: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:178:9 + --> tests/ui/useless_asref.rs:194:9 | LL | Some(1).as_ref().map(|&x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()` diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed index de1062f123b7b..a96c8f46f551f 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.fixed +++ b/src/tools/clippy/tests/ui/useless_attribute.fixed @@ -6,7 +6,9 @@ #![feature(rustc_private)] #![allow(dead_code)] +//~^ useless_attribute #![cfg_attr(clippy, allow(dead_code))] +//~^ useless_attribute #[rustfmt::skip] #[allow(unused_imports)] #[allow(unused_extern_crates)] @@ -18,6 +20,7 @@ extern crate proc_macro_derive; fn test_indented_attr() { #![allow(clippy::almost_swapped)] + //~^ useless_attribute use std::collections::HashSet; let _ = HashSet::::default(); diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs index 94657dd1ca378..b26410134bbb5 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.rs +++ b/src/tools/clippy/tests/ui/useless_attribute.rs @@ -6,7 +6,9 @@ #![feature(rustc_private)] #[allow(dead_code)] +//~^ useless_attribute #[cfg_attr(clippy, allow(dead_code))] +//~^ useless_attribute #[rustfmt::skip] #[allow(unused_imports)] #[allow(unused_extern_crates)] @@ -18,6 +20,7 @@ extern crate proc_macro_derive; fn test_indented_attr() { #[allow(clippy::almost_swapped)] + //~^ useless_attribute use std::collections::HashSet; let _ = HashSet::::default(); diff --git a/src/tools/clippy/tests/ui/useless_attribute.stderr b/src/tools/clippy/tests/ui/useless_attribute.stderr index 19f0e02de6808..91383adf994bf 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.stderr +++ b/src/tools/clippy/tests/ui/useless_attribute.stderr @@ -8,13 +8,13 @@ LL | #[allow(dead_code)] = help: to override `-D warnings` add `#[allow(clippy::useless_attribute)]` error: useless lint attribute - --> tests/ui/useless_attribute.rs:9:1 + --> tests/ui/useless_attribute.rs:10:1 | LL | #[cfg_attr(clippy, allow(dead_code))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![cfg_attr(clippy, allow(dead_code)` error: useless lint attribute - --> tests/ui/useless_attribute.rs:20:5 + --> tests/ui/useless_attribute.rs:22:5 | LL | #[allow(clippy::almost_swapped)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if you just forgot a `!`, use: `#![allow(clippy::almost_swapped)]` diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 697d437b3885c..489caacf21235 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -7,7 +7,9 @@ use std::ops::ControlFlow; fn test_generic(val: T) -> T { let _ = val; + //~^ useless_conversion val + //~^ useless_conversion } fn test_generic2 + Into, U: From>(val: T) { @@ -20,6 +22,7 @@ fn test_generic2 + Into, U: From>(val: T) { fn test_questionmark() -> Result<(), ()> { { let _: i32 = 0i32; + //~^ useless_conversion Ok(Ok(())) }??; Ok(()) @@ -50,28 +53,33 @@ fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let mut lines = text.lines(); if Some("ok") == lines.next() {} + //~^ useless_conversion } fn lint_into_iter_on_expr_implementing_iterator() { let text = "foo\r\nbar\n\nbaz\n"; let mut lines = text.lines(); + //~^ useless_conversion if Some("ok") == lines.next() {} } fn lint_into_iter_on_expr_implementing_iterator_2() { let text = "foo\r\nbar\n\nbaz\n"; if Some("ok") == text.lines().next() {} + //~^ useless_conversion } #[allow(const_item_mutation)] fn lint_into_iter_on_const_implementing_iterator() { const NUMBERS: std::ops::Range = 0..10; let _ = NUMBERS.next(); + //~^ useless_conversion } fn lint_into_iter_on_const_implementing_iterator_2() { const NUMBERS: std::ops::Range = 0..10; let mut n = NUMBERS; + //~^ useless_conversion n.next(); } @@ -134,27 +142,38 @@ fn main() { } let _: String = "foo".to_string(); + //~^ useless_conversion let _: String = "foo".to_string(); + //~^ useless_conversion let _ = "foo".to_string(); + //~^ useless_conversion let _ = format!("A: {:04}", 123); + //~^ useless_conversion let _ = "".lines(); + //~^ useless_conversion let _ = vec![1, 2, 3].into_iter(); + //~^ useless_conversion let _: String = format!("Hello {}", "world"); + //~^ useless_conversion // keep parentheses around `a + b` for suggestion (see #4750) let a: i32 = 1; let b: i32 = 1; let _ = (a + b) * 3; + //~^ useless_conversion // see #7205 let s: Foo<'a'> = Foo; let _: Foo<'b'> = s.into(); let s2: Foo<'a'> = Foo; let _: Foo<'a'> = s2; + //~^ useless_conversion let s3: Foo<'a'> = Foo; let _ = s3; + //~^ useless_conversion let s4: Foo<'a'> = Foo; let _ = vec![s4, s4, s4].into_iter(); + //~^ useless_conversion issue11300::bar(); } @@ -187,12 +206,17 @@ fn explicit_into_iter_fn_arg() { a(vec![1, 2].into_iter()); b(vec![1, 2]); + //~^ useless_conversion c(vec![1, 2]); + //~^ useless_conversion d(vec![1, 2]); + //~^ useless_conversion b([&1, &2, &3].into_iter().cloned()); b(vec![1, 2]); + //~^ useless_conversion b(vec![1, 2]); + //~^ useless_conversion macro_rules! macro_generated { () => { @@ -239,6 +263,7 @@ mod issue11300 { // This should trigger the lint, receiver type [i32; 3] also implements `Helper` foo2::([1, 2, 3]); + //~^ useless_conversion // This again should *not* lint, since X = () and I = std::array::IntoIter, // and `[i32; 3]: Helper<()>` is not true (only `std::array::IntoIter: Helper<()>` is). @@ -247,6 +272,7 @@ mod issue11300 { // This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`, // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary. foo3([1, 2, 3]); + //~^ useless_conversion } fn ice() { @@ -256,6 +282,7 @@ mod issue11300 { } S1.foo([1, 2]); + //~^ useless_conversion // ICE that occurred in itertools trait Itertools { @@ -275,6 +302,7 @@ mod issue11300 { let v0: Vec = vec![0, 2, 4]; let v1: Vec = vec![1, 3, 5, 7]; v0.into_iter().interleave_shortest(v1); + //~^ useless_conversion trait TraitWithLifetime<'a> {} impl<'a> TraitWithLifetime<'a> for std::array::IntoIter<&'a i32, 2> {} @@ -303,16 +331,20 @@ impl From> for Foo<'b'> { fn direct_application() { let _: Result<(), std::io::Error> = test_issue_3913(); //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913(); //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913(); //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913(); //~^ useless_conversion let c: ControlFlow<()> = ControlFlow::Continue(()); let _: ControlFlow<()> = c; //~^ useless_conversion + let c: ControlFlow<()> = ControlFlow::Continue(()); let _: ControlFlow<()> = c; //~^ useless_conversion diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 4d8ad61a8c995..4f3a3b00ea206 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -7,7 +7,9 @@ use std::ops::ControlFlow; fn test_generic(val: T) -> T { let _ = T::from(val); + //~^ useless_conversion val.into() + //~^ useless_conversion } fn test_generic2 + Into, U: From>(val: T) { @@ -20,6 +22,7 @@ fn test_generic2 + Into, U: From>(val: T) { fn test_questionmark() -> Result<(), ()> { { let _: i32 = 0i32.into(); + //~^ useless_conversion Ok(Ok(())) }??; Ok(()) @@ -50,28 +53,33 @@ fn lint_into_iter_on_mutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let mut lines = text.lines(); if Some("ok") == lines.into_iter().next() {} + //~^ useless_conversion } fn lint_into_iter_on_expr_implementing_iterator() { let text = "foo\r\nbar\n\nbaz\n"; let mut lines = text.lines().into_iter(); + //~^ useless_conversion if Some("ok") == lines.next() {} } fn lint_into_iter_on_expr_implementing_iterator_2() { let text = "foo\r\nbar\n\nbaz\n"; if Some("ok") == text.lines().into_iter().next() {} + //~^ useless_conversion } #[allow(const_item_mutation)] fn lint_into_iter_on_const_implementing_iterator() { const NUMBERS: std::ops::Range = 0..10; let _ = NUMBERS.into_iter().next(); + //~^ useless_conversion } fn lint_into_iter_on_const_implementing_iterator_2() { const NUMBERS: std::ops::Range = 0..10; let mut n = NUMBERS.into_iter(); + //~^ useless_conversion n.next(); } @@ -134,27 +142,38 @@ fn main() { } let _: String = "foo".to_string().into(); + //~^ useless_conversion let _: String = From::from("foo".to_string()); + //~^ useless_conversion let _ = String::from("foo".to_string()); + //~^ useless_conversion let _ = String::from(format!("A: {:04}", 123)); + //~^ useless_conversion let _ = "".lines().into_iter(); + //~^ useless_conversion let _ = vec![1, 2, 3].into_iter().into_iter(); + //~^ useless_conversion let _: String = format!("Hello {}", "world").into(); + //~^ useless_conversion // keep parentheses around `a + b` for suggestion (see #4750) let a: i32 = 1; let b: i32 = 1; let _ = i32::from(a + b) * 3; + //~^ useless_conversion // see #7205 let s: Foo<'a'> = Foo; let _: Foo<'b'> = s.into(); let s2: Foo<'a'> = Foo; let _: Foo<'a'> = s2.into(); + //~^ useless_conversion let s3: Foo<'a'> = Foo; let _ = Foo::<'a'>::from(s3); + //~^ useless_conversion let s4: Foo<'a'> = Foo; let _ = vec![s4, s4, s4].into_iter().into_iter(); + //~^ useless_conversion issue11300::bar(); } @@ -187,12 +206,17 @@ fn explicit_into_iter_fn_arg() { a(vec![1, 2].into_iter()); b(vec![1, 2].into_iter()); + //~^ useless_conversion c(vec![1, 2].into_iter()); + //~^ useless_conversion d(vec![1, 2].into_iter()); + //~^ useless_conversion b([&1, &2, &3].into_iter().cloned()); b(vec![1, 2].into_iter().into_iter()); + //~^ useless_conversion b(vec![1, 2].into_iter().into_iter().into_iter()); + //~^ useless_conversion macro_rules! macro_generated { () => { @@ -239,6 +263,7 @@ mod issue11300 { // This should trigger the lint, receiver type [i32; 3] also implements `Helper` foo2::([1, 2, 3].into_iter()); + //~^ useless_conversion // This again should *not* lint, since X = () and I = std::array::IntoIter, // and `[i32; 3]: Helper<()>` is not true (only `std::array::IntoIter: Helper<()>` is). @@ -247,6 +272,7 @@ mod issue11300 { // This should lint. Removing the `.into_iter()` means that `I` gets substituted with `[i32; 3]`, // and `i32: Helper2<[i32, 3]>` is true, so this call is indeed unnecessary. foo3([1, 2, 3].into_iter()); + //~^ useless_conversion } fn ice() { @@ -256,6 +282,7 @@ mod issue11300 { } S1.foo([1, 2].into_iter()); + //~^ useless_conversion // ICE that occurred in itertools trait Itertools { @@ -275,6 +302,7 @@ mod issue11300 { let v0: Vec = vec![0, 2, 4]; let v1: Vec = vec![1, 3, 5, 7]; v0.into_iter().interleave_shortest(v1.into_iter()); + //~^ useless_conversion trait TraitWithLifetime<'a> {} impl<'a> TraitWithLifetime<'a> for std::array::IntoIter<&'a i32, 2> {} @@ -303,16 +331,20 @@ impl From> for Foo<'b'> { fn direct_application() { let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); //~^ useless_conversion + let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); //~^ useless_conversion let c: ControlFlow<()> = ControlFlow::Continue(()); let _: ControlFlow<()> = c.map_break(Into::into); //~^ useless_conversion + let c: ControlFlow<()> = ControlFlow::Continue(()); let _: ControlFlow<()> = c.map_continue(Into::into); //~^ useless_conversion diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index ed50f3071862e..3cde2a786e466 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -11,115 +11,115 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:10:5 + --> tests/ui/useless_conversion.rs:11:5 | LL | val.into() | ^^^^^^^^^^ help: consider removing `.into()`: `val` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:22:22 + --> tests/ui/useless_conversion.rs:24:22 | LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:52:22 + --> tests/ui/useless_conversion.rs:55:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:57:21 + --> tests/ui/useless_conversion.rs:61:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:63:22 + --> tests/ui/useless_conversion.rs:68:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:69:13 + --> tests/ui/useless_conversion.rs:75:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range` - --> tests/ui/useless_conversion.rs:74:17 + --> tests/ui/useless_conversion.rs:81:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:136:21 + --> tests/ui/useless_conversion.rs:144:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:137:21 + --> tests/ui/useless_conversion.rs:146:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:138:13 + --> tests/ui/useless_conversion.rs:148:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:139:13 + --> tests/ui/useless_conversion.rs:150:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> tests/ui/useless_conversion.rs:140:13 + --> tests/ui/useless_conversion.rs:152:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter` - --> tests/ui/useless_conversion.rs:141:13 + --> tests/ui/useless_conversion.rs:154:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion.rs:142:21 + --> tests/ui/useless_conversion.rs:156:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> tests/ui/useless_conversion.rs:147:13 + --> tests/ui/useless_conversion.rs:162:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:153:23 + --> tests/ui/useless_conversion.rs:169:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> tests/ui/useless_conversion.rs:155:13 + --> tests/ui/useless_conversion.rs:172:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter>` - --> tests/ui/useless_conversion.rs:157:13 + --> tests/ui/useless_conversion.rs:175:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:189:7 + --> tests/ui/useless_conversion.rs:208:7 | LL | b(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -127,13 +127,13 @@ LL | b(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:179:13 + --> tests/ui/useless_conversion.rs:198:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:190:7 + --> tests/ui/useless_conversion.rs:210:7 | LL | c(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -141,13 +141,13 @@ LL | c(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:180:18 + --> tests/ui/useless_conversion.rs:199:18 | LL | fn c(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:191:7 + --> tests/ui/useless_conversion.rs:212:7 | LL | d(vec![1, 2].into_iter()); | ^^^^^^^^^^------------ @@ -155,13 +155,13 @@ LL | d(vec![1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:183:12 + --> tests/ui/useless_conversion.rs:202:12 | LL | T: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:194:7 + --> tests/ui/useless_conversion.rs:216:7 | LL | b(vec![1, 2].into_iter().into_iter()); | ^^^^^^^^^^------------------------ @@ -169,13 +169,13 @@ LL | b(vec![1, 2].into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:179:13 + --> tests/ui/useless_conversion.rs:198:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:195:7 + --> tests/ui/useless_conversion.rs:218:7 | LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | ^^^^^^^^^^------------------------------------ @@ -183,13 +183,13 @@ LL | b(vec![1, 2].into_iter().into_iter().into_iter()); | help: consider removing the `.into_iter()`s | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:179:13 + --> tests/ui/useless_conversion.rs:198:13 | LL | fn b>(_: T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:241:24 + --> tests/ui/useless_conversion.rs:265:24 | LL | foo2::([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -197,13 +197,13 @@ LL | foo2::([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:220:12 + --> tests/ui/useless_conversion.rs:244:12 | LL | I: IntoIterator + Helper, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:249:14 + --> tests/ui/useless_conversion.rs:274:14 | LL | foo3([1, 2, 3].into_iter()); | ^^^^^^^^^------------ @@ -211,13 +211,13 @@ LL | foo3([1, 2, 3].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:229:12 + --> tests/ui/useless_conversion.rs:253:12 | LL | I: IntoIterator, | ^^^^^^^^^^^^^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:258:16 + --> tests/ui/useless_conversion.rs:284:16 | LL | S1.foo([1, 2].into_iter()); | ^^^^^^------------ @@ -225,13 +225,13 @@ LL | S1.foo([1, 2].into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:255:27 + --> tests/ui/useless_conversion.rs:281:27 | LL | pub fn foo(&self, _: I) {} | ^^^^^^^^^^^^ error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:277:44 + --> tests/ui/useless_conversion.rs:304:44 | LL | v0.into_iter().interleave_shortest(v1.into_iter()); | ^^------------ @@ -239,67 +239,67 @@ LL | v0.into_iter().interleave_shortest(v1.into_iter()); | help: consider removing the `.into_iter()` | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:264:20 + --> tests/ui/useless_conversion.rs:291:20 | LL | J: IntoIterator, | ^^^^^^^^^^^^ error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:304:58 + --> tests/ui/useless_conversion.rs:332:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(Into::into); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:306:58 + --> tests/ui/useless_conversion.rs:335:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(Into::into); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:308:58 + --> tests/ui/useless_conversion.rs:338:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map(From::from); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `std::io::Error` - --> tests/ui/useless_conversion.rs:310:58 + --> tests/ui/useless_conversion.rs:341:58 | LL | let _: Result<(), std::io::Error> = test_issue_3913().map_err(From::from); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:314:31 + --> tests/ui/useless_conversion.rs:345:31 | LL | let _: ControlFlow<()> = c.map_break(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `()` - --> tests/ui/useless_conversion.rs:317:31 + --> tests/ui/useless_conversion.rs:349:31 | LL | let _: ControlFlow<()> = c.map_continue(Into::into); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `u32` - --> tests/ui/useless_conversion.rs:331:41 + --> tests/ui/useless_conversion.rs:363:41 | LL | let _: Vec = [1u32].into_iter().map(Into::into).collect(); | ^^^^^^^^^^^^^^^^ help: consider removing error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion.rs:342:18 + --> tests/ui/useless_conversion.rs:374:18 | LL | x.into_iter().map(Into::into).collect() | ^^^^^^^^^^^^^^^^ help: consider removing error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:358:29 + --> tests/ui/useless_conversion.rs:390:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:347:32 + --> tests/ui/useless_conversion.rs:379:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -310,13 +310,13 @@ LL + takes_into_iter(&self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:366:29 + --> tests/ui/useless_conversion.rs:398:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:347:32 + --> tests/ui/useless_conversion.rs:379:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -327,13 +327,13 @@ LL + takes_into_iter(&mut self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:375:29 + --> tests/ui/useless_conversion.rs:407:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:347:32 + --> tests/ui/useless_conversion.rs:379:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -344,13 +344,13 @@ LL + takes_into_iter(*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:384:29 + --> tests/ui/useless_conversion.rs:416:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:347:32 + --> tests/ui/useless_conversion.rs:379:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -361,13 +361,13 @@ LL + takes_into_iter(&*self.my_field); | error: explicit call to `.into_iter()` in function argument accepting `IntoIterator` - --> tests/ui/useless_conversion.rs:393:29 + --> tests/ui/useless_conversion.rs:425:29 | LL | takes_into_iter(self.my_field.into_iter()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()` - --> tests/ui/useless_conversion.rs:347:32 + --> tests/ui/useless_conversion.rs:379:32 | LL | fn takes_into_iter(_: impl IntoIterator) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.rs b/src/tools/clippy/tests/ui/useless_conversion_try.rs index 23edeae12b83a..d16506d94aa3c 100644 --- a/src/tools/clippy/tests/ui/useless_conversion_try.rs +++ b/src/tools/clippy/tests/ui/useless_conversion_try.rs @@ -7,9 +7,10 @@ fn test_generic(val: T) -> T { let _ = T::try_from(val).unwrap(); - //~^ ERROR: useless conversion to the same type: `T` + //~^ useless_conversion + val.try_into().unwrap() - //~^ ERROR: useless conversion to the same type: `T` + //~^ useless_conversion } fn test_generic2 + Into, U: From>(val: T) { @@ -32,19 +33,25 @@ fn main() { let _: String = "foo".try_into().unwrap(); } let _: String = "foo".to_string().try_into().unwrap(); - //~^ ERROR: useless conversion to the same type: `std::string::String` + //~^ useless_conversion + let _: String = TryFrom::try_from("foo".to_string()).unwrap(); - //~^ ERROR: useless conversion to the same type: `std::string::String` + //~^ useless_conversion + let _ = String::try_from("foo".to_string()).unwrap(); - //~^ ERROR: useless conversion to the same type: `std::string::String` + //~^ useless_conversion + let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); - //~^ ERROR: useless conversion to the same type: `std::string::String` + //~^ useless_conversion + let _: String = format!("Hello {}", "world").try_into().unwrap(); - //~^ ERROR: useless conversion to the same type: `std::string::String` + //~^ useless_conversion + let _: String = String::new().try_into().unwrap(); - //~^ ERROR: useless conversion to the same type: `std::string::String` + //~^ useless_conversion + let _: String = match String::from("_").try_into() { - //~^ ERROR: useless conversion to the same type: `std::string::String` + //~^ useless_conversion Ok(a) => a, Err(_) => String::new(), }; diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.stderr b/src/tools/clippy/tests/ui/useless_conversion_try.stderr index 30a43629dbd6a..1c62426c89526 100644 --- a/src/tools/clippy/tests/ui/useless_conversion_try.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion_try.stderr @@ -12,7 +12,7 @@ LL | #![deny(clippy::useless_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: useless conversion to the same type: `T` - --> tests/ui/useless_conversion_try.rs:11:5 + --> tests/ui/useless_conversion_try.rs:12:5 | LL | val.try_into().unwrap() | ^^^^^^^^^^^^^^ @@ -20,7 +20,7 @@ LL | val.try_into().unwrap() = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:34:21 + --> tests/ui/useless_conversion_try.rs:35:21 | LL | let _: String = "foo".to_string().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,7 +28,7 @@ LL | let _: String = "foo".to_string().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:36:21 + --> tests/ui/useless_conversion_try.rs:38:21 | LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | let _: String = TryFrom::try_from("foo".to_string()).unwrap(); = help: consider removing `TryFrom::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:38:13 + --> tests/ui/useless_conversion_try.rs:41:13 | LL | let _ = String::try_from("foo".to_string()).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | let _ = String::try_from("foo".to_string()).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:40:13 + --> tests/ui/useless_conversion_try.rs:44:13 | LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -52,7 +52,7 @@ LL | let _ = String::try_from(format!("A: {:04}", 123)).unwrap(); = help: consider removing `String::try_from()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:42:21 + --> tests/ui/useless_conversion_try.rs:47:21 | LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -60,7 +60,7 @@ LL | let _: String = format!("Hello {}", "world").try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:44:21 + --> tests/ui/useless_conversion_try.rs:50:21 | LL | let _: String = String::new().try_into().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL | let _: String = String::new().try_into().unwrap(); = help: consider removing `.try_into()` error: useless conversion to the same type: `std::string::String` - --> tests/ui/useless_conversion_try.rs:46:27 + --> tests/ui/useless_conversion_try.rs:53:27 | LL | let _: String = match String::from("_").try_into() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.fixed b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.fixed index 03b34afa54ec9..f7f60bbe3f8dc 100644 --- a/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.fixed +++ b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.fixed @@ -5,7 +5,7 @@ use std::num::{NonZero, NonZeroUsize}; #[clippy::msrv = "1.83"] const fn func() -> NonZeroUsize { const { NonZeroUsize::new(3).unwrap() } - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked } #[clippy::msrv = "1.82"] @@ -35,17 +35,17 @@ macro_rules! nzu { fn main() { const _A: NonZeroUsize = NonZeroUsize::new(3).unwrap(); - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked static _B: NonZero = NonZero::::new(42).unwrap(); - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked const _C: usize = unsafe { NonZeroUsize::new(3).unwrap().get() }; - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked const AUX: usize = 3; const _D: NonZeroUsize = NonZeroUsize::new(AUX).unwrap(); - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked const _X: NonZeroUsize = uns!(NonZeroUsize::new_unchecked(3)); const _Y: NonZeroUsize = unsafe { nzu!() }; diff --git a/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.rs b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.rs index d450e3a03ec58..c90a63915efb8 100644 --- a/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.rs +++ b/src/tools/clippy/tests/ui/useless_nonzero_new_unchecked.rs @@ -5,7 +5,7 @@ use std::num::{NonZero, NonZeroUsize}; #[clippy::msrv = "1.83"] const fn func() -> NonZeroUsize { const { unsafe { NonZeroUsize::new_unchecked(3) } } - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked } #[clippy::msrv = "1.82"] @@ -35,17 +35,17 @@ macro_rules! nzu { fn main() { const _A: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(3) }; - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked static _B: NonZero = unsafe { NonZero::::new_unchecked(42) }; - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked const _C: usize = unsafe { NonZeroUsize::new_unchecked(3).get() }; - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked const AUX: usize = 3; const _D: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(AUX) }; - //~^ ERROR: `Option::unwrap()` can be safely used in a `const` context + //~^ useless_nonzero_new_unchecked const _X: NonZeroUsize = uns!(NonZeroUsize::new_unchecked(3)); const _Y: NonZeroUsize = unsafe { nzu!() }; diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed index 9e755a82af45f..f360a8afadf61 100644 --- a/src/tools/clippy/tests/ui/vec.fixed +++ b/src/tools/clippy/tests/ui/vec.fixed @@ -28,24 +28,34 @@ impl Line { fn main() { on_slice(&[]); + //~^ useless_vec on_slice(&[]); on_mut_slice(&mut []); + //~^ useless_vec on_slice(&[1, 2]); + //~^ useless_vec on_slice(&[1, 2]); on_mut_slice(&mut [1, 2]); + //~^ useless_vec on_slice(&[1, 2]); + //~^ useless_vec on_slice(&[1, 2]); on_mut_slice(&mut [1, 2]); + //~^ useless_vec #[rustfmt::skip] on_slice(&[1, 2]); + //~^ useless_vec on_slice(&[1, 2]); on_mut_slice(&mut [1, 2]); + //~^ useless_vec on_slice(&[1; 2]); + //~^ useless_vec on_slice(&[1; 2]); on_mut_slice(&mut [1; 2]); + //~^ useless_vec on_vec(&vec![]); on_vec(&vec![1, 2]); @@ -72,17 +82,21 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 let _x: i32 = [1, 2, 3].iter().sum(); + //~^ useless_vec // Do lint let mut x = [1, 2, 3]; + //~^ useless_vec x.fill(123); dbg!(x[0]); dbg!(x.len()); dbg!(x.iter().sum::()); let _x: &[i32] = &[1, 2, 3]; + //~^ useless_vec for _ in [1, 2, 3] {} + //~^ useless_vec // Don't lint let x = vec![1, 2, 3]; @@ -122,6 +136,7 @@ fn issue11075() { } #[allow(clippy::never_loop)] for _string in [repro!(true), repro!(null)] { + //~^ useless_vec unimplemented!(); } @@ -139,6 +154,8 @@ fn issue11075() { } in_macro!(1, [1, 2], [1; 2]); + //~^ useless_vec + //~| useless_vec macro_rules! from_macro { () => { @@ -158,10 +175,12 @@ fn issue11075() { #[clippy::msrv = "1.53"] fn above() { for a in [1, 2, 3] { + //~^ useless_vec let _: usize = a; } for a in [String::new(), String::new()] { + //~^ useless_vec let _: String = a; } } @@ -193,7 +212,8 @@ fn issue11861() { // Do not lint the next line this_macro_needs_vec!(vec![1]); - this_macro_doesnt_need_vec!([1]); //~ ERROR: useless use of `vec!` + this_macro_doesnt_need_vec!([1]); + //~^ useless_vec macro_rules! m { ($x:expr) => { @@ -220,4 +240,5 @@ fn issue_11958() { fn issue_12101() { for a in &[1, 2] {} + //~^ useless_vec } diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs index c483271438b1f..a779d33557cb4 100644 --- a/src/tools/clippy/tests/ui/vec.rs +++ b/src/tools/clippy/tests/ui/vec.rs @@ -28,24 +28,34 @@ impl Line { fn main() { on_slice(&vec![]); + //~^ useless_vec on_slice(&[]); on_mut_slice(&mut vec![]); + //~^ useless_vec on_slice(&vec![1, 2]); + //~^ useless_vec on_slice(&[1, 2]); on_mut_slice(&mut vec![1, 2]); + //~^ useless_vec on_slice(&vec![1, 2]); + //~^ useless_vec on_slice(&[1, 2]); on_mut_slice(&mut vec![1, 2]); + //~^ useless_vec #[rustfmt::skip] on_slice(&vec!(1, 2)); + //~^ useless_vec on_slice(&[1, 2]); on_mut_slice(&mut vec![1, 2]); + //~^ useless_vec on_slice(&vec![1; 2]); + //~^ useless_vec on_slice(&[1; 2]); on_mut_slice(&mut vec![1; 2]); + //~^ useless_vec on_vec(&vec![]); on_vec(&vec![1, 2]); @@ -72,17 +82,21 @@ fn main() { // https://github.com/rust-lang/rust-clippy/issues/2262#issuecomment-783979246 let _x: i32 = vec![1, 2, 3].iter().sum(); + //~^ useless_vec // Do lint let mut x = vec![1, 2, 3]; + //~^ useless_vec x.fill(123); dbg!(x[0]); dbg!(x.len()); dbg!(x.iter().sum::()); let _x: &[i32] = &vec![1, 2, 3]; + //~^ useless_vec for _ in vec![1, 2, 3] {} + //~^ useless_vec // Don't lint let x = vec![1, 2, 3]; @@ -122,6 +136,7 @@ fn issue11075() { } #[allow(clippy::never_loop)] for _string in vec![repro!(true), repro!(null)] { + //~^ useless_vec unimplemented!(); } @@ -139,6 +154,8 @@ fn issue11075() { } in_macro!(1, vec![1, 2], vec![1; 2]); + //~^ useless_vec + //~| useless_vec macro_rules! from_macro { () => { @@ -158,10 +175,12 @@ fn issue11075() { #[clippy::msrv = "1.53"] fn above() { for a in vec![1, 2, 3] { + //~^ useless_vec let _: usize = a; } for a in vec![String::new(), String::new()] { + //~^ useless_vec let _: String = a; } } @@ -193,7 +212,8 @@ fn issue11861() { // Do not lint the next line this_macro_needs_vec!(vec![1]); - this_macro_doesnt_need_vec!(vec![1]); //~ ERROR: useless use of `vec!` + this_macro_doesnt_need_vec!(vec![1]); + //~^ useless_vec macro_rules! m { ($x:expr) => { @@ -220,4 +240,5 @@ fn issue_11958() { fn issue_12101() { for a in &(vec![1, 2]) {} + //~^ useless_vec } diff --git a/src/tools/clippy/tests/ui/vec.stderr b/src/tools/clippy/tests/ui/vec.stderr index 3faea8033fe2c..806d6617200ff 100644 --- a/src/tools/clippy/tests/ui/vec.stderr +++ b/src/tools/clippy/tests/ui/vec.stderr @@ -8,121 +8,121 @@ LL | on_slice(&vec![]); = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]` error: useless use of `vec!` - --> tests/ui/vec.rs:32:18 + --> tests/ui/vec.rs:33:18 | LL | on_mut_slice(&mut vec![]); | ^^^^^^^^^^^ help: you can use a slice directly: `&mut []` error: useless use of `vec!` - --> tests/ui/vec.rs:34:14 + --> tests/ui/vec.rs:36:14 | LL | on_slice(&vec![1, 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:36:18 + --> tests/ui/vec.rs:39:18 | LL | on_mut_slice(&mut vec![1, 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:38:14 + --> tests/ui/vec.rs:42:14 | LL | on_slice(&vec![1, 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:40:18 + --> tests/ui/vec.rs:45:18 | LL | on_mut_slice(&mut vec![1, 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:42:14 + --> tests/ui/vec.rs:48:14 | LL | on_slice(&vec!(1, 2)); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:44:18 + --> tests/ui/vec.rs:51:18 | LL | on_mut_slice(&mut vec![1, 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1, 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:46:14 + --> tests/ui/vec.rs:54:14 | LL | on_slice(&vec![1; 2]); | ^^^^^^^^^^^ help: you can use a slice directly: `&[1; 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:48:18 + --> tests/ui/vec.rs:57:18 | LL | on_mut_slice(&mut vec![1; 2]); | ^^^^^^^^^^^^^^^ help: you can use a slice directly: `&mut [1; 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:74:19 + --> tests/ui/vec.rs:84:19 | LL | let _x: i32 = vec![1, 2, 3].iter().sum(); | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` error: useless use of `vec!` - --> tests/ui/vec.rs:77:17 + --> tests/ui/vec.rs:88:17 | LL | let mut x = vec![1, 2, 3]; | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` error: useless use of `vec!` - --> tests/ui/vec.rs:83:22 + --> tests/ui/vec.rs:95:22 | LL | let _x: &[i32] = &vec![1, 2, 3]; | ^^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2, 3]` error: useless use of `vec!` - --> tests/ui/vec.rs:85:14 + --> tests/ui/vec.rs:98:14 | LL | for _ in vec![1, 2, 3] {} | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` error: useless use of `vec!` - --> tests/ui/vec.rs:124:20 + --> tests/ui/vec.rs:138:20 | LL | for _string in vec![repro!(true), repro!(null)] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[repro!(true), repro!(null)]` error: useless use of `vec!` - --> tests/ui/vec.rs:141:18 + --> tests/ui/vec.rs:156:18 | LL | in_macro!(1, vec![1, 2], vec![1; 2]); | ^^^^^^^^^^ help: you can use an array directly: `[1, 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:141:30 + --> tests/ui/vec.rs:156:30 | LL | in_macro!(1, vec![1, 2], vec![1; 2]); | ^^^^^^^^^^ help: you can use an array directly: `[1; 2]` error: useless use of `vec!` - --> tests/ui/vec.rs:160:14 + --> tests/ui/vec.rs:177:14 | LL | for a in vec![1, 2, 3] { | ^^^^^^^^^^^^^ help: you can use an array directly: `[1, 2, 3]` error: useless use of `vec!` - --> tests/ui/vec.rs:164:14 + --> tests/ui/vec.rs:182:14 | LL | for a in vec![String::new(), String::new()] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can use an array directly: `[String::new(), String::new()]` error: useless use of `vec!` - --> tests/ui/vec.rs:196:33 + --> tests/ui/vec.rs:215:33 | LL | this_macro_doesnt_need_vec!(vec![1]); | ^^^^^^^ help: you can use an array directly: `[1]` error: useless use of `vec!` - --> tests/ui/vec.rs:222:14 + --> tests/ui/vec.rs:242:14 | LL | for a in &(vec![1, 2]) {} | ^^^^^^^^^^^^^ help: you can use a slice directly: `&[1, 2]` diff --git a/src/tools/clippy/tests/ui/vec_box_sized.rs b/src/tools/clippy/tests/ui/vec_box_sized.rs index 49eaf8e062af3..897add423b6d4 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.rs +++ b/src/tools/clippy/tests/ui/vec_box_sized.rs @@ -24,22 +24,30 @@ unsafe impl Allocator for DummyAllocator { mod should_trigger { use super::{DummyAllocator, SizedStruct}; const C: Vec> = Vec::new(); + //~^ vec_box static S: Vec> = Vec::new(); + //~^ vec_box struct StructWithVecBox { sized_type: Vec>, + //~^ vec_box } struct A(Vec>); + //~^ vec_box struct B(Vec>>); + //~^ vec_box fn allocator_global_defined_vec() -> Vec, std::alloc::Global> { + //~^ vec_box Vec::new() } fn allocator_global_defined_box() -> Vec> { + //~^ vec_box Vec::new() } fn allocator_match() -> Vec, DummyAllocator> { + //~^ vec_box Vec::new_in(DummyAllocator) } } @@ -77,6 +85,7 @@ mod inner_mod { use super::inner::S; pub fn f() -> Vec> { + //~^ vec_box vec![] } } diff --git a/src/tools/clippy/tests/ui/vec_box_sized.stderr b/src/tools/clippy/tests/ui/vec_box_sized.stderr index 0ffcc83143402..65db267977a6f 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.stderr +++ b/src/tools/clippy/tests/ui/vec_box_sized.stderr @@ -8,49 +8,49 @@ LL | const C: Vec> = Vec::new(); = help: to override `-D warnings` add `#[allow(clippy::vec_box)]` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:27:15 + --> tests/ui/vec_box_sized.rs:28:15 | LL | static S: Vec> = Vec::new(); | ^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:30:21 + --> tests/ui/vec_box_sized.rs:32:21 | LL | sized_type: Vec>, | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:33:14 + --> tests/ui/vec_box_sized.rs:36:14 | LL | struct A(Vec>); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:34:18 + --> tests/ui/vec_box_sized.rs:38:18 | LL | struct B(Vec>>); | ^^^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:36:42 + --> tests/ui/vec_box_sized.rs:41:42 | LL | fn allocator_global_defined_vec() -> Vec, std::alloc::Global> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:39:42 + --> tests/ui/vec_box_sized.rs:45:42 | LL | fn allocator_global_defined_box() -> Vec> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:42:29 + --> tests/ui/vec_box_sized.rs:49:29 | LL | fn allocator_match() -> Vec, DummyAllocator> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Vec` error: `Vec` is already on the heap, the boxing is unnecessary - --> tests/ui/vec_box_sized.rs:79:23 + --> tests/ui/vec_box_sized.rs:87:23 | LL | pub fn f() -> Vec> { | ^^^^^^^^^^^ help: try: `Vec` diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.rs b/src/tools/clippy/tests/ui/vec_init_then_push.rs index 1c60a75c56ae0..a32187edfea61 100644 --- a/src/tools/clippy/tests/ui/vec_init_then_push.rs +++ b/src/tools/clippy/tests/ui/vec_init_then_push.rs @@ -3,16 +3,18 @@ //@no-rustfix fn main() { let mut def_err: Vec = Default::default(); - //~^ ERROR: calls to `push` immediately after creation - //~| NOTE: `-D clippy::vec-init-then-push` implied by `-D warnings` + //~^ vec_init_then_push + def_err.push(0); let mut new_err = Vec::::new(); - //~^ ERROR: calls to `push` immediately after creation + //~^ vec_init_then_push + new_err.push(1); let mut cap_err = Vec::with_capacity(2); - //~^ ERROR: calls to `push` immediately after creation + //~^ vec_init_then_push + cap_err.push(0); cap_err.push(1); cap_err.push(2); @@ -25,7 +27,8 @@ fn main() { cap_ok.push(0); new_err = Vec::new(); - //~^ ERROR: calls to `push` immediately after creation + //~^ vec_init_then_push + new_err.push(0); let mut vec = Vec::new(); @@ -76,7 +79,8 @@ fn _cond_push(x: bool) -> Vec { fn _push_then_edit(x: u32) -> Vec { let mut v = Vec::new(); - //~^ ERROR: calls to `push` immediately after creation + //~^ vec_init_then_push + v.push(x); v.push(1); v[0] = v[1] + 5; @@ -85,7 +89,8 @@ fn _push_then_edit(x: u32) -> Vec { fn _cond_push_with_large_start(x: bool) -> Vec { let mut v = Vec::new(); - //~^ ERROR: calls to `push` immediately after creation + //~^ vec_init_then_push + v.push(0); v.push(1); v.push(0); @@ -99,7 +104,8 @@ fn _cond_push_with_large_start(x: bool) -> Vec { } let mut v2 = Vec::new(); - //~^ ERROR: calls to `push` immediately after creation + //~^ vec_init_then_push + v2.push(0); v2.push(1); v2.push(0); @@ -115,7 +121,8 @@ fn _cond_push_with_large_start(x: bool) -> Vec { fn f() { let mut v = Vec::new(); - //~^ ERROR: calls to `push` immediately after creation + //~^ vec_init_then_push + v.push((0i32, 0i32)); let y = v[0].0.abs(); } diff --git a/src/tools/clippy/tests/ui/vec_init_then_push.stderr b/src/tools/clippy/tests/ui/vec_init_then_push.stderr index f35625c9b0859..1900ad7bd6a0e 100644 --- a/src/tools/clippy/tests/ui/vec_init_then_push.stderr +++ b/src/tools/clippy/tests/ui/vec_init_then_push.stderr @@ -13,66 +13,68 @@ error: calls to `push` immediately after creation --> tests/ui/vec_init_then_push.rs:10:5 | LL | / let mut new_err = Vec::::new(); -LL | | +... | LL | | new_err.push(1); | |____________________^ help: consider using the `vec![]` macro: `let mut new_err = vec![..];` error: calls to `push` immediately after creation - --> tests/ui/vec_init_then_push.rs:14:5 + --> tests/ui/vec_init_then_push.rs:15:5 | LL | / let mut cap_err = Vec::with_capacity(2); LL | | +LL | | LL | | cap_err.push(0); LL | | cap_err.push(1); LL | | cap_err.push(2); | |____________________^ help: consider using the `vec![]` macro: `let mut cap_err = vec![..];` error: calls to `push` immediately after creation - --> tests/ui/vec_init_then_push.rs:27:5 + --> tests/ui/vec_init_then_push.rs:29:5 | LL | / new_err = Vec::new(); -LL | | +... | LL | | new_err.push(0); | |____________________^ help: consider using the `vec![]` macro: `new_err = vec![..];` error: calls to `push` immediately after creation - --> tests/ui/vec_init_then_push.rs:78:5 + --> tests/ui/vec_init_then_push.rs:81:5 | LL | / let mut v = Vec::new(); LL | | +LL | | LL | | v.push(x); LL | | v.push(1); | |______________^ help: consider using the `vec![]` macro: `let mut v = vec![..];` error: calls to `push` immediately after creation - --> tests/ui/vec_init_then_push.rs:87:5 + --> tests/ui/vec_init_then_push.rs:91:5 | LL | / let mut v = Vec::new(); LL | | +LL | | LL | | v.push(0); -LL | | v.push(1); ... | LL | | v.push(1); LL | | v.push(0); | |______________^ help: consider using the `vec![]` macro: `let mut v = vec![..];` error: calls to `push` immediately after creation - --> tests/ui/vec_init_then_push.rs:101:5 + --> tests/ui/vec_init_then_push.rs:106:5 | LL | / let mut v2 = Vec::new(); LL | | +LL | | LL | | v2.push(0); -LL | | v2.push(1); ... | LL | | v2.push(1); LL | | v2.push(0); | |_______________^ help: consider using the `vec![]` macro: `let mut v2 = vec![..];` error: calls to `push` immediately after creation - --> tests/ui/vec_init_then_push.rs:117:5 + --> tests/ui/vec_init_then_push.rs:123:5 | LL | / let mut v = Vec::new(); -LL | | +... | LL | | v.push((0i32, 0i32)); | |_________________________^ help: consider using the `vec![]` macro: `let v = vec![..];` diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.fixed b/src/tools/clippy/tests/ui/vec_resize_to_zero.fixed index b4c2d8209e763..260943f655e3e 100644 --- a/src/tools/clippy/tests/ui/vec_resize_to_zero.fixed +++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.fixed @@ -5,7 +5,7 @@ fn main() { // applicable here v.clear(); - //~^ ERROR: emptying a vector with `resize` + //~^ vec_resize_to_zero // not applicable v.resize(2, 5); diff --git a/src/tools/clippy/tests/ui/vec_resize_to_zero.rs b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs index 5b11c940f21a7..d6054715143c0 100644 --- a/src/tools/clippy/tests/ui/vec_resize_to_zero.rs +++ b/src/tools/clippy/tests/ui/vec_resize_to_zero.rs @@ -5,7 +5,7 @@ fn main() { // applicable here v.resize(0, 5); - //~^ ERROR: emptying a vector with `resize` + //~^ vec_resize_to_zero // not applicable v.resize(2, 5); diff --git a/src/tools/clippy/tests/ui/verbose_file_reads.rs b/src/tools/clippy/tests/ui/verbose_file_reads.rs index 9dd4f4e1d9bef..374cd39df947b 100644 --- a/src/tools/clippy/tests/ui/verbose_file_reads.rs +++ b/src/tools/clippy/tests/ui/verbose_file_reads.rs @@ -21,10 +21,12 @@ fn main() -> std::io::Result<()> { let mut f = File::open(path)?; let mut buffer = Vec::new(); f.read_to_end(&mut buffer)?; - //~^ ERROR: use of `File::read_to_end` + //~^ verbose_file_reads + // ...and this let mut string_buffer = String::new(); f.read_to_string(&mut string_buffer)?; - //~^ ERROR: use of `File::read_to_string` + //~^ verbose_file_reads + Ok(()) } diff --git a/src/tools/clippy/tests/ui/verbose_file_reads.stderr b/src/tools/clippy/tests/ui/verbose_file_reads.stderr index e85068fc7a9c7..9e6f6788562ff 100644 --- a/src/tools/clippy/tests/ui/verbose_file_reads.stderr +++ b/src/tools/clippy/tests/ui/verbose_file_reads.stderr @@ -9,7 +9,7 @@ LL | f.read_to_end(&mut buffer)?; = help: to override `-D warnings` add `#[allow(clippy::verbose_file_reads)]` error: use of `File::read_to_string` - --> tests/ui/verbose_file_reads.rs:27:5 + --> tests/ui/verbose_file_reads.rs:28:5 | LL | f.read_to_string(&mut string_buffer)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.fixed b/src/tools/clippy/tests/ui/waker_clone_wake.fixed index 9c02b9a90fdd0..d7b5000a5d504 100644 --- a/src/tools/clippy/tests/ui/waker_clone_wake.fixed +++ b/src/tools/clippy/tests/ui/waker_clone_wake.fixed @@ -13,8 +13,10 @@ macro_rules! mac { pub fn wake(cx: &mut std::task::Context) { cx.waker().wake_by_ref(); + //~^ waker_clone_wake mac!(cx).wake_by_ref(); + //~^ waker_clone_wake } pub fn no_lint(cx: &mut std::task::Context, c: &Custom) { diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.rs b/src/tools/clippy/tests/ui/waker_clone_wake.rs index edc3bbd8fc089..27fa922d11123 100644 --- a/src/tools/clippy/tests/ui/waker_clone_wake.rs +++ b/src/tools/clippy/tests/ui/waker_clone_wake.rs @@ -13,8 +13,10 @@ macro_rules! mac { pub fn wake(cx: &mut std::task::Context) { cx.waker().clone().wake(); + //~^ waker_clone_wake mac!(cx).clone().wake(); + //~^ waker_clone_wake } pub fn no_lint(cx: &mut std::task::Context, c: &Custom) { diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.stderr b/src/tools/clippy/tests/ui/waker_clone_wake.stderr index bf2c02a76c9bb..9eb167d13107a 100644 --- a/src/tools/clippy/tests/ui/waker_clone_wake.stderr +++ b/src/tools/clippy/tests/ui/waker_clone_wake.stderr @@ -8,7 +8,7 @@ LL | cx.waker().clone().wake(); = help: to override `-D warnings` add `#[allow(clippy::waker_clone_wake)]` error: cloning a `Waker` only to wake it - --> tests/ui/waker_clone_wake.rs:17:5 + --> tests/ui/waker_clone_wake.rs:18:5 | LL | mac!(cx).clone().wake(); | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `mac!(cx).wake_by_ref()` diff --git a/src/tools/clippy/tests/ui/while_float.rs b/src/tools/clippy/tests/ui/while_float.rs index a3b0618948e6b..727b954ffcca8 100644 --- a/src/tools/clippy/tests/ui/while_float.rs +++ b/src/tools/clippy/tests/ui/while_float.rs @@ -2,9 +2,11 @@ fn main() { let mut x = 0.0_f32; while x < 42.0_f32 { + //~^ while_float x += 0.5; } while x < 42.0 { + //~^ while_float x += 1.0; } let mut x = 0; diff --git a/src/tools/clippy/tests/ui/while_float.stderr b/src/tools/clippy/tests/ui/while_float.stderr index b8e934b97c6c4..e83e1b925c169 100644 --- a/src/tools/clippy/tests/ui/while_float.stderr +++ b/src/tools/clippy/tests/ui/while_float.stderr @@ -11,7 +11,7 @@ LL | #[deny(clippy::while_float)] | ^^^^^^^^^^^^^^^^^^^ error: while condition comparing floats - --> tests/ui/while_float.rs:7:11 + --> tests/ui/while_float.rs:8:11 | LL | while x < 42.0 { | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/while_let_loop.rs b/src/tools/clippy/tests/ui/while_let_loop.rs index fa5325bebffaf..d591ab984cfaf 100644 --- a/src/tools/clippy/tests/ui/while_let_loop.rs +++ b/src/tools/clippy/tests/ui/while_let_loop.rs @@ -4,8 +4,8 @@ fn main() { let y = Some(true); loop { - //~^ ERROR: this loop could be written as a `while let` loop - //~| NOTE: `-D clippy::while-let-loop` implied by `-D warnings` + //~^ while_let_loop + if let Some(_x) = y { let _v = 1; } else { @@ -23,7 +23,8 @@ fn main() { } loop { - //~^ ERROR: this loop could be written as a `while let` loop + //~^ while_let_loop + match y { Some(_x) => true, None => break, @@ -31,7 +32,8 @@ fn main() { } loop { - //~^ ERROR: this loop could be written as a `while let` loop + //~^ while_let_loop + let x = match y { Some(x) => x, None => break, @@ -41,7 +43,8 @@ fn main() { } loop { - //~^ ERROR: this loop could be written as a `while let` loop + //~^ while_let_loop + let x = match y { Some(x) => x, None => break, @@ -72,7 +75,8 @@ fn main() { // #675, this used to have a wrong suggestion loop { - //~^ ERROR: this loop could be written as a `while let` loop + //~^ while_let_loop + let (e, l) = match "".split_whitespace().next() { Some(word) => (word.is_empty(), word.len()), None => break, diff --git a/src/tools/clippy/tests/ui/while_let_loop.stderr b/src/tools/clippy/tests/ui/while_let_loop.stderr index 10c2311d82f7f..bd482857e675a 100644 --- a/src/tools/clippy/tests/ui/while_let_loop.stderr +++ b/src/tools/clippy/tests/ui/while_let_loop.stderr @@ -17,43 +17,43 @@ error: this loop could be written as a `while let` loop | LL | / loop { LL | | +LL | | LL | | match y { -LL | | Some(_x) => true, -LL | | None => break, +... | LL | | }; LL | | } | |_____^ help: try: `while let Some(_x) = y { .. }` error: this loop could be written as a `while let` loop - --> tests/ui/while_let_loop.rs:33:5 + --> tests/ui/while_let_loop.rs:34:5 | LL | / loop { LL | | +LL | | LL | | let x = match y { -LL | | Some(x) => x, ... | LL | | let _str = "foo"; LL | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> tests/ui/while_let_loop.rs:43:5 + --> tests/ui/while_let_loop.rs:45:5 | LL | / loop { LL | | +LL | | LL | | let x = match y { -LL | | Some(x) => x, ... | LL | | } | |_____^ help: try: `while let Some(x) = y { .. }` error: this loop could be written as a `while let` loop - --> tests/ui/while_let_loop.rs:74:5 + --> tests/ui/while_let_loop.rs:77:5 | LL | / loop { LL | | +LL | | LL | | let (e, l) = match "".split_whitespace().next() { -LL | | Some(word) => (word.is_empty(), word.len()), ... | LL | | let _ = (e, l); LL | | } diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed index b8087c6e000f5..f9ccefab5898d 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed @@ -13,16 +13,19 @@ fn base() { let mut iter = 1..20; for x in iter { + //~^ while_let_on_iterator println!("{}", x); } let mut iter = 1..20; for x in iter { + //~^ while_let_on_iterator println!("{}", x); } let mut iter = 1..20; for _ in iter {} + //~^ while_let_on_iterator let mut iter = 1..20; while let None = iter.next() {} // this is fine (if nonsensical) @@ -99,6 +102,7 @@ fn refutable2() { let mut it = v.windows(2); for [..] in it {} + //~^ while_let_on_iterator let v = vec![[1], [2], [3]]; let mut it = v.iter(); @@ -106,6 +110,7 @@ fn refutable2() { let mut it = v.iter(); for [_x] in it {} + //~^ while_let_on_iterator } // binding @@ -119,6 +124,7 @@ fn refutable2() { let v = vec![[1], [2], [3]]; let mut it = v.iter(); for x @ [_] in it { + //~^ while_let_on_iterator println!("{:?}", x); } } @@ -139,6 +145,7 @@ fn nested_loops() { loop { let mut y = a.iter(); for _ in y { + //~^ while_let_on_iterator // use a for loop here } } @@ -196,6 +203,7 @@ fn issue6491() { let mut it = 1..40; while let Some(n) = it.next() { for m in it.by_ref() { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -207,8 +215,10 @@ fn issue6491() { // This is fine, inner loop uses a new iterator. let mut it = 1..40; for n in it { + //~^ while_let_on_iterator let mut it = 1..40; for m in it { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -218,6 +228,7 @@ fn issue6491() { // Weird binding shouldn't change anything. let (mut it, _) = (1..40, 0); for m in it { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -227,6 +238,7 @@ fn issue6491() { // Used after the loop, needs &mut. let mut it = 1..40; for m in it.by_ref() { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -244,6 +256,7 @@ fn issue6231() { let mut opt = Some(0); while let Some(n) = opt.take().or_else(|| it.next()) { for m in it.by_ref() { + //~^ while_let_on_iterator if n % 10 == 0 { break; } @@ -259,6 +272,7 @@ fn issue1924() { fn f(&mut self) -> Option { // Used as a field. for i in self.0.by_ref() { + //~^ while_let_on_iterator if !(3..8).contains(&i) { return Some(i); } @@ -291,6 +305,7 @@ fn issue1924() { } // This one is fine, a different field is borrowed for i in self.0.0.0.by_ref() { + //~^ while_let_on_iterator if i == 1 { return self.0.1.take(); } else { @@ -320,6 +335,7 @@ fn issue1924() { // Needs &mut, field of the iterator is accessed after the loop let mut it = S2(1..40, 0); for n in it.by_ref() { + //~^ while_let_on_iterator if n == 0 { break; } @@ -332,6 +348,7 @@ fn issue7249() { let mut x = || { // Needs &mut, the closure can be called multiple times for x in it.by_ref() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -346,6 +363,7 @@ fn issue7510() { let it = &mut it; // Needs to reborrow `it` as the binding isn't mutable for x in it.by_ref() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -357,6 +375,7 @@ fn issue7510() { let it = S(&mut it); // Needs to reborrow `it.0` as the binding isn't mutable for x in it.0.by_ref() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -392,6 +411,7 @@ fn custom_deref() { let mut s = S2(S1 { x: 0..10 }); for x in s.x.by_ref() { + //~^ while_let_on_iterator println!("{}", x); } } @@ -399,6 +419,7 @@ fn custom_deref() { fn issue_8113() { let mut x = [0..10]; for x in x[0].by_ref() { + //~^ while_let_on_iterator println!("{}", x); } } @@ -407,6 +428,7 @@ fn fn_once_closure() { let mut it = 0..10; (|| { for x in it.by_ref() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -417,6 +439,7 @@ fn fn_once_closure() { let mut it = 0..10; f(|| { for x in it { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -427,6 +450,7 @@ fn fn_once_closure() { let mut it = 0..10; f2(|| { for x in it.by_ref() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -437,6 +461,7 @@ fn fn_once_closure() { f3(|| { let mut it = 0..10; for x in it { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -449,6 +474,7 @@ fn fn_once_closure() { let mut it = 0..10; f4(|| { for x in it { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -459,6 +485,7 @@ fn fn_once_closure() { fn issue13123() { let mut it = 0..20; 'label: for n in it { + //~^ while_let_on_iterator if n % 25 == 0 { break 'label; } @@ -468,6 +495,7 @@ fn issue13123() { fn main() { let mut it = 0..20; for _ in it { + //~^ while_let_on_iterator println!("test"); } } diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs index 8e02f59b51265..f957f2e5a5238 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs @@ -13,16 +13,19 @@ fn base() { let mut iter = 1..20; while let Option::Some(x) = iter.next() { + //~^ while_let_on_iterator println!("{}", x); } let mut iter = 1..20; while let Some(x) = iter.next() { + //~^ while_let_on_iterator println!("{}", x); } let mut iter = 1..20; while let Some(_) = iter.next() {} + //~^ while_let_on_iterator let mut iter = 1..20; while let None = iter.next() {} // this is fine (if nonsensical) @@ -99,6 +102,7 @@ fn refutable2() { let mut it = v.windows(2); while let Some([..]) = it.next() {} + //~^ while_let_on_iterator let v = vec![[1], [2], [3]]; let mut it = v.iter(); @@ -106,6 +110,7 @@ fn refutable2() { let mut it = v.iter(); while let Some([_x]) = it.next() {} + //~^ while_let_on_iterator } // binding @@ -119,6 +124,7 @@ fn refutable2() { let v = vec![[1], [2], [3]]; let mut it = v.iter(); while let Some(x @ [_]) = it.next() { + //~^ while_let_on_iterator println!("{:?}", x); } } @@ -139,6 +145,7 @@ fn nested_loops() { loop { let mut y = a.iter(); while let Some(_) = y.next() { + //~^ while_let_on_iterator // use a for loop here } } @@ -196,6 +203,7 @@ fn issue6491() { let mut it = 1..40; while let Some(n) = it.next() { while let Some(m) = it.next() { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -207,8 +215,10 @@ fn issue6491() { // This is fine, inner loop uses a new iterator. let mut it = 1..40; while let Some(n) = it.next() { + //~^ while_let_on_iterator let mut it = 1..40; while let Some(m) = it.next() { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -218,6 +228,7 @@ fn issue6491() { // Weird binding shouldn't change anything. let (mut it, _) = (1..40, 0); while let Some(m) = it.next() { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -227,6 +238,7 @@ fn issue6491() { // Used after the loop, needs &mut. let mut it = 1..40; while let Some(m) = it.next() { + //~^ while_let_on_iterator if m % 10 == 0 { break; } @@ -244,6 +256,7 @@ fn issue6231() { let mut opt = Some(0); while let Some(n) = opt.take().or_else(|| it.next()) { while let Some(m) = it.next() { + //~^ while_let_on_iterator if n % 10 == 0 { break; } @@ -259,6 +272,7 @@ fn issue1924() { fn f(&mut self) -> Option { // Used as a field. while let Some(i) = self.0.next() { + //~^ while_let_on_iterator if !(3..8).contains(&i) { return Some(i); } @@ -291,6 +305,7 @@ fn issue1924() { } // This one is fine, a different field is borrowed while let Some(i) = self.0.0.0.next() { + //~^ while_let_on_iterator if i == 1 { return self.0.1.take(); } else { @@ -320,6 +335,7 @@ fn issue1924() { // Needs &mut, field of the iterator is accessed after the loop let mut it = S2(1..40, 0); while let Some(n) = it.next() { + //~^ while_let_on_iterator if n == 0 { break; } @@ -332,6 +348,7 @@ fn issue7249() { let mut x = || { // Needs &mut, the closure can be called multiple times while let Some(x) = it.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -346,6 +363,7 @@ fn issue7510() { let it = &mut it; // Needs to reborrow `it` as the binding isn't mutable while let Some(x) = it.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -357,6 +375,7 @@ fn issue7510() { let it = S(&mut it); // Needs to reborrow `it.0` as the binding isn't mutable while let Some(x) = it.0.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -392,6 +411,7 @@ fn custom_deref() { let mut s = S2(S1 { x: 0..10 }); while let Some(x) = s.x.next() { + //~^ while_let_on_iterator println!("{}", x); } } @@ -399,6 +419,7 @@ fn custom_deref() { fn issue_8113() { let mut x = [0..10]; while let Some(x) = x[0].next() { + //~^ while_let_on_iterator println!("{}", x); } } @@ -407,6 +428,7 @@ fn fn_once_closure() { let mut it = 0..10; (|| { while let Some(x) = it.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -417,6 +439,7 @@ fn fn_once_closure() { let mut it = 0..10; f(|| { while let Some(x) = it.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -427,6 +450,7 @@ fn fn_once_closure() { let mut it = 0..10; f2(|| { while let Some(x) = it.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -437,6 +461,7 @@ fn fn_once_closure() { f3(|| { let mut it = 0..10; while let Some(x) = it.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -449,6 +474,7 @@ fn fn_once_closure() { let mut it = 0..10; f4(|| { while let Some(x) = it.next() { + //~^ while_let_on_iterator if x % 2 == 0 { break; } @@ -459,6 +485,7 @@ fn fn_once_closure() { fn issue13123() { let mut it = 0..20; 'label: while let Some(n) = it.next() { + //~^ while_let_on_iterator if n % 25 == 0 { break 'label; } @@ -468,6 +495,7 @@ fn issue13123() { fn main() { let mut it = 0..20; while let Some(..) = it.next() { + //~^ while_let_on_iterator println!("test"); } } diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr index d96b26acf345d..50f20227b90f9 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr @@ -8,163 +8,163 @@ LL | while let Option::Some(x) = iter.next() { = help: to override `-D warnings` add `#[allow(clippy::while_let_on_iterator)]` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:20:5 + --> tests/ui/while_let_on_iterator.rs:21:5 | LL | while let Some(x) = iter.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in iter` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:25:5 + --> tests/ui/while_let_on_iterator.rs:27:5 | LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:101:9 + --> tests/ui/while_let_on_iterator.rs:104:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:108:9 + --> tests/ui/while_let_on_iterator.rs:112:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:121:9 + --> tests/ui/while_let_on_iterator.rs:126:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:141:9 + --> tests/ui/while_let_on_iterator.rs:147:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:198:9 + --> tests/ui/while_let_on_iterator.rs:205:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:209:5 + --> tests/ui/while_let_on_iterator.rs:217:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:211:9 + --> tests/ui/while_let_on_iterator.rs:220:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:220:9 + --> tests/ui/while_let_on_iterator.rs:230:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:229:9 + --> tests/ui/while_let_on_iterator.rs:240:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:246:9 + --> tests/ui/while_let_on_iterator.rs:258:9 | LL | while let Some(m) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:261:13 + --> tests/ui/while_let_on_iterator.rs:274:13 | LL | while let Some(i) = self.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:293:13 + --> tests/ui/while_let_on_iterator.rs:307:13 | LL | while let Some(i) = self.0.0.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in self.0.0.0.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:322:5 + --> tests/ui/while_let_on_iterator.rs:337:5 | LL | while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:334:9 + --> tests/ui/while_let_on_iterator.rs:350:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:348:5 + --> tests/ui/while_let_on_iterator.rs:365:5 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:359:5 + --> tests/ui/while_let_on_iterator.rs:377:5 | LL | while let Some(x) = it.0.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:394:5 + --> tests/ui/while_let_on_iterator.rs:413:5 | LL | while let Some(x) = s.x.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:401:5 + --> tests/ui/while_let_on_iterator.rs:421:5 | LL | while let Some(x) = x[0].next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:409:9 + --> tests/ui/while_let_on_iterator.rs:430:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:419:9 + --> tests/ui/while_let_on_iterator.rs:441:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:429:9 + --> tests/ui/while_let_on_iterator.rs:452:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.by_ref()` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:439:9 + --> tests/ui/while_let_on_iterator.rs:463:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:451:9 + --> tests/ui/while_let_on_iterator.rs:476:9 | LL | while let Some(x) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:461:5 + --> tests/ui/while_let_on_iterator.rs:487:5 | LL | 'label: while let Some(n) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'label: for n in it` error: this loop could be written as a `for` loop - --> tests/ui/while_let_on_iterator.rs:470:5 + --> tests/ui/while_let_on_iterator.rs:497:5 | LL | while let Some(..) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.rs b/src/tools/clippy/tests/ui/wild_in_or_pats.rs index bc8a1dbee71db..ced13cc50c5d5 100644 --- a/src/tools/clippy/tests/ui/wild_in_or_pats.rs +++ b/src/tools/clippy/tests/ui/wild_in_or_pats.rs @@ -6,7 +6,8 @@ fn main() { dbg!("matched a"); }, "bar" | _ => { - //~^ ERROR: wildcard pattern covers any other pattern as it will match anyway + //~^ wildcard_in_or_patterns + dbg!("matched (bar or) wild"); }, }; @@ -15,7 +16,8 @@ fn main() { dbg!("matched a"); }, "bar" | "bar2" | _ => { - //~^ ERROR: wildcard pattern covers any other pattern as it will match anyway + //~^ wildcard_in_or_patterns + dbg!("matched (bar or bar2 or) wild"); }, }; @@ -24,7 +26,8 @@ fn main() { dbg!("matched a"); }, _ | "bar" | _ => { - //~^ ERROR: wildcard pattern covers any other pattern as it will match anyway + //~^ wildcard_in_or_patterns + dbg!("matched (bar or) wild"); }, }; @@ -33,7 +36,8 @@ fn main() { dbg!("matched a"); }, _ | "bar" => { - //~^ ERROR: wildcard pattern covers any other pattern as it will match anyway + //~^ wildcard_in_or_patterns + dbg!("matched (bar or) wild"); }, }; @@ -67,6 +71,7 @@ fn main() { dbg!("Change the color"); }, ExhaustiveEnum::Quit | _ => { + //~^ wildcard_in_or_patterns dbg!("Quit or other"); }, }; @@ -102,6 +107,7 @@ fn main() { dbg!("On the y axis at {y}"); }, ExhaustiveStruct { x: 1, y: 1 } | _ => { + //~^ wildcard_in_or_patterns dbg!("On neither axis: ({x}, {y})"); }, } diff --git a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr index 5e409d6dfa6d7..09b2b533cd3ed 100644 --- a/src/tools/clippy/tests/ui/wild_in_or_pats.stderr +++ b/src/tools/clippy/tests/ui/wild_in_or_pats.stderr @@ -9,7 +9,7 @@ LL | "bar" | _ => { = help: to override `-D warnings` add `#[allow(clippy::wildcard_in_or_patterns)]` error: wildcard pattern covers any other pattern as it will match anyway - --> tests/ui/wild_in_or_pats.rs:17:9 + --> tests/ui/wild_in_or_pats.rs:18:9 | LL | "bar" | "bar2" | _ => { | ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | "bar" | "bar2" | _ => { = help: consider handling `_` separately error: wildcard pattern covers any other pattern as it will match anyway - --> tests/ui/wild_in_or_pats.rs:26:9 + --> tests/ui/wild_in_or_pats.rs:28:9 | LL | _ | "bar" | _ => { | ^^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | _ | "bar" | _ => { = help: consider handling `_` separately error: wildcard pattern covers any other pattern as it will match anyway - --> tests/ui/wild_in_or_pats.rs:35:9 + --> tests/ui/wild_in_or_pats.rs:38:9 | LL | _ | "bar" => { | ^^^^^^^^^ @@ -33,7 +33,7 @@ LL | _ | "bar" => { = help: consider handling `_` separately error: wildcard pattern covers any other pattern as it will match anyway - --> tests/ui/wild_in_or_pats.rs:69:9 + --> tests/ui/wild_in_or_pats.rs:73:9 | LL | ExhaustiveEnum::Quit | _ => { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,7 +41,7 @@ LL | ExhaustiveEnum::Quit | _ => { = help: consider handling `_` separately error: wildcard pattern covers any other pattern as it will match anyway - --> tests/ui/wild_in_or_pats.rs:104:9 + --> tests/ui/wild_in_or_pats.rs:109:9 | LL | ExhaustiveStruct { x: 1, y: 1 } | _ => { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed index 1089415733a91..141ff6eb2ac75 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed @@ -37,14 +37,17 @@ fn main() { match color { Color::Red => println!("Red"), Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan => eprintln!("Not red"), + //~^ wildcard_enum_match_arm }; match color { Color::Red => println!("Red"), _not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan => eprintln!("Not red"), + //~^ wildcard_enum_match_arm }; let _str = match color { Color::Red => "Red".to_owned(), not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan => format!("{:?}", not_red), + //~^ wildcard_enum_match_arm }; match color { Color::Red => {}, @@ -61,6 +64,7 @@ fn main() { match color { Color::Rgb(r, _, _) if r > 0 => "Some red", Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan => "No red", + //~^ wildcard_enum_match_arm }; match color { Color::Red | Color::Green | Color::Blue | Color::Cyan => {}, @@ -78,6 +82,7 @@ fn main() { match error_kind { ErrorKind::NotFound => {}, ErrorKind::PermissionDenied | _ => {}, + //~^ wildcard_enum_match_arm } match error_kind { ErrorKind::NotFound => {}, @@ -96,6 +101,7 @@ fn main() { match Enum::A { Enum::A => (), Enum::B | Enum::__Private => (), + //~^ wildcard_enum_match_arm } } } diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs index d9285c56f3efd..a13684e9100bd 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs @@ -37,14 +37,17 @@ fn main() { match color { Color::Red => println!("Red"), _ => eprintln!("Not red"), + //~^ wildcard_enum_match_arm }; match color { Color::Red => println!("Red"), _not_red => eprintln!("Not red"), + //~^ wildcard_enum_match_arm }; let _str = match color { Color::Red => "Red".to_owned(), not_red => format!("{:?}", not_red), + //~^ wildcard_enum_match_arm }; match color { Color::Red => {}, @@ -61,6 +64,7 @@ fn main() { match color { Color::Rgb(r, _, _) if r > 0 => "Some red", _ => "No red", + //~^ wildcard_enum_match_arm }; match color { Color::Red | Color::Green | Color::Blue | Color::Cyan => {}, @@ -78,6 +82,7 @@ fn main() { match error_kind { ErrorKind::NotFound => {}, _ => {}, + //~^ wildcard_enum_match_arm } match error_kind { ErrorKind::NotFound => {}, @@ -96,6 +101,7 @@ fn main() { match Enum::A { Enum::A => (), _ => (), + //~^ wildcard_enum_match_arm } } } diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr index 70ac768aaacdc..088c6b7b2841a 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr @@ -11,31 +11,31 @@ LL | #![deny(clippy::wildcard_enum_match_arm)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wildcard match will also match any future added variants - --> tests/ui/wildcard_enum_match_arm.rs:43:9 + --> tests/ui/wildcard_enum_match_arm.rs:44:9 | LL | _not_red => eprintln!("Not red"), | ^^^^^^^^ help: try: `_not_red @ Color::Green | _not_red @ Color::Blue | _not_red @ Color::Rgb(..) | _not_red @ Color::Cyan` error: wildcard match will also match any future added variants - --> tests/ui/wildcard_enum_match_arm.rs:47:9 + --> tests/ui/wildcard_enum_match_arm.rs:49:9 | LL | not_red => format!("{:?}", not_red), | ^^^^^^^ help: try: `not_red @ Color::Green | not_red @ Color::Blue | not_red @ Color::Rgb(..) | not_red @ Color::Cyan` error: wildcard match will also match any future added variants - --> tests/ui/wildcard_enum_match_arm.rs:63:9 + --> tests/ui/wildcard_enum_match_arm.rs:66:9 | LL | _ => "No red", | ^ help: try: `Color::Red | Color::Green | Color::Blue | Color::Rgb(..) | Color::Cyan` error: wildcard matches known variants and will also match future added variants - --> tests/ui/wildcard_enum_match_arm.rs:80:9 + --> tests/ui/wildcard_enum_match_arm.rs:84:9 | LL | _ => {}, | ^ help: try: `ErrorKind::PermissionDenied | _` error: wildcard match will also match any future added variants - --> tests/ui/wildcard_enum_match_arm.rs:98:13 + --> tests/ui/wildcard_enum_match_arm.rs:103:13 | LL | _ => (), | ^ help: try: `Enum::B | Enum::__Private` diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index 46890ee9213f1..a26b4a34190cc 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -13,15 +13,21 @@ extern crate wildcard_imports_helper; use crate::fn_mod::foo; +//~^ wildcard_imports use crate::mod_mod::inner_mod; +//~^ wildcard_imports use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +//~^ wildcard_imports #[macro_use] use crate::struct_mod::{A, inner_struct_mod}; +//~^ wildcard_imports #[allow(unused_imports)] use wildcard_imports_helper::inner::inner_for_self_import; use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; +//~^ wildcard_imports use wildcard_imports_helper::{ExternA, extern_foo}; +//~^ wildcard_imports use std::io::prelude::*; use wildcard_imports_helper::extern_prelude::v1::*; @@ -92,6 +98,7 @@ mod underscore_mod { fn does_lint() { use self::exports_underscore_ish::{_Deref, dummy}; + //~^ wildcard_imports let _ = (&0).deref(); dummy(); } @@ -123,13 +130,16 @@ mod in_fn_test { fn test_intern() { use crate::fn_mod::foo; + //~^ wildcard_imports foo(); } fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; + //~^ wildcard_imports use wildcard_imports_helper::{ExternA, extern_foo}; + //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); inner_extern_foo(); @@ -142,6 +152,8 @@ mod in_fn_test { fn test_inner_nested() { #[rustfmt::skip] use self::{inner::inner_foo, inner2::inner_bar}; + //~^ wildcard_imports + //~| wildcard_imports inner_foo(); inner_bar(); @@ -149,6 +161,7 @@ mod in_fn_test { fn test_extern_reexported() { use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + //~^ wildcard_imports extern_exported(); let _ = ExternExportedStruct; @@ -178,6 +191,7 @@ mod in_fn_test { fn test_reexported() { use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + //~^ wildcard_imports exported(); let _ = ExportedStruct; @@ -187,6 +201,7 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { use crate:: in_fn_test::exported; + //~^ wildcard_imports use crate:: fn_mod::foo; exported(); @@ -198,6 +213,7 @@ mod super_imports { mod should_be_replaced { use super::foofoo; + //~^ wildcard_imports fn with_super() { let _ = foofoo(); @@ -236,6 +252,7 @@ mod super_imports { fn insidefoo() {} mod inner { use super::insidefoo; + //~^ wildcard_imports fn with_super() { let _ = insidefoo(); } @@ -244,6 +261,7 @@ mod super_imports { mod use_explicit_should_be_replaced { use crate::super_imports::foofoo; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); @@ -253,6 +271,7 @@ mod super_imports { mod use_double_super_should_be_replaced { mod inner { use super::super::foofoo; + //~^ wildcard_imports fn with_double_super() { let _ = foofoo(); @@ -262,6 +281,7 @@ mod super_imports { mod use_super_explicit_should_be_replaced { use super::super::super_imports::foofoo; + //~^ wildcard_imports fn with_super_explicit() { let _ = foofoo(); @@ -270,6 +290,7 @@ mod super_imports { mod attestation_should_be_replaced { use super::foofoo; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs index 1a5586cbb88d9..2168f0a8918dd 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports.rs @@ -13,15 +13,21 @@ extern crate wildcard_imports_helper; use crate::fn_mod::*; +//~^ wildcard_imports use crate::mod_mod::*; +//~^ wildcard_imports use crate::multi_fn_mod::*; +//~^ wildcard_imports #[macro_use] use crate::struct_mod::*; +//~^ wildcard_imports #[allow(unused_imports)] use wildcard_imports_helper::inner::inner_for_self_import; use wildcard_imports_helper::inner::inner_for_self_import::*; +//~^ wildcard_imports use wildcard_imports_helper::*; +//~^ wildcard_imports use std::io::prelude::*; use wildcard_imports_helper::extern_prelude::v1::*; @@ -92,6 +98,7 @@ mod underscore_mod { fn does_lint() { use self::exports_underscore_ish::*; + //~^ wildcard_imports let _ = (&0).deref(); dummy(); } @@ -123,13 +130,16 @@ mod in_fn_test { fn test_intern() { use crate::fn_mod::*; + //~^ wildcard_imports foo(); } fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + //~^ wildcard_imports use wildcard_imports_helper::*; + //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); inner_extern_foo(); @@ -142,6 +152,8 @@ mod in_fn_test { fn test_inner_nested() { #[rustfmt::skip] use self::{inner::*, inner2::*}; + //~^ wildcard_imports + //~| wildcard_imports inner_foo(); inner_bar(); @@ -149,6 +161,7 @@ mod in_fn_test { fn test_extern_reexported() { use wildcard_imports_helper::*; + //~^ wildcard_imports extern_exported(); let _ = ExternExportedStruct; @@ -178,6 +191,7 @@ mod in_fn_test { fn test_reexported() { use crate::in_fn_test::*; + //~^ wildcard_imports exported(); let _ = ExportedStruct; @@ -187,7 +201,9 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { use crate:: in_fn_test:: * ; + //~^ wildcard_imports use crate:: fn_mod:: + //~^ wildcard_imports *; exported(); @@ -199,6 +215,7 @@ mod super_imports { mod should_be_replaced { use super::*; + //~^ wildcard_imports fn with_super() { let _ = foofoo(); @@ -237,6 +254,7 @@ mod super_imports { fn insidefoo() {} mod inner { use super::*; + //~^ wildcard_imports fn with_super() { let _ = insidefoo(); } @@ -245,6 +263,7 @@ mod super_imports { mod use_explicit_should_be_replaced { use crate::super_imports::*; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); @@ -254,6 +273,7 @@ mod super_imports { mod use_double_super_should_be_replaced { mod inner { use super::super::*; + //~^ wildcard_imports fn with_double_super() { let _ = foofoo(); @@ -263,6 +283,7 @@ mod super_imports { mod use_super_explicit_should_be_replaced { use super::super::super_imports::*; + //~^ wildcard_imports fn with_super_explicit() { let _ = foofoo(); @@ -271,6 +292,7 @@ mod super_imports { mod attestation_should_be_replaced { use super::*; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index 8e88f216394d2..f774126102bce 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -8,129 +8,130 @@ LL | use crate::fn_mod::*; = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:16:5 + --> tests/ui/wildcard_imports.rs:17:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:17:5 + --> tests/ui/wildcard_imports.rs:19:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:19:5 + --> tests/ui/wildcard_imports.rs:22:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:23:5 + --> tests/ui/wildcard_imports.rs:27:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:24:5 + --> tests/ui/wildcard_imports.rs:29:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:94:13 + --> tests/ui/wildcard_imports.rs:100:13 | LL | use self::exports_underscore_ish::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `self::exports_underscore_ish::{_Deref, dummy}` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:125:13 + --> tests/ui/wildcard_imports.rs:132:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:131:75 + --> tests/ui/wildcard_imports.rs:139:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:132:13 + --> tests/ui/wildcard_imports.rs:141:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:144:20 + --> tests/ui/wildcard_imports.rs:154:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:144:30 + --> tests/ui/wildcard_imports.rs:154:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:151:13 + --> tests/ui/wildcard_imports.rs:163:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:180:9 + --> tests/ui/wildcard_imports.rs:193:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:189:9 + --> tests/ui/wildcard_imports.rs:203:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:190:9 + --> tests/ui/wildcard_imports.rs:205:9 | LL | use crate:: fn_mod:: | _________^ +LL | | LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:201:13 + --> tests/ui/wildcard_imports.rs:217:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:239:17 + --> tests/ui/wildcard_imports.rs:256:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:247:13 + --> tests/ui/wildcard_imports.rs:265:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:256:17 + --> tests/ui/wildcard_imports.rs:275:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:265:13 + --> tests/ui/wildcard_imports.rs:285:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports.rs:273:13 + --> tests/ui/wildcard_imports.rs:294:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed index 197dd3b94df09..a3d1aebba8af4 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -11,14 +11,20 @@ extern crate wildcard_imports_helper; use crate::fn_mod::foo; +//~^ wildcard_imports use crate::mod_mod::inner_mod; +//~^ wildcard_imports use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +//~^ wildcard_imports use crate::struct_mod::{A, inner_struct_mod}; +//~^ wildcard_imports #[allow(unused_imports)] use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; +//~^ wildcard_imports use wildcard_imports_helper::prelude::v1::*; use wildcard_imports_helper::{ExternA, extern_foo}; +//~^ wildcard_imports use std::io::prelude::*; @@ -87,6 +93,7 @@ mod underscore_mod { fn does_lint() { use exports_underscore_ish::{_Deref, dummy}; + //~^ wildcard_imports let _ = (&0).deref(); dummy(); } @@ -117,13 +124,16 @@ mod in_fn_test { fn test_intern() { use crate::fn_mod::foo; + //~^ wildcard_imports foo(); } fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; + //~^ wildcard_imports use wildcard_imports_helper::{ExternA, extern_foo}; + //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); inner_extern_foo(); @@ -136,6 +146,8 @@ mod in_fn_test { fn test_inner_nested() { #[rustfmt::skip] use self::{inner::inner_foo, inner2::inner_bar}; + //~^ wildcard_imports + //~| wildcard_imports inner_foo(); inner_bar(); @@ -143,6 +155,7 @@ mod in_fn_test { fn test_extern_reexported() { use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + //~^ wildcard_imports extern_exported(); let _ = ExternExportedStruct; @@ -172,6 +185,7 @@ mod in_fn_test { fn test_reexported() { use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + //~^ wildcard_imports exported(); let _ = ExportedStruct; @@ -181,6 +195,7 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { use crate:: in_fn_test::exported; + //~^ wildcard_imports use crate:: fn_mod::foo; exported(); @@ -192,6 +207,7 @@ mod super_imports { mod should_be_replaced { use super::foofoo; + //~^ wildcard_imports fn with_super() { let _ = foofoo(); @@ -230,6 +246,7 @@ mod super_imports { fn insidefoo() {} mod inner { use super::insidefoo; + //~^ wildcard_imports fn with_super() { let _ = insidefoo(); } @@ -238,6 +255,7 @@ mod super_imports { mod use_explicit_should_be_replaced { use crate::super_imports::foofoo; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); @@ -247,6 +265,7 @@ mod super_imports { mod use_double_super_should_be_replaced { mod inner { use super::super::foofoo; + //~^ wildcard_imports fn with_double_super() { let _ = foofoo(); @@ -256,6 +275,7 @@ mod super_imports { mod use_super_explicit_should_be_replaced { use super::super::super_imports::foofoo; + //~^ wildcard_imports fn with_super_explicit() { let _ = foofoo(); @@ -264,6 +284,7 @@ mod super_imports { mod attestation_should_be_replaced { use super::foofoo; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr index 66adacd95dcc1..a1b557f39f0d2 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -8,129 +8,130 @@ LL | use crate::fn_mod::*; = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:14:5 + --> tests/ui/wildcard_imports_2021.rs:15:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:15:5 + --> tests/ui/wildcard_imports_2021.rs:17:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:16:5 + --> tests/ui/wildcard_imports_2021.rs:19:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:19:5 + --> tests/ui/wildcard_imports_2021.rs:23:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:21:5 + --> tests/ui/wildcard_imports_2021.rs:26:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:89:13 + --> tests/ui/wildcard_imports_2021.rs:95:13 | LL | use exports_underscore_ish::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:119:13 + --> tests/ui/wildcard_imports_2021.rs:126:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:125:75 + --> tests/ui/wildcard_imports_2021.rs:133:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:126:13 + --> tests/ui/wildcard_imports_2021.rs:135:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:138:20 + --> tests/ui/wildcard_imports_2021.rs:148:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:138:30 + --> tests/ui/wildcard_imports_2021.rs:148:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:145:13 + --> tests/ui/wildcard_imports_2021.rs:157:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:174:9 + --> tests/ui/wildcard_imports_2021.rs:187:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:183:9 + --> tests/ui/wildcard_imports_2021.rs:197:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:184:9 + --> tests/ui/wildcard_imports_2021.rs:199:9 | LL | use crate:: fn_mod:: | _________^ +LL | | LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:195:13 + --> tests/ui/wildcard_imports_2021.rs:211:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:233:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:241:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:250:17 + --> tests/ui/wildcard_imports_2021.rs:269:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:259:13 + --> tests/ui/wildcard_imports_2021.rs:279:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:267:13 + --> tests/ui/wildcard_imports_2021.rs:288:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed index 197dd3b94df09..a3d1aebba8af4 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -11,14 +11,20 @@ extern crate wildcard_imports_helper; use crate::fn_mod::foo; +//~^ wildcard_imports use crate::mod_mod::inner_mod; +//~^ wildcard_imports use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +//~^ wildcard_imports use crate::struct_mod::{A, inner_struct_mod}; +//~^ wildcard_imports #[allow(unused_imports)] use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; +//~^ wildcard_imports use wildcard_imports_helper::prelude::v1::*; use wildcard_imports_helper::{ExternA, extern_foo}; +//~^ wildcard_imports use std::io::prelude::*; @@ -87,6 +93,7 @@ mod underscore_mod { fn does_lint() { use exports_underscore_ish::{_Deref, dummy}; + //~^ wildcard_imports let _ = (&0).deref(); dummy(); } @@ -117,13 +124,16 @@ mod in_fn_test { fn test_intern() { use crate::fn_mod::foo; + //~^ wildcard_imports foo(); } fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; + //~^ wildcard_imports use wildcard_imports_helper::{ExternA, extern_foo}; + //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); inner_extern_foo(); @@ -136,6 +146,8 @@ mod in_fn_test { fn test_inner_nested() { #[rustfmt::skip] use self::{inner::inner_foo, inner2::inner_bar}; + //~^ wildcard_imports + //~| wildcard_imports inner_foo(); inner_bar(); @@ -143,6 +155,7 @@ mod in_fn_test { fn test_extern_reexported() { use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + //~^ wildcard_imports extern_exported(); let _ = ExternExportedStruct; @@ -172,6 +185,7 @@ mod in_fn_test { fn test_reexported() { use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + //~^ wildcard_imports exported(); let _ = ExportedStruct; @@ -181,6 +195,7 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { use crate:: in_fn_test::exported; + //~^ wildcard_imports use crate:: fn_mod::foo; exported(); @@ -192,6 +207,7 @@ mod super_imports { mod should_be_replaced { use super::foofoo; + //~^ wildcard_imports fn with_super() { let _ = foofoo(); @@ -230,6 +246,7 @@ mod super_imports { fn insidefoo() {} mod inner { use super::insidefoo; + //~^ wildcard_imports fn with_super() { let _ = insidefoo(); } @@ -238,6 +255,7 @@ mod super_imports { mod use_explicit_should_be_replaced { use crate::super_imports::foofoo; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); @@ -247,6 +265,7 @@ mod super_imports { mod use_double_super_should_be_replaced { mod inner { use super::super::foofoo; + //~^ wildcard_imports fn with_double_super() { let _ = foofoo(); @@ -256,6 +275,7 @@ mod super_imports { mod use_super_explicit_should_be_replaced { use super::super::super_imports::foofoo; + //~^ wildcard_imports fn with_super_explicit() { let _ = foofoo(); @@ -264,6 +284,7 @@ mod super_imports { mod attestation_should_be_replaced { use super::foofoo; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr index 66adacd95dcc1..a1b557f39f0d2 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -8,129 +8,130 @@ LL | use crate::fn_mod::*; = help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:14:5 + --> tests/ui/wildcard_imports_2021.rs:15:5 | LL | use crate::mod_mod::*; | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:15:5 + --> tests/ui/wildcard_imports_2021.rs:17:5 | LL | use crate::multi_fn_mod::*; | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:16:5 + --> tests/ui/wildcard_imports_2021.rs:19:5 | LL | use crate::struct_mod::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:19:5 + --> tests/ui/wildcard_imports_2021.rs:23:5 | LL | use wildcard_imports_helper::inner::inner_for_self_import::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:21:5 + --> tests/ui/wildcard_imports_2021.rs:26:5 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:89:13 + --> tests/ui/wildcard_imports_2021.rs:95:13 | LL | use exports_underscore_ish::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:119:13 + --> tests/ui/wildcard_imports_2021.rs:126:13 | LL | use crate::fn_mod::*; | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:125:75 + --> tests/ui/wildcard_imports_2021.rs:133:75 | LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; | ^ help: try: `inner_extern_foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:126:13 + --> tests/ui/wildcard_imports_2021.rs:135:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:138:20 + --> tests/ui/wildcard_imports_2021.rs:148:20 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^ help: try: `inner::inner_foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:138:30 + --> tests/ui/wildcard_imports_2021.rs:148:30 | LL | use self::{inner::*, inner2::*}; | ^^^^^^^^^ help: try: `inner2::inner_bar` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:145:13 + --> tests/ui/wildcard_imports_2021.rs:157:13 | LL | use wildcard_imports_helper::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:174:9 + --> tests/ui/wildcard_imports_2021.rs:187:9 | LL | use crate::in_fn_test::*; | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:183:9 + --> tests/ui/wildcard_imports_2021.rs:197:9 | LL | use crate:: in_fn_test:: * ; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:184:9 + --> tests/ui/wildcard_imports_2021.rs:199:9 | LL | use crate:: fn_mod:: | _________^ +LL | | LL | | *; | |_________^ help: try: `crate:: fn_mod::foo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:195:13 + --> tests/ui/wildcard_imports_2021.rs:211:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:233:17 + --> tests/ui/wildcard_imports_2021.rs:250:17 | LL | use super::*; | ^^^^^^^^ help: try: `super::insidefoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:241:13 + --> tests/ui/wildcard_imports_2021.rs:259:13 | LL | use crate::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:250:17 + --> tests/ui/wildcard_imports_2021.rs:269:17 | LL | use super::super::*; | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:259:13 + --> tests/ui/wildcard_imports_2021.rs:279:13 | LL | use super::super::super_imports::*; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` error: usage of wildcard import - --> tests/ui/wildcard_imports_2021.rs:267:13 + --> tests/ui/wildcard_imports_2021.rs:288:13 | LL | use super::*; | ^^^^^^^^ help: try: `super::foofoo` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs index 606ff080e774b..8075c15bc14f1 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs @@ -11,14 +11,20 @@ extern crate wildcard_imports_helper; use crate::fn_mod::*; +//~^ wildcard_imports use crate::mod_mod::*; +//~^ wildcard_imports use crate::multi_fn_mod::*; +//~^ wildcard_imports use crate::struct_mod::*; +//~^ wildcard_imports #[allow(unused_imports)] use wildcard_imports_helper::inner::inner_for_self_import::*; +//~^ wildcard_imports use wildcard_imports_helper::prelude::v1::*; use wildcard_imports_helper::*; +//~^ wildcard_imports use std::io::prelude::*; @@ -87,6 +93,7 @@ mod underscore_mod { fn does_lint() { use exports_underscore_ish::*; + //~^ wildcard_imports let _ = (&0).deref(); dummy(); } @@ -117,13 +124,16 @@ mod in_fn_test { fn test_intern() { use crate::fn_mod::*; + //~^ wildcard_imports foo(); } fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, *}; + //~^ wildcard_imports use wildcard_imports_helper::*; + //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); inner_extern_foo(); @@ -136,6 +146,8 @@ mod in_fn_test { fn test_inner_nested() { #[rustfmt::skip] use self::{inner::*, inner2::*}; + //~^ wildcard_imports + //~| wildcard_imports inner_foo(); inner_bar(); @@ -143,6 +155,7 @@ mod in_fn_test { fn test_extern_reexported() { use wildcard_imports_helper::*; + //~^ wildcard_imports extern_exported(); let _ = ExternExportedStruct; @@ -172,6 +185,7 @@ mod in_fn_test { fn test_reexported() { use crate::in_fn_test::*; + //~^ wildcard_imports exported(); let _ = ExportedStruct; @@ -181,7 +195,9 @@ fn test_reexported() { #[rustfmt::skip] fn test_weird_formatting() { use crate:: in_fn_test:: * ; + //~^ wildcard_imports use crate:: fn_mod:: + //~^ wildcard_imports *; exported(); @@ -193,6 +209,7 @@ mod super_imports { mod should_be_replaced { use super::*; + //~^ wildcard_imports fn with_super() { let _ = foofoo(); @@ -231,6 +248,7 @@ mod super_imports { fn insidefoo() {} mod inner { use super::*; + //~^ wildcard_imports fn with_super() { let _ = insidefoo(); } @@ -239,6 +257,7 @@ mod super_imports { mod use_explicit_should_be_replaced { use crate::super_imports::*; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); @@ -248,6 +267,7 @@ mod super_imports { mod use_double_super_should_be_replaced { mod inner { use super::super::*; + //~^ wildcard_imports fn with_double_super() { let _ = foofoo(); @@ -257,6 +277,7 @@ mod super_imports { mod use_super_explicit_should_be_replaced { use super::super::super_imports::*; + //~^ wildcard_imports fn with_super_explicit() { let _ = foofoo(); @@ -265,6 +286,7 @@ mod super_imports { mod attestation_should_be_replaced { use super::*; + //~^ wildcard_imports fn with_explicit() { let _ = foofoo(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs index 203c4e15b50c3..c41458d5bb0a7 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs @@ -1,3 +1,4 @@ +//@check-pass //@compile-flags: --test #![warn(clippy::wildcard_imports)] diff --git a/src/tools/clippy/tests/ui/write_literal.fixed b/src/tools/clippy/tests/ui/write_literal.fixed index f1def776e1bca..e84f768e33d0c 100644 --- a/src/tools/clippy/tests/ui/write_literal.fixed +++ b/src/tools/clippy/tests/ui/write_literal.fixed @@ -29,46 +29,55 @@ fn main() { // these should throw warnings write!(v, "Hello world"); - //~^ ERROR: literal with an empty format string - //~| NOTE: `-D clippy::write-literal` implied by `-D warnings` + //~^ write_literal + writeln!(v, "Hello {} world", world); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "Hello world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "a literal {:.4}", 5); - //~^ ERROR: literal with an empty format string + //~^ write_literal // positional args don't change the fact // that we're using a literal -- this should // throw a warning writeln!(v, "hello world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "world hello"); - //~^ ERROR: literal with an empty format string + //~^ write_literal // named args shouldn't change anything either writeln!(v, "hello world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "world hello"); - //~^ ERROR: literal with an empty format string + //~^ write_literal // #10128 writeln!(v, "hello {0} world", 2); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "world {0} hello", 2); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4); - //~^ ERROR: literal with an empty format string + //~^ write_literal } fn issue_13959() { let mut v = Vec::new(); writeln!(v, "\""); + //~^ write_literal writeln!( v, " + //~^ write_literal foo \\ \\\\ diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs index 1b7df91b47e1f..fc29fcbede7e6 100644 --- a/src/tools/clippy/tests/ui/write_literal.rs +++ b/src/tools/clippy/tests/ui/write_literal.rs @@ -29,47 +29,56 @@ fn main() { // these should throw warnings write!(v, "Hello {}", "world"); - //~^ ERROR: literal with an empty format string - //~| NOTE: `-D clippy::write-literal` implied by `-D warnings` + //~^ write_literal + writeln!(v, "Hello {} {}", world, "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "Hello {}", "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{} {:.4}", "a literal", 5); - //~^ ERROR: literal with an empty format string + //~^ write_literal // positional args don't change the fact // that we're using a literal -- this should // throw a warning writeln!(v, "{0} {1}", "hello", "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{1} {0}", "hello", "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal // named args shouldn't change anything either writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal // #10128 writeln!(v, "{0} {1} {2}", "hello", 2, "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{2} {1} {0}", "hello", 2, "world"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); - //~^ ERROR: literal with an empty format string + //~^ write_literal } fn issue_13959() { let mut v = Vec::new(); writeln!(v, "{}", r#"""#); + //~^ write_literal writeln!( v, "{}", r#" + //~^ write_literal foo \ \\ diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr index 35c93d567cd35..d53c2a7de2e05 100644 --- a/src/tools/clippy/tests/ui/write_literal.stderr +++ b/src/tools/clippy/tests/ui/write_literal.stderr @@ -25,7 +25,7 @@ LL + writeln!(v, "Hello {} world", world); | error: literal with an empty format string - --> tests/ui/write_literal.rs:36:29 + --> tests/ui/write_literal.rs:37:29 | LL | writeln!(v, "Hello {}", "world"); | ^^^^^^^ @@ -37,7 +37,7 @@ LL + writeln!(v, "Hello world"); | error: literal with an empty format string - --> tests/ui/write_literal.rs:38:29 + --> tests/ui/write_literal.rs:40:29 | LL | writeln!(v, "{} {:.4}", "a literal", 5); | ^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + writeln!(v, "a literal {:.4}", 5); | error: literal with an empty format string - --> tests/ui/write_literal.rs:44:28 + --> tests/ui/write_literal.rs:46:28 | LL | writeln!(v, "{0} {1}", "hello", "world"); | ^^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + writeln!(v, "hello world"); | error: literal with an empty format string - --> tests/ui/write_literal.rs:46:28 + --> tests/ui/write_literal.rs:49:28 | LL | writeln!(v, "{1} {0}", "hello", "world"); | ^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + writeln!(v, "world hello"); | error: literal with an empty format string - --> tests/ui/write_literal.rs:50:38 + --> tests/ui/write_literal.rs:53:38 | LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + writeln!(v, "hello world"); | error: literal with an empty format string - --> tests/ui/write_literal.rs:52:38 + --> tests/ui/write_literal.rs:56:38 | LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL + writeln!(v, "world hello"); | error: literal with an empty format string - --> tests/ui/write_literal.rs:56:32 + --> tests/ui/write_literal.rs:60:32 | LL | writeln!(v, "{0} {1} {2}", "hello", 2, "world"); | ^^^^^^^^^^^^^^^^^^^ @@ -109,7 +109,7 @@ LL + writeln!(v, "hello {0} world", 2); | error: literal with an empty format string - --> tests/ui/write_literal.rs:58:32 + --> tests/ui/write_literal.rs:63:32 | LL | writeln!(v, "{2} {1} {0}", "hello", 2, "world"); | ^^^^^^^^^^^^^^^^^^^ @@ -121,7 +121,7 @@ LL + writeln!(v, "world {0} hello", 2); | error: literal with an empty format string - --> tests/ui/write_literal.rs:60:39 + --> tests/ui/write_literal.rs:66:39 | LL | writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4); | ^^^^^^^ @@ -133,7 +133,7 @@ LL + writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4); | error: literal with an empty format string - --> tests/ui/write_literal.rs:62:41 + --> tests/ui/write_literal.rs:69:41 | LL | writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL + writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4); | error: literal with an empty format string - --> tests/ui/write_literal.rs:68:23 + --> tests/ui/write_literal.rs:75:23 | LL | writeln!(v, "{}", r#"""#); | ^^^^^^ @@ -157,12 +157,12 @@ LL + writeln!(v, "\""); | error: literal with an empty format string - --> tests/ui/write_literal.rs:72:9 + --> tests/ui/write_literal.rs:80:9 | LL | / r#" +LL | | LL | | foo LL | | \ -LL | | \\ ... | LL | | bar LL | | "# @@ -171,6 +171,7 @@ LL | | "# help: try | LL ~ " +LL + LL + foo LL + \\ LL + \\\\ diff --git a/src/tools/clippy/tests/ui/write_literal_2.rs b/src/tools/clippy/tests/ui/write_literal_2.rs index b2ed552d46bcc..f896782aaf3b5 100644 --- a/src/tools/clippy/tests/ui/write_literal_2.rs +++ b/src/tools/clippy/tests/ui/write_literal_2.rs @@ -8,44 +8,58 @@ fn main() { let mut v = Vec::new(); writeln!(v, "{}", "{hello}"); - //~^ ERROR: literal with an empty format string - //~| NOTE: `-D clippy::write-literal` implied by `-D warnings` + //~^ write_literal + writeln!(v, r"{}", r"{hello}"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{}", '\''); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{}", '"'); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, r"{}", '"'); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, r"{}", '\''); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!( v, "some {}", "hello \ + //~^ write_literal world!", - //~^^ ERROR: literal with an empty format string ); writeln!( v, "some {}\ {} \\ {}", - "1", "2", "3", + "1", + "2", + "3", + //~^^^ write_literal ); writeln!(v, "{}", "\\"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, r"{}", "\\"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, r#"{}"#, "\\"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{}", r"\"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + writeln!(v, "{}", "\r"); - //~^ ERROR: literal with an empty format string + //~^ write_literal + // hard mode writeln!(v, r#"{}{}"#, '#', '"'); - //~^ ERROR: literal with an empty format string + //~^ write_literal + // should not lint writeln!(v, r"{}", "\r"); } diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr index 9fba3ce548a06..29803d6a8b185 100644 --- a/src/tools/clippy/tests/ui/write_literal_2.stderr +++ b/src/tools/clippy/tests/ui/write_literal_2.stderr @@ -25,7 +25,7 @@ LL + writeln!(v, r"{{hello}}"); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:15:23 + --> tests/ui/write_literal_2.rs:16:23 | LL | writeln!(v, "{}", '\''); | ^^^^ @@ -37,7 +37,7 @@ LL + writeln!(v, "'"); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:17:23 + --> tests/ui/write_literal_2.rs:19:23 | LL | writeln!(v, "{}", '"'); | ^^^ @@ -49,13 +49,13 @@ LL + writeln!(v, "\""); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:19:24 + --> tests/ui/write_literal_2.rs:22:24 | LL | writeln!(v, r"{}", '"'); | ^^^ error: literal with an empty format string - --> tests/ui/write_literal_2.rs:21:24 + --> tests/ui/write_literal_2.rs:25:24 | LL | writeln!(v, r"{}", '\''); | ^^^^ @@ -67,23 +67,27 @@ LL + writeln!(v, r"'"); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:26:9 + --> tests/ui/write_literal_2.rs:31:9 | LL | / "hello \ +LL | | LL | | world!", | |_______________^ | help: try | LL ~ "some hello \ +LL + LL ~ world!", | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:34:9 + --> tests/ui/write_literal_2.rs:39:9 | -LL | "1", "2", "3", - | ^^^^^^^^^^^^^ +LL | / "1", +LL | | "2", +LL | | "3", + | |___________^ | help: try | @@ -92,7 +96,7 @@ LL ~ 2 \\ 3", | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:36:23 + --> tests/ui/write_literal_2.rs:44:23 | LL | writeln!(v, "{}", "\\"); | ^^^^ @@ -104,7 +108,7 @@ LL + writeln!(v, "\\"); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:38:24 + --> tests/ui/write_literal_2.rs:47:24 | LL | writeln!(v, r"{}", "\\"); | ^^^^ @@ -116,7 +120,7 @@ LL + writeln!(v, r"\"); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:40:26 + --> tests/ui/write_literal_2.rs:50:26 | LL | writeln!(v, r#"{}"#, "\\"); | ^^^^ @@ -128,7 +132,7 @@ LL + writeln!(v, r#"\"#); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:42:23 + --> tests/ui/write_literal_2.rs:53:23 | LL | writeln!(v, "{}", r"\"); | ^^^^ @@ -140,7 +144,7 @@ LL + writeln!(v, "\\"); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:44:23 + --> tests/ui/write_literal_2.rs:56:23 | LL | writeln!(v, "{}", "\r"); | ^^^^ @@ -152,7 +156,7 @@ LL + writeln!(v, "\r"); | error: literal with an empty format string - --> tests/ui/write_literal_2.rs:47:28 + --> tests/ui/write_literal_2.rs:60:28 | LL | writeln!(v, r#"{}{}"#, '#', '"'); | ^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/write_with_newline.fixed b/src/tools/clippy/tests/ui/write_with_newline.fixed index 82afff5c81f54..40742bbbb4275 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.fixed +++ b/src/tools/clippy/tests/ui/write_with_newline.fixed @@ -10,16 +10,19 @@ fn main() { // These should fail writeln!(v, "Hello"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline - //~| NOTE: `-D clippy::write-with-newline` implied by `-D warnings` + //~^ write_with_newline + writeln!(v, "Hello {}", "world"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + writeln!(v, "Hello {} {}", "world", "#2"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + writeln!(v, "{}", 1265); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + writeln!(v); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline // These should be fine write!(v, ""); @@ -42,7 +45,8 @@ fn main() { // #3514 write!(v, "\\n"); writeln!(v, "\\"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + write!(v, "\\\\n"); // Raw strings @@ -51,11 +55,11 @@ fn main() { // Literal newlines should also fail writeln!( - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline v ); writeln!( - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline v ); @@ -63,7 +67,8 @@ fn main() { write!(v, "\r\n"); write!(v, "foo\r\n"); writeln!(v, "\\r"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + write!(v, "foo\rbar\n"); // Ignore expanded format strings diff --git a/src/tools/clippy/tests/ui/write_with_newline.rs b/src/tools/clippy/tests/ui/write_with_newline.rs index 96e4bf0fbc4bd..ad6af69e78137 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.rs +++ b/src/tools/clippy/tests/ui/write_with_newline.rs @@ -10,16 +10,19 @@ fn main() { // These should fail write!(v, "Hello\n"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline - //~| NOTE: `-D clippy::write-with-newline` implied by `-D warnings` + //~^ write_with_newline + write!(v, "Hello {}\n", "world"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + write!(v, "Hello {} {}\n", "world", "#2"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + write!(v, "{}\n", 1265); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + write!(v, "\n"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline // These should be fine write!(v, ""); @@ -42,7 +45,8 @@ fn main() { // #3514 write!(v, "\\n"); write!(v, "\\\n"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + write!(v, "\\\\n"); // Raw strings @@ -51,13 +55,13 @@ fn main() { // Literal newlines should also fail write!( - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline v, " " ); write!( - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline v, r" " @@ -67,7 +71,8 @@ fn main() { write!(v, "\r\n"); write!(v, "foo\r\n"); write!(v, "\\r\n"); - //~^ ERROR: using `write!()` with a format string that ends in a single newline + //~^ write_with_newline + write!(v, "foo\rbar\n"); // Ignore expanded format strings diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr index 7eb741107a7b8..7243b7943df00 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.stderr +++ b/src/tools/clippy/tests/ui/write_with_newline.stderr @@ -25,7 +25,7 @@ LL + writeln!(v, "Hello {}", "world"); | error: using `write!()` with a format string that ends in a single newline - --> tests/ui/write_with_newline.rs:17:5 + --> tests/ui/write_with_newline.rs:18:5 | LL | write!(v, "Hello {} {}\n", "world", "#2"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL + writeln!(v, "Hello {} {}", "world", "#2"); | error: using `write!()` with a format string that ends in a single newline - --> tests/ui/write_with_newline.rs:19:5 + --> tests/ui/write_with_newline.rs:21:5 | LL | write!(v, "{}\n", 1265); | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -49,7 +49,7 @@ LL + writeln!(v, "{}", 1265); | error: using `write!()` with a format string that ends in a single newline - --> tests/ui/write_with_newline.rs:21:5 + --> tests/ui/write_with_newline.rs:24:5 | LL | write!(v, "\n"); | ^^^^^^^^^^^^^^^ @@ -61,7 +61,7 @@ LL + writeln!(v); | error: using `write!()` with a format string that ends in a single newline - --> tests/ui/write_with_newline.rs:44:5 + --> tests/ui/write_with_newline.rs:47:5 | LL | write!(v, "\\\n"); | ^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL + writeln!(v, "\\"); | error: using `write!()` with a format string that ends in a single newline - --> tests/ui/write_with_newline.rs:53:5 + --> tests/ui/write_with_newline.rs:57:5 | LL | / write!( LL | | @@ -91,7 +91,7 @@ LL ~ v | error: using `write!()` with a format string that ends in a single newline - --> tests/ui/write_with_newline.rs:59:5 + --> tests/ui/write_with_newline.rs:63:5 | LL | / write!( LL | | @@ -109,7 +109,7 @@ LL ~ v | error: using `write!()` with a format string that ends in a single newline - --> tests/ui/write_with_newline.rs:69:5 + --> tests/ui/write_with_newline.rs:73:5 | LL | write!(v, "\\r\n"); | ^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.fixed b/src/tools/clippy/tests/ui/writeln_empty_string.fixed index f6a7481f6422c..5cb702b10f2d5 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.fixed +++ b/src/tools/clippy/tests/ui/writeln_empty_string.fixed @@ -7,9 +7,11 @@ fn main() { // These should fail writeln!(v); + //~^ writeln_empty_string let mut suggestion = Vec::new(); writeln!(suggestion); + //~^ writeln_empty_string // These should be fine writeln!(v); diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.rs b/src/tools/clippy/tests/ui/writeln_empty_string.rs index 0297dba8c45d1..e6478264a578d 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.rs +++ b/src/tools/clippy/tests/ui/writeln_empty_string.rs @@ -7,9 +7,11 @@ fn main() { // These should fail writeln!(v, ""); + //~^ writeln_empty_string let mut suggestion = Vec::new(); writeln!(suggestion, ""); + //~^ writeln_empty_string // These should be fine writeln!(v); diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.stderr b/src/tools/clippy/tests/ui/writeln_empty_string.stderr index 20ece6a419264..43e76309ba64c 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.stderr +++ b/src/tools/clippy/tests/ui/writeln_empty_string.stderr @@ -10,7 +10,7 @@ LL | writeln!(v, ""); = help: to override `-D warnings` add `#[allow(clippy::writeln_empty_string)]` error: empty string literal in `writeln!` - --> tests/ui/writeln_empty_string.rs:12:5 + --> tests/ui/writeln_empty_string.rs:13:5 | LL | writeln!(suggestion, ""); | ^^^^^^^^^^^^^^^^^^^----^ diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs index d7ed883b767c3..840dfe7c6524e 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs @@ -14,14 +14,15 @@ impl Foo { fn is_u32(&self) {} fn to_i32(self) {} fn from_i32(self) {} - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention pub fn as_i64(self) {} pub fn into_i64(self) {} pub fn is_i64(self) {} pub fn to_i64(self) {} pub fn from_i64(self) {} - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention + // check whether the lint can be allowed at the function level #[allow(clippy::wrong_self_convention)] pub fn from_cake(self) {} @@ -34,30 +35,38 @@ struct Bar; impl Bar { fn as_i32(self) {} - //~^ ERROR: methods called `as_*` usually take `self` by reference or `self` by mutabl + //~^ wrong_self_convention + fn as_u32(&self) {} fn into_i32(&self) {} - //~^ ERROR: methods called `into_*` usually take `self` by value + //~^ wrong_self_convention + fn into_u32(self) {} fn is_i32(self) {} - //~^ ERROR: methods called `is_*` usually take `self` by mutable reference or `self` b + //~^ wrong_self_convention + fn is_u32(&self) {} fn to_i32(self) {} - //~^ ERROR: methods with the following characteristics: (`to_*` and `self` type is not + //~^ wrong_self_convention + fn to_u32(&self) {} fn from_i32(self) {} - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention pub fn as_i64(self) {} - //~^ ERROR: methods called `as_*` usually take `self` by reference or `self` by mutabl + //~^ wrong_self_convention + pub fn into_i64(&self) {} - //~^ ERROR: methods called `into_*` usually take `self` by value + //~^ wrong_self_convention + pub fn is_i64(self) {} - //~^ ERROR: methods called `is_*` usually take `self` by mutable reference or `self` b + //~^ wrong_self_convention + pub fn to_i64(self) {} - //~^ ERROR: methods with the following characteristics: (`to_*` and `self` type is not + //~^ wrong_self_convention + pub fn from_i64(self) {} - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention // test for false positives fn as_(self) {} @@ -103,19 +112,23 @@ mod issue4037 { mod issue6307 { trait T: Sized { fn as_i32(self) {} - //~^ ERROR: methods called `as_*` usually take `self` by reference or `self` by mu + //~^ wrong_self_convention + fn as_u32(&self) {} fn into_i32(self) {} fn into_i32_ref(&self) {} - //~^ ERROR: methods called `into_*` usually take `self` by value + //~^ wrong_self_convention + fn into_u32(self) {} fn is_i32(self) {} - //~^ ERROR: methods called `is_*` usually take `self` by mutable reference or `sel + //~^ wrong_self_convention + fn is_u32(&self) {} fn to_i32(self) {} fn to_u32(&self) {} fn from_i32(self) {} - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention + // check whether the lint can be allowed at the function level #[allow(clippy::wrong_self_convention)] fn from_cake(self) {} @@ -131,19 +144,23 @@ mod issue6307 { trait U { fn as_i32(self); - //~^ ERROR: methods called `as_*` usually take `self` by reference or `self` by mu + //~^ wrong_self_convention + fn as_u32(&self); fn into_i32(self); fn into_i32_ref(&self); - //~^ ERROR: methods called `into_*` usually take `self` by value + //~^ wrong_self_convention + fn into_u32(self); fn is_i32(self); - //~^ ERROR: methods called `is_*` usually take `self` by mutable reference or `sel + //~^ wrong_self_convention + fn is_u32(&self); fn to_i32(self); fn to_u32(&self); fn from_i32(self); - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention + // check whether the lint can be allowed at the function level #[allow(clippy::wrong_self_convention)] fn from_cake(self); @@ -162,14 +179,16 @@ mod issue6307 { fn as_u32(&self); fn into_i32(self); fn into_i32_ref(&self); - //~^ ERROR: methods called `into_*` usually take `self` by value + //~^ wrong_self_convention + fn into_u32(self); fn is_i32(self); fn is_u32(&self); fn to_i32(self); fn to_u32(&self); fn from_i32(self); - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention + // check whether the lint can be allowed at the function level #[allow(clippy::wrong_self_convention)] fn from_cake(self); @@ -194,7 +213,8 @@ mod issue6727 { } // trigger lint fn to_u64_v2(&self) -> u64 { - //~^ ERROR: methods with the following characteristics: (`to_*` and `self` type is + //~^ wrong_self_convention + 1 } } @@ -204,7 +224,8 @@ mod issue6727 { impl FooNoCopy { // trigger lint fn to_u64(self) -> u64 { - //~^ ERROR: methods with the following characteristics: (`to_*` and `self` type is + //~^ wrong_self_convention + 2 } fn to_u64_v2(&self) -> u64 { diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr index 5c286721c4782..e720ddf3fae17 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr @@ -17,7 +17,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> tests/ui/wrong_self_convention.rs:36:15 + --> tests/ui/wrong_self_convention.rs:37:15 | LL | fn as_i32(self) {} | ^^^^ @@ -25,7 +25,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> tests/ui/wrong_self_convention.rs:39:17 + --> tests/ui/wrong_self_convention.rs:41:17 | LL | fn into_i32(&self) {} | ^^^^^ @@ -33,7 +33,7 @@ LL | fn into_i32(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` - --> tests/ui/wrong_self_convention.rs:42:15 + --> tests/ui/wrong_self_convention.rs:45:15 | LL | fn is_i32(self) {} | ^^^^ @@ -41,7 +41,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> tests/ui/wrong_self_convention.rs:45:15 + --> tests/ui/wrong_self_convention.rs:49:15 | LL | fn to_i32(self) {} | ^^^^ @@ -49,7 +49,7 @@ LL | fn to_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> tests/ui/wrong_self_convention.rs:48:17 + --> tests/ui/wrong_self_convention.rs:53:17 | LL | fn from_i32(self) {} | ^^^^ @@ -57,7 +57,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> tests/ui/wrong_self_convention.rs:51:19 + --> tests/ui/wrong_self_convention.rs:56:19 | LL | pub fn as_i64(self) {} | ^^^^ @@ -65,7 +65,7 @@ LL | pub fn as_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> tests/ui/wrong_self_convention.rs:53:21 + --> tests/ui/wrong_self_convention.rs:59:21 | LL | pub fn into_i64(&self) {} | ^^^^^ @@ -73,7 +73,7 @@ LL | pub fn into_i64(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` - --> tests/ui/wrong_self_convention.rs:55:19 + --> tests/ui/wrong_self_convention.rs:62:19 | LL | pub fn is_i64(self) {} | ^^^^ @@ -81,7 +81,7 @@ LL | pub fn is_i64(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> tests/ui/wrong_self_convention.rs:57:19 + --> tests/ui/wrong_self_convention.rs:65:19 | LL | pub fn to_i64(self) {} | ^^^^ @@ -89,7 +89,7 @@ LL | pub fn to_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> tests/ui/wrong_self_convention.rs:59:21 + --> tests/ui/wrong_self_convention.rs:68:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -97,7 +97,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> tests/ui/wrong_self_convention.rs:105:19 + --> tests/ui/wrong_self_convention.rs:114:19 | LL | fn as_i32(self) {} | ^^^^ @@ -105,7 +105,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> tests/ui/wrong_self_convention.rs:109:25 + --> tests/ui/wrong_self_convention.rs:119:25 | LL | fn into_i32_ref(&self) {} | ^^^^^ @@ -113,7 +113,7 @@ LL | fn into_i32_ref(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` - --> tests/ui/wrong_self_convention.rs:112:19 + --> tests/ui/wrong_self_convention.rs:123:19 | LL | fn is_i32(self) {} | ^^^^ @@ -121,7 +121,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> tests/ui/wrong_self_convention.rs:117:21 + --> tests/ui/wrong_self_convention.rs:129:21 | LL | fn from_i32(self) {} | ^^^^ @@ -129,7 +129,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> tests/ui/wrong_self_convention.rs:133:19 + --> tests/ui/wrong_self_convention.rs:146:19 | LL | fn as_i32(self); | ^^^^ @@ -137,7 +137,7 @@ LL | fn as_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> tests/ui/wrong_self_convention.rs:137:25 + --> tests/ui/wrong_self_convention.rs:151:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -145,7 +145,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by mutable reference or `self` by reference or no `self` - --> tests/ui/wrong_self_convention.rs:140:19 + --> tests/ui/wrong_self_convention.rs:155:19 | LL | fn is_i32(self); | ^^^^ @@ -153,7 +153,7 @@ LL | fn is_i32(self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> tests/ui/wrong_self_convention.rs:145:21 + --> tests/ui/wrong_self_convention.rs:161:21 | LL | fn from_i32(self); | ^^^^ @@ -161,7 +161,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> tests/ui/wrong_self_convention.rs:164:25 + --> tests/ui/wrong_self_convention.rs:181:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -169,7 +169,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> tests/ui/wrong_self_convention.rs:171:21 + --> tests/ui/wrong_self_convention.rs:189:21 | LL | fn from_i32(self); | ^^^^ @@ -177,7 +177,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value - --> tests/ui/wrong_self_convention.rs:196:22 + --> tests/ui/wrong_self_convention.rs:215:22 | LL | fn to_u64_v2(&self) -> u64 { | ^^^^^ @@ -185,7 +185,7 @@ LL | fn to_u64_v2(&self) -> u64 { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> tests/ui/wrong_self_convention.rs:206:19 + --> tests/ui/wrong_self_convention.rs:226:19 | LL | fn to_u64(self) -> u64 { | ^^^^ diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs index 44b70f877be4d..0a3e4982a49ac 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs @@ -52,7 +52,8 @@ mod issue7179 { // lint pub fn from_be_self(self) -> Self { - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention + S(i32::from_be(self.0)) } } @@ -62,7 +63,7 @@ mod issue7179 { fn from_be(s: Self) -> Self; // lint fn from_be_self(self) -> Self; - //~^ ERROR: methods called `from_*` usually take no `self` + //~^ wrong_self_convention } trait Foo: Sized { diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr index 7aabdcd408c66..2eafb95d9bbe5 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr @@ -9,7 +9,7 @@ LL | pub fn from_be_self(self) -> Self { = help: to override `-D warnings` add `#[allow(clippy::wrong_self_convention)]` error: methods called `from_*` usually take no `self` - --> tests/ui/wrong_self_convention2.rs:64:25 + --> tests/ui/wrong_self_convention2.rs:65:25 | LL | fn from_be_self(self) -> Self; | ^^^^ diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs index 9169fc6d71f6a..eb6f08fff4245 100644 --- a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs +++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.rs @@ -12,7 +12,8 @@ mod issue6758 { impl Test { // If a method starts with `to_` and not ends with `_mut` it should expect `&self` pub fn to_many(&mut self) -> Option<&mut [T]> { - //~^ ERROR: methods with the following characteristics: (`to_*` and `self` type is + //~^ wrong_self_convention + match self { Self::Many(data) => Some(data), _ => None, @@ -21,7 +22,8 @@ mod issue6758 { // If a method starts with `to_` and ends with `_mut` it should expect `&mut self` pub fn to_many_mut(&self) -> Option<&[T]> { - //~^ ERROR: methods with the following characteristics: (`to_*` and `*_mut`) usual + //~^ wrong_self_convention + match self { Self::Many(data) => Some(data), _ => None, diff --git a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr index f52a36632101c..5ea2e8192efee 100644 --- a/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_conventions_mut.stderr @@ -9,7 +9,7 @@ LL | pub fn to_many(&mut self) -> Option<&mut [T]> { = help: to override `-D warnings` add `#[allow(clippy::wrong_self_convention)]` error: methods with the following characteristics: (`to_*` and `*_mut`) usually take `self` by mutable reference - --> tests/ui/wrong_self_conventions_mut.rs:23:28 + --> tests/ui/wrong_self_conventions_mut.rs:24:28 | LL | pub fn to_many_mut(&self) -> Option<&[T]> { | ^^^^^ diff --git a/src/tools/clippy/tests/ui/zero_div_zero.rs b/src/tools/clippy/tests/ui/zero_div_zero.rs index 340ed5ef1339d..79a309f499339 100644 --- a/src/tools/clippy/tests/ui/zero_div_zero.rs +++ b/src/tools/clippy/tests/ui/zero_div_zero.rs @@ -2,13 +2,17 @@ #[warn(clippy::zero_divided_by_zero)] fn main() { let nan = 0.0 / 0.0; - //~^ ERROR: constant division of `0.0` with `0.0` will always result in NaN + //~^ zero_divided_by_zero + let f64_nan = 0.0 / 0.0f64; - //~^ ERROR: constant division of `0.0` with `0.0` will always result in NaN + //~^ zero_divided_by_zero + let other_f64_nan = 0.0f64 / 0.0; - //~^ ERROR: constant division of `0.0` with `0.0` will always result in NaN + //~^ zero_divided_by_zero + let one_more_f64_nan = 0.0f64 / 0.0f64; - //~^ ERROR: constant division of `0.0` with `0.0` will always result in NaN + //~^ zero_divided_by_zero + let zero = 0.0; let other_zero = 0.0; let other_nan = zero / other_zero; // fine - this lint doesn't propagate constants. diff --git a/src/tools/clippy/tests/ui/zero_div_zero.stderr b/src/tools/clippy/tests/ui/zero_div_zero.stderr index 5294ebdfa5da1..bcf752d7c26c1 100644 --- a/src/tools/clippy/tests/ui/zero_div_zero.stderr +++ b/src/tools/clippy/tests/ui/zero_div_zero.stderr @@ -9,7 +9,7 @@ LL | let nan = 0.0 / 0.0; = help: to override `-D warnings` add `#[allow(clippy::zero_divided_by_zero)]` error: constant division of `0.0` with `0.0` will always result in NaN - --> tests/ui/zero_div_zero.rs:6:19 + --> tests/ui/zero_div_zero.rs:7:19 | LL | let f64_nan = 0.0 / 0.0f64; | ^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | let f64_nan = 0.0 / 0.0f64; = help: consider using `f64::NAN` if you would like a constant representing NaN error: constant division of `0.0` with `0.0` will always result in NaN - --> tests/ui/zero_div_zero.rs:8:25 + --> tests/ui/zero_div_zero.rs:10:25 | LL | let other_f64_nan = 0.0f64 / 0.0; | ^^^^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let other_f64_nan = 0.0f64 / 0.0; = help: consider using `f64::NAN` if you would like a constant representing NaN error: constant division of `0.0` with `0.0` will always result in NaN - --> tests/ui/zero_div_zero.rs:10:28 + --> tests/ui/zero_div_zero.rs:13:28 | LL | let one_more_f64_nan = 0.0f64 / 0.0f64; | ^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/zero_offset.rs b/src/tools/clippy/tests/ui/zero_offset.rs index c7a69dee4b2de..bedb09536c538 100644 --- a/src/tools/clippy/tests/ui/zero_offset.rs +++ b/src/tools/clippy/tests/ui/zero_offset.rs @@ -3,24 +3,29 @@ fn main() { unsafe { let m = &mut () as *mut (); m.offset(0); - //~^ ERROR: offset calculation on zero-sized value - //~| NOTE: `#[deny(clippy::zst_offset)]` on by default + //~^ zst_offset + m.wrapping_add(0); - //~^ ERROR: offset calculation on zero-sized value + //~^ zst_offset + m.sub(0); - //~^ ERROR: offset calculation on zero-sized value + //~^ zst_offset + m.wrapping_sub(0); - //~^ ERROR: offset calculation on zero-sized value + //~^ zst_offset let c = &() as *const (); c.offset(0); - //~^ ERROR: offset calculation on zero-sized value + //~^ zst_offset + c.wrapping_add(0); - //~^ ERROR: offset calculation on zero-sized value + //~^ zst_offset + c.sub(0); - //~^ ERROR: offset calculation on zero-sized value + //~^ zst_offset + c.wrapping_sub(0); - //~^ ERROR: offset calculation on zero-sized value + //~^ zst_offset let sized = &1 as *const i32; sized.offset(0); diff --git a/src/tools/clippy/tests/ui/zero_offset.stderr b/src/tools/clippy/tests/ui/zero_offset.stderr index a1efe3904c18b..b69c7b92d56a6 100644 --- a/src/tools/clippy/tests/ui/zero_offset.stderr +++ b/src/tools/clippy/tests/ui/zero_offset.stderr @@ -13,37 +13,37 @@ LL | m.wrapping_add(0); | ^^^^^^^^^^^^^^^^^ error: offset calculation on zero-sized value - --> tests/ui/zero_offset.rs:10:9 + --> tests/ui/zero_offset.rs:11:9 | LL | m.sub(0); | ^^^^^^^^ error: offset calculation on zero-sized value - --> tests/ui/zero_offset.rs:12:9 + --> tests/ui/zero_offset.rs:14:9 | LL | m.wrapping_sub(0); | ^^^^^^^^^^^^^^^^^ error: offset calculation on zero-sized value - --> tests/ui/zero_offset.rs:16:9 + --> tests/ui/zero_offset.rs:18:9 | LL | c.offset(0); | ^^^^^^^^^^^ error: offset calculation on zero-sized value - --> tests/ui/zero_offset.rs:18:9 + --> tests/ui/zero_offset.rs:21:9 | LL | c.wrapping_add(0); | ^^^^^^^^^^^^^^^^^ error: offset calculation on zero-sized value - --> tests/ui/zero_offset.rs:20:9 + --> tests/ui/zero_offset.rs:24:9 | LL | c.sub(0); | ^^^^^^^^ error: offset calculation on zero-sized value - --> tests/ui/zero_offset.rs:22:9 + --> tests/ui/zero_offset.rs:27:9 | LL | c.wrapping_sub(0); | ^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/zero_ptr.fixed b/src/tools/clippy/tests/ui/zero_ptr.fixed index 5d99bc9b757de..f2375d57f3a28 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.fixed +++ b/src/tools/clippy/tests/ui/zero_ptr.fixed @@ -2,11 +2,16 @@ pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { let _ = std::ptr::null::(); + //~^ zero_ptr let _ = std::ptr::null_mut::(); + //~^ zero_ptr let _: *const u8 = std::ptr::null(); + //~^ zero_ptr foo(0 as _, 0 as _); foo(std::ptr::null(), std::ptr::null_mut()); + //~^ zero_ptr + //~| zero_ptr let z = 0; let _ = z as *const usize; // this is currently not caught diff --git a/src/tools/clippy/tests/ui/zero_ptr.rs b/src/tools/clippy/tests/ui/zero_ptr.rs index 09d321c7a18da..ee01e426a43b4 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.rs +++ b/src/tools/clippy/tests/ui/zero_ptr.rs @@ -2,11 +2,16 @@ pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { let _ = 0 as *const usize; + //~^ zero_ptr let _ = 0 as *mut f64; + //~^ zero_ptr let _: *const u8 = 0 as *const _; + //~^ zero_ptr foo(0 as _, 0 as _); foo(0 as *const _, 0 as *mut _); + //~^ zero_ptr + //~| zero_ptr let z = 0; let _ = z as *const usize; // this is currently not caught diff --git a/src/tools/clippy/tests/ui/zero_ptr.stderr b/src/tools/clippy/tests/ui/zero_ptr.stderr index a580bebd5d3aa..8dc781f36258c 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.stderr +++ b/src/tools/clippy/tests/ui/zero_ptr.stderr @@ -8,25 +8,25 @@ LL | let _ = 0 as *const usize; = help: to override `-D warnings` add `#[allow(clippy::zero_ptr)]` error: `0 as *mut _` detected - --> tests/ui/zero_ptr.rs:5:13 + --> tests/ui/zero_ptr.rs:6:13 | LL | let _ = 0 as *mut f64; | ^^^^^^^^^^^^^ help: try: `std::ptr::null_mut::()` error: `0 as *const _` detected - --> tests/ui/zero_ptr.rs:6:24 + --> tests/ui/zero_ptr.rs:8:24 | LL | let _: *const u8 = 0 as *const _; | ^^^^^^^^^^^^^ help: try: `std::ptr::null()` error: `0 as *const _` detected - --> tests/ui/zero_ptr.rs:9:9 + --> tests/ui/zero_ptr.rs:12:9 | LL | foo(0 as *const _, 0 as *mut _); | ^^^^^^^^^^^^^ help: try: `std::ptr::null()` error: `0 as *mut _` detected - --> tests/ui/zero_ptr.rs:9:24 + --> tests/ui/zero_ptr.rs:12:24 | LL | foo(0 as *const _, 0 as *mut _); | ^^^^^^^^^^^ help: try: `std::ptr::null_mut()` diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed index 25143eee8cc30..bbb2464e41d2c 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed @@ -4,7 +4,10 @@ pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let _ = core::ptr::null::(); + //~^ zero_ptr let _ = core::ptr::null_mut::(); + //~^ zero_ptr let _: *const u8 = core::ptr::null(); + //~^ zero_ptr 0 } diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs index 965733b45d92e..22fe2d24e4b1a 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs @@ -4,7 +4,10 @@ pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let _ = 0 as *const usize; + //~^ zero_ptr let _ = 0 as *mut f64; + //~^ zero_ptr let _: *const u8 = 0 as *const _; + //~^ zero_ptr 0 } diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr index 014bf312bf325..77978d0a38b24 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr @@ -11,13 +11,13 @@ LL | #![deny(clippy::zero_ptr)] | ^^^^^^^^^^^^^^^^ error: `0 as *mut _` detected - --> tests/ui/zero_ptr_no_std.rs:7:13 + --> tests/ui/zero_ptr_no_std.rs:8:13 | LL | let _ = 0 as *mut f64; | ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::()` error: `0 as *const _` detected - --> tests/ui/zero_ptr_no_std.rs:8:24 + --> tests/ui/zero_ptr_no_std.rs:10:24 | LL | let _: *const u8 = 0 as *const _; | ^^^^^^^^^^^^^ help: try: `core::ptr::null()` diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed index 989e8ae70e586..fb9d7880a4a7f 100644 --- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed +++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.fixed @@ -16,27 +16,36 @@ fn main() { // on arrays f(); let a: [i32; 0] = []; + //~^ zero_repeat_side_effects let mut b; f(); b = [] as [i32; 0]; + //~^ zero_repeat_side_effects // on vecs // vecs dont support inferring value of consts f(); let c: std::vec::Vec = vec![]; + //~^ zero_repeat_side_effects let d; f(); d = vec![] as std::vec::Vec; + //~^ zero_repeat_side_effects // for macros println!("side effect"); let e: [(); 0] = []; + //~^ zero_repeat_side_effects // for nested calls { f() }; let g: [i32; 0] = []; + //~^ zero_repeat_side_effects // as function param drop({ f(); vec![] as std::vec::Vec }); + //~^ zero_repeat_side_effects // when singled out/not part of assignment/local { f(); vec![] as std::vec::Vec }; + //~^ zero_repeat_side_effects { f(); [] as [i32; 0] }; + //~^ zero_repeat_side_effects // should not trigger let a = [f(); N]; diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs index 68511f41a95ea..8b22ff840244e 100644 --- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs +++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.rs @@ -16,27 +16,36 @@ fn main() { // on arrays let a = [f(); 0]; + //~^ zero_repeat_side_effects let mut b; b = [f(); 0]; + //~^ zero_repeat_side_effects // on vecs // vecs dont support inferring value of consts let c = vec![f(); 0]; + //~^ zero_repeat_side_effects let d; d = vec![f(); 0]; + //~^ zero_repeat_side_effects // for macros let e = [println!("side effect"); 0]; + //~^ zero_repeat_side_effects // for nested calls let g = [{ f() }; 0]; + //~^ zero_repeat_side_effects // as function param drop(vec![f(); 0]); + //~^ zero_repeat_side_effects // when singled out/not part of assignment/local vec![f(); 0]; + //~^ zero_repeat_side_effects [f(); 0]; + //~^ zero_repeat_side_effects // should not trigger let a = [f(); N]; diff --git a/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr index d578e22b97168..2dba52e2112ec 100644 --- a/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr +++ b/src/tools/clippy/tests/ui/zero_repeat_side_effects.stderr @@ -8,49 +8,49 @@ LL | let a = [f(); 0]; = help: to override `-D warnings` add `#[allow(clippy::zero_repeat_side_effects)]` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:20:5 + --> tests/ui/zero_repeat_side_effects.rs:21:5 | LL | b = [f(); 0]; | ^^^^^^^^^^^^ help: consider using: `f(); b = [] as [i32; 0]` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:24:5 + --> tests/ui/zero_repeat_side_effects.rs:26:5 | LL | let c = vec![f(); 0]; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f(); let c: std::vec::Vec = vec![];` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:26:5 + --> tests/ui/zero_repeat_side_effects.rs:29:5 | LL | d = vec![f(); 0]; | ^^^^^^^^^^^^^^^^ help: consider using: `f(); d = vec![] as std::vec::Vec` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:29:5 + --> tests/ui/zero_repeat_side_effects.rs:33:5 | LL | let e = [println!("side effect"); 0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `println!("side effect"); let e: [(); 0] = [];` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:32:5 + --> tests/ui/zero_repeat_side_effects.rs:37:5 | LL | let g = [{ f() }; 0]; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `{ f() }; let g: [i32; 0] = [];` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:35:10 + --> tests/ui/zero_repeat_side_effects.rs:41:10 | LL | drop(vec![f(); 0]); | ^^^^^^^^^^^^ help: consider using: `{ f(); vec![] as std::vec::Vec }` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:38:5 + --> tests/ui/zero_repeat_side_effects.rs:45:5 | LL | vec![f(); 0]; | ^^^^^^^^^^^^ help: consider using: `{ f(); vec![] as std::vec::Vec }` error: function or method calls as the initial value in zero-sized array initializers may cause side effects - --> tests/ui/zero_repeat_side_effects.rs:39:5 + --> tests/ui/zero_repeat_side_effects.rs:47:5 | LL | [f(); 0]; | ^^^^^^^^ help: consider using: `{ f(); [] as [i32; 0] }` diff --git a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.rs b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.rs index 565f639201ff7..cdeea15f28bc8 100644 --- a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.rs +++ b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.rs @@ -3,28 +3,28 @@ use std::collections::BTreeMap; const CONST_OK: Option> = None; const CONST_NOT_OK: Option> = None; -//~^ ERROR: map with zero-sized value type +//~^ zero_sized_map_values static STATIC_OK: Option> = None; static STATIC_NOT_OK: Option> = None; -//~^ ERROR: map with zero-sized value type +//~^ zero_sized_map_values type OkMap = BTreeMap; type NotOkMap = BTreeMap; -//~^ ERROR: map with zero-sized value type +//~^ zero_sized_map_values enum TestEnum { Ok(BTreeMap), NotOk(BTreeMap), - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } struct Test { ok: BTreeMap, not_ok: BTreeMap, - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values also_not_ok: Vec>, - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } trait TestTrait { @@ -33,7 +33,7 @@ trait TestTrait { fn produce_output() -> Self::Output; fn weird_map(&self, map: BTreeMap); - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } impl Test { @@ -42,7 +42,8 @@ impl Test { } fn not_ok(&self) -> BTreeMap { - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values + todo!() } } @@ -60,8 +61,9 @@ impl TestTrait for Test { } fn test(map: BTreeMap, key: &str) -> BTreeMap { - //~^ ERROR: map with zero-sized value type - //~| ERROR: map with zero-sized value type + //~^ zero_sized_map_values + //~| zero_sized_map_values + todo!(); } @@ -71,10 +73,11 @@ fn test2(map: BTreeMap, key: &str) -> BTreeMap { fn main() { let _: BTreeMap = BTreeMap::new(); - //~^ ERROR: map with zero-sized value type - //~| ERROR: map with zero-sized value type + //~^ zero_sized_map_values + //~| zero_sized_map_values + let _: BTreeMap = BTreeMap::new(); let _: BTreeMap<_, _> = std::iter::empty::<(String, ())>().collect(); - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } diff --git a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr index 65fc81e10e6c3..40acb0b211f7f 100644 --- a/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr +++ b/src/tools/clippy/tests/ui/zero_sized_btreemap_values.stderr @@ -65,7 +65,7 @@ LL | fn not_ok(&self) -> BTreeMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_btreemap_values.rs:62:14 + --> tests/ui/zero_sized_btreemap_values.rs:63:14 | LL | fn test(map: BTreeMap, key: &str) -> BTreeMap { | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | fn test(map: BTreeMap, key: &str) -> BTreeMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_btreemap_values.rs:62:50 + --> tests/ui/zero_sized_btreemap_values.rs:63:50 | LL | fn test(map: BTreeMap, key: &str) -> BTreeMap { | ^^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | fn test(map: BTreeMap, key: &str) -> BTreeMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_btreemap_values.rs:73:35 + --> tests/ui/zero_sized_btreemap_values.rs:75:35 | LL | let _: BTreeMap = BTreeMap::new(); | ^^^^^^^^ @@ -89,7 +89,7 @@ LL | let _: BTreeMap = BTreeMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_btreemap_values.rs:73:12 + --> tests/ui/zero_sized_btreemap_values.rs:75:12 | LL | let _: BTreeMap = BTreeMap::new(); | ^^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _: BTreeMap = BTreeMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_btreemap_values.rs:78:12 + --> tests/ui/zero_sized_btreemap_values.rs:81:12 | LL | let _: BTreeMap<_, _> = std::iter::empty::<(String, ())>().collect(); | ^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs index 5498261ee95a0..4beeef421f30e 100644 --- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs +++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs @@ -3,28 +3,28 @@ use std::collections::HashMap; const CONST_OK: Option> = None; const CONST_NOT_OK: Option> = None; -//~^ ERROR: map with zero-sized value type +//~^ zero_sized_map_values static STATIC_OK: Option> = None; static STATIC_NOT_OK: Option> = None; -//~^ ERROR: map with zero-sized value type +//~^ zero_sized_map_values type OkMap = HashMap; type NotOkMap = HashMap; -//~^ ERROR: map with zero-sized value type +//~^ zero_sized_map_values enum TestEnum { Ok(HashMap), NotOk(HashMap), - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } struct Test { ok: HashMap, not_ok: HashMap, - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values also_not_ok: Vec>, - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } trait TestTrait { @@ -33,7 +33,7 @@ trait TestTrait { fn produce_output() -> Self::Output; fn weird_map(&self, map: HashMap); - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } impl Test { @@ -42,7 +42,8 @@ impl Test { } fn not_ok(&self) -> HashMap { - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values + todo!() } } @@ -60,8 +61,9 @@ impl TestTrait for Test { } fn test(map: HashMap, key: &str) -> HashMap { - //~^ ERROR: map with zero-sized value type - //~| ERROR: map with zero-sized value type + //~^ zero_sized_map_values + //~| zero_sized_map_values + todo!(); } @@ -71,10 +73,11 @@ fn test2(map: HashMap, key: &str) -> HashMap { fn main() { let _: HashMap = HashMap::new(); - //~^ ERROR: map with zero-sized value type - //~| ERROR: map with zero-sized value type + //~^ zero_sized_map_values + //~| zero_sized_map_values + let _: HashMap = HashMap::new(); let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); - //~^ ERROR: map with zero-sized value type + //~^ zero_sized_map_values } diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr index 08afef58a2aaa..ed8536acfe8fa 100644 --- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr +++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr @@ -65,7 +65,7 @@ LL | fn not_ok(&self) -> HashMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:62:14 + --> tests/ui/zero_sized_hashmap_values.rs:63:14 | LL | fn test(map: HashMap, key: &str) -> HashMap { | ^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ LL | fn test(map: HashMap, key: &str) -> HashMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:62:49 + --> tests/ui/zero_sized_hashmap_values.rs:63:49 | LL | fn test(map: HashMap, key: &str) -> HashMap { | ^^^^^^^^^^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | fn test(map: HashMap, key: &str) -> HashMap { = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:73:34 + --> tests/ui/zero_sized_hashmap_values.rs:75:34 | LL | let _: HashMap = HashMap::new(); | ^^^^^^^ @@ -89,7 +89,7 @@ LL | let _: HashMap = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:73:12 + --> tests/ui/zero_sized_hashmap_values.rs:75:12 | LL | let _: HashMap = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^ @@ -97,7 +97,7 @@ LL | let _: HashMap = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:78:12 + --> tests/ui/zero_sized_hashmap_values.rs:81:12 | LL | let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); | ^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs index 6f0d2760a860d..25bbc02ffb762 100644 --- a/src/tools/clippy/tests/ui/zombie_processes.rs +++ b/src/tools/clippy/tests/ui/zombie_processes.rs @@ -13,6 +13,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + x.kill(); x.id(); } @@ -40,6 +41,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + let v = &x; // (allow shared refs is fine because one cannot call `.wait()` through that) } @@ -65,6 +67,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + if true { std::process::exit(0); } @@ -72,6 +75,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + if true { while false {} // Calling `exit()` after leaving a while loop should still be linted. @@ -98,6 +102,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + if true { return; } @@ -107,6 +112,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + if true { x.wait().unwrap(); } @@ -115,6 +121,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + if true { x.wait().unwrap(); } else { @@ -125,6 +132,7 @@ fn main() { { let mut x = Command::new("").spawn().unwrap(); //~^ zombie_processes + if true { // this else block exists to test the other help message } else { diff --git a/src/tools/clippy/tests/ui/zombie_processes.stderr b/src/tools/clippy/tests/ui/zombie_processes.stderr index afc518c60db2a..0374d097b1b5a 100644 --- a/src/tools/clippy/tests/ui/zombie_processes.stderr +++ b/src/tools/clippy/tests/ui/zombie_processes.stderr @@ -11,7 +11,7 @@ LL | let mut x = Command::new("").spawn().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes.rs:41:21 + --> tests/ui/zombie_processes.rs:42:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -21,7 +21,7 @@ LL | let mut x = Command::new("").spawn().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes.rs:66:21 + --> tests/ui/zombie_processes.rs:68:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -31,7 +31,7 @@ LL | let mut x = Command::new("").spawn().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes.rs:73:21 + --> tests/ui/zombie_processes.rs:76:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -41,18 +41,18 @@ LL | let mut x = Command::new("").spawn().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is not `wait()`ed on in all code paths - --> tests/ui/zombie_processes.rs:99:21 + --> tests/ui/zombie_processes.rs:103:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: no `wait()` call exists on the code path to this early return - --> tests/ui/zombie_processes.rs:102:13 + --> tests/ui/zombie_processes.rs:107:13 | LL | return; | ^^^^^^ note: `wait()` call exists, but it is unreachable due to the early return - --> tests/ui/zombie_processes.rs:104:9 + --> tests/ui/zombie_processes.rs:109:9 | LL | x.wait().unwrap(); | ^ @@ -61,20 +61,20 @@ LL | x.wait().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is not `wait()`ed on in all code paths - --> tests/ui/zombie_processes.rs:108:21 + --> tests/ui/zombie_processes.rs:113:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: this if expression has a `wait()` call, but it is missing an else block - --> tests/ui/zombie_processes.rs:110:9 + --> tests/ui/zombie_processes.rs:116:9 | LL | / if true { LL | | x.wait().unwrap(); LL | | } | |_________^ note: `wait()` called here - --> tests/ui/zombie_processes.rs:111:13 + --> tests/ui/zombie_processes.rs:117:13 | LL | x.wait().unwrap(); | ^ @@ -83,13 +83,13 @@ LL | x.wait().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is not `wait()`ed on in all code paths - --> tests/ui/zombie_processes.rs:116:21 + --> tests/ui/zombie_processes.rs:122:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `wait()` is not called in this if branch - --> tests/ui/zombie_processes.rs:120:10 + --> tests/ui/zombie_processes.rs:127:10 | LL | } else { | __________^ @@ -97,7 +97,7 @@ LL | | // this else block exists to test the other help message LL | | } | |_________^ note: `wait()` is called in the other branch - --> tests/ui/zombie_processes.rs:119:13 + --> tests/ui/zombie_processes.rs:126:13 | LL | x.wait().unwrap(); | ^ @@ -106,20 +106,20 @@ LL | x.wait().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is not `wait()`ed on in all code paths - --> tests/ui/zombie_processes.rs:126:21 + --> tests/ui/zombie_processes.rs:133:21 | LL | let mut x = Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `wait()` is not called in this if branch - --> tests/ui/zombie_processes.rs:128:9 + --> tests/ui/zombie_processes.rs:136:9 | LL | / if true { LL | | // this else block exists to test the other help message LL | | } else { | |_________^ note: `wait()` is called in the other branch - --> tests/ui/zombie_processes.rs:131:13 + --> tests/ui/zombie_processes.rs:139:13 | LL | x.wait().unwrap(); | ^ diff --git a/src/tools/clippy/tests/ui/zombie_processes_fixable.fixed b/src/tools/clippy/tests/ui/zombie_processes_fixable.fixed index 6045262f519a7..220abbfcfd7b9 100644 --- a/src/tools/clippy/tests/ui/zombie_processes_fixable.fixed +++ b/src/tools/clippy/tests/ui/zombie_processes_fixable.fixed @@ -5,16 +5,20 @@ use std::process::{Child, Command}; fn main() { let _ = Command::new("").spawn().unwrap().wait(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes + Command::new("").spawn().unwrap().wait(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes + spawn_proc().wait(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes + spawn_proc().wait().unwrap(); // OK } fn not_main() { Command::new("").spawn().unwrap().wait(); + //~^ zombie_processes } fn spawn_proc() -> Child { diff --git a/src/tools/clippy/tests/ui/zombie_processes_fixable.rs b/src/tools/clippy/tests/ui/zombie_processes_fixable.rs index e1ecb771641e2..820a839cd4619 100644 --- a/src/tools/clippy/tests/ui/zombie_processes_fixable.rs +++ b/src/tools/clippy/tests/ui/zombie_processes_fixable.rs @@ -5,16 +5,20 @@ use std::process::{Child, Command}; fn main() { let _ = Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes + Command::new("").spawn().unwrap(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes + spawn_proc(); - //~^ ERROR: spawned process is never `wait()`ed on + //~^ zombie_processes + spawn_proc().wait().unwrap(); // OK } fn not_main() { Command::new("").spawn().unwrap(); + //~^ zombie_processes } fn spawn_proc() -> Child { diff --git a/src/tools/clippy/tests/ui/zombie_processes_fixable.stderr b/src/tools/clippy/tests/ui/zombie_processes_fixable.stderr index e1c40472c325e..abc593fe4396d 100644 --- a/src/tools/clippy/tests/ui/zombie_processes_fixable.stderr +++ b/src/tools/clippy/tests/ui/zombie_processes_fixable.stderr @@ -10,7 +10,7 @@ LL | let _ = Command::new("").spawn().unwrap(); = help: to override `-D warnings` add `#[allow(clippy::zombie_processes)]` error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes_fixable.rs:9:5 + --> tests/ui/zombie_processes_fixable.rs:10:5 | LL | Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()` @@ -19,7 +19,7 @@ LL | Command::new("").spawn().unwrap(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes_fixable.rs:11:5 + --> tests/ui/zombie_processes_fixable.rs:13:5 | LL | spawn_proc(); | ^^^^^^^^^^^^- help: try: `.wait()` @@ -28,7 +28,7 @@ LL | spawn_proc(); = note: see https://doc.rust-lang.org/stable/std/process/struct.Child.html#warning error: spawned process is never `wait()`ed on - --> tests/ui/zombie_processes_fixable.rs:17:5 + --> tests/ui/zombie_processes_fixable.rs:20:5 | LL | Command::new("").spawn().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: try: `.wait()` diff --git a/src/tools/clippy/tests/ui/{literal_string_with_formatting_args}.rs b/src/tools/clippy/tests/ui/{literal_string_with_formatting_args}.rs new file mode 100644 index 0000000000000..3096558a516a6 --- /dev/null +++ b/src/tools/clippy/tests/ui/{literal_string_with_formatting_args}.rs @@ -0,0 +1,48 @@ +//@check-pass + +// Regression test for . +// The `dbg` macro generates a literal with the name of the current file, so +// we need to ensure the lint is not emitted in this case. + +// Clippy sets `-Zflatten_format_args=no`, which changes the default behavior of how format args +// are lowered and only that one has this non-macro span. Adding the flag makes it repro on +// godbolt and shows a root context span for the file name string. +// +// So instead of having: +// +// ``` +// Lit( +// Spanned { +// node: Str( +// "[/app/example.rs:2:5] \"something\" = ", +// Cooked, +// ), +// span: /rustc/eb54a50837ad4bcc9842924f27e7287ca66e294c/library/std/src/macros.rs:365:35: 365:58 (#4), +// }, +// ), +// ``` +// +// We get: +// +// ``` +// Lit( +// Spanned { +// node: Str( +// "/app/example.rs", +// Cooked, +// ), +// span: /app/example.rs:2:5: 2:22 (#0), +// }, +// ) +// ``` + +#![crate_name = "foo"] +#![allow(unused)] +#![warn(clippy::literal_string_with_formatting_args)] + +fn another_bad() { + let literal_string_with_formatting_args = 0; + dbg!("something"); +} + +fn main() {} diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs index ed357137095ba..f6fc2354ca08b 100644 --- a/src/tools/clippy/tests/versioncheck.rs +++ b/src/tools/clippy/tests/versioncheck.rs @@ -90,3 +90,14 @@ fn check_that_clippy_has_the_same_major_version_as_rustc() { }, } } + +#[test] +fn check_host_compiler() { + // do not run this test inside the upstream rustc repo: + if option_env!("RUSTC_TEST_SUITE").is_some() { + return; + } + + let version = rustc_tools_util::get_version_info!(); + assert_eq!(version.host_compiler, Some("nightly".to_string())); +} diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 98ab7adf5a726..08d3c1c343e08 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -190,6 +190,9 @@ pub struct Config { /// The cargo executable. pub cargo_path: Option, + /// Rustc executable used to compile run-make recipes. + pub stage0_rustc_path: Option, + /// The rustdoc executable. pub rustdoc_path: Option, @@ -220,8 +223,10 @@ pub struct Config { /// The directory containing the test suite sources. Must be a subdirectory of `src_root`. pub src_test_suite_root: PathBuf, - /// The directory where programs should be built - pub build_base: PathBuf, + /// Root build directory (e.g. `build/`). + pub build_root: PathBuf, + /// Test suite specific build directory (e.g. `build/host/test/ui/`). + pub build_test_suite_root: PathBuf, /// The directory containing the compiler sysroot pub sysroot_base: PathBuf, @@ -347,7 +352,7 @@ pub struct Config { /// If true, this will generate a coverage file with UI test files that run `MachineApplicable` /// diagnostics but are missing `run-rustfix` annotations. The generated coverage file is - /// created in `//rustfix_missing_coverage.txt` + /// created in `/rustfix_missing_coverage.txt` pub rustfix_coverage: bool, /// whether to run `tidy` (html-tidy) when a rustdoc test fails @@ -476,9 +481,17 @@ impl Config { } pub fn has_asm_support(&self) -> bool { + // This should match the stable list in `LoweringContext::lower_inline_asm`. static ASM_SUPPORTED_ARCHS: &[&str] = &[ - "x86", "x86_64", "arm", "aarch64", "riscv32", + "x86", + "x86_64", + "arm", + "aarch64", + "arm64ec", + "riscv32", "riscv64", + "loongarch64", + "s390x", // These targets require an additional asm_experimental_arch feature. // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32", ]; @@ -812,12 +825,16 @@ pub const UI_STDERR_16: &str = "16bit.stderr"; pub const UI_COVERAGE: &str = "coverage"; pub const UI_COVERAGE_MAP: &str = "cov-map"; -/// Absolute path to the directory where all output for all tests in the given -/// `relative_dir` group should reside. Example: -/// /path/to/build/host-tuple/test/ui/relative/ +/// Absolute path to the directory where all output for all tests in the given `relative_dir` group +/// should reside. Example: +/// +/// ```text +/// /path/to/build/host-tuple/test/ui/relative/ +/// ``` +/// /// This is created early when tests are collected to avoid race conditions. pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf { - config.build_base.join(relative_dir) + config.build_test_suite_root.join(relative_dir) } /// Generates a unique name for the test, such as `testname.revision.mode`. diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 8c909bcb19527..b2ad5a3b3d0bb 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -52,6 +52,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "ignore-coverage-run", "ignore-cross-compile", "ignore-eabi", + "ignore-elf", "ignore-emscripten", "ignore-endian-big", "ignore-enzyme", @@ -182,6 +183,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-bpf", "only-cdb", "only-dist", + "only-elf", "only-emscripten", "only-gnu", "only-i686-pc-windows-gnu", diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 3bdf37a1f294a..7675e13990d6c 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -709,11 +709,11 @@ impl TestProps { /// returns a struct containing various parts of the directive. fn line_directive<'line>( line_number: usize, - comment: &str, original_line: &'line str, ) -> Option> { // Ignore lines that don't start with the comment prefix. - let after_comment = original_line.trim_start().strip_prefix(comment)?.trim_start(); + let after_comment = + original_line.trim_start().strip_prefix(COMPILETEST_DIRECTIVE_PREFIX)?.trim_start(); let revision; let raw_directive; @@ -722,7 +722,7 @@ fn line_directive<'line>( // A comment like `//@[foo]` only applies to revision `foo`. let Some((line_revision, after_close_bracket)) = after_open_bracket.split_once(']') else { panic!( - "malformed condition directive: expected `{comment}[foo]`, found `{original_line}`" + "malformed condition directive: expected `{COMPILETEST_DIRECTIVE_PREFIX}[foo]`, found `{original_line}`" ) }; @@ -836,6 +836,8 @@ pub(crate) fn check_directive<'a>( CheckDirectiveResult { is_known_directive: is_known(&directive_name), trailing_directive } } +const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; + fn iter_header( mode: Mode, _suite: &str, @@ -849,8 +851,7 @@ fn iter_header( } // Coverage tests in coverage-run mode always have these extra directives, without needing to - // specify them manually in every test file. (Some of the comments below have been copied over - // from the old `tests/run-make/coverage-reports/Makefile`, which no longer exists.) + // specify them manually in every test file. // // FIXME(jieyouxu): I feel like there's a better way to do this, leaving for later. if mode == Mode::CoverageRun { @@ -867,9 +868,6 @@ fn iter_header( } } - // NOTE(jieyouxu): once we get rid of `Makefile`s we can unconditionally check for `//@`. - let comment = if testfile.extension().is_some_and(|e| e == "rs") { "//@" } else { "#" }; - let mut rdr = BufReader::with_capacity(1024, rdr); let mut ln = String::new(); let mut line_number = 0; @@ -882,7 +880,7 @@ fn iter_header( } let ln = ln.trim(); - let Some(directive_line) = line_directive(line_number, comment, ln) else { + let Some(directive_line) = line_directive(line_number, ln) else { continue; }; @@ -1070,10 +1068,11 @@ impl Config { } } +// FIXME(jieyouxu): fix some of these variable names to more accurately reflect what they do. fn expand_variables(mut value: String, config: &Config) -> String { const CWD: &str = "{{cwd}}"; const SRC_BASE: &str = "{{src-base}}"; - const BUILD_BASE: &str = "{{build-base}}"; + const TEST_SUITE_BUILD_BASE: &str = "{{build-base}}"; const RUST_SRC_BASE: &str = "{{rust-src-base}}"; const SYSROOT_BASE: &str = "{{sysroot-base}}"; const TARGET_LINKER: &str = "{{target-linker}}"; @@ -1088,12 +1087,13 @@ fn expand_variables(mut value: String, config: &Config) -> String { value = value.replace(SRC_BASE, &config.src_test_suite_root.to_str().unwrap()); } - if value.contains(BUILD_BASE) { - value = value.replace(BUILD_BASE, &config.build_base.to_string_lossy()); + if value.contains(TEST_SUITE_BUILD_BASE) { + value = + value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.to_str().unwrap()); } if value.contains(SYSROOT_BASE) { - value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_string_lossy()); + value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_str().unwrap()); } if value.contains(TARGET_LINKER) { diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 72a3b9d85c8cf..c369fff97f4f0 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -166,6 +166,16 @@ fn parse_cfg_name_directive<'a>( message: "when the target vendor is Apple" } + condition! { + name: "elf", + condition: !config.target.contains("windows") + && !config.target.contains("wasm") + && !config.target.contains("apple") + && !config.target.contains("aix") + && !config.target.contains("uefi"), + message: "when the target binary format is ELF" + } + condition! { name: "enzyme", condition: config.has_enzyme, diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index c9536b7a19b79..007318be7cc39 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -155,7 +155,8 @@ impl ConfigBuilder { "--jsondocck-path=", "--src-root=", "--src-test-suite-root=", - "--build-base=", + "--build-root=", + "--build-test-suite-root=", "--sysroot-base=", "--cc=c", "--cxx=c++", @@ -238,11 +239,6 @@ fn check_ignore(config: &Config, contents: &str) -> bool { d.ignore } -fn parse_makefile(config: &Config, contents: &str) -> EarlyProps { - let bytes = contents.as_bytes(); - EarlyProps::from_reader(config, Path::new("Makefile"), bytes) -} - #[test] fn should_fail() { let config: Config = cfg().build(); @@ -260,10 +256,6 @@ fn revisions() { let config: Config = cfg().build(); assert_eq!(parse_rs(&config, "//@ revisions: a b c").revisions, vec!["a", "b", "c"],); - assert_eq!( - parse_makefile(&config, "# revisions: hello there").revisions, - vec!["hello", "there"], - ); } #[test] @@ -895,8 +887,6 @@ fn test_needs_target_has_atomic() { } #[test] -// FIXME: this test will fail against stage 0 until #137037 changes reach beta. -#[cfg_attr(bootstrap, ignore)] fn test_rustc_abi() { let config = cfg().target("i686-unknown-linux-gnu").build(); assert_eq!(config.target_cfg().rustc_abi, Some("x86-sse2".to_string())); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 979821701385e..dd611b19a8d0d 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -21,7 +21,7 @@ pub mod util; use core::panic; use std::collections::HashSet; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::io::{self, ErrorKind}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; @@ -54,6 +54,12 @@ pub fn parse_config(args: Vec) -> Config { .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") .optopt("", "cargo-path", "path to cargo to use for compiling", "PATH") + .optopt( + "", + "stage0-rustc-path", + "path to rustc to use for compiling run-make recipes", + "PATH", + ) .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") .optopt("", "coverage-dump-path", "path to coverage-dump to use in tests", "PATH") .reqopt("", "python", "path to python to use for doc tests", "PATH") @@ -63,7 +69,8 @@ pub fn parse_config(args: Vec) -> Config { .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") .reqopt("", "src-root", "directory containing sources", "PATH") .reqopt("", "src-test-suite-root", "directory containing test suite sources", "PATH") - .reqopt("", "build-base", "directory to deposit test outputs", "PATH") + .reqopt("", "build-root", "path to root build directory", "PATH") + .reqopt("", "build-test-suite-root", "path to test suite specific build directory", "PATH") .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH") .reqopt("", "stage", "stage number under test", "N") .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") @@ -157,7 +164,7 @@ pub fn parse_config(args: Vec) -> Config { "", "rustfix-coverage", "enable this to generate a Rustfix coverage file, which is saved in \ - `.//rustfix_missing_coverage.txt`", + `.//rustfix_missing_coverage.txt`", ) .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") .optflag("", "only-modified", "only run tests that result been modified") @@ -267,12 +274,8 @@ pub fn parse_config(args: Vec) -> Config { let path = Path::new(f); let mut iter = path.iter().skip(1); - // We skip the test folder and check if the user passed `rmake.rs` or `Makefile`. - if iter - .next() - .is_some_and(|s| s == OsStr::new("rmake.rs") || s == OsStr::new("Makefile")) - && iter.next().is_none() - { + // We skip the test folder and check if the user passed `rmake.rs`. + if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() { path.parent().unwrap().to_str().unwrap().to_string() } else { f.to_string() @@ -309,12 +312,17 @@ pub fn parse_config(args: Vec) -> Config { src_test_suite_root.display() ); + let build_root = opt_path(matches, "build-root"); + let build_test_suite_root = opt_path(matches, "build-test-suite-root"); + assert!(build_test_suite_root.starts_with(&build_root)); + Config { bless: matches.opt_present("bless"), compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), rustc_path: opt_path(matches, "rustc-path"), cargo_path: matches.opt_str("cargo-path").map(PathBuf::from), + stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(PathBuf::from), rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from), python: matches.opt_str("python").unwrap(), @@ -327,7 +335,9 @@ pub fn parse_config(args: Vec) -> Config { src_root, src_test_suite_root, - build_base: opt_path(matches, "build-base"), + build_root, + build_test_suite_root, + sysroot_base: opt_path(matches, "sysroot-base"), stage, @@ -438,7 +448,11 @@ pub fn log_config(config: &Config) { logv(c, format!("src_root: {}", config.src_root.display())); logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root.display())); - logv(c, format!("build_base: {:?}", config.build_base.display())); + logv(c, format!("build_root: {}", config.build_root.display())); + logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root.display())); + + logv(c, format!("sysroot_base: {}", config.sysroot_base.display())); + logv(c, format!("stage: {}", config.stage)); logv(c, format!("stage_id: {}", config.stage_id)); logv(c, format!("mode: {}", config.mode)); @@ -488,7 +502,7 @@ pub fn run_tests(config: Arc) { // we first make sure that the coverage file does not exist. // It will be created later on. if config.rustfix_coverage { - let mut coverage_file_path = config.build_base.clone(); + let mut coverage_file_path = config.build_test_suite_root.clone(); coverage_file_path.push("rustfix_missing_coverage.txt"); if coverage_file_path.exists() { if let Err(e) = fs::remove_file(&coverage_file_path) { @@ -765,16 +779,9 @@ fn collect_tests_from_dir( return Ok(()); } - // For run-make tests, a "test file" is actually a directory that contains - // an `rmake.rs` or `Makefile`" + // For run-make tests, a "test file" is actually a directory that contains an `rmake.rs`. if cx.config.mode == Mode::RunMake { - if dir.join("Makefile").exists() && dir.join("rmake.rs").exists() { - return Err(io::Error::other( - "run-make tests cannot have both `Makefile` and `rmake.rs`", - )); - } - - if dir.join("Makefile").exists() || dir.join("rmake.rs").exists() { + if dir.join("rmake.rs").exists() { let paths = TestPaths { file: dir.to_path_buf(), relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), @@ -843,24 +850,14 @@ pub fn is_test(file_name: &OsString) -> bool { !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) } -/// For a single test file, creates one or more test structures (one per revision) -/// that can be handed over to libtest to run, possibly in parallel. +/// For a single test file, creates one or more test structures (one per revision) that can be +/// handed over to libtest to run, possibly in parallel. fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &TestPaths) { - // For run-make tests, each "test file" is actually a _directory_ containing - // an `rmake.rs` or `Makefile`. But for the purposes of directive parsing, - // we want to look at that recipe file, not the directory itself. + // For run-make tests, each "test file" is actually a _directory_ containing an `rmake.rs`. But + // for the purposes of directive parsing, we want to look at that recipe file, not the directory + // itself. let test_path = if cx.config.mode == Mode::RunMake { - if testpaths.file.join("rmake.rs").exists() && testpaths.file.join("Makefile").exists() { - panic!("run-make tests cannot have both `rmake.rs` and `Makefile`"); - } - - if testpaths.file.join("rmake.rs").exists() { - // Parse directives in rmake.rs. - testpaths.file.join("rmake.rs") - } else { - // Parse directives in the Makefile. - testpaths.file.join("Makefile") - } + testpaths.file.join("rmake.rs") } else { PathBuf::from(&testpaths.file) }; diff --git a/src/tools/compiletest/src/raise_fd_limit.rs b/src/tools/compiletest/src/raise_fd_limit.rs index 4445ecb7ce857..7b12ba946b9eb 100644 --- a/src/tools/compiletest/src/raise_fd_limit.rs +++ b/src/tools/compiletest/src/raise_fd_limit.rs @@ -7,7 +7,6 @@ #[cfg(target_vendor = "apple")] #[allow(non_camel_case_types)] pub unsafe fn raise_fd_limit() { - use std::mem::size_of_val; use std::ptr::null_mut; use std::{cmp, io}; diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 536e19bc4933e..6e250ca12c937 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -535,7 +535,9 @@ impl<'test> TestCx<'test> { .arg(&out_dir) .arg(&format!("--target={}", target)) .arg("-L") - .arg(&self.config.build_base) + // FIXME(jieyouxu): this search path seems questionable. Is this intended for + // `rust_test_helpers` in ui tests? + .arg(&self.config.build_test_suite_root) .arg("-L") .arg(aux_dir) .arg("-A") @@ -1366,7 +1368,7 @@ impl<'test> TestCx<'test> { // Note: avoid adding a subdirectory of an already filtered directory here, otherwise the // same slice of text will be double counted and the truncation might not happen. add_path(&self.config.src_test_suite_root); - add_path(&self.config.build_base); + add_path(&self.config.build_test_suite_root); read2_abbreviated(child, &filter_paths_from_len).expect("failed to read output") } @@ -1421,7 +1423,7 @@ impl<'test> TestCx<'test> { } fn get_mir_dump_dir(&self) -> PathBuf { - let mut mir_dump_dir = PathBuf::from(self.config.build_base.as_path()); + let mut mir_dump_dir = self.config.build_test_suite_root.clone(); debug!("input_file: {:?}", self.testpaths.file); mir_dump_dir.push(&self.testpaths.relative_dir); mir_dump_dir.push(self.testpaths.file.file_stem().unwrap()); @@ -2410,14 +2412,11 @@ impl<'test> TestCx<'test> { let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf()); normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL"); - // Paths into the build directory - let test_build_dir = &self.config.build_base; - let parent_build_dir = test_build_dir.parent().unwrap().parent().unwrap().parent().unwrap(); - - // eg. /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui - normalize_path(test_build_dir, "$TEST_BUILD_DIR"); + // eg. + // /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui//$name.$revision.$mode/ + normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR"); // eg. /home/user/rust/build - normalize_path(parent_build_dir, "$BUILD_DIR"); + normalize_path(&self.config.build_root, "$BUILD_DIR"); if json { // escaped newlines in json strings should be readable @@ -2436,6 +2435,18 @@ impl<'test> TestCx<'test> { .into_owned(); normalized = Self::normalize_platform_differences(&normalized); + + // Normalize long type name hash. + normalized = + static_regex!(r"\$TEST_BUILD_DIR/(?P[^\.]+).long-type-(?P\d+).txt") + .replace_all(&normalized, |caps: &Captures<'_>| { + format!( + "$TEST_BUILD_DIR/{filename}.long-type-$LONG_TYPE_HASH.txt", + filename = &caps["filename"] + ) + }) + .into_owned(); + normalized = normalized.replace("\t", "\\t"); // makes tabs visible // Remove test annotations like `//~ ERROR text` from the output, diff --git a/src/tools/compiletest/src/runtest/crashes.rs b/src/tools/compiletest/src/runtest/crashes.rs index 885ed3b08faca..da1e74b4a56bc 100644 --- a/src/tools/compiletest/src/runtest/crashes.rs +++ b/src/tools/compiletest/src/runtest/crashes.rs @@ -15,7 +15,7 @@ impl TestCx<'_> { // if a test does not crash, consider it an error if proc_res.status.success() || matches!(proc_res.status.code(), Some(1 | 0)) { self.fatal(&format!( - "crashtest no longer crashes/triggers ICE, horray! Please give it a meaningful \ + "crashtest no longer crashes/triggers ICE, hooray! Please give it a meaningful \ name, add a doc-comment to the start of the test explaining why it exists and \ move it to tests/ui or wherever you see fit. Adding 'Fixes #' to your PR \ description ensures that the corresponding ticket is auto-closed upon merge. \ diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index 591aff0defeb0..ea985866a0522 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -65,7 +65,7 @@ impl TestCx<'_> { // FIXME(#41968): Move this check to tidy? if !errors::load_errors(&self.testpaths.file, self.revision).is_empty() { - self.fatal("compile-pass tests with expected warnings should be moved to ui/"); + self.fatal("build-pass tests with expected warnings should be moved to ui/"); } } diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index 74e6af36ea1dd..073116933bdb6 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -9,182 +9,16 @@ use crate::util::{copy_dir_all, dylib_env_var}; impl TestCx<'_> { pub(super) fn run_rmake_test(&self) { - let test_dir = &self.testpaths.file; - if test_dir.join("rmake.rs").exists() { - self.run_rmake_v2_test(); - } else if test_dir.join("Makefile").exists() { - self.run_rmake_legacy_test(); - } else { - self.fatal("failed to find either `rmake.rs` or `Makefile`") - } - } - - fn run_rmake_legacy_test(&self) { - let cwd = env::current_dir().unwrap(); - - // FIXME(Zalathar): This should probably be `output_base_dir` to avoid - // an unnecessary extra subdirectory, but since legacy Makefile tests - // are hopefully going away, it seems safer to leave this perilous code - // as-is until it can all be deleted. - let tmpdir = cwd.join(self.output_base_name()); - ignore_not_found(|| recursive_remove(&tmpdir)).unwrap(); - - fs::create_dir_all(&tmpdir).unwrap(); - - let host = &self.config.host; - let make = if host.contains("dragonfly") - || host.contains("freebsd") - || host.contains("netbsd") - || host.contains("openbsd") - || host.contains("aix") - { - "gmake" - } else { - "make" - }; - - let mut cmd = Command::new(make); - cmd.current_dir(&self.testpaths.file) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()) - .env("TARGET", &self.config.target) - .env("PYTHON", &self.config.python) - .env("S", &self.config.src_root) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("TMPDIR", &tmpdir) - .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components) - // We for sure don't want these tests to run in parallel, so make - // sure they don't have access to these vars if we run via `make` - // at the top level - .env_remove("MAKEFLAGS") - .env_remove("MFLAGS") - .env_remove("CARGO_MAKEFLAGS"); - - if let Some(ref cargo) = self.config.cargo_path { - cmd.env("CARGO", cwd.join(cargo)); - } - - if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", cwd.join(rustdoc)); - } - - if let Some(ref node) = self.config.nodejs { - cmd.env("NODE", node); - } - - if let Some(ref linker) = self.config.target_linker { - cmd.env("RUSTC_LINKER", linker); - } - - if let Some(ref clang) = self.config.run_clang_based_tests_with { - cmd.env("CLANG", clang); - } - - if let Some(ref filecheck) = self.config.llvm_filecheck { - cmd.env("LLVM_FILECHECK", filecheck); - } - - if let Some(ref llvm_bin_dir) = self.config.llvm_bin_dir { - cmd.env("LLVM_BIN_DIR", llvm_bin_dir); - } - - if let Some(ref remote_test_client) = self.config.remote_test_client { - cmd.env("REMOTE_TEST_CLIENT", remote_test_client); - } - - // We don't want RUSTFLAGS set from the outside to interfere with - // compiler flags set in the test cases: - cmd.env_remove("RUSTFLAGS"); - - // Use dynamic musl for tests because static doesn't allow creating dylibs - if self.config.host.contains("musl") { - cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); - } - - if self.config.bless { - cmd.env("RUSTC_BLESS_TEST", "--bless"); - // Assume this option is active if the environment variable is "defined", with _any_ value. - // As an example, a `Makefile` can use this option by: - // - // ifdef RUSTC_BLESS_TEST - // cp "$(TMPDIR)"/actual_something.ext expected_something.ext - // else - // $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext - // endif - } - - if self.config.target.contains("msvc") && !self.config.cc.is_empty() { - // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` - // and that `lib.exe` lives next to it. - let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe"); - - // MSYS doesn't like passing flags of the form `/foo` as it thinks it's - // a path and instead passes `C:\msys64\foo`, so convert all - // `/`-arguments to MSVC here to `-` arguments. - let cflags = self - .config - .cflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::>() - .join(" "); - let cxxflags = self - .config - .cxxflags - .split(' ') - .map(|s| s.replace("/", "-")) - .collect::>() - .join(" "); - - cmd.env("IS_MSVC", "1") - .env("IS_WINDOWS", "1") - .env("MSVC_LIB", format!("'{}' -nologo", lib.display())) - .env("MSVC_LIB_PATH", format!("{}", lib.display())) - .env("CC", format!("'{}' {}", self.config.cc, cflags)) - .env("CXX", format!("'{}' {}", &self.config.cxx, cxxflags)); - } else { - cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cxxflags)) - .env("AR", &self.config.ar); - - if self.config.target.contains("windows") { - cmd.env("IS_WINDOWS", "1"); - } - } - - let (output, truncated) = - self.read2_abbreviated(cmd.spawn().expect("failed to spawn `make`")); - if !output.status.success() { - let res = ProcRes { - status: output.status, - stdout: String::from_utf8_lossy(&output.stdout).into_owned(), - stderr: String::from_utf8_lossy(&output.stderr).into_owned(), - truncated, - cmdline: format!("{:?}", cmd), - }; - self.fatal_proc_rec("make failed", &res); - } - } - - fn run_rmake_v2_test(&self) { // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust - // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. + // library and is available under + // `build/$HOST/stage0-bootstrap-tools/$TARGET/release/librun_make_support.rlib`. // // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support` // library. // 2. We need to run the recipe binary. - // `self.config.build_base` is actually the build base folder + "test" + test suite name, it - // looks like `build//test/run-make`. But we want `build//`. Note - // that the `build` directory does not need to be called `build`, nor does it need to be - // under `src_root`, so we must compute it based off of `self.config.build_base`. - let build_root = - self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf(); + let host_build_root = self.config.build_root.join(&self.config.host); // We construct the following directory tree for each rmake.rs test: // ``` @@ -196,8 +30,6 @@ impl TestCx<'_> { // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove // a currently running executable because the recipe executable is not under the // `rmake_out/` directory. - // - // This setup intentionally diverges from legacy Makefile run-make tests. let base_dir = self.output_base_dir(); ignore_not_found(|| recursive_remove(&base_dir)).unwrap(); @@ -229,25 +61,21 @@ impl TestCx<'_> { // // ``` // build// - // ├── stageN-tools-bin/ - // │ └── librun_make_support.rlib // <- support rlib itself - // ├── stageN-tools/ - // │ ├── release/deps/ // <- deps of deps - // │ └── /release/deps/ // <- deps + // ├── stage0-bootstrap-tools/ + // │ ├── /release/librun_make_support.rlib // <- support rlib itself + // │ ├── /release/deps/ // <- deps + // │ └── release/deps/ // <- deps of deps // ``` // // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the - // support lib and its deps are organized, can't we copy them to the tools-bin dir as - // well?), but this seems to work for now. + // support lib and its deps are organized), but this seems to work for now. - let stage_number = self.config.stage; + let tools_bin = host_build_root.join("stage0-bootstrap-tools"); + let support_host_path = tools_bin.join(&self.config.host).join("release"); + let support_lib_path = support_host_path.join("librun_make_support.rlib"); - let stage_tools_bin = build_root.join(format!("stage{stage_number}-tools-bin")); - let support_lib_path = stage_tools_bin.join("librun_make_support.rlib"); - - let stage_tools = build_root.join(format!("stage{stage_number}-tools")); - let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps"); - let support_lib_deps_deps = stage_tools.join("release").join("deps"); + let support_lib_deps = support_host_path.join("deps"); + let support_lib_deps_deps = tools_bin.join("release").join("deps"); // To compile the recipe with rustc, we need to provide suitable dynamic library search // paths to rustc. This includes both: @@ -258,12 +86,6 @@ impl TestCx<'_> { let base_dylib_search_paths = Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); - let host_dylib_search_paths = { - let mut paths = vec![self.config.compile_lib_path.clone()]; - paths.extend(base_dylib_search_paths.iter().cloned()); - paths - }; - // Calculate the paths of the recipe binary. As previously discussed, this is placed at // `/` with `bin_name` being `rmake` or `rmake.exe` depending on // platform. @@ -273,8 +95,21 @@ impl TestCx<'_> { p }; - let mut rustc = Command::new(&self.config.rustc_path); + // run-make-support and run-make tests are compiled using the stage0 compiler + // If the stage is 0, then the compiler that we test (either bootstrap or an explicitly + // set compiler) is the one that actually compiled run-make-support. + let stage0_rustc = self + .config + .stage0_rustc_path + .as_ref() + .expect("stage0 rustc is required to run run-make tests"); + let mut rustc = Command::new(&stage0_rustc); rustc + // `rmake.rs` **must** be buildable by a stable compiler, it may not use *any* unstable + // library or compiler features. Here, we force the stage 0 rustc to consider itself as + // a stable-channel compiler via `RUSTC_BOOTSTRAP=-1` to prevent *any* unstable + // library/compiler usages, even if stage 0 rustc is *actually* a nightly rustc. + .env("RUSTC_BOOTSTRAP", "-1") .arg("-o") .arg(&recipe_bin) // Specify library search paths for `run_make_support`. @@ -287,35 +122,12 @@ impl TestCx<'_> { .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) - .arg("-Cprefer-dynamic") - // Provide necessary library search paths for rustc. - .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); + .arg("-Cprefer-dynamic"); // In test code we want to be very pedantic about values being silently discarded that are // annotated with `#[must_use]`. rustc.arg("-Dunused_must_use"); - // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc - // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is - // > compiled using the bootstrap rustc wrapper which sets `--sysroot - // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile - // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the - // > `libstd.rlib` against which `librun_make_support.rlib` is compiled. - // - // The gist here is that we have to pass the proper stage0 sysroot if we want - // - // ``` - // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0 - // ``` - // - // to work correctly. - // - // See for more background. - let stage0_sysroot = build_root.join("stage0-sysroot"); - if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { - rustc.arg("--sysroot").arg(&stage0_sysroot); - } - // Now run rustc to build the recipe. let res = self.run_command_to_procres(&mut rustc); if !res.status.success() { @@ -325,35 +137,24 @@ impl TestCx<'_> { // To actually run the recipe, we have to provide the recipe with a bunch of information // provided through env vars. - // Compute stage-specific standard library paths. - let stage_std_path = build_root.join(format!("stage{stage_number}")).join("lib"); - // Compute dynamic library search paths for recipes. + // These dylib directories are needed to **execute the recipe**. let recipe_dylib_search_paths = { let mut paths = base_dylib_search_paths.clone(); - - // For stage 0, we need to explicitly include the stage0-sysroot libstd dylib. - // See . - if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { - paths.push( - stage0_sysroot.join("lib").join("rustlib").join(&self.config.host).join("lib"), - ); - } - - paths.push(support_lib_path.parent().unwrap().to_path_buf()); - paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); - paths - }; - - // Compute runtime library search paths for recipes. This is target-specific. - let target_runtime_dylib_search_paths = { - let mut paths = vec![rmake_out_dir.clone()]; - paths.extend(base_dylib_search_paths.iter().cloned()); + paths.push( + stage0_rustc + .parent() + .unwrap() + .parent() + .unwrap() + .join("lib") + .join("rustlib") + .join(&self.config.host) + .join("lib"), + ); paths }; - // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and - // `TARGET_RPATH_DIR`, it is **extremely** confusing! let mut cmd = Command::new(&recipe_bin); cmd.current_dir(&rmake_out_dir) .stdout(Stdio::piped()) @@ -362,9 +163,14 @@ impl TestCx<'_> { // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows. .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) // Provide the dylib search paths. + // This is required to run the **recipe** itself. .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap()) - // Provide runtime dylib search paths. - .env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap()) + // Provide the directory to libraries that are needed to run the *compiler* invoked + // by the recipe. + .env("HOST_RUSTC_DYLIB_PATH", &self.config.compile_lib_path) + // Provide the directory to libraries that might be needed to run binaries created + // by a compiler invoked by the recipe. + .env("TARGET_EXE_DYLIB_PATH", &self.config.run_lib_path) // Provide the target. .env("TARGET", &self.config.target) // Some tests unfortunately still need Python, so provide path to a Python interpreter. @@ -372,16 +178,9 @@ impl TestCx<'_> { // Provide path to sources root. .env("SOURCE_ROOT", &self.config.src_root) // Path to the host build directory. - .env("BUILD_ROOT", &build_root) + .env("BUILD_ROOT", &host_build_root) // Provide path to stage-corresponding rustc. .env("RUSTC", &self.config.rustc_path) - // Provide the directory to libraries that are needed to run the *compiler*. This is not - // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the - // recipe wants to invoke rustc. - .env("HOST_RPATH_DIR", &self.config.compile_lib_path) - // Provide the directory to libraries that might be needed to run compiled binaries - // (further compiled by the recipe!). - .env("TARGET_RPATH_DIR", &self.config.run_lib_path) // Provide which LLVM components are available (e.g. which LLVM components are provided // through a specific CI runner). .env("LLVM_COMPONENTS", &self.config.llvm_components); diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index 0c6d46188e6f4..3329e10745f8d 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -66,7 +66,7 @@ impl TestCx<'_> { && !self.props.run_rustfix && !self.props.rustfix_only_machine_applicable { - let mut coverage_file_path = self.config.build_base.clone(); + let mut coverage_file_path = self.config.build_test_suite_root.clone(); coverage_file_path.push("rustfix_missing_coverage.txt"); debug!("coverage_file_path: {}", coverage_file_path.display()); diff --git a/src/tools/enzyme b/src/tools/enzyme index 5004a8f6f5d84..a35f4f773118c 160000 --- a/src/tools/enzyme +++ b/src/tools/enzyme @@ -1 +1 @@ -Subproject commit 5004a8f6f5d8468b64fae457afb7d96e1784c783 +Subproject commit a35f4f773118ccfbd8d05102eb12a34097b1ee55 diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 7bfa7e3355d3f..54249fbd9ae71 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::process::ExitCode; -use std::sync::OnceLock; +use std::sync::LazyLock; use std::{env, fs}; use regex::{Regex, RegexBuilder}; @@ -151,8 +151,7 @@ impl CommandKind { } } -static LINE_PATTERN: OnceLock = OnceLock::new(); -fn line_pattern() -> Regex { +static LINE_PATTERN: LazyLock = LazyLock::new(|| { RegexBuilder::new( r#" //@\s+ @@ -165,7 +164,19 @@ fn line_pattern() -> Regex { .unicode(true) .build() .unwrap() -} +}); + +static DEPRECATED_LINE_PATTERN: LazyLock = LazyLock::new(|| { + RegexBuilder::new( + r#" + //\s+@ + "#, + ) + .ignore_whitespace(true) + .unicode(true) + .build() + .unwrap() +}); fn print_err(msg: &str, lineno: usize) { eprintln!("Invalid command: {} on line {}", msg, lineno) @@ -184,21 +195,23 @@ fn get_commands(template: &str) -> Result, ()> { for (lineno, line) in file.split('\n').enumerate() { let lineno = lineno + 1; - let cap = match LINE_PATTERN.get_or_init(line_pattern).captures(line) { - Some(c) => c, - None => continue, + if DEPRECATED_LINE_PATTERN.is_match(line) { + print_err("Deprecated command syntax, replace `// @` with `//@ `", lineno); + errors = true; + continue; + } + + let Some(cap) = LINE_PATTERN.captures(line) else { + continue; }; - let negated = cap.name("negated").unwrap().as_str() == "!"; + let negated = &cap["negated"] == "!"; let args_str = &cap["args"]; - let args = match shlex::split(args_str) { - Some(args) => args, - None => { - print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno); - errors = true; - continue; - } + let Some(args) = shlex::split(args_str) else { + print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno); + errors = true; + continue; }; if let Some((kind, path)) = CommandKind::parse(&cap["cmd"], negated, &args) { diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 791b231c27a06..8c9e4c8bb3a60 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -326,6 +326,7 @@ impl<'a> Validator<'a> { self.check_type(o); } } + GenericArgs::ReturnTypeNotation => {} } } diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index f1be6e9e749d4..7123d43eb564c 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -9,4 +9,4 @@ path = "main.rs" [dependencies] regex = "1" -html5ever = "0.27.0" +html5ever = "0.29.0" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 19340b5d07a11..84cba3f8c4473 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -16,7 +16,7 @@ //! A few exceptions are allowed as there's known bugs in rustdoc, but this //! should catch the majority of "broken link" cases. -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::io::ErrorKind; use std::path::{Component, Path, PathBuf}; @@ -544,7 +544,7 @@ fn parse_html(source: &str, sink: Sink) -> Sink { let mut input = BufferQueue::default(); input.push_back(tendril.try_reinterpret().unwrap()); - let mut tok = Tokenizer::new(sink, TokenizerOpts::default()); + let tok = Tokenizer::new(sink, TokenizerOpts::default()); let _ = tok.feed(&mut input); assert!(input.is_empty()); tok.end(); @@ -554,8 +554,8 @@ fn parse_html(source: &str, sink: Sink) -> Sink { #[derive(Default)] struct AttrCollector { attr_name: &'static [u8], - base: Option, - found_attrs: Vec<(u64, String)>, + base: Cell>, + found_attrs: RefCell>, /// Tracks whether or not it is inside a

(self, predicate: P) -> Filter where Self: Sized, @@ -954,7 +954,7 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "enumerate_method")] + #[rustc_diagnostic_item = "enumerate_method"] fn enumerate(self) -> Enumerate where Self: Sized, @@ -1825,10 +1825,19 @@ pub trait Iterator { Inspect::new(self, f) } - /// Borrows an iterator, rather than consuming it. + /// Creates a "by reference" adapter for this instance of `Iterator`. /// - /// This is useful to allow applying iterator adapters while still - /// retaining ownership of the original iterator. + /// Consuming method calls (direct or indirect calls to `next`) + /// on the "by reference" adapter will consume the original iterator, + /// but ownership-taking methods (those with a `self` parameter) + /// only take ownership of the "by reference" iterator. + /// + /// This is useful for applying ownership-taking methods + /// (such as `take` in the example below) + /// without giving up ownership of the original iterator, + /// so you can use the original iterator afterwards. + /// + /// Uses [impl Iterator for &mut I { type Item = I::Item; ...}](https://doc.rust-lang.org/nightly/std/iter/trait.Iterator.html#impl-Iterator-for-%26mut+I). /// /// # Examples /// @@ -1963,11 +1972,20 @@ pub trait Iterator { #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you really need to exhaust the iterator, consider `.for_each(drop)` instead"] - #[cfg_attr(not(test), rustc_diagnostic_item = "iterator_collect_fn")] + #[rustc_diagnostic_item = "iterator_collect_fn"] fn collect>(self) -> B where Self: Sized, { + // This is too aggressive to turn on for everything all the time, but PR#137908 + // accidentally noticed that some rustc iterators had malformed `size_hint`s, + // so this will help catch such things in debug-assertions-std runners, + // even if users won't actually ever see it. + if cfg!(debug_assertions) { + let hint = self.size_hint(); + assert!(hint.1.is_none_or(|high| high >= hint.0), "Malformed size_hint {hint:?}"); + } + FromIterator::from_iter(self) } @@ -3358,7 +3376,7 @@ pub trait Iterator { /// assert_eq!(v_map, vec![1, 2, 3]); /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "iter_copied")] + #[rustc_diagnostic_item = "iter_copied"] fn copied<'a, T: 'a>(self) -> Copied where Self: Sized + Iterator, @@ -3406,7 +3424,7 @@ pub trait Iterator { /// assert_eq!(&[vec![23]], &faster[..]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "iter_cloned")] + #[rustc_diagnostic_item = "iter_cloned"] fn cloned<'a, T: 'a>(self) -> Cloned where Self: Sized + Iterator, @@ -4024,6 +4042,9 @@ where } } +/// Implements `Iterator` for mutable references to iterators, such as those produced by [`Iterator::by_ref`]. +/// +/// This implementation passes all method calls on to the original iterator. #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for &mut I { type Item = I::Item; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 99d5af9f0ef95..e1ca69edcbbd9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -43,18 +43,6 @@ //! which do not trigger a panic can be assured that this function is never //! called. The `lang` attribute is called `eh_personality`. -// Since core defines many fundamental lang items, all tests live in a -// separate crate, coretests (library/coretests), to avoid bizarre issues. -// -// Here we explicitly #[cfg]-out this whole crate when testing. If we don't do -// this, both the generated test artifact and the linked libtest (which -// transitively includes core) will both define the same set of lang items, -// and this will cause the E0152 "found duplicate lang item" error. See -// discussion in #50466 for details. -// -// This cfg won't affect doc tests. -#![cfg(not(test))] -// #![stable(feature = "core", since = "1.6.0")] #![doc( html_playground_url = "https://play.rust-lang.org/", @@ -64,7 +52,6 @@ )] #![doc(rust_logo)] #![doc(cfg_hide( - not(test), no_fp_fmt_parse, target_pointer_width = "16", target_pointer_width = "32", @@ -202,14 +189,17 @@ // // Target features: // tidy-alphabetical-start +#![feature(aarch64_unstable_target_feature)] #![feature(arm_target_feature)] #![feature(avx512_target_feature)] #![feature(hexagon_target_feature)] +#![feature(keylocker_x86)] #![feature(loongarch_target_feature)] #![feature(mips_target_feature)] #![feature(powerpc_target_feature)] #![feature(riscv_target_feature)] #![feature(rtm_target_feature)] +#![feature(s390x_target_feature)] #![feature(sha512_sm_x86)] #![feature(sse4a_target_feature)] #![feature(tbm_target_feature)] @@ -223,15 +213,11 @@ extern crate self as core; #[prelude_import] #[allow(unused)] -use prelude::rust_2021::*; +use prelude::rust_2024::*; -#[cfg(not(test))] // See #65860 #[macro_use] mod macros; -// We don't export this through #[macro_export] for now, to avoid breakage. -// See https://github.com/rust-lang/rust/issues/82913 -#[cfg(not(test))] #[unstable(feature = "assert_matches", issue = "82775")] /// Unstable module containing the unstable `assert_matches` macro. pub mod assert_matches { @@ -247,7 +233,6 @@ pub mod autodiff { pub use crate::macros::builtin::autodiff; } -#[cfg(not(bootstrap))] #[unstable(feature = "contracts", issue = "128044")] pub mod contracts; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 4c6fd196bd31c..fa0d882181a51 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -37,7 +37,7 @@ macro_rules! panic { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "assert_eq_macro")] +#[rustc_diagnostic_item = "assert_eq_macro"] #[allow_internal_unstable(panic_internals)] macro_rules! assert_eq { ($left:expr, $right:expr $(,)?) => { @@ -93,7 +93,7 @@ macro_rules! assert_eq { /// ``` #[macro_export] #[stable(feature = "assert_ne", since = "1.13.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "assert_ne_macro")] +#[rustc_diagnostic_item = "assert_ne_macro"] #[allow_internal_unstable(panic_internals)] macro_rules! assert_ne { ($left:expr, $right:expr $(,)?) => { @@ -196,95 +196,6 @@ pub macro assert_matches { }, } -/// A macro for defining `#[cfg]` match-like statements. -/// -/// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of -/// `#[cfg]` cases, emitting the implementation which matches first. -/// -/// This allows you to conveniently provide a long list `#[cfg]`'d blocks of code -/// without having to rewrite each clause multiple times. -/// -/// Trailing `_` wildcard match arms are **optional** and they indicate a fallback branch when -/// all previous declarations do not evaluate to true. -/// -/// # Example -/// -/// ``` -/// #![feature(cfg_match)] -/// -/// cfg_match! { -/// cfg(unix) => { -/// fn foo() { /* unix specific functionality */ } -/// } -/// cfg(target_pointer_width = "32") => { -/// fn foo() { /* non-unix, 32-bit functionality */ } -/// } -/// _ => { -/// fn foo() { /* fallback implementation */ } -/// } -/// } -/// ``` -#[cfg(bootstrap)] -#[unstable(feature = "cfg_match", issue = "115585")] -#[rustc_diagnostic_item = "cfg_match"] -pub macro cfg_match { - // with a final wildcard - ( - $(cfg($initial_meta:meta) => { $($initial_tokens:tt)* })+ - _ => { $($extra_tokens:tt)* } - ) => { - cfg_match! { - @__items (); - $((($initial_meta) ($($initial_tokens)*)),)+ - (() ($($extra_tokens)*)), - } - }, - - // without a final wildcard - ( - $(cfg($extra_meta:meta) => { $($extra_tokens:tt)* })* - ) => { - cfg_match! { - @__items (); - $((($extra_meta) ($($extra_tokens)*)),)* - } - }, - - // Internal and recursive macro to emit all the items - // - // Collects all the previous cfgs in a list at the beginning, so they can be - // negated. After the semicolon is all the remaining items. - (@__items ($($_:meta,)*);) => {}, - ( - @__items ($($no:meta,)*); - (($($yes:meta)?) ($($tokens:tt)*)), - $($rest:tt,)* - ) => { - // Emit all items within one block, applying an appropriate #[cfg]. The - // #[cfg] will require all `$yes` matchers specified and must also negate - // all previous matchers. - #[cfg(all( - $($yes,)? - not(any($($no),*)) - ))] - cfg_match! { @__identity $($tokens)* } - - // Recurse to emit all other items in `$rest`, and when we do so add all - // our `$yes` matchers to the list of `$no` matchers as future emissions - // will have to negate everything we just matched as well. - cfg_match! { - @__items ($($no,)* $($yes,)?); - $($rest,)* - } - }, - - // Internal macro to make __apply work out right for different match types, - // because of how macros match/expand stuff. - (@__identity $($tokens:tt)*) => { - $($tokens)* - } -} - /// A macro for defining `#[cfg]` match-like statements. /// /// It is similar to the `if/elif` C preprocessor macro by allowing definition of a cascade of @@ -324,7 +235,6 @@ pub macro cfg_match { /// _ => { "Behind every successful diet is an unwatched pizza" } /// }}; /// ``` -#[cfg(not(bootstrap))] #[unstable(feature = "cfg_match", issue = "115585")] #[rustc_diagnostic_item = "cfg_match"] pub macro cfg_match { @@ -421,7 +331,7 @@ macro_rules! debug_assert { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_eq_macro")] +#[rustc_diagnostic_item = "debug_assert_eq_macro"] macro_rules! debug_assert_eq { ($($arg:tt)*) => { if $crate::cfg!(debug_assertions) { @@ -451,7 +361,7 @@ macro_rules! debug_assert_eq { /// ``` #[macro_export] #[stable(feature = "assert_ne", since = "1.13.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_ne_macro")] +#[rustc_diagnostic_item = "debug_assert_ne_macro"] macro_rules! debug_assert_ne { ($($arg:tt)*) => { if $crate::cfg!(debug_assertions) { @@ -532,7 +442,7 @@ pub macro debug_assert_matches($($arg:tt)*) { /// ``` #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")] +#[rustc_diagnostic_item = "matches_macro"] macro_rules! matches { ($expression:expr, $pattern:pat $(if $guard:expr)? $(,)?) => { match $expression { @@ -707,7 +617,7 @@ macro_rules! r#try { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")] +#[rustc_diagnostic_item = "write_macro"] macro_rules! write { ($dst:expr, $($arg:tt)*) => { $dst.write_fmt($crate::format_args!($($arg)*)) @@ -741,7 +651,7 @@ macro_rules! write { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")] +#[rustc_diagnostic_item = "writeln_macro"] #[allow_internal_unstable(format_args_nl)] macro_rules! writeln { ($dst:expr $(,)?) => { @@ -808,7 +718,7 @@ macro_rules! writeln { #[rustc_builtin_macro(unreachable)] #[allow_internal_unstable(edition_panic)] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")] +#[rustc_diagnostic_item = "unreachable_macro"] macro_rules! unreachable { // Expands to either `$crate::panic::unreachable_2015` or `$crate::panic::unreachable_2021` // depending on the edition of the caller. @@ -893,7 +803,7 @@ macro_rules! unreachable { /// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "unimplemented_macro")] +#[rustc_diagnostic_item = "unimplemented_macro"] #[allow_internal_unstable(panic_internals)] macro_rules! unimplemented { () => { @@ -973,7 +883,7 @@ macro_rules! unimplemented { /// ``` #[macro_export] #[stable(feature = "todo_macro", since = "1.40.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "todo_macro")] +#[rustc_diagnostic_item = "todo_macro"] #[allow_internal_unstable(panic_internals)] macro_rules! todo { () => { @@ -1085,7 +995,7 @@ pub(crate) mod builtin { /// and cannot be stored for later use. /// This is a known limitation, see [#92698](https://github.com/rust-lang/rust/issues/92698). #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "format_args_macro")] + #[rustc_diagnostic_item = "format_args_macro"] #[allow_internal_unsafe] #[allow_internal_unstable(fmt_internals)] #[rustc_builtin_macro] @@ -1432,7 +1342,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "include_str_macro")] + #[rustc_diagnostic_item = "include_str_macro"] macro_rules! include_str { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -1472,7 +1382,7 @@ pub(crate) mod builtin { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_builtin_macro] #[macro_export] - #[cfg_attr(not(test), rustc_diagnostic_item = "include_bytes_macro")] + #[rustc_diagnostic_item = "include_bytes_macro"] macro_rules! include_bytes { ($file:expr $(,)?) => {{ /* compiler built-in */ }}; } @@ -1782,7 +1692,6 @@ pub(crate) mod builtin { /// The attribute carries an argument token-tree which is /// eventually parsed as a unary closure expression that is /// invoked on a reference to the return value. - #[cfg(not(bootstrap))] #[unstable(feature = "contracts", issue = "128044")] #[allow_internal_unstable(contracts_internals)] #[rustc_builtin_macro] @@ -1795,7 +1704,6 @@ pub(crate) mod builtin { /// The attribute carries an argument token-tree which is /// eventually parsed as an boolean expression with access to the /// function's formal parameters - #[cfg(not(bootstrap))] #[unstable(feature = "contracts", issue = "128044")] #[allow_internal_unstable(contracts_internals)] #[rustc_builtin_macro] @@ -1835,6 +1743,21 @@ pub(crate) mod builtin { /* compiler built-in */ } + /// Provide a list of type aliases and other opaque-type-containing type definitions. + /// This list will be used in the body of the item it is applied to to define opaque + /// types' hidden types. + /// Can only be applied to things that have bodies. + #[unstable( + feature = "type_alias_impl_trait", + issue = "63063", + reason = "`type_alias_impl_trait` has open design concerns" + )] + #[rustc_builtin_macro] + #[cfg(not(bootstrap))] + pub macro define_opaque($($tt:tt)*) { + /* compiler built-in */ + } + /// Unstable placeholder for type ascription. #[allow_internal_unstable(builtin_syntax)] #[unstable( diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 042ee419d57e4..68011310d2cad 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -82,7 +82,7 @@ macro marker_impls { /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Send")] +#[rustc_diagnostic_item = "Send"] #[diagnostic::on_unimplemented( message = "`{Self}` cannot be sent between threads safely", label = "`{Self}` cannot be sent between threads safely" @@ -405,7 +405,7 @@ marker_impls! { /// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html -/// [`size_of::`]: crate::mem::size_of +/// [`size_of::`]: size_of /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] @@ -453,8 +453,8 @@ impl Copy for ! {} #[stable(feature = "rust1", since = "1.0.0")] impl Copy for &T {} -/// Marker trait for the types that are allowed in union fields, unsafe fields, -/// and unsafe binder types. +/// Marker trait for the types that are allowed in union fields and unsafe +/// binder types. /// /// Implemented for: /// * `&T`, `&mut T` for all `T`, @@ -465,9 +465,13 @@ impl Copy for &T {} /// Notably, this doesn't include all trivially-destructible types for semver /// reasons. /// -/// Bikeshed name for now. +/// Bikeshed name for now. This trait does not do anything other than reflect the +/// set of types that are allowed within unions for field validity. #[unstable(feature = "bikeshed_guaranteed_no_drop", issue = "none")] -#[cfg_attr(not(bootstrap), lang = "bikeshed_guaranteed_no_drop")] +#[lang = "bikeshed_guaranteed_no_drop"] +#[rustc_deny_explicit_impl] +#[rustc_do_not_implement_via_object] +#[doc(hidden)] pub trait BikeshedGuaranteedNoDrop {} /// Types for which it is safe to share references between threads. @@ -541,7 +545,7 @@ pub trait BikeshedGuaranteedNoDrop {} /// [transmute]: crate::mem::transmute /// [nomicon-send-and-sync]: ../../nomicon/send-and-sync.html #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Sync")] +#[rustc_diagnostic_item = "Sync"] #[lang = "sync"] #[rustc_on_unimplemented( on( @@ -731,7 +735,6 @@ impl !Sync for *mut T {} /// # } /// # fn convert_params(_: ParamType) -> usize { 42 } /// use std::marker::PhantomData; -/// use std::mem; /// /// struct ExternalResource { /// resource_handle: *mut (), @@ -740,7 +743,7 @@ impl !Sync for *mut T {} /// /// impl ExternalResource { /// fn new() -> Self { -/// let size_of_res = mem::size_of::(); +/// let size_of_res = size_of::(); /// Self { /// resource_handle: foreign_lib::new(size_of_res), /// resource_type: PhantomData, @@ -1302,6 +1305,7 @@ pub trait FnPtr: Copy + Clone { /// ``` #[rustc_builtin_macro(CoercePointee, attributes(pointee))] #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize, coerce_pointee_validated)] +#[rustc_diagnostic_item = "CoercePointee"] #[unstable(feature = "derive_coerce_pointee", issue = "123430")] pub macro CoercePointee($item:item) { /* compiler built-in */ @@ -1313,7 +1317,6 @@ pub macro CoercePointee($item:item) { /// /// This trait is not intended to be implemented by users or used other than /// validation, so it should never be stabilized. -#[cfg(not(bootstrap))] #[lang = "coerce_pointee_validated"] #[unstable(feature = "coerce_pointee_validated", issue = "none")] #[doc(hidden)] diff --git a/library/core/src/marker/variance.rs b/library/core/src/marker/variance.rs index 23334e6575ddf..235f8a3bb79f2 100644 --- a/library/core/src/marker/variance.rs +++ b/library/core/src/marker/variance.rs @@ -136,6 +136,8 @@ phantom_lifetime! { /// For all `'a`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` + #[rustc_pub_transparent] + #[repr(transparent)] pub struct PhantomCovariantLifetime<'a>(PhantomCovariant<&'a ()>); /// Zero-sized type used to mark a lifetime as contravariant. /// @@ -149,6 +151,8 @@ phantom_lifetime! { /// For all `'a`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` + #[rustc_pub_transparent] + #[repr(transparent)] pub struct PhantomContravariantLifetime<'a>(PhantomContravariant<&'a ()>); /// Zero-sized type used to mark a lifetime as invariant. /// @@ -162,6 +166,8 @@ phantom_lifetime! { /// For all `'a`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` + #[rustc_pub_transparent] + #[repr(transparent)] pub struct PhantomInvariantLifetime<'a>(PhantomInvariant<&'a ()>); } @@ -179,6 +185,8 @@ phantom_type! { /// For all `T`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` + #[rustc_pub_transparent] + #[repr(transparent)] pub struct PhantomCovariant(PhantomData T>); /// Zero-sized type used to mark a type parameter as contravariant. /// @@ -193,6 +201,8 @@ phantom_type! { /// For all `T`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` + #[rustc_pub_transparent] + #[repr(transparent)] pub struct PhantomContravariant(PhantomData); /// Zero-sized type used to mark a type parameter as invariant. /// @@ -206,6 +216,8 @@ phantom_type! { /// For all `T`, the following are guaranteed: /// * `size_of::>() == 0` /// * `align_of::>() == 1` + #[rustc_pub_transparent] + #[repr(transparent)] pub struct PhantomInvariant(PhantomData T>); } diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index edc39f8f28cf5..ce84f105e5c50 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -203,7 +203,7 @@ use crate::{fmt, intrinsics, ptr, slice}; /// `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as `T`: /// /// ```rust -/// use std::mem::{MaybeUninit, size_of, align_of}; +/// use std::mem::MaybeUninit; /// assert_eq!(size_of::>(), size_of::()); /// assert_eq!(align_of::>(), align_of::()); /// ``` @@ -215,7 +215,7 @@ use crate::{fmt, intrinsics, ptr, slice}; /// optimizations, potentially resulting in a larger size: /// /// ```rust -/// # use std::mem::{MaybeUninit, size_of}; +/// # use std::mem::MaybeUninit; /// assert_eq!(size_of::>(), 1); /// assert_eq!(size_of::>>(), 2); /// ``` @@ -331,42 +331,6 @@ impl MaybeUninit { MaybeUninit { uninit: () } } - /// Creates a new array of `MaybeUninit` items, in an uninitialized state. - /// - /// Note: in a future Rust version this method may become unnecessary - /// when Rust allows - /// [inline const expressions](https://github.com/rust-lang/rust/issues/76001). - /// The example below could then use `let mut buf = [const { MaybeUninit::::uninit() }; 32];`. - /// - /// # Examples - /// - /// ```no_run - /// #![feature(maybe_uninit_uninit_array, maybe_uninit_slice)] - /// - /// use std::mem::MaybeUninit; - /// - /// unsafe extern "C" { - /// fn read_into_buffer(ptr: *mut u8, max_len: usize) -> usize; - /// } - /// - /// /// Returns a (possibly smaller) slice of data that was actually read - /// fn read(buf: &mut [MaybeUninit]) -> &[u8] { - /// unsafe { - /// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len()); - /// buf[..len].assume_init_ref() - /// } - /// } - /// - /// let mut buf: [MaybeUninit; 32] = MaybeUninit::uninit_array(); - /// let data = read(&mut buf); - /// ``` - #[unstable(feature = "maybe_uninit_uninit_array", issue = "96097")] - #[must_use] - #[inline(always)] - pub const fn uninit_array() -> [Self; N] { - [const { MaybeUninit::uninit() }; N] - } - /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being /// filled with `0` bytes. It depends on `T` whether that already makes for /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, @@ -1041,7 +1005,6 @@ impl MaybeUninit { /// Deprecated version of [`slice::assume_init_ref`]. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[deprecated( note = "replaced by inherent assume_init_ref method; will eventually be removed", since = "1.83.0" @@ -1053,7 +1016,6 @@ impl MaybeUninit { /// Deprecated version of [`slice::assume_init_mut`]. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] - #[rustc_const_unstable(feature = "maybe_uninit_slice", issue = "63569")] #[deprecated( note = "replaced by inherent assume_init_mut method; will eventually be removed", since = "1.83.0" @@ -1326,7 +1288,6 @@ impl [MaybeUninit] { /// /// [`write_clone_of_slice`]: slice::write_clone_of_slice #[unstable(feature = "maybe_uninit_write_slice", issue = "79995")] - #[rustc_const_unstable(feature = "maybe_uninit_write_slice", issue = "79995")] pub const fn write_copy_of_slice(&mut self, src: &[T]) -> &mut [T] where T: Copy, diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index b9bb6d6a13f7f..27387754633d1 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -140,7 +140,7 @@ pub use crate::intrinsics::transmute; #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mem_forget")] +#[rustc_diagnostic_item = "mem_forget"] pub const fn forget(t: T) { let _ = ManuallyDrop::new(t); } @@ -226,31 +226,27 @@ pub fn forget_unsized(t: T) { /// # Examples /// /// ``` -/// use std::mem; -/// /// // Some primitives -/// assert_eq!(4, mem::size_of::()); -/// assert_eq!(8, mem::size_of::()); -/// assert_eq!(0, mem::size_of::<()>()); +/// assert_eq!(4, size_of::()); +/// assert_eq!(8, size_of::()); +/// assert_eq!(0, size_of::<()>()); /// /// // Some arrays -/// assert_eq!(8, mem::size_of::<[i32; 2]>()); -/// assert_eq!(12, mem::size_of::<[i32; 3]>()); -/// assert_eq!(0, mem::size_of::<[i32; 0]>()); +/// assert_eq!(8, size_of::<[i32; 2]>()); +/// assert_eq!(12, size_of::<[i32; 3]>()); +/// assert_eq!(0, size_of::<[i32; 0]>()); /// /// /// // Pointer size equality -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::<*const i32>()); -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); -/// assert_eq!(mem::size_of::<&i32>(), mem::size_of::>()); -/// assert_eq!(mem::size_of::>(), mem::size_of::>>()); +/// assert_eq!(size_of::<&i32>(), size_of::<*const i32>()); +/// assert_eq!(size_of::<&i32>(), size_of::>()); +/// assert_eq!(size_of::<&i32>(), size_of::>()); +/// assert_eq!(size_of::>(), size_of::>>()); /// ``` /// /// Using `#[repr(C)]`. /// /// ``` -/// use std::mem; -/// /// #[repr(C)] /// struct FieldStruct { /// first: u8, @@ -265,13 +261,13 @@ pub fn forget_unsized(t: T) { /// // The size of the third field is 1, so add 1 to the size. Size is 5. /// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its /// // fields is 2), so add 1 to the size for padding. Size is 6. -/// assert_eq!(6, mem::size_of::()); +/// assert_eq!(6, size_of::()); /// /// #[repr(C)] /// struct TupleStruct(u8, u16, u8); /// /// // Tuple structs follow the same rules. -/// assert_eq!(6, mem::size_of::()); +/// assert_eq!(6, size_of::()); /// /// // Note that reordering the fields can lower the size. We can remove both padding bytes /// // by putting `third` before `second`. @@ -282,7 +278,7 @@ pub fn forget_unsized(t: T) { /// second: u16 /// } /// -/// assert_eq!(4, mem::size_of::()); +/// assert_eq!(4, size_of::()); /// /// // Union size is the size of the largest field. /// #[repr(C)] @@ -291,7 +287,7 @@ pub fn forget_unsized(t: T) { /// larger: u16 /// } /// -/// assert_eq!(2, mem::size_of::()); +/// assert_eq!(2, size_of::()); /// ``` /// /// [alignment]: align_of @@ -304,7 +300,7 @@ pub fn forget_unsized(t: T) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_mem_size_of", since = "1.24.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of")] +#[rustc_diagnostic_item = "mem_size_of"] pub const fn size_of() -> usize { intrinsics::size_of::() } @@ -320,13 +316,11 @@ pub const fn size_of() -> usize { /// # Examples /// /// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::size_of_val(&5i32)); +/// assert_eq!(4, size_of_val(&5i32)); /// /// let x: [u8; 13] = [0; 13]; /// let y: &[u8] = &x; -/// assert_eq!(13, mem::size_of_val(y)); +/// assert_eq!(13, size_of_val(y)); /// ``` /// /// [`size_of::()`]: size_of @@ -334,7 +328,7 @@ pub const fn size_of() -> usize { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_size_of_val", since = "1.85.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mem_size_of_val")] +#[rustc_diagnostic_item = "mem_size_of_val"] pub const fn size_of_val(val: &T) -> usize { // SAFETY: `val` is a reference, so it's a valid raw pointer unsafe { intrinsics::size_of_val(val) } @@ -381,7 +375,7 @@ pub const fn size_of_val(val: &T) -> usize { /// #![feature(layout_for_ptr)] /// use std::mem; /// -/// assert_eq!(4, mem::size_of_val(&5i32)); +/// assert_eq!(4, size_of_val(&5i32)); /// /// let x: [u8; 13] = [0; 13]; /// let y: &[u8] = &x; @@ -454,9 +448,7 @@ pub fn min_align_of_val(val: &T) -> usize { /// # Examples /// /// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::align_of::()); +/// assert_eq!(4, align_of::()); /// ``` #[inline(always)] #[must_use] @@ -477,9 +469,7 @@ pub const fn align_of() -> usize { /// # Examples /// /// ``` -/// use std::mem; -/// -/// assert_eq!(4, mem::align_of_val(&5i32)); +/// assert_eq!(4, align_of_val(&5i32)); /// ``` #[inline] #[must_use] @@ -856,7 +846,7 @@ pub fn take(dest: &mut T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] #[rustc_const_stable(feature = "const_replace", since = "1.83.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mem_replace")] +#[rustc_diagnostic_item = "mem_replace"] pub const fn replace(dest: &mut T, src: T) -> T { // It may be tempting to use `swap` to avoid `unsafe` here. Don't! // The compiler optimizes the implementation below to two `memcpy`s @@ -866,8 +856,13 @@ pub const fn replace(dest: &mut T, src: T) -> T { // such that the old value is not duplicated. Nothing is dropped and // nothing here can panic. unsafe { - let result = ptr::read(dest); - ptr::write(dest, src); + // Ideally we wouldn't use the intrinsics here, but going through the + // `ptr` methods introduces two unnecessary UbChecks, so until we can + // remove those for pointers that come from references, this uses the + // intrinsics instead so this stays very cheap in MIR (and debug). + + let result = crate::intrinsics::read_via_copy(dest); + crate::intrinsics::write_via_move(dest, src); result } } @@ -936,7 +931,7 @@ pub const fn replace(dest: &mut T, src: T) -> T { /// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mem_drop")] +#[rustc_diagnostic_item = "mem_drop"] pub fn drop(_x: T) {} /// Bitwise-copies a value. @@ -1159,7 +1154,7 @@ impl fmt::Debug for Discriminant { /// ``` #[stable(feature = "discriminant_value", since = "1.21.0")] #[rustc_const_stable(feature = "const_discriminant", since = "1.75.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "mem_discriminant")] +#[rustc_diagnostic_item = "mem_discriminant"] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const fn discriminant(v: &T) -> Discriminant { Discriminant(intrinsics::discriminant_value(v)) @@ -1259,42 +1254,56 @@ impl SizedTypeProperties for T {} /// Expands to the offset in bytes of a field from the beginning of the given type. /// -/// Structs, enums, unions and tuples are supported. -/// -/// Nested field accesses may be used, but not array indexes. +/// The type may be a `struct`, `enum`, `union`, or tuple. /// -/// If the nightly-only feature `offset_of_enum` is enabled, -/// variants may be traversed as if they were fields. -/// Variants themselves do not have an offset. +/// The field may be a nested field (`field1.field2`), but not an array index. +/// The field must be visible to the call site. /// -/// Visibility is respected - all types and fields must be visible to the call site: +/// The offset is returned as a [`usize`]. /// -/// ``` -/// mod nested { -/// #[repr(C)] -/// pub struct Struct { -/// private: u8, -/// } -/// } +/// # Offsets of, and in, dynamically sized types /// -/// // assert_eq!(mem::offset_of!(nested::Struct, private), 0); -/// // ^^^ error[E0616]: field `private` of struct `Struct` is private -/// ``` +/// The field’s type must be [`Sized`], but it may be located in a [dynamically sized] container. +/// If the field type is dynamically sized, then you cannot use `offset_of!` (since the field's +/// alignment, and therefore its offset, may also be dynamic) and must take the offset from an +/// actual pointer to the container instead. /// -/// Only [`Sized`] fields are supported, but the container may be unsized: /// ``` /// # use core::mem; +/// # use core::fmt::Debug; /// #[repr(C)] -/// pub struct Struct { +/// pub struct Struct { /// a: u8, -/// b: [u8], +/// b: T, /// } /// -/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK -/// // assert_eq!(mem::offset_of!(Struct, b), 1); -/// // ^^^ error[E0277]: doesn't have a size known at compile-time +/// #[derive(Debug)] +/// #[repr(C, align(4))] +/// struct Align4(u32); +/// +/// assert_eq!(mem::offset_of!(Struct, a), 0); // OK — Sized field +/// assert_eq!(mem::offset_of!(Struct, b), 4); // OK — not DST +/// +/// // assert_eq!(mem::offset_of!(Struct, b), 1); +/// // ^^^ error[E0277]: ... cannot be known at compilation time +/// +/// // To obtain the offset of a !Sized field, examine a concrete value +/// // instead of using offset_of!. +/// let value: Struct = Struct { a: 1, b: Align4(2) }; +/// let ref_unsized: &Struct = &value; +/// let offset_of_b = unsafe { +/// (&raw const ref_unsized.b).byte_offset_from_unsigned(ref_unsized) +/// }; +/// assert_eq!(offset_of_b, 4); /// ``` /// +/// If you need to obtain the offset of a field of a `!Sized` type, then, since the offset may +/// depend on the particular value being stored (in particular, `dyn Trait` values have a +/// dynamically-determined alignment), you must retrieve the offset from a specific reference +/// or pointer, and so you cannot use `offset_of!` to work without one. +/// +/// # Layout is subject to change +/// /// Note that type layout is, in general, [subject to change and /// platform-specific](https://doc.rust-lang.org/reference/type-layout.html). If /// layout stability is required, consider using an [explicit `repr` attribute]. @@ -1330,11 +1339,16 @@ impl SizedTypeProperties for T {} /// /// [explicit `repr` attribute]: https://doc.rust-lang.org/reference/type-layout.html#representations /// +/// # Unstable features +/// +/// The following unstable features expand the functionality of `offset_of!`: +/// +/// * [`offset_of_enum`] — allows `enum` variants to be traversed as if they were fields. +/// * [`offset_of_slice`] — allows getting the offset of a field of type `[T]`. +/// /// # Examples /// /// ``` -/// #![feature(offset_of_enum)] -/// /// use std::mem; /// #[repr(C)] /// struct FieldStruct { @@ -1356,18 +1370,11 @@ impl SizedTypeProperties for T {} /// struct NestedB(u8); /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); -/// -/// #[repr(u8)] -/// enum Enum { -/// A(u8, u16), -/// B { one: u8, two: u16 }, -/// } -/// -/// assert_eq!(mem::offset_of!(Enum, A.0), 1); -/// assert_eq!(mem::offset_of!(Enum, B.two), 2); -/// -/// assert_eq!(mem::offset_of!(Option<&u8>, Some.0), 0); /// ``` +/// +/// [dynamically sized]: https://doc.rust-lang.org/reference/dynamically-sized-types.html +/// [`offset_of_enum`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-enum.html +/// [`offset_of_slice`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/offset-of-slice.html #[stable(feature = "offset_of", since = "1.77.0")] #[allow_internal_unstable(builtin_syntax)] pub macro offset_of($Container:ty, $($fields:expr)+ $(,)?) { diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 7b920d7a777ca..782b826448a32 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -153,7 +153,7 @@ pub struct Assume { /// /// ```compile_fail,E0277 /// #![feature(transmutability)] - /// use core::mem::{align_of, TransmuteFrom}; + /// use core::mem::TransmuteFrom; /// /// assert_eq!(align_of::<[u8; 2]>(), 1); /// assert_eq!(align_of::(), 2); @@ -172,7 +172,7 @@ pub struct Assume { /// /// ```rust /// #![feature(pointer_is_aligned_to, transmutability)] - /// use core::mem::{align_of, Assume, TransmuteFrom}; + /// use core::mem::{Assume, TransmuteFrom}; /// /// let src: &[u8; 2] = &[0xFF, 0xFF]; /// @@ -337,7 +337,7 @@ impl Assume { /// transmutability, /// )] /// #![allow(incomplete_features)] - /// use core::mem::{align_of, Assume, TransmuteFrom}; + /// use core::mem::{Assume, TransmuteFrom}; /// /// /// Attempts to transmute `src` to `&Dst`. /// /// diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 8e4417ec461b8..7aa5ed60d0467 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -25,7 +25,7 @@ use crate::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not}; /// assert_eq!(localhost_v4.is_ipv6(), false); /// assert_eq!(localhost_v4.is_ipv4(), true); /// ``` -#[cfg_attr(not(test), rustc_diagnostic_item = "IpAddr")] +#[rustc_diagnostic_item = "IpAddr"] #[stable(feature = "ip_addr", since = "1.7.0")] #[derive(Copy, Clone, Eq, PartialEq, Hash, PartialOrd, Ord)] pub enum IpAddr { diff --git a/library/core/src/net/socket_addr.rs b/library/core/src/net/socket_addr.rs index 9204797e6e157..21753d0092497 100644 --- a/library/core/src/net/socket_addr.rs +++ b/library/core/src/net/socket_addr.rs @@ -8,11 +8,15 @@ use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr}; /// as possibly some version-dependent additional information. See [`SocketAddrV4`]'s and /// [`SocketAddrV6`]'s respective documentation for more details. /// -/// The size of a `SocketAddr` instance may vary depending on the target operating -/// system. -/// /// [IP address]: IpAddr /// +/// # Portability +/// +/// `SocketAddr` is intended to be a portable representation of socket addresses and is likely not +/// the same as the internal socket address type used by the target operating system's API. Like all +/// `repr(Rust)` structs, however, its exact layout remains undefined and should not be relied upon +/// between builds. +/// /// # Examples /// /// ``` @@ -42,13 +46,16 @@ pub enum SocketAddr { /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// -/// The size of a `SocketAddrV4` struct may vary depending on the target operating -/// system. Do not assume that this type has the same memory layout as the underlying -/// system representation. -/// /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793 /// [`IPv4` address]: Ipv4Addr /// +/// # Portability +/// +/// `SocketAddrV4` is intended to be a portable representation of socket addresses and is likely not +/// the same as the internal socket address type used by the target operating system's API. Like all +/// `repr(Rust)` structs, however, its exact layout remains undefined and should not be relied upon +/// between builds. +/// /// # Textual representation /// /// `SocketAddrV4` provides a [`FromStr`](crate::str::FromStr) implementation. @@ -84,13 +91,16 @@ pub struct SocketAddrV4 { /// /// See [`SocketAddr`] for a type encompassing both IPv4 and IPv6 socket addresses. /// -/// The size of a `SocketAddrV6` struct may vary depending on the target operating -/// system. Do not assume that this type has the same memory layout as the underlying -/// system representation. -/// /// [IETF RFC 2553, Section 3.3]: https://tools.ietf.org/html/rfc2553#section-3.3 /// [`IPv6` address]: Ipv6Addr /// +/// # Portability +/// +/// `SocketAddrV6` is intended to be a portable representation of socket addresses and is likely not +/// the same as the internal socket address type used by the target operating system's API. Like all +/// `repr(Rust)` structs, however, its exact layout remains undefined and should not be relied upon +/// between builds. +/// /// # Textual representation /// /// `SocketAddrV6` provides a [`FromStr`](crate::str::FromStr) implementation, @@ -200,7 +210,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_ip(&mut self, new_ip: IpAddr) { // `match (*self, new_ip)` would have us mutate a copy of self only to throw it away. match (self, new_ip) { @@ -244,7 +254,7 @@ impl SocketAddr { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_port(&mut self, new_port: u16) { match *self { SocketAddr::V4(ref mut a) => a.set_port(new_port), @@ -350,7 +360,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_ip(&mut self, new_ip: Ipv4Addr) { self.ip = new_ip; } @@ -386,7 +396,7 @@ impl SocketAddrV4 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -448,7 +458,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_ip(&mut self, new_ip: Ipv6Addr) { self.ip = new_ip; } @@ -484,7 +494,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_port(&mut self, new_port: u16) { self.port = new_port; } @@ -532,7 +542,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_flowinfo(&mut self, new_flowinfo: u32) { self.flowinfo = new_flowinfo; } @@ -575,7 +585,7 @@ impl SocketAddrV6 { /// ``` #[inline] #[stable(feature = "sockaddr_setters", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_sockaddr_setters", issue = "131714")] + #[rustc_const_stable(feature = "const_sockaddr_setters", since = "CURRENT_RUSTC_VERSION")] pub const fn set_scope_id(&mut self, new_scope_id: u32) { self.scope_id = new_scope_id; } diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 2a47c89e2aee2..e33f58197bba5 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -253,12 +253,11 @@ macro_rules! define_bignum { /// Multiplies itself by `5^e` and returns its own mutable reference. pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name { - use crate::mem; use crate::num::bignum::SMALL_POW5; // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes // are consecutive powers of two, so this is well suited index for the table. - let table_index = mem::size_of::<$ty>().trailing_zeros() as usize; + let table_index = size_of::<$ty>().trailing_zeros() as usize; let (small_power, small_e) = SMALL_POW5[table_index]; let small_power = small_power as $ty; @@ -405,6 +404,8 @@ macro_rules! define_bignum { } } + impl crate::clone::UseCloned for $name {} + impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { let sz = if self.size < 1 { 1 } else { self.size }; diff --git a/library/core/src/num/dec2flt/common.rs b/library/core/src/num/dec2flt/common.rs index 4dadf406ae8c7..a140a311c452f 100644 --- a/library/core/src/num/dec2flt/common.rs +++ b/library/core/src/num/dec2flt/common.rs @@ -8,12 +8,12 @@ pub(crate) trait ByteSlice { /// Writes a 64-bit integer as 8 bytes in little-endian order. fn write_u64(&mut self, value: u64); - /// Calculate the offset of a slice from another. + /// Calculate the difference in length between two slices. fn offset_from(&self, other: &Self) -> isize; /// Iteratively parse and consume digits from bytes. - /// Returns the same bytes with consumed digits being - /// elided. + /// + /// Returns the same bytes with consumed digits being elided. Breaks on invalid digits. fn parse_digits(&self, func: impl FnMut(u8)) -> &Self; } @@ -39,11 +39,11 @@ impl ByteSlice for [u8] { fn parse_digits(&self, mut func: impl FnMut(u8)) -> &Self { let mut s = self; - while let Some((c, s_next)) = s.split_first() { + while let Some((c, rest)) = s.split_first() { let c = c.wrapping_sub(b'0'); if c < 10 { func(c); - s = s_next; + s = rest; } else { break; } @@ -53,7 +53,9 @@ impl ByteSlice for [u8] { } } -/// Determine if 8 bytes are all decimal digits. +/// Determine if all characters in an 8-byte byte string (represented as a `u64`) are all decimal +/// digits. +/// /// This does not care about the order in which the bytes were loaded. pub(crate) fn is_8digits(v: u64) -> bool { let a = v.wrapping_add(0x4646_4646_4646_4646); @@ -61,19 +63,20 @@ pub(crate) fn is_8digits(v: u64) -> bool { (a | b) & 0x8080_8080_8080_8080 == 0 } -/// A custom 64-bit floating point type, representing `f * 2^e`. -/// e is biased, so it be directly shifted into the exponent bits. +/// A custom 64-bit floating point type, representing `m * 2^p`. +/// p is biased, so it be directly shifted into the exponent bits. #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] pub struct BiasedFp { /// The significant digits. - pub f: u64, + pub m: u64, /// The biased, binary exponent. - pub e: i32, + pub p_biased: i32, } impl BiasedFp { + /// Represent `0 ^ p` #[inline] - pub const fn zero_pow2(e: i32) -> Self { - Self { f: 0, e } + pub const fn zero_pow2(p_biased: i32) -> Self { + Self { m: 0, p_biased } } } diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs index b37724ba62d5e..db7176c124318 100644 --- a/library/core/src/num/dec2flt/decimal.rs +++ b/library/core/src/num/dec2flt/decimal.rs @@ -1,358 +1,87 @@ -//! Arbitrary-precision decimal class for fallback algorithms. -//! -//! This is only used if the fast-path (native floats) and -//! the Eisel-Lemire algorithm are unable to unambiguously -//! determine the float. -//! -//! The technique used is "Simple Decimal Conversion", developed -//! by Nigel Tao and Ken Thompson. A detailed description of the -//! algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion", -//! available online: . - -use crate::num::dec2flt::common::{ByteSlice, is_8digits}; - -#[derive(Clone)] -pub(super) struct Decimal { - /// The number of significant digits in the decimal. - pub num_digits: usize, - /// The offset of the decimal point in the significant digits. - pub decimal_point: i32, - /// If the number of significant digits stored in the decimal is truncated. - pub truncated: bool, - /// Buffer of the raw digits, in the range [0, 9]. - pub digits: [u8; Self::MAX_DIGITS], +//! Representation of a float as the significant digits and exponent. + +use crate::num::dec2flt::float::RawFloat; +use crate::num::dec2flt::fpu::set_precision; + +const INT_POW10: [u64; 16] = [ + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, +]; + +/// A floating point number with up to 64 bits of mantissa and an `i64` exponent. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +pub struct Decimal { + pub exponent: i64, + pub mantissa: u64, + pub negative: bool, + pub many_digits: bool, } -impl Default for Decimal { - fn default() -> Self { - Self { num_digits: 0, decimal_point: 0, truncated: false, digits: [0; Self::MAX_DIGITS] } +impl Decimal { + /// Detect if the float can be accurately reconstructed from native floats. + #[inline] + fn can_use_fast_path(&self) -> bool { + F::MIN_EXPONENT_FAST_PATH <= self.exponent + && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH + && self.mantissa <= F::MAX_MANTISSA_FAST_PATH + && !self.many_digits } -} -impl Decimal { - /// The maximum number of digits required to unambiguously round a float. - /// - /// For a double-precision IEEE 754 float, this required 767 digits, - /// so we store the max digits + 1. - /// - /// We can exactly represent a float in radix `b` from radix 2 if - /// `b` is divisible by 2. This function calculates the exact number of - /// digits required to exactly represent that float. - /// - /// According to the "Handbook of Floating Point Arithmetic", - /// for IEEE754, with emin being the min exponent, p2 being the - /// precision, and b being the radix, the number of digits follows as: + /// Try turning the decimal into an exact float representation, using machine-sized integers + /// and floats. /// - /// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋` + /// This is extracted into a separate function so that it can be attempted before constructing + /// a Decimal. This only works if both the mantissa and the exponent + /// can be exactly represented as a machine float, since IEE-754 guarantees + /// no rounding will occur. /// - /// For f32, this follows as: - /// emin = -126 - /// p2 = 24 - /// - /// For f64, this follows as: - /// emin = -1022 - /// p2 = 53 - /// - /// In Python: - /// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))` - pub(super) const MAX_DIGITS: usize = 768; - /// The max digits that can be exactly represented in a 64-bit integer. - pub(super) const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19; - pub(super) const DECIMAL_POINT_RANGE: i32 = 2047; - - /// Append a digit to the buffer. - pub(super) fn try_add_digit(&mut self, digit: u8) { - if self.num_digits < Self::MAX_DIGITS { - self.digits[self.num_digits] = digit; - } - self.num_digits += 1; - } - - /// Trim trailing zeros from the buffer. - pub(super) fn trim(&mut self) { - // All of the following calls to `Decimal::trim` can't panic because: - // - // 1. `parse_decimal` sets `num_digits` to a max of `Decimal::MAX_DIGITS`. - // 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`. - // 3. `left_shift` `num_digits` to a max of `Decimal::MAX_DIGITS`. - // - // Trim is only called in `right_shift` and `left_shift`. - debug_assert!(self.num_digits <= Self::MAX_DIGITS); - while self.num_digits != 0 && self.digits[self.num_digits - 1] == 0 { - self.num_digits -= 1; - } - } - - pub(super) fn round(&self) -> u64 { - if self.num_digits == 0 || self.decimal_point < 0 { - return 0; - } else if self.decimal_point > 18 { - return 0xFFFF_FFFF_FFFF_FFFF_u64; - } - let dp = self.decimal_point as usize; - let mut n = 0_u64; - for i in 0..dp { - n *= 10; - if i < self.num_digits { - n += self.digits[i] as u64; - } - } - let mut round_up = false; - if dp < self.num_digits { - round_up = self.digits[dp] >= 5; - if self.digits[dp] == 5 && dp + 1 == self.num_digits { - round_up = self.truncated || ((dp != 0) && (1 & self.digits[dp - 1] != 0)) - } - } - if round_up { - n += 1; - } - n - } - - /// Computes decimal * 2^shift. - pub(super) fn left_shift(&mut self, shift: usize) { - if self.num_digits == 0 { - return; - } - let num_new_digits = number_of_digits_decimal_left_shift(self, shift); - let mut read_index = self.num_digits; - let mut write_index = self.num_digits + num_new_digits; - let mut n = 0_u64; - while read_index != 0 { - read_index -= 1; - write_index -= 1; - n += (self.digits[read_index] as u64) << shift; - let quotient = n / 10; - let remainder = n - (10 * quotient); - if write_index < Self::MAX_DIGITS { - self.digits[write_index] = remainder as u8; - } else if remainder > 0 { - self.truncated = true; - } - n = quotient; - } - while n > 0 { - write_index -= 1; - let quotient = n / 10; - let remainder = n - (10 * quotient); - if write_index < Self::MAX_DIGITS { - self.digits[write_index] = remainder as u8; - } else if remainder > 0 { - self.truncated = true; - } - n = quotient; - } - self.num_digits += num_new_digits; - if self.num_digits > Self::MAX_DIGITS { - self.num_digits = Self::MAX_DIGITS; - } - self.decimal_point += num_new_digits as i32; - self.trim(); - } - - /// Computes decimal * 2^-shift. - pub(super) fn right_shift(&mut self, shift: usize) { - let mut read_index = 0; - let mut write_index = 0; - let mut n = 0_u64; - while (n >> shift) == 0 { - if read_index < self.num_digits { - n = (10 * n) + self.digits[read_index] as u64; - read_index += 1; - } else if n == 0 { - return; + /// There is an exception: disguised fast-path cases, where we can shift + /// powers-of-10 from the exponent to the significant digits. + pub fn try_fast_path(&self) -> Option { + // Here we need to work around . + // The fast path crucially depends on arithmetic being rounded to the correct number of bits + // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision + // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit. + // The `set_precision` function takes care of setting the precision on architectures which + // require setting it by changing the global state (like the control word of the x87 FPU). + let _cw = set_precision::(); + + if !self.can_use_fast_path::() { + return None; + } + + let value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH { + // normal fast path + let value = F::from_u64(self.mantissa); + if self.exponent < 0 { + value / F::pow10_fast_path((-self.exponent) as _) } else { - while (n >> shift) == 0 { - n *= 10; - read_index += 1; - } - break; - } - } - self.decimal_point -= read_index as i32 - 1; - if self.decimal_point < -Self::DECIMAL_POINT_RANGE { - // `self = Self::Default()`, but without the overhead of clearing `digits`. - self.num_digits = 0; - self.decimal_point = 0; - self.truncated = false; - return; - } - let mask = (1_u64 << shift) - 1; - while read_index < self.num_digits { - let new_digit = (n >> shift) as u8; - n = (10 * (n & mask)) + self.digits[read_index] as u64; - read_index += 1; - self.digits[write_index] = new_digit; - write_index += 1; - } - while n > 0 { - let new_digit = (n >> shift) as u8; - n = 10 * (n & mask); - if write_index < Self::MAX_DIGITS { - self.digits[write_index] = new_digit; - write_index += 1; - } else if new_digit > 0 { - self.truncated = true; - } - } - self.num_digits = write_index; - self.trim(); - } -} - -/// Parse a big integer representation of the float as a decimal. -pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal { - let mut d = Decimal::default(); - let start = s; - - while let Some((&b'0', s_next)) = s.split_first() { - s = s_next; - } - - s = s.parse_digits(|digit| d.try_add_digit(digit)); - - if let Some((b'.', s_next)) = s.split_first() { - s = s_next; - let first = s; - // Skip leading zeros. - if d.num_digits == 0 { - while let Some((&b'0', s_next)) = s.split_first() { - s = s_next; - } - } - while s.len() >= 8 && d.num_digits + 8 < Decimal::MAX_DIGITS { - let v = s.read_u64(); - if !is_8digits(v) { - break; + value * F::pow10_fast_path(self.exponent as _) } - d.digits[d.num_digits..].write_u64(v - 0x3030_3030_3030_3030); - d.num_digits += 8; - s = &s[8..]; - } - s = s.parse_digits(|digit| d.try_add_digit(digit)); - d.decimal_point = s.len() as i32 - first.len() as i32; - } - if d.num_digits != 0 { - // Ignore the trailing zeros if there are any - let mut n_trailing_zeros = 0; - for &c in start[..(start.len() - s.len())].iter().rev() { - if c == b'0' { - n_trailing_zeros += 1; - } else if c != b'.' { - break; - } - } - d.decimal_point += n_trailing_zeros as i32; - d.num_digits -= n_trailing_zeros; - d.decimal_point += d.num_digits as i32; - if d.num_digits > Decimal::MAX_DIGITS { - d.truncated = true; - d.num_digits = Decimal::MAX_DIGITS; - } - } - if let Some((&ch, s_next)) = s.split_first() { - if ch == b'e' || ch == b'E' { - s = s_next; - let mut neg_exp = false; - if let Some((&ch, s_next)) = s.split_first() { - neg_exp = ch == b'-'; - if ch == b'-' || ch == b'+' { - s = s_next; - } + } else { + // disguised fast path + let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH; + let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?; + if mantissa > F::MAX_MANTISSA_FAST_PATH { + return None; } - let mut exp_num = 0_i32; - - s.parse_digits(|digit| { - if exp_num < 0x10000 { - exp_num = 10 * exp_num + digit as i32; - } - }); + F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _) + }; - d.decimal_point += if neg_exp { -exp_num } else { exp_num }; - } - } - for i in d.num_digits..Decimal::MAX_DIGITS_WITHOUT_OVERFLOW { - d.digits[i] = 0; - } - d -} - -fn number_of_digits_decimal_left_shift(d: &Decimal, mut shift: usize) -> usize { - #[rustfmt::skip] - const TABLE: [u16; 65] = [ - 0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817, 0x181D, 0x2024, - 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067, 0x3073, 0x3080, 0x388E, 0x389C, - 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF, 0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, - 0x5180, 0x5998, 0x59B0, 0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, - 0x72AA, 0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC, 0x8C02, - 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C, 0x051C, 0x051C, - ]; - #[rustfmt::skip] - const TABLE_POW5: [u8; 0x051C] = [ - 5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3, 9, 0, 6, 2, 5, 1, - 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8, 1, 2, 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, - 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1, 0, 3, 5, 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, - 5, 1, 5, 2, 5, 8, 7, 8, 9, 0, 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6, - 9, 7, 2, 6, 5, 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5, 3, 6, 7, 4, 3, 1, - 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5, 2, 3, 8, 4, 1, 8, 5, 7, 9, - 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0, 9, 2, 8, 9, 5, 5, 0, 7, 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, - 4, 4, 7, 7, 5, 3, 9, 0, 6, 2, 5, 2, 9, 8, 0, 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1, - 4, 9, 0, 1, 1, 6, 1, 1, 9, 3, 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8, 0, 5, 9, 6, 9, 2, - 3, 8, 2, 8, 1, 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4, 6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6, - 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5, 7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5, 7, 4, 6, 1, 5, - 4, 7, 8, 5, 1, 5, 6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0, 7, 7, 3, 9, 2, 5, 7, 8, 1, 2, - 5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6, 9, 6, 2, 8, 9, 0, 6, 2, 5, 1, 1, 6, 4, 1, 5, - 3, 2, 1, 8, 2, 6, 9, 3, 4, 8, 1, 4, 4, 5, 3, 1, 2, 5, 5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, - 6, 7, 4, 0, 7, 2, 2, 6, 5, 6, 2, 5, 2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6, - 1, 3, 2, 8, 1, 2, 5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8, 0, 6, 6, 4, 0, - 6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9, 0, 3, 3, 2, 0, 3, 1, 2, 5, 3, - 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2, 9, 5, 1, 6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, - 9, 8, 9, 4, 0, 3, 5, 4, 5, 8, 5, 6, 4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, - 7, 0, 1, 7, 7, 2, 9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5, - 0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7, 3, 7, 3, 6, 7, 5, - 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5, 6, 2, 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, - 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9, 3, 7, 9, 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, - 8, 6, 0, 8, 0, 8, 0, 1, 4, 8, 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0, - 9, 4, 3, 0, 4, 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2, 5, 1, 4, 2, 1, 0, - 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2, 4, 8, 5, 3, 5, 1, 5, 6, 2, 5, 7, 1, - 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0, 0, 1, 8, 5, 8, 7, 1, 1, 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, - 5, 3, 5, 5, 2, 7, 1, 3, 6, 7, 8, 8, 0, 0, 5, 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8, - 9, 0, 6, 2, 5, 1, 7, 7, 6, 3, 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4, 6, 7, 7, 8, 1, 0, - 6, 6, 8, 9, 4, 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1, 9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3, - 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5, 6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8, 5, 0, 0, 6, 2, - 6, 1, 6, 1, 6, 9, 4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2, 5, 2, 2, 2, 0, 4, 4, 6, 0, 4, - 9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6, 3, 3, 3, 6, 1, 8, 1, 6, 4, 0, 6, 2, 5, 1, 1, - 1, 0, 2, 2, 3, 0, 2, 4, 6, 2, 5, 1, 5, 6, 5, 4, 0, 4, 2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, - 2, 0, 3, 1, 2, 5, 5, 5, 5, 1, 1, 1, 5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5, - 8, 3, 4, 0, 4, 5, 4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5, 6, 2, 8, 9, 1, - 3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8, 1, 2, 5, 1, 3, 8, 7, 7, 7, 8, - 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9, 5, 3, 9, 5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, - 6, 2, 5, 6, 9, 3, 8, 8, 9, 3, 9, 0, 3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, - 5, 5, 6, 7, 6, 2, 6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1, - 8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5, 1, 7, 3, 4, 7, 2, - 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2, 4, 4, 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, - 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1, 7, 3, 7, 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, - 2, 4, 0, 6, 9, 5, 9, 5, 3, 3, 6, 9, 1, 4, 0, 6, 2, 5, - ]; - - shift &= 63; - let x_a = TABLE[shift]; - let x_b = TABLE[shift + 1]; - let num_new_digits = (x_a >> 11) as _; - let pow5_a = (0x7FF & x_a) as usize; - let pow5_b = (0x7FF & x_b) as usize; - let pow5 = &TABLE_POW5[pow5_a..]; - for (i, &p5) in pow5.iter().enumerate().take(pow5_b - pow5_a) { - if i >= d.num_digits { - return num_new_digits - 1; - } else if d.digits[i] == p5 { - continue; - } else if d.digits[i] < p5 { - return num_new_digits - 1; - } else { - return num_new_digits; - } + if self.negative { Some(-value) } else { Some(value) } } - num_new_digits } diff --git a/library/core/src/num/dec2flt/decimal_seq.rs b/library/core/src/num/dec2flt/decimal_seq.rs new file mode 100644 index 0000000000000..de22280c001c9 --- /dev/null +++ b/library/core/src/num/dec2flt/decimal_seq.rs @@ -0,0 +1,379 @@ +//! Arbitrary-precision decimal type used by fallback algorithms. +//! +//! This is only used if the fast-path (native floats) and +//! the Eisel-Lemire algorithm are unable to unambiguously +//! determine the float. +//! +//! The technique used is "Simple Decimal Conversion", developed +//! by Nigel Tao and Ken Thompson. A detailed description of the +//! algorithm can be found in "ParseNumberF64 by Simple Decimal Conversion", +//! available online: . + +use crate::num::dec2flt::common::{ByteSlice, is_8digits}; + +/// A decimal floating-point number, represented as a sequence of decimal digits. +#[derive(Clone, Debug, PartialEq)] +pub struct DecimalSeq { + /// The number of significant digits in the decimal. + pub num_digits: usize, + /// The offset of the decimal point in the significant digits. + pub decimal_point: i32, + /// If the number of significant digits stored in the decimal is truncated. + pub truncated: bool, + /// Buffer of the raw digits, in the range [0, 9]. + pub digits: [u8; Self::MAX_DIGITS], +} + +impl Default for DecimalSeq { + fn default() -> Self { + Self { num_digits: 0, decimal_point: 0, truncated: false, digits: [0; Self::MAX_DIGITS] } + } +} + +impl DecimalSeq { + /// The maximum number of digits required to unambiguously round up to a 64-bit float. + /// + /// For an IEEE 754 binary64 float, this required 767 digits. So we store the max digits + 1. + /// + /// We can exactly represent a float in radix `b` from radix 2 if + /// `b` is divisible by 2. This function calculates the exact number of + /// digits required to exactly represent that float. + /// + /// According to the "Handbook of Floating Point Arithmetic", + /// for IEEE754, with `emin` being the min exponent, `p2` being the + /// precision, and `b` being the radix, the number of digits follows as: + /// + /// `−emin + p2 + ⌊(emin + 1) log(2, b) − log(1 − 2^(−p2), b)⌋` + /// + /// For f32, this follows as: + /// emin = -126 + /// p2 = 24 + /// + /// For f64, this follows as: + /// emin = -1022 + /// p2 = 53 + /// + /// In Python: + /// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))` + pub const MAX_DIGITS: usize = 768; + + /// The max decimal digits that can be exactly represented in a 64-bit integer. + pub(super) const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19; + pub(super) const DECIMAL_POINT_RANGE: i32 = 2047; + + /// Append a digit to the buffer if it fits. + // FIXME(tgross35): it may be better for this to return an option + // FIXME(tgross35): incrementing the digit counter even if we don't push anything + // seems incorrect. + pub(super) fn try_add_digit(&mut self, digit: u8) { + if self.num_digits < Self::MAX_DIGITS { + self.digits[self.num_digits] = digit; + } + self.num_digits += 1; + } + + /// Trim trailing zeros from the buffer. + // FIXME(tgross35): this could be `.rev().position()` if perf is okay + pub fn trim(&mut self) { + // All of the following calls to `DecimalSeq::trim` can't panic because: + // + // 1. `parse_decimal` sets `num_digits` to a max of `DecimalSeq::MAX_DIGITS`. + // 2. `right_shift` sets `num_digits` to `write_index`, which is bounded by `num_digits`. + // 3. `left_shift` `num_digits` to a max of `DecimalSeq::MAX_DIGITS`. + // + // Trim is only called in `right_shift` and `left_shift`. + debug_assert!(self.num_digits <= Self::MAX_DIGITS); + while self.num_digits != 0 && self.digits[self.num_digits - 1] == 0 { + self.num_digits -= 1; + } + } + + pub(super) fn round(&self) -> u64 { + if self.num_digits == 0 || self.decimal_point < 0 { + return 0; + } else if self.decimal_point >= Self::MAX_DIGITS_WITHOUT_OVERFLOW as i32 { + return 0xFFFF_FFFF_FFFF_FFFF_u64; + } + + let dp = self.decimal_point as usize; + let mut n = 0_u64; + + for i in 0..dp { + n *= 10; + if i < self.num_digits { + n += self.digits[i] as u64; + } + } + + let mut round_up = false; + + if dp < self.num_digits { + round_up = self.digits[dp] >= 5; + if self.digits[dp] == 5 && dp + 1 == self.num_digits { + round_up = self.truncated || ((dp != 0) && (1 & self.digits[dp - 1] != 0)) + } + } + + if round_up { + n += 1; + } + n + } + + /// Computes decimal * 2^shift. + pub(super) fn left_shift(&mut self, shift: usize) { + if self.num_digits == 0 { + return; + } + let num_new_digits = number_of_digits_decimal_left_shift(self, shift); + let mut read_index = self.num_digits; + let mut write_index = self.num_digits + num_new_digits; + let mut n = 0_u64; + + while read_index != 0 { + read_index -= 1; + write_index -= 1; + n += (self.digits[read_index] as u64) << shift; + let quotient = n / 10; + let remainder = n - (10 * quotient); + if write_index < Self::MAX_DIGITS { + self.digits[write_index] = remainder as u8; + } else if remainder > 0 { + self.truncated = true; + } + n = quotient; + } + + while n > 0 { + write_index -= 1; + let quotient = n / 10; + let remainder = n - (10 * quotient); + if write_index < Self::MAX_DIGITS { + self.digits[write_index] = remainder as u8; + } else if remainder > 0 { + self.truncated = true; + } + n = quotient; + } + + self.num_digits += num_new_digits; + + if self.num_digits > Self::MAX_DIGITS { + self.num_digits = Self::MAX_DIGITS; + } + + self.decimal_point += num_new_digits as i32; + self.trim(); + } + + /// Computes decimal * 2^-shift. + pub(super) fn right_shift(&mut self, shift: usize) { + let mut read_index = 0; + let mut write_index = 0; + let mut n = 0_u64; + while (n >> shift) == 0 { + if read_index < self.num_digits { + n = (10 * n) + self.digits[read_index] as u64; + read_index += 1; + } else if n == 0 { + return; + } else { + while (n >> shift) == 0 { + n *= 10; + read_index += 1; + } + break; + } + } + self.decimal_point -= read_index as i32 - 1; + if self.decimal_point < -Self::DECIMAL_POINT_RANGE { + // `self = Self::Default()`, but without the overhead of clearing `digits`. + self.num_digits = 0; + self.decimal_point = 0; + self.truncated = false; + return; + } + let mask = (1_u64 << shift) - 1; + while read_index < self.num_digits { + let new_digit = (n >> shift) as u8; + n = (10 * (n & mask)) + self.digits[read_index] as u64; + read_index += 1; + self.digits[write_index] = new_digit; + write_index += 1; + } + while n > 0 { + let new_digit = (n >> shift) as u8; + n = 10 * (n & mask); + if write_index < Self::MAX_DIGITS { + self.digits[write_index] = new_digit; + write_index += 1; + } else if new_digit > 0 { + self.truncated = true; + } + } + self.num_digits = write_index; + self.trim(); + } +} + +/// Parse a big integer representation of the float as a decimal. +pub fn parse_decimal_seq(mut s: &[u8]) -> DecimalSeq { + let mut d = DecimalSeq::default(); + let start = s; + + while let Some((&b'0', s_next)) = s.split_first() { + s = s_next; + } + + s = s.parse_digits(|digit| d.try_add_digit(digit)); + + if let Some((b'.', s_next)) = s.split_first() { + s = s_next; + let first = s; + // Skip leading zeros. + if d.num_digits == 0 { + while let Some((&b'0', s_next)) = s.split_first() { + s = s_next; + } + } + while s.len() >= 8 && d.num_digits + 8 < DecimalSeq::MAX_DIGITS { + let v = s.read_u64(); + if !is_8digits(v) { + break; + } + d.digits[d.num_digits..].write_u64(v - 0x3030_3030_3030_3030); + d.num_digits += 8; + s = &s[8..]; + } + s = s.parse_digits(|digit| d.try_add_digit(digit)); + d.decimal_point = s.len() as i32 - first.len() as i32; + } + + if d.num_digits != 0 { + // Ignore the trailing zeros if there are any + let mut n_trailing_zeros = 0; + for &c in start[..(start.len() - s.len())].iter().rev() { + if c == b'0' { + n_trailing_zeros += 1; + } else if c != b'.' { + break; + } + } + d.decimal_point += n_trailing_zeros as i32; + d.num_digits -= n_trailing_zeros; + d.decimal_point += d.num_digits as i32; + if d.num_digits > DecimalSeq::MAX_DIGITS { + d.truncated = true; + d.num_digits = DecimalSeq::MAX_DIGITS; + } + } + + if let Some((&ch, s_next)) = s.split_first() { + if ch == b'e' || ch == b'E' { + s = s_next; + let mut neg_exp = false; + if let Some((&ch, s_next)) = s.split_first() { + neg_exp = ch == b'-'; + if ch == b'-' || ch == b'+' { + s = s_next; + } + } + let mut exp_num = 0_i32; + + s.parse_digits(|digit| { + if exp_num < 0x10000 { + exp_num = 10 * exp_num + digit as i32; + } + }); + + d.decimal_point += if neg_exp { -exp_num } else { exp_num }; + } + } + + for i in d.num_digits..DecimalSeq::MAX_DIGITS_WITHOUT_OVERFLOW { + d.digits[i] = 0; + } + + d +} + +fn number_of_digits_decimal_left_shift(d: &DecimalSeq, mut shift: usize) -> usize { + #[rustfmt::skip] + const TABLE: [u16; 65] = [ + 0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817, 0x181D, 0x2024, + 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067, 0x3073, 0x3080, 0x388E, 0x389C, + 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF, 0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, + 0x5180, 0x5998, 0x59B0, 0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, + 0x72AA, 0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC, 0x8C02, + 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C, 0x051C, 0x051C, + ]; + #[rustfmt::skip] + const TABLE_POW5: [u8; 0x051C] = [ + 5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3, 9, 0, 6, 2, 5, 1, + 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8, 1, 2, 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, + 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1, 0, 3, 5, 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, + 5, 1, 5, 2, 5, 8, 7, 8, 9, 0, 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6, + 9, 7, 2, 6, 5, 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5, 3, 6, 7, 4, 3, 1, + 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5, 2, 3, 8, 4, 1, 8, 5, 7, 9, + 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0, 9, 2, 8, 9, 5, 5, 0, 7, 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, + 4, 4, 7, 7, 5, 3, 9, 0, 6, 2, 5, 2, 9, 8, 0, 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1, + 4, 9, 0, 1, 1, 6, 1, 1, 9, 3, 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8, 0, 5, 9, 6, 9, 2, + 3, 8, 2, 8, 1, 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4, 6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6, + 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5, 7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5, 7, 4, 6, 1, 5, + 4, 7, 8, 5, 1, 5, 6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0, 7, 7, 3, 9, 2, 5, 7, 8, 1, 2, + 5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6, 9, 6, 2, 8, 9, 0, 6, 2, 5, 1, 1, 6, 4, 1, 5, + 3, 2, 1, 8, 2, 6, 9, 3, 4, 8, 1, 4, 4, 5, 3, 1, 2, 5, 5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, + 6, 7, 4, 0, 7, 2, 2, 6, 5, 6, 2, 5, 2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6, + 1, 3, 2, 8, 1, 2, 5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8, 0, 6, 6, 4, 0, + 6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9, 0, 3, 3, 2, 0, 3, 1, 2, 5, 3, + 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2, 9, 5, 1, 6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, + 9, 8, 9, 4, 0, 3, 5, 4, 5, 8, 5, 6, 4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, + 7, 0, 1, 7, 7, 2, 9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5, + 0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7, 3, 7, 3, 6, 7, 5, + 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5, 6, 2, 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, + 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9, 3, 7, 9, 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, + 8, 6, 0, 8, 0, 8, 0, 1, 4, 8, 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0, + 9, 4, 3, 0, 4, 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2, 5, 1, 4, 2, 1, 0, + 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2, 4, 8, 5, 3, 5, 1, 5, 6, 2, 5, 7, 1, + 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0, 0, 1, 8, 5, 8, 7, 1, 1, 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, + 5, 3, 5, 5, 2, 7, 1, 3, 6, 7, 8, 8, 0, 0, 5, 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8, + 9, 0, 6, 2, 5, 1, 7, 7, 6, 3, 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4, 6, 7, 7, 8, 1, 0, + 6, 6, 8, 9, 4, 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1, 9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3, + 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5, 6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8, 5, 0, 0, 6, 2, + 6, 1, 6, 1, 6, 9, 4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2, 5, 2, 2, 2, 0, 4, 4, 6, 0, 4, + 9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6, 3, 3, 3, 6, 1, 8, 1, 6, 4, 0, 6, 2, 5, 1, 1, + 1, 0, 2, 2, 3, 0, 2, 4, 6, 2, 5, 1, 5, 6, 5, 4, 0, 4, 2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, + 2, 0, 3, 1, 2, 5, 5, 5, 5, 1, 1, 1, 5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5, + 8, 3, 4, 0, 4, 5, 4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5, 6, 2, 8, 9, 1, + 3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8, 1, 2, 5, 1, 3, 8, 7, 7, 7, 8, + 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9, 5, 3, 9, 5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, + 6, 2, 5, 6, 9, 3, 8, 8, 9, 3, 9, 0, 3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, + 5, 5, 6, 7, 6, 2, 6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1, + 8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5, 1, 7, 3, 4, 7, 2, + 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2, 4, 4, 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, + 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1, 7, 3, 7, 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, + 2, 4, 0, 6, 9, 5, 9, 5, 3, 3, 6, 9, 1, 4, 0, 6, 2, 5, + ]; + + shift &= 63; + let x_a = TABLE[shift]; + let x_b = TABLE[shift + 1]; + let num_new_digits = (x_a >> 11) as _; + let pow5_a = (0x7FF & x_a) as usize; + let pow5_b = (0x7FF & x_b) as usize; + let pow5 = &TABLE_POW5[pow5_a..]; + + for (i, &p5) in pow5.iter().enumerate().take(pow5_b - pow5_a) { + if i >= d.num_digits { + return num_new_digits - 1; + } else if d.digits[i] == p5 { + continue; + } else if d.digits[i] < p5 { + return num_new_digits - 1; + } else { + return num_new_digits; + } + } + + num_new_digits +} diff --git a/library/core/src/num/dec2flt/float.rs b/library/core/src/num/dec2flt/float.rs index da57aa9a546af..b8a28a6756917 100644 --- a/library/core/src/num/dec2flt/float.rs +++ b/library/core/src/num/dec2flt/float.rs @@ -1,14 +1,57 @@ //! Helper trait for generic float types. +use core::f64; + use crate::fmt::{Debug, LowerExp}; use crate::num::FpCategory; -use crate::ops::{Add, Div, Mul, Neg}; +use crate::ops::{self, Add, Div, Mul, Neg}; + +/// Lossy `as` casting between two types. +pub trait CastInto: Copy { + fn cast(self) -> T; +} + +/// Collection of traits that allow us to be generic over integer size. +pub trait Integer: + Sized + + Clone + + Copy + + Debug + + ops::Shr + + ops::Shl + + ops::BitAnd + + ops::BitOr + + PartialEq + + CastInto +{ + const ZERO: Self; + const ONE: Self; +} + +macro_rules! int { + ($($ty:ty),+) => { + $( + impl CastInto for $ty { + fn cast(self) -> i16 { + self as i16 + } + } + + impl Integer for $ty { + const ZERO: Self = 0; + const ONE: Self = 1; + } + )+ + } +} + +int!(u32, u64); -/// A helper trait to avoid duplicating basically all the conversion code for `f32` and `f64`. +/// A helper trait to avoid duplicating basically all the conversion code for IEEE floats. /// /// See the parent module's doc comment for why this is necessary. /// -/// Should **never ever** be implemented for other types or be used outside the dec2flt module. +/// Should **never ever** be implemented for other types or be used outside the `dec2flt` module. #[doc(hidden)] pub trait RawFloat: Sized @@ -24,62 +67,107 @@ pub trait RawFloat: + Copy + Debug { + /// The unsigned integer with the same size as the float + type Int: Integer + Into; + + /* general constants */ + const INFINITY: Self; const NEG_INFINITY: Self; const NAN: Self; const NEG_NAN: Self; - /// The number of bits in the significand, *excluding* the hidden bit. - const MANTISSA_EXPLICIT_BITS: usize; - - // Round-to-even only happens for negative values of q - // when q ≥ −4 in the 64-bit case and when q ≥ −17 in - // the 32-bitcase. - // - // When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we - // have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have - // 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10. - // - // When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64 - // so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case) - // or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64 - // (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11 - // or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase). - // - // Thus we have that we only need to round ties to even when - // we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10] - // (in the 32-bit case). In both cases,the power of five(5^|q|) - // fits in a 64-bit word. - const MIN_EXPONENT_ROUND_TO_EVEN: i32; - const MAX_EXPONENT_ROUND_TO_EVEN: i32; + /// Bit width of the float + const BITS: u32; - // Minimum exponent that for a fast path case, or `-⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋` - const MIN_EXPONENT_FAST_PATH: i64; + /// The number of bits in the significand, *including* the hidden bit. + const SIG_TOTAL_BITS: u32; - // Maximum exponent that for a fast path case, or `⌊(MANTISSA_EXPLICIT_BITS+1)/log2(5)⌋` - const MAX_EXPONENT_FAST_PATH: i64; + const EXP_MASK: Self::Int; + const SIG_MASK: Self::Int; - // Maximum exponent that can be represented for a disguised-fast path case. - // This is `MAX_EXPONENT_FAST_PATH + ⌊(MANTISSA_EXPLICIT_BITS+1)/log2(10)⌋` - const MAX_EXPONENT_DISGUISED_FAST_PATH: i64; - - // Minimum exponent value `-(1 << (EXP_BITS - 1)) + 1`. - const MINIMUM_EXPONENT: i32; + /// The number of bits in the significand, *excluding* the hidden bit. + const SIG_BITS: u32 = Self::SIG_TOTAL_BITS - 1; + + /// Number of bits in the exponent. + const EXP_BITS: u32 = Self::BITS - Self::SIG_BITS - 1; + + /// The saturated (maximum bitpattern) value of the exponent, i.e. the infinite + /// representation. + /// + /// This shifted fully right, use `EXP_MASK` for the shifted value. + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// Signed version of `EXP_SAT` since we convert a lot. + const INFINITE_POWER: i32 = Self::EXP_SAT as i32; + + /// The exponent bias value. This is also the maximum value of the exponent. + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + /// Minimum exponent value of normal values. + const EXP_MIN: i32 = -(Self::EXP_BIAS as i32 - 1); + + /// Round-to-even only happens for negative values of q + /// when q ≥ −4 in the 64-bit case and when q ≥ −17 in + /// the 32-bitcase. + /// + /// When q ≥ 0,we have that 5^q ≤ 2m+1. In the 64-bit case,we + /// have 5^q ≤ 2m+1 ≤ 2^54 or q ≤ 23. In the 32-bit case,we have + /// 5^q ≤ 2m+1 ≤ 2^25 or q ≤ 10. + /// + /// When q < 0, we have w ≥ (2m+1)×5^−q. We must have that w < 2^64 + /// so (2m+1)×5^−q < 2^64. We have that 2m+1 > 2^53 (64-bit case) + /// or 2m+1 > 2^24 (32-bit case). Hence,we must have 2^53×5^−q < 2^64 + /// (64-bit) and 2^24×5^−q < 2^64 (32-bit). Hence we have 5^−q < 2^11 + /// or q ≥ −4 (64-bit case) and 5^−q < 2^40 or q ≥ −17 (32-bitcase). + /// + /// Thus we have that we only need to round ties to even when + /// we have that q ∈ [−4,23](in the 64-bit case) or q∈[−17,10] + /// (in the 32-bit case). In both cases,the power of five(5^|q|) + /// fits in a 64-bit word. + const MIN_EXPONENT_ROUND_TO_EVEN: i32; + const MAX_EXPONENT_ROUND_TO_EVEN: i32; - // Largest exponent value `(1 << EXP_BITS) - 1`. - const INFINITE_POWER: i32; + /* limits related to Fast pathing */ + + /// Largest decimal exponent for a non-infinite value. + /// + /// This is the max exponent in binary converted to the max exponent in decimal. Allows fast + /// pathing anything larger than `10^LARGEST_POWER_OF_TEN`, which will round to infinity. + const LARGEST_POWER_OF_TEN: i32 = { + let largest_pow2 = Self::EXP_BIAS + 1; + pow2_to_pow10(largest_pow2 as i64) as i32 + }; + + /// Smallest decimal exponent for a non-zero value. This allows for fast pathing anything + /// smaller than `10^SMALLEST_POWER_OF_TEN`, which will round to zero. + /// + /// The smallest power of ten is represented by `⌊log10(2^-n / (2^64 - 1))⌋`, where `n` is + /// the smallest power of two. The `2^64 - 1)` denomenator comes from the number of values + /// that are representable by the intermediate storage format. I don't actually know _why_ + /// the storage format is relevant here. + /// + /// The values may be calculated using the formula. Unfortunately we cannot calculate them at + /// compile time since intermediates exceed the range of an `f64`. + const SMALLEST_POWER_OF_TEN: i32; - // Index (in bits) of the sign. - const SIGN_INDEX: usize; + /// Maximum exponent for a fast path case, or `⌊(SIG_BITS+1)/log2(5)⌋` + // assuming FLT_EVAL_METHOD = 0 + const MAX_EXPONENT_FAST_PATH: i64 = { + let log2_5 = f64::consts::LOG2_10 - 1.0; + (Self::SIG_TOTAL_BITS as f64 / log2_5) as i64 + }; - // Smallest decimal exponent for a non-zero value. - const SMALLEST_POWER_OF_TEN: i32; + /// Minimum exponent for a fast path case, or `-⌊(SIG_BITS+1)/log2(5)⌋` + const MIN_EXPONENT_FAST_PATH: i64 = -Self::MAX_EXPONENT_FAST_PATH; - // Largest decimal exponent for a non-infinite value. - const LARGEST_POWER_OF_TEN: i32; + /// Maximum exponent that can be represented for a disguised-fast path case. + /// This is `MAX_EXPONENT_FAST_PATH + ⌊(SIG_BITS+1)/log2(10)⌋` + const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = + Self::MAX_EXPONENT_FAST_PATH + (Self::SIG_TOTAL_BITS as f64 / f64::consts::LOG2_10) as i64; - // Maximum mantissa for the fast-path (`1 << 53` for f64). - const MAX_MANTISSA_FAST_PATH: u64 = 2_u64 << Self::MANTISSA_EXPLICIT_BITS; + /// Maximum mantissa for the fast-path (`1 << 53` for f64). + const MAX_MANTISSA_FAST_PATH: u64 = 1 << Self::SIG_TOTAL_BITS; /// Converts integer into float through an as cast. /// This is only called in the fast-path algorithm, and therefore @@ -96,27 +184,51 @@ pub trait RawFloat: /// Returns the category that this number falls into. fn classify(self) -> FpCategory; + /// Transmute to the integer representation + fn to_bits(self) -> Self::Int; + /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8); + /// + /// That is, this returns `(m, p, s)` such that `s * m * 2^p` represents the original float. + /// For 0, the exponent will be `-(EXP_BIAS + SIG_BITS`, which is the + /// minimum subnormal power. + fn integer_decode(self) -> (u64, i16, i8) { + let bits = self.to_bits(); + let sign: i8 = if bits >> (Self::BITS - 1) == Self::Int::ZERO { 1 } else { -1 }; + let mut exponent: i16 = ((bits & Self::EXP_MASK) >> Self::SIG_BITS).cast(); + let mantissa = if exponent == 0 { + (bits & Self::SIG_MASK) << 1 + } else { + (bits & Self::SIG_MASK) | (Self::Int::ONE << Self::SIG_BITS) + }; + // Exponent bias + mantissa shift + exponent -= (Self::EXP_BIAS + Self::SIG_BITS) as i16; + (mantissa.into(), exponent, sign) + } +} + +/// Solve for `b` in `10^b = 2^a` +const fn pow2_to_pow10(a: i64) -> i64 { + let res = (a as f64) / f64::consts::LOG2_10; + res as i64 } impl RawFloat for f32 { + type Int = u32; + const INFINITY: Self = f32::INFINITY; const NEG_INFINITY: Self = f32::NEG_INFINITY; const NAN: Self = f32::NAN; const NEG_NAN: Self = -f32::NAN; - const MANTISSA_EXPLICIT_BITS: usize = 23; + const BITS: u32 = 32; + const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS; + const EXP_MASK: Self::Int = Self::EXP_MASK; + const SIG_MASK: Self::Int = Self::MAN_MASK; + const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -17; const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 10; - const MIN_EXPONENT_FAST_PATH: i64 = -10; // assuming FLT_EVAL_METHOD = 0 - const MAX_EXPONENT_FAST_PATH: i64 = 10; - const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 17; - const MINIMUM_EXPONENT: i32 = -127; - const INFINITE_POWER: i32 = 0xFF; - const SIGN_INDEX: usize = 31; const SMALLEST_POWER_OF_TEN: i32 = -65; - const LARGEST_POWER_OF_TEN: i32 = 38; #[inline] fn from_u64(v: u64) -> Self { @@ -136,16 +248,8 @@ impl RawFloat for f32 { TABLE[exponent & 15] } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits = self.to_bits(); - let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 23) & 0xff) as i16; - let mantissa = - if exponent == 0 { (bits & 0x7fffff) << 1 } else { (bits & 0x7fffff) | 0x800000 }; - // Exponent bias + mantissa shift - exponent -= 127 + 23; - (mantissa as u64, exponent, sign) + fn to_bits(self) -> Self::Int { + self.to_bits() } fn classify(self) -> FpCategory { @@ -154,22 +258,21 @@ impl RawFloat for f32 { } impl RawFloat for f64 { - const INFINITY: Self = f64::INFINITY; - const NEG_INFINITY: Self = f64::NEG_INFINITY; - const NAN: Self = f64::NAN; - const NEG_NAN: Self = -f64::NAN; + type Int = u64; + + const INFINITY: Self = Self::INFINITY; + const NEG_INFINITY: Self = Self::NEG_INFINITY; + const NAN: Self = Self::NAN; + const NEG_NAN: Self = -Self::NAN; + + const BITS: u32 = 64; + const SIG_TOTAL_BITS: u32 = Self::MANTISSA_DIGITS; + const EXP_MASK: Self::Int = Self::EXP_MASK; + const SIG_MASK: Self::Int = Self::MAN_MASK; - const MANTISSA_EXPLICIT_BITS: usize = 52; const MIN_EXPONENT_ROUND_TO_EVEN: i32 = -4; const MAX_EXPONENT_ROUND_TO_EVEN: i32 = 23; - const MIN_EXPONENT_FAST_PATH: i64 = -22; // assuming FLT_EVAL_METHOD = 0 - const MAX_EXPONENT_FAST_PATH: i64 = 22; - const MAX_EXPONENT_DISGUISED_FAST_PATH: i64 = 37; - const MINIMUM_EXPONENT: i32 = -1023; - const INFINITE_POWER: i32 = 0x7FF; - const SIGN_INDEX: usize = 63; const SMALLEST_POWER_OF_TEN: i32 = -342; - const LARGEST_POWER_OF_TEN: i32 = 308; #[inline] fn from_u64(v: u64) -> Self { @@ -190,19 +293,8 @@ impl RawFloat for f64 { TABLE[exponent & 31] } - /// Returns the mantissa, exponent and sign as integers. - fn integer_decode(self) -> (u64, i16, i8) { - let bits = self.to_bits(); - let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 }; - let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16; - let mantissa = if exponent == 0 { - (bits & 0xfffffffffffff) << 1 - } else { - (bits & 0xfffffffffffff) | 0x10000000000000 - }; - // Exponent bias + mantissa shift - exponent -= 1023 + 52; - (mantissa, exponent, sign) + fn to_bits(self) -> Self::Int { + self.to_bits() } fn classify(self) -> FpCategory { diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs index daeee1755b0b5..8aad087ec1bc4 100644 --- a/library/core/src/num/dec2flt/fpu.rs +++ b/library/core/src/num/dec2flt/fpu.rs @@ -22,7 +22,6 @@ pub(super) use fpu_precision::set_precision; #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] mod fpu_precision { use core::arch::asm; - use core::mem::size_of; /// A structure used to preserve the original value of the FPU control word, so that it can be /// restored when the structure is dropped. diff --git a/library/core/src/num/dec2flt/lemire.rs b/library/core/src/num/dec2flt/lemire.rs index 01642e1b1112a..f84929a03c172 100644 --- a/library/core/src/num/dec2flt/lemire.rs +++ b/library/core/src/num/dec2flt/lemire.rs @@ -38,7 +38,7 @@ pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { // Normalize our significant digits, so the most-significant bit is set. let lz = w.leading_zeros(); w <<= lz; - let (lo, hi) = compute_product_approx(q, w, F::MANTISSA_EXPLICIT_BITS + 3); + let (lo, hi) = compute_product_approx(q, w, F::SIG_BITS as usize + 3); if lo == 0xFFFF_FFFF_FFFF_FFFF { // If we have failed to approximate w x 5^-q with our 128-bit value. // Since the addition of 1 could lead to an overflow which could then @@ -61,8 +61,8 @@ pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { } } let upperbit = (hi >> 63) as i32; - let mut mantissa = hi >> (upperbit + 64 - F::MANTISSA_EXPLICIT_BITS as i32 - 3); - let mut power2 = power(q as i32) + upperbit - lz as i32 - F::MINIMUM_EXPONENT; + let mut mantissa = hi >> (upperbit + 64 - F::SIG_BITS as i32 - 3); + let mut power2 = power(q as i32) + upperbit - lz as i32 - F::EXP_MIN + 1; if power2 <= 0 { if -power2 + 1 >= 64 { // Have more than 64 bits below the minimum exponent, must be 0. @@ -72,8 +72,8 @@ pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { mantissa >>= -power2 + 1; mantissa += mantissa & 1; mantissa >>= 1; - power2 = (mantissa >= (1_u64 << F::MANTISSA_EXPLICIT_BITS)) as i32; - return BiasedFp { f: mantissa, e: power2 }; + power2 = (mantissa >= (1_u64 << F::SIG_BITS)) as i32; + return BiasedFp { m: mantissa, p_biased: power2 }; } // Need to handle rounding ties. Normally, we need to round up, // but if we fall right in between and we have an even basis, we @@ -89,8 +89,8 @@ pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { if lo <= 1 && q >= F::MIN_EXPONENT_ROUND_TO_EVEN as i64 && q <= F::MAX_EXPONENT_ROUND_TO_EVEN as i64 - && mantissa & 3 == 1 - && (mantissa << (upperbit + 64 - F::MANTISSA_EXPLICIT_BITS as i32 - 3)) == hi + && mantissa & 0b11 == 0b01 + && (mantissa << (upperbit + 64 - F::SIG_BITS as i32 - 3)) == hi { // Zero the lowest bit, so we don't round up. mantissa &= !1_u64; @@ -98,20 +98,20 @@ pub fn compute_float(q: i64, mut w: u64) -> BiasedFp { // Round-to-even, then shift the significant digits into place. mantissa += mantissa & 1; mantissa >>= 1; - if mantissa >= (2_u64 << F::MANTISSA_EXPLICIT_BITS) { + if mantissa >= (2_u64 << F::SIG_BITS) { // Rounding up overflowed, so the carry bit is set. Set the // mantissa to 1 (only the implicit, hidden bit is set) and // increase the exponent. - mantissa = 1_u64 << F::MANTISSA_EXPLICIT_BITS; + mantissa = 1_u64 << F::SIG_BITS; power2 += 1; } // Zero out the hidden bit. - mantissa &= !(1_u64 << F::MANTISSA_EXPLICIT_BITS); + mantissa &= !(1_u64 << F::SIG_BITS); if power2 >= F::INFINITE_POWER { // Exponent is above largest normal value, must be infinite. return fp_inf; } - BiasedFp { f: mantissa, e: power2 } + BiasedFp { m: mantissa, p_biased: power2 } } /// Calculate a base 2 exponent from a decimal exponent. diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index 6dca740684537..d1a0e1db31314 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -3,8 +3,8 @@ //! # Problem statement //! //! We are given a decimal string such as `12.34e56`. This string consists of integral (`12`), -//! fractional (`34`), and exponent (`56`) parts. All parts are optional and interpreted as zero -//! when missing. +//! fractional (`34`), and exponent (`56`) parts. All parts are optional and interpreted as a +//! default value (1 or 0) when missing. //! //! We seek the IEEE 754 floating point number that is closest to the exact value of the decimal //! string. It is well-known that many decimal strings do not have terminating representations in @@ -67,6 +67,18 @@ //! "such that the exponent +/- the number of decimal digits fits into a 64 bit integer". //! Larger exponents are accepted, but we don't do arithmetic with them, they are immediately //! turned into {positive,negative} {zero,infinity}. +//! +//! # Notation +//! +//! This module uses the same notation as the Lemire paper: +//! +//! - `m`: binary mantissa; always nonnegative +//! - `p`: binary exponent; a signed integer +//! - `w`: decimal significand; always nonnegative +//! - `q`: decimal exponent; a signed integer +//! +//! This gives `m * 2^p` for the binary floating-point number, with `w * 10^q` as the decimal +//! equivalent. #![doc(hidden)] #![unstable( @@ -85,14 +97,14 @@ use crate::fmt; use crate::str::FromStr; mod common; -mod decimal; +pub mod decimal; +pub mod decimal_seq; mod fpu; mod slow; mod table; // float is used in flt2dec, and all are used in unit tests. pub mod float; pub mod lemire; -pub mod number; pub mod parse; macro_rules! from_str_float_impl { @@ -220,10 +232,10 @@ pub fn pfe_invalid() -> ParseFloatError { } /// Converts a `BiasedFp` to the closest machine float type. -fn biased_fp_to_float(x: BiasedFp) -> T { - let mut word = x.f; - word |= (x.e as u64) << T::MANTISSA_EXPLICIT_BITS; - T::from_u64_bits(word) +fn biased_fp_to_float(x: BiasedFp) -> F { + let mut word = x.m; + word |= (x.p_biased as u64) << F::SIG_BITS; + F::from_u64_bits(word) } /// Converts a decimal string into a floating point number. @@ -260,12 +272,15 @@ pub fn dec2flt(s: &str) -> Result { // redundantly using the Eisel-Lemire algorithm if it was unable to // correctly round on the first pass. let mut fp = compute_float::(num.exponent, num.mantissa); - if num.many_digits && fp.e >= 0 && fp != compute_float::(num.exponent, num.mantissa + 1) { - fp.e = -1; + if num.many_digits + && fp.p_biased >= 0 + && fp != compute_float::(num.exponent, num.mantissa + 1) + { + fp.p_biased = -1; } // Unable to correctly round the float using the Eisel-Lemire algorithm. // Fallback to a slower, but always correct algorithm. - if fp.e < 0 { + if fp.p_biased < 0 { fp = parse_long_mantissa::(s); } diff --git a/library/core/src/num/dec2flt/number.rs b/library/core/src/num/dec2flt/number.rs deleted file mode 100644 index 2538991564ae4..0000000000000 --- a/library/core/src/num/dec2flt/number.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! Representation of a float as the significant digits and exponent. - -use crate::num::dec2flt::float::RawFloat; -use crate::num::dec2flt::fpu::set_precision; - -#[rustfmt::skip] -const INT_POW10: [u64; 16] = [ - 1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000, - 1000000000000000, -]; - -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] -pub struct Number { - pub exponent: i64, - pub mantissa: u64, - pub negative: bool, - pub many_digits: bool, -} - -impl Number { - /// Detect if the float can be accurately reconstructed from native floats. - #[inline] - fn is_fast_path(&self) -> bool { - F::MIN_EXPONENT_FAST_PATH <= self.exponent - && self.exponent <= F::MAX_EXPONENT_DISGUISED_FAST_PATH - && self.mantissa <= F::MAX_MANTISSA_FAST_PATH - && !self.many_digits - } - - /// The fast path algorithm using machine-sized integers and floats. - /// - /// This is extracted into a separate function so that it can be attempted before constructing - /// a Decimal. This only works if both the mantissa and the exponent - /// can be exactly represented as a machine float, since IEE-754 guarantees - /// no rounding will occur. - /// - /// There is an exception: disguised fast-path cases, where we can shift - /// powers-of-10 from the exponent to the significant digits. - pub fn try_fast_path(&self) -> Option { - // Here we need to work around . - // The fast path crucially depends on arithmetic being rounded to the correct number of bits - // without any intermediate rounding. On x86 (without SSE or SSE2) this requires the precision - // of the x87 FPU stack to be changed so that it directly rounds to 64/32 bit. - // The `set_precision` function takes care of setting the precision on architectures which - // require setting it by changing the global state (like the control word of the x87 FPU). - let _cw = set_precision::(); - - if self.is_fast_path::() { - let mut value = if self.exponent <= F::MAX_EXPONENT_FAST_PATH { - // normal fast path - let value = F::from_u64(self.mantissa); - if self.exponent < 0 { - value / F::pow10_fast_path((-self.exponent) as _) - } else { - value * F::pow10_fast_path(self.exponent as _) - } - } else { - // disguised fast path - let shift = self.exponent - F::MAX_EXPONENT_FAST_PATH; - let mantissa = self.mantissa.checked_mul(INT_POW10[shift as usize])?; - if mantissa > F::MAX_MANTISSA_FAST_PATH { - return None; - } - F::from_u64(mantissa) * F::pow10_fast_path(F::MAX_EXPONENT_FAST_PATH as _) - }; - if self.negative { - value = -value; - } - Some(value) - } else { - None - } - } -} diff --git a/library/core/src/num/dec2flt/parse.rs b/library/core/src/num/dec2flt/parse.rs index 06ee8e95fbc47..e38fedc58bec0 100644 --- a/library/core/src/num/dec2flt/parse.rs +++ b/library/core/src/num/dec2flt/parse.rs @@ -1,8 +1,8 @@ //! Functions to parse floating-point numbers. use crate::num::dec2flt::common::{ByteSlice, is_8digits}; +use crate::num::dec2flt::decimal::Decimal; use crate::num::dec2flt::float::RawFloat; -use crate::num::dec2flt::number::Number; const MIN_19DIGIT_INT: u64 = 100_0000_0000_0000_0000; @@ -100,7 +100,7 @@ fn parse_scientific(s_ref: &mut &[u8]) -> Option { /// /// This creates a representation of the float as the /// significant digits and the decimal exponent. -fn parse_partial_number(mut s: &[u8]) -> Option<(Number, usize)> { +fn parse_partial_number(mut s: &[u8]) -> Option<(Decimal, usize)> { debug_assert!(!s.is_empty()); // parse initial digits before dot @@ -146,7 +146,7 @@ fn parse_partial_number(mut s: &[u8]) -> Option<(Number, usize)> { // handle uncommon case with many digits if n_digits <= 19 { - return Some((Number { exponent, mantissa, negative: false, many_digits: false }, len)); + return Some((Decimal { exponent, mantissa, negative: false, many_digits: false }, len)); } n_digits -= 19; @@ -179,13 +179,13 @@ fn parse_partial_number(mut s: &[u8]) -> Option<(Number, usize)> { exponent += exp_number; } - Some((Number { exponent, mantissa, negative: false, many_digits }, len)) + Some((Decimal { exponent, mantissa, negative: false, many_digits }, len)) } /// Try to parse a non-special floating point number, /// as well as two slices with integer and fractional parts /// and the parsed exponent. -pub fn parse_number(s: &[u8]) -> Option { +pub fn parse_number(s: &[u8]) -> Option { if let Some((float, rest)) = parse_partial_number(s) { if rest == s.len() { return Some(float); diff --git a/library/core/src/num/dec2flt/slow.rs b/library/core/src/num/dec2flt/slow.rs index 85d4b13284b7d..3baed42652393 100644 --- a/library/core/src/num/dec2flt/slow.rs +++ b/library/core/src/num/dec2flt/slow.rs @@ -1,7 +1,7 @@ //! Slow, fallback algorithm for cases the Eisel-Lemire algorithm cannot round. use crate::num::dec2flt::common::BiasedFp; -use crate::num::dec2flt::decimal::{Decimal, parse_decimal}; +use crate::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; use crate::num::dec2flt::float::RawFloat; /// Parse the significant digits and biased, binary exponent of a float. @@ -36,7 +36,7 @@ pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { let fp_zero = BiasedFp::zero_pow2(0); let fp_inf = BiasedFp::zero_pow2(F::INFINITE_POWER); - let mut d = parse_decimal(s); + let mut d = parse_decimal_seq(s); // Short-circuit if the value can only be a literal 0 or infinity. if d.num_digits == 0 || d.decimal_point < -324 { @@ -50,7 +50,7 @@ pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { let n = d.decimal_point as usize; let shift = get_shift(n); d.right_shift(shift); - if d.decimal_point < -Decimal::DECIMAL_POINT_RANGE { + if d.decimal_point < -DecimalSeq::DECIMAL_POINT_RANGE { return fp_zero; } exp2 += shift as i32; @@ -67,43 +67,43 @@ pub(crate) fn parse_long_mantissa(s: &[u8]) -> BiasedFp { get_shift((-d.decimal_point) as _) }; d.left_shift(shift); - if d.decimal_point > Decimal::DECIMAL_POINT_RANGE { + if d.decimal_point > DecimalSeq::DECIMAL_POINT_RANGE { return fp_inf; } exp2 -= shift as i32; } // We are now in the range [1/2 ... 1] but the binary format uses [1 ... 2]. exp2 -= 1; - while (F::MINIMUM_EXPONENT + 1) > exp2 { - let mut n = ((F::MINIMUM_EXPONENT + 1) - exp2) as usize; + while F::EXP_MIN > exp2 { + let mut n = (F::EXP_MIN - exp2) as usize; if n > MAX_SHIFT { n = MAX_SHIFT; } d.right_shift(n); exp2 += n as i32; } - if (exp2 - F::MINIMUM_EXPONENT) >= F::INFINITE_POWER { + if (exp2 - F::EXP_MIN + 1) >= F::INFINITE_POWER { return fp_inf; } // Shift the decimal to the hidden bit, and then round the value // to get the high mantissa+1 bits. - d.left_shift(F::MANTISSA_EXPLICIT_BITS + 1); + d.left_shift(F::SIG_BITS as usize + 1); let mut mantissa = d.round(); - if mantissa >= (1_u64 << (F::MANTISSA_EXPLICIT_BITS + 1)) { + if mantissa >= (1_u64 << (F::SIG_BITS + 1)) { // Rounding up overflowed to the carry bit, need to // shift back to the hidden bit. d.right_shift(1); exp2 += 1; mantissa = d.round(); - if (exp2 - F::MINIMUM_EXPONENT) >= F::INFINITE_POWER { + if (exp2 - F::EXP_MIN + 1) >= F::INFINITE_POWER { return fp_inf; } } - let mut power2 = exp2 - F::MINIMUM_EXPONENT; - if mantissa < (1_u64 << F::MANTISSA_EXPLICIT_BITS) { + let mut power2 = exp2 - F::EXP_MIN + 1; + if mantissa < (1_u64 << F::SIG_BITS) { power2 -= 1; } // Zero out all the bits above the explicit mantissa bits. - mantissa &= (1_u64 << F::MANTISSA_EXPLICIT_BITS) - 1; - BiasedFp { f: mantissa, e: power2 } + mantissa &= (1_u64 << F::SIG_BITS) - 1; + BiasedFp { m: mantissa, p_biased: power2 } } diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 5e45974b3d422..b17190971c3e8 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -12,11 +12,9 @@ #![unstable(feature = "f128", issue = "116909")] use crate::convert::FloatToInt; -#[cfg(not(test))] -use crate::intrinsics; -use crate::mem; use crate::num::FpCategory; use crate::panic::const_assert; +use crate::{intrinsics, mem}; /// Basic mathematical constants. #[unstable(feature = "f128", issue = "116909")] @@ -138,7 +136,6 @@ pub mod consts { pub const LN_10: f128 = 2.30258509299404568401799145468436420760110148862877297603333_f128; } -#[cfg(not(test))] impl f128 { // FIXME(f16_f128): almost all methods in this `impl` are missing examples and a const // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index e3176cd168852..d20677f43b417 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -12,11 +12,9 @@ #![unstable(feature = "f16", issue = "116909")] use crate::convert::FloatToInt; -#[cfg(not(test))] -use crate::intrinsics; -use crate::mem; use crate::num::FpCategory; use crate::panic::const_assert; +use crate::{intrinsics, mem}; /// Basic mathematical constants. #[unstable(feature = "f16", issue = "116909")] @@ -133,7 +131,6 @@ pub mod consts { pub const LN_10: f16 = 2.30258509299404568401799145468436421_f16; } -#[cfg(not(test))] impl f16 { // FIXME(f16_f128): almost all methods in this `impl` are missing examples and a const // implementation. Add these once we can run code on all platforms and have f16/f128 in CTFE. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 4d42997369ffb..79d864e1b1966 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -12,11 +12,9 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -#[cfg(not(test))] -use crate::intrinsics; -use crate::mem; use crate::num::FpCategory; use crate::panic::const_assert; +use crate::{intrinsics, mem}; /// The radix or base of the internal representation of `f32`. /// Use [`f32::RADIX`] instead. @@ -386,7 +384,6 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[cfg(not(test))] impl f32 { /// The radix or base of the internal representation of `f32`. #[stable(feature = "assoc_int_consts", since = "1.43.0")] @@ -416,7 +413,7 @@ impl f32 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f32::MANTISSA_DIGITS #[stable(feature = "assoc_int_consts", since = "1.43.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "f32_epsilon")] + #[rustc_diagnostic_item = "f32_epsilon"] pub const EPSILON: f32 = 1.19209290e-07_f32; /// Smallest finite `f32` value. @@ -493,13 +490,13 @@ impl f32 { pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32; /// Sign bit - const SIGN_MASK: u32 = 0x8000_0000; + pub(crate) const SIGN_MASK: u32 = 0x8000_0000; /// Exponent mask - const EXP_MASK: u32 = 0x7f80_0000; + pub(crate) const EXP_MASK: u32 = 0x7f80_0000; /// Mantissa mask - const MAN_MASK: u32 = 0x007f_ffff; + pub(crate) const MAN_MASK: u32 = 0x007f_ffff; /// Minimum representable positive value (min subnormal) const TINY_BITS: u32 = 0x1; @@ -741,8 +738,8 @@ impl f32 { /// [`MAX`]: Self::MAX #[inline] #[doc(alias = "nextUp")] - #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "float_next_up_down", since = "1.86.0")] + #[rustc_const_stable(feature = "float_next_up_down", since = "1.86.0")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -792,8 +789,8 @@ impl f32 { /// [`MAX`]: Self::MAX #[inline] #[doc(alias = "nextDown")] - #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "float_next_up_down", since = "1.86.0")] + #[rustc_const_stable(feature = "float_next_up_down", since = "1.86.0")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 907971d303ffc..ca28b40bb3adc 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -12,11 +12,9 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::convert::FloatToInt; -#[cfg(not(test))] -use crate::intrinsics; -use crate::mem; use crate::num::FpCategory; use crate::panic::const_assert; +use crate::{intrinsics, mem}; /// The radix or base of the internal representation of `f64`. /// Use [`f64::RADIX`] instead. @@ -386,7 +384,6 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[cfg(not(test))] impl f64 { /// The radix or base of the internal representation of `f64`. #[stable(feature = "assoc_int_consts", since = "1.43.0")] @@ -415,7 +412,7 @@ impl f64 { /// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon /// [`MANTISSA_DIGITS`]: f64::MANTISSA_DIGITS #[stable(feature = "assoc_int_consts", since = "1.43.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "f64_epsilon")] + #[rustc_diagnostic_item = "f64_epsilon"] pub const EPSILON: f64 = 2.2204460492503131e-16_f64; /// Smallest finite `f64` value. @@ -492,13 +489,13 @@ impl f64 { pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64; /// Sign bit - const SIGN_MASK: u64 = 0x8000_0000_0000_0000; + pub(crate) const SIGN_MASK: u64 = 0x8000_0000_0000_0000; /// Exponent mask - const EXP_MASK: u64 = 0x7ff0_0000_0000_0000; + pub(crate) const EXP_MASK: u64 = 0x7ff0_0000_0000_0000; /// Mantissa mask - const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff; + pub(crate) const MAN_MASK: u64 = 0x000f_ffff_ffff_ffff; /// Minimum representable positive value (min subnormal) const TINY_BITS: u64 = 0x1; @@ -758,8 +755,8 @@ impl f64 { /// [`MAX`]: Self::MAX #[inline] #[doc(alias = "nextUp")] - #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "float_next_up_down", since = "1.86.0")] + #[rustc_const_stable(feature = "float_next_up_down", since = "1.86.0")] pub const fn next_up(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here @@ -809,8 +806,8 @@ impl f64 { /// [`MAX`]: Self::MAX #[inline] #[doc(alias = "nextDown")] - #[stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "float_next_up_down", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "float_next_up_down", since = "1.86.0")] + #[rustc_const_stable(feature = "float_next_up_down", since = "1.86.0")] pub const fn next_down(self) -> Self { // Some targets violate Rust's assumption of IEEE semantics, e.g. by flushing // denormals to zero. This is in general unsound and unsupported, but here diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 296b5ebdfafcc..a72ca4bcb059b 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -183,6 +183,52 @@ macro_rules! int_impl { (self as $UnsignedT).trailing_ones() } + /// Returns `self` with only the most significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_most_significant_one(), 0b_01000000); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_most_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_most_significant_one(self) -> Self { + self & (((1 as $SelfT) << (<$SelfT>::BITS - 1)).wrapping_shr(self.leading_zeros())) + } + + /// Returns `self` with only the least significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_least_significant_one(), 0b_00000100); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_least_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_least_significant_one(self) -> Self { + self & self.wrapping_neg() + } + /// Returns the bit pattern of `self` reinterpreted as an unsigned integer of the same size. /// /// This produces the same result as an `as` cast, but ensures that the bit-width remains @@ -1306,11 +1352,11 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1428,12 +1474,12 @@ macro_rules! int_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -3581,7 +3627,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + pub const fn to_be_bytes(self) -> [u8; size_of::()] { self.to_be().to_ne_bytes() } @@ -3601,7 +3647,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + pub const fn to_le_bytes(self) -> [u8; size_of::()] { self.to_le().to_ne_bytes() } @@ -3637,7 +3683,7 @@ macro_rules! int_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + pub const fn to_ne_bytes(self) -> [u8; size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to // arrays of bytes unsafe { mem::transmute(self) } @@ -3659,7 +3705,7 @@ macro_rules! int_impl { /// /// ``` #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")] - #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")] + #[doc = concat!(" let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")] /// *input = rest; #[doc = concat!(" ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")] /// } @@ -3668,7 +3714,7 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] #[must_use] #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + pub const fn from_be_bytes(bytes: [u8; size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) } @@ -3688,7 +3734,7 @@ macro_rules! int_impl { /// /// ``` #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")] - #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")] + #[doc = concat!(" let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")] /// *input = rest; #[doc = concat!(" ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")] /// } @@ -3697,7 +3743,7 @@ macro_rules! int_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] #[must_use] #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + pub const fn from_le_bytes(bytes: [u8; size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) } @@ -3728,7 +3774,7 @@ macro_rules! int_impl { /// /// ``` #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")] - #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")] + #[doc = concat!(" let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")] /// *input = rest; #[doc = concat!(" ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")] /// } @@ -3739,7 +3785,7 @@ macro_rules! int_impl { // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them #[inline] - pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + pub const fn from_ne_bytes(bytes: [u8; size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them unsafe { mem::transmute(bytes) } } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 80a38a6013dd0..151e128cd78a9 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1241,7 +1241,7 @@ impl usize { /// Returns an `usize` where every byte is equal to `x`. #[inline] pub(crate) const fn repeat_u8(x: u8) -> usize { - usize::from_ne_bytes([x; mem::size_of::()]) + usize::from_ne_bytes([x; size_of::()]) } /// Returns an `usize` where every byte pair is equal to `x`. @@ -1249,7 +1249,7 @@ impl usize { pub(crate) const fn repeat_u16(x: u16) -> usize { let mut r = 0usize; let mut i = 0; - while i < mem::size_of::() { + while i < size_of::() { // Use `wrapping_shl` to make it work on targets with 16-bit `usize` r = r.wrapping_shl(16) | (x as usize); i += 2; @@ -1330,7 +1330,7 @@ pub enum FpCategory { #[inline(always)] #[unstable(issue = "none", feature = "std_internals")] pub const fn can_not_overflow(radix: u32, is_signed_ty: bool, digits: &[u8]) -> bool { - radix <= 16 && digits.len() <= mem::size_of::() * 2 - is_signed_ty as usize + radix <= 16 && digits.len() <= size_of::() * 2 - is_signed_ty as usize } #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index b59451d7c7580..7585ec140e31e 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1,6 +1,7 @@ //! Definitions of integer that is known not to equal zero. use super::{IntErrorKind, ParseIntError}; +use crate::clone::UseCloned; use crate::cmp::Ordering; use crate::hash::{Hash, Hasher}; use crate::marker::{Freeze, StructuralPartialEq}; @@ -86,7 +87,7 @@ impl_zeroable_primitive!( /// For example, `Option>` is the same size as `u32`: /// /// ``` -/// use core::{mem::size_of, num::NonZero}; +/// use core::{num::NonZero}; /// /// assert_eq!(size_of::>>(), size_of::()); /// ``` @@ -102,7 +103,6 @@ impl_zeroable_primitive!( /// `Option>` are guaranteed to have the same size and alignment: /// /// ``` -/// # use std::mem::{size_of, align_of}; /// use std::num::NonZero; /// /// assert_eq!(size_of::>(), size_of::>>()); @@ -183,6 +183,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl UseCloned for NonZero where T: ZeroablePrimitive {} + #[stable(feature = "nonzero", since = "1.28.0")] impl Copy for NonZero where T: ZeroablePrimitive {} @@ -500,7 +503,6 @@ macro_rules! nonzero_integer { #[doc = concat!("For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`:")] /// /// ```rust - /// use std::mem::size_of; #[doc = concat!("assert_eq!(size_of::>(), size_of::<", stringify!($Int), ">());")] /// ``` /// @@ -516,7 +518,6 @@ macro_rules! nonzero_integer { /// are guaranteed to have the same size and alignment: /// /// ``` - /// # use std::mem::{size_of, align_of}; #[doc = concat!("use std::num::", stringify!($Ty), ";")] /// #[doc = concat!("assert_eq!(size_of::<", stringify!($Ty), ">(), size_of::>());")] @@ -605,6 +606,70 @@ macro_rules! nonzero_integer { } } + /// Returns `self` with only the most significant bit set. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + /// # use core::num::NonZero; + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b_01100100)?;")] + #[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b_01000000)?;")] + /// + /// assert_eq!(a.isolate_most_significant_one(), b); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_most_significant_one(self) -> Self { + let n = self.get() & (((1 as $Int) << (<$Int>::BITS - 1)).wrapping_shr(self.leading_zeros())); + + // SAFETY: + // `self` is non-zero, so masking to preserve only the most + // significant set bit will result in a non-zero `n`. + unsafe { NonZero::new_unchecked(n) } + } + + /// Returns `self` with only the least significant bit set. + /// + /// # Example + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + /// # use core::num::NonZero; + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b_01100100)?;")] + #[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b_00000100)?;")] + /// + /// assert_eq!(a.isolate_least_significant_one(), b); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_least_significant_one(self) -> Self { + let n = self.get(); + let n = n & n.wrapping_neg(); + + // SAFETY: `self` is non-zero, so `self` with only its least + // significant set bit will remain non-zero. + unsafe { NonZero::new_unchecked(n) } + } + /// Returns the number of ones in the binary representation of `self`. /// /// # Examples @@ -625,8 +690,8 @@ macro_rules! nonzero_integer { /// # } /// ``` /// - #[stable(feature = "non_zero_count_ones", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "non_zero_count_ones", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "non_zero_count_ones", since = "1.86.0")] + #[rustc_const_stable(feature = "non_zero_count_ones", since = "1.86.0")] #[doc(alias = "popcount")] #[doc(alias = "popcnt")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 74d3ae699f66f..586892758398b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -213,6 +213,52 @@ macro_rules! uint_impl { (!self).trailing_zeros() } + /// Returns `self` with only the most significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_most_significant_one(), 0b_01000000); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_most_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_most_significant_one(self) -> Self { + self & (((1 as $SelfT) << (<$SelfT>::BITS - 1)).wrapping_shr(self.leading_zeros())) + } + + /// Returns `self` with only the least significant bit set, or `0` if + /// the input is `0`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(isolate_most_least_significant_one)] + /// + #[doc = concat!("let n: ", stringify!($SelfT), " = 0b_01100100;")] + /// + /// assert_eq!(n.isolate_least_significant_one(), 0b_00000100); + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".isolate_least_significant_one(), 0);")] + /// ``` + #[unstable(feature = "isolate_most_least_significant_one", issue = "136909")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn isolate_least_significant_one(self) -> Self { + self & self.wrapping_neg() + } + /// Returns the bit pattern of `self` reinterpreted as a signed integer of the same size. /// /// This produces the same result as an `as` cast, but ensures that the bit-width remains @@ -1567,11 +1613,11 @@ macro_rules! uint_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")] #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -1688,11 +1734,11 @@ macro_rules! uint_impl { /// /// Basic usage: /// ``` - /// #![feature(unbounded_shifts)] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")] #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")] /// ``` - #[unstable(feature = "unbounded_shifts", issue = "129375")] + #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] @@ -2487,15 +2533,20 @@ macro_rules! uint_impl { #[doc = concat!("assert_eq!((diff1, diff0), (3, ", stringify!($SelfT), "::MAX));")] /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] + #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) { // note: longer-term this should be done via an intrinsic, but this has been shown // to generate optimal code for now, and LLVM doesn't have an equivalent intrinsic - let (a, b) = self.overflowing_sub(rhs); - let (c, d) = a.overflowing_sub(borrow as $SelfT); - (c, b | d) + let (a, c1) = self.overflowing_sub(rhs); + let (b, c2) = a.overflowing_sub(borrow as $SelfT); + // SAFETY: Only one of `c1` and `c2` can be set. + // For c1 to be set we need to have underflowed, but if we did then + // `a` is nonzero, which means that `c2` cannot possibly + // underflow because it's subtracting at most `1` (since it came from `bool`) + (b, unsafe { intrinsics::disjoint_bitor(c1, c2) }) } /// Calculates `self` - `rhs` with a signed `rhs` @@ -2540,7 +2591,7 @@ macro_rules! uint_impl { without modifying the original"] #[inline] pub const fn abs_diff(self, other: Self) -> Self { - if mem::size_of::() == 1 { + if size_of::() == 1 { // Trick LLVM into generating the psadbw instruction when SSE2 // is available and this function is autovectorized for u8's. (self as i32).wrapping_sub(other as i32).abs() as Self @@ -3274,14 +3325,14 @@ macro_rules! uint_impl { /// Basic usage: /// /// ``` - /// #![feature(unsigned_is_multiple_of)] #[doc = concat!("assert!(6_", stringify!($SelfT), ".is_multiple_of(2));")] #[doc = concat!("assert!(!5_", stringify!($SelfT), ".is_multiple_of(2));")] /// #[doc = concat!("assert!(0_", stringify!($SelfT), ".is_multiple_of(0));")] #[doc = concat!("assert!(!6_", stringify!($SelfT), ".is_multiple_of(0));")] /// ``` - #[unstable(feature = "unsigned_is_multiple_of", issue = "128101")] + #[stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "unsigned_is_multiple_of", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] #[rustc_inherit_overflow_checks] @@ -3419,7 +3470,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + pub const fn to_be_bytes(self) -> [u8; size_of::()] { self.to_be().to_ne_bytes() } @@ -3439,7 +3490,7 @@ macro_rules! uint_impl { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + pub const fn to_le_bytes(self) -> [u8; size_of::()] { self.to_le().to_ne_bytes() } @@ -3475,7 +3526,7 @@ macro_rules! uint_impl { // SAFETY: const sound because integers are plain old datatypes so we can always // transmute them to arrays of bytes #[inline] - pub const fn to_ne_bytes(self) -> [u8; mem::size_of::()] { + pub const fn to_ne_bytes(self) -> [u8; size_of::()] { // SAFETY: integers are plain old datatypes so we can always transmute them to // arrays of bytes unsafe { mem::transmute(self) } @@ -3497,7 +3548,7 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")] - #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")] + #[doc = concat!(" let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")] /// *input = rest; #[doc = concat!(" ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap())")] /// } @@ -3506,7 +3557,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] #[must_use] #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + pub const fn from_be_bytes(bytes: [u8; size_of::()]) -> Self { Self::from_be(Self::from_ne_bytes(bytes)) } @@ -3526,7 +3577,7 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")] - #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")] + #[doc = concat!(" let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")] /// *input = rest; #[doc = concat!(" ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap())")] /// } @@ -3535,7 +3586,7 @@ macro_rules! uint_impl { #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] #[must_use] #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + pub const fn from_le_bytes(bytes: [u8; size_of::()]) -> Self { Self::from_le(Self::from_ne_bytes(bytes)) } @@ -3566,7 +3617,7 @@ macro_rules! uint_impl { /// /// ``` #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")] - #[doc = concat!(" let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")] + #[doc = concat!(" let (int_bytes, rest) = input.split_at(size_of::<", stringify!($SelfT), ">());")] /// *input = rest; #[doc = concat!(" ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap())")] /// } @@ -3577,7 +3628,7 @@ macro_rules! uint_impl { // SAFETY: const sound because integers are plain old datatypes so we can always // transmute to them #[inline] - pub const fn from_ne_bytes(bytes: [u8; mem::size_of::()]) -> Self { + pub const fn from_ne_bytes(bytes: [u8; size_of::()]) -> Self { // SAFETY: integers are plain old datatypes so we can always transmute to them unsafe { mem::transmute(bytes) } } diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index fe7ff2d9ede6a..54d79beca95ab 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -96,6 +96,7 @@ pub trait Add { macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_ops", issue = "90080")] impl const Add for $t { type Output = $t; diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index 6984100e498e8..deb54c8ba348e 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -493,7 +493,7 @@ macro_rules! shl_impl_all { )*) } -shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } +shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// The right shift operator `>>`. Note that because this trait is implemented /// for all integer types with multiple right-hand-side types, Rust's type diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index c8fcee5c140f5..0d910685927e0 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -79,7 +79,7 @@ use crate::{convert, ops}; /// [`Break`]: ControlFlow::Break /// [`Continue`]: ControlFlow::Continue #[stable(feature = "control_flow_enum_type", since = "1.55.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "ControlFlow")] +#[rustc_diagnostic_item = "ControlFlow"] // ControlFlow should not implement PartialOrd or Ord, per RFC 3058: // https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -229,6 +229,27 @@ impl ControlFlow { } } +impl ControlFlow { + /// Extracts the value `T` that is wrapped by `ControlFlow`. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_into_value)] + /// use std::ops::ControlFlow; + /// + /// assert_eq!(ControlFlow::::Break(1024).into_value(), 1024); + /// assert_eq!(ControlFlow::::Continue(512).into_value(), 512); + /// ``` + #[unstable(feature = "control_flow_into_value", issue = "137461")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] + pub const fn into_value(self) -> T { + match self { + ControlFlow::Continue(x) | ControlFlow::Break(x) => x, + } + } +} + /// These are used only as part of implementing the iterator adapters. /// They have mediocre names and non-obvious semantics, so aren't /// currently on a path to potential stabilization. diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index 11490ea2bfcb4..e74f5443ac2d8 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -150,6 +150,7 @@ pub trait Deref { } #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] impl const Deref for &T { type Target = T; @@ -163,6 +164,7 @@ impl const Deref for &T { impl !DerefMut for &T {} #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] impl const Deref for &mut T { type Target = T; @@ -273,6 +275,7 @@ pub trait DerefMut: ~const Deref { } #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] impl const DerefMut for &mut T { fn deref_mut(&mut self) -> &mut T { *self diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 5580faefacc0d..1935268cda891 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -771,13 +771,11 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// /// assert_eq!((..10).start_bound(), Unbounded); /// assert_eq!((3..10).start_bound(), Included(&3)); - /// # } /// ``` #[stable(feature = "collections_range", since = "1.28.0")] fn start_bound(&self) -> Bound<&T>; @@ -789,13 +787,11 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// /// assert_eq!((3..).end_bound(), Unbounded); /// assert_eq!((3..10).end_bound(), Excluded(&10)); - /// # } /// ``` #[stable(feature = "collections_range", since = "1.28.0")] fn end_bound(&self) -> Bound<&T>; @@ -829,6 +825,71 @@ pub trait RangeBounds { Unbounded => true, }) } + + /// Returns `true` if the range contains no items. + /// One-sided ranges (`RangeFrom`, etc) always return `false`. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_bounds_is_empty)] + /// use std::ops::RangeBounds; + /// + /// assert!(!(3..).is_empty()); + /// assert!(!(..2).is_empty()); + /// assert!(!RangeBounds::is_empty(&(3..5))); + /// assert!( RangeBounds::is_empty(&(3..3))); + /// assert!( RangeBounds::is_empty(&(3..2))); + /// ``` + /// + /// The range is empty if either side is incomparable: + /// + /// ``` + /// #![feature(range_bounds_is_empty)] + /// use std::ops::RangeBounds; + /// + /// assert!(!RangeBounds::is_empty(&(3.0..5.0))); + /// assert!( RangeBounds::is_empty(&(3.0..f32::NAN))); + /// assert!( RangeBounds::is_empty(&(f32::NAN..5.0))); + /// ``` + /// + /// But never empty is either side is unbounded: + /// + /// ``` + /// #![feature(range_bounds_is_empty)] + /// use std::ops::RangeBounds; + /// + /// assert!(!(..0).is_empty()); + /// assert!(!(i32::MAX..).is_empty()); + /// assert!(!RangeBounds::::is_empty(&(..))); + /// ``` + /// + /// `(Excluded(a), Excluded(b))` is only empty if `a >= b`: + /// + /// ``` + /// #![feature(range_bounds_is_empty)] + /// use std::ops::Bound::*; + /// use std::ops::RangeBounds; + /// + /// assert!(!(Excluded(1), Excluded(3)).is_empty()); + /// assert!(!(Excluded(1), Excluded(2)).is_empty()); + /// assert!( (Excluded(1), Excluded(1)).is_empty()); + /// assert!( (Excluded(2), Excluded(1)).is_empty()); + /// assert!( (Excluded(3), Excluded(1)).is_empty()); + /// ``` + #[unstable(feature = "range_bounds_is_empty", issue = "137300")] + fn is_empty(&self) -> bool + where + T: PartialOrd, + { + !match (self.start_bound(), self.end_bound()) { + (Unbounded, _) | (_, Unbounded) => true, + (Included(start), Excluded(end)) + | (Excluded(start), Included(end)) + | (Excluded(start), Excluded(end)) => start < end, + (Included(start), Included(end)) => start <= end, + } + } } /// Used to convert a range into start and end bounds, consuming the @@ -845,7 +906,6 @@ pub trait IntoBounds: RangeBounds { /// /// ``` /// #![feature(range_into_bounds)] - /// /// use std::ops::Bound::*; /// use std::ops::IntoBounds; /// @@ -853,6 +913,76 @@ pub trait IntoBounds: RangeBounds { /// assert_eq!((..=7).into_bounds(), (Unbounded, Included(7))); /// ``` fn into_bounds(self) -> (Bound, Bound); + + /// Compute the intersection of `self` and `other`. + /// + /// # Examples + /// + /// ``` + /// #![feature(range_into_bounds)] + /// use std::ops::Bound::*; + /// use std::ops::IntoBounds; + /// + /// assert_eq!((3..).intersect(..5), (Included(3), Excluded(5))); + /// assert_eq!((-12..387).intersect(0..256), (Included(0), Excluded(256))); + /// assert_eq!((1..5).intersect(..), (Included(1), Excluded(5))); + /// assert_eq!((1..=9).intersect(0..10), (Included(1), Included(9))); + /// assert_eq!((7..=13).intersect(8..13), (Included(8), Excluded(13))); + /// ``` + /// + /// Combine with `is_empty` to determine if two ranges overlap. + /// + /// ``` + /// #![feature(range_into_bounds)] + /// #![feature(range_bounds_is_empty)] + /// use std::ops::{RangeBounds, IntoBounds}; + /// + /// assert!(!(3..).intersect(..5).is_empty()); + /// assert!(!(-12..387).intersect(0..256).is_empty()); + /// assert!((1..5).intersect(6..).is_empty()); + /// ``` + fn intersect(self, other: R) -> (Bound, Bound) + where + Self: Sized, + T: Ord, + R: Sized + IntoBounds, + { + let (self_start, self_end) = IntoBounds::into_bounds(self); + let (other_start, other_end) = IntoBounds::into_bounds(other); + + let start = match (self_start, other_start) { + (Included(a), Included(b)) => Included(Ord::max(a, b)), + (Excluded(a), Excluded(b)) => Excluded(Ord::max(a, b)), + (Unbounded, Unbounded) => Unbounded, + + (x, Unbounded) | (Unbounded, x) => x, + + (Included(i), Excluded(e)) | (Excluded(e), Included(i)) => { + if i > e { + Included(i) + } else { + Excluded(e) + } + } + }; + let end = match (self_end, other_end) { + (Included(a), Included(b)) => Included(Ord::min(a, b)), + (Excluded(a), Excluded(b)) => Excluded(Ord::min(a, b)), + (Unbounded, Unbounded) => Unbounded, + + (x, Unbounded) | (Unbounded, x) => x, + + (Included(i), Excluded(e)) | (Excluded(e), Included(i)) => { + if i < e { + Included(i) + } else { + Excluded(e) + } + } + }; + + (start, end) + } } use self::Bound::{Excluded, Included, Unbounded}; diff --git a/library/core/src/option.rs b/library/core/src/option.rs index a9f06b92ad5dd..7ec0ac7127142 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -924,7 +924,7 @@ impl Option { #[inline] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "option_expect")] + #[rustc_diagnostic_item = "option_expect"] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] #[rustc_const_stable(feature = "const_option", since = "1.83.0")] pub const fn expect(self, msg: &str) -> T { @@ -969,7 +969,7 @@ impl Option { #[inline(always)] #[track_caller] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "option_unwrap")] + #[rustc_diagnostic_item = "option_unwrap"] #[rustc_allow_const_fn_unstable(const_precise_live_drops)] #[rustc_const_stable(feature = "const_option", since = "1.83.0")] pub const fn unwrap(self) -> T { @@ -2050,6 +2050,9 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl crate::clone::UseCloned for Option where T: crate::clone::UseCloned {} + #[stable(feature = "rust1", since = "1.0.0")] impl Default for Option { /// Returns [`None`][Option::None]. diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs index 37859212c0ee3..a60f0799c0eae 100644 --- a/library/core/src/panic/unwind_safe.rs +++ b/library/core/src/panic/unwind_safe.rs @@ -82,7 +82,7 @@ use crate::task::{Context, Poll}; /// [`AssertUnwindSafe`] wrapper struct can be used to force this trait to be /// implemented for any closed over variables passed to `catch_unwind`. #[stable(feature = "catch_unwind", since = "1.9.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "unwind_safe_trait")] +#[rustc_diagnostic_item = "unwind_safe_trait"] #[diagnostic::on_unimplemented( message = "the type `{Self}` may not be safely transferred across an unwind boundary", label = "`{Self}` may not be safely transferred across an unwind boundary" @@ -98,7 +98,7 @@ pub auto trait UnwindSafe {} /// This is a "helper marker trait" used to provide impl blocks for the /// [`UnwindSafe`] trait, for more information see that documentation. #[stable(feature = "catch_unwind", since = "1.9.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "ref_unwind_safe_trait")] +#[rustc_diagnostic_item = "ref_unwind_safe_trait"] #[diagnostic::on_unimplemented( message = "the type `{Self}` may contain interior mutability and a reference may not be safely \ transferrable across a catch_unwind boundary", diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index d36e677d21a18..33ad59916e391 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -294,7 +294,7 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -#[cfg_attr(not(bootstrap), lang = "panic_null_pointer_dereference")] // needed by codegen for panic on null pointer deref +#[lang = "panic_null_pointer_dereference"] // needed by codegen for panic on null pointer deref #[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind fn panic_null_pointer_dereference() -> ! { if cfg!(feature = "panic_immediate_abort") { diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs index 752e79c2dacee..f8826096df3e1 100644 --- a/library/core/src/pat.rs +++ b/library/core/src/pat.rs @@ -12,3 +12,65 @@ macro_rules! pattern_type { /* compiler built-in */ }; } + +/// A trait implemented for integer types and `char`. +/// Useful in the future for generic pattern types, but +/// used right now to simplify ast lowering of pattern type ranges. +#[unstable(feature = "pattern_type_range_trait", issue = "123646")] +#[rustc_const_unstable(feature = "pattern_type_range_trait", issue = "123646")] +#[const_trait] +#[diagnostic::on_unimplemented( + message = "`{Self}` is not a valid base type for range patterns", + label = "only integer types and `char` are supported" +)] +pub trait RangePattern { + /// Trait version of the inherent `MIN` assoc const. + #[cfg_attr(not(bootstrap), lang = "RangeMin")] + const MIN: Self; + + /// Trait version of the inherent `MIN` assoc const. + #[cfg_attr(not(bootstrap), lang = "RangeMax")] + const MAX: Self; + + /// A compile-time helper to subtract 1 for exclusive ranges. + #[cfg_attr(not(bootstrap), lang = "RangeSub")] + #[track_caller] + fn sub_one(self) -> Self; +} + +macro_rules! impl_range_pat { + ($($ty:ty,)*) => { + $( + #[rustc_const_unstable(feature = "pattern_type_range_trait", issue = "123646")] + impl const RangePattern for $ty { + const MIN: $ty = <$ty>::MIN; + const MAX: $ty = <$ty>::MAX; + fn sub_one(self) -> Self { + match self.checked_sub(1) { + Some(val) => val, + None => panic!("exclusive range end at minimum value of type") + } + } + } + )* + } +} + +impl_range_pat! { + i8, i16, i32, i64, i128, isize, + u8, u16, u32, u64, u128, usize, +} + +#[rustc_const_unstable(feature = "pattern_type_range_trait", issue = "123646")] +impl const RangePattern for char { + const MIN: Self = char::MIN; + + const MAX: Self = char::MAX; + + fn sub_one(self) -> Self { + match char::from_u32(self as u32 - 1) { + None => panic!("exclusive range to start of valid chars"), + Some(val) => val, + } + } +} diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 2a0bf89fcf7a9..7fcd19f67ee2d 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -1240,8 +1240,8 @@ impl Pin { /// points to is pinned, that is a violation of the API contract and may lead to undefined /// behavior in later (even safe) operations. /// - /// By using this method, you are also making a promise about the [`Deref`] and - /// [`DerefMut`] implementations of `Ptr`, if they exist. Most importantly, they + /// By using this method, you are also making a promise about the [`Deref`], + /// [`DerefMut`], and [`Drop`] implementations of `Ptr`, if they exist. Most importantly, they /// must not move out of their `self` arguments: `Pin::as_mut` and `Pin::as_ref` /// will call `DerefMut::deref_mut` and `Deref::deref` *on the pointer type `Ptr`* /// and expect these methods to uphold the pinning invariants. diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 590ffd64b5bff..8d867a269a21a 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -70,3 +70,26 @@ pub mod rust_2024 { #[doc(no_inline)] pub use crate::future::{Future, IntoFuture}; } + +/// The Future version of the core prelude. +/// +/// See the [module-level documentation](self) for more. +#[doc(hidden)] +#[unstable(feature = "prelude_future", issue = "none")] +pub mod rust_future { + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use super::v1::*; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::iter::FromIterator; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use crate::convert::{TryFrom, TryInto}; + + #[stable(feature = "prelude_2024", since = "1.85.0")] + #[doc(no_inline)] + pub use crate::future::{Future, IntoFuture}; +} diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 50fd67e839557..c5975c0305031 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -111,3 +111,11 @@ pub use crate::macros::builtin::type_ascribe; reason = "placeholder syntax for deref patterns" )] pub use crate::macros::builtin::deref; + +#[unstable( + feature = "type_alias_impl_trait", + issue = "63063", + reason = "`type_alias_impl_trait` has open design concerns" +)] +#[cfg(not(bootstrap))] +pub use crate::macros::builtin::define_opaque; diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index bbf5939fe1b05..89c856fe10746 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -398,12 +398,12 @@ mod prim_never {} /// let v = vec!['h', 'e', 'l', 'l', 'o']; /// /// // five elements times four bytes for each element -/// assert_eq!(20, v.len() * std::mem::size_of::()); +/// assert_eq!(20, v.len() * size_of::()); /// /// let s = String::from("hello"); /// /// // five elements times one byte per element -/// assert_eq!(5, s.len() * std::mem::size_of::()); +/// assert_eq!(5, s.len() * size_of::()); /// ``` /// /// [`String`]: ../std/string/struct.String.html @@ -443,8 +443,8 @@ mod prim_never {} /// let s = String::from("love: ❤️"); /// let v: Vec = s.chars().collect(); /// -/// assert_eq!(12, std::mem::size_of_val(&s[..])); -/// assert_eq!(32, std::mem::size_of_val(&v[..])); +/// assert_eq!(12, size_of_val(&s[..])); +/// assert_eq!(32, size_of_val(&v[..])); /// ``` #[stable(feature = "rust1", since = "1.0.0")] mod prim_char {} @@ -594,10 +594,8 @@ impl () {} /// #[allow(unused_extern_crates)] /// extern crate libc; /// -/// use std::mem; -/// /// unsafe { -/// let my_num: *mut i32 = libc::malloc(mem::size_of::()) as *mut i32; +/// let my_num: *mut i32 = libc::malloc(size_of::()) as *mut i32; /// if my_num.is_null() { /// panic!("failed to allocate memory"); /// } @@ -893,11 +891,11 @@ mod prim_array {} /// /// ``` /// # use std::rc::Rc; -/// let pointer_size = std::mem::size_of::<&u8>(); -/// assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>()); -/// assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>()); -/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); -/// assert_eq!(2 * pointer_size, std::mem::size_of::>()); +/// let pointer_size = size_of::<&u8>(); +/// assert_eq!(2 * pointer_size, size_of::<&[u8]>()); +/// assert_eq!(2 * pointer_size, size_of::<*const [u8]>()); +/// assert_eq!(2 * pointer_size, size_of::>()); +/// assert_eq!(2 * pointer_size, size_of::>()); /// ``` /// /// ## Trait Implementations @@ -1692,15 +1690,13 @@ mod prim_ref {} /// This zero-sized type *coerces* to a regular function pointer. For example: /// /// ```rust -/// use std::mem; -/// /// fn bar(x: i32) {} /// /// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar` -/// assert_eq!(mem::size_of_val(¬_bar_ptr), 0); +/// assert_eq!(size_of_val(¬_bar_ptr), 0); /// /// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer -/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::()); +/// assert_eq!(size_of_val(&bar_ptr), size_of::()); /// /// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar` /// ``` diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index 2da94e72566e9..19311e39b454e 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -13,8 +13,8 @@ use crate::{cmp, fmt, hash, mem, num}; pub struct Alignment(AlignmentEnum); // Alignment is `repr(usize)`, but via extra steps. -const _: () = assert!(mem::size_of::() == mem::size_of::()); -const _: () = assert!(mem::align_of::() == mem::align_of::()); +const _: () = assert!(size_of::() == size_of::()); +const _: () = assert!(align_of::() == align_of::()); fn _alignment_can_be_structurally_matched(a: Alignment) -> bool { matches!(a, Alignment::MIN) @@ -38,14 +38,14 @@ impl Alignment { /// Returns the alignment for a type. /// - /// This provides the same numerical value as [`mem::align_of`], + /// This provides the same numerical value as [`align_of`], /// but in an `Alignment` instead of a `usize`. #[unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] #[must_use] pub const fn of() -> Self { // This can't actually panic since type alignment is always a power of two. - const { Alignment::new(mem::align_of::()).unwrap() } + const { Alignment::new(align_of::()).unwrap() } } /// Creates an `Alignment` from a `usize`, or returns `None` if it's diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 974946a7818d7..7d0839aff3f73 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -1,7 +1,7 @@ use super::*; use crate::cmp::Ordering::{Equal, Greater, Less}; use crate::intrinsics::const_eval_select; -use crate::mem::SizedTypeProperties; +use crate::mem::{self, SizedTypeProperties}; use crate::slice::{self, SliceIndex}; impl *const T { @@ -193,7 +193,6 @@ impl *const T { /// This is an [Exposed Provenance][crate::ptr#exposed-provenance] API. /// /// [`with_exposed_provenance`]: with_exposed_provenance - #[must_use] #[inline(always)] #[stable(feature = "exposed_provenance", since = "1.84.0")] pub fn expose_provenance(self) -> usize { @@ -595,9 +594,9 @@ impl *const T { } /// Calculates the distance between two pointers within the same allocation. The returned value is in - /// units of T: the distance in bytes divided by `mem::size_of::()`. + /// units of T: the distance in bytes divided by `size_of::()`. /// - /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::() as isize)`, + /// This is equivalent to `(self as isize - origin as isize) / (size_of::() as isize)`, /// except that it has a lot more opportunities for UB, in exchange for the compiler /// better understanding what you are doing. /// @@ -633,7 +632,7 @@ impl *const T { /// objects is not known at compile-time. However, the requirement also exists at /// runtime and may be exploited by optimizations. If you wish to compute the difference between /// pointers that are not guaranteed to be from the same allocation, use `(self as isize - - /// origin as isize) / mem::size_of::()`. + /// origin as isize) / size_of::()`. // FIXME: recommend `addr()` instead of `as usize` once that is stable. /// /// [`add`]: #method.add @@ -683,7 +682,7 @@ impl *const T { where T: Sized, { - let pointee_size = mem::size_of::(); + let pointee_size = size_of::(); assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); // SAFETY: the caller must uphold the safety contract for `ptr_offset_from`. unsafe { intrinsics::ptr_offset_from(self, origin) } @@ -709,7 +708,7 @@ impl *const T { /// Calculates the distance between two pointers within the same allocation, *where it's known that /// `self` is equal to or greater than `origin`*. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// units of T: the distance in bytes is divided by `size_of::()`. /// /// This computes the same value that [`offset_from`](#method.offset_from) /// would compute, but with the added precondition that the offset is @@ -723,9 +722,8 @@ impl *const T { /// to [`sub`](#method.sub)). The following are all equivalent, assuming /// that their safety preconditions are met: /// ```rust - /// # #![feature(ptr_sub_ptr)] /// # unsafe fn blah(ptr: *const i32, origin: *const i32, count: usize) -> bool { unsafe { - /// ptr.sub_ptr(origin) == count + /// ptr.offset_from_unsigned(origin) == count /// # && /// origin.add(count) == ptr /// # && @@ -752,26 +750,24 @@ impl *const T { /// # Examples /// /// ``` - /// #![feature(ptr_sub_ptr)] - /// /// let a = [0; 5]; /// let ptr1: *const i32 = &a[1]; /// let ptr2: *const i32 = &a[3]; /// unsafe { - /// assert_eq!(ptr2.sub_ptr(ptr1), 2); + /// assert_eq!(ptr2.offset_from_unsigned(ptr1), 2); /// assert_eq!(ptr1.add(2), ptr2); /// assert_eq!(ptr2.sub(2), ptr1); - /// assert_eq!(ptr2.sub_ptr(ptr2), 0); + /// assert_eq!(ptr2.offset_from_unsigned(ptr2), 0); /// } /// /// // This would be incorrect, as the pointers are not correctly ordered: - /// // ptr1.sub_ptr(ptr2) + /// // ptr1.offset_from_unsigned(ptr2) /// ``` - #[unstable(feature = "ptr_sub_ptr", issue = "95892")] - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub const unsafe fn sub_ptr(self, origin: *const T) -> usize + pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, { @@ -789,14 +785,14 @@ impl *const T { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::sub_ptr requires `self >= origin`", + "ptr::offset_from_unsigned requires `self >= origin`", ( this: *const () = self as *const (), origin: *const () = origin as *const (), ) => runtime_ptr_ge(this, origin) ); - let pointee_size = mem::size_of::(); + let pointee_size = size_of::(); assert!(0 < pointee_size && pointee_size <= isize::MAX as usize); // SAFETY: the caller must uphold the safety contract for `ptr_offset_from_unsigned`. unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } @@ -807,18 +803,18 @@ impl *const T { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`sub_ptr`][pointer::sub_ptr] on it. See that method for + /// using [`sub_ptr`][pointer::offset_from_unsigned] on it. See that method for /// documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. - #[unstable(feature = "ptr_sub_ptr", issue = "95892")] - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub const unsafe fn byte_sub_ptr(self, origin: *const U) -> usize { + pub const unsafe fn byte_offset_from_unsigned(self, origin: *const U) -> usize { // SAFETY: the caller must uphold the safety contract for `sub_ptr`. - unsafe { self.cast::().sub_ptr(origin.cast::()) } + unsafe { self.cast::().offset_from_unsigned(origin.cast::()) } } /// Returns whether two pointers are guaranteed to be equal. @@ -1316,7 +1312,7 @@ impl *const T { unsafe { read_unaligned(self) } } - /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// Copies `count * size_of::()` bytes from `self` to `dest`. The source /// and destination may overlap. /// /// NOTE: this has the *same* argument order as [`ptr::copy`]. @@ -1336,7 +1332,7 @@ impl *const T { unsafe { copy(self, dest, count) } } - /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// Copies `count * size_of::()` bytes from `self` to `dest`. The source /// and destination may *not* overlap. /// /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. @@ -1378,8 +1374,6 @@ impl *const T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// use std::mem::align_of; - /// /// # unsafe { /// let x = [5_u8, 6, 7, 8, 9]; /// let ptr = x.as_ptr(); @@ -1439,7 +1433,7 @@ impl *const T { where T: Sized, { - self.is_aligned_to(mem::align_of::()) + self.is_aligned_to(align_of::()) } /// Returns whether the pointer is aligned to `align`. @@ -1598,7 +1592,7 @@ impl *const [T] { /// When calling this method, you have to ensure that *either* the pointer is null *or* /// all of the following is true: /// - /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::()` many bytes, + /// * The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single [allocated object]! @@ -1610,7 +1604,7 @@ impl *const [T] { /// them from other data. You can obtain a pointer that is usable as `data` /// for zero-length slices using [`NonNull::dangling()`]. /// - /// * The total size `ptr.len() * mem::size_of::()` of the slice must be no larger than `isize::MAX`. + /// * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 9eee29d485f41..4870750638957 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -74,7 +74,7 @@ pub trait Pointee { /// #![feature(ptr_metadata)] /// /// fn this_never_panics() { -/// assert_eq!(std::mem::size_of::<&T>(), std::mem::size_of::()) +/// assert_eq!(size_of::<&T>(), size_of::()) /// } /// ``` #[unstable(feature = "ptr_metadata", issue = "81513")] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index eb99be817a2ca..ea53da78d3bd2 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -48,7 +48,7 @@ //! //! Valid raw pointers as defined above are not necessarily properly aligned (where //! "proper" alignment is defined by the pointee type, i.e., `*const T` must be -//! aligned to `mem::align_of::()`). However, most functions require their +//! aligned to `align_of::()`). However, most functions require their //! arguments to be properly aligned, and will explicitly state //! this requirement in their documentation. Notable exceptions to this are //! [`read_unaligned`] and [`write_unaligned`]. @@ -297,7 +297,7 @@ //! //! // Our value, which must have enough alignment to have spare least-significant-bits. //! let my_precious_data: u32 = 17; -//! assert!(core::mem::align_of::() > 1); +//! assert!(align_of::() > 1); //! //! // Create a tagged pointer //! let ptr = &my_precious_data as *const u32; @@ -1098,12 +1098,12 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { } else { macro_rules! attempt_swap_as_chunks { ($ChunkTy:ty) => { - if mem::align_of::() >= mem::align_of::<$ChunkTy>() - && mem::size_of::() % mem::size_of::<$ChunkTy>() == 0 + if align_of::() >= align_of::<$ChunkTy>() + && size_of::() % size_of::<$ChunkTy>() == 0 { let x: *mut $ChunkTy = x.cast(); let y: *mut $ChunkTy = y.cast(); - let count = count * (mem::size_of::() / mem::size_of::<$ChunkTy>()); + let count = count * (size_of::() / size_of::<$ChunkTy>()); // SAFETY: these are the same bytes that the caller promised were // ok, just typed as `MaybeUninit`s instead of as `T`s. // The `if` condition above ensures that we're not violating @@ -1117,9 +1117,9 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { // Split up the slice into small power-of-two-sized chunks that LLVM is able // to vectorize (unless it's a special type with more-than-pointer alignment, // because we don't want to pessimize things like slices of SIMD vectors.) - if mem::align_of::() <= mem::size_of::() - && (!mem::size_of::().is_power_of_two() - || mem::size_of::() > mem::size_of::() * 2) + if align_of::() <= size_of::() + && (!size_of::().is_power_of_two() + || size_of::() > size_of::() * 2) { attempt_swap_as_chunks!(usize); attempt_swap_as_chunks!(u8); @@ -1443,10 +1443,8 @@ pub const unsafe fn read(src: *const T) -> T { /// Read a `usize` value from a byte buffer: /// /// ``` -/// use std::mem; -/// /// fn read_usize(x: &[u8]) -> usize { -/// assert!(x.len() >= mem::size_of::()); +/// assert!(x.len() >= size_of::()); /// /// let ptr = x.as_ptr() as *const usize; /// @@ -1467,7 +1465,7 @@ pub const unsafe fn read_unaligned(src: *const T) -> T { // Also, since we just wrote a valid value into `tmp`, it is guaranteed // to be properly initialized. unsafe { - copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, mem::size_of::()); + copy_nonoverlapping(src as *const u8, tmp.as_mut_ptr() as *mut u8, size_of::()); tmp.assume_init() } } @@ -1647,10 +1645,8 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// Write a `usize` value to a byte buffer: /// /// ``` -/// use std::mem; -/// /// fn write_usize(x: &mut [u8], val: usize) { -/// assert!(x.len() >= mem::size_of::()); +/// assert!(x.len() >= size_of::()); /// /// let ptr = x.as_mut_ptr() as *mut usize; /// @@ -1667,7 +1663,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { - copy_nonoverlapping((&raw const src) as *const u8, dst as *mut u8, mem::size_of::()); + copy_nonoverlapping((&raw const src) as *const u8, dst as *mut u8, size_of::()); // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } @@ -1911,7 +1907,7 @@ pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { inverse & m_minus_one } - let stride = mem::size_of::(); + let stride = size_of::(); let addr: usize = p.addr(); diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 94ebd0d2522ee..b960a3d86bef0 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1,7 +1,7 @@ use super::*; use crate::cmp::Ordering::{Equal, Greater, Less}; use crate::intrinsics::const_eval_select; -use crate::mem::SizedTypeProperties; +use crate::mem::{self, SizedTypeProperties}; use crate::slice::{self, SliceIndex}; impl *mut T { @@ -769,9 +769,9 @@ impl *mut T { } /// Calculates the distance between two pointers within the same allocation. The returned value is in - /// units of T: the distance in bytes divided by `mem::size_of::()`. + /// units of T: the distance in bytes divided by `size_of::()`. /// - /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::() as isize)`, + /// This is equivalent to `(self as isize - origin as isize) / (size_of::() as isize)`, /// except that it has a lot more opportunities for UB, in exchange for the compiler /// better understanding what you are doing. /// @@ -807,7 +807,7 @@ impl *mut T { /// objects is not known at compile-time. However, the requirement also exists at /// runtime and may be exploited by optimizations. If you wish to compute the difference between /// pointers that are not guaranteed to be from the same allocation, use `(self as isize - - /// origin as isize) / mem::size_of::()`. + /// origin as isize) / size_of::()`. // FIXME: recommend `addr()` instead of `as usize` once that is stable. /// /// [`add`]: #method.add @@ -881,7 +881,7 @@ impl *mut T { /// Calculates the distance between two pointers within the same allocation, *where it's known that /// `self` is equal to or greater than `origin`*. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// units of T: the distance in bytes is divided by `size_of::()`. /// /// This computes the same value that [`offset_from`](#method.offset_from) /// would compute, but with the added precondition that the offset is @@ -895,9 +895,8 @@ impl *mut T { /// to [`sub`](#method.sub)). The following are all equivalent, assuming /// that their safety preconditions are met: /// ```rust - /// # #![feature(ptr_sub_ptr)] /// # unsafe fn blah(ptr: *mut i32, origin: *mut i32, count: usize) -> bool { unsafe { - /// ptr.sub_ptr(origin) == count + /// ptr.offset_from_unsigned(origin) == count /// # && /// origin.add(count) == ptr /// # && @@ -924,32 +923,30 @@ impl *mut T { /// # Examples /// /// ``` - /// #![feature(ptr_sub_ptr)] - /// /// let mut a = [0; 5]; /// let p: *mut i32 = a.as_mut_ptr(); /// unsafe { /// let ptr1: *mut i32 = p.add(1); /// let ptr2: *mut i32 = p.add(3); /// - /// assert_eq!(ptr2.sub_ptr(ptr1), 2); + /// assert_eq!(ptr2.offset_from_unsigned(ptr1), 2); /// assert_eq!(ptr1.add(2), ptr2); /// assert_eq!(ptr2.sub(2), ptr1); - /// assert_eq!(ptr2.sub_ptr(ptr2), 0); + /// assert_eq!(ptr2.offset_from_unsigned(ptr2), 0); /// } /// /// // This would be incorrect, as the pointers are not correctly ordered: /// // ptr1.offset_from(ptr2) - #[unstable(feature = "ptr_sub_ptr", issue = "95892")] - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub const unsafe fn sub_ptr(self, origin: *const T) -> usize + pub const unsafe fn offset_from_unsigned(self, origin: *const T) -> usize where T: Sized, { // SAFETY: the caller must uphold the safety contract for `sub_ptr`. - unsafe { (self as *const T).sub_ptr(origin) } + unsafe { (self as *const T).offset_from_unsigned(origin) } } /// Calculates the distance between two pointers within the same allocation, *where it's known that @@ -957,18 +954,18 @@ impl *mut T { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`sub_ptr`][pointer::sub_ptr] on it. See that method for + /// using [`sub_ptr`][pointer::offset_from_unsigned] on it. See that method for /// documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. - #[unstable(feature = "ptr_sub_ptr", issue = "95892")] - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - pub const unsafe fn byte_sub_ptr(self, origin: *mut U) -> usize { + pub const unsafe fn byte_offset_from_unsigned(self, origin: *mut U) -> usize { // SAFETY: the caller must uphold the safety contract for `byte_sub_ptr`. - unsafe { (self as *const T).byte_sub_ptr(origin) } + unsafe { (self as *const T).byte_offset_from_unsigned(origin) } } /// Adds an unsigned offset to a pointer. @@ -1400,7 +1397,7 @@ impl *mut T { unsafe { read_unaligned(self) } } - /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// Copies `count * size_of::()` bytes from `self` to `dest`. The source /// and destination may overlap. /// /// NOTE: this has the *same* argument order as [`ptr::copy`]. @@ -1420,7 +1417,7 @@ impl *mut T { unsafe { copy(self, dest, count) } } - /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// Copies `count * size_of::()` bytes from `self` to `dest`. The source /// and destination may *not* overlap. /// /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. @@ -1440,7 +1437,7 @@ impl *mut T { unsafe { copy_nonoverlapping(self, dest, count) } } - /// Copies `count * size_of` bytes from `src` to `self`. The source + /// Copies `count * size_of::()` bytes from `src` to `self`. The source /// and destination may overlap. /// /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. @@ -1460,7 +1457,7 @@ impl *mut T { unsafe { copy(src, self, count) } } - /// Copies `count * size_of` bytes from `src` to `self`. The source + /// Copies `count * size_of::()` bytes from `src` to `self`. The source /// and destination may *not* overlap. /// /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. @@ -1626,8 +1623,6 @@ impl *mut T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// use std::mem::align_of; - /// /// # unsafe { /// let mut x = [5_u8, 6, 7, 8, 9]; /// let ptr = x.as_mut_ptr(); @@ -1692,7 +1687,7 @@ impl *mut T { where T: Sized, { - self.is_aligned_to(mem::align_of::()) + self.is_aligned_to(align_of::()) } /// Returns whether the pointer is aligned to `align`. @@ -1953,7 +1948,7 @@ impl *mut [T] { /// When calling this method, you have to ensure that *either* the pointer is null *or* /// all of the following is true: /// - /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::()` many bytes, + /// * The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single [allocated object]! @@ -1965,7 +1960,7 @@ impl *mut [T] { /// them from other data. You can obtain a pointer that is usable as `data` /// for zero-length slices using [`NonNull::dangling()`]. /// - /// * The total size `ptr.len() * mem::size_of::()` of the slice must be no larger than `isize::MAX`. + /// * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is @@ -2011,7 +2006,7 @@ impl *mut [T] { /// When calling this method, you have to ensure that *either* the pointer is null *or* /// all of the following is true: /// - /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::()` + /// * The pointer must be [valid] for reads and writes for `ptr.len() * size_of::()` /// many bytes, and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single [allocated object]! @@ -2023,7 +2018,7 @@ impl *mut [T] { /// them from other data. You can obtain a pointer that is usable as `data` /// for zero-length slices using [`NonNull::dangling()`]. /// - /// * The total size `ptr.len() * mem::size_of::()` of the slice must be no larger than `isize::MAX`. + /// * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index f4ac00062d733..c769ba673c61e 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -49,7 +49,6 @@ use crate::{fmt, hash, intrinsics, mem, ptr}; /// are guaranteed to have the same size and alignment: /// /// ``` -/// # use std::mem::{size_of, align_of}; /// use std::ptr::NonNull; /// /// assert_eq!(size_of::>(), size_of::>>()); @@ -724,9 +723,9 @@ impl NonNull { } /// Calculates the distance between two pointers within the same allocation. The returned value is in - /// units of T: the distance in bytes divided by `mem::size_of::()`. + /// units of T: the distance in bytes divided by `size_of::()`. /// - /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::() as isize)`, + /// This is equivalent to `(self as isize - origin as isize) / (size_of::() as isize)`, /// except that it has a lot more opportunities for UB, in exchange for the compiler /// better understanding what you are doing. /// @@ -762,7 +761,7 @@ impl NonNull { /// objects is not known at compile-time. However, the requirement also exists at /// runtime and may be exploited by optimizations. If you wish to compute the difference between /// pointers that are not guaranteed to be from the same allocation, use `(self as isize - - /// origin as isize) / mem::size_of::()`. + /// origin as isize) / size_of::()`. // FIXME: recommend `addr()` instead of `as usize` once that is stable. /// /// [`add`]: #method.add @@ -842,7 +841,7 @@ impl NonNull { /// Calculates the distance between two pointers within the same allocation, *where it's known that /// `self` is equal to or greater than `origin`*. The returned value is in - /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// units of T: the distance in bytes is divided by `size_of::()`. /// /// This computes the same value that [`offset_from`](#method.offset_from) /// would compute, but with the added precondition that the offset is @@ -856,9 +855,8 @@ impl NonNull { /// to [`sub`](#method.sub)). The following are all equivalent, assuming /// that their safety preconditions are met: /// ```rust - /// # #![feature(ptr_sub_ptr)] /// # unsafe fn blah(ptr: std::ptr::NonNull, origin: std::ptr::NonNull, count: usize) -> bool { unsafe { - /// ptr.sub_ptr(origin) == count + /// ptr.offset_from_unsigned(origin) == count /// # && /// origin.add(count) == ptr /// # && @@ -885,32 +883,31 @@ impl NonNull { /// # Examples /// /// ``` - /// #![feature(ptr_sub_ptr)] /// use std::ptr::NonNull; /// /// let a = [0; 5]; /// let ptr1: NonNull = NonNull::from(&a[1]); /// let ptr2: NonNull = NonNull::from(&a[3]); /// unsafe { - /// assert_eq!(ptr2.sub_ptr(ptr1), 2); + /// assert_eq!(ptr2.offset_from_unsigned(ptr1), 2); /// assert_eq!(ptr1.add(2), ptr2); /// assert_eq!(ptr2.sub(2), ptr1); - /// assert_eq!(ptr2.sub_ptr(ptr2), 0); + /// assert_eq!(ptr2.offset_from_unsigned(ptr2), 0); /// } /// /// // This would be incorrect, as the pointers are not correctly ordered: - /// // ptr1.sub_ptr(ptr2) + /// // ptr1.offset_from_unsigned(ptr2) /// ``` #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[unstable(feature = "ptr_sub_ptr", issue = "95892")] - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] - pub const unsafe fn sub_ptr(self, subtracted: NonNull) -> usize + #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + pub const unsafe fn offset_from_unsigned(self, subtracted: NonNull) -> usize where T: Sized, { // SAFETY: the caller must uphold the safety contract for `sub_ptr`. - unsafe { self.as_ptr().sub_ptr(subtracted.as_ptr()) } + unsafe { self.as_ptr().offset_from_unsigned(subtracted.as_ptr()) } } /// Calculates the distance between two pointers within the same allocation, *where it's known that @@ -918,18 +915,18 @@ impl NonNull { /// units of **bytes**. /// /// This is purely a convenience for casting to a `u8` pointer and - /// using [`sub_ptr`][NonNull::sub_ptr] on it. See that method for + /// using [`sub_ptr`][NonNull::offset_from_unsigned] on it. See that method for /// documentation and safety requirements. /// /// For non-`Sized` pointees this operation considers only the data pointers, /// ignoring the metadata. #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[unstable(feature = "ptr_sub_ptr", issue = "95892")] - #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] - pub const unsafe fn byte_sub_ptr(self, origin: NonNull) -> usize { + #[stable(feature = "ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_ptr_sub_ptr", since = "CURRENT_RUSTC_VERSION")] + pub const unsafe fn byte_offset_from_unsigned(self, origin: NonNull) -> usize { // SAFETY: the caller must uphold the safety contract for `byte_sub_ptr`. - unsafe { self.as_ptr().byte_sub_ptr(origin.as_ptr()) } + unsafe { self.as_ptr().byte_offset_from_unsigned(origin.as_ptr()) } } /// Reads the value from `self` without moving it. This leaves the @@ -991,7 +988,7 @@ impl NonNull { unsafe { ptr::read_unaligned(self.as_ptr()) } } - /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// Copies `count * size_of::()` bytes from `self` to `dest`. The source /// and destination may overlap. /// /// NOTE: this has the *same* argument order as [`ptr::copy`]. @@ -1011,7 +1008,7 @@ impl NonNull { unsafe { ptr::copy(self.as_ptr(), dest.as_ptr(), count) } } - /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// Copies `count * size_of::()` bytes from `self` to `dest`. The source /// and destination may *not* overlap. /// /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. @@ -1031,7 +1028,7 @@ impl NonNull { unsafe { ptr::copy_nonoverlapping(self.as_ptr(), dest.as_ptr(), count) } } - /// Copies `count * size_of` bytes from `src` to `self`. The source + /// Copies `count * size_of::()` bytes from `src` to `self`. The source /// and destination may overlap. /// /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. @@ -1051,7 +1048,7 @@ impl NonNull { unsafe { ptr::copy(src.as_ptr(), self.as_ptr(), count) } } - /// Copies `count * size_of` bytes from `src` to `self`. The source + /// Copies `count * size_of::()` bytes from `src` to `self`. The source /// and destination may *not* overlap. /// /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. @@ -1225,7 +1222,6 @@ impl NonNull { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// use std::mem::align_of; /// use std::ptr::NonNull; /// /// # unsafe { @@ -1445,7 +1441,7 @@ impl NonNull<[T]> { /// /// When calling this method, you have to ensure that all of the following is true: /// - /// * The pointer must be [valid] for reads for `ptr.len() * mem::size_of::()` many bytes, + /// * The pointer must be [valid] for reads for `ptr.len() * size_of::()` many bytes, /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! @@ -1457,7 +1453,7 @@ impl NonNull<[T]> { /// them from other data. You can obtain a pointer that is usable as `data` /// for zero-length slices using [`NonNull::dangling()`]. /// - /// * The total size `ptr.len() * mem::size_of::()` of the slice must be no larger than `isize::MAX`. + /// * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is @@ -1490,7 +1486,7 @@ impl NonNull<[T]> { /// /// When calling this method, you have to ensure that all of the following is true: /// - /// * The pointer must be [valid] for reads and writes for `ptr.len() * mem::size_of::()` + /// * The pointer must be [valid] for reads and writes for `ptr.len() * size_of::()` /// many bytes, and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! @@ -1502,7 +1498,7 @@ impl NonNull<[T]> { /// them from other data. You can obtain a pointer that is usable as `data` /// for zero-length slices using [`NonNull::dangling()`]. /// - /// * The total size `ptr.len() * mem::size_of::()` of the slice must be no larger than `isize::MAX`. + /// * The total size `ptr.len() * size_of::()` of the slice must be no larger than `isize::MAX`. /// See the safety documentation of [`pointer::offset`]. /// /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is diff --git a/library/core/src/range.rs b/library/core/src/range.rs index e94499065ac9a..2276112a27bb3 100644 --- a/library/core/src/range.rs +++ b/library/core/src/range.rs @@ -50,7 +50,7 @@ pub use crate::ops::{ /// assert_eq!(Range::from(3..5), Range { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, Range::from(3..6).into_iter().sum()); /// ``` -#[cfg_attr(not(bootstrap), lang = "RangeCopy")] +#[lang = "RangeCopy"] #[derive(Clone, Copy, Default, PartialEq, Eq, Hash)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct Range { @@ -216,7 +216,7 @@ impl From> for Range { /// assert_eq!(RangeInclusive::from(3..=5), RangeInclusive { start: 3, end: 5 }); /// assert_eq!(3 + 4 + 5, RangeInclusive::from(3..=5).into_iter().sum()); /// ``` -#[cfg_attr(not(bootstrap), lang = "RangeInclusiveCopy")] +#[lang = "RangeInclusiveCopy"] #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct RangeInclusive { @@ -408,7 +408,7 @@ impl From> for RangeInclusive { /// assert_eq!(RangeFrom::from(2..), core::range::RangeFrom { start: 2 }); /// assert_eq!(2 + 3 + 4, RangeFrom::from(2..).into_iter().take(3).sum()); /// ``` -#[cfg_attr(not(bootstrap), lang = "RangeFromCopy")] +#[lang = "RangeFromCopy"] #[derive(Clone, Copy, PartialEq, Eq, Hash)] #[unstable(feature = "new_range_api", issue = "125687")] pub struct RangeFrom { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 92b5cba153166..48ab9267f216c 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -654,7 +654,7 @@ impl Result { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "result_ok_method")] + #[rustc_diagnostic_item = "result_ok_method"] pub fn ok(self) -> Option { match self { Ok(x) => Some(x), @@ -1744,6 +1744,14 @@ where } } +#[unstable(feature = "ergonomic_clones", issue = "132290")] +impl crate::clone::UseCloned for Result +where + T: crate::clone::UseCloned, + E: crate::clone::UseCloned, +{ +} + #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for Result { type Item = T; diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 51b25fa40e3d9..91befdb8c78d9 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -7,7 +7,6 @@ use crate::fmt::{self, Write}; use crate::intrinsics::const_eval_select; use crate::{ascii, iter, ops}; -#[cfg(not(test))] impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs index 9cb00644e6442..804bdfcbb4fc7 100644 --- a/library/core/src/slice/cmp.rs +++ b/library/core/src/slice/cmp.rs @@ -1,10 +1,10 @@ //! Comparison traits for `[T]`. use super::{from_raw_parts, memchr}; +use crate::ascii; use crate::cmp::{self, BytewiseEq, Ordering}; use crate::intrinsics::compare_bytes; use crate::num::NonZero; -use crate::{ascii, mem}; #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq<[U]> for [T] @@ -87,7 +87,7 @@ where // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. // The two slices have been checked to have the same size above. unsafe { - let size = mem::size_of_val(self); + let size = size_of_val(self); compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 } } @@ -266,7 +266,7 @@ macro_rules! impl_slice_contains { fn slice_contains(&self, arr: &[$t]) -> bool { // Make our LANE_COUNT 4x the normal lane count (aiming for 128 bit vectors). // The compiler will nicely unroll it. - const LANE_COUNT: usize = 4 * (128 / (mem::size_of::<$t>() * 8)); + const LANE_COUNT: usize = 4 * (128 / (size_of::<$t>() * 8)); // SIMD let mut chunks = arr.chunks_exact(LANE_COUNT); for chunk in &mut chunks { diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index b1456a1bc1da8..7c1ed3fe8a246 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -54,7 +54,7 @@ macro_rules! len { // To get rid of some bounds checks (see `position`), we use ptr_sub instead of // offset_from (Tested by `codegen/slice-position-bounds-check`.) // SAFETY: by the type invariant pointers are aligned and `start <= end` - unsafe { end.sub_ptr($self.ptr) } + unsafe { end.offset_from_unsigned($self.ptr) } }, ) }}; diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index 98db7aaf53321..1e1053583a617 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -2,11 +2,10 @@ // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch use crate::intrinsics::const_eval_select; -use crate::mem; const LO_USIZE: usize = usize::repeat_u8(0x01); const HI_USIZE: usize = usize::repeat_u8(0x80); -const USIZE_BYTES: usize = mem::size_of::(); +const USIZE_BYTES: usize = size_of::(); /// Returns `true` if `x` contains any zero byte. /// @@ -138,7 +137,7 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { // offset is always aligned, so just testing `>` is sufficient and avoids possible // overflow. let repeated_x = usize::repeat_u8(x); - let chunk_bytes = mem::size_of::(); + let chunk_bytes = size_of::(); while offset > min_aligned_offset { // SAFETY: offset starts at len - suffix.len(), as long as it is greater than diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 7b9a76e814a15..2c699ee9fdd4c 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -78,7 +78,7 @@ pub use raw::{from_raw_parts, from_raw_parts_mut}; /// Calculates the direction and split point of a one-sided range. /// -/// This is a helper function for `take` and `take_mut` that returns +/// This is a helper function for `split_off` and `split_off_mut` that returns /// the direction of the split (front or back) as well as the index at /// which to split. Returns `None` if the split index would overflow. #[inline] @@ -97,7 +97,6 @@ enum Direction { Back, } -#[cfg(not(test))] impl [T] { /// Returns the number of elements in the slice. /// @@ -956,7 +955,6 @@ impl [T] { /// [`swap`]: slice::swap /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html #[unstable(feature = "slice_swap_unchecked", issue = "88539")] - #[rustc_const_unstable(feature = "slice_swap_unchecked", issue = "88539")] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { assert_unsafe_precondition!( check_library_ub, @@ -1046,7 +1044,7 @@ impl [T] { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[cfg_attr(not(test), rustc_diagnostic_item = "slice_iter")] + #[rustc_diagnostic_item = "slice_iter"] pub fn iter(&self) -> Iter<'_, T> { Iter::new(self) } @@ -2928,10 +2926,17 @@ impl [T] { /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `T` panics. + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics. /// /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the @@ -2954,7 +2959,8 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation panics. /// /// # Examples /// @@ -2982,15 +2988,17 @@ impl [T] { /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// If the comparison function `compare` does not implement a [total order] the resulting order - /// of elements in the slice is unspecified. All original elements will remain in the slice and - /// any possible modifications via interior mutability are observed in the input. Same is true - /// if `compare` panics. + /// If the comparison function `compare` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and /// examples see the [`Ord`] documentation. /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if `compare` panics. + /// /// # Current implementation /// /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which @@ -3003,7 +3011,8 @@ impl [T] { /// /// # Panics /// - /// May panic if `compare` does not implement a [total order]. + /// May panic if the `compare` does not implement a [total order], or if + /// the `compare` itself panics. /// /// # Examples /// @@ -3034,10 +3043,16 @@ impl [T] { /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not /// allocate), and *O*(*n* \* log(*n*)) worst-case. /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. + /// + /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor + /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and + /// examples see the [`Ord`] documentation. + /// + /// All original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics. /// /// # Current implementation /// @@ -3051,7 +3066,8 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. /// /// # Examples /// @@ -3715,7 +3731,7 @@ impl [T] { #[doc(alias = "memcpy")] #[inline] #[stable(feature = "copy_from_slice", since = "1.9.0")] - #[rustc_const_unstable(feature = "const_copy_from_slice", issue = "131415")] + #[rustc_const_stable(feature = "const_copy_from_slice", since = "CURRENT_RUSTC_VERSION")] #[track_caller] pub const fn copy_from_slice(&mut self, src: &[T]) where @@ -3876,9 +3892,9 @@ impl [T] { // Explicitly wrap the function call in a const block so it gets // constant-evaluated even in debug mode. - let gcd: usize = const { gcd(mem::size_of::(), mem::size_of::()) }; - let ts: usize = mem::size_of::() / gcd; - let us: usize = mem::size_of::() / gcd; + let gcd: usize = const { gcd(size_of::(), size_of::()) }; + let ts: usize = size_of::() / gcd; + let us: usize = size_of::() / gcd; // Armed with this knowledge, we can find how many `U`s we can fit! let us_len = self.len() / ts * us; @@ -3928,7 +3944,7 @@ impl [T] { // ptr.align_offset. let ptr = self.as_ptr(); // SAFETY: See the `align_to_mut` method for the detailed safety comment. - let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::()) }; + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; if offset > self.len() { (self, &[], &[]) } else { @@ -3938,7 +3954,7 @@ impl [T] { #[cfg(miri)] crate::intrinsics::miri_promise_symbolic_alignment( rest.as_ptr().cast(), - mem::align_of::(), + align_of::(), ); // SAFETY: now `rest` is definitely aligned, so `from_raw_parts` below is okay, // since the caller guarantees that we can transmute `T` to `U` safely. @@ -3999,7 +4015,7 @@ impl [T] { // valid pointer `ptr` (it comes from a reference to `self`) and with // a size that is a power of two (since it comes from the alignment for U), // satisfying its safety constraints. - let offset = unsafe { crate::ptr::align_offset(ptr, mem::align_of::()) }; + let offset = unsafe { crate::ptr::align_offset(ptr, align_of::()) }; if offset > self.len() { (self, &mut [], &mut []) } else { @@ -4011,7 +4027,7 @@ impl [T] { #[cfg(miri)] crate::intrinsics::miri_promise_symbolic_alignment( mut_ptr.cast() as *const (), - mem::align_of::(), + align_of::(), ); // We can't use `rest` again after this, that would invalidate its alias `mut_ptr`! // SAFETY: see comments for `align_to`. @@ -4082,7 +4098,7 @@ impl [T] { // These are expected to always match, as vector types are laid out like // arrays per , but we // might as well double-check since it'll optimize away anyhow. - assert_eq!(mem::size_of::>(), mem::size_of::<[T; LANES]>()); + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); // SAFETY: The simd types have the same layout as arrays, just with // potentially-higher alignment, so the de-facto transmutes are sound. @@ -4118,7 +4134,7 @@ impl [T] { // These are expected to always match, as vector types are laid out like // arrays per , but we // might as well double-check since it'll optimize away anyhow. - assert_eq!(mem::size_of::>(), mem::size_of::<[T; LANES]>()); + assert_eq!(size_of::>(), size_of::<[T; LANES]>()); // SAFETY: The simd types have the same layout as arrays, just with // potentially-higher alignment, so the de-facto transmutes are sound. @@ -4295,8 +4311,6 @@ impl [T] { /// Splitting off the first three elements of a slice: /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; /// let mut first_three = slice.split_off(..3).unwrap(); /// @@ -4307,8 +4321,6 @@ impl [T] { /// Splitting off the last two elements of a slice: /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; /// let mut tail = slice.split_off(2..).unwrap(); /// @@ -4319,8 +4331,6 @@ impl [T] { /// Getting `None` when `range` is out of bounds: /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; /// /// assert_eq!(None, slice.split_off(5..)); @@ -4331,7 +4341,7 @@ impl [T] { /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] - #[unstable(feature = "slice_take", issue = "62280")] + #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] pub fn split_off<'a, R: OneSidedRange>( self: &mut &'a Self, range: R, @@ -4367,8 +4377,6 @@ impl [T] { /// Splitting off the first three elements of a slice: /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; /// let mut first_three = slice.split_off_mut(..3).unwrap(); /// @@ -4379,8 +4387,6 @@ impl [T] { /// Taking the last two elements of a slice: /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; /// let mut tail = slice.split_off_mut(2..).unwrap(); /// @@ -4391,8 +4397,6 @@ impl [T] { /// Getting `None` when `range` is out of bounds: /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; /// /// assert_eq!(None, slice.split_off_mut(5..)); @@ -4403,7 +4407,7 @@ impl [T] { /// ``` #[inline] #[must_use = "method does not modify the slice if the range is out of bounds"] - #[unstable(feature = "slice_take", issue = "62280")] + #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] pub fn split_off_mut<'a, R: OneSidedRange>( self: &mut &'a mut Self, range: R, @@ -4433,8 +4437,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &[_] = &['a', 'b', 'c']; /// let first = slice.split_off_first().unwrap(); /// @@ -4442,7 +4444,7 @@ impl [T] { /// assert_eq!(first, &'a'); /// ``` #[inline] - #[unstable(feature = "slice_take", issue = "62280")] + #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] pub fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> { let (first, rem) = self.split_first()?; *self = rem; @@ -4457,8 +4459,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; /// let first = slice.split_off_first_mut().unwrap(); /// *first = 'd'; @@ -4467,7 +4467,7 @@ impl [T] { /// assert_eq!(first, &'d'); /// ``` #[inline] - #[unstable(feature = "slice_take", issue = "62280")] + #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] pub fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { let (first, rem) = mem::take(self).split_first_mut()?; *self = rem; @@ -4482,8 +4482,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &[_] = &['a', 'b', 'c']; /// let last = slice.split_off_last().unwrap(); /// @@ -4491,7 +4489,7 @@ impl [T] { /// assert_eq!(last, &'c'); /// ``` #[inline] - #[unstable(feature = "slice_take", issue = "62280")] + #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] pub fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> { let (last, rem) = self.split_last()?; *self = rem; @@ -4506,8 +4504,6 @@ impl [T] { /// # Examples /// /// ``` - /// #![feature(slice_take)] - /// /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; /// let last = slice.split_off_last_mut().unwrap(); /// *last = 'd'; @@ -4516,7 +4512,7 @@ impl [T] { /// assert_eq!(last, &'d'); /// ``` #[inline] - #[unstable(feature = "slice_take", issue = "62280")] + #[stable(feature = "slice_take", since = "CURRENT_RUSTC_VERSION")] pub fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { let (last, rem) = mem::take(self).split_last_mut()?; *self = rem; @@ -4569,7 +4565,7 @@ impl [T] { /// /// [`get_disjoint_mut`]: slice::get_disjoint_mut /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html - #[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "get_many_mut", since = "1.86.0")] #[inline] pub unsafe fn get_disjoint_unchecked_mut( &mut self, @@ -4636,7 +4632,7 @@ impl [T] { /// } /// assert_eq!(v, &[1, 11, 111]); /// ``` - #[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "get_many_mut", since = "1.86.0")] #[inline] pub fn get_disjoint_mut( &mut self, @@ -4703,11 +4699,11 @@ impl [T] { let byte_offset = elem_start.wrapping_sub(self_start); - if byte_offset % mem::size_of::() != 0 { + if byte_offset % size_of::() != 0 { return None; } - let offset = byte_offset / mem::size_of::(); + let offset = byte_offset / size_of::(); if offset < self.len() { Some(offset) } else { None } } @@ -4757,11 +4753,11 @@ impl [T] { let byte_start = subslice_start.wrapping_sub(self_start); - if byte_start % core::mem::size_of::() != 0 { + if byte_start % size_of::() != 0 { return None; } - let start = byte_start / core::mem::size_of::(); + let start = byte_start / size_of::(); let end = start.wrapping_add(subslice.len()); if start <= self.len() && end <= self.len() { Some(start..end) } else { None } @@ -4847,7 +4843,6 @@ impl [[T; N]] { } } -#[cfg(not(test))] impl [f32] { /// Sorts the slice of floats. /// @@ -4876,7 +4871,6 @@ impl [f32] { } } -#[cfg(not(test))] impl [f64] { /// Sorts the slice of floats. /// @@ -5025,7 +5019,7 @@ fn get_disjoint_check_valid( /// assert_eq!(v.get_disjoint_mut([0, 999]), Err(GetDisjointMutError::IndexOutOfBounds)); /// assert_eq!(v.get_disjoint_mut([1, 1]), Err(GetDisjointMutError::OverlappingIndices)); /// ``` -#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "get_many_mut", since = "1.86.0")] #[derive(Debug, Clone, PartialEq, Eq)] pub enum GetDisjointMutError { /// An index provided was out-of-bounds for the slice. @@ -5034,7 +5028,7 @@ pub enum GetDisjointMutError { OverlappingIndices, } -#[stable(feature = "get_many_mut", since = "CURRENT_RUSTC_VERSION")] +#[stable(feature = "get_many_mut", since = "1.86.0")] impl fmt::Display for GetDisjointMutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let msg = match self { diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs index 319b76899bf8e..3582c7e8b3f38 100644 --- a/library/core/src/slice/raw.rs +++ b/library/core/src/slice/raw.rs @@ -11,7 +11,7 @@ use crate::{array, ptr, ub_checks}; /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `data` must be non-null, [valid] for reads for `len * mem::size_of::()` many bytes, +/// * `data` must be non-null, [valid] for reads for `len * size_of::()` many bytes, /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! @@ -28,7 +28,7 @@ use crate::{array, ptr, ub_checks}; /// * The memory referenced by the returned slice must not be mutated for the duration /// of lifetime `'a`, except inside an `UnsafeCell`. /// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`, +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, /// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// @@ -146,7 +146,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// /// Behavior is undefined if any of the following conditions are violated: /// -/// * `data` must be non-null, [valid] for both reads and writes for `len * mem::size_of::()` many bytes, +/// * `data` must be non-null, [valid] for both reads and writes for `len * size_of::()` many bytes, /// and it must be properly aligned. This means in particular: /// /// * The entire memory range of this slice must be contained within a single allocated object! @@ -163,7 +163,7 @@ pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] /// (not derived from the return value) for the duration of lifetime `'a`. /// Both read and write accesses are forbidden. /// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`, +/// * The total size `len * size_of::()` of the slice must be no larger than `isize::MAX`, /// and adding that size to `data` must not "wrap around" the address space. /// See the safety documentation of [`pointer::offset`]. /// @@ -272,7 +272,7 @@ pub const fn from_mut(s: &mut T) -> &mut [T] { #[rustc_const_unstable(feature = "const_slice_from_ptr_range", issue = "89792")] pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { // SAFETY: the caller must uphold the safety contract for `from_ptr_range`. - unsafe { from_raw_parts(range.start, range.end.sub_ptr(range.start)) } + unsafe { from_raw_parts(range.start, range.end.offset_from_unsigned(range.start)) } } /// Forms a mutable slice from a pointer range. @@ -342,5 +342,5 @@ pub const unsafe fn from_ptr_range<'a, T>(range: Range<*const T>) -> &'a [T] { #[rustc_const_unstable(feature = "const_slice_from_mut_ptr_range", issue = "89792")] pub const unsafe fn from_mut_ptr_range<'a, T>(range: Range<*mut T>) -> &'a mut [T] { // SAFETY: the caller must uphold the safety contract for `from_mut_ptr_range`. - unsafe { from_raw_parts_mut(range.start, range.end.sub_ptr(range.start)) } + unsafe { from_raw_parts_mut(range.start, range.end.offset_from_unsigned(range.start)) } } diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs index 5d5ee4c7b6240..80178f297eaae 100644 --- a/library/core/src/slice/rotate.rs +++ b/library/core/src/slice/rotate.rs @@ -1,4 +1,4 @@ -use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::mem::{MaybeUninit, SizedTypeProperties}; use crate::{cmp, ptr}; type BufType = [usize; 32]; @@ -21,12 +21,12 @@ pub(super) unsafe fn ptr_rotate(left: usize, mid: *mut T, right: usize) { } // `T` is not a zero-sized type, so it's okay to divide by its size. if !cfg!(feature = "optimize_for_size") - && cmp::min(left, right) <= mem::size_of::() / mem::size_of::() + && cmp::min(left, right) <= size_of::() / size_of::() { // SAFETY: guaranteed by the caller unsafe { ptr_rotate_memmove(left, mid, right) }; } else if !cfg!(feature = "optimize_for_size") - && ((left + right < 24) || (mem::size_of::() > mem::size_of::<[usize; 4]>())) + && ((left + right < 24) || (size_of::() > size_of::<[usize; 4]>())) { // SAFETY: guaranteed by the caller unsafe { ptr_rotate_gcd(left, mid, right) } diff --git a/library/core/src/slice/sort/shared/pivot.rs b/library/core/src/slice/sort/shared/pivot.rs index 255a1eb6c88a8..3aace484b6a89 100644 --- a/library/core/src/slice/sort/shared/pivot.rs +++ b/library/core/src/slice/sort/shared/pivot.rs @@ -31,9 +31,9 @@ pub fn choose_pivot bool>(v: &[T], is_less: &mut F) -> us let c = v_base.add(len_div_8 * 7); // [7*floor(n/8), 8*floor(n/8)) if len < PSEUDO_MEDIAN_REC_THRESHOLD { - median3(&*a, &*b, &*c, is_less).sub_ptr(v_base) + median3(&*a, &*b, &*c, is_less).offset_from_unsigned(v_base) } else { - median3_rec(a, b, c, len_div_8, is_less).sub_ptr(v_base) + median3_rec(a, b, c, len_div_8, is_less).offset_from_unsigned(v_base) } } } diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index f6dcf42ba6037..95f196a40d01c 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -113,7 +113,7 @@ pub(crate) trait UnstableSmallSortFreezeTypeImpl: Sized + FreezeMarker { impl UnstableSmallSortFreezeTypeImpl for T { #[inline(always)] default fn small_sort_threshold() -> usize { - if (mem::size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + if (size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { SMALL_SORT_GENERAL_THRESHOLD } else { SMALL_SORT_FALLBACK_THRESHOLD @@ -125,7 +125,7 @@ impl UnstableSmallSortFreezeTypeImpl for T { where F: FnMut(&T, &T) -> bool, { - if (mem::size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + if (size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { small_sort_general(v, is_less); } else { small_sort_fallback(v, is_less); @@ -143,10 +143,10 @@ impl UnstableSmallSortFreezeTypeImpl for T { #[inline(always)] fn small_sort_threshold() -> usize { if has_efficient_in_place_swap::() - && (mem::size_of::() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE + && (size_of::() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { SMALL_SORT_NETWORK_THRESHOLD - } else if (mem::size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + } else if (size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { SMALL_SORT_GENERAL_THRESHOLD } else { SMALL_SORT_FALLBACK_THRESHOLD @@ -159,10 +159,10 @@ impl UnstableSmallSortFreezeTypeImpl for T { F: FnMut(&T, &T) -> bool, { if has_efficient_in_place_swap::() - && (mem::size_of::() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE + && (size_of::() * SMALL_SORT_NETWORK_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { small_sort_network(v, is_less); - } else if (mem::size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { + } else if (size_of::() * SMALL_SORT_GENERAL_SCRATCH_LEN) <= MAX_STACK_ARRAY_SIZE { small_sort_general(v, is_less); } else { small_sort_fallback(v, is_less); @@ -238,7 +238,7 @@ fn small_sort_general_with_scratch bool>( unsafe { let scratch_base = scratch.as_mut_ptr() as *mut T; - let presorted_len = if const { mem::size_of::() <= 16 } && len >= 16 { + let presorted_len = if const { size_of::() <= 16 } && len >= 16 { // SAFETY: scratch_base is valid and has enough space. sort8_stable(v_base, scratch_base, scratch_base.add(len), is_less); sort8_stable( @@ -863,5 +863,5 @@ fn panic_on_ord_violation() -> ! { #[must_use] pub(crate) const fn has_efficient_in_place_swap() -> bool { // Heuristic that holds true on all tested 64-bit capable architectures. - mem::size_of::() <= 8 // mem::size_of::() + size_of::() <= 8 // size_of::() } diff --git a/library/core/src/slice/sort/stable/merge.rs b/library/core/src/slice/sort/stable/merge.rs index 0cb21740795b7..bb2747bfc78ac 100644 --- a/library/core/src/slice/sort/stable/merge.rs +++ b/library/core/src/slice/sort/stable/merge.rs @@ -143,7 +143,7 @@ impl Drop for MergeState { // leave the input slice `v` with each original element and all possible // modifications observed. unsafe { - let len = self.end.sub_ptr(self.start); + let len = self.end.offset_from_unsigned(self.start); ptr::copy_nonoverlapping(self.start, self.dst, len); } } diff --git a/library/core/src/slice/sort/stable/mod.rs b/library/core/src/slice/sort/stable/mod.rs index 3ff2e71fd05bc..090367cdabadd 100644 --- a/library/core/src/slice/sort/stable/mod.rs +++ b/library/core/src/slice/sort/stable/mod.rs @@ -3,7 +3,7 @@ #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::cmp; use crate::intrinsics; -use crate::mem::{self, MaybeUninit, SizedTypeProperties}; +use crate::mem::{MaybeUninit, SizedTypeProperties}; #[cfg(not(any(feature = "optimize_for_size", target_pointer_width = "16")))] use crate::slice::sort::shared::smallsort::{ SMALL_SORT_GENERAL_SCRATCH_LEN, StableSmallSortTypeImpl, insertion_sort_shift_left, @@ -107,7 +107,7 @@ fn driftsort_main bool, BufT: BufGuard>(v: &mut [T], i // If min_good_run_len is ever modified, this code must be updated to allocate // the correct scratch size for it. const MAX_FULL_ALLOC_BYTES: usize = 8_000_000; // 8MB - let max_full_alloc = MAX_FULL_ALLOC_BYTES / mem::size_of::(); + let max_full_alloc = MAX_FULL_ALLOC_BYTES / size_of::(); let len = v.len(); let alloc_len = cmp::max( cmp::max(len - len / 2, cmp::min(len, max_full_alloc)), @@ -155,7 +155,7 @@ impl AlignedStorage { } fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit] { - let len = N / mem::size_of::(); + let len = N / size_of::(); // SAFETY: `_align` ensures we are correctly aligned. unsafe { core::slice::from_raw_parts_mut(self.storage.as_mut_ptr().cast(), len) } diff --git a/library/core/src/slice/sort/stable/quicksort.rs b/library/core/src/slice/sort/stable/quicksort.rs index 630c6ff907703..3c9688790c40b 100644 --- a/library/core/src/slice/sort/stable/quicksort.rs +++ b/library/core/src/slice/sort/stable/quicksort.rs @@ -1,6 +1,6 @@ //! This module contains a stable quicksort and partition implementation. -use crate::mem::{self, ManuallyDrop, MaybeUninit}; +use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::slice::sort::shared::FreezeMarker; use crate::slice::sort::shared::pivot::choose_pivot; use crate::slice::sort::shared::smallsort::StableSmallSortTypeImpl; @@ -126,7 +126,7 @@ fn stable_partition bool>( // this gave significant performance boosts in benchmarks. Unrolling // through for _ in 0..UNROLL_LEN { .. } instead of manually improves // compile times but has a ~10-20% performance penalty on opt-level=s. - if const { mem::size_of::() <= 16 } { + if const { size_of::() <= 16 } { const UNROLL_LEN: usize = 4; let unroll_end = v_base.add(loop_end_pos.saturating_sub(UNROLL_LEN - 1)); while state.scan < unroll_end { diff --git a/library/core/src/slice/sort/unstable/quicksort.rs b/library/core/src/slice/sort/unstable/quicksort.rs index 4feef5deeb0fb..68a1611871699 100644 --- a/library/core/src/slice/sort/unstable/quicksort.rs +++ b/library/core/src/slice/sort/unstable/quicksort.rs @@ -1,6 +1,8 @@ //! This module contains an unstable quicksort and two partition implementations. -use crate::mem::{self, ManuallyDrop}; +#[cfg(not(feature = "optimize_for_size"))] +use crate::mem; +use crate::mem::ManuallyDrop; #[cfg(not(feature = "optimize_for_size"))] use crate::slice::sort::shared::pivot::choose_pivot; #[cfg(not(feature = "optimize_for_size"))] @@ -137,7 +139,7 @@ where const fn inst_partition bool>() -> fn(&mut [T], &T, &mut F) -> usize { const MAX_BRANCHLESS_PARTITION_SIZE: usize = 96; - if mem::size_of::() <= MAX_BRANCHLESS_PARTITION_SIZE { + if size_of::() <= MAX_BRANCHLESS_PARTITION_SIZE { // Specialize for types that are relatively cheap to copy, where branchless optimizations // have large leverage e.g. `u64` and `String`. cfg_if! { @@ -224,7 +226,7 @@ where left = left.add(1); } - left.sub_ptr(v_base) + left.offset_from_unsigned(v_base) // `gap_opt` goes out of scope and overwrites the last wrong-side element on the right side // with the first wrong-side element of the left side that was initially overwritten by the @@ -304,7 +306,7 @@ where // Manual unrolling that works well on x86, Arm and with opt-level=s without murdering // compile-times. Leaving this to the compiler yields ok to bad results. - let unroll_len = const { if mem::size_of::() <= 16 { 2 } else { 1 } }; + let unroll_len = const { if size_of::() <= 16 { 2 } else { 1 } }; let unroll_end = v_base.add(len - (unroll_len - 1)); while state.right < unroll_end { diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs index de68f80aa0c8e..1276d9014f0ef 100644 --- a/library/core/src/str/converts.rs +++ b/library/core/src/str/converts.rs @@ -126,7 +126,7 @@ pub const fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[stable(feature = "str_mut_extras", since = "1.20.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] +#[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "str_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { // FIXME(const-hack): This should use `?` again, once it's `const` diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs index b5d7aaf05d4bd..452403b23dee1 100644 --- a/library/core/src/str/count.rs +++ b/library/core/src/str/count.rs @@ -20,7 +20,7 @@ use core::intrinsics::unlikely; -const USIZE_SIZE: usize = core::mem::size_of::(); +const USIZE_SIZE: usize = size_of::(); const UNROLL_INNER: usize = 4; #[inline] diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 4754d18b06eac..5cc08f8a71afb 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -114,7 +114,6 @@ fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { ); } -#[cfg(not(test))] impl str { /// Returns the length of `self`. /// @@ -134,7 +133,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_str_len", since = "1.39.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_len")] + #[rustc_diagnostic_item = "str_len"] #[must_use] #[inline] pub const fn len(&self) -> usize { @@ -265,7 +264,7 @@ impl str { /// See the docs for [`Utf8Error`] for more details on the kinds of /// errors that can be returned. #[stable(feature = "inherent_str_constructors", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_unstable(feature = "const_str_from_utf8", issue = "91006")] + #[rustc_const_stable(feature = "const_str_from_utf8", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "str_inherent_from_utf8_mut"] pub const fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { converts::from_utf8_mut(v) @@ -354,7 +353,7 @@ impl str { /// ``` #[must_use] #[stable(feature = "is_char_boundary", since = "1.9.0")] - #[rustc_const_stable(feature = "const_is_char_boundary", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_is_char_boundary", since = "1.86.0")] #[inline] pub const fn is_char_boundary(&self, index: usize) -> bool { // 0 is always ok. @@ -811,7 +810,7 @@ impl str { #[inline] #[must_use] #[stable(feature = "str_split_at", since = "1.4.0")] - #[rustc_const_stable(feature = "const_str_split_at", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_str_split_at", since = "1.86.0")] pub const fn split_at(&self, mid: usize) -> (&str, &str) { match self.split_at_checked(mid) { None => slice_error_fail(self, 0, mid), @@ -852,7 +851,7 @@ impl str { #[inline] #[must_use] #[stable(feature = "str_split_at", since = "1.4.0")] - #[rustc_const_stable(feature = "const_str_split_at", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_str_split_at", since = "1.86.0")] pub const fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { @@ -892,7 +891,7 @@ impl str { #[inline] #[must_use] #[stable(feature = "split_at_checked", since = "1.80.0")] - #[rustc_const_stable(feature = "const_str_split_at", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_str_split_at", since = "1.86.0")] pub const fn split_at_checked(&self, mid: usize) -> Option<(&str, &str)> { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { @@ -933,7 +932,7 @@ impl str { #[inline] #[must_use] #[stable(feature = "split_at_checked", since = "1.80.0")] - #[rustc_const_stable(feature = "const_str_split_at", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_str_split_at", since = "1.86.0")] pub const fn split_at_mut_checked(&mut self, mid: usize) -> Option<(&mut str, &mut str)> { // is_char_boundary checks that the index is in [0, .len()] if self.is_char_boundary(mid) { @@ -1029,7 +1028,7 @@ impl str { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_chars")] + #[rustc_diagnostic_item = "str_chars"] pub fn chars(&self) -> Chars<'_> { Chars { iter: self.as_bytes().iter() } } @@ -1160,7 +1159,7 @@ impl str { #[must_use = "this returns the split string as an iterator, \ without modifying the original"] #[stable(feature = "split_whitespace", since = "1.1.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_split_whitespace")] + #[rustc_diagnostic_item = "str_split_whitespace"] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace<'_> { SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } @@ -1355,7 +1354,7 @@ impl str { /// assert!(bananas.starts_with(&['a', 'b', 'c', 'd'])); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_starts_with")] + #[rustc_diagnostic_item = "str_starts_with"] pub fn starts_with(&self, pat: P) -> bool { pat.is_prefix_of(self) } @@ -1380,7 +1379,7 @@ impl str { /// assert!(!bananas.ends_with("nana")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_ends_with")] + #[rustc_diagnostic_item = "str_ends_with"] pub fn ends_with(&self, pat: P) -> bool where for<'a> P::Searcher<'a>: ReverseSearcher<'a>, @@ -2114,7 +2113,7 @@ impl str { #[must_use = "this returns the trimmed string as a slice, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_trim")] + #[rustc_diagnostic_item = "str_trim"] pub fn trim(&self) -> &str { self.trim_matches(|c: char| c.is_whitespace()) } @@ -2153,7 +2152,7 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_trim_start")] + #[rustc_diagnostic_item = "str_trim_start"] pub fn trim_start(&self) -> &str { self.trim_start_matches(|c: char| c.is_whitespace()) } @@ -2192,7 +2191,7 @@ impl str { #[must_use = "this returns the trimmed string as a new slice, \ without modifying the original"] #[stable(feature = "trim_direction", since = "1.30.0")] - #[cfg_attr(not(test), rustc_diagnostic_item = "str_trim_end")] + #[rustc_diagnostic_item = "str_trim_end"] pub fn trim_end(&self) -> &str { self.trim_end_matches(|c: char| c.is_whitespace()) } diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs index 0f724dd961329..8174e4ff97dfc 100644 --- a/library/core/src/str/validations.rs +++ b/library/core/src/str/validations.rs @@ -2,7 +2,6 @@ use super::Utf8Error; use crate::intrinsics::const_eval_select; -use crate::mem; /// Returns the initial codepoint accumulator for the first byte. /// The first byte is special, only want bottom 5 bits for width 2, 4 bits @@ -128,7 +127,7 @@ pub(super) const fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { let mut index = 0; let len = v.len(); - const USIZE_BYTES: usize = mem::size_of::(); + const USIZE_BYTES: usize = size_of::(); let ascii_block_size = 2 * USIZE_BYTES; let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 }; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 73180bde54aa9..88bee62203101 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -44,8 +44,9 @@ //! The most important aspect of this model is that *data races* are undefined behavior. A data race //! is defined as conflicting non-synchronized accesses where at least one of the accesses is //! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at -//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before* -//! the other, according to the happens-before order of the memory model. +//! least one of them is a write. (A `compare_exchange` or `compare_exchange_weak` that does not +//! succeed is not considered a write.) They are *non-synchronized* if neither of them +//! *happens-before* the other, according to the happens-before order of the memory model. //! //! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust //! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially @@ -294,7 +295,7 @@ unsafe impl Sync for AtomicBool {} /// loads and stores of pointers. Its size depends on the target pointer's size. #[cfg(target_has_atomic_load_store = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "AtomicPtr")] +#[rustc_diagnostic_item = "AtomicPtr"] #[cfg_attr(target_pointer_width = "16", repr(C, align(2)))] #[cfg_attr(target_pointer_width = "32", repr(C, align(4)))] #[cfg_attr(target_pointer_width = "64", repr(C, align(8)))] @@ -2033,7 +2034,7 @@ impl AtomicPtr { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_add(&self, val: usize, order: Ordering) -> *mut T { - self.fetch_byte_add(val.wrapping_mul(core::mem::size_of::()), order) + self.fetch_byte_add(val.wrapping_mul(size_of::()), order) } /// Offsets the pointer's address by subtracting `val` (in units of `T`), @@ -2078,7 +2079,7 @@ impl AtomicPtr { #[unstable(feature = "strict_provenance_atomic_ptr", issue = "99108")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub fn fetch_ptr_sub(&self, val: usize, order: Ordering) -> *mut T { - self.fetch_byte_sub(val.wrapping_mul(core::mem::size_of::()), order) + self.fetch_byte_sub(val.wrapping_mul(size_of::()), order) } /// Offsets the pointer's address by adding `val` *bytes*, returning the @@ -3445,7 +3446,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI8"), + rustc_diagnostic_item = "AtomicI8", "i8", "", atomic_min, atomic_max, @@ -3464,7 +3465,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU8"), + rustc_diagnostic_item = "AtomicU8", "u8", "", atomic_umin, atomic_umax, @@ -3483,7 +3484,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI16"), + rustc_diagnostic_item = "AtomicI16", "i16", "", atomic_min, atomic_max, @@ -3502,7 +3503,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU16"), + rustc_diagnostic_item = "AtomicU16", "u16", "", atomic_umin, atomic_umax, @@ -3521,7 +3522,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI32"), + rustc_diagnostic_item = "AtomicI32", "i32", "", atomic_min, atomic_max, @@ -3540,7 +3541,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU32"), + rustc_diagnostic_item = "AtomicU32", "u32", "", atomic_umin, atomic_umax, @@ -3559,7 +3560,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI64"), + rustc_diagnostic_item = "AtomicI64", "i64", "", atomic_min, atomic_max, @@ -3578,7 +3579,7 @@ atomic_int! { stable(feature = "integer_atomics_stable", since = "1.34.0"), rustc_const_stable(feature = "const_integer_atomics", since = "1.34.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU64"), + rustc_diagnostic_item = "AtomicU64", "u64", "", atomic_umin, atomic_umax, @@ -3597,7 +3598,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "99069"), rustc_const_unstable(feature = "integer_atomics", issue = "99069"), rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicI128"), + rustc_diagnostic_item = "AtomicI128", "i128", "#![feature(integer_atomics)]\n\n", atomic_min, atomic_max, @@ -3616,7 +3617,7 @@ atomic_int! { unstable(feature = "integer_atomics", issue = "99069"), rustc_const_unstable(feature = "integer_atomics", issue = "99069"), rustc_const_unstable(feature = "integer_atomics", issue = "99069"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicU128"), + rustc_diagnostic_item = "AtomicU128", "u128", "#![feature(integer_atomics)]\n\n", atomic_umin, atomic_umax, @@ -3639,7 +3640,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicIsize"), + rustc_diagnostic_item = "AtomicIsize", "isize", "", atomic_min, atomic_max, @@ -3658,7 +3659,7 @@ macro_rules! atomic_int_ptr_sized { stable(feature = "atomic_nand", since = "1.27.0"), rustc_const_stable(feature = "const_ptr_sized_atomics", since = "1.24.0"), rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0"), - cfg_attr(not(test), rustc_diagnostic_item = "AtomicUsize"), + rustc_diagnostic_item = "AtomicUsize", "usize", "", atomic_umin, atomic_umax, @@ -3997,24 +3998,24 @@ unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { /// /// A fence 'A' which has (at least) [`Release`] ordering semantics, synchronizes /// with a fence 'B' with (at least) [`Acquire`] semantics, if and only if there -/// exist operations X and Y, both operating on some atomic object 'M' such +/// exist operations X and Y, both operating on some atomic object 'm' such /// that A is sequenced before X, Y is sequenced before B and Y observes -/// the change to M. This provides a happens-before dependence between A and B. +/// the change to m. This provides a happens-before dependence between A and B. /// /// ```text /// Thread 1 Thread 2 /// /// fence(Release); A -------------- -/// x.store(3, Relaxed); X --------- | +/// m.store(3, Relaxed); X --------- | /// | | /// | | -/// -------------> Y if x.load(Relaxed) == 3 { +/// -------------> Y if m.load(Relaxed) == 3 { /// |-------> B fence(Acquire); /// ... /// } /// ``` /// -/// Note that in the example above, it is crucial that the accesses to `x` are atomic. Fences cannot +/// Note that in the example above, it is crucial that the accesses to `m` are atomic. Fences cannot /// be used to establish synchronization among non-atomic accesses in different threads. However, /// thanks to the happens-before relationship between A and B, any non-atomic accesses that /// happen-before A are now also properly synchronized with any non-atomic accesses that diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 3f57b04753a6b..9b8fefe42af60 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -402,7 +402,7 @@ impl<'a> ContextBuilder<'a> { /// [`Wake`]: ../../alloc/task/trait.Wake.html #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] -#[cfg_attr(not(test), rustc_diagnostic_item = "Waker")] +#[rustc_diagnostic_item = "Waker"] pub struct Waker { waker: RawWaker, } diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 8b211b442eab6..18c03b4a6f89c 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -77,7 +77,7 @@ const DAYS_PER_WEEK: u64 = 7; /// crate to do so. #[stable(feature = "duration", since = "1.3.0")] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] -#[cfg_attr(not(test), rustc_diagnostic_item = "Duration")] +#[rustc_diagnostic_item = "Duration"] pub struct Duration { secs: u64, nanos: Nanoseconds, // Always 0 <= nanos < NANOS_PER_SEC @@ -1377,7 +1377,8 @@ impl fmt::Debug for Duration { } else { // We need to add padding. Use the `Formatter::padding` helper function. let default_align = fmt::Alignment::Left; - let post_padding = f.padding(requested_w - actual_w, default_align)?; + let post_padding = + f.padding((requested_w - actual_w) as u16, default_align)?; emit_without_padding(f)?; post_padding.write(f) } diff --git a/library/coretests/benches/ascii/is_ascii.rs b/library/coretests/benches/ascii/is_ascii.rs index ced7084fb0e48..a6c718409ee85 100644 --- a/library/coretests/benches/ascii/is_ascii.rs +++ b/library/coretests/benches/ascii/is_ascii.rs @@ -95,7 +95,7 @@ benches! { // These are separate since it's easier to debug errors if they don't go through // macro expansion first. fn is_ascii_align_to(bytes: &[u8]) -> bool { - if bytes.len() < core::mem::size_of::() { + if bytes.len() < size_of::() { return bytes.iter().all(|b| b.is_ascii()); } // SAFETY: transmuting a sequence of `u8` to `usize` is always fine @@ -106,7 +106,7 @@ fn is_ascii_align_to(bytes: &[u8]) -> bool { } fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool { - if bytes.len() < core::mem::size_of::() { + if bytes.len() < size_of::() { return bytes.iter().all(|b| b.is_ascii()); } // SAFETY: transmuting a sequence of `u8` to `[usize; 2]` is always fine @@ -118,6 +118,6 @@ fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool { #[inline] fn contains_nonascii(v: usize) -> bool { - const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; core::mem::size_of::()]); + const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; size_of::()]); (NONASCII_MASK & v) != 0 } diff --git a/library/coretests/benches/iter.rs b/library/coretests/benches/iter.rs index e14f26b729032..e49d152eb539f 100644 --- a/library/coretests/benches/iter.rs +++ b/library/coretests/benches/iter.rs @@ -1,6 +1,5 @@ use core::borrow::Borrow; use core::iter::*; -use core::mem; use core::num::Wrapping; use core::ops::Range; @@ -477,7 +476,7 @@ fn bench_next_chunk_copied(b: &mut Bencher) { let mut iter = black_box(&v).iter().copied(); let mut acc = Wrapping(0); // This uses a while-let loop to side-step the TRA specialization in ArrayChunks - while let Ok(chunk) = iter.next_chunk::<{ mem::size_of::() }>() { + while let Ok(chunk) = iter.next_chunk::<{ size_of::() }>() { let d = u64::from_ne_bytes(chunk); acc += Wrapping(d.rotate_left(7).wrapping_add(1)); } @@ -496,7 +495,7 @@ fn bench_next_chunk_trusted_random_access(b: &mut Bencher) { .iter() // this shows that we're not relying on the slice::Iter specialization in Copied .map(|b| *b.borrow()) - .array_chunks::<{ mem::size_of::() }>() + .array_chunks::<{ size_of::() }>() .map(|ary| { let d = u64::from_ne_bytes(ary); Wrapping(d.rotate_left(7).wrapping_add(1)) diff --git a/library/coretests/tests/alloc.rs b/library/coretests/tests/alloc.rs index b88f1821cd77c..72fdf82c1f8cf 100644 --- a/library/coretests/tests/alloc.rs +++ b/library/coretests/tests/alloc.rs @@ -1,5 +1,4 @@ use core::alloc::Layout; -use core::mem::size_of; use core::ptr::{self, NonNull}; #[test] diff --git a/library/coretests/tests/atomic.rs b/library/coretests/tests/atomic.rs index 0ffba538b2074..e0c0fe4790c04 100644 --- a/library/coretests/tests/atomic.rs +++ b/library/coretests/tests/atomic.rs @@ -250,8 +250,6 @@ fn atomic_access_bool() { #[test] fn atomic_alignment() { - use std::mem::{align_of, size_of}; - #[cfg(target_has_atomic = "8")] assert_eq!(align_of::(), size_of::()); #[cfg(target_has_atomic = "ptr")] diff --git a/library/coretests/tests/hash/sip.rs b/library/coretests/tests/hash/sip.rs index f79954f916b77..6add1a33cb931 100644 --- a/library/coretests/tests/hash/sip.rs +++ b/library/coretests/tests/hash/sip.rs @@ -1,7 +1,7 @@ #![allow(deprecated)] use core::hash::{Hash, Hasher, SipHasher, SipHasher13}; -use core::{mem, slice}; +use core::slice; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); @@ -314,7 +314,7 @@ fn test_write_short_works() { h1.write_u8(0x01u8); let mut h2 = SipHasher::new(); h2.write(unsafe { - slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::()) + slice::from_raw_parts(&test_usize as *const _ as *const u8, size_of::()) }); h2.write(b"bytes"); h2.write(b"string"); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ca58f41d7dd9e..79022fec8a20c 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -44,6 +44,7 @@ #![feature(ip)] #![feature(ip_from)] #![feature(is_ascii_octdigit)] +#![feature(isolate_most_least_significant_one)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_chain)] @@ -72,7 +73,6 @@ #![feature(slice_internals)] #![feature(slice_partition_dedup)] #![feature(slice_split_once)] -#![feature(slice_take)] #![feature(split_array)] #![feature(split_as_slice)] #![feature(std_internals)] @@ -86,9 +86,7 @@ #![feature(try_blocks)] #![feature(try_find)] #![feature(try_trait_v2)] -#![feature(unsigned_is_multiple_of)] #![feature(unsize)] -#![feature(unsized_tuple_coercion)] #![feature(unwrap_infallible)] // tidy-alphabetical-end #![allow(internal_features)] @@ -153,10 +151,7 @@ mod intrinsics; mod io; mod iter; mod lazy; -#[cfg(not(bootstrap))] mod macros; -#[cfg(bootstrap)] -mod macros_bootstrap; mod manually_drop; mod mem; mod net; diff --git a/library/coretests/tests/macros_bootstrap.rs b/library/coretests/tests/macros_bootstrap.rs deleted file mode 100644 index f10ef862c5dd9..0000000000000 --- a/library/coretests/tests/macros_bootstrap.rs +++ /dev/null @@ -1,193 +0,0 @@ -#![allow(unused_must_use)] - -#[allow(dead_code)] -trait Trait { - fn blah(&self); -} - -#[allow(dead_code)] -struct Struct; - -impl Trait for Struct { - cfg_match! { - cfg(feature = "blah") => { - fn blah(&self) { - unimplemented!(); - } - } - _ => { - fn blah(&self) { - unimplemented!(); - } - } - } -} - -#[test] -fn assert_eq_trailing_comma() { - assert_eq!(1, 1,); -} - -#[test] -fn assert_escape() { - assert!(r#"☃\backslash"#.contains("\\")); -} - -#[test] -fn assert_ne_trailing_comma() { - assert_ne!(1, 2,); -} - -#[rustfmt::skip] -#[test] -fn matches_leading_pipe() { - matches!(1, | 1 | 2 | 3); -} - -#[test] -fn cfg_match_basic() { - cfg_match! { - cfg(target_pointer_width = "64") => { fn f0_() -> bool { true }} - } - - cfg_match! { - cfg(unix) => { fn f1_() -> bool { true }} - cfg(any(target_os = "macos", target_os = "linux")) => { fn f1_() -> bool { false }} - } - - cfg_match! { - cfg(target_pointer_width = "32") => { fn f2_() -> bool { false }} - cfg(target_pointer_width = "64") => { fn f2_() -> bool { true }} - } - - cfg_match! { - cfg(target_pointer_width = "16") => { fn f3_() -> i32 { 1 }} - _ => { fn f3_() -> i32 { 2 }} - } - - #[cfg(target_pointer_width = "64")] - assert!(f0_()); - - #[cfg(unix)] - assert!(f1_()); - - #[cfg(target_pointer_width = "32")] - assert!(!f2_()); - #[cfg(target_pointer_width = "64")] - assert!(f2_()); - - #[cfg(not(target_pointer_width = "16"))] - assert_eq!(f3_(), 2); -} - -#[test] -fn cfg_match_debug_assertions() { - cfg_match! { - cfg(debug_assertions) => { - assert!(cfg!(debug_assertions)); - assert_eq!(4, 2+2); - } - _ => { - assert!(cfg!(not(debug_assertions))); - assert_eq!(10, 5+5); - } - } -} - -#[cfg(target_pointer_width = "64")] -#[test] -fn cfg_match_no_duplication_on_64() { - cfg_match! { - cfg(windows) => { - fn foo() {} - } - cfg(unix) => { - fn foo() {} - } - cfg(target_pointer_width = "64") => { - fn foo() {} - } - } - foo(); -} - -#[test] -fn cfg_match_options() { - cfg_match! { - cfg(test) => { - use core::option::Option as Option2; - fn works1() -> Option2 { Some(1) } - } - _ => { fn works1() -> Option { None } } - } - - cfg_match! { - cfg(feature = "foo") => { fn works2() -> bool { false } } - cfg(test) => { fn works2() -> bool { true } } - _ => { fn works2() -> bool { false } } - } - - cfg_match! { - cfg(feature = "foo") => { fn works3() -> bool { false } } - _ => { fn works3() -> bool { true } } - } - - cfg_match! { - cfg(test) => { - use core::option::Option as Option3; - fn works4() -> Option3 { Some(1) } - } - } - - cfg_match! { - cfg(feature = "foo") => { fn works5() -> bool { false } } - cfg(test) => { fn works5() -> bool { true } } - } - - assert!(works1().is_some()); - assert!(works2()); - assert!(works3()); - assert!(works4().is_some()); - assert!(works5()); -} - -#[test] -fn cfg_match_two_functions() { - cfg_match! { - cfg(target_pointer_width = "64") => { - fn foo1() {} - fn bar1() {} - } - _ => { - fn foo2() {} - fn bar2() {} - } - } - - #[cfg(target_pointer_width = "64")] - { - foo1(); - bar1(); - } - #[cfg(not(target_pointer_width = "64"))] - { - foo2(); - bar2(); - } -} - -fn _accepts_expressions() -> i32 { - cfg_match! { - cfg(unix) => { 1 } - _ => { 2 } - } -} - -fn _allows_stmt_expr_attributes() { - let one = 1; - let two = 2; - cfg_match! { - cfg(unix) => { one * two; } - _ => { one + two; } - } -} diff --git a/library/coretests/tests/nonzero.rs b/library/coretests/tests/nonzero.rs index 43c279053d829..00232c9b7061a 100644 --- a/library/coretests/tests/nonzero.rs +++ b/library/coretests/tests/nonzero.rs @@ -1,6 +1,5 @@ use core::num::{IntErrorKind, NonZero}; use core::option::Option::None; -use std::mem::size_of; #[test] fn test_create_nonzero_instance() { @@ -321,6 +320,106 @@ fn nonzero_trailing_zeros() { assert_eq!(TRAILING_ZEROS, 2); } +#[test] +fn test_nonzero_isolate_most_significant_one() { + // Signed most significant one + macro_rules! nonzero_int_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = -1; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + // Right shift the most significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS >> i).unwrap().isolate_most_significant_one(), + NonZero::<$T>::new(MOST_SIG_ONE >> i).unwrap().isolate_most_significant_one() + ); + i += 1; + } + } + )+ + }; + } + + // Unsigned most significant one + macro_rules! nonzero_uint_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = <$T>::MAX; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS >> i).unwrap().isolate_most_significant_one(), + NonZero::<$T>::new(MOST_SIG_ONE >> i).unwrap().isolate_most_significant_one(), + ); + i += 1; + } + } + )+ + }; + } + + nonzero_int_impl!(i8, i16, i32, i64, i128, isize); + nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); +} + +#[test] +fn test_nonzero_isolate_least_significant_one() { + // Signed least significant one + macro_rules! nonzero_int_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = -1; + const LEAST_SIG_ONE: $T = 1; + + // Left shift the least significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS << i).unwrap().isolate_least_significant_one(), + NonZero::<$T>::new(LEAST_SIG_ONE << i).unwrap().isolate_least_significant_one() + ); + i += 1; + } + } + )+ + }; + } + + // Unsigned least significant one + macro_rules! nonzero_uint_impl { + ($($T:ty),+) => { + $( + { + const BITS: $T = <$T>::MAX; + const LEAST_SIG_ONE: $T = 1; + + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + NonZero::<$T>::new(BITS << i).unwrap().isolate_least_significant_one(), + NonZero::<$T>::new(LEAST_SIG_ONE << i).unwrap().isolate_least_significant_one(), + ); + i += 1; + } + } + )+ + }; + } + + nonzero_int_impl!(i8, i16, i32, i64, i128, isize); + nonzero_uint_impl!(u8, u16, u32, u64, u128, usize); +} + #[test] fn test_nonzero_uint_div() { let nz = NonZero::new(1).unwrap(); diff --git a/library/coretests/tests/num/dec2flt/decimal.rs b/library/coretests/tests/num/dec2flt/decimal.rs new file mode 100644 index 0000000000000..1fa06de692e07 --- /dev/null +++ b/library/coretests/tests/num/dec2flt/decimal.rs @@ -0,0 +1,28 @@ +use core::num::dec2flt::decimal::Decimal; + +type FPath = ((i64, u64, bool, bool), Option); + +const FPATHS_F32: &[FPath] = + &[((0, 0, false, false), Some(0.0)), ((0, 0, false, false), Some(0.0))]; +const FPATHS_F64: &[FPath] = + &[((0, 0, false, false), Some(0.0)), ((0, 0, false, false), Some(0.0))]; + +#[test] +fn check_fast_path_f32() { + for ((exponent, mantissa, negative, many_digits), expected) in FPATHS_F32.iter().copied() { + let dec = Decimal { exponent, mantissa, negative, many_digits }; + let actual = dec.try_fast_path::(); + + assert_eq!(actual, expected); + } +} + +#[test] +fn check_fast_path_f64() { + for ((exponent, mantissa, negative, many_digits), expected) in FPATHS_F64.iter().copied() { + let dec = Decimal { exponent, mantissa, negative, many_digits }; + let actual = dec.try_fast_path::(); + + assert_eq!(actual, expected); + } +} diff --git a/library/coretests/tests/num/dec2flt/decimal_seq.rs b/library/coretests/tests/num/dec2flt/decimal_seq.rs new file mode 100644 index 0000000000000..f46ba7c465a6e --- /dev/null +++ b/library/coretests/tests/num/dec2flt/decimal_seq.rs @@ -0,0 +1,30 @@ +use core::num::dec2flt::decimal_seq::{DecimalSeq, parse_decimal_seq}; + +#[test] +fn test_trim() { + let mut dec = DecimalSeq::default(); + let digits = [1, 2, 3, 4]; + + dec.digits[0..4].copy_from_slice(&digits); + dec.num_digits = 8; + dec.trim(); + + assert_eq!(dec.digits[0..4], digits); + assert_eq!(dec.num_digits, 4); +} + +#[test] +fn test_parse() { + let tests = [("1.234", [1, 2, 3, 4], 1)]; + + for (s, exp_digits, decimal_point) in tests { + let actual = parse_decimal_seq(s.as_bytes()); + let mut digits = [0; DecimalSeq::MAX_DIGITS]; + digits[..exp_digits.len()].copy_from_slice(&exp_digits); + + let expected = + DecimalSeq { num_digits: exp_digits.len(), decimal_point, truncated: false, digits }; + + assert_eq!(actual, expected); + } +} diff --git a/library/coretests/tests/num/dec2flt/float.rs b/library/coretests/tests/num/dec2flt/float.rs index 7a9587a18d030..b5afd3e3b2436 100644 --- a/library/coretests/tests/num/dec2flt/float.rs +++ b/library/coretests/tests/num/dec2flt/float.rs @@ -12,8 +12,8 @@ fn test_f32_integer_decode() { // Ignore the "sign" (quiet / signalling flag) of NAN. // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (12582912, 105)); + let (nan_m, nan_p, _nan_s) = f32::NAN.integer_decode(); + assert_eq!((nan_m, nan_p), (12582912, 105)); } #[test] @@ -28,6 +28,46 @@ fn test_f64_integer_decode() { // Ignore the "sign" (quiet / signalling flag) of NAN. // It can vary between runtime operations and LLVM folding. - let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode(); - assert_eq!((nan_m, nan_e), (6755399441055744, 972)); + let (nan_m, nan_p, _nan_s) = f64::NAN.integer_decode(); + assert_eq!((nan_m, nan_p), (6755399441055744, 972)); +} + +/* Sanity checks of computed magic numbers */ + +#[test] +fn test_f32_consts() { + assert_eq!(::INFINITY, f32::INFINITY); + assert_eq!(::NEG_INFINITY, -f32::INFINITY); + assert_eq!(::NAN.to_bits(), f32::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f32::NAN).to_bits()); + assert_eq!(::SIG_BITS, 23); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -17); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 10); + assert_eq!(::MIN_EXPONENT_FAST_PATH, -10); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 10); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 17); + assert_eq!(::EXP_MIN, -126); + assert_eq!(::EXP_SAT, 0xff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -65); + assert_eq!(::LARGEST_POWER_OF_TEN, 38); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 16777216); +} + +#[test] +fn test_f64_consts() { + assert_eq!(::INFINITY, f64::INFINITY); + assert_eq!(::NEG_INFINITY, -f64::INFINITY); + assert_eq!(::NAN.to_bits(), f64::NAN.to_bits()); + assert_eq!(::NEG_NAN.to_bits(), (-f64::NAN).to_bits()); + assert_eq!(::SIG_BITS, 52); + assert_eq!(::MIN_EXPONENT_ROUND_TO_EVEN, -4); + assert_eq!(::MAX_EXPONENT_ROUND_TO_EVEN, 23); + assert_eq!(::MIN_EXPONENT_FAST_PATH, -22); + assert_eq!(::MAX_EXPONENT_FAST_PATH, 22); + assert_eq!(::MAX_EXPONENT_DISGUISED_FAST_PATH, 37); + assert_eq!(::EXP_MIN, -1022); + assert_eq!(::EXP_SAT, 0x7ff); + assert_eq!(::SMALLEST_POWER_OF_TEN, -342); + assert_eq!(::LARGEST_POWER_OF_TEN, 308); + assert_eq!(::MAX_MANTISSA_FAST_PATH, 9007199254740992); } diff --git a/library/coretests/tests/num/dec2flt/lemire.rs b/library/coretests/tests/num/dec2flt/lemire.rs index f71bbb7c7a318..0db80fbd52506 100644 --- a/library/coretests/tests/num/dec2flt/lemire.rs +++ b/library/coretests/tests/num/dec2flt/lemire.rs @@ -1,13 +1,14 @@ +use core::num::dec2flt::float::RawFloat; use core::num::dec2flt::lemire::compute_float; fn compute_float32(q: i64, w: u64) -> (i32, u64) { let fp = compute_float::(q, w); - (fp.e, fp.f) + (fp.p_biased, fp.m) } fn compute_float64(q: i64, w: u64) -> (i32, u64) { let fp = compute_float::(q, w); - (fp.e, fp.f) + (fp.p_biased, fp.m) } #[test] @@ -27,6 +28,11 @@ fn compute_float_f32_rounding() { // Let's check the lines to see if anything is different in table... assert_eq!(compute_float32(-10, 167772190000000000), (151, 2)); assert_eq!(compute_float32(-10, 167772200000000000), (151, 2)); + + // Check the rounding point between infinity and the next representable number down + assert_eq!(compute_float32(38, 3), (f32::INFINITE_POWER - 1, 6402534)); + assert_eq!(compute_float32(38, 4), (f32::INFINITE_POWER, 0)); // infinity + assert_eq!(compute_float32(20, 3402823470000000000), (f32::INFINITE_POWER - 1, 8388607)); } #[test] diff --git a/library/coretests/tests/num/dec2flt/mod.rs b/library/coretests/tests/num/dec2flt/mod.rs index 874e0ec7093c7..a9025be5ca7f1 100644 --- a/library/coretests/tests/num/dec2flt/mod.rs +++ b/library/coretests/tests/num/dec2flt/mod.rs @@ -1,5 +1,7 @@ #![allow(overflowing_literals)] +mod decimal; +mod decimal_seq; mod float; mod lemire; mod parse; diff --git a/library/coretests/tests/num/dec2flt/parse.rs b/library/coretests/tests/num/dec2flt/parse.rs index 4a5d24ba7d5fa..59be3915052d8 100644 --- a/library/coretests/tests/num/dec2flt/parse.rs +++ b/library/coretests/tests/num/dec2flt/parse.rs @@ -1,9 +1,9 @@ -use core::num::dec2flt::number::Number; +use core::num::dec2flt::decimal::Decimal; use core::num::dec2flt::parse::parse_number; use core::num::dec2flt::{dec2flt, pfe_invalid}; -fn new_number(e: i64, m: u64) -> Number { - Number { exponent: e, mantissa: m, negative: false, many_digits: false } +fn new_dec(e: i64, m: u64) -> Decimal { + Decimal { exponent: e, mantissa: m, negative: false, many_digits: false } } #[test] @@ -31,23 +31,23 @@ fn invalid_chars() { } } -fn parse_positive(s: &[u8]) -> Option { +fn parse_positive(s: &[u8]) -> Option { parse_number(s) } #[test] fn valid() { - assert_eq!(parse_positive(b"123.456e789"), Some(new_number(786, 123456))); - assert_eq!(parse_positive(b"123.456e+789"), Some(new_number(786, 123456))); - assert_eq!(parse_positive(b"123.456e-789"), Some(new_number(-792, 123456))); - assert_eq!(parse_positive(b".050"), Some(new_number(-3, 50))); - assert_eq!(parse_positive(b"999"), Some(new_number(0, 999))); - assert_eq!(parse_positive(b"1.e300"), Some(new_number(300, 1))); - assert_eq!(parse_positive(b".1e300"), Some(new_number(299, 1))); - assert_eq!(parse_positive(b"101e-33"), Some(new_number(-33, 101))); + assert_eq!(parse_positive(b"123.456e789"), Some(new_dec(786, 123456))); + assert_eq!(parse_positive(b"123.456e+789"), Some(new_dec(786, 123456))); + assert_eq!(parse_positive(b"123.456e-789"), Some(new_dec(-792, 123456))); + assert_eq!(parse_positive(b".050"), Some(new_dec(-3, 50))); + assert_eq!(parse_positive(b"999"), Some(new_dec(0, 999))); + assert_eq!(parse_positive(b"1.e300"), Some(new_dec(300, 1))); + assert_eq!(parse_positive(b".1e300"), Some(new_dec(299, 1))); + assert_eq!(parse_positive(b"101e-33"), Some(new_dec(-33, 101))); let zeros = "0".repeat(25); let s = format!("1.5e{zeros}"); - assert_eq!(parse_positive(s.as_bytes()), Some(new_number(-1, 15))); + assert_eq!(parse_positive(s.as_bytes()), Some(new_dec(-1, 15))); } macro_rules! assert_float_result_bits_eq { @@ -57,6 +57,21 @@ macro_rules! assert_float_result_bits_eq { }}; } +#[test] +fn regression() { + // These showed up in fuzz tests when the minimum exponent was incorrect. + assert_float_result_bits_eq!( + 0x0, + f64, + "3313756768023998018398807867233977556112078681253148176737587500333136120852692315608454494981109839693784033457129423181787087843504060087613228932431e-475" + ); + assert_float_result_bits_eq!( + 0x0, + f64, + "5298127456259331337220.92759278003098321644501973966679724599271041396379712108366679824365568578569680024083293475291869842408884554511641179110778276695274832779269225510492006696321279587846006535230380114430977056662212751544508159333199129106162019382177820713609e-346" + ); +} + #[test] fn issue31109() { // Regression test for #31109. diff --git a/library/coretests/tests/num/flt2dec/mod.rs b/library/coretests/tests/num/flt2dec/mod.rs index 6041923117c2a..c64bb0a30720a 100644 --- a/library/coretests/tests/num/flt2dec/mod.rs +++ b/library/coretests/tests/num/flt2dec/mod.rs @@ -577,7 +577,7 @@ where } // very large output - assert_eq!(to_string(f, 1.1, Minus, 80000), format!("1.1{:0>79999}", "")); + assert_eq!(to_string(f, 1.1, Minus, 50000), format!("1.1{:0>49999}", "")); } pub fn to_shortest_exp_str_test(mut f_: F) @@ -914,22 +914,22 @@ where ); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000, false), format!("0.{:0>79999}e0", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000, false), format!("1.{:0>79999}e1", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000, false), format!("1.{:0>79999}e0", "")); + assert_eq!(to_string(f, 0.0, Minus, 50000, false), format!("0.{:0>49999}e0", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 50000, false), format!("1.{:0>49999}e1", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 50000, false), format!("1.{:0>49999}e0", "")); assert_eq!( - to_string(f, 1.0e-1, Minus, 80000, false), + to_string(f, 1.0e-1, Minus, 50000, false), format!( - "1.000000000000000055511151231257827021181583404541015625{:0>79945}\ + "1.000000000000000055511151231257827021181583404541015625{:0>49945}\ e-1", "" ) ); assert_eq!( - to_string(f, 1.0e-20, Minus, 80000, false), + to_string(f, 1.0e-20, Minus, 50000, false), format!( "9.999999999999999451532714542095716517295037027873924471077157760\ - 66783064379706047475337982177734375{:0>79901}e-21", + 66783064379706047475337982177734375{:0>49901}e-21", "" ) ); @@ -1150,18 +1150,18 @@ where ); // very large output - assert_eq!(to_string(f, 0.0, Minus, 80000), format!("0.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e1, Minus, 80000), format!("10.{:0>80000}", "")); - assert_eq!(to_string(f, 1.0e0, Minus, 80000), format!("1.{:0>80000}", "")); + assert_eq!(to_string(f, 0.0, Minus, 50000), format!("0.{:0>50000}", "")); + assert_eq!(to_string(f, 1.0e1, Minus, 50000), format!("10.{:0>50000}", "")); + assert_eq!(to_string(f, 1.0e0, Minus, 50000), format!("1.{:0>50000}", "")); assert_eq!( - to_string(f, 1.0e-1, Minus, 80000), - format!("0.1000000000000000055511151231257827021181583404541015625{:0>79945}", "") + to_string(f, 1.0e-1, Minus, 50000), + format!("0.1000000000000000055511151231257827021181583404541015625{:0>49945}", "") ); assert_eq!( - to_string(f, 1.0e-20, Minus, 80000), + to_string(f, 1.0e-20, Minus, 50000), format!( "0.0000000000000000000099999999999999994515327145420957165172950370\ - 2787392447107715776066783064379706047475337982177734375{:0>79881}", + 2787392447107715776066783064379706047475337982177734375{:0>49881}", "" ) ); diff --git a/library/coretests/tests/num/int_log.rs b/library/coretests/tests/num/int_log.rs index 60902752dab64..e8d35fc21ce6e 100644 --- a/library/coretests/tests/num/int_log.rs +++ b/library/coretests/tests/num/int_log.rs @@ -1,5 +1,13 @@ //! Tests for the `Integer::{ilog,log2,log10}` methods. +/// Rounds the argument down to the next integer, except that we account for potential imprecision +/// in the input, so if `f` is very close to an integer, it will round to that. +fn round_down_imprecise(f: f32) -> u32 { + // Rounds up for values less than 16*EPSILON below an integer, + // and rounds down for everything else. + (f + 16.0 * f32::EPSILON) as u32 +} + #[test] fn checked_ilog() { assert_eq!(999u32.checked_ilog(10), Some(2)); @@ -25,15 +33,24 @@ fn checked_ilog() { } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); + assert_eq!( + i.checked_ilog(13), + Some(round_down_imprecise((i as f32).log(13.0))), + "checking {i}" + ); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32), "checking {i}"); + assert_eq!( + i.checked_ilog(13), + Some(round_down_imprecise((i as f32).log(13.0))), + "checking {i}" + ); } } #[test] +#[cfg_attr(miri, ignore)] // FIXME test is broken on Miri: https://github.com/rust-lang/rust/issues/137591 fn checked_ilog2() { assert_eq!(5u32.checked_ilog2(), Some(2)); assert_eq!(0u64.checked_ilog2(), None); @@ -45,25 +62,34 @@ fn checked_ilog2() { assert_eq!(0i8.checked_ilog2(), None); assert_eq!(0i16.checked_ilog2(), None); - assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32)); - assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32)); - assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32)); + assert_eq!(8192u16.checked_ilog2(), Some(round_down_imprecise((8192f32).log2()))); + assert_eq!(32768u16.checked_ilog2(), Some(round_down_imprecise((32768f32).log2()))); + assert_eq!(8192i16.checked_ilog2(), Some(round_down_imprecise((8192f32).log2()))); for i in 1..=u8::MAX { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); + assert_eq!( + i.checked_ilog2(), + Some(round_down_imprecise((i as f32).log2())), + "checking {i}" + ); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - // Guard against Android's imprecise f32::ilog2 implementation. - if i != 8192 && i != 32768 { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); - } + assert_eq!( + i.checked_ilog2(), + Some(round_down_imprecise((i as f32).log2())), + "checking {i}" + ); } for i in i8::MIN..=0 { assert_eq!(i.checked_ilog2(), None, "checking {i}"); } for i in 1..=i8::MAX { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); + assert_eq!( + i.checked_ilog2(), + Some(round_down_imprecise((i as f32).log2())), + "checking {i}" + ); } #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { @@ -71,10 +97,11 @@ fn checked_ilog2() { } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - // Guard against Android's imprecise f32::ilog2 implementation. - if i != 8192 { - assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32), "checking {i}"); - } + assert_eq!( + i.checked_ilog2(), + Some(round_down_imprecise((i as f32).log2())), + "checking {i}" + ); } } @@ -91,15 +118,27 @@ fn checked_ilog10() { } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); + assert_eq!( + i.checked_ilog10(), + Some(round_down_imprecise((i as f32).log10())), + "checking {i}" + ); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); + assert_eq!( + i.checked_ilog10(), + Some(round_down_imprecise((i as f32).log10())), + "checking {i}" + ); } #[cfg(not(miri))] // Miri is too slow for i in 1..=100_000u32 { - assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32), "checking {i}"); + assert_eq!( + i.checked_ilog10(), + Some(round_down_imprecise((i as f32).log10())), + "checking {i}" + ); } } diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs index f13b836378b9e..bbf19d2b444f9 100644 --- a/library/coretests/tests/num/int_macros.rs +++ b/library/coretests/tests/num/int_macros.rs @@ -192,6 +192,40 @@ macro_rules! int_module { } } + #[test] + fn test_isolate_most_significant_one() { + const BITS: $T = -1; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + // Right shift the most significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS >> i).isolate_most_significant_one(), + (MOST_SIG_ONE >> i).isolate_most_significant_one() + ); + i += 1; + } + } + + #[test] + fn test_isolate_least_significant_one() { + const BITS: $T = -1; + const LEAST_SIG_ONE: $T = 1; + + // Left shift the least significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS << i).isolate_least_significant_one(), + (LEAST_SIG_ONE << i).isolate_least_significant_one() + ); + i += 1; + } + } + #[test] fn test_from_str() { fn from_str(t: &str) -> Option { @@ -478,5 +512,169 @@ macro_rules! int_module { assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); } } + + // test_unbounded_sh* constants + const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS; + const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3; + const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2; + + const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1; + const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3; + const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1; + const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1; + + test_runtime_and_compiletime! { + fn test_unbounded_shl() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // -1 + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_ONE), (-1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_TWO), (-1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_THREE), (-1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, 1), (-1 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, 3), (-1 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, 5), (-1 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + + fn test_unbounded_shr() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), -1); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // -1 + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_ONE), (-1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_TWO), (-1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_THREE), (-1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, 1), (-1 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, 3), (-1 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, 5), (-1 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW2), -1); + assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW3), -1); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + } }; } diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 99a2d4cd462b1..d09eb97b17e06 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -141,6 +141,40 @@ macro_rules! uint_module { } } + #[test] + fn test_isolate_most_significant_one() { + const BITS: $T = <$T>::MAX; + const MOST_SIG_ONE: $T = 1 << (<$T>::BITS - 1); + + // Right shift the most significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS >> i).isolate_most_significant_one(), + (MOST_SIG_ONE >> i).isolate_most_significant_one(), + ); + i += 1; + } + } + + #[test] + fn test_isolate_least_significant_one() { + const BITS: $T = <$T>::MAX; + const LEAST_SIG_ONE: $T = 1; + + // Left shift the least significant one through each + // bit position, starting with all bits set + let mut i = 0; + while i < <$T>::BITS { + assert_eq!( + (BITS << i).isolate_least_significant_one(), + (LEAST_SIG_ONE << i).isolate_least_significant_one(), + ); + i += 1; + } + } + fn from_str(t: &str) -> Option { core::str::FromStr::from_str(t).ok() } @@ -317,5 +351,169 @@ macro_rules! uint_module { assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); } } + + // test_unbounded_sh* constants + const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS; + const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3; + const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2; + + const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1; + const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3; + const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1; + const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1; + + test_runtime_and_compiletime! { + fn test_unbounded_shl() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // !0 + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_ONE), (!0 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_TWO), (!0 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_THREE), (!0 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, 1), (!0 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, 3), (!0 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, 5), (!0 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5)); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + + fn test_unbounded_shr() { + // <$T>::MIN + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0); + + // <$T>::MAX + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 1 + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0); + + // !0 + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_ONE), (!0 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_TWO), (!0 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_THREE), (!0 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, 1), (!0 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, 3), (!0 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, 5), (!0 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 8 + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0); + + // 17 + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5)); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0); + assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0); + } + } }; } diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index 0c9f9b338b0c1..6091926084a35 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -1,6 +1,6 @@ use core::cell::RefCell; use core::marker::Freeze; -use core::mem::{self, MaybeUninit}; +use core::mem::MaybeUninit; use core::num::NonZero; use core::ptr; use core::ptr::*; @@ -388,7 +388,7 @@ fn align_offset_various_strides() { let mut expected = usize::MAX; // Naive but definitely correct way to find the *first* aligned element of stride::. for el in 0..align { - if (numptr + el * ::std::mem::size_of::()) % align == 0 { + if (numptr + el * size_of::()) % align == 0 { expected = el; break; } @@ -398,7 +398,7 @@ fn align_offset_various_strides() { eprintln!( "aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr, - ::std::mem::size_of::(), + size_of::(), align, expected, got @@ -525,31 +525,24 @@ fn ptr_metadata() { assert_eq!(metadata("foo"), 3_usize); assert_eq!(metadata(&[4, 7][..]), 2_usize); - let dst_tuple: &(bool, [u8]) = &(true, [0x66, 0x6F, 0x6F]); let dst_struct: &Pair = &Pair(true, [0x66, 0x6F, 0x6F]); - assert_eq!(metadata(dst_tuple), 3_usize); assert_eq!(metadata(dst_struct), 3_usize); unsafe { - let dst_tuple: &(bool, str) = std::mem::transmute(dst_tuple); let dst_struct: &Pair = std::mem::transmute(dst_struct); - assert_eq!(&dst_tuple.1, "foo"); assert_eq!(&dst_struct.1, "foo"); - assert_eq!(metadata(dst_tuple), 3_usize); assert_eq!(metadata(dst_struct), 3_usize); } let vtable_1: DynMetadata = metadata(&4_u16 as &dyn Debug); let vtable_2: DynMetadata = metadata(&4_u16 as &dyn Display); let vtable_3: DynMetadata = metadata(&4_u32 as &dyn Display); - let vtable_4: DynMetadata = metadata(&(true, 7_u32) as &(bool, dyn Display)); - let vtable_5: DynMetadata = + let vtable_4: DynMetadata = metadata(&Pair(true, 7_u32) as &Pair); unsafe { let address_1: *const () = std::mem::transmute(vtable_1); let address_2: *const () = std::mem::transmute(vtable_2); let address_3: *const () = std::mem::transmute(vtable_3); let address_4: *const () = std::mem::transmute(vtable_4); - let address_5: *const () = std::mem::transmute(vtable_5); // Different trait => different vtable pointer assert_ne!(address_1, address_2); // Different erased type => different vtable pointer @@ -558,7 +551,6 @@ fn ptr_metadata() { // This is *not guaranteed*, so we skip it in Miri. if !cfg!(miri) { assert_eq!(address_3, address_4); - assert_eq!(address_3, address_5); } } } @@ -613,9 +605,9 @@ fn dyn_metadata() { let meta = metadata(trait_object); assert_eq!(meta.size_of(), 64); - assert_eq!(meta.size_of(), std::mem::size_of::()); + assert_eq!(meta.size_of(), size_of::()); assert_eq!(meta.align_of(), 32); - assert_eq!(meta.align_of(), std::mem::align_of::()); + assert_eq!(meta.align_of(), align_of::()); assert_eq!(meta.layout(), std::alloc::Layout::new::()); assert!(format!("{meta:?}").starts_with("DynMetadata(0x")); @@ -789,7 +781,7 @@ fn nonnull_tagged_pointer_with_provenance() { impl TaggedPointer { /// The ABI-required minimum alignment of the `P` type. - pub const ALIGNMENT: usize = core::mem::align_of::(); + pub const ALIGNMENT: usize = align_of::(); /// A mask for data-carrying bits of the address. pub const DATA_MASK: usize = !Self::ADDRESS_MASK; /// Number of available bits of storage in the address. @@ -873,7 +865,7 @@ fn test_const_copy_ptr() { ptr::copy( &ptr1 as *const _ as *const MaybeUninit, &mut ptr2 as *mut _ as *mut MaybeUninit, - mem::size_of::<&i32>(), + size_of::<&i32>(), ); } @@ -891,7 +883,7 @@ fn test_const_copy_ptr() { ptr::copy_nonoverlapping( &ptr1 as *const _ as *const MaybeUninit, &mut ptr2 as *mut _ as *mut MaybeUninit, - mem::size_of::<&i32>(), + size_of::<&i32>(), ); } @@ -936,7 +928,7 @@ fn test_const_swap_ptr() { let mut s2 = A(S { ptr: &666, f1: 0, f2: [0; 3] }); // Swap ptr1 and ptr2, as an array. - type T = [u8; mem::size_of::()]; + type T = [u8; size_of::()]; unsafe { ptr::swap(ptr::from_mut(&mut s1).cast::(), ptr::from_mut(&mut s2).cast::()); } diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs index 1c5c8a9ebf258..d17e681480c70 100644 --- a/library/coretests/tests/slice.rs +++ b/library/coretests/tests/slice.rs @@ -5,8 +5,6 @@ use core::num::NonZero; use core::ops::{Range, RangeInclusive}; use core::slice; -use rand::seq::IndexedRandom; - #[test] fn test_position() { let b = [1, 2, 3, 5, 5]; @@ -1810,6 +1808,7 @@ fn select_nth_unstable() { use core::cmp::Ordering::{Equal, Greater, Less}; use rand::Rng; + use rand::seq::IndexedRandom; let mut rng = crate::test_rng(); @@ -2058,15 +2057,13 @@ fn test_align_to_non_trivial() { #[test] fn test_align_to_empty_mid() { - use core::mem; - // Make sure that we do not create empty unaligned slices for the mid part, even when the // overall slice is too short to contain an aligned address. let bytes = [1, 2, 3, 4, 5, 6, 7]; type Chunk = u32; for offset in 0..4 { let (_, mid, _) = unsafe { bytes[offset..offset + 1].align_to::() }; - assert_eq!(mid.as_ptr() as usize % mem::align_of::(), 0); + assert_eq!(mid.as_ptr() as usize % align_of::(), 0); } } diff --git a/library/panic_abort/Cargo.toml b/library/panic_abort/Cargo.toml index a9d1f53761cbf..6f43ac4809a32 100644 --- a/library/panic_abort/Cargo.toml +++ b/library/panic_abort/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" description = "Implementation of Rust panics via process aborts" -edition = "2021" +edition = "2024" [lib] test = false diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index c2abb79192e9f..d176434e06ba1 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" description = "Implementation of Rust panics via stack unwinding" -edition = "2021" +edition = "2024" [lib] test = false diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index 1569c26c9de47..bad795a019c9a 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -9,7 +9,7 @@ use alloc::boxed::Box; use core::any::Any; use core::sync::atomic::{AtomicBool, Ordering}; -use core::{intrinsics, mem, ptr}; +use core::{intrinsics, ptr}; use unwind as uw; @@ -97,7 +97,7 @@ pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box { pub(crate) unsafe fn panic(data: Box) -> u32 { unsafe { - let exception = __cxa_allocate_exception(mem::size_of::()) as *mut Exception; + let exception = __cxa_allocate_exception(size_of::()) as *mut Exception; if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 1111c2009b3dd..a284633ea2fc7 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -14,6 +14,7 @@ #![no_std] #![unstable(feature = "panic_unwind", issue = "32837")] #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] +#![feature(cfg_emscripten_wasm_eh)] #![feature(core_intrinsics)] #![feature(lang_items)] #![feature(panic_unwind)] @@ -25,7 +26,6 @@ // `real_imp` is unused with Miri, so silence warnings. #![cfg_attr(miri, allow(dead_code))] #![allow(internal_features)] -#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] #![warn(unreachable_pub)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 3a95b940221c2..3794b56c0898f 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -49,7 +49,7 @@ use alloc::boxed::Box; use core::any::Any; use core::ffi::{c_int, c_uint, c_void}; -use core::mem::{self, ManuallyDrop}; +use core::mem::ManuallyDrop; // NOTE(nbdd0121): The `canary` field is part of stable ABI. #[repr(C)] @@ -225,7 +225,7 @@ static mut CATCHABLE_TYPE: _CatchableType = _CatchableType { properties: 0, pType: ptr_t::null(), thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 }, - sizeOrOffset: mem::size_of::() as c_int, + sizeOrOffset: size_of::() as c_int, copyFunction: ptr_t::null(), }; diff --git a/library/proc_macro/Cargo.toml b/library/proc_macro/Cargo.toml index e54a50aa15c61..72cb4e4166f8e 100644 --- a/library/proc_macro/Cargo.toml +++ b/library/proc_macro/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "proc_macro" version = "0.0.0" -edition = "2021" +edition = "2024" [dependencies] std = { path = "../std" } diff --git a/library/proc_macro/src/bridge/selfless_reify.rs b/library/proc_macro/src/bridge/selfless_reify.rs index 312a79152e23b..b06434a5ffee2 100644 --- a/library/proc_macro/src/bridge/selfless_reify.rs +++ b/library/proc_macro/src/bridge/selfless_reify.rs @@ -50,7 +50,7 @@ macro_rules! define_reify_functions { >(f: F) -> $(extern $abi)? fn($($arg_ty),*) -> $ret_ty { // FIXME(eddyb) describe the `F` type (e.g. via `type_name::`) once panic // formatting becomes possible in `const fn`. - assert!(mem::size_of::() == 0, "selfless_reify: closure must be zero-sized"); + assert!(size_of::() == 0, "selfless_reify: closure must be zero-sized"); $(extern $abi)? fn wrapper< $($($param,)*)? diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml index 230e8051602e4..e075a38daea11 100644 --- a/library/profiler_builtins/Cargo.toml +++ b/library/profiler_builtins/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "profiler_builtins" version = "0.0.0" -edition = "2021" +edition = "2024" [lib] test = false diff --git a/library/rustc-std-workspace-alloc/Cargo.toml b/library/rustc-std-workspace-alloc/Cargo.toml index 049ca3e46b57d..5a177808d1bd8 100644 --- a/library/rustc-std-workspace-alloc/Cargo.toml +++ b/library/rustc-std-workspace-alloc/Cargo.toml @@ -5,7 +5,7 @@ license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ -edition = "2021" +edition = "2024" [lib] path = "lib.rs" diff --git a/library/rustc-std-workspace-core/Cargo.toml b/library/rustc-std-workspace-core/Cargo.toml index ff5cfcbd64144..9315c08a4d199 100644 --- a/library/rustc-std-workspace-core/Cargo.toml +++ b/library/rustc-std-workspace-core/Cargo.toml @@ -5,7 +5,7 @@ license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ -edition = "2021" +edition = "2024" [lib] path = "lib.rs" diff --git a/library/rustc-std-workspace-std/Cargo.toml b/library/rustc-std-workspace-std/Cargo.toml index 3a1dc2a02b557..f70994e1f8868 100644 --- a/library/rustc-std-workspace-std/Cargo.toml +++ b/library/rustc-std-workspace-std/Cargo.toml @@ -5,7 +5,7 @@ license = 'MIT OR Apache-2.0' description = """ Hack for the compiler's own build system """ -edition = "2021" +edition = "2024" [lib] path = "lib.rs" diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 228ee6eea05fa..9d9601b79a7ed 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -6,7 +6,7 @@ version = "0.0.0" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/rust.git" description = "The Rust Standard Library" -edition = "2021" +edition = "2024" autobenches = false [lib] @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.146" } +compiler_builtins = { version = "=0.1.151" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', @@ -35,7 +35,7 @@ miniz_oxide = { version = "0.8.0", optional = true, default-features = false } addr2line = { version = "0.24.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] -libc = { version = "0.2.169", default-features = false, features = [ +libc = { version = "0.2.171", default-features = false, features = [ 'rustc-dep-of-std', ], public = true } @@ -73,7 +73,7 @@ fortanix-sgx-abi = { version = "0.5.0", features = [ ], public = true } [target.'cfg(target_os = "hermit")'.dependencies] -hermit-abi = { version = "0.4.0", features = [ +hermit-abi = { version = "0.5.0", features = [ 'rustc-dep-of-std', ], public = true } @@ -159,8 +159,6 @@ test = true level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa", "aarch64-unknown-nto-qnx710_iosock", "x86_64-pc-nto-qnx710_iosock", "x86_64-pc-nto-qnx800","aarch64-unknown-nto-qnx800"))', - 'cfg(target_env, values("nto71_iosock", "nto80"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/std/build.rs b/library/std/build.rs index 8dc326a3dde6a..a0cfbc4685ee5 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -12,6 +12,11 @@ fn main() { .expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set") .parse() .unwrap(); + let target_features: Vec<_> = env::var("CARGO_CFG_TARGET_FEATURE") + .unwrap_or_default() + .split(",") + .map(ToOwned::to_owned) + .collect(); let is_miri = env::var_os("CARGO_CFG_MIRI").is_some(); println!("cargo:rustc-check-cfg=cfg(netbsd10)"); @@ -37,6 +42,7 @@ fn main() { || target_os == "fuchsia" || (target_vendor == "fortanix" && target_env == "sgx") || target_os == "hermit" + || target_os == "trusty" || target_os == "l4re" || target_os == "redox" || target_os == "haiku" @@ -101,13 +107,13 @@ fn main() { ("s390x", _) => false, // Unsupported ("arm64ec", _) => false, + // LLVM crash + ("aarch64", _) if !target_features.iter().any(|f| f == "neon") => false, // MinGW ABI bugs ("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false, // Infinite recursion ("csky", _) => false, ("hexagon", _) => false, - ("loongarch64", _) => false, - ("mips" | "mips64" | "mips32r6" | "mips64r6", _) => false, ("powerpc" | "powerpc64", _) => false, ("sparc" | "sparc64", _) => false, ("wasm32" | "wasm64", _) => false, diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index fc333d7ff3f95..3e641ac5d9041 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -432,6 +432,7 @@ mod helper { use super::*; pub(super) type LazyResolve = impl (FnOnce() -> Capture) + Send + Sync + UnwindSafe; + #[cfg_attr(not(bootstrap), define_opaque(LazyResolve))] pub(super) fn lazy_resolve(mut capture: Capture) -> LazyResolve { move || { // Use the global backtrace lock to synchronize this as it's a diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 6a0ff3a29e08f..2487f5a2a503f 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -208,20 +208,32 @@ use crate::ops::Index; /// # Usage in `const` and `static` /// /// As explained above, `HashMap` is randomly seeded: each `HashMap` instance uses a different seed, -/// which means that `HashMap::new` cannot be used in const context. To construct a `HashMap` in the -/// initializer of a `const` or `static` item, you will have to use a different hasher that does not -/// involve a random seed, as demonstrated in the following example. **A `HashMap` constructed this -/// way is not resistant against HashDoS!** +/// which means that `HashMap::new` normally cannot be used in a `const` or `static` initializer. /// +/// However, if you need to use a `HashMap` in a `const` or `static` initializer while retaining +/// random seed generation, you can wrap the `HashMap` in [`LazyLock`]. +/// +/// Alternatively, you can construct a `HashMap` in a `const` or `static` initializer using a different +/// hasher that does not rely on a random seed. **Be aware that a `HashMap` created this way is not +/// resistant to HashDoS attacks!** +/// +/// [`LazyLock`]: crate::sync::LazyLock /// ```rust /// use std::collections::HashMap; /// use std::hash::{BuildHasherDefault, DefaultHasher}; -/// use std::sync::Mutex; +/// use std::sync::{LazyLock, Mutex}; /// -/// const EMPTY_MAP: HashMap, BuildHasherDefault> = +/// // HashMaps with a fixed, non-random hasher +/// const NONRANDOM_EMPTY_MAP: HashMap, BuildHasherDefault> = /// HashMap::with_hasher(BuildHasherDefault::new()); -/// static MAP: Mutex, BuildHasherDefault>> = +/// static NONRANDOM_MAP: Mutex, BuildHasherDefault>> = /// Mutex::new(HashMap::with_hasher(BuildHasherDefault::new())); +/// +/// // HashMaps using LazyLock to retain random seeding +/// const RANDOM_EMPTY_MAP: LazyLock>> = +/// LazyLock::new(HashMap::new); +/// static RANDOM_MAP: LazyLock>>> = +/// LazyLock::new(|| Mutex::new(HashMap::new())); /// ``` #[cfg_attr(not(test), rustc_diagnostic_item = "HashMap")] @@ -656,7 +668,6 @@ impl HashMap { /// Splitting a map into even and odd keys, reusing the original map: /// /// ``` - /// #![feature(hash_extract_if)] /// use std::collections::HashMap; /// /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); @@ -672,7 +683,7 @@ impl HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - #[unstable(feature = "hash_extract_if", issue = "59618")] + #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -1024,7 +1035,7 @@ where /// ``` #[inline] #[doc(alias = "get_many_mut")] - #[stable(feature = "map_many_mut", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "map_many_mut", since = "1.86.0")] pub fn get_disjoint_mut( &mut self, ks: [&Q; N], @@ -1091,7 +1102,7 @@ where /// ``` #[inline] #[doc(alias = "get_many_unchecked_mut")] - #[stable(feature = "map_many_mut", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "map_many_mut", since = "1.86.0")] pub unsafe fn get_disjoint_unchecked_mut( &mut self, ks: [&Q; N], @@ -1279,69 +1290,6 @@ where } } -impl HashMap -where - S: BuildHasher, -{ - /// Creates a raw entry builder for the `HashMap`. - /// - /// Raw entries provide the lowest level of control for searching and - /// manipulating a map. They must be manually initialized with a hash and - /// then manually searched. After this, insertions into a vacant entry - /// still require an owned key to be provided. - /// - /// Raw entries are useful for such exotic situations as: - /// - /// * Hash memoization - /// * Deferring the creation of an owned key until it is known to be required - /// * Using a search key that doesn't work with the Borrow trait - /// * Using custom comparison logic without newtype wrappers - /// - /// Because raw entries provide much more low-level control, it's much easier - /// to put the `HashMap` into an inconsistent state which, while memory-safe, - /// will cause the map to produce seemingly random results. Higher-level and - /// more foolproof APIs like `entry` should be preferred when possible. - /// - /// In particular, the hash used to initialize the raw entry must still be - /// consistent with the hash of the key that is ultimately stored in the entry. - /// This is because implementations of `HashMap` may need to recompute hashes - /// when resizing, at which point only the keys are available. - /// - /// Raw entries give mutable access to the keys. This must not be used - /// to modify how the key would compare or hash, as the map will not re-evaluate - /// where the key should go, meaning the keys may become "lost" if their - /// location does not reflect their state. For instance, if you change a key - /// so that the map now contains keys which compare equal, search may start - /// acting erratically, with two keys randomly masking each other. Implementations - /// are free to assume this doesn't happen (within the limits of memory-safety). - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn raw_entry_mut(&mut self) -> RawEntryBuilderMut<'_, K, V, S> { - RawEntryBuilderMut { map: self } - } - - /// Creates a raw immutable entry builder for the `HashMap`. - /// - /// Raw entries provide the lowest level of control for searching and - /// manipulating a map. They must be manually initialized with a hash and - /// then manually searched. - /// - /// This is useful for - /// * Hash memoization - /// * Using a search key that doesn't work with the Borrow trait - /// * Using custom comparison logic without newtype wrappers - /// - /// Unless you are in such a situation, higher-level and more foolproof APIs like - /// `get` should be preferred. - /// - /// Immutable raw entries have very limited use; you might instead want `raw_entry_mut`. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn raw_entry(&self) -> RawEntryBuilder<'_, K, V, S> { - RawEntryBuilder { map: self } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Clone for HashMap where @@ -1722,8 +1670,6 @@ impl<'a, K, V> Drain<'a, K, V> { /// # Example /// /// ``` -/// #![feature(hash_extract_if)] -/// /// use std::collections::HashMap; /// /// let mut map = HashMap::from([ @@ -1731,7 +1677,7 @@ impl<'a, K, V> Drain<'a, K, V> { /// ]); /// let iter = map.extract_if(|_k, v| *v % 2 == 0); /// ``` -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf<'a, K, V, F> where @@ -1831,404 +1777,6 @@ impl Default for IntoValues { } } -/// A builder for computing where in a HashMap a key-value pair would be stored. -/// -/// See the [`HashMap::raw_entry_mut`] docs for usage examples. -#[unstable(feature = "hash_raw_entry", issue = "56167")] -pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { - map: &'a mut HashMap, -} - -/// A view into a single entry in a map, which may either be vacant or occupied. -/// -/// This is a lower-level version of [`Entry`]. -/// -/// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], -/// then calling one of the methods of that [`RawEntryBuilderMut`]. -/// -/// [`raw_entry_mut`]: HashMap::raw_entry_mut -#[unstable(feature = "hash_raw_entry", issue = "56167")] -pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { - /// An occupied entry. - Occupied(RawOccupiedEntryMut<'a, K, V, S>), - /// A vacant entry. - Vacant(RawVacantEntryMut<'a, K, V, S>), -} - -/// A view into an occupied entry in a `HashMap`. -/// It is part of the [`RawEntryMut`] enum. -#[unstable(feature = "hash_raw_entry", issue = "56167")] -pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a, S: 'a> { - base: base::RawOccupiedEntryMut<'a, K, V, S>, -} - -/// A view into a vacant entry in a `HashMap`. -/// It is part of the [`RawEntryMut`] enum. -#[unstable(feature = "hash_raw_entry", issue = "56167")] -pub struct RawVacantEntryMut<'a, K: 'a, V: 'a, S: 'a> { - base: base::RawVacantEntryMut<'a, K, V, S>, -} - -/// A builder for computing where in a HashMap a key-value pair would be stored. -/// -/// See the [`HashMap::raw_entry`] docs for usage examples. -#[unstable(feature = "hash_raw_entry", issue = "56167")] -pub struct RawEntryBuilder<'a, K: 'a, V: 'a, S: 'a> { - map: &'a HashMap, -} - -impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> -where - S: BuildHasher, -{ - /// Creates a `RawEntryMut` from the given key. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn from_key(self, k: &Q) -> RawEntryMut<'a, K, V, S> - where - K: Borrow, - Q: Hash + Eq, - { - map_raw_entry(self.map.base.raw_entry_mut().from_key(k)) - } - - /// Creates a `RawEntryMut` from the given key and its hash. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> RawEntryMut<'a, K, V, S> - where - K: Borrow, - Q: Eq, - { - map_raw_entry(self.map.base.raw_entry_mut().from_key_hashed_nocheck(hash, k)) - } - - /// Creates a `RawEntryMut` from the given hash. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn from_hash(self, hash: u64, is_match: F) -> RawEntryMut<'a, K, V, S> - where - for<'b> F: FnMut(&'b K) -> bool, - { - map_raw_entry(self.map.base.raw_entry_mut().from_hash(hash, is_match)) - } -} - -impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> -where - S: BuildHasher, -{ - /// Access an entry by key. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn from_key(self, k: &Q) -> Option<(&'a K, &'a V)> - where - K: Borrow, - Q: Hash + Eq, - { - self.map.base.raw_entry().from_key(k) - } - - /// Access an entry by a key and its hash. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn from_key_hashed_nocheck(self, hash: u64, k: &Q) -> Option<(&'a K, &'a V)> - where - K: Borrow, - Q: Hash + Eq, - { - self.map.base.raw_entry().from_key_hashed_nocheck(hash, k) - } - - /// Access an entry by hash. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn from_hash(self, hash: u64, is_match: F) -> Option<(&'a K, &'a V)> - where - F: FnMut(&K) -> bool, - { - self.map.base.raw_entry().from_hash(hash, is_match) - } -} - -impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { - /// Ensures a value is in the entry by inserting the default if empty, and returns - /// mutable references to the key and value in the entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(hash_raw_entry)] - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// - /// map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 3); - /// assert_eq!(map["poneyland"], 3); - /// - /// *map.raw_entry_mut().from_key("poneyland").or_insert("poneyland", 10).1 *= 2; - /// assert_eq!(map["poneyland"], 6); - /// ``` - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn or_insert(self, default_key: K, default_val: V) -> (&'a mut K, &'a mut V) - where - K: Hash, - S: BuildHasher, - { - match self { - RawEntryMut::Occupied(entry) => entry.into_key_value(), - RawEntryMut::Vacant(entry) => entry.insert(default_key, default_val), - } - } - - /// Ensures a value is in the entry by inserting the result of the default function if empty, - /// and returns mutable references to the key and value in the entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(hash_raw_entry)] - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, String> = HashMap::new(); - /// - /// map.raw_entry_mut().from_key("poneyland").or_insert_with(|| { - /// ("poneyland", "hoho".to_string()) - /// }); - /// - /// assert_eq!(map["poneyland"], "hoho".to_string()); - /// ``` - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn or_insert_with(self, default: F) -> (&'a mut K, &'a mut V) - where - F: FnOnce() -> (K, V), - K: Hash, - S: BuildHasher, - { - match self { - RawEntryMut::Occupied(entry) => entry.into_key_value(), - RawEntryMut::Vacant(entry) => { - let (k, v) = default(); - entry.insert(k, v) - } - } - } - - /// Provides in-place mutable access to an occupied entry before any - /// potential inserts into the map. - /// - /// # Examples - /// - /// ``` - /// #![feature(hash_raw_entry)] - /// use std::collections::HashMap; - /// - /// let mut map: HashMap<&str, u32> = HashMap::new(); - /// - /// map.raw_entry_mut() - /// .from_key("poneyland") - /// .and_modify(|_k, v| { *v += 1 }) - /// .or_insert("poneyland", 42); - /// assert_eq!(map["poneyland"], 42); - /// - /// map.raw_entry_mut() - /// .from_key("poneyland") - /// .and_modify(|_k, v| { *v += 1 }) - /// .or_insert("poneyland", 0); - /// assert_eq!(map["poneyland"], 43); - /// ``` - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn and_modify(self, f: F) -> Self - where - F: FnOnce(&mut K, &mut V), - { - match self { - RawEntryMut::Occupied(mut entry) => { - { - let (k, v) = entry.get_key_value_mut(); - f(k, v); - } - RawEntryMut::Occupied(entry) - } - RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), - } - } -} - -impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { - /// Gets a reference to the key in the entry. - #[inline] - #[must_use] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn key(&self) -> &K { - self.base.key() - } - - /// Gets a mutable reference to the key in the entry. - #[inline] - #[must_use] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn key_mut(&mut self) -> &mut K { - self.base.key_mut() - } - - /// Converts the entry into a mutable reference to the key in the entry - /// with a lifetime bound to the map itself. - #[inline] - #[must_use = "`self` will be dropped if the result is not used"] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn into_key(self) -> &'a mut K { - self.base.into_key() - } - - /// Gets a reference to the value in the entry. - #[inline] - #[must_use] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn get(&self) -> &V { - self.base.get() - } - - /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry - /// with a lifetime bound to the map itself. - #[inline] - #[must_use = "`self` will be dropped if the result is not used"] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn into_mut(self) -> &'a mut V { - self.base.into_mut() - } - - /// Gets a mutable reference to the value in the entry. - #[inline] - #[must_use] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn get_mut(&mut self) -> &mut V { - self.base.get_mut() - } - - /// Gets a reference to the key and value in the entry. - #[inline] - #[must_use] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn get_key_value(&mut self) -> (&K, &V) { - self.base.get_key_value() - } - - /// Gets a mutable reference to the key and value in the entry. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn get_key_value_mut(&mut self) -> (&mut K, &mut V) { - self.base.get_key_value_mut() - } - - /// Converts the `OccupiedEntry` into a mutable reference to the key and value in the entry - /// with a lifetime bound to the map itself. - #[inline] - #[must_use = "`self` will be dropped if the result is not used"] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn into_key_value(self) -> (&'a mut K, &'a mut V) { - self.base.into_key_value() - } - - /// Sets the value of the entry, and returns the entry's old value. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn insert(&mut self, value: V) -> V { - self.base.insert(value) - } - - /// Sets the value of the entry, and returns the entry's old value. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn insert_key(&mut self, key: K) -> K { - self.base.insert_key(key) - } - - /// Takes the value out of the entry, and returns it. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn remove(self) -> V { - self.base.remove() - } - - /// Take the ownership of the key and value from the map. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn remove_entry(self) -> (K, V) { - self.base.remove_entry() - } -} - -impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { - /// Sets the value of the entry with the `VacantEntry`'s key, - /// and returns a mutable reference to it. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn insert(self, key: K, value: V) -> (&'a mut K, &'a mut V) - where - K: Hash, - S: BuildHasher, - { - self.base.insert(key, value) - } - - /// Sets the value of the entry with the VacantEntry's key, - /// and returns a mutable reference to it. - #[inline] - #[unstable(feature = "hash_raw_entry", issue = "56167")] - pub fn insert_hashed_nocheck(self, hash: u64, key: K, value: V) -> (&'a mut K, &'a mut V) - where - K: Hash, - S: BuildHasher, - { - self.base.insert_hashed_nocheck(hash, key, value) - } -} - -#[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawEntryBuilderMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawEntryBuilder").finish_non_exhaustive() - } -} - -#[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawEntryMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - RawEntryMut::Vacant(ref v) => f.debug_tuple("RawEntry").field(v).finish(), - RawEntryMut::Occupied(ref o) => f.debug_tuple("RawEntry").field(o).finish(), - } - } -} - -#[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawOccupiedEntryMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawOccupiedEntryMut") - .field("key", self.key()) - .field("value", self.get()) - .finish_non_exhaustive() - } -} - -#[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawVacantEntryMut<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawVacantEntryMut").finish_non_exhaustive() - } -} - -#[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawEntryBuilder<'_, K, V, S> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RawEntryBuilder").finish_non_exhaustive() - } -} - /// A view into a single entry in a map, which may either be vacant or occupied. /// /// This `enum` is constructed from the [`entry`] method on [`HashMap`]. @@ -2746,7 +2294,7 @@ where } } -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -2763,10 +2311,10 @@ where } } -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -3301,16 +2849,6 @@ pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReser } } -#[inline] -fn map_raw_entry<'a, K: 'a, V: 'a, S: 'a>( - raw: base::RawEntryMut<'a, K, V, S>, -) -> RawEntryMut<'a, K, V, S> { - match raw { - base::RawEntryMut::Occupied(base) => RawEntryMut::Occupied(RawOccupiedEntryMut { base }), - base::RawEntryMut::Vacant(base) => RawEntryMut::Vacant(RawVacantEntryMut { base }), - } -} - #[allow(dead_code)] fn assert_covariance() { fn map_key<'new>(v: HashMap<&'static str, u8>) -> HashMap<&'new str, u8> { diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index a275488a55602..9f7df20a1d7e4 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -852,99 +852,6 @@ fn test_try_reserve() { } } -#[test] -fn test_raw_entry() { - use super::RawEntryMut::{Occupied, Vacant}; - - let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let compute_hash = |map: &HashMap, k: i32| -> u64 { - use core::hash::{BuildHasher, Hash, Hasher}; - - let mut hasher = map.hasher().build_hasher(); - k.hash(&mut hasher); - hasher.finish() - }; - - // Existing key (insert) - match map.raw_entry_mut().from_key(&1) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - assert_eq!(view.get(), &10); - assert_eq!(view.insert(100), 10); - } - } - let hash1 = compute_hash(&map, 1); - assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100)); - assert_eq!(map.len(), 6); - - // Existing key (update) - match map.raw_entry_mut().from_key(&2) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - let v = view.get_mut(); - let new_v = (*v) * 10; - *v = new_v; - } - } - let hash2 = compute_hash(&map, 2); - assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200)); - assert_eq!(map.len(), 6); - - // Existing key (take) - let hash3 = compute_hash(&map, 3); - match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { - Vacant(_) => unreachable!(), - Occupied(view) => { - assert_eq!(view.remove_entry(), (3, 30)); - } - } - assert_eq!(map.raw_entry().from_key(&3), None); - assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); - assert_eq!(map.len(), 5); - - // Nonexistent key (insert) - match map.raw_entry_mut().from_key(&10) { - Occupied(_) => unreachable!(), - Vacant(view) => { - assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); - } - } - assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); - assert_eq!(map.len(), 6); - - // Ensure all lookup methods produce equivalent results. - for k in 0..12 { - let hash = compute_hash(&map, k); - let v = map.get(&k).cloned(); - let kv = v.as_ref().map(|v| (&k, v)); - - assert_eq!(map.raw_entry().from_key(&k), kv); - assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); - - match map.raw_entry_mut().from_key(&k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - match map.raw_entry_mut().from_hash(hash, |q| *q == k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - } -} - mod test_extract_if { use super::*; use crate::panic::{AssertUnwindSafe, catch_unwind}; diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index c265d42d06a9f..a547a9943c1a0 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -293,7 +293,6 @@ impl HashSet { /// Splitting a set into even and odd values, reusing the original set: /// /// ``` - /// #![feature(hash_extract_if)] /// use std::collections::HashSet; /// /// let mut set: HashSet = (0..8).collect(); @@ -309,7 +308,7 @@ impl HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - #[unstable(feature = "hash_extract_if", issue = "59618")] + #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, @@ -1385,15 +1384,13 @@ pub struct Drain<'a, K: 'a> { /// # Examples /// /// ``` -/// #![feature(hash_extract_if)] -/// /// use std::collections::HashSet; /// /// let mut a = HashSet::from([1, 2, 3]); /// /// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); /// ``` -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] pub struct ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, @@ -1676,7 +1673,7 @@ impl fmt::Debug for Drain<'_, K> { } } -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, @@ -1693,10 +1690,10 @@ where } } -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} -#[unstable(feature = "hash_extract_if", issue = "59618")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F> where F: FnMut(&K) -> bool, diff --git a/library/std/src/env.rs b/library/std/src/env.rs index adbd68896241c..6961fa8ea947f 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -202,6 +202,9 @@ impl fmt::Debug for VarsOs { /// Returns [`VarError::NotUnicode`] if the variable's value is not valid /// Unicode. If this is not desired, consider using [`var_os`]. /// +/// Use [`env!`] or [`option_env!`] instead if you want to check environment +/// variables at compile time. +/// /// # Examples /// /// ``` @@ -641,11 +644,6 @@ impl Error for JoinPathsError { /// None => println!("Impossible to get your home dir!"), /// } /// ``` -#[deprecated( - since = "1.29.0", - note = "This function's behavior may be unexpected on Windows. \ - Consider using a crate from crates.io instead." -)] #[must_use] #[stable(feature = "env", since = "1.0.0")] pub fn home_dir() -> Option { @@ -668,7 +666,9 @@ pub fn home_dir() -> Option { /// On Unix, returns the value of the `TMPDIR` environment variable if it is /// set, otherwise the value is OS-specific: /// - On Android, there is no global temporary folder (it is usually allocated -/// per-app), it returns `/data/local/tmp`. +/// per-app), it will return the application's cache dir if the program runs +/// in application's namespace and system version is Android 13 (or above), or +/// `/data/local/tmp` otherwise. /// - On Darwin-based OSes (macOS, iOS, etc) it returns the directory provided /// by `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)`, as recommended by [Apple's /// security guidelines][appledoc]. diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs index 14ce2b69ca427..974514c9c4556 100644 --- a/library/std/src/f128.rs +++ b/library/std/src/f128.rs @@ -126,7 +126,7 @@ impl f128 { #[unstable(feature = "f128", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn round_ties_even(self) -> f128 { - unsafe { intrinsics::rintf128(self) } + intrinsics::round_ties_even_f128(self) } /// Returns the integer part of `self`. diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs index 0af69dff05add..c3b51bf31de70 100644 --- a/library/std/src/f16.rs +++ b/library/std/src/f16.rs @@ -126,7 +126,7 @@ impl f16 { #[unstable(feature = "f16", issue = "116909")] #[must_use = "method returns a new number and does not mutate the original value"] pub fn round_ties_even(self) -> f16 { - unsafe { intrinsics::rintf16(self) } + intrinsics::round_ties_even_f16(self) } /// Returns the integer part of `self`. diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index 295eee8700af2..19fb24c8ee26c 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -122,7 +122,7 @@ impl f32 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f32 { - unsafe { intrinsics::rintf32(self) } + intrinsics::round_ties_even_f32(self) } /// Returns the integer part of `self`. diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 0d713ecbc7312..f1c3cb561271a 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -122,7 +122,7 @@ impl f64 { #[stable(feature = "round_ties_even", since = "1.77.0")] #[inline] pub fn round_ties_even(self) -> f64 { - unsafe { intrinsics::rintf64(self) } + intrinsics::round_ties_even_f64(self) } /// Returns the integer part of `self`. diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index f4a02802336d5..aa25ff5293c71 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -257,7 +257,30 @@ impl OsString { #[inline] #[rustc_confusables("append", "put")] pub fn push>(&mut self, s: T) { - self.inner.push_slice(&s.as_ref().inner) + trait SpecPushTo { + fn spec_push_to(&self, buf: &mut OsString); + } + + impl> SpecPushTo for T { + #[inline] + default fn spec_push_to(&self, buf: &mut OsString) { + buf.inner.push_slice(&self.as_ref().inner); + } + } + + // Use a more efficient implementation when the string is UTF-8. + macro spec_str($T:ty) { + impl SpecPushTo for $T { + #[inline] + fn spec_push_to(&self, buf: &mut OsString) { + buf.inner.push_str(self); + } + } + } + spec_str!(str); + spec_str!(String); + + s.spec_push_to(self) } /// Creates a new `OsString` with at least the given capacity. @@ -587,7 +610,30 @@ impl> From<&T> for OsString { /// Copies any value implementing [AsRef]<[OsStr]> /// into a newly allocated [`OsString`]. fn from(s: &T) -> OsString { - s.as_ref().to_os_string() + trait SpecToOsString { + fn spec_to_os_string(&self) -> OsString; + } + + impl> SpecToOsString for T { + #[inline] + default fn spec_to_os_string(&self) -> OsString { + self.as_ref().to_os_string() + } + } + + // Preserve the known-UTF-8 property for strings. + macro spec_str($T:ty) { + impl SpecToOsString for $T { + #[inline] + fn spec_to_os_string(&self) -> OsString { + OsString::from(String::from(self)) + } + } + } + spec_str!(str); + spec_str!(String); + + s.spec_to_os_string() } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 57e235c3efe1d..f9a360585e852 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -14,7 +14,8 @@ target_os = "emscripten", target_os = "wasi", target_env = "sgx", - target_os = "xous" + target_os = "xous", + target_os = "trusty", )) ))] mod tests; @@ -2446,7 +2447,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// # Platform-specific behavior /// /// This function currently corresponds to the `rename` function on Unix -/// and the `SetFileInformationByHandle` function on Windows. +/// and the `MoveFileExW` or `SetFileInformationByHandle` function on Windows. /// /// Because of this, the behavior when both `from` and `to` exist differs. On /// Unix, if `from` is a directory, `to` must also be an (empty) directory. If @@ -2857,9 +2858,11 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// See [`fs::remove_file`] and [`fs::remove_dir`]. /// -/// `remove_dir_all` will fail if `remove_dir` or `remove_file` fail on any constituent paths, including the root `path`. -/// As a result, the directory you are deleting must exist, meaning that this function is not idempotent. -/// Additionally, `remove_dir_all` will also fail if the `path` is not a directory. +/// [`remove_dir_all`] will fail if [`remove_dir`] or [`remove_file`] fail on *any* constituent +/// paths, *including* the root `path`. Consequently, +/// +/// - The directory you are deleting *must* exist, meaning that this function is *not idempotent*. +/// - [`remove_dir_all`] will fail if the `path` is *not* a directory. /// /// Consider ignoring the error if validating the removal is not required for your use case. /// diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 1a266f71965d9..6dd18e4f4c837 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1878,7 +1878,7 @@ fn windows_unix_socket_exists() { let bytes = socket_path.as_os_str().as_encoded_bytes(); let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()); addr.sun_path[..bytes.len()].copy_from_slice(bytes); - let len = mem::size_of_val(&addr) as i32; + let len = size_of_val(&addr) as i32; let result = c::bind(socket, (&raw const addr).cast::(), len); c::closesocket(socket); assert_eq!(result, 0); @@ -1914,8 +1914,11 @@ fn test_hidden_file_truncation() { assert_eq!(metadata.len(), 0); } +// See https://github.com/rust-lang/rust/pull/131072 for more details about why +// these two tests are disabled under Windows 7 here. #[cfg(windows)] #[test] +#[cfg_attr(target_vendor = "win7", ignore = "Unsupported under Windows 7.")] fn test_rename_file_over_open_file() { // Make sure that std::fs::rename works if the target file is already opened with FILE_SHARE_DELETE. See #123985. let tmpdir = tmpdir(); @@ -1940,6 +1943,7 @@ fn test_rename_file_over_open_file() { #[test] #[cfg(windows)] +#[cfg_attr(target_vendor = "win7", ignore = "Unsupported under Windows 7.")] fn test_rename_directory_to_non_empty_directory() { // Renaming a directory over a non-empty existing directory should fail on Windows. let tmpdir: TempDir = tmpdir(); @@ -1958,6 +1962,10 @@ fn test_rename_directory_to_non_empty_directory() { #[test] fn test_rename_symlink() { let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + let original = tmpdir.join("original"); let dest = tmpdir.join("dest"); let not_exist = Path::new("does not exist"); diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index 8b46738ab8aee..40441dc057d0d 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -109,25 +109,29 @@ impl BufReader { /// /// `n` must be less than or equal to `capacity`. /// - /// the returned slice may be less than `n` bytes long if + /// The returned slice may be less than `n` bytes long if /// end of file is reached. /// + /// After calling this method, you may call [`consume`](BufRead::consume) + /// with a value less than or equal to `n` to advance over some or all of + /// the returned bytes. + /// /// ## Examples /// /// ```rust /// #![feature(bufreader_peek)] /// use std::io::{Read, BufReader}; /// - /// let mut bytes = &b"oh, hello"[..]; + /// let mut bytes = &b"oh, hello there"[..]; /// let mut rdr = BufReader::with_capacity(6, &mut bytes); /// assert_eq!(rdr.peek(2).unwrap(), b"oh"); /// let mut buf = [0; 4]; /// rdr.read(&mut buf[..]).unwrap(); /// assert_eq!(&buf, b"oh, "); - /// assert_eq!(rdr.peek(2).unwrap(), b"he"); + /// assert_eq!(rdr.peek(5).unwrap(), b"hello"); /// let mut s = String::new(); /// rdr.read_to_string(&mut s).unwrap(); - /// assert_eq!(&s, "hello"); + /// assert_eq!(&s, "hello there"); /// assert_eq!(rdr.peek(1).unwrap().len(), 0); /// ``` #[unstable(feature = "bufreader_peek", issue = "128405")] diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 5251cc302cb49..9fd2472ebdfdb 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -109,8 +109,8 @@ impl Buffer { /// Read more bytes into the buffer without discarding any of its contents pub fn read_more(&mut self, mut reader: impl Read) -> io::Result { - let mut buf = BorrowedBuf::from(&mut self.buf[self.pos..]); - let old_init = self.initialized - self.pos; + let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]); + let old_init = self.initialized - self.filled; unsafe { buf.set_init(old_init); } diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 606099c8bc67a..d7131e2fe92fd 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -153,7 +153,7 @@ impl Cursor { /// let reference = buff.get_mut(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_mut_cursor", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_mut_cursor", since = "1.86.0")] pub const fn get_mut(&mut self) -> &mut T { &mut self.inner } @@ -201,7 +201,7 @@ impl Cursor { /// assert_eq!(buff.position(), 4); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_mut_cursor", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "const_mut_cursor", since = "1.86.0")] pub const fn set_position(&mut self, pos: u64) { self.pos = pos; } @@ -439,6 +439,27 @@ fn slice_write_vectored( Ok(nwritten) } +#[inline] +fn slice_write_all(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<()> { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } +} + +#[inline] +fn slice_write_all_vectored( + pos_mut: &mut u64, + slice: &mut [u8], + bufs: &[IoSlice<'_>], +) -> io::Result<()> { + for buf in bufs { + let n = slice_write(pos_mut, slice, buf)?; + if n < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) +} + /// Reserves the required space, and pads the vec with 0s if necessary. fn reserve_and_pad( pos_mut: &mut u64, @@ -481,9 +502,12 @@ fn reserve_and_pad( Ok(pos) } -/// Writes the slice to the vec without allocating -/// # Safety: vec must have buf.len() spare capacity -unsafe fn vec_write_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize +/// Writes the slice to the vec without allocating. +/// +/// # Safety +/// +/// `vec` must have `buf.len()` spare capacity. +unsafe fn vec_write_all_unchecked(pos: usize, vec: &mut Vec, buf: &[u8]) -> usize where A: Allocator, { @@ -492,7 +516,7 @@ where pos + buf.len() } -/// Resizing write implementation for [`Cursor`] +/// Resizing `write_all` implementation for [`Cursor`]. /// /// Cursor is allowed to have a pre-allocated and initialised /// vector body, but with a position of 0. This means the [`Write`] @@ -501,7 +525,7 @@ where /// This also allows for the vec body to be empty, but with a position of N. /// This means that [`Write`] will pad the vec with 0 initially, /// before writing anything from that point -fn vec_write(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result +fn vec_write_all(pos_mut: &mut u64, vec: &mut Vec, buf: &[u8]) -> io::Result where A: Allocator, { @@ -512,7 +536,7 @@ where // Safety: we have ensured that the capacity is available // and that all bytes get written up to pos unsafe { - pos = vec_write_unchecked(pos, vec, buf); + pos = vec_write_all_unchecked(pos, vec, buf); if pos > vec.len() { vec.set_len(pos); } @@ -523,7 +547,7 @@ where Ok(buf_len) } -/// Resizing write_vectored implementation for [`Cursor`] +/// Resizing `write_all_vectored` implementation for [`Cursor`]. /// /// Cursor is allowed to have a pre-allocated and initialised /// vector body, but with a position of 0. This means the [`Write`] @@ -532,7 +556,7 @@ where /// This also allows for the vec body to be empty, but with a position of N. /// This means that [`Write`] will pad the vec with 0 initially, /// before writing anything from that point -fn vec_write_vectored( +fn vec_write_all_vectored( pos_mut: &mut u64, vec: &mut Vec, bufs: &[IoSlice<'_>], @@ -550,7 +574,7 @@ where // and that all bytes get written up to the last pos unsafe { for buf in bufs { - pos = vec_write_unchecked(pos, vec, buf); + pos = vec_write_all_unchecked(pos, vec, buf); } if pos > vec.len() { vec.set_len(pos); @@ -579,6 +603,16 @@ impl Write for Cursor<&mut [u8]> { true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -591,11 +625,11 @@ where A: Allocator, { fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, self.inner, buf) + vec_write_all(&mut self.pos, self.inner, buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - vec_write_vectored(&mut self.pos, self.inner, bufs) + vec_write_all_vectored(&mut self.pos, self.inner, bufs) } #[inline] @@ -603,6 +637,16 @@ where true } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + vec_write_all(&mut self.pos, self.inner, buf)?; + Ok(()) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + vec_write_all_vectored(&mut self.pos, self.inner, bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -615,11 +659,11 @@ where A: Allocator, { fn write(&mut self, buf: &[u8]) -> io::Result { - vec_write(&mut self.pos, &mut self.inner, buf) + vec_write_all(&mut self.pos, &mut self.inner, buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - vec_write_vectored(&mut self.pos, &mut self.inner, bufs) + vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs) } #[inline] @@ -627,6 +671,16 @@ where true } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + vec_write_all(&mut self.pos, &mut self.inner, buf)?; + Ok(()) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + vec_write_all_vectored(&mut self.pos, &mut self.inner, bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -653,6 +707,16 @@ where true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -676,6 +740,16 @@ impl Write for Cursor<[u8; N]> { true } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + slice_write_all(&mut self.pos, &mut self.inner, buf) + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + slice_write_all_vectored(&mut self.pos, &mut self.inner, bufs) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index 30bc0e3b08833..8472f90305007 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -83,7 +83,7 @@ impl Error { pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!( ErrorKind::NotFound, - "The number of hardware threads is not known for the target platform", + "the number of hardware threads is not known for the target platform", ); pub(crate) const UNSUPPORTED_PLATFORM: Self = @@ -373,8 +373,8 @@ pub enum ErrorKind { TooManyLinks, /// A filename was invalid. /// - /// This error can also cause if it exceeded the filename length limit. - #[unstable(feature = "io_error_more", issue = "86442")] + /// This error can also occur if a length limit for a name was exceeded. + #[stable(feature = "io_error_invalid_filename", since = "CURRENT_RUSTC_VERSION")] InvalidFilename, /// Program argument list too long. /// diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs index edac6563478cd..3e4029768eb85 100644 --- a/library/std/src/io/error/tests.rs +++ b/library/std/src/io/error/tests.rs @@ -1,6 +1,5 @@ use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error}; use crate::assert_matches::assert_matches; -use crate::mem::size_of; use crate::sys::decode_error_kind; use crate::sys::os::error_string; use crate::{error, fmt}; diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 8239b29884e8e..d0245f3d4984c 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -455,7 +455,17 @@ impl Write for &mut [u8] { #[inline] fn write_all(&mut self, data: &[u8]) -> io::Result<()> { - if self.write(data)? == data.len() { Ok(()) } else { Err(io::Error::WRITE_ALL_EOF) } + if self.write(data)? < data.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) } #[inline] @@ -495,6 +505,12 @@ impl Write for Vec { Ok(()) } + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -515,6 +531,7 @@ impl Read for VecDeque { Ok(n) } + #[inline] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { let (front, back) = self.as_slices(); @@ -547,6 +564,7 @@ impl Read for VecDeque { Ok(()) } + #[inline] fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> { let len = cursor.capacity(); let (front, back) = self.as_slices(); @@ -638,6 +656,12 @@ impl Write for VecDeque { Ok(()) } + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + self.write_vectored(bufs)?; + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) @@ -646,12 +670,46 @@ impl Write for VecDeque { #[unstable(feature = "read_buf", issue = "78485")] impl<'a> io::Write for core::io::BorrowedCursor<'a> { + #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { let amt = cmp::min(buf.len(), self.capacity()); self.append(&buf[..amt]); Ok(amt) } + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut nwritten = 0; + for buf in bufs { + let n = self.write(buf)?; + nwritten += n; + if n < buf.len() { + break; + } + } + Ok(nwritten) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + if self.write(buf)? < buf.len() { Err(io::Error::WRITE_ALL_EOF) } else { Ok(()) } + } + + #[inline] + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + for buf in bufs { + if self.write(buf)? < buf.len() { + return Err(io::Error::WRITE_ALL_EOF); + } + } + Ok(()) + } + #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 980ea1478e084..7f610bc88bfd7 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -2534,7 +2534,7 @@ pub trait BufRead: Read { fn read_line(&mut self, buf: &mut String) -> Result { // Note that we are not calling the `.read_until` method here, but // rather our hardcoded implementation. For more details as to why, see - // the comments in `read_to_end`. + // the comments in `default_read_to_string`. unsafe { append_to_string(buf, |b| read_until(self, b'\n', b)) } } diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 661c422811abb..ce46241f8e84d 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -20,7 +20,7 @@ type LocalStream = Arc>>; thread_local! { /// Used by the test crate to capture the output of the print macros and panics. - static OUTPUT_CAPTURE: Cell> = { + static OUTPUT_CAPTURE: Cell> = const { Cell::new(None) } } @@ -575,6 +575,11 @@ impl fmt::Debug for StdinLock<'_> { /// output stream. Access is also synchronized via a lock and explicit control /// over locking is available via the [`lock`] method. /// +/// By default, the handle is line-buffered when connected to a terminal, meaning +/// it flushes automatically when a newline (`\n`) is encountered. For immediate +/// output, you can manually call the [`flush`] method. When the handle goes out +/// of scope, the buffer is automatically flushed. +/// /// Created by the [`io::stdout`] method. /// /// ### Note: Windows Portability Considerations @@ -590,6 +595,7 @@ impl fmt::Debug for StdinLock<'_> { /// standard library or via raw Windows API calls, will fail. /// /// [`lock`]: Stdout::lock +/// [`flush`]: Write::flush /// [`io::stdout`]: stdout #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdout { @@ -604,6 +610,11 @@ pub struct Stdout { /// This handle implements the [`Write`] trait, and is constructed via /// the [`Stdout::lock`] method. See its documentation for more. /// +/// By default, the handle is line-buffered when connected to a terminal, meaning +/// it flushes automatically when a newline (`\n`) is encountered. For immediate +/// output, you can manually call the [`flush`] method. When the handle goes out +/// of scope, the buffer is automatically flushed. +/// /// ### Note: Windows Portability Considerations /// /// When operating in a console, the Windows implementation of this stream does not support @@ -615,6 +626,8 @@ pub struct Stdout { /// the contained handle will be null. In such cases, the standard library's `Read` and /// `Write` will do nothing and silently succeed. All other I/O operations, via the /// standard library or via raw Windows API calls, will fail. +/// +/// [`flush`]: Write::flush #[must_use = "if unused stdout will immediately unlock"] #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { @@ -629,6 +642,11 @@ static STDOUT: OnceLock>>> = OnceLoc /// is synchronized via a mutex. If you need more explicit control over /// locking, see the [`Stdout::lock`] method. /// +/// By default, the handle is line-buffered when connected to a terminal, meaning +/// it flushes automatically when a newline (`\n`) is encountered. For immediate +/// output, you can manually call the [`flush`] method. When the handle goes out +/// of scope, the buffer is automatically flushed. +/// /// ### Note: Windows Portability Considerations /// /// When operating in a console, the Windows implementation of this stream does not support @@ -669,6 +687,22 @@ static STDOUT: OnceLock>>> = OnceLoc /// Ok(()) /// } /// ``` +/// +/// Ensuring output is flushed immediately: +/// +/// ```no_run +/// use std::io::{self, Write}; +/// +/// fn main() -> io::Result<()> { +/// let mut stdout = io::stdout(); +/// stdout.write_all(b"hello, ")?; +/// stdout.flush()?; // Manual flush +/// stdout.write_all(b"world!\n")?; // Automatically flushed +/// Ok(()) +/// } +/// ``` +/// +/// [`flush`]: Write::flush #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "io_stdout")] diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f64f034cce779..fd962b0415c7d 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -811,13 +811,17 @@ fn read_to_end_error() { } #[test] -// Miri does not support signalling OOM -#[cfg_attr(miri, ignore)] -// 64-bit only to be sure the allocator will fail fast on an impossible to satisfy size -#[cfg(target_pointer_width = "64")] fn try_oom_error() { - let mut v = Vec::::new(); - let reserve_err = v.try_reserve(isize::MAX as usize - 1).unwrap_err(); + use alloc::alloc::Layout; + use alloc::collections::{TryReserveError, TryReserveErrorKind}; + + // We simulate a `Vec::try_reserve` error rather than attempting a huge size for real. This way + // we're not subject to the whims of optimization that might skip the actual allocation, and it + // also works for 32-bit targets and miri that might not OOM at all. + let layout = Layout::new::(); + let kind = TryReserveErrorKind::AllocError { layout, non_exhaustive: () }; + let reserve_err = TryReserveError::from(kind); + let io_err = io::Error::from(reserve_err); assert_eq!(io::ErrorKind::OutOfMemory, io_err.kind()); } diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index bdd330611de3d..c07c391892d80 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1064,7 +1064,7 @@ mod move_keyword {} /// ```rust,compile_fail,E0502 /// let mut v = vec![0, 1]; /// let mut_ref_v = &mut v; -/// ##[allow(unused)] +/// # #[allow(unused)] /// let ref_v = &v; /// mut_ref_v.push(2); /// ``` @@ -2121,8 +2121,8 @@ mod unsafe_keyword {} #[doc(keyword = "use")] // -/// Import or rename items from other crates or modules, or specify precise capturing -/// with `use<..>`. +/// Import or rename items from other crates or modules, use values under ergonomic clones +/// semantic, or specify precise capturing with `use<..>`. /// /// ## Importing items /// @@ -2205,6 +2205,11 @@ mod unsafe_keyword {} /// /// For more details about precise capturing, see the [Reference][ref-impl-trait]. /// +/// ## Ergonomic clones +/// +/// Use a values, copying its content if the value implements `Copy`, cloning the contents if the +/// value implements `UseCloned` or moving it otherwise. +/// /// [`crate`]: keyword.crate.html /// [`self`]: keyword.self.html /// [`super`]: keyword.super.html diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0661b3d770e48..35ada678740fe 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -274,7 +274,6 @@ // tidy-alphabetical-start // stabilization was reverted after it hit beta -#![cfg_attr(not(bootstrap), feature(extended_varargs_abi_support))] #![feature(alloc_error_handler)] #![feature(allocator_internals)] #![feature(allow_internal_unsafe)] @@ -293,6 +292,7 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] +#![feature(extended_varargs_abi_support)] #![feature(f128)] #![feature(f16)] #![feature(formatting_options)] @@ -666,6 +666,8 @@ pub mod arch { pub use std_detect::is_loongarch_feature_detected; #[unstable(feature = "is_riscv_feature_detected", issue = "111192")] pub use std_detect::is_riscv_feature_detected; + #[unstable(feature = "stdarch_s390x_feature_detection", issue = "135413")] + pub use std_detect::is_s390x_feature_detected; #[stable(feature = "simd_x86", since = "1.27.0")] pub use std_detect::is_x86_feature_detected; #[unstable(feature = "stdarch_mips_feature_detection", issue = "111188")] diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 9b68f872955c0..6a95142640726 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -5,7 +5,8 @@ not(any( target_os = "emscripten", all(target_os = "wasi", target_env = "p1"), - target_os = "xous" + target_os = "xous", + target_os = "trusty", )) ))] mod tests; diff --git a/library/std/src/net/test.rs b/library/std/src/net/test.rs index a5c3983cd89ec..df48b2f2420c3 100644 --- a/library/std/src/net/test.rs +++ b/library/std/src/net/test.rs @@ -31,3 +31,14 @@ pub fn tsa(a: A) -> Result, String> { Err(e) => Err(e.to_string()), } } + +pub fn compare_ignore_zoneid(a: &SocketAddr, b: &SocketAddr) -> bool { + match (a, b) { + (SocketAddr::V6(a), SocketAddr::V6(b)) => { + a.ip().segments() == b.ip().segments() + && a.flowinfo() == b.flowinfo() + && a.port() == b.port() + } + _ => a == b, + } +} diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 3eb798ad34aaa..a97b3299774bb 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -4,7 +4,8 @@ target_os = "emscripten", all(target_os = "wasi", target_env = "p1"), target_env = "sgx", - target_os = "xous" + target_os = "xous", + target_os = "trusty", )) ))] mod tests; diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 1c8c58d187957..91da3135f97c6 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -1,4 +1,4 @@ -use crate::net::test::{next_test_ip4, next_test_ip6}; +use crate::net::test::{compare_ignore_zoneid, next_test_ip4, next_test_ip6}; use crate::net::*; use crate::sync::mpsc::channel; use crate::thread; @@ -46,7 +46,7 @@ fn socket_smoke_test_ip4() { let (nread, src) = t!(server.recv_from(&mut buf)); assert_eq!(nread, 1); assert_eq!(buf[0], 99); - assert_eq!(src, client_ip); + assert_eq!(compare_ignore_zoneid(&src, &client_ip), true); rx2.recv().unwrap(); }) } @@ -78,7 +78,9 @@ fn udp_clone_smoke() { let _t = thread::spawn(move || { let mut buf = [0, 0]; - assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); + let res = sock2.recv_from(&mut buf).unwrap(); + assert_eq!(res.0, 1); + assert_eq!(compare_ignore_zoneid(&res.1, &addr1), true); assert_eq!(buf[0], 1); t!(sock2.send_to(&[2], &addr1)); }); @@ -94,7 +96,9 @@ fn udp_clone_smoke() { }); tx1.send(()).unwrap(); let mut buf = [0, 0]; - assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); + let res = sock1.recv_from(&mut buf).unwrap(); + assert_eq!(res.0, 1); + assert_eq!(compare_ignore_zoneid(&res.1, &addr2), true); rx2.recv().unwrap(); }) } diff --git a/library/std/src/os/fd/mod.rs b/library/std/src/os/fd/mod.rs index 35de4860fe249..95cf4932e6e2c 100644 --- a/library/std/src/os/fd/mod.rs +++ b/library/std/src/os/fd/mod.rs @@ -13,6 +13,7 @@ mod raw; mod owned; // Implementations for `AsRawFd` etc. for network types. +#[cfg(not(target_os = "trusty"))] mod net; #[cfg(test)] diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 5cec11ecccf1c..701cf82335757 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -4,12 +4,20 @@ #![deny(unsafe_op_in_unsafe_fn)] use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; +#[cfg(not(target_os = "trusty"))] +use crate::fs; use crate::marker::PhantomData; use crate::mem::ManuallyDrop; -#[cfg(not(any(target_arch = "wasm32", target_env = "sgx", target_os = "hermit")))] +#[cfg(not(any( + target_arch = "wasm32", + target_env = "sgx", + target_os = "hermit", + target_os = "trusty" +)))] use crate::sys::cvt; +#[cfg(not(target_os = "trusty"))] use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::{fmt, fs, io}; +use crate::{fmt, io}; type ValidRawFd = core::num::niche_types::NotAllOnes; @@ -87,7 +95,7 @@ impl OwnedFd { impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - #[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))] + #[cfg(not(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty")))] #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> crate::io::Result { // We want to atomically duplicate this file descriptor and set the @@ -110,7 +118,7 @@ impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - #[cfg(any(target_arch = "wasm32", target_os = "hermit"))] + #[cfg(any(target_arch = "wasm32", target_os = "hermit", target_os = "trusty"))] #[stable(feature = "io_safety", since = "1.63.0")] pub fn try_clone_to_owned(&self) -> crate::io::Result { Err(crate::io::Error::UNSUPPORTED_PLATFORM) @@ -280,6 +288,7 @@ impl AsFd for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl AsFd for fs::File { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { @@ -288,6 +297,7 @@ impl AsFd for fs::File { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { /// Takes ownership of a [`File`](fs::File)'s underlying file descriptor. #[inline] @@ -297,6 +307,7 @@ impl From for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for fs::File { /// Returns a [`File`](fs::File) that takes ownership of the given /// file descriptor. @@ -307,6 +318,7 @@ impl From for fs::File { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl AsFd for crate::net::TcpStream { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { @@ -315,6 +327,7 @@ impl AsFd for crate::net::TcpStream { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { /// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor. #[inline] @@ -324,6 +337,7 @@ impl From for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for crate::net::TcpStream { #[inline] fn from(owned_fd: OwnedFd) -> Self { @@ -334,6 +348,7 @@ impl From for crate::net::TcpStream { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl AsFd for crate::net::TcpListener { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { @@ -342,6 +357,7 @@ impl AsFd for crate::net::TcpListener { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { /// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor. #[inline] @@ -351,6 +367,7 @@ impl From for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for crate::net::TcpListener { #[inline] fn from(owned_fd: OwnedFd) -> Self { @@ -361,6 +378,7 @@ impl From for crate::net::TcpListener { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl AsFd for crate::net::UdpSocket { #[inline] fn as_fd(&self) -> BorrowedFd<'_> { @@ -369,6 +387,7 @@ impl AsFd for crate::net::UdpSocket { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for OwnedFd { /// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor. #[inline] @@ -378,6 +397,7 @@ impl From for OwnedFd { } #[stable(feature = "io_safety", since = "1.63.0")] +#[cfg(not(target_os = "trusty"))] impl From for crate::net::UdpSocket { #[inline] fn from(owned_fd: OwnedFd) -> Self { diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 03dff94350dad..083ac6e3fe6b1 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -5,6 +5,9 @@ #[cfg(target_os = "hermit")] use hermit_abi as libc; +#[cfg(not(target_os = "trusty"))] +use crate::fs; +use crate::io; #[cfg(target_os = "hermit")] use crate::os::hermit::io::OwnedFd; #[cfg(not(target_os = "hermit"))] @@ -15,8 +18,8 @@ use crate::os::unix::io::AsFd; use crate::os::unix::io::OwnedFd; #[cfg(target_os = "wasi")] use crate::os::wasi::io::OwnedFd; +#[cfg(not(target_os = "trusty"))] use crate::sys_common::{AsInner, IntoInner}; -use crate::{fs, io}; /// Raw file descriptors. #[stable(feature = "rust1", since = "1.0.0")] @@ -161,6 +164,7 @@ impl FromRawFd for RawFd { } #[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(target_os = "trusty"))] impl AsRawFd for fs::File { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -168,6 +172,7 @@ impl AsRawFd for fs::File { } } #[stable(feature = "from_raw_os", since = "1.1.0")] +#[cfg(not(target_os = "trusty"))] impl FromRawFd for fs::File { #[inline] unsafe fn from_raw_fd(fd: RawFd) -> fs::File { @@ -175,6 +180,7 @@ impl FromRawFd for fs::File { } } #[stable(feature = "into_raw_os", since = "1.4.0")] +#[cfg(not(target_os = "trusty"))] impl IntoRawFd for fs::File { #[inline] fn into_raw_fd(self) -> RawFd { @@ -183,6 +189,7 @@ impl IntoRawFd for fs::File { } #[stable(feature = "asraw_stdio", since = "1.21.0")] +#[cfg(not(target_os = "trusty"))] impl AsRawFd for io::Stdin { #[inline] fn as_raw_fd(&self) -> RawFd { @@ -207,6 +214,7 @@ impl AsRawFd for io::Stderr { } #[stable(feature = "asraw_stdio_locks", since = "1.35.0")] +#[cfg(not(target_os = "trusty"))] impl<'a> AsRawFd for io::StdinLock<'a> { #[inline] fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/os/fd/tests.rs b/library/std/src/os/fd/tests.rs index b39863644f116..7e9cf038e9a75 100644 --- a/library/std/src/os/fd/tests.rs +++ b/library/std/src/os/fd/tests.rs @@ -36,7 +36,6 @@ fn test_fd() { #[cfg(any(unix, target_os = "wasi"))] #[test] fn test_niche_optimizations() { - use crate::mem::size_of; #[cfg(unix)] use crate::os::unix::io::{BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[cfg(target_os = "wasi")] diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index e28a1c3e6d5f4..58cbecd30e538 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -169,6 +169,8 @@ pub mod rtems; pub mod solaris; #[cfg(target_os = "solid_asp3")] pub mod solid; +#[cfg(target_os = "trusty")] +pub mod trusty; #[cfg(target_os = "uefi")] pub mod uefi; #[cfg(target_os = "vita")] @@ -178,7 +180,7 @@ pub mod vxworks; #[cfg(target_os = "xous")] pub mod xous; -#[cfg(any(unix, target_os = "hermit", target_os = "wasi", doc))] +#[cfg(any(unix, target_os = "hermit", target_os = "trusty", target_os = "wasi", doc))] pub mod fd; #[cfg(any(target_os = "linux", target_os = "android", doc))] diff --git a/library/std/src/os/trusty/io/mod.rs b/library/std/src/os/trusty/io/mod.rs new file mode 100644 index 0000000000000..4cfd448305b65 --- /dev/null +++ b/library/std/src/os/trusty/io/mod.rs @@ -0,0 +1,4 @@ +#![stable(feature = "os_fd", since = "1.66.0")] + +#[stable(feature = "os_fd", since = "1.66.0")] +pub use crate::os::fd::*; diff --git a/library/std/src/os/trusty/mod.rs b/library/std/src/os/trusty/mod.rs new file mode 100644 index 0000000000000..cc67c92d7ff47 --- /dev/null +++ b/library/std/src/os/trusty/mod.rs @@ -0,0 +1,3 @@ +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod io; diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 04a45fd035a55..0427feb29550f 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -276,63 +276,89 @@ impl FileExt for fs::File { } /// Unix-specific extensions to [`fs::Permissions`]. +/// +/// # Examples +/// +/// ```no_run +/// use std::fs::{File, Permissions}; +/// use std::io::{ErrorKind, Result as IoResult}; +/// use std::os::unix::fs::PermissionsExt; +/// +/// fn main() -> IoResult<()> { +/// let name = "test_file_for_permissions"; +/// +/// // make sure file does not exist +/// let _ = std::fs::remove_file(name); +/// assert_eq!( +/// File::open(name).unwrap_err().kind(), +/// ErrorKind::NotFound, +/// "file already exists" +/// ); +/// +/// // full read/write/execute mode bits for owner of file +/// // that we want to add to existing mode bits +/// let my_mode = 0o700; +/// +/// // create new file with specified permissions +/// { +/// let file = File::create(name)?; +/// let mut permissions = file.metadata()?.permissions(); +/// eprintln!("Current permissions: {:o}", permissions.mode()); +/// +/// // make sure new permissions are not already set +/// assert!( +/// permissions.mode() & my_mode != my_mode, +/// "permissions already set" +/// ); +/// +/// // either use `set_mode` to change an existing Permissions struct +/// permissions.set_mode(permissions.mode() | my_mode); +/// +/// // or use `from_mode` to construct a new Permissions struct +/// permissions = Permissions::from_mode(permissions.mode() | my_mode); +/// +/// // write new permissions to file +/// file.set_permissions(permissions)?; +/// } +/// +/// let permissions = File::open(name)?.metadata()?.permissions(); +/// eprintln!("New permissions: {:o}", permissions.mode()); +/// +/// // assert new permissions were set +/// assert_eq!( +/// permissions.mode() & my_mode, +/// my_mode, +/// "new permissions not set" +/// ); +/// Ok(()) +/// } +/// ``` +/// +/// ```no_run +/// use std::fs::Permissions; +/// use std::os::unix::fs::PermissionsExt; +/// +/// // read/write for owner and read for others +/// let my_mode = 0o644; +/// let mut permissions = Permissions::from_mode(my_mode); +/// assert_eq!(permissions.mode(), my_mode); +/// +/// // read/write/execute for owner +/// let other_mode = 0o700; +/// permissions.set_mode(other_mode); +/// assert_eq!(permissions.mode(), other_mode); +/// ``` #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { - /// Returns the underlying raw `st_mode` bits that contain the standard - /// Unix permissions for this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); - /// - /// println!("permissions: {:o}", permissions.mode()); - /// Ok(()) - /// } - /// ``` + /// Returns the mode permission bits #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; - /// Sets the underlying raw bits for this set of permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) - /// } - /// ``` + /// Sets the mode permission bits. #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); - /// Creates a new instance of `Permissions` from the given set of Unix - /// permission bits. - /// - /// # Examples - /// - /// ``` - /// use std::fs::Permissions; - /// use std::os::unix::fs::PermissionsExt; - /// - /// // Read/write for owner and read for others. - /// let permissions = Permissions::from_mode(0o644); - /// assert_eq!(permissions.mode(), 0o644); - /// ``` + /// Creates a new instance from the given mode permission bits. #[stable(feature = "fs_ext", since = "1.1.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "permissions_from_mode")] fn from_mode(mode: u32) -> Self; diff --git a/library/std/src/os/unix/io/tests.rs b/library/std/src/os/unix/io/tests.rs index 84d2a7a1a91b4..fc147730578ac 100644 --- a/library/std/src/os/unix/io/tests.rs +++ b/library/std/src/os/unix/io/tests.rs @@ -1,4 +1,3 @@ -use crate::mem::size_of; use crate::os::unix::io::RawFd; #[test] diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 56789f235fdab..cb1246db3109e 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -94,7 +94,7 @@ impl SocketAddr { { unsafe { let mut addr: libc::sockaddr_un = mem::zeroed(); - let mut len = mem::size_of::() as libc::socklen_t; + let mut len = size_of::() as libc::socklen_t; cvt(f((&raw mut addr) as *mut _, &mut len))?; SocketAddr::from_parts(addr, len) } diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index be236317d047d..27428c9eb2855 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -177,7 +177,7 @@ impl UnixListener { #[stable(feature = "unix_socket", since = "1.10.0")] pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; - let mut len = mem::size_of_val(&storage) as libc::socklen_t; + let mut len = size_of_val(&storage) as libc::socklen_t; let sock = self.0.accept((&raw mut storage) as *mut _, &mut len)?; let addr = SocketAddr::from_parts(storage, len)?; Ok((UnixStream(sock), addr)) diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index e1014a4f296dd..2dd7d409e48c2 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -41,15 +41,15 @@ mod impl_linux { use libc::{SO_PEERCRED, SOL_SOCKET, c_void, getsockopt, socklen_t, ucred}; use super::UCred; + use crate::io; use crate::os::unix::io::AsRawFd; use crate::os::unix::net::UnixStream; - use crate::{io, mem}; pub fn peer_cred(socket: &UnixStream) -> io::Result { - let ucred_size = mem::size_of::(); + let ucred_size = size_of::(); // Trivial sanity checks. - assert!(mem::size_of::() <= mem::size_of::()); + assert!(size_of::() <= size_of::()); assert!(ucred_size <= u32::MAX as usize); let mut ucred_size = ucred_size as socklen_t; @@ -64,7 +64,7 @@ mod impl_linux { &mut ucred_size, ); - if ret == 0 && ucred_size as usize == mem::size_of::() { + if ret == 0 && ucred_size as usize == size_of::() { Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) }) } else { Err(io::Error::last_os_error()) @@ -101,9 +101,9 @@ mod impl_apple { use libc::{LOCAL_PEERPID, SOL_LOCAL, c_void, getpeereid, getsockopt, pid_t, socklen_t}; use super::UCred; + use crate::io; use crate::os::unix::io::AsRawFd; use crate::os::unix::net::UnixStream; - use crate::{io, mem}; pub fn peer_cred(socket: &UnixStream) -> io::Result { let mut cred = UCred { uid: 1, gid: 1, pid: None }; @@ -115,7 +115,7 @@ mod impl_apple { } let mut pid: pid_t = 1; - let mut pid_size = mem::size_of::() as socklen_t; + let mut pid_size = size_of::() as socklen_t; let ret = getsockopt( socket.as_raw_fd(), @@ -125,7 +125,7 @@ mod impl_apple { &mut pid_size, ); - if ret == 0 && pid_size as usize == mem::size_of::() { + if ret == 0 && pid_size as usize == size_of::() { cred.pid = Some(pid); Ok(cred) } else { diff --git a/library/std/src/os/wasi/io/tests.rs b/library/std/src/os/wasi/io/tests.rs index 418274752b0ad..c5c6a19a6c885 100644 --- a/library/std/src/os/wasi/io/tests.rs +++ b/library/std/src/os/wasi/io/tests.rs @@ -1,4 +1,3 @@ -use crate::mem::size_of; use crate::os::wasi::io::RawFd; #[test] diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 2bc6ce222ae5c..1c228914de93f 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -90,7 +90,7 @@ impl OwnedSocket { #[cfg(target_vendor = "uwp")] pub(crate) fn set_no_inherit(&self) -> io::Result<()> { - Err(io::const_error!(io::ErrorKind::Unsupported, "Unavailable on UWP")) + Err(io::const_error!(io::ErrorKind::Unsupported, "unavailable on UWP")) } } diff --git a/library/std/src/os/windows/io/tests.rs b/library/std/src/os/windows/io/tests.rs index 41734e52e8cce..029b6f5cd3d9e 100644 --- a/library/std/src/os/windows/io/tests.rs +++ b/library/std/src/os/windows/io/tests.rs @@ -1,6 +1,5 @@ #[test] fn test_niche_optimizations_socket() { - use crate::mem::size_of; use crate::os::windows::io::{ BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, }; diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 201274cf03aec..a084f452e55d0 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -500,11 +500,7 @@ impl<'a> ProcThreadAttributeListBuilder<'a> { /// [1]: pub fn attribute(self, attribute: usize, value: &'a T) -> Self { unsafe { - self.raw_attribute( - attribute, - ptr::addr_of!(*value).cast::(), - crate::mem::size_of::(), - ) + self.raw_attribute(attribute, ptr::addr_of!(*value).cast::(), size_of::()) } } @@ -535,7 +531,7 @@ impl<'a> ProcThreadAttributeListBuilder<'a> { /// pub Y: i16, /// } /// - /// extern "system" { + /// unsafe extern "system" { /// fn CreatePipe( /// hreadpipe: *mut HANDLE, /// hwritepipe: *mut HANDLE, @@ -574,7 +570,7 @@ impl<'a> ProcThreadAttributeListBuilder<'a> { /// .raw_attribute( /// PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, /// h_pc as *const c_void, - /// std::mem::size_of::(), + /// size_of::(), /// ) /// .finish()? /// }; diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs index 1db314e9ddad7..9394f0a0496b2 100644 --- a/library/std/src/os/xous/ffi.rs +++ b/library/std/src/os/xous/ffi.rs @@ -368,7 +368,7 @@ pub(crate) unsafe fn map_memory( let mut a0 = Syscall::MapMemory as usize; let mut a1 = phys.map(|p| p.as_ptr() as usize).unwrap_or_default(); let mut a2 = virt.map(|p| p.as_ptr() as usize).unwrap_or_default(); - let a3 = count * core::mem::size_of::(); + let a3 = count * size_of::(); let a4 = flags.bits(); let a5 = 0; let a6 = 0; @@ -392,7 +392,7 @@ pub(crate) unsafe fn map_memory( if result == SyscallResult::MemoryRange as usize { let start = core::ptr::with_exposed_provenance_mut::(a1); - let len = a2 / core::mem::size_of::(); + let len = a2 / size_of::(); let end = unsafe { start.add(len) }; Ok(unsafe { core::slice::from_raw_parts_mut(start, len) }) } else if result == SyscallResult::Error as usize { @@ -409,7 +409,7 @@ pub(crate) unsafe fn map_memory( pub(crate) unsafe fn unmap_memory(range: *mut [T]) -> Result<(), Error> { let mut a0 = Syscall::UnmapMemory as usize; let mut a1 = range.as_mut_ptr() as usize; - let a2 = range.len() * core::mem::size_of::(); + let a2 = range.len() * size_of::(); let a3 = 0; let a4 = 0; let a5 = 0; @@ -455,7 +455,7 @@ pub(crate) unsafe fn update_memory_flags( ) -> Result<(), Error> { let mut a0 = Syscall::UpdateMemoryFlags as usize; let mut a1 = range.as_mut_ptr() as usize; - let a2 = range.len() * core::mem::size_of::(); + let a2 = range.len() * size_of::(); let a3 = new_flags.bits(); let a4 = 0; // Process ID is currently None let a5 = 0; diff --git a/library/std/src/os/xous/services/log.rs b/library/std/src/os/xous/services/log.rs index 1661011ca64b1..095d4f4a3e7a8 100644 --- a/library/std/src/os/xous/services/log.rs +++ b/library/std/src/os/xous/services/log.rs @@ -7,8 +7,8 @@ use crate::os::xous::ffi::Connection; /// `group_or_null([1,2,3,4,5,6,7,8], 1)` on a 32-bit system will return a /// `usize` with 5678 packed into it. fn group_or_null(data: &[u8], offset: usize) -> usize { - let start = offset * core::mem::size_of::(); - let mut out_array = [0u8; core::mem::size_of::()]; + let start = offset * size_of::(); + let mut out_array = [0u8; size_of::()]; if start < data.len() { for (dest, src) in out_array.iter_mut().zip(&data[start..]) { *dest = *src; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index f9f3b488f0d03..980213be7ea90 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -294,11 +294,6 @@ where } } -// Detect scheme on Redox -pub(crate) fn has_redox_scheme(s: &[u8]) -> bool { - cfg!(target_os = "redox") && s.contains(&b':') -} - //////////////////////////////////////////////////////////////////////////////// // Cross-platform, iterator-independent parsing //////////////////////////////////////////////////////////////////////////////// @@ -2834,8 +2829,7 @@ impl Path { Components { path: self.as_u8_slice(), prefix, - has_physical_root: has_physical_root(self.as_u8_slice(), prefix) - || has_redox_scheme(self.as_u8_slice()), + has_physical_root: has_physical_root(self.as_u8_slice(), prefix), front: State::Prefix, back: State::Body, } diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 992a9207a7206..5f7097c26e228 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -160,3 +160,18 @@ pub mod rust_2024 { #[doc(no_inline)] pub use core::prelude::rust_2024::*; } + +/// The Future version of the prelude of The Rust Standard Library. +/// +/// See the [module-level documentation](self) for more. +#[doc(hidden)] +#[unstable(feature = "prelude_future", issue = "none")] +pub mod rust_future { + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use super::v1::*; + + #[unstable(feature = "prelude_next", issue = "none")] + #[doc(no_inline)] + pub use core::prelude::rust_future::*; +} diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs index 5b324b2e91671..4217f65864072 100644 --- a/library/std/src/prelude/v1.rs +++ b/library/std/src/prelude/v1.rs @@ -103,6 +103,15 @@ pub use core::prelude::v1::type_ascribe; )] pub use core::prelude::v1::deref; +// Do not `doc(no_inline)` either. +#[unstable( + feature = "type_alias_impl_trait", + issue = "63063", + reason = "`type_alias_impl_trait` has open design concerns" +)] +#[cfg(not(bootstrap))] +pub use core::prelude::v1::define_opaque; + // The file so far is equivalent to core/src/prelude/v1.rs. It is duplicated // rather than glob imported because we want docs to show these re-exports as // pointing to within `std`. diff --git a/library/std/src/process.rs b/library/std/src/process.rs index bdd4844b6511a..37762c65f6556 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -154,7 +154,8 @@ target_os = "emscripten", target_os = "wasi", target_env = "sgx", - target_os = "xous" + target_os = "xous", + target_os = "trusty", )) ))] mod tests; diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index 8caa2dcfad99c..8712332dd2767 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -1382,3 +1382,6 @@ impl fmt::Debug for Receiver { f.pad("Receiver { .. }") } } + +#[cfg(test)] +mod tests; diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs new file mode 100644 index 0000000000000..6deb4dc2fe0cc --- /dev/null +++ b/library/std/src/sync/mpmc/tests.rs @@ -0,0 +1,14 @@ +// Ensure that thread_local init with `const { 0 }` still has unique address at run-time +#[test] +fn waker_current_thread_id() { + let first = super::waker::current_thread_id(); + let t = crate::thread::spawn(move || { + let second = super::waker::current_thread_id(); + assert_ne!(first, second); + assert_eq!(second, super::waker::current_thread_id()); + }); + + assert_eq!(first, super::waker::current_thread_id()); + t.join().unwrap(); + assert_eq!(first, super::waker::current_thread_id()); +} diff --git a/library/std/src/sync/mpmc/waker.rs b/library/std/src/sync/mpmc/waker.rs index 1895466f95d45..f5e764e69bd6e 100644 --- a/library/std/src/sync/mpmc/waker.rs +++ b/library/std/src/sync/mpmc/waker.rs @@ -204,6 +204,6 @@ impl Drop for SyncWaker { pub fn current_thread_id() -> usize { // `u8` is not drop so this variable will be available during thread destruction, // whereas `thread::current()` would not be - thread_local! { static DUMMY: u8 = 0 } + thread_local! { static DUMMY: u8 = const { 0 } } DUMMY.with(|x| (x as *const u8).addr()) } diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 21e6b65a744f8..ffb90b1469584 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -191,7 +191,7 @@ impl OnceLock { /// }) /// ``` #[inline] - #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "once_wait", since = "1.86.0")] pub fn wait(&self) -> &T { self.once.wait_force(); diff --git a/library/std/src/sync/poison/once.rs b/library/std/src/sync/poison/once.rs index d2938b7a0c12e..103e519540795 100644 --- a/library/std/src/sync/poison/once.rs +++ b/library/std/src/sync/poison/once.rs @@ -284,7 +284,7 @@ impl Once { /// If this [`Once`] has been poisoned because an initialization closure has /// panicked, this method will also panic. Use [`wait_force`](Self::wait_force) /// if this behavior is not desired. - #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "once_wait", since = "1.86.0")] pub fn wait(&self) { if !self.inner.is_completed() { self.inner.wait(false); @@ -293,7 +293,7 @@ impl Once { /// Blocks the current thread until initialization has completed, ignoring /// poisoning. - #[stable(feature = "once_wait", since = "CURRENT_RUSTC_VERSION")] + #[stable(feature = "once_wait", since = "1.86.0")] pub fn wait_force(&self) { if !self.inner.is_completed() { self.inner.wait(true); diff --git a/library/std/src/sys/alloc/mod.rs b/library/std/src/sys/alloc/mod.rs index 2c0b533a5703f..8489e17c971d9 100644 --- a/library/std/src/sys/alloc/mod.rs +++ b/library/std/src/sys/alloc/mod.rs @@ -72,6 +72,7 @@ cfg_if::cfg_if! { target_family = "unix", target_os = "wasi", target_os = "teeos", + target_os = "trusty", ))] { mod unix; } else if #[cfg(target_os = "windows")] { diff --git a/library/std/src/sys/alloc/unix.rs b/library/std/src/sys/alloc/unix.rs index 1af9d76629014..a7ac4117ec902 100644 --- a/library/std/src/sys/alloc/unix.rs +++ b/library/std/src/sys/alloc/unix.rs @@ -81,7 +81,7 @@ cfg_if::cfg_if! { // while others require the alignment to be at least the pointer size (Illumos, macOS). // posix_memalign only has one, clear requirement: that the alignment be a multiple of // `sizeof(void*)`. Since these are all powers of 2, we can just use max. - let align = layout.align().max(crate::mem::size_of::()); + let align = layout.align().max(size_of::()); let ret = unsafe { libc::posix_memalign(&mut out, align, layout.size()) }; if ret != 0 { ptr::null_mut() } else { out as *mut u8 } } diff --git a/library/std/src/sys/alloc/windows/tests.rs b/library/std/src/sys/alloc/windows/tests.rs index 674a3e1d92d17..1d5614528b12a 100644 --- a/library/std/src/sys/alloc/windows/tests.rs +++ b/library/std/src/sys/alloc/windows/tests.rs @@ -1,9 +1,8 @@ use super::{Header, MIN_ALIGN}; -use crate::mem; #[test] fn alloc_header() { // Header must fit in the padding before an aligned pointer - assert!(mem::size_of::